68 static constexpr size_t map_entire_file = 0;
71 using file_handle_type =
void*;
73 using file_handle_type = int;
76 const inline file_handle_type invalid_handle = (file_handle_type)-1;
80 bool create_file(std::filesystem::path
const& path,
size_t size, std::error_code& error)
noexcept;
88 template <
typename VALUE_TYPE>
90 struct basic_mmap_base
92 static_assert(
sizeof(VALUE_TYPE) ==
sizeof(std::byte));
94 using value_type = VALUE_TYPE;
95 using size_type = size_t;
96 using reference = value_type&;
97 using const_reference =
const value_type&;
98 using pointer = value_type*;
99 using const_pointer =
const value_type*;
100 using difference_type = std::ptrdiff_t;
101 using iterator = pointer;
102 using const_iterator = const_pointer;
103 using reverse_iterator = std::reverse_iterator<iterator>;
104 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
105 using iterator_category = std::random_access_iterator_tag;
106 using handle_type = file_handle_type;
108 basic_mmap_base()
noexcept =
default;
109 basic_mmap_base(basic_mmap_base&& other) noexcept
110 : data_(std::exchange(other.data_,
nullptr))
111 , length_(std::exchange(other.length_, 0))
112 , mapped_length_(std::exchange(other.mapped_length_, 0))
113 , file_handle_(std::exchange(other.file_handle_, invalid_handle))
114 , file_mapping_handle_(std::exchange(other.file_mapping_handle_, invalid_handle))
118 [[nodiscard]] handle_type file_handle()
const noexcept {
return file_handle_; }
119 [[nodiscard]] handle_type mapping_handle()
const noexcept {
return file_mapping_handle_ == invalid_handle ? file_handle_ : file_mapping_handle_; }
121 [[nodiscard]]
bool is_open()
const noexcept {
return file_handle_ != invalid_handle; }
123 [[nodiscard]]
bool empty()
const noexcept {
return length() == 0; }
125 [[nodiscard]]
bool is_mapped()
const noexcept
128 return file_mapping_handle_ != invalid_handle;
134 template <
typename T = VALUE_TYPE>
135 [[nodiscard]] std::span<T const> to_span()
const noexcept {
return {
reinterpret_cast<T const*
>(data()), size() }; }
137 [[nodiscard]] size_type size()
const noexcept {
return length(); }
138 [[nodiscard]] size_type length()
const noexcept {
return length_; }
139 [[nodiscard]] size_type mapped_length()
const noexcept {
return mapped_length_; }
141 [[nodiscard]] size_type mapping_offset()
const noexcept
143 return mapped_length_ - length_;
146 [[nodiscard]] const_pointer data()
const noexcept {
return data_; }
148 [[nodiscard]] const_iterator begin()
const noexcept {
return data(); }
149 [[nodiscard]] const_iterator cbegin()
const noexcept {
return data(); }
151 [[nodiscard]] const_iterator end()
const noexcept {
return data() + length(); }
152 [[nodiscard]] const_iterator cend()
const noexcept {
return data() + length(); }
154 [[nodiscard]] const_reverse_iterator rbegin()
const noexcept
156 return const_reverse_iterator(end());
159 [[nodiscard]] const_reverse_iterator crbegin()
const noexcept
161 return const_reverse_iterator(end());
164 [[nodiscard]] const_reverse_iterator rend()
const noexcept
166 return const_reverse_iterator(begin());
168 [[nodiscard]] const_reverse_iterator crend()
const noexcept
170 return const_reverse_iterator(begin());
173 [[nodiscard]] const_reference operator[](
const size_type i)
const noexcept {
return data_[i]; }
175 void swap(basic_mmap_base& other)
noexcept
180 swap(data_, other.data_);
181 swap(file_handle_, other.file_handle_);
182 swap(file_mapping_handle_, other.file_mapping_handle_);
183 swap(length_, other.length_);
184 swap(mapped_length_, other.mapped_length_);
188 void unmap()
noexcept;
196 int64_t mapped_length;
197 file_handle_type file_mapping_handle;
200 pointer data_ =
nullptr;
202 size_type length_ = 0;
203 size_type mapped_length_ = 0;
205 handle_type file_handle_ = invalid_handle;
206 handle_type file_mapping_handle_ = invalid_handle;
208 const_pointer get_mapping_start()
const noexcept
210 return !data() ? nullptr : data() - mapping_offset();
215 template <
typename CRTP,
typename VALUE_TYPE = std::
byte>
218 using typename basic_mmap_base<VALUE_TYPE>::size_type;
219 using typename basic_mmap_base<VALUE_TYPE>::handle_type;
220 using typename basic_mmap_base<VALUE_TYPE>::pointer;
222 basic_mmap() noexcept = default;
223 basic_mmap(const std::filesystem::path& path, const size_type offset = 0, const
size_t length = map_entire_file)
225 std::error_code error;
226 map(path, offset, length, error);
227 if (error) {
throw std::system_error{ error }; }
229 basic_mmap(
const handle_type handle,
const size_type offset = 0,
const size_type length = map_entire_file)
231 std::error_code error;
232 map(handle, offset, length, error);
233 if (error) {
throw std::system_error{ error }; }
236 basic_mmap(
const basic_mmap&) =
delete;
237 basic_mmap(basic_mmap&&) noexcept = default;
238 basic_mmap& operator=(const basic_mmap&) = delete;
239 basic_mmap& operator=(basic_mmap&& other) noexcept
245 this->data_ = std::exchange(other.data_,
nullptr);
246 this->length_ = std::exchange(other.length_, 0);
247 this->mapped_length_ = std::exchange(other.mapped_length_, 0);
248 this->file_handle_ = std::exchange(other.file_handle_, invalid_handle);
249 this->file_mapping_handle_ = std::exchange(other.file_mapping_handle_, invalid_handle);
254 ~basic_mmap() noexcept
256 static_cast<CRTP*
>(
this)->conditional_sync();
262 void map(
const std::filesystem::path& path,
const size_type offset,
const size_type length, std::error_code& error)
noexcept
267 error = std::make_error_code(std::errc::invalid_argument);
272 const auto file_size = std::filesystem::file_size(path, error);
278 error = std::make_error_code(std::errc::file_too_large);
283 const auto handle =
static_cast<CRTP*
>(
this)->open_file(path, error);
288 if (handle == invalid_handle)
290 error = std::make_error_code(std::errc::bad_file_descriptor);
294 if (offset + length > file_size)
296 error = std::make_error_code(std::errc::invalid_argument);
300 const auto ctx =
static_cast<CRTP*
>(
this)->memory_map(handle, offset, length == map_entire_file ? (file_size - offset) : length, error);
310 this->file_handle_ = handle;
311 this->data_ =
reinterpret_cast<pointer
>(ctx.data);
312 this->length_ = ctx.length;
313 this->mapped_length_ = ctx.mapped_length;
314 this->file_mapping_handle_ = ctx.file_mapping_handle;
318 void map(
const std::filesystem::path& path, std::error_code& error)
noexcept
320 this->map(path, 0, map_entire_file, error);
327 template <
typename VALUE_TYPE = std::
byte>
328 struct mmap_source :
public basic_mmap<mmap_source<VALUE_TYPE>, VALUE_TYPE>
331 using typename basic_mmap<mmap_source<VALUE_TYPE>, VALUE_TYPE>::mmap_context;
333 template <
typename VALUE_TYPE_>
334 friend mmap_source<VALUE_TYPE_> make_mmap_source(
const std::filesystem::path& path,
typename mmap_source<VALUE_TYPE_>::size_type offset,
typename mmap_source<VALUE_TYPE_>::size_type length, std::error_code& error)
noexcept;
336 operator std::basic_string_view<VALUE_TYPE>()
const noexcept
338 return std::basic_string_view<VALUE_TYPE>{ this->data(), this->size() };
343 friend struct basic_mmap<
mmap_source<VALUE_TYPE>, VALUE_TYPE>;
345 static file_handle_type open_file(
const std::filesystem::path& path, std::error_code& error)
noexcept;
347 static mmap_context memory_map(
const file_handle_type file_handle,
const int64_t offset,
const int64_t length, std::error_code& error)
noexcept;
349 void conditional_sync() {}
359 template <
typename VALUE_TYPE = std::
byte>
360 struct mmap_sink :
public basic_mmap<mmap_sink<VALUE_TYPE>, VALUE_TYPE>
363 using typename basic_mmap<mmap_sink<VALUE_TYPE>, VALUE_TYPE>::reference;
364 using typename basic_mmap<mmap_sink<VALUE_TYPE>, VALUE_TYPE>::size_type;
365 using typename basic_mmap<mmap_sink<VALUE_TYPE>, VALUE_TYPE>::mmap_context;
366 using typename basic_mmap<mmap_sink<VALUE_TYPE>, VALUE_TYPE>::pointer;
367 using typename basic_mmap<mmap_sink<VALUE_TYPE>, VALUE_TYPE>::iterator;
368 using typename basic_mmap<mmap_sink<VALUE_TYPE>, VALUE_TYPE>::reverse_iterator;
371 [[nodiscard]] reference operator[](
const size_type i)
const noexcept {
return this->data_[i]; }
376 [[nodiscard]] pointer data()
noexcept {
return this->data_; }
379 [[nodiscard]] iterator begin()
noexcept {
return this->data(); }
382 [[nodiscard]] iterator end()
noexcept {
return this->data() + this->length(); }
385 [[nodiscard]] reverse_iterator rbegin()
noexcept {
return reverse_iterator(this->end()); }
388 [[nodiscard]] reverse_iterator rend()
noexcept {
return reverse_iterator(this->begin()); }
390 void sync(std::error_code& error)
noexcept;
394 friend struct basic_mmap<
mmap_sink<VALUE_TYPE>, VALUE_TYPE>;
396 static file_handle_type open_file(
const std::filesystem::path& path, std::error_code& error)
noexcept;
398 static mmap_context memory_map(
const file_handle_type file_handle,
const int64_t offset,
const int64_t length, std::error_code& error)
noexcept;
400 pointer get_mapping_start()
noexcept
402 return !this->data() ? nullptr : this->data() - this->mapping_offset();
405 void conditional_sync()
412 template <
typename VALUE_TYPE =
char>
413 [[nodiscard]]
mmap_source<VALUE_TYPE> make_mmap_source(
const std::filesystem::path& path,
typename mmap_source<VALUE_TYPE>::size_type offset,
typename mmap_source<VALUE_TYPE>::size_type length, std::error_code& error)
noexcept
416 mmap.map(path, offset, length, error);
420 template <
typename VALUE_TYPE =
char>
421 [[nodiscard]] mmap_source<VALUE_TYPE> make_mmap_source(
const std::filesystem::path& path, std::error_code& error)
noexcept
423 return make_mmap_source<VALUE_TYPE>(path, 0, map_entire_file, error);
426 template <
typename VALUE_TYPE =
char>
427 [[nodiscard]]
mmap_source<VALUE_TYPE> make_mmap_source(
const std::filesystem::path& path,
typename mmap_source<VALUE_TYPE>::size_type offset,
typename mmap_source<VALUE_TYPE>::size_type length)
432 template <
typename VALUE_TYPE =
char>
435 return make_mmap_source<VALUE_TYPE>(path, 0, map_entire_file);
438 template <
typename VALUE_TYPE>
439 [[nodiscard]]
mmap_sink<VALUE_TYPE> make_mmap_sink(
const std::filesystem::path& path,
typename mmap_sink<VALUE_TYPE>::size_type offset,
typename mmap_sink<VALUE_TYPE>::size_type length, std::error_code& error)
noexcept
441 if (!detail::create_file(path, offset + length, error))
445 mmap.map(path, offset, length, error);
449 template <
typename VALUE_TYPE>
450 [[nodiscard]]
mmap_sink<VALUE_TYPE> make_mmap_sink(
const std::filesystem::path& path, std::error_code& error)
noexcept
452 return make_mmap_sink<VALUE_TYPE>(path, 0, map_entire_file, error);
455 template <
typename VALUE_TYPE>
456 [[nodiscard]]
mmap_sink<VALUE_TYPE> make_mmap_sink(
const std::filesystem::path& path,
typename mmap_sink<VALUE_TYPE>::size_type offset,
typename mmap_sink<VALUE_TYPE>::size_type length)
458 std::error_code error;
459 if (!detail::create_file(path, offset + length, error))
465 template <
typename VALUE_TYPE>
468 return make_mmap_sink<VALUE_TYPE>(path, 0, map_entire_file);
474#ifdef GHASSANPL_MMAP_IMPL
475#include "mmap_impl.h"
Primary namespace for everything in this library.
Base for mmap_source and mmap_sink with a specific value type.
A read-write view over a file.
A read-only memory view over a file.