removed CharTraits

This commit is contained in:
mandreyel 2017-10-06 00:03:15 +02:00
parent 54694df5f7
commit c52e35b2e8
5 changed files with 119 additions and 115 deletions

View File

@ -21,11 +21,11 @@ int handle_error(const std::error_code& error)
int main() int main()
{ {
// Read-only memory map the whole file by using `use_full_file_size` where the // Read-only memory map the whole file by using `map_entire_file` where the
// length of the mapping would otherwise be expected, with the factory method. // length of the mapping would otherwise be expected, with the factory method.
std::error_code error; std::error_code error;
mio::mmap_source mmap1 = mio::make_mmap_source("log.txt", mio::mmap_source mmap1 = mio::make_mmap_source("log.txt",
offset_type(0), mio::use_full_file_size, error); offset_type(0), length_type(mio::map_entire_file), error);
if(error) { return handle_error(error); } if(error) { return handle_error(error); }
// Read-write memory map the beginning of some file using the `map` member function. // Read-write memory map the beginning of some file using the `map` member function.
@ -53,9 +53,11 @@ int main()
return handle_error(error); return handle_error(error);
} }
// mio exposes an interface that abstracts away memory as a string, so it is // It's possible to change the character type of the mmap object, which is useful
// possible to create mmap objects that have custom underlying character types: // for wide strings or reading fixed width integers (although endianness is not
// accounted for by mio, so appropriate conversions need be done by the user).
using wmmap_source = mio::basic_mmap_source<wchar_t>; using wmmap_source = mio::basic_mmap_source<wchar_t>;
using i32mmap_source = mio::basic_mmap_source<int32_t>;
} }
``` ```

View File

@ -37,7 +37,7 @@
namespace mio { namespace mio {
namespace detail { namespace detail {
enum { use_full_file_size = 0 }; enum { map_entire_file = 0 };
enum class access_mode enum class access_mode
{ {
@ -45,10 +45,7 @@ enum class access_mode
read_write read_write
}; };
template< template<typename CharT> struct basic_mmap
typename CharT,
typename CharTraits = std::char_traits<CharT>
> struct basic_mmap
{ {
using value_type = CharT; using value_type = CharT;
using size_type = int64_t; using size_type = int64_t;
@ -77,7 +74,7 @@ private:
// systems the file handle is necessary to retrieve a file mapping handle, but any // systems the file handle is necessary to retrieve a file mapping handle, but any
// subsequent operations on the mapped region must be done through the latter. // subsequent operations on the mapped region must be done through the latter.
handle_type file_handle_ = INVALID_HANDLE_VALUE; handle_type file_handle_ = INVALID_HANDLE_VALUE;
#if defined(_WIN32) #ifdef _WIN32
handle_type file_mapping_handle_ = INVALID_HANDLE_VALUE; handle_type file_mapping_handle_ = INVALID_HANDLE_VALUE;
#endif #endif
@ -108,8 +105,9 @@ public:
bool is_mapped() const noexcept; bool is_mapped() const noexcept;
bool empty() const noexcept { return length() == 0; } bool empty() const noexcept { return length() == 0; }
size_type length() const noexcept { return length_ >> sizeof(CharT); } size_type length() const noexcept { return length_ >> (sizeof(CharT) - 1); }
size_type mapped_length() const noexcept { return mapped_length_ >> sizeof(CharT); } size_type mapped_length() const noexcept
{ return mapped_length_ >> (sizeof(CharT) - 1); }
pointer data() noexcept { return data_; } pointer data() noexcept { return data_; }
const_pointer data() const noexcept { return data_; } const_pointer data() const noexcept { return data_; }
@ -153,29 +151,23 @@ private:
const access_mode mode, std::error_code& error); const access_mode mode, std::error_code& error);
}; };
template<typename CharT, typename CharTraits> template<typename CharT>
bool operator==(const basic_mmap<CharT, CharTraits>& a, bool operator==(const basic_mmap<CharT>& a, const basic_mmap<CharT>& b);
const basic_mmap<CharT, CharTraits>& b);
template<typename CharT, typename CharTraits> template<typename CharT>
bool operator!=(const basic_mmap<CharT, CharTraits>& a, bool operator!=(const basic_mmap<CharT>& a, const basic_mmap<CharT>& b);
const basic_mmap<CharT, CharTraits>& b);
template<typename CharT, typename CharTraits> template<typename CharT>
bool operator<(const basic_mmap<CharT, CharTraits>& a, bool operator<(const basic_mmap<CharT>& a, const basic_mmap<CharT>& b);
const basic_mmap<CharT, CharTraits>& b);
template<typename CharT, typename CharTraits> template<typename CharT>
bool operator<=(const basic_mmap<CharT, CharTraits>& a, bool operator<=(const basic_mmap<CharT>& a, const basic_mmap<CharT>& b);
const basic_mmap<CharT, CharTraits>& b);
template<typename CharT, typename CharTraits> template<typename CharT>
bool operator>(const basic_mmap<CharT, CharTraits>& a, bool operator>(const basic_mmap<CharT>& a, const basic_mmap<CharT>& b);
const basic_mmap<CharT, CharTraits>& b);
template<typename CharT, typename CharTraits> template<typename CharT>
bool operator>=(const basic_mmap<CharT, CharTraits>& a, bool operator>=(const basic_mmap<CharT>& a, const basic_mmap<CharT>& b);
const basic_mmap<CharT, CharTraits>& b);
} // namespace detail } // namespace detail
} // namespace mio } // namespace mio

