mirror of
https://github.com/vimpunk/mio.git
synced 2025-12-06 08:46:51 +08:00
Merge pull request #49 from mandreyel/add-different-offset-tests
Add different offset tests
This commit is contained in:
commit
b9737f60c3
@ -180,11 +180,11 @@ public:
|
|||||||
size_type length() const noexcept { return length_; }
|
size_type length() const noexcept { return length_; }
|
||||||
size_type mapped_length() const noexcept { return mapped_length_; }
|
size_type mapped_length() const noexcept { return mapped_length_; }
|
||||||
|
|
||||||
/**
|
/** Returns the offset relative to the start of the mapping. */
|
||||||
* Returns the offset, relative to the file's start, at which the mapping was
|
size_type mapping_offset() const noexcept
|
||||||
* requested to be created.
|
{
|
||||||
*/
|
return mapped_length_ - length_;
|
||||||
size_type offset() const noexcept { return mapped_length_ - length_; }
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a pointer to the first requested byte, or `nullptr` if no memory mapping
|
* Returns a pointer to the first requested byte, or `nullptr` if no memory mapping
|
||||||
@ -362,12 +362,12 @@ private:
|
|||||||
typename = typename std::enable_if<A == access_mode::write>::type
|
typename = typename std::enable_if<A == access_mode::write>::type
|
||||||
> pointer get_mapping_start() noexcept
|
> pointer get_mapping_start() noexcept
|
||||||
{
|
{
|
||||||
return !data() ? nullptr : data() - offset();
|
return !data() ? nullptr : data() - mapping_offset();
|
||||||
}
|
}
|
||||||
|
|
||||||
const_pointer get_mapping_start() const noexcept
|
const_pointer get_mapping_start() const noexcept
|
||||||
{
|
{
|
||||||
return !data() ? nullptr : data() - offset();
|
return !data() ? nullptr : data() - mapping_offset();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -162,12 +162,6 @@ public:
|
|||||||
return pimpl_ ? pimpl_->mapped_length() : 0;
|
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
|
* Returns a pointer to the first requested byte, or `nullptr` if no memory mapping
|
||||||
* exists.
|
* exists.
|
||||||
|
|||||||
@ -155,15 +155,17 @@ private:
|
|||||||
// Points to the first requested byte, and not to the actual start of the mapping.
|
// Points to the first requested byte, and not to the actual start of the mapping.
|
||||||
pointer data_ = nullptr;
|
pointer data_ = nullptr;
|
||||||
|
|
||||||
// Length, in bytes, requested by user, which may not be the length of the full
|
// Length--in bytes--requested by user (which may not be the length of the
|
||||||
// mapping, and the entire length of the full mapping.
|
// full mapping) and the length of the full mapping.
|
||||||
size_type length_ = 0;
|
size_type length_ = 0;
|
||||||
size_type mapped_length_ = 0;
|
size_type mapped_length_ = 0;
|
||||||
|
|
||||||
// Letting user map a file using both an existing file handle and a path introcudes
|
// Letting user map a file using both an existing file handle and a path
|
||||||
// On POSIX, we only need a file handle to create a mapping, while on Windows
|
// introcudes some complexity (see `is_handle_internal_`).
|
||||||
// systems the file handle is necessary to retrieve a file mapping handle, but any
|
// On POSIX, we only need a file handle to create a mapping, while on
|
||||||
// subsequent operations on the mapped region must be done through the latter.
|
// 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;
|
handle_type file_handle_ = INVALID_HANDLE_VALUE;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
handle_type file_mapping_handle_ = INVALID_HANDLE_VALUE;
|
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
|
// 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
|
// 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
|
// provided path. For this reason, this flag is used to determine when to
|
||||||
// close file_handle_.
|
// close `file_handle_`.
|
||||||
bool is_handle_internal_;
|
bool is_handle_internal_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -257,11 +259,11 @@ public:
|
|||||||
size_type length() const noexcept { return length_; }
|
size_type length() const noexcept { return length_; }
|
||||||
size_type mapped_length() const noexcept { return mapped_length_; }
|
size_type mapped_length() const noexcept { return mapped_length_; }
|
||||||
|
|
||||||
/**
|
/** Returns the offset relative to the start of the mapping. */
|
||||||
* Returns the offset, relative to the file's start, at which the mapping was
|
size_type mapping_offset() const noexcept
|
||||||
* requested to be created.
|
{
|
||||||
*/
|
return mapped_length_ - length_;
|
||||||
size_type offset() const noexcept { return mapped_length_ - length_; }
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a pointer to the first requested byte, or `nullptr` if no memory mapping
|
* Returns a pointer to the first requested byte, or `nullptr` if no memory mapping
|
||||||
@ -439,12 +441,12 @@ private:
|
|||||||
typename = typename std::enable_if<A == access_mode::write>::type
|
typename = typename std::enable_if<A == access_mode::write>::type
|
||||||
> pointer get_mapping_start() noexcept
|
> pointer get_mapping_start() noexcept
|
||||||
{
|
{
|
||||||
return !data() ? nullptr : data() - offset();
|
return !data() ? nullptr : data() - mapping_offset();
|
||||||
}
|
}
|
||||||
|
|
||||||
const_pointer get_mapping_start() const noexcept
|
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<AccessMode, ByteT>::unmap()
|
|||||||
if(data_) { ::munmap(const_cast<pointer>(get_mapping_start()), mapped_length_); }
|
if(data_) { ::munmap(const_cast<pointer>(get_mapping_start()), mapped_length_); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// If file_handle_ was obtained by our opening it (when map is called with a path,
|
// If `file_handle_` was obtained by our opening it (when map is called with
|
||||||
// rather than an existing file handle), we need to close it, otherwise it must not
|
// a path, rather than an existing file handle), we need to close it,
|
||||||
// be closed as it may still be used outside this instance.
|
// otherwise it must not be closed as it may still be used outside this
|
||||||
|
// instance.
|
||||||
if(is_handle_internal_)
|
if(is_handle_internal_)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -1501,12 +1504,6 @@ public:
|
|||||||
return pimpl_ ? pimpl_->mapped_length() : 0;
|
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
|
* Returns a pointer to the first requested byte, or `nullptr` if no memory mapping
|
||||||
* exists.
|
* exists.
|
||||||
|
|||||||
127
test/test.cpp
127
test/test.cpp
@ -15,29 +15,32 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#endif
|
#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.
|
// Just make sure this compiles.
|
||||||
#ifdef CXX17
|
#ifdef CXX17
|
||||||
# include <cstddef>
|
# include <cstddef>
|
||||||
using mmap_source = mio::basic_mmap_source<std::byte>;
|
using mmap_source = mio::basic_mmap_source<std::byte>;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
template<class MMap>
|
||||||
|
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()
|
int main()
|
||||||
{
|
{
|
||||||
const char _path[] = "test-file";
|
std::error_code error;
|
||||||
|
|
||||||
// Make sure mio compiles with non-const char* strings too.
|
// Make sure mio compiles with non-const char* strings too.
|
||||||
|
const char _path[] = "test-file";
|
||||||
const int path_len = sizeof(_path);
|
const int path_len = sizeof(_path);
|
||||||
char* path = new char[path_len];
|
char* path = new char[path_len];
|
||||||
std::copy(_path, _path + path_len, path);
|
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.
|
// 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);
|
std::string buffer(file_size, 0);
|
||||||
// Start at first printable ASCII character.
|
// Start at first printable ASCII character.
|
||||||
char v = 33;
|
char v = 33;
|
||||||
@ -50,54 +53,26 @@ int main()
|
|||||||
v = 33;
|
v = 33;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ofstream file(path);
|
std::ofstream file(path);
|
||||||
file << buffer;
|
file << buffer;
|
||||||
file.close();
|
file.close();
|
||||||
|
|
||||||
const size_t offset = 300;
|
// Test whole file mapping.
|
||||||
assert(offset < buffer.size());
|
test_at_offset(buffer, path, 0, error);
|
||||||
|
if (error) { return handle_error(error); }
|
||||||
|
|
||||||
{
|
// Test starting from below the page size.
|
||||||
// Map the region of the file to which buffer was written.
|
test_at_offset(buffer, path, page_size - 3, error);
|
||||||
mio::mmap_source file_view = mio::make_mmap_source(
|
if (error) { return handle_error(error); }
|
||||||
path, offset, mio::map_entire_file, error);
|
|
||||||
if(error) { return handle_error(error); }
|
|
||||||
|
|
||||||
const size_t mapped_size = buffer.size() - offset; // 15834
|
// Test starting from above the page size.
|
||||||
assert(file_view.is_open());
|
test_at_offset(buffer, path, page_size + 3, error);
|
||||||
assert(file_view.size() == mapped_size);
|
if (error) { return handle_error(error); }
|
||||||
|
|
||||||
// Then verify that mmap's bytes correspond to that of buffer.
|
// Test starting from above the page size.
|
||||||
for(size_t buf_idx = offset, view_idx = 0;
|
test_at_offset(buffer, path, 2 * page_size + 3, error);
|
||||||
buf_idx < buffer.size() && view_idx < mapped_size;
|
if (error) { return handle_error(error); }
|
||||||
++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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
#define CHECK_INVALID_MMAP(m) do { \
|
#define CHECK_INVALID_MMAP(m) do { \
|
||||||
@ -155,3 +130,53 @@ int main()
|
|||||||
|
|
||||||
std::printf("all tests passed!\n");
|
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<class MMap>
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user