diff --git a/include/mio/mmap.hpp b/include/mio/mmap.hpp index ddb95b2..def559a 100644 --- a/include/mio/mmap.hpp +++ b/include/mio/mmap.hpp @@ -180,11 +180,11 @@ public: size_type length() const noexcept { return length_; } size_type mapped_length() const noexcept { return mapped_length_; } - /** - * Returns the offset, relative to the file's start, at which the mapping was - * requested to be created. - */ - size_type offset() const noexcept { return mapped_length_ - length_; } + /** Returns the offset relative to the start of the mapping. */ + size_type mapping_offset() const noexcept + { + return mapped_length_ - length_; + } /** * Returns a pointer to the first requested byte, or `nullptr` if no memory mapping @@ -362,12 +362,12 @@ private: typename = typename std::enable_if::type > pointer get_mapping_start() noexcept { - return !data() ? nullptr : data() - offset(); + return !data() ? nullptr : data() - mapping_offset(); } const_pointer get_mapping_start() const noexcept { - return !data() ? nullptr : data() - offset(); + return !data() ? nullptr : data() - mapping_offset(); } /** diff --git a/include/mio/shared_mmap.hpp b/include/mio/shared_mmap.hpp index b914c18..f125a59 100644 --- a/include/mio/shared_mmap.hpp +++ b/include/mio/shared_mmap.hpp @@ -162,12 +162,6 @@ public: return pimpl_ ? pimpl_->mapped_length() : 0; } - /** - * Returns the offset, relative to the file's start, at which the mapping was - * requested to be created. - */ - size_type offset() const noexcept { return pimpl_ ? pimpl_->offset() : 0; } - /** * Returns a pointer to the first requested byte, or `nullptr` if no memory mapping * exists. diff --git a/single_include/mio/mio.hpp b/single_include/mio/mio.hpp index 1d43307..b4b8cd5 100644 --- a/single_include/mio/mio.hpp +++ b/single_include/mio/mio.hpp @@ -155,15 +155,17 @@ private: // Points to the first requested byte, and not to the actual start of the mapping. pointer data_ = nullptr; - // Length, in bytes, requested by user, which may not be the length of the full - // mapping, and the entire length of the full mapping. + // Length--in bytes--requested by user (which may not be the length of the + // full mapping) and the length of the full mapping. size_type length_ = 0; size_type mapped_length_ = 0; - // Letting user map a file using both an existing file handle and a path introcudes - // On POSIX, we only need a file handle to create a mapping, while on Windows - // 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. + // Letting user map a file using both an existing file handle and a path + // introcudes some complexity (see `is_handle_internal_`). + // On POSIX, we only need a file handle to create a mapping, while on + // Windows 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. handle_type file_handle_ = INVALID_HANDLE_VALUE; #ifdef _WIN32 handle_type file_mapping_handle_ = INVALID_HANDLE_VALUE; @@ -173,7 +175,7 @@ private: // introcudes some complexity in that we must not close the file handle if // user provided it, but we must close it if we obtained it using the // provided path. For this reason, this flag is used to determine when to - // close file_handle_. + // close `file_handle_`. bool is_handle_internal_; public: @@ -257,11 +259,11 @@ public: size_type length() const noexcept { return length_; } size_type mapped_length() const noexcept { return mapped_length_; } - /** - * Returns the offset, relative to the file's start, at which the mapping was - * requested to be created. - */ - size_type offset() const noexcept { return mapped_length_ - length_; } + /** Returns the offset relative to the start of the mapping. */ + size_type mapping_offset() const noexcept + { + return mapped_length_ - length_; + } /** * Returns a pointer to the first requested byte, or `nullptr` if no memory mapping @@ -439,12 +441,12 @@ private: typename = typename std::enable_if::type > pointer get_mapping_start() noexcept { - return !data() ? nullptr : data() - offset(); + return !data() ? nullptr : data() - mapping_offset(); } const_pointer get_mapping_start() const noexcept { - return !data() ? nullptr : data() - offset(); + return !data() ? nullptr : data() - mapping_offset(); } /** @@ -1140,9 +1142,10 @@ void basic_mmap::unmap() if(data_) { ::munmap(const_cast(get_mapping_start()), mapped_length_); } #endif - // If file_handle_ was obtained by our opening it (when map is called with a path, - // rather than an existing file handle), we need to close it, otherwise it must not - // be closed as it may still be used outside this instance. + // If `file_handle_` was obtained by our opening it (when map is called with + // a path, rather than an existing file handle), we need to close it, + // otherwise it must not be closed as it may still be used outside this + // instance. if(is_handle_internal_) { #ifdef _WIN32 @@ -1501,12 +1504,6 @@ public: return pimpl_ ? pimpl_->mapped_length() : 0; } - /** - * Returns the offset, relative to the file's start, at which the mapping was - * requested to be created. - */ - size_type offset() const noexcept { return pimpl_ ? pimpl_->offset() : 0; } - /** * Returns a pointer to the first requested byte, or `nullptr` if no memory mapping * exists. diff --git a/test/test.cpp b/test/test.cpp index b0a9c24..82827f9 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -15,29 +15,32 @@ #include #endif -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(); -} - // Just make sure this compiles. #ifdef CXX17 # include using mmap_source = mio::basic_mmap_source; #endif +template +void test_at_offset(const MMap& file_view, const std::string& buffer, + const size_t offset); +void test_at_offset(const std::string& buffer, const char* path, + const size_t offset, std::error_code& error); +int handle_error(const std::error_code& error); + int main() { - const char _path[] = "test-file"; + std::error_code error; + // Make sure mio compiles with non-const char* strings too. + const char _path[] = "test-file"; const int path_len = sizeof(_path); char* path = new char[path_len]; std::copy(_path, _path + path_len, path); - std::error_code error; + + const auto page_size = mio::page_size(); // Fill buffer, then write it to file. - const int file_size = 0x4000 - 250; // 16134 + const int file_size = 4 * page_size - 250; // 16134, if page size is 4KiB std::string buffer(file_size, 0); // Start at first printable ASCII character. char v = 33; @@ -50,54 +53,26 @@ int main() v = 33; } } + std::ofstream file(path); file << buffer; file.close(); - const size_t offset = 300; - assert(offset < buffer.size()); + // Test whole file mapping. + test_at_offset(buffer, path, 0, error); + if (error) { return handle_error(error); } - { - // Map the region of the file to which buffer was written. - mio::mmap_source file_view = mio::make_mmap_source( - path, offset, mio::map_entire_file, error); - if(error) { return handle_error(error); } + // Test starting from below the page size. + test_at_offset(buffer, path, page_size - 3, error); + if (error) { return handle_error(error); } - const size_t mapped_size = buffer.size() - offset; // 15834 - assert(file_view.is_open()); - assert(file_view.size() == mapped_size); + // Test starting from above the page size. + test_at_offset(buffer, path, page_size + 3, error); + if (error) { return handle_error(error); } - // Then verify that mmap's bytes correspond to that of buffer. - for(size_t buf_idx = offset, view_idx = 0; - buf_idx < buffer.size() && view_idx < mapped_size; - ++buf_idx, ++view_idx) { - if(file_view[view_idx] != buffer[buf_idx]) { - std::printf("%luth byte mismatch: expected(%d) <> actual(%d)", - buf_idx, buffer[buf_idx], file_view[view_idx]); - std::cout << std::flush; - assert(0); - } - } - - // Turn file_view into a shared mmap. - mio::shared_mmap_source shared_file_view(std::move(file_view)); - - assert(!file_view.is_open()); - assert(shared_file_view.is_open()); - assert(shared_file_view.size() == mapped_size); - - // Then verify that shared_mmap's bytes correspond to that of buffer. - for(size_t buf_idx = offset, view_idx = 0; - buf_idx < buffer.size() && view_idx < mapped_size; - ++buf_idx, ++view_idx) { - if(shared_file_view[view_idx] != buffer[buf_idx]) { - std::printf("%luth byte mismatch: expected(%d) <> actual(%d)", - buf_idx, buffer[buf_idx], shared_file_view[view_idx]); - std::cout << std::flush; - assert(0); - } - } - } + // Test starting from above the page size. + test_at_offset(buffer, path, 2 * page_size + 3, error); + if (error) { return handle_error(error); } { #define CHECK_INVALID_MMAP(m) do { \ @@ -155,3 +130,53 @@ int main() std::printf("all tests passed!\n"); } + +void test_at_offset(const std::string& buffer, const char* path, + const size_t offset, std::error_code& error) +{ + // Sanity check. + assert(offset < buffer.size()); + + // Map the region of the file to which buffer was written. + mio::mmap_source file_view = mio::make_mmap_source( + path, offset, mio::map_entire_file, error); + if(error) { return; } + + assert(file_view.is_open()); + const size_t mapped_size = buffer.size() - offset; + assert(file_view.size() == mapped_size); + + test_at_offset(file_view, buffer, offset); + + // Turn file_view into a shared mmap. + mio::shared_mmap_source shared_file_view(std::move(file_view)); + assert(!file_view.is_open()); + assert(shared_file_view.is_open()); + assert(shared_file_view.size() == mapped_size); + + //test_at_offset(shared_file_view, buffer, offset); +} + +template +void test_at_offset(const MMap& file_view, const std::string& buffer, + const size_t offset) +{ + // Then verify that mmap's bytes correspond to that of buffer. + for(size_t buf_idx = offset, view_idx = 0; + buf_idx < buffer.size() && view_idx < file_view.size(); + ++buf_idx, ++view_idx) { + if(file_view[view_idx] != buffer[buf_idx]) { + std::printf("%luth byte mismatch: expected(%d) <> actual(%d)", + buf_idx, buffer[buf_idx], file_view[view_idx]); + std::cout << std::flush; + assert(0); + } + } +} + +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(); +}