View File

@ -41,7 +41,7 @@ namespace detail {
// Generic handle type for use by free functions. // Generic handle type for use by free functions.
using handle_type = basic_mmap<char>::handle_type; using handle_type = basic_mmap<char>::handle_type;
#if defined(_WIN32) #ifdef _WIN32
inline DWORD int64_high(int64_t n) noexcept inline DWORD int64_high(int64_t n) noexcept
{ {
return n >> 32; return n >> 32;
@ -73,7 +73,7 @@ handle_type open_file(const Path& path, const access_mode mode, std::error_code&
error = std::make_error_code(std::errc::invalid_argument); error = std::make_error_code(std::errc::invalid_argument);
return INVALID_HANDLE_VALUE; return INVALID_HANDLE_VALUE;
} }
#if defined(_WIN32) #ifdef _WIN32
const auto handle = ::CreateFile(c_str(path), const auto handle = ::CreateFile(c_str(path),
mode == access_mode::read_only ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, mode == access_mode::read_only ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
@ -116,14 +116,14 @@ inline int64_t query_file_size(handle_type handle, std::error_code& error)
// -- basic_mmap -- // -- basic_mmap --
template<typename CharT, typename CharTraits> template<typename CharT>
basic_mmap<CharT, CharTraits>::~basic_mmap() basic_mmap<CharT>::~basic_mmap()
{ {
unmap(); unmap();
} }
template<typename CharT, typename CharTraits> template<typename CharT>
basic_mmap<CharT, CharTraits>::basic_mmap(basic_mmap<CharT, CharTraits>&& other) basic_mmap<CharT>::basic_mmap(basic_mmap<CharT>&& other)
: data_(std::move(other.data_)) : data_(std::move(other.data_))
, length_(std::move(other.length_)) , length_(std::move(other.length_))
, mapped_length_(std::move(other.mapped_length_)) , mapped_length_(std::move(other.mapped_length_))
@ -141,8 +141,8 @@ basic_mmap<CharT, CharTraits>::basic_mmap(basic_mmap<CharT, CharTraits>&& other)
#endif #endif
} }
template<typename CharT, typename CharTraits> template<typename CharT>
basic_mmap<CharT, CharTraits>& basic_mmap<CharT, CharTraits>::operator=(basic_mmap<CharT, CharTraits>&& other) basic_mmap<CharT>& basic_mmap<CharT>::operator=(basic_mmap<CharT>&& other)
{ {
if(this != &other) if(this != &other)
{ {
@ -170,9 +170,9 @@ basic_mmap<CharT, CharTraits>& basic_mmap<CharT, CharTraits>::operator=(basic_mm
return *this; return *this;
} }
template<typename CharT, typename CharTraits> template<typename CharT>
typename basic_mmap<CharT, CharTraits>::handle_type typename basic_mmap<CharT>::handle_type
basic_mmap<CharT, CharTraits>::mapping_handle() const noexcept basic_mmap<CharT>::mapping_handle() const noexcept
{ {
#ifdef _WIN32 #ifdef _WIN32
return file_mapping_handle_; return file_mapping_handle_;
@ -181,9 +181,9 @@ basic_mmap<CharT, CharTraits>::mapping_handle() const noexcept
#endif #endif
} }
template<typename CharT, typename CharTraits> template<typename CharT>
template<typename String> template<typename String>
void basic_mmap<CharT, CharTraits>::map(String& path, size_type offset, void basic_mmap<CharT>::map(String& path, size_type offset,
size_type length, access_mode mode, std::error_code& error) size_type length, access_mode mode, std::error_code& error)
{ {
error.clear(); error.clear();
@ -202,8 +202,8 @@ void basic_mmap<CharT, CharTraits>::map(String& path, size_type offset,
} }
} }
template<typename CharT, typename CharTraits> template<typename CharT>
void basic_mmap<CharT, CharTraits>::map(handle_type handle, size_type offset, void basic_mmap<CharT>::map(handle_type handle, size_type offset,
size_type length, access_mode mode, std::error_code& error) size_type length, access_mode mode, std::error_code& error)
{ {
error.clear(); error.clear();
@ -216,7 +216,7 @@ void basic_mmap<CharT, CharTraits>::map(handle_type handle, size_type offset,
const auto file_size = query_file_size(handle, error); const auto file_size = query_file_size(handle, error);
if(error) { return; } if(error) { return; }
if(length <= use_full_file_size) if(length <= map_entire_file)
{ {
length = file_size; length = file_size;
} }
@ -231,13 +231,13 @@ void basic_mmap<CharT, CharTraits>::map(handle_type handle, size_type offset,
map(offset, length, mode, error); map(offset, length, mode, error);
} }
template<typename CharT, typename CharTraits> template<typename CharT>
void basic_mmap<CharT, CharTraits>::map(const size_type offset, const size_type length, void basic_mmap<CharT>::map(const size_type offset, const size_type length,
const access_mode mode, std::error_code& error) const access_mode mode, std::error_code& error)
{ {
const size_type aligned_offset = make_offset_page_aligned(offset); const size_type aligned_offset = make_offset_page_aligned(offset);
const size_type length_to_map = offset - aligned_offset + length; const size_type length_to_map = offset - aligned_offset + length;
#if defined(_WIN32) #ifdef _WIN32
const size_type max_file_size = offset + length; const size_type max_file_size = offset + length;
file_mapping_handle_ = ::CreateFileMapping( file_mapping_handle_ = ::CreateFileMapping(
file_handle_, file_handle_,
@ -282,8 +282,8 @@ void basic_mmap<CharT, CharTraits>::map(const size_type offset, const size_type
mapped_length_ = length_to_map; mapped_length_ = length_to_map;
} }
template<typename CharT, typename CharTraits> template<typename CharT>
void basic_mmap<CharT, CharTraits>::sync(std::error_code& error) void basic_mmap<CharT>::sync(std::error_code& error)
{ {
error.clear(); error.clear();
if(!is_open()) if(!is_open())
@ -313,8 +313,8 @@ void basic_mmap<CharT, CharTraits>::sync(std::error_code& error)
#endif #endif
} }
template<typename CharT, typename CharTraits> template<typename CharT>
void basic_mmap<CharT, CharTraits>::unmap() void basic_mmap<CharT>::unmap()
{ {
if(!is_open()) { return; } if(!is_open()) { return; }
// TODO do we care about errors here? // TODO do we care about errors here?
@ -350,23 +350,23 @@ void basic_mmap<CharT, CharTraits>::unmap()
#endif #endif
} }
template<typename CharT, typename CharTraits> template<typename CharT>
typename basic_mmap<CharT, CharTraits>::pointer typename basic_mmap<CharT>::pointer
basic_mmap<CharT, CharTraits>::get_mapping_start() noexcept basic_mmap<CharT>::get_mapping_start() noexcept
{ {
if(!data_) { return nullptr; } if(!data_) { return nullptr; }
const auto offset = mapped_length_ - length_; const auto offset = mapped_length_ - length_;
return data_ - offset; return data_ - offset;
} }
template<typename CharT, typename CharTraits> template<typename CharT>
bool basic_mmap<CharT, CharTraits>::is_open() const noexcept bool basic_mmap<CharT>::is_open() const noexcept
{ {
return file_handle_ != INVALID_HANDLE_VALUE; return file_handle_ != INVALID_HANDLE_VALUE;
} }
template<typename CharT, typename CharTraits> template<typename CharT>
bool basic_mmap<CharT, CharTraits>::is_mapped() const noexcept bool basic_mmap<CharT>::is_mapped() const noexcept
{ {
#ifdef _WIN32 #ifdef _WIN32
return file_mapping_handle_ != INVALID_HANDLE_VALUE; return file_mapping_handle_ != INVALID_HANDLE_VALUE;
@ -375,8 +375,8 @@ bool basic_mmap<CharT, CharTraits>::is_mapped() const noexcept
#endif #endif
} }
template<typename CharT, typename CharTraits> template<typename CharT>
void basic_mmap<CharT, CharTraits>::swap(basic_mmap<CharT, CharTraits>& other) void basic_mmap<CharT>::swap(basic_mmap<CharT>& other)
{ {
if(this != &other) if(this != &other)
{ {
@ -392,49 +392,43 @@ void basic_mmap<CharT, CharTraits>::swap(basic_mmap<CharT, CharTraits>& other)
} }
} }
template<typename CharT, typename CharTraits> template<typename CharT>
bool operator==(const basic_mmap<CharT, CharTraits>& a, bool operator==(const basic_mmap<CharT>& a, const basic_mmap<CharT>& b)
const basic_mmap<CharT, CharTraits>& b)
{ {
return a.size() == b.size() return a.data() == b.data()
&& CharTraits::compare(a.data(), b.data(), a.size()) == 0; && a.size() == b.size();
} }
template<typename CharT, typename CharTraits> template<typename CharT>
bool operator!=(const basic_mmap<CharT, CharTraits>& a, bool operator!=(const basic_mmap<CharT>& a, const basic_mmap<CharT>& b)
const basic_mmap<CharT, CharTraits>& b)
{ {
return !(a == b); return !(a == b);
} }
template<typename CharT, typename CharTraits> template<typename CharT>
bool operator<(const basic_mmap<CharT, CharTraits>& a, bool operator<(const basic_mmap<CharT>& a, const basic_mmap<CharT>& b)
const basic_mmap<CharT, CharTraits>& b)
{ {
return CharTraits::compare(a.data(), b.data(), a.size()) < 0; if(a.data() == b.data()) { return a.size() < b.size(); }
return a.data() < b.data();
} }
// TODO optimize template<typename CharT>
template<typename CharT, typename CharTraits> bool operator<=(const basic_mmap<CharT>& a, const basic_mmap<CharT>& b)
bool operator<=(const basic_mmap<CharT, CharTraits>& a,
const basic_mmap<CharT, CharTraits>& b)
{ {
return (a == b) || (a < b); return !(a > b);
} }
template<typename CharT, typename CharTraits> template<typename CharT>
bool operator>(const basic_mmap<CharT, CharTraits>& a, bool operator>(const basic_mmap<CharT>& a, const basic_mmap<CharT>& b)
const basic_mmap<CharT, CharTraits>& b)
{ {
return CharTraits::compare(a.data(), b.data(), a.size()) > 0; if(a.data() == b.data()) { return a.size() > b.size(); }
return a.data() > b.data();
} }
// TODO optimize template<typename CharT>
template<typename CharT, typename CharTraits> bool operator>=(const basic_mmap<CharT>& a, const basic_mmap<CharT>& b)
bool operator>=(const basic_mmap<CharT, CharTraits>& a,
const basic_mmap<CharT, CharTraits>& b)
{ {
return (a == b) || (a > b); return !(a < b);
} }
} // namespace detail } // namespace detail

View File

@ -34,20 +34,20 @@ using detail::access_mode;
// This value may be provided as the `length` parameter to the constructor or // This value may be provided as the `length` parameter to the constructor or
// `map`, in which case a memory mapping of the entire file is created. // `map`, in which case a memory mapping of the entire file is created.
using detail::use_full_file_size; using detail::map_entire_file;
template< template<
access_mode AccessMode, access_mode AccessMode,
typename CharT, typename CharT
typename CharTraits = std::char_traits<CharT>
> class basic_mmap > class basic_mmap
{ {
static_assert(AccessMode == access_mode::read_only static_assert(AccessMode == access_mode::read_only
|| AccessMode == access_mode::read_write, || AccessMode == access_mode::read_write,
"AccessMode must be either read_only or read_write"); "AccessMode must be either read_only or read_write");
using impl_type = detail::basic_mmap<CharT, CharTraits>; using impl_type = detail::basic_mmap<CharT>;
impl_type impl_; impl_type impl_;
public: public:
using value_type = typename impl_type::value_type; using value_type = typename impl_type::value_type;
@ -211,8 +211,10 @@ public:
* from the start of the file. * from the start of the file.
* *
* `length` must be the number of bytes to map, regardless of the underlying * `length` must be the number of bytes to map, regardless of the underlying
* value_type's size! If it is `use_full_file_size`, a mapping of the entire file * value_type's size. That is, if CharT is a wide char, the value returned by
* is created. * the `size` and `length` methods is not the same as this `length` value (TODO
* this can be confusing).
* If it is `map_entire_file`, a mapping of the entire file is created.
*/ */
template<typename String> template<typename String>
void map(const String& path, const size_type offset, void map(const String& path, const size_type offset,
@ -237,8 +239,10 @@ public:
* from the start of the file. * from the start of the file.
* *
* `length` must be the number of bytes to map, regardless of the underlying * `length` must be the number of bytes to map, regardless of the underlying
* value_type's size! If it is `use_full_file_size`, a mapping of the entire file * value_type's size. That is, if CharT is a wide char, the value returned by
* is created. * the `size` and `length` methods is not the same as this `length` value (TODO
* this can be confusing).
* If it is `map_entire_file`, a mapping of the entire file is created.
*/ */
void map(const handle_type handle, const size_type offset, void map(const handle_type handle, const size_type offset,
const size_type length, std::error_code& error) const size_type length, std::error_code& error)
@ -259,14 +263,16 @@ public:
void swap(basic_mmap& other) { impl_.swap(other.impl_); } void swap(basic_mmap& other) { impl_.swap(other.impl_); }
/** Flushes the memory mapped page to disk. */ /** Flushes the memory mapped page to disk. Errors are reported via `error`. */
// TODO better name?
template< template<
access_mode A = AccessMode, access_mode A = AccessMode,
typename = typename std::enable_if<A == access_mode::read_write>::type typename = typename std::enable_if<A == access_mode::read_write>::type
> void sync(std::error_code& error) { impl_.sync(error); } > void sync(std::error_code& error) { impl_.sync(error); }
/** All operators compare two mapped areas according to CharTraits::compare. */ /**
* All operators compare the address of the first byte and size of the two mapped
* regions.
*/
friend bool operator==(const basic_mmap& a, const basic_mmap& b) friend bool operator==(const basic_mmap& a, const basic_mmap& b)
{ {
@ -303,21 +309,20 @@ public:
* This is the basis for all read-only mmap objects and should be preferred over * This is the basis for all read-only mmap objects and should be preferred over
* directly using basic_mmap. * directly using basic_mmap.
*/ */
template< template<typename CharT>
typename CharT, using basic_mmap_source = basic_mmap<access_mode::read_only, CharT>;
typename CharTraits = std::char_traits<CharT>
> using basic_mmap_source = basic_mmap<access_mode::read_only, CharT, CharTraits>;
/** /**
* This is the basis for all read-write mmap objects and should be preferred over * This is the basis for all read-write mmap objects and should be preferred over
* directly using basic_mmap. * directly using basic_mmap.
*/ */
template< template<typename CharT>
typename CharT, using basic_mmap_sink = basic_mmap<access_mode::read_write, CharT>;
typename CharTraits = std::char_traits<CharT>
> using basic_mmap_sink = basic_mmap<access_mode::read_write, CharT, CharTraits>;
/** These aliases should cover the most common use cases. */ /**
* These aliases cover the most common use cases, both representing a raw byte stream
* (either with a char or an unsigned char/uint8_t).
*/
using mmap_source = basic_mmap_source<char>; using mmap_source = basic_mmap_source<char>;
using ummap_source = basic_mmap_source<unsigned char>; using ummap_source = basic_mmap_source<unsigned char>;

View File

@ -6,6 +6,13 @@
#include <cassert> #include <cassert>
#include <system_error> #include <system_error>
int handle_error(const std::error_code& error)
{
const auto& errmsg = error.message();
std::printf("error mapping file: %s, exiting...\n", errmsg.c_str());
return error.value();
}
int main() int main()
{ {
const char* path = "test-file"; const char* path = "test-file";
@ -19,13 +26,8 @@ int main()
// Map the region of the file to which buffer was written. // Map the region of the file to which buffer was written.
std::error_code error; std::error_code error;
mio::mmap_source file_view = mio::make_mmap_source( mio::mmap_source file_view = mio::make_mmap_source(
path, 0, mio::use_full_file_size, error); path, 0, mio::map_entire_file, error);
if(error) if(error) { return handle_error(error); }
{
const auto& errmsg = error.message();
std::printf("error mapping file: %s, exiting...\n", errmsg.c_str());
return error.value();
}
assert(file_view.is_open()); assert(file_view.is_open());
assert(file_view.size() == buffer.size()); assert(file_view.size() == buffer.size());
@ -71,5 +73,14 @@ int main()
// Just making sure custom types compile. // Just making sure custom types compile.
mio::ummap_source ummap; mio::ummap_source ummap;
const auto page_size = mio::page_size();
// Now check if an mmap with a wider char type reports the correct size.
using u16mmap_source = mio::basic_mmap_source<char16_t>;
u16mmap_source wide_mmap = mio::make_mmap<u16mmap_source>(path, 0, page_size, error);
if(error) { return handle_error(error); }
assert(wide_mmap.size() == page_size / 2);
std::printf("all tests passed!\n"); std::printf("all tests passed!\n");
} }