This commit is contained in:
mandreyel 2018-04-15 19:02:52 +02:00
commit ecf20ef27f
4 changed files with 19 additions and 15 deletions

View File

@ -10,6 +10,8 @@ Because memory mapping is the best thing since sliced bread!
More seriously, the primary motivation for writing this library instead of using Boost.Iostreams, was the lack of support for establishing a memory mapping with an already open file handle/descriptor. This is possible with mio.
Furthermore, Boost.Iostreams' solution requires that the user pick offsets exactly at page boundaries, which is cumbersome and error prone. mio, on the other hand, manages this internally, accepting any offset and finding the nearest page boundary.
Albeit a minor nitpick, Boost.Iostreams implements memory mapped file IO with a `std::shared_ptr` to provide shared semantics, even if not needed, and the overhead of the heap allocation may be unnecessary and/or unwanted.
In mio, there are two classes to cover the two use-cases: one that is move-only (basically a zero-cost abstraction over the system specific mmapping functions), and the other that acts just like its Boost.Iostreams counterpart, with shared semantics.
@ -58,6 +60,7 @@ However, mio does not check whether the provided file descriptor has the same ac
#include <system_error> // for std::error_code
#include <cstdio> // for std::printf
#include <cassert>
#include <algorithm>
int handle_error(const std::error_code& error)
{
@ -74,8 +77,6 @@ int main()
mio::mmap_sink rw_mmap = mio::make_mmap_sink(
"file.txt", 0, mio::map_entire_file, error);
if (error) { return handle_error(error); }
assert(rw_mmap.is_open());
assert(!rw_mmap.empty());
// You can use any iterator based function.
std::fill(rw_mmap.begin(), rw_mmap.end(), 0);
@ -93,7 +94,7 @@ int main()
// Don't forget to flush changes to disk, which is NOT done by the destructor for
// more explicit control of this potentially expensive operation.
rw_mmap.sync(error);
if(error) { handle_error(error); }
if (error) { return handle_error(error); }
// We can then remove the mapping, after which rw_mmap will be in a default
// constructed state, i.e. this has the same effect as if the destructor had been
@ -110,7 +111,7 @@ int main()
}
```
`mio::basic_mmap` move-only, but if multiple copies to the same mapping is required, use `mio::basic_shared_mmap` which has `std::shared_ptr` semantics and has the same interface as `mio::basic_mmap`.
`mio::basic_mmap` is move-only, but if multiple copies to the same mapping are needed, use `mio::basic_shared_mmap` which has `std::shared_ptr` semantics and has the same interface as `mio::basic_mmap`.
```c++
#include <mio/shared_mmap.hpp>
@ -121,7 +122,7 @@ mio::shared_mmap_source shared_mmap4;
shared_mmap4.map("path", offset, size_to_map, error);
```
It's possible to define the type of a byte (which has to be the same width as `char`), though aliases for the most commonly ones are provided by default:
It's possible to define the type of a byte (which has to be the same width as `char`), though aliases for the most common ones are provided by default:
```c++
using mmap_source = basic_mmap_source<char>;
using ummap_source = basic_mmap_source<unsigned char>;
@ -135,7 +136,7 @@ using mmap_source = mio::basic_mmap_source<std::byte>;
using mmap_sink = mio::basic_mmap_sink<std::byte>;
```
You can query the underlying system's page allocation granularity by invoking `mio::page_size()`, which is located in `mio/page.hpp`.
Though generally not needed, since mio maps users requested offsets to page boundaries, you can query the underlying system's page allocation granularity by invoking `mio::page_size()`, which is located in `mio/page.hpp`.
### Installation
mio is a header-only library, so just copy the contents in `mio/include` into your system wide include path, such as `/usr/include`, or into your project's lib folder.

View File

@ -122,7 +122,7 @@ struct mmap_context
#endif
};
mmap_context memory_map(const file_handle_type file_handle, const int64_t offset,
inline mmap_context memory_map(const file_handle_type file_handle, const int64_t offset,
const int64_t length, const access_mode mode, std::error_code& error)
{
const int64_t aligned_offset = make_offset_page_aligned(offset);

View File

@ -151,7 +151,10 @@ public:
* Returns an iterator to the first requested byte, if a valid memory mapping
* exists, otherwise this function call is equivalent to invoking `end`.
*/
iterator begin() noexcept { return impl_.begin(); }
template<
access_mode A = AccessMode,
typename = typename std::enable_if<A == access_mode::write>::type
> iterator begin() noexcept { return impl_.begin(); }
const_iterator begin() const noexcept { return impl_.begin(); }
const_iterator cbegin() const noexcept { return impl_.cbegin(); }

View File

@ -36,7 +36,7 @@ int main()
// Don't forget to flush changes to disk, which is NOT done by the destructor for
// more explicit control of this potentially expensive operation.
rw_mmap.sync(error);
if(error) { handle_error(error); }
if (error) { return handle_error(error); }
// We can then remove the mapping, after which rw_mmap will be in a default
// constructed state, i.e. this has the same effect as if the destructor had been