pyxcp 0.25.5__cp312-cp312-macosx_11_0_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. pyxcp/__init__.py +20 -0
  2. pyxcp/aml/EtasCANMonitoring.a2l +82 -0
  3. pyxcp/aml/EtasCANMonitoring.aml +67 -0
  4. pyxcp/aml/XCP_Common.aml +408 -0
  5. pyxcp/aml/XCPonCAN.aml +78 -0
  6. pyxcp/aml/XCPonEth.aml +33 -0
  7. pyxcp/aml/XCPonFlx.aml +113 -0
  8. pyxcp/aml/XCPonSxI.aml +66 -0
  9. pyxcp/aml/XCPonUSB.aml +106 -0
  10. pyxcp/aml/ifdata_CAN.a2l +20 -0
  11. pyxcp/aml/ifdata_Eth.a2l +11 -0
  12. pyxcp/aml/ifdata_Flx.a2l +94 -0
  13. pyxcp/aml/ifdata_SxI.a2l +13 -0
  14. pyxcp/aml/ifdata_USB.a2l +81 -0
  15. pyxcp/asam/__init__.py +0 -0
  16. pyxcp/asam/types.py +131 -0
  17. pyxcp/asamkeydll +0 -0
  18. pyxcp/asamkeydll.c +116 -0
  19. pyxcp/asamkeydll.sh +2 -0
  20. pyxcp/checksum.py +732 -0
  21. pyxcp/cmdline.py +71 -0
  22. pyxcp/config/__init__.py +1257 -0
  23. pyxcp/config/legacy.py +120 -0
  24. pyxcp/constants.py +47 -0
  25. pyxcp/cpp_ext/__init__.py +0 -0
  26. pyxcp/cpp_ext/aligned_buffer.hpp +168 -0
  27. pyxcp/cpp_ext/bin.hpp +105 -0
  28. pyxcp/cpp_ext/blockmem.hpp +58 -0
  29. pyxcp/cpp_ext/cpp_ext.cpython-310-darwin.so +0 -0
  30. pyxcp/cpp_ext/cpp_ext.cpython-311-darwin.so +0 -0
  31. pyxcp/cpp_ext/cpp_ext.cpython-312-darwin.so +0 -0
  32. pyxcp/cpp_ext/daqlist.hpp +374 -0
  33. pyxcp/cpp_ext/event.hpp +67 -0
  34. pyxcp/cpp_ext/extension_wrapper.cpp +208 -0
  35. pyxcp/cpp_ext/framing.hpp +360 -0
  36. pyxcp/cpp_ext/helper.hpp +280 -0
  37. pyxcp/cpp_ext/mcobject.hpp +248 -0
  38. pyxcp/cpp_ext/sxi_framing.hpp +332 -0
  39. pyxcp/cpp_ext/tsqueue.hpp +46 -0
  40. pyxcp/daq_stim/__init__.py +291 -0
  41. pyxcp/daq_stim/optimize/__init__.py +67 -0
  42. pyxcp/daq_stim/optimize/binpacking.py +41 -0
  43. pyxcp/daq_stim/scheduler.cpp +62 -0
  44. pyxcp/daq_stim/scheduler.hpp +75 -0
  45. pyxcp/daq_stim/stim.cpp +13 -0
  46. pyxcp/daq_stim/stim.cpython-310-darwin.so +0 -0
  47. pyxcp/daq_stim/stim.cpython-311-darwin.so +0 -0
  48. pyxcp/daq_stim/stim.cpython-312-darwin.so +0 -0
  49. pyxcp/daq_stim/stim.hpp +604 -0
  50. pyxcp/daq_stim/stim_wrapper.cpp +50 -0
  51. pyxcp/dllif.py +100 -0
  52. pyxcp/errormatrix.py +878 -0
  53. pyxcp/examples/conf_can.toml +19 -0
  54. pyxcp/examples/conf_can_user.toml +16 -0
  55. pyxcp/examples/conf_can_vector.json +11 -0
  56. pyxcp/examples/conf_can_vector.toml +11 -0
  57. pyxcp/examples/conf_eth.toml +9 -0
  58. pyxcp/examples/conf_nixnet.json +20 -0
  59. pyxcp/examples/conf_socket_can.toml +12 -0
  60. pyxcp/examples/run_daq.py +165 -0
  61. pyxcp/examples/xcp_policy.py +60 -0
  62. pyxcp/examples/xcp_read_benchmark.py +38 -0
  63. pyxcp/examples/xcp_skel.py +48 -0
  64. pyxcp/examples/xcp_unlock.py +36 -0
  65. pyxcp/examples/xcp_user_supplied_driver.py +43 -0
  66. pyxcp/examples/xcphello.py +65 -0
  67. pyxcp/examples/xcphello_recorder.py +107 -0
  68. pyxcp/master/__init__.py +10 -0
  69. pyxcp/master/errorhandler.py +677 -0
  70. pyxcp/master/master.py +2641 -0
  71. pyxcp/py.typed +0 -0
  72. pyxcp/recorder/.idea/.gitignore +8 -0
  73. pyxcp/recorder/.idea/misc.xml +4 -0
  74. pyxcp/recorder/.idea/modules.xml +8 -0
  75. pyxcp/recorder/.idea/recorder.iml +6 -0
  76. pyxcp/recorder/.idea/sonarlint/issuestore/3/8/3808afc69ac1edb9d760000a2f137335b1b99728 +7 -0
  77. pyxcp/recorder/.idea/sonarlint/issuestore/9/a/9a2aa4db38d3115ed60da621e012c0efc0172aae +0 -0
  78. pyxcp/recorder/.idea/sonarlint/issuestore/b/4/b49006702b459496a8e8c94ebe60947108361b91 +0 -0
  79. pyxcp/recorder/.idea/sonarlint/issuestore/index.pb +7 -0
  80. pyxcp/recorder/.idea/sonarlint/securityhotspotstore/3/8/3808afc69ac1edb9d760000a2f137335b1b99728 +0 -0
  81. pyxcp/recorder/.idea/sonarlint/securityhotspotstore/9/a/9a2aa4db38d3115ed60da621e012c0efc0172aae +0 -0
  82. pyxcp/recorder/.idea/sonarlint/securityhotspotstore/b/4/b49006702b459496a8e8c94ebe60947108361b91 +0 -0
  83. pyxcp/recorder/.idea/sonarlint/securityhotspotstore/index.pb +7 -0
  84. pyxcp/recorder/.idea/vcs.xml +10 -0
  85. pyxcp/recorder/__init__.py +96 -0
  86. pyxcp/recorder/build_clang.cmd +1 -0
  87. pyxcp/recorder/build_clang.sh +2 -0
  88. pyxcp/recorder/build_gcc.cmd +1 -0
  89. pyxcp/recorder/build_gcc.sh +2 -0
  90. pyxcp/recorder/build_gcc_arm.sh +2 -0
  91. pyxcp/recorder/converter/__init__.py +444 -0
  92. pyxcp/recorder/lz4.c +2829 -0
  93. pyxcp/recorder/lz4.h +879 -0
  94. pyxcp/recorder/lz4hc.c +2041 -0
  95. pyxcp/recorder/lz4hc.h +413 -0
  96. pyxcp/recorder/mio.hpp +1714 -0
  97. pyxcp/recorder/reader.hpp +138 -0
  98. pyxcp/recorder/reco.py +278 -0
  99. pyxcp/recorder/recorder.rst +0 -0
  100. pyxcp/recorder/rekorder.cpp +59 -0
  101. pyxcp/recorder/rekorder.cpython-310-darwin.so +0 -0
  102. pyxcp/recorder/rekorder.cpython-311-darwin.so +0 -0
  103. pyxcp/recorder/rekorder.cpython-312-darwin.so +0 -0
  104. pyxcp/recorder/rekorder.hpp +274 -0
  105. pyxcp/recorder/setup.py +41 -0
  106. pyxcp/recorder/test_reko.py +34 -0
  107. pyxcp/recorder/unfolder.hpp +1354 -0
  108. pyxcp/recorder/wrap.cpp +184 -0
  109. pyxcp/recorder/writer.hpp +302 -0
  110. pyxcp/scripts/__init__.py +0 -0
  111. pyxcp/scripts/pyxcp_probe_can_drivers.py +20 -0
  112. pyxcp/scripts/xcp_examples.py +64 -0
  113. pyxcp/scripts/xcp_fetch_a2l.py +40 -0
  114. pyxcp/scripts/xcp_id_scanner.py +18 -0
  115. pyxcp/scripts/xcp_info.py +159 -0
  116. pyxcp/scripts/xcp_profile.py +26 -0
  117. pyxcp/scripts/xmraw_converter.py +31 -0
  118. pyxcp/stim/__init__.py +0 -0
  119. pyxcp/tests/test_asam_types.py +24 -0
  120. pyxcp/tests/test_binpacking.py +186 -0
  121. pyxcp/tests/test_can.py +1324 -0
  122. pyxcp/tests/test_checksum.py +95 -0
  123. pyxcp/tests/test_daq.py +193 -0
  124. pyxcp/tests/test_daq_opt.py +426 -0
  125. pyxcp/tests/test_frame_padding.py +156 -0
  126. pyxcp/tests/test_framing.py +262 -0
  127. pyxcp/tests/test_master.py +2116 -0
  128. pyxcp/tests/test_transport.py +177 -0
  129. pyxcp/tests/test_utils.py +30 -0
  130. pyxcp/timing.py +60 -0
  131. pyxcp/transport/__init__.py +13 -0
  132. pyxcp/transport/base.py +484 -0
  133. pyxcp/transport/base_transport.hpp +0 -0
  134. pyxcp/transport/can.py +660 -0
  135. pyxcp/transport/eth.py +254 -0
  136. pyxcp/transport/hdf5_policy.py +167 -0
  137. pyxcp/transport/sxi.py +209 -0
  138. pyxcp/transport/transport_ext.cpython-310-darwin.so +0 -0
  139. pyxcp/transport/transport_ext.cpython-311-darwin.so +0 -0
  140. pyxcp/transport/transport_ext.cpython-312-darwin.so +0 -0
  141. pyxcp/transport/transport_ext.hpp +214 -0
  142. pyxcp/transport/transport_wrapper.cpp +249 -0
  143. pyxcp/transport/usb_transport.py +229 -0
  144. pyxcp/types.py +987 -0
  145. pyxcp/utils/__init__.py +127 -0
  146. pyxcp/utils/cli.py +78 -0
  147. pyxcp/vector/__init__.py +0 -0
  148. pyxcp/vector/map.py +82 -0
  149. pyxcp-0.25.5.dist-info/METADATA +341 -0
  150. pyxcp-0.25.5.dist-info/RECORD +153 -0
  151. pyxcp-0.25.5.dist-info/WHEEL +6 -0
  152. pyxcp-0.25.5.dist-info/entry_points.txt +9 -0
  153. pyxcp-0.25.5.dist-info/licenses/LICENSE +165 -0
pyxcp/recorder/mio.hpp ADDED
@@ -0,0 +1,1714 @@
1
+ /* Copyright 2017 https://github.com/mandreyel
2
+ *
3
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this
4
+ * software and associated documentation files (the "Software"), to deal in the Software
5
+ * without restriction, including without limitation the rights to use, copy, modify,
6
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
7
+ * permit persons to whom the Software is furnished to do so, subject to the following
8
+ * conditions:
9
+ *
10
+ * The above copyright notice and this permission notice shall be included in all copies
11
+ * or substantial portions of the Software.
12
+ *
13
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
14
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
15
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
16
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
17
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
18
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19
+ */
20
+
21
+ #ifndef MIO_MMAP_HEADER
22
+ #define MIO_MMAP_HEADER
23
+
24
+ // #include "mio/page.hpp"
25
+ /* Copyright 2017 https://github.com/mandreyel
26
+ *
27
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this
28
+ * software and associated documentation files (the "Software"), to deal in the Software
29
+ * without restriction, including without limitation the rights to use, copy, modify,
30
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
31
+ * permit persons to whom the Software is furnished to do so, subject to the following
32
+ * conditions:
33
+ *
34
+ * The above copyright notice and this permission notice shall be included in all copies
35
+ * or substantial portions of the Software.
36
+ *
37
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
38
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
39
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
40
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
41
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
42
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
43
+ */
44
+
45
+ #ifndef MIO_PAGE_HEADER
46
+ #define MIO_PAGE_HEADER
47
+
48
+ #ifdef _WIN32
49
+ #include <windows.h>
50
+ #else
51
+ #include <unistd.h>
52
+ #endif
53
+
54
+ namespace mio {
55
+
56
+ /**
57
+ * This is used by `basic_mmap` to determine whether to create a read-only or
58
+ * a read-write memory mapping.
59
+ */
60
+ enum class access_mode {
61
+ read,
62
+ write
63
+ };
64
+
65
+ /**
66
+ * Determines the operating system's page allocation granularity.
67
+ *
68
+ * On the first call to this function, it invokes the operating system specific syscall
69
+ * to determine the page size, caches the value, and returns it. Any subsequent call to
70
+ * this function serves the cached value, so no further syscalls are made.
71
+ */
72
+ inline size_t page_size() {
73
+ static const size_t page_size = [] {
74
+ #ifdef _WIN32
75
+ SYSTEM_INFO SystemInfo;
76
+ GetSystemInfo(&SystemInfo);
77
+ return SystemInfo.dwAllocationGranularity;
78
+ #else
79
+ return sysconf(_SC_PAGE_SIZE);
80
+ #endif
81
+ }();
82
+ return page_size;
83
+ }
84
+
85
+ /**
86
+ * Alligns `offset` to the operating's system page size such that it subtracts the
87
+ * difference until the nearest page boundary before `offset`, or does nothing if
88
+ * `offset` is already page aligned.
89
+ */
90
+ inline size_t make_offset_page_aligned(size_t offset) noexcept {
91
+ const size_t page_size_ = page_size();
92
+ // Use integer division to round down to the nearest page alignment.
93
+ return offset / page_size_ * page_size_;
94
+ }
95
+
96
+ } // namespace mio
97
+
98
+ #endif // MIO_PAGE_HEADER
99
+
100
+ #include <cstdint>
101
+ #include <iterator>
102
+ #include <string>
103
+ #include <system_error>
104
+
105
+ #ifdef _WIN32
106
+ #ifndef WIN32_LEAN_AND_MEAN
107
+ #define WIN32_LEAN_AND_MEAN
108
+ #endif // WIN32_LEAN_AND_MEAN
109
+ #include <windows.h>
110
+ #else // ifdef _WIN32
111
+ #define INVALID_HANDLE_VALUE -1
112
+ #endif // ifdef _WIN32
113
+
114
+ namespace mio {
115
+
116
+ // This value may be provided as the `length` parameter to the constructor or
117
+ // `map`, in which case a memory mapping of the entire file is created.
118
+ enum {
119
+ map_entire_file = 0
120
+ };
121
+
122
+ #ifdef _WIN32
123
+ using file_handle_type = HANDLE;
124
+ #else
125
+ using file_handle_type = int;
126
+ #endif
127
+
128
+ // This value represents an invalid file handle type. This can be used to
129
+ // determine whether `basic_mmap::file_handle` is valid, for example.
130
+ const static file_handle_type invalid_handle = INVALID_HANDLE_VALUE;
131
+
132
+ template<access_mode AccessMode, typename ByteT>
133
+ struct basic_mmap {
134
+ using value_type = ByteT;
135
+ using size_type = size_t;
136
+ using reference = value_type&;
137
+ using const_reference = const value_type&;
138
+ using pointer = value_type*;
139
+ using const_pointer = const value_type*;
140
+ using difference_type = std::ptrdiff_t;
141
+ using iterator = pointer;
142
+ using const_iterator = const_pointer;
143
+ using reverse_iterator = std::reverse_iterator<iterator>;
144
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
145
+ using iterator_category = std::random_access_iterator_tag;
146
+ using handle_type = file_handle_type;
147
+
148
+ static_assert(sizeof(ByteT) == sizeof(char), "ByteT must be the same size as char.");
149
+
150
+ private:
151
+
152
+ // Points to the first requested byte, and not to the actual start of the mapping.
153
+ pointer data_ = nullptr;
154
+
155
+ // Length--in bytes--requested by user (which may not be the length of the
156
+ // full mapping) and the length of the full mapping.
157
+ size_type length_ = 0;
158
+ size_type mapped_length_ = 0;
159
+
160
+ // Letting user map a file using both an existing file handle and a path
161
+ // introcudes some complexity (see `is_handle_internal_`).
162
+ // On POSIX, we only need a file handle to create a mapping, while on
163
+ // Windows systems the file handle is necessary to retrieve a file mapping
164
+ // handle, but any subsequent operations on the mapped region must be done
165
+ // through the latter.
166
+ handle_type file_handle_ = INVALID_HANDLE_VALUE;
167
+ #ifdef _WIN32
168
+ handle_type file_mapping_handle_ = INVALID_HANDLE_VALUE;
169
+ #endif
170
+
171
+ // Letting user map a file using both an existing file handle and a path
172
+ // introcudes some complexity in that we must not close the file handle if
173
+ // user provided it, but we must close it if we obtained it using the
174
+ // provided path. For this reason, this flag is used to determine when to
175
+ // close `file_handle_`.
176
+ bool is_handle_internal_;
177
+
178
+ public:
179
+
180
+ /**
181
+ * The default constructed mmap object is in a non-mapped state, that is,
182
+ * any operation that attempts to access nonexistent underlying data will
183
+ * result in undefined behaviour/segmentation faults.
184
+ */
185
+ basic_mmap() = default;
186
+
187
+ #ifdef __cpp_exceptions
188
+ /**
189
+ * The same as invoking the `map` function, except any error that may occur
190
+ * while establishing the mapping is wrapped in a `std::system_error` and is
191
+ * thrown.
192
+ */
193
+ template<typename String>
194
+ basic_mmap(const String& path, const size_type offset = 0, const size_type length = map_entire_file) {
195
+ std::error_code error;
196
+ map(path, offset, length, error);
197
+ if (error) {
198
+ throw std::system_error(error);
199
+ }
200
+ }
201
+
202
+ /**
203
+ * The same as invoking the `map` function, except any error that may occur
204
+ * while establishing the mapping is wrapped in a `std::system_error` and is
205
+ * thrown.
206
+ */
207
+ basic_mmap(const handle_type handle, const size_type offset = 0, const size_type length = map_entire_file) {
208
+ std::error_code error;
209
+ map(handle, offset, length, error);
210
+ if (error) {
211
+ throw std::system_error(error);
212
+ }
213
+ }
214
+ #endif // __cpp_exceptions
215
+
216
+ /**
217
+ * `basic_mmap` has single-ownership semantics, so transferring ownership
218
+ * may only be accomplished by moving the object.
219
+ */
220
+ basic_mmap(const basic_mmap&) = delete;
221
+ basic_mmap(basic_mmap&&);
222
+ basic_mmap& operator=(const basic_mmap&) = delete;
223
+ basic_mmap& operator=(basic_mmap&&);
224
+
225
+ /**
226
+ * If this is a read-write mapping, the destructor invokes sync. Regardless
227
+ * of the access mode, unmap is invoked as a final step.
228
+ */
229
+ ~basic_mmap();
230
+
231
+ /**
232
+ * On UNIX systems 'file_handle' and 'mapping_handle' are the same. On Windows,
233
+ * however, a mapped region of a file gets its own handle, which is returned by
234
+ * 'mapping_handle'.
235
+ */
236
+ handle_type file_handle() const noexcept {
237
+ return file_handle_;
238
+ }
239
+
240
+ handle_type mapping_handle() const noexcept;
241
+
242
+ /** Returns whether a valid memory mapping has been created. */
243
+ bool is_open() const noexcept {
244
+ return file_handle_ != invalid_handle;
245
+ }
246
+
247
+ /**
248
+ * Returns true if no mapping was established, that is, conceptually the
249
+ * same as though the length that was mapped was 0. This function is
250
+ * provided so that this class has Container semantics.
251
+ */
252
+ bool empty() const noexcept {
253
+ return length() == 0;
254
+ }
255
+
256
+ /** Returns true if a mapping was established. */
257
+ bool is_mapped() const noexcept;
258
+
259
+ /**
260
+ * `size` and `length` both return the logical length, i.e. the number of bytes
261
+ * user requested to be mapped, while `mapped_length` returns the actual number of
262
+ * bytes that were mapped which is a multiple of the underlying operating system's
263
+ * page allocation granularity.
264
+ */
265
+ size_type size() const noexcept {
266
+ return length();
267
+ }
268
+
269
+ size_type length() const noexcept {
270
+ return length_;
271
+ }
272
+
273
+ size_type mapped_length() const noexcept {
274
+ return mapped_length_;
275
+ }
276
+
277
+ /** Returns the offset relative to the start of the mapping. */
278
+ size_type mapping_offset() const noexcept {
279
+ return mapped_length_ - length_;
280
+ }
281
+
282
+ /**
283
+ * Returns a pointer to the first requested byte, or `nullptr` if no memory mapping
284
+ * exists.
285
+ */
286
+ template< access_mode A = AccessMode, typename = typename std::enable_if<A == access_mode::write>::type >
287
+ pointer data() noexcept {
288
+ return data_;
289
+ }
290
+
291
+ const_pointer data() const noexcept {
292
+ return data_;
293
+ }
294
+
295
+ /**
296
+ * Returns an iterator to the first requested byte, if a valid memory mapping
297
+ * exists, otherwise this function call is undefined behaviour.
298
+ */
299
+ template< access_mode A = AccessMode, typename = typename std::enable_if<A == access_mode::write>::type >
300
+ iterator begin() noexcept {
301
+ return data();
302
+ }
303
+
304
+ const_iterator begin() const noexcept {
305
+ return data();
306
+ }
307
+
308
+ const_iterator cbegin() const noexcept {
309
+ return data();
310
+ }
311
+
312
+ /**
313
+ * Returns an iterator one past the last requested byte, if a valid memory mapping
314
+ * exists, otherwise this function call is undefined behaviour.
315
+ */
316
+ template< access_mode A = AccessMode, typename = typename std::enable_if<A == access_mode::write>::type >
317
+ iterator end() noexcept {
318
+ return data() + length();
319
+ }
320
+
321
+ const_iterator end() const noexcept {
322
+ return data() + length();
323
+ }
324
+
325
+ const_iterator cend() const noexcept {
326
+ return data() + length();
327
+ }
328
+
329
+ /**
330
+ * Returns a reverse iterator to the last memory mapped byte, if a valid
331
+ * memory mapping exists, otherwise this function call is undefined
332
+ * behaviour.
333
+ */
334
+ template< access_mode A = AccessMode, typename = typename std::enable_if<A == access_mode::write>::type >
335
+ reverse_iterator rbegin() noexcept {
336
+ return reverse_iterator(end());
337
+ }
338
+
339
+ const_reverse_iterator rbegin() const noexcept {
340
+ return const_reverse_iterator(end());
341
+ }
342
+
343
+ const_reverse_iterator crbegin() const noexcept {
344
+ return const_reverse_iterator(end());
345
+ }
346
+
347
+ /**
348
+ * Returns a reverse iterator past the first mapped byte, if a valid memory
349
+ * mapping exists, otherwise this function call is undefined behaviour.
350
+ */
351
+ template< access_mode A = AccessMode, typename = typename std::enable_if<A == access_mode::write>::type >
352
+ reverse_iterator rend() noexcept {
353
+ return reverse_iterator(begin());
354
+ }
355
+
356
+ const_reverse_iterator rend() const noexcept {
357
+ return const_reverse_iterator(begin());
358
+ }
359
+
360
+ const_reverse_iterator crend() const noexcept {
361
+ return const_reverse_iterator(begin());
362
+ }
363
+
364
+ /**
365
+ * Returns a reference to the `i`th byte from the first requested byte (as returned
366
+ * by `data`). If this is invoked when no valid memory mapping has been created
367
+ * prior to this call, undefined behaviour ensues.
368
+ */
369
+ reference operator[](const size_type i) noexcept {
370
+ return data_[i];
371
+ }
372
+
373
+ const_reference operator[](const size_type i) const noexcept {
374
+ return data_[i];
375
+ }
376
+
377
+ /**
378
+ * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the
379
+ * reason is reported via `error` and the object remains in a state as if this
380
+ * function hadn't been called.
381
+ *
382
+ * `path`, which must be a path to an existing file, is used to retrieve a file
383
+ * handle (which is closed when the object destructs or `unmap` is called), which is
384
+ * then used to memory map the requested region. Upon failure, `error` is set to
385
+ * indicate the reason and the object remains in an unmapped state.
386
+ *
387
+ * `offset` is the number of bytes, relative to the start of the file, where the
388
+ * mapping should begin. When specifying it, there is no need to worry about
389
+ * providing a value that is aligned with the operating system's page allocation
390
+ * granularity. This is adjusted by the implementation such that the first requested
391
+ * byte (as returned by `data` or `begin`), so long as `offset` is valid, will be at
392
+ * `offset` from the start of the file.
393
+ *
394
+ * `length` is the number of bytes to map. It may be `map_entire_file`, in which
395
+ * case a mapping of the entire file is created.
396
+ */
397
+ template<typename String>
398
+ void map(const String& path, const size_type offset, const size_type length, std::error_code& error);
399
+
400
+ /**
401
+ * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the
402
+ * reason is reported via `error` and the object remains in a state as if this
403
+ * function hadn't been called.
404
+ *
405
+ * `path`, which must be a path to an existing file, is used to retrieve a file
406
+ * handle (which is closed when the object destructs or `unmap` is called), which is
407
+ * then used to memory map the requested region. Upon failure, `error` is set to
408
+ * indicate the reason and the object remains in an unmapped state.
409
+ *
410
+ * The entire file is mapped.
411
+ */
412
+ template<typename String>
413
+ void map(const String& path, std::error_code& error) {
414
+ map(path, 0, map_entire_file, error);
415
+ }
416
+
417
+ /**
418
+ * Establishes a memory mapping with AccessMode. If the mapping is
419
+ * unsuccesful, the reason is reported via `error` and the object remains in
420
+ * a state as if this function hadn't been called.
421
+ *
422
+ * `handle`, which must be a valid file handle, which is used to memory map the
423
+ * requested region. Upon failure, `error` is set to indicate the reason and the
424
+ * object remains in an unmapped state.
425
+ *
426
+ * `offset` is the number of bytes, relative to the start of the file, where the
427
+ * mapping should begin. When specifying it, there is no need to worry about
428
+ * providing a value that is aligned with the operating system's page allocation
429
+ * granularity. This is adjusted by the implementation such that the first requested
430
+ * byte (as returned by `data` or `begin`), so long as `offset` is valid, will be at
431
+ * `offset` from the start of the file.
432
+ *
433
+ * `length` is the number of bytes to map. It may be `map_entire_file`, in which
434
+ * case a mapping of the entire file is created.
435
+ */
436
+ void map(const handle_type handle, const size_type offset, const size_type length, std::error_code& error);
437
+
438
+ /**
439
+ * Establishes a memory mapping with AccessMode. If the mapping is
440
+ * unsuccesful, the reason is reported via `error` and the object remains in
441
+ * a state as if this function hadn't been called.
442
+ *
443
+ * `handle`, which must be a valid file handle, which is used to memory map the
444
+ * requested region. Upon failure, `error` is set to indicate the reason and the
445
+ * object remains in an unmapped state.
446
+ *
447
+ * The entire file is mapped.
448
+ */
449
+ void map(const handle_type handle, std::error_code& error) {
450
+ map(handle, 0, map_entire_file, error);
451
+ }
452
+
453
+ /**
454
+ * If a valid memory mapping has been created prior to this call, this call
455
+ * instructs the kernel to unmap the memory region and disassociate this object
456
+ * from the file.
457
+ *
458
+ * The file handle associated with the file that is mapped is only closed if the
459
+ * mapping was created using a file path. If, on the other hand, an existing
460
+ * file handle was used to create the mapping, the file handle is not closed.
461
+ */
462
+ void unmap();
463
+
464
+ void swap(basic_mmap& other);
465
+
466
+ /** Flushes the memory mapped page to disk. Errors are reported via `error`. */
467
+ template<access_mode A = AccessMode>
468
+ typename std::enable_if<A == access_mode::write, void>::type sync(std::error_code& error);
469
+
470
+ /**
471
+ * All operators compare the address of the first byte and size of the two mapped
472
+ * regions.
473
+ */
474
+
475
+ private:
476
+
477
+ template< access_mode A = AccessMode, typename = typename std::enable_if<A == access_mode::write>::type >
478
+ pointer get_mapping_start() noexcept {
479
+ return !data() ? nullptr : data() - mapping_offset();
480
+ }
481
+
482
+ const_pointer get_mapping_start() const noexcept {
483
+ return !data() ? nullptr : data() - mapping_offset();
484
+ }
485
+
486
+ /**
487
+ * The destructor syncs changes to disk if `AccessMode` is `write`, but not
488
+ * if it's `read`, but since the destructor cannot be templated, we need to
489
+ * do SFINAE in a dedicated function, where one syncs and the other is a noop.
490
+ */
491
+ template<access_mode A = AccessMode>
492
+ typename std::enable_if<A == access_mode::write, void>::type conditional_sync();
493
+ template<access_mode A = AccessMode>
494
+ typename std::enable_if<A == access_mode::read, void>::type conditional_sync();
495
+ };
496
+
497
+ template<access_mode AccessMode, typename ByteT>
498
+ bool operator==(const basic_mmap<AccessMode, ByteT>& a, const basic_mmap<AccessMode, ByteT>& b);
499
+
500
+ template<access_mode AccessMode, typename ByteT>
501
+ bool operator!=(const basic_mmap<AccessMode, ByteT>& a, const basic_mmap<AccessMode, ByteT>& b);
502
+
503
+ template<access_mode AccessMode, typename ByteT>
504
+ bool operator<(const basic_mmap<AccessMode, ByteT>& a, const basic_mmap<AccessMode, ByteT>& b);
505
+
506
+ template<access_mode AccessMode, typename ByteT>
507
+ bool operator<=(const basic_mmap<AccessMode, ByteT>& a, const basic_mmap<AccessMode, ByteT>& b);
508
+
509
+ template<access_mode AccessMode, typename ByteT>
510
+ bool operator>(const basic_mmap<AccessMode, ByteT>& a, const basic_mmap<AccessMode, ByteT>& b);
511
+
512
+ template<access_mode AccessMode, typename ByteT>
513
+ bool operator>=(const basic_mmap<AccessMode, ByteT>& a, const basic_mmap<AccessMode, ByteT>& b);
514
+
515
+ /**
516
+ * This is the basis for all read-only mmap objects and should be preferred over
517
+ * directly using `basic_mmap`.
518
+ */
519
+ template<typename ByteT>
520
+ using basic_mmap_source = basic_mmap<access_mode::read, ByteT>;
521
+
522
+ /**
523
+ * This is the basis for all read-write mmap objects and should be preferred over
524
+ * directly using `basic_mmap`.
525
+ */
526
+ template<typename ByteT>
527
+ using basic_mmap_sink = basic_mmap<access_mode::write, ByteT>;
528
+
529
+ /**
530
+ * These aliases cover the most common use cases, both representing a raw byte stream
531
+ * (either with a char or an unsigned char/uint8_t).
532
+ */
533
+ using mmap_source = basic_mmap_source<char>;
534
+ using ummap_source = basic_mmap_source<unsigned char>;
535
+
536
+ using mmap_sink = basic_mmap_sink<char>;
537
+ using ummap_sink = basic_mmap_sink<unsigned char>;
538
+
539
+ /**
540
+ * Convenience factory method that constructs a mapping for any `basic_mmap` or
541
+ * `basic_mmap` type.
542
+ */
543
+ template< typename MMap, typename MappingToken >
544
+ MMap make_mmap(const MappingToken& token, int64_t offset, int64_t length, std::error_code& error) {
545
+ MMap mmap;
546
+ mmap.map(token, offset, length, error);
547
+ return mmap;
548
+ }
549
+
550
+ /**
551
+ * Convenience factory method.
552
+ *
553
+ * MappingToken may be a String (`std::string`, `std::string_view`, `const char*`,
554
+ * `std::filesystem::path`, `std::vector<char>`, or similar), or a
555
+ * `mmap_source::handle_type`.
556
+ */
557
+ template<typename MappingToken>
558
+ mmap_source make_mmap_source(
559
+ const MappingToken& token, mmap_source::size_type offset, mmap_source::size_type length, std::error_code& error
560
+ ) {
561
+ return make_mmap<mmap_source>(token, offset, length, error);
562
+ }
563
+
564
+ template<typename MappingToken>
565
+ mmap_source make_mmap_source(const MappingToken& token, std::error_code& error) {
566
+ return make_mmap_source(token, 0, map_entire_file, error);
567
+ }
568
+
569
+ /**
570
+ * Convenience factory method.
571
+ *
572
+ * MappingToken may be a String (`std::string`, `std::string_view`, `const char*`,
573
+ * `std::filesystem::path`, `std::vector<char>`, or similar), or a
574
+ * `mmap_sink::handle_type`.
575
+ */
576
+ template<typename MappingToken>
577
+ mmap_sink make_mmap_sink(
578
+ const MappingToken& token, mmap_sink::size_type offset, mmap_sink::size_type length, std::error_code& error
579
+ ) {
580
+ return make_mmap<mmap_sink>(token, offset, length, error);
581
+ }
582
+
583
+ template<typename MappingToken>
584
+ mmap_sink make_mmap_sink(const MappingToken& token, std::error_code& error) {
585
+ return make_mmap_sink(token, 0, map_entire_file, error);
586
+ }
587
+
588
+ } // namespace mio
589
+
590
+ // #include "detail/mmap.ipp"
591
+ /* Copyright 2017 https://github.com/mandreyel
592
+ *
593
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this
594
+ * software and associated documentation files (the "Software"), to deal in the Software
595
+ * without restriction, including without limitation the rights to use, copy, modify,
596
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
597
+ * permit persons to whom the Software is furnished to do so, subject to the following
598
+ * conditions:
599
+ *
600
+ * The above copyright notice and this permission notice shall be included in all copies
601
+ * or substantial portions of the Software.
602
+ *
603
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
604
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
605
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
606
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
607
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
608
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
609
+ */
610
+
611
+ #ifndef MIO_BASIC_MMAP_IMPL
612
+ #define MIO_BASIC_MMAP_IMPL
613
+
614
+ // #include "mio/mmap.hpp"
615
+
616
+ // #include "mio/page.hpp"
617
+
618
+ // #include "mio/detail/string_util.hpp"
619
+ /* Copyright 2017 https://github.com/mandreyel
620
+ *
621
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this
622
+ * software and associated documentation files (the "Software"), to deal in the Software
623
+ * without restriction, including without limitation the rights to use, copy, modify,
624
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
625
+ * permit persons to whom the Software is furnished to do so, subject to the following
626
+ * conditions:
627
+ *
628
+ * The above copyright notice and this permission notice shall be included in all copies
629
+ * or substantial portions of the Software.
630
+ *
631
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
632
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
633
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
634
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
635
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
636
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
637
+ */
638
+
639
+ #ifndef MIO_STRING_UTIL_HEADER
640
+ #define MIO_STRING_UTIL_HEADER
641
+
642
+ #include <type_traits>
643
+
644
+ namespace mio {
645
+ namespace detail {
646
+
647
+ template<
648
+ typename S, typename C = typename std::decay<S>::type, typename = decltype(std::declval<C>().data()),
649
+ typename = typename std::enable_if<
650
+ std::is_same<typename C::value_type, char>::value
651
+ #ifdef _WIN32
652
+ || std::is_same<typename C::value_type, wchar_t>::value
653
+ #endif
654
+ >::type >
655
+ struct char_type_helper {
656
+ using type = typename C::value_type;
657
+ };
658
+
659
+ template<class T>
660
+ struct char_type {
661
+ using type = typename char_type_helper<T>::type;
662
+ };
663
+
664
+ // TODO: can we avoid this brute force approach?
665
+ template<>
666
+ struct char_type<char*> {
667
+ using type = char;
668
+ };
669
+
670
+ template<>
671
+ struct char_type<const char*> {
672
+ using type = char;
673
+ };
674
+
675
+ template<size_t N>
676
+ struct char_type<char[N]> {
677
+ using type = char;
678
+ };
679
+
680
+ template<size_t N>
681
+ struct char_type<const char[N]> {
682
+ using type = char;
683
+ };
684
+
685
+ #ifdef _WIN32
686
+ template<>
687
+ struct char_type<wchar_t*> {
688
+ using type = wchar_t;
689
+ };
690
+
691
+ template<>
692
+ struct char_type<const wchar_t*> {
693
+ using type = wchar_t;
694
+ };
695
+
696
+ template<size_t N>
697
+ struct char_type<wchar_t[N]> {
698
+ using type = wchar_t;
699
+ };
700
+
701
+ template<size_t N>
702
+ struct char_type<const wchar_t[N]> {
703
+ using type = wchar_t;
704
+ };
705
+ #endif // _WIN32
706
+
707
+ template<typename CharT, typename S>
708
+ struct is_c_str_helper {
709
+ static constexpr bool value = std::is_same<
710
+ CharT*,
711
+ // TODO: I'm so sorry for this... Can this be made cleaner?
712
+ typename std::add_pointer< typename std::remove_cv<
713
+ typename std::remove_pointer< typename std::decay< S >::type >::type >::type >::type >::value;
714
+ };
715
+
716
+ template<typename S>
717
+ struct is_c_str {
718
+ static constexpr bool value = is_c_str_helper<char, S>::value;
719
+ };
720
+
721
+ #ifdef _WIN32
722
+ template<typename S>
723
+ struct is_c_wstr {
724
+ static constexpr bool value = is_c_str_helper<wchar_t, S>::value;
725
+ };
726
+ #endif // _WIN32
727
+
728
+ template<typename S>
729
+ struct is_c_str_or_c_wstr {
730
+ static constexpr bool value = is_c_str<S>::value
731
+ #ifdef _WIN32
732
+ || is_c_wstr<S>::value
733
+ #endif
734
+ ;
735
+ };
736
+
737
+ template<
738
+ typename String, typename = decltype(std::declval<String>().data()),
739
+ typename = typename std::enable_if<!is_c_str_or_c_wstr<String>::value>::type >
740
+ const typename char_type<String>::type* c_str(const String& path) {
741
+ return path.data();
742
+ }
743
+
744
+ template<
745
+ typename String, typename = decltype(std::declval<String>().empty()),
746
+ typename = typename std::enable_if<!is_c_str_or_c_wstr<String>::value>::type >
747
+ bool empty(const String& path) {
748
+ return path.empty();
749
+ }
750
+
751
+ template< typename String, typename = typename std::enable_if<is_c_str_or_c_wstr<String>::value>::type >
752
+ const typename char_type<String>::type* c_str(String path) {
753
+ return path;
754
+ }
755
+
756
+ template< typename String, typename = typename std::enable_if<is_c_str_or_c_wstr<String>::value>::type >
757
+ bool empty(String path) {
758
+ return !path || (*path == 0);
759
+ }
760
+
761
+ } // namespace detail
762
+ } // namespace mio
763
+
764
+ #endif // MIO_STRING_UTIL_HEADER
765
+
766
+ #include <algorithm>
767
+
768
+ #ifndef _WIN32
769
+ #include <fcntl.h>
770
+ #include <sys/mman.h>
771
+ #include <sys/stat.h>
772
+ #include <unistd.h>
773
+ #endif
774
+
775
+ namespace mio {
776
+ namespace detail {
777
+
778
+ #ifdef _WIN32
779
+ namespace win {
780
+
781
+ /** Returns the 4 upper bytes of an 8-byte integer. */
782
+ inline DWORD int64_high(int64_t n) noexcept {
783
+ return n >> 32;
784
+ }
785
+
786
+ /** Returns the 4 lower bytes of an 8-byte integer. */
787
+ inline DWORD int64_low(int64_t n) noexcept {
788
+ return n & 0xffffffff;
789
+ }
790
+
791
+ std::wstring s_2_ws(const std::string& s) {
792
+ if (s.empty())
793
+ return {};
794
+ const auto s_length = static_cast<int>(s.length());
795
+ auto buf = std::vector<wchar_t>(s_length);
796
+ const auto wide_char_count = MultiByteToWideChar(CP_UTF8, 0, s.c_str(), s_length, buf.data(), s_length);
797
+ return std::wstring(buf.data(), wide_char_count);
798
+ }
799
+
800
+ template<
801
+ typename String,
802
+ typename = typename std::enable_if< std::is_same<typename char_type<String>::type, char>::value >::type >
803
+ file_handle_type open_file_helper(const String& path, const access_mode mode) {
804
+ return ::CreateFileW(
805
+ s_2_ws(path).c_str(), mode == access_mode::read ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,
806
+ FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0
807
+ );
808
+ }
809
+
810
+ template<typename String>
811
+ typename std::enable_if< std::is_same<typename char_type<String>::type, wchar_t>::value, file_handle_type >::type
812
+ open_file_helper(const String& path, const access_mode mode) {
813
+ return ::CreateFileW(
814
+ c_str(path), mode == access_mode::read ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,
815
+ FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0
816
+ );
817
+ }
818
+
819
+ } // namespace win
820
+ #endif // _WIN32
821
+
822
+ /**
823
+ * Returns the last platform specific system error (errno on POSIX and
824
+ * GetLastError on Win) as a `std::error_code`.
825
+ */
826
+ inline std::error_code last_error() noexcept {
827
+ std::error_code error;
828
+ #ifdef _WIN32
829
+ error.assign(GetLastError(), std::system_category());
830
+ #else
831
+ error.assign(errno, std::system_category());
832
+ #endif
833
+ return error;
834
+ }
835
+
836
+ template<typename String>
837
+ file_handle_type open_file(const String& path, const access_mode mode, std::error_code& error) {
838
+ error.clear();
839
+ if (detail::empty(path)) {
840
+ error = std::make_error_code(std::errc::invalid_argument);
841
+ return invalid_handle;
842
+ }
843
+ #ifdef _WIN32
844
+ const auto handle = win::open_file_helper(path, mode);
845
+ #else // POSIX
846
+ const auto handle = ::open(c_str(path), mode == access_mode::read ? O_RDONLY : O_RDWR);
847
+ #endif
848
+ if (handle == invalid_handle) {
849
+ error = detail::last_error();
850
+ }
851
+ return handle;
852
+ }
853
+
854
+ inline size_t query_file_size(file_handle_type handle, std::error_code& error) {
855
+ error.clear();
856
+ #ifdef _WIN32
857
+ LARGE_INTEGER file_size;
858
+ if (::GetFileSizeEx(handle, &file_size) == 0) {
859
+ error = detail::last_error();
860
+ return 0;
861
+ }
862
+ return static_cast<int64_t>(file_size.QuadPart);
863
+ #else // POSIX
864
+ struct stat sbuf;
865
+ if (::fstat(handle, &sbuf) == -1) {
866
+ error = detail::last_error();
867
+ return 0;
868
+ }
869
+ return sbuf.st_size;
870
+ #endif
871
+ }
872
+
873
+ struct mmap_context {
874
+ char* data;
875
+ int64_t length;
876
+ int64_t mapped_length;
877
+ #ifdef _WIN32
878
+ file_handle_type file_mapping_handle;
879
+ #endif
880
+ };
881
+
882
+ inline mmap_context memory_map(
883
+ const file_handle_type file_handle, const int64_t offset, const int64_t length, const access_mode mode,
884
+ std::error_code& error
885
+ ) {
886
+ const int64_t aligned_offset = make_offset_page_aligned(offset);
887
+ const int64_t length_to_map = offset - aligned_offset + length;
888
+ #ifdef _WIN32
889
+ const int64_t max_file_size = offset + length;
890
+ const auto file_mapping_handle = ::CreateFileMapping(
891
+ file_handle, 0, mode == access_mode::read ? PAGE_READONLY : PAGE_READWRITE, win::int64_high(max_file_size),
892
+ win::int64_low(max_file_size), 0
893
+ );
894
+ if (file_mapping_handle == invalid_handle) {
895
+ error = detail::last_error();
896
+ return {};
897
+ }
898
+ char* mapping_start = static_cast<char*>(::MapViewOfFile(
899
+ file_mapping_handle, mode == access_mode::read ? FILE_MAP_READ : FILE_MAP_WRITE, win::int64_high(aligned_offset),
900
+ win::int64_low(aligned_offset), length_to_map
901
+ ));
902
+ if (mapping_start == nullptr) {
903
+ // Close file handle if mapping it failed.
904
+ ::CloseHandle(file_mapping_handle);
905
+ error = detail::last_error();
906
+ return {};
907
+ }
908
+ #else // POSIX
909
+ char* mapping_start = static_cast<char*>(::mmap(
910
+ 0, // Don't give hint as to where to map.
911
+ length_to_map, mode == access_mode::read ? PROT_READ : PROT_WRITE, MAP_SHARED, file_handle, aligned_offset
912
+ ));
913
+ if (mapping_start == MAP_FAILED) {
914
+ error = detail::last_error();
915
+ return {};
916
+ }
917
+ #endif
918
+ mmap_context ctx;
919
+ ctx.data = mapping_start + offset - aligned_offset;
920
+ ctx.length = length;
921
+ ctx.mapped_length = length_to_map;
922
+ #ifdef _WIN32
923
+ ctx.file_mapping_handle = file_mapping_handle;
924
+ #endif
925
+ return ctx;
926
+ }
927
+
928
+ } // namespace detail
929
+
930
+ // -- basic_mmap --
931
+
932
+ template<access_mode AccessMode, typename ByteT>
933
+ basic_mmap<AccessMode, ByteT>::~basic_mmap() {
934
+ conditional_sync();
935
+ unmap();
936
+ }
937
+
938
+ template<access_mode AccessMode, typename ByteT>
939
+ basic_mmap<AccessMode, ByteT>::basic_mmap(basic_mmap&& other) :
940
+ data_(std::move(other.data_)),
941
+ length_(std::move(other.length_)),
942
+ mapped_length_(std::move(other.mapped_length_)),
943
+ file_handle_(std::move(other.file_handle_))
944
+ #ifdef _WIN32
945
+ ,
946
+ file_mapping_handle_(std::move(other.file_mapping_handle_))
947
+ #endif
948
+ ,
949
+ is_handle_internal_(std::move(other.is_handle_internal_)) {
950
+ other.data_ = nullptr;
951
+ other.length_ = other.mapped_length_ = 0;
952
+ other.file_handle_ = invalid_handle;
953
+ #ifdef _WIN32
954
+ other.file_mapping_handle_ = invalid_handle;
955
+ #endif
956
+ }
957
+
958
+ template<access_mode AccessMode, typename ByteT>
959
+ basic_mmap<AccessMode, ByteT>& basic_mmap<AccessMode, ByteT>::operator=(basic_mmap&& other) {
960
+ if (this != &other) {
961
+ // First the existing mapping needs to be removed.
962
+ unmap();
963
+ data_ = std::move(other.data_);
964
+ length_ = std::move(other.length_);
965
+ mapped_length_ = std::move(other.mapped_length_);
966
+ file_handle_ = std::move(other.file_handle_);
967
+ #ifdef _WIN32
968
+ file_mapping_handle_ = std::move(other.file_mapping_handle_);
969
+ #endif
970
+ is_handle_internal_ = std::move(other.is_handle_internal_);
971
+
972
+ // The moved from basic_mmap's fields need to be reset, because
973
+ // otherwise other's destructor will unmap the same mapping that was
974
+ // just moved into this.
975
+ other.data_ = nullptr;
976
+ other.length_ = other.mapped_length_ = 0;
977
+ other.file_handle_ = invalid_handle;
978
+ #ifdef _WIN32
979
+ other.file_mapping_handle_ = invalid_handle;
980
+ #endif
981
+ other.is_handle_internal_ = false;
982
+ }
983
+ return *this;
984
+ }
985
+
986
+ template<access_mode AccessMode, typename ByteT>
987
+ typename basic_mmap<AccessMode, ByteT>::handle_type basic_mmap<AccessMode, ByteT>::mapping_handle() const noexcept {
988
+ #ifdef _WIN32
989
+ return file_mapping_handle_;
990
+ #else
991
+ return file_handle_;
992
+ #endif
993
+ }
994
+
995
+ template<access_mode AccessMode, typename ByteT>
996
+ template<typename String>
997
+ void basic_mmap<AccessMode, ByteT>::map(
998
+ const String& path, const size_type offset, const size_type length, std::error_code& error
999
+ ) {
1000
+ error.clear();
1001
+ if (detail::empty(path)) {
1002
+ error = std::make_error_code(std::errc::invalid_argument);
1003
+ return;
1004
+ }
1005
+ const auto handle = detail::open_file(path, AccessMode, error);
1006
+ if (error) {
1007
+ return;
1008
+ }
1009
+
1010
+ map(handle, offset, length, error);
1011
+ // This MUST be after the call to map, as that sets this to true.
1012
+ if (!error) {
1013
+ is_handle_internal_ = true;
1014
+ }
1015
+ }
1016
+
1017
+ template<access_mode AccessMode, typename ByteT>
1018
+ void basic_mmap<AccessMode, ByteT>::map(
1019
+ const handle_type handle, const size_type offset, const size_type length, std::error_code& error
1020
+ ) {
1021
+ error.clear();
1022
+ if (handle == invalid_handle) {
1023
+ error = std::make_error_code(std::errc::bad_file_descriptor);
1024
+ return;
1025
+ }
1026
+
1027
+ const auto file_size = detail::query_file_size(handle, error);
1028
+ if (error) {
1029
+ return;
1030
+ }
1031
+
1032
+ if (offset + length > file_size) {
1033
+ error = std::make_error_code(std::errc::invalid_argument);
1034
+ return;
1035
+ }
1036
+
1037
+ const auto ctx =
1038
+ detail::memory_map(handle, offset, length == map_entire_file ? (file_size - offset) : length, AccessMode, error);
1039
+ if (!error) {
1040
+ // We must unmap the previous mapping that may have existed prior to this call.
1041
+ // Note that this must only be invoked after a new mapping has been created in
1042
+ // order to provide the strong guarantee that, should the new mapping fail, the
1043
+ // `map` function leaves this instance in a state as though the function had
1044
+ // never been invoked.
1045
+ unmap();
1046
+ file_handle_ = handle;
1047
+ is_handle_internal_ = false;
1048
+ data_ = std::bit_cast<pointer>(ctx.data);
1049
+ length_ = ctx.length;
1050
+ mapped_length_ = ctx.mapped_length;
1051
+ #ifdef _WIN32
1052
+ file_mapping_handle_ = ctx.file_mapping_handle;
1053
+ #endif
1054
+ }
1055
+ }
1056
+
1057
+ template<access_mode AccessMode, typename ByteT>
1058
+ template<access_mode A>
1059
+ typename std::enable_if<A == access_mode::write, void>::type basic_mmap<AccessMode, ByteT>::sync(std::error_code& error) {
1060
+ error.clear();
1061
+ if (!is_open()) {
1062
+ error = std::make_error_code(std::errc::bad_file_descriptor);
1063
+ return;
1064
+ }
1065
+
1066
+ if (data()) {
1067
+ #ifdef _WIN32
1068
+ if (::FlushViewOfFile(get_mapping_start(), mapped_length_) == 0 || ::FlushFileBuffers(file_handle_) == 0)
1069
+ #else // POSIX
1070
+ if (::msync(get_mapping_start(), mapped_length_, MS_SYNC) != 0)
1071
+ #endif
1072
+ {
1073
+ error = detail::last_error();
1074
+ return;
1075
+ }
1076
+ }
1077
+ #ifdef _WIN32
1078
+ if (::FlushFileBuffers(file_handle_) == 0) {
1079
+ error = detail::last_error();
1080
+ }
1081
+ #endif
1082
+ }
1083
+
1084
+ template<access_mode AccessMode, typename ByteT>
1085
+ void basic_mmap<AccessMode, ByteT>::unmap() {
1086
+ if (!is_open()) {
1087
+ return;
1088
+ }
1089
+ // TODO do we care about errors here?
1090
+ #ifdef _WIN32
1091
+ if (is_mapped()) {
1092
+ ::UnmapViewOfFile(get_mapping_start());
1093
+ ::CloseHandle(file_mapping_handle_);
1094
+ }
1095
+ #else // POSIX
1096
+ if (data_) {
1097
+ ::munmap(const_cast<pointer>(get_mapping_start()), mapped_length_);
1098
+ }
1099
+ #endif
1100
+
1101
+ // If `file_handle_` was obtained by our opening it (when map is called with
1102
+ // a path, rather than an existing file handle), we need to close it,
1103
+ // otherwise it must not be closed as it may still be used outside this
1104
+ // instance.
1105
+ if (is_handle_internal_) {
1106
+ #ifdef _WIN32
1107
+ ::CloseHandle(file_handle_);
1108
+ #else // POSIX
1109
+ ::close(file_handle_);
1110
+ #endif
1111
+ }
1112
+
1113
+ // Reset fields to their default values.
1114
+ data_ = nullptr;
1115
+ length_ = mapped_length_ = 0;
1116
+ file_handle_ = invalid_handle;
1117
+ #ifdef _WIN32
1118
+ file_mapping_handle_ = invalid_handle;
1119
+ #endif
1120
+ }
1121
+
1122
+ template<access_mode AccessMode, typename ByteT>
1123
+ bool basic_mmap<AccessMode, ByteT>::is_mapped() const noexcept {
1124
+ #ifdef _WIN32
1125
+ return file_mapping_handle_ != invalid_handle;
1126
+ #else // POSIX
1127
+ return is_open();
1128
+ #endif
1129
+ }
1130
+
1131
+ template<access_mode AccessMode, typename ByteT>
1132
+ void basic_mmap<AccessMode, ByteT>::swap(basic_mmap& other) {
1133
+ if (this != &other) {
1134
+ using std::swap;
1135
+ swap(data_, other.data_);
1136
+ swap(file_handle_, other.file_handle_);
1137
+ #ifdef _WIN32
1138
+ swap(file_mapping_handle_, other.file_mapping_handle_);
1139
+ #endif
1140
+ swap(length_, other.length_);
1141
+ swap(mapped_length_, other.mapped_length_);
1142
+ swap(is_handle_internal_, other.is_handle_internal_);
1143
+ }
1144
+ }
1145
+
1146
+ template<access_mode AccessMode, typename ByteT>
1147
+ template<access_mode A>
1148
+ typename std::enable_if<A == access_mode::write, void>::type basic_mmap<AccessMode, ByteT>::conditional_sync() {
1149
+ // This is invoked from the destructor, so not much we can do about
1150
+ // failures here.
1151
+ std::error_code ec;
1152
+ sync(ec);
1153
+ }
1154
+
1155
+ template<access_mode AccessMode, typename ByteT>
1156
+ template<access_mode A>
1157
+ typename std::enable_if<A == access_mode::read, void>::type basic_mmap<AccessMode, ByteT>::conditional_sync() {
1158
+ // noop
1159
+ }
1160
+
1161
+ template<access_mode AccessMode, typename ByteT>
1162
+ bool operator==(const basic_mmap<AccessMode, ByteT>& a, const basic_mmap<AccessMode, ByteT>& b) {
1163
+ return a.data() == b.data() && a.size() == b.size();
1164
+ }
1165
+
1166
+ template<access_mode AccessMode, typename ByteT>
1167
+ bool operator!=(const basic_mmap<AccessMode, ByteT>& a, const basic_mmap<AccessMode, ByteT>& b) {
1168
+ return !(a == b);
1169
+ }
1170
+
1171
+ template<access_mode AccessMode, typename ByteT>
1172
+ bool operator<(const basic_mmap<AccessMode, ByteT>& a, const basic_mmap<AccessMode, ByteT>& b) {
1173
+ if (a.data() == b.data()) {
1174
+ return a.size() < b.size();
1175
+ }
1176
+ return a.data() < b.data();
1177
+ }
1178
+
1179
+ template<access_mode AccessMode, typename ByteT>
1180
+ bool operator<=(const basic_mmap<AccessMode, ByteT>& a, const basic_mmap<AccessMode, ByteT>& b) {
1181
+ return !(a > b);
1182
+ }
1183
+
1184
+ template<access_mode AccessMode, typename ByteT>
1185
+ bool operator>(const basic_mmap<AccessMode, ByteT>& a, const basic_mmap<AccessMode, ByteT>& b) {
1186
+ if (a.data() == b.data()) {
1187
+ return a.size() > b.size();
1188
+ }
1189
+ return a.data() > b.data();
1190
+ }
1191
+
1192
+ template<access_mode AccessMode, typename ByteT>
1193
+ bool operator>=(const basic_mmap<AccessMode, ByteT>& a, const basic_mmap<AccessMode, ByteT>& b) {
1194
+ return !(a < b);
1195
+ }
1196
+
1197
+ } // namespace mio
1198
+
1199
+ #endif // MIO_BASIC_MMAP_IMPL
1200
+
1201
+ #endif // MIO_MMAP_HEADER
1202
+ /* Copyright 2017 https://github.com/mandreyel
1203
+ *
1204
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this
1205
+ * software and associated documentation files (the "Software"), to deal in the Software
1206
+ * without restriction, including without limitation the rights to use, copy, modify,
1207
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
1208
+ * permit persons to whom the Software is furnished to do so, subject to the following
1209
+ * conditions:
1210
+ *
1211
+ * The above copyright notice and this permission notice shall be included in all copies
1212
+ * or substantial portions of the Software.
1213
+ *
1214
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
1215
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
1216
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
1217
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
1218
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
1219
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1220
+ */
1221
+
1222
+ #ifndef MIO_PAGE_HEADER
1223
+ #define MIO_PAGE_HEADER
1224
+
1225
+ #ifdef _WIN32
1226
+ #include <windows.h>
1227
+ #else
1228
+ #include <unistd.h>
1229
+ #endif
1230
+
1231
+ namespace mio {
1232
+
1233
+ /**
1234
+ * This is used by `basic_mmap` to determine whether to create a read-only or
1235
+ * a read-write memory mapping.
1236
+ */
1237
+ enum class access_mode {
1238
+ read,
1239
+ write
1240
+ };
1241
+
1242
+ /**
1243
+ * Determines the operating system's page allocation granularity.
1244
+ *
1245
+ * On the first call to this function, it invokes the operating system specific syscall
1246
+ * to determine the page size, caches the value, and returns it. Any subsequent call to
1247
+ * this function serves the cached value, so no further syscalls are made.
1248
+ */
1249
+ inline size_t page_size() {
1250
+ static const size_t page_size = [] {
1251
+ #ifdef _WIN32
1252
+ SYSTEM_INFO SystemInfo;
1253
+ GetSystemInfo(&SystemInfo);
1254
+ return SystemInfo.dwAllocationGranularity;
1255
+ #else
1256
+ return sysconf(_SC_PAGE_SIZE);
1257
+ #endif
1258
+ }();
1259
+ return page_size;
1260
+ }
1261
+
1262
+ /**
1263
+ * Alligns `offset` to the operating's system page size such that it subtracts the
1264
+ * difference until the nearest page boundary before `offset`, or does nothing if
1265
+ * `offset` is already page aligned.
1266
+ */
1267
+ inline size_t make_offset_page_aligned(size_t offset) noexcept {
1268
+ const size_t page_size_ = page_size();
1269
+ // Use integer division to round down to the nearest page alignment.
1270
+ return offset / page_size_ * page_size_;
1271
+ }
1272
+
1273
+ } // namespace mio
1274
+
1275
+ #endif // MIO_PAGE_HEADER
1276
+ /* Copyright 2017 https://github.com/mandreyel
1277
+ *
1278
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this
1279
+ * software and associated documentation files (the "Software"), to deal in the Software
1280
+ * without restriction, including without limitation the rights to use, copy, modify,
1281
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
1282
+ * permit persons to whom the Software is furnished to do so, subject to the following
1283
+ * conditions:
1284
+ *
1285
+ * The above copyright notice and this permission notice shall be included in all copies
1286
+ * or substantial portions of the Software.
1287
+ *
1288
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
1289
+ * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
1290
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
1291
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
1292
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
1293
+ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1294
+ */
1295
+
1296
+ #ifndef MIO_SHARED_MMAP_HEADER
1297
+ #define MIO_SHARED_MMAP_HEADER
1298
+
1299
+ // #include "mio/mmap.hpp"
1300
+
1301
+ #include <memory> // std::shared_ptr
1302
+ #include <system_error> // std::error_code
1303
+
1304
+ namespace mio {
1305
+
1306
+ /**
1307
+ * Exposes (nearly) the same interface as `basic_mmap`, but endowes it with
1308
+ * `std::shared_ptr` semantics.
1309
+ *
1310
+ * This is not the default behaviour of `basic_mmap` to avoid allocating on the heap if
1311
+ * shared semantics are not required.
1312
+ */
1313
+ template< access_mode AccessMode, typename ByteT >
1314
+ class basic_shared_mmap {
1315
+ using impl_type = basic_mmap<AccessMode, ByteT>;
1316
+ std::shared_ptr<impl_type> pimpl_;
1317
+
1318
+ public:
1319
+
1320
+ using value_type = typename impl_type::value_type;
1321
+ using size_type = typename impl_type::size_type;
1322
+ using reference = typename impl_type::reference;
1323
+ using const_reference = typename impl_type::const_reference;
1324
+ using pointer = typename impl_type::pointer;
1325
+ using const_pointer = typename impl_type::const_pointer;
1326
+ using difference_type = typename impl_type::difference_type;
1327
+ using iterator = typename impl_type::iterator;
1328
+ using const_iterator = typename impl_type::const_iterator;
1329
+ using reverse_iterator = typename impl_type::reverse_iterator;
1330
+ using const_reverse_iterator = typename impl_type::const_reverse_iterator;
1331
+ using iterator_category = typename impl_type::iterator_category;
1332
+ using handle_type = typename impl_type::handle_type;
1333
+ using mmap_type = impl_type;
1334
+
1335
+ basic_shared_mmap() = default;
1336
+ basic_shared_mmap(const basic_shared_mmap&) = default;
1337
+ basic_shared_mmap& operator=(const basic_shared_mmap&) = default;
1338
+ basic_shared_mmap(basic_shared_mmap&&) = default;
1339
+ basic_shared_mmap& operator=(basic_shared_mmap&&) = default;
1340
+
1341
+ /** Takes ownership of an existing mmap object. */
1342
+ basic_shared_mmap(mmap_type&& mmap) : pimpl_(std::make_shared<mmap_type>(std::move(mmap))) {
1343
+ }
1344
+
1345
+ /** Takes ownership of an existing mmap object. */
1346
+ basic_shared_mmap& operator=(mmap_type&& mmap) {
1347
+ pimpl_ = std::make_shared<mmap_type>(std::move(mmap));
1348
+ return *this;
1349
+ }
1350
+
1351
+ /** Initializes this object with an already established shared mmap. */
1352
+ basic_shared_mmap(std::shared_ptr<mmap_type> mmap) : pimpl_(std::move(mmap)) {
1353
+ }
1354
+
1355
+ /** Initializes this object with an already established shared mmap. */
1356
+ basic_shared_mmap& operator=(std::shared_ptr<mmap_type> mmap) {
1357
+ pimpl_ = std::move(mmap);
1358
+ return *this;
1359
+ }
1360
+
1361
+ #ifdef __cpp_exceptions
1362
+ /**
1363
+ * The same as invoking the `map` function, except any error that may occur
1364
+ * while establishing the mapping is wrapped in a `std::system_error` and is
1365
+ * thrown.
1366
+ */
1367
+ template<typename String>
1368
+ basic_shared_mmap(const String& path, const size_type offset = 0, const size_type length = map_entire_file) {
1369
+ std::error_code error;
1370
+ map(path, offset, length, error);
1371
+ if (error) {
1372
+ throw std::system_error(error);
1373
+ }
1374
+ }
1375
+
1376
+ /**
1377
+ * The same as invoking the `map` function, except any error that may occur
1378
+ * while establishing the mapping is wrapped in a `std::system_error` and is
1379
+ * thrown.
1380
+ */
1381
+ basic_shared_mmap(const handle_type handle, const size_type offset = 0, const size_type length = map_entire_file) {
1382
+ std::error_code error;
1383
+ map(handle, offset, length, error);
1384
+ if (error) {
1385
+ throw std::system_error(error);
1386
+ }
1387
+ }
1388
+ #endif // __cpp_exceptions
1389
+
1390
+ /**
1391
+ * If this is a read-write mapping and the last reference to the mapping,
1392
+ * the destructor invokes sync. Regardless of the access mode, unmap is
1393
+ * invoked as a final step.
1394
+ */
1395
+ ~basic_shared_mmap() = default;
1396
+
1397
+ /** Returns the underlying `std::shared_ptr` instance that holds the mmap. */
1398
+ std::shared_ptr<mmap_type> get_shared_ptr() {
1399
+ return pimpl_;
1400
+ }
1401
+
1402
+ /**
1403
+ * On UNIX systems 'file_handle' and 'mapping_handle' are the same. On Windows,
1404
+ * however, a mapped region of a file gets its own handle, which is returned by
1405
+ * 'mapping_handle'.
1406
+ */
1407
+ handle_type file_handle() const noexcept {
1408
+ return pimpl_ ? pimpl_->file_handle() : invalid_handle;
1409
+ }
1410
+
1411
+ handle_type mapping_handle() const noexcept {
1412
+ return pimpl_ ? pimpl_->mapping_handle() : invalid_handle;
1413
+ }
1414
+
1415
+ /** Returns whether a valid memory mapping has been created. */
1416
+ bool is_open() const noexcept {
1417
+ return pimpl_ && pimpl_->is_open();
1418
+ }
1419
+
1420
+ /**
1421
+ * Returns true if no mapping was established, that is, conceptually the
1422
+ * same as though the length that was mapped was 0. This function is
1423
+ * provided so that this class has Container semantics.
1424
+ */
1425
+ bool empty() const noexcept {
1426
+ return !pimpl_ || pimpl_->empty();
1427
+ }
1428
+
1429
+ /**
1430
+ * `size` and `length` both return the logical length, i.e. the number of bytes
1431
+ * user requested to be mapped, while `mapped_length` returns the actual number of
1432
+ * bytes that were mapped which is a multiple of the underlying operating system's
1433
+ * page allocation granularity.
1434
+ */
1435
+ size_type size() const noexcept {
1436
+ return pimpl_ ? pimpl_->length() : 0;
1437
+ }
1438
+
1439
+ size_type length() const noexcept {
1440
+ return pimpl_ ? pimpl_->length() : 0;
1441
+ }
1442
+
1443
+ size_type mapped_length() const noexcept {
1444
+ return pimpl_ ? pimpl_->mapped_length() : 0;
1445
+ }
1446
+
1447
+ /**
1448
+ * Returns a pointer to the first requested byte, or `nullptr` if no memory mapping
1449
+ * exists.
1450
+ */
1451
+ template< access_mode A = AccessMode, typename = typename std::enable_if<A == access_mode::write>::type >
1452
+ pointer data() noexcept {
1453
+ return pimpl_->data();
1454
+ }
1455
+
1456
+ const_pointer data() const noexcept {
1457
+ return pimpl_ ? pimpl_->data() : nullptr;
1458
+ }
1459
+
1460
+ /**
1461
+ * Returns an iterator to the first requested byte, if a valid memory mapping
1462
+ * exists, otherwise this function call is undefined behaviour.
1463
+ */
1464
+ iterator begin() noexcept {
1465
+ return pimpl_->begin();
1466
+ }
1467
+
1468
+ const_iterator begin() const noexcept {
1469
+ return pimpl_->begin();
1470
+ }
1471
+
1472
+ const_iterator cbegin() const noexcept {
1473
+ return pimpl_->cbegin();
1474
+ }
1475
+
1476
+ /**
1477
+ * Returns an iterator one past the last requested byte, if a valid memory mapping
1478
+ * exists, otherwise this function call is undefined behaviour.
1479
+ */
1480
+ template< access_mode A = AccessMode, typename = typename std::enable_if<A == access_mode::write>::type >
1481
+ iterator end() noexcept {
1482
+ return pimpl_->end();
1483
+ }
1484
+
1485
+ const_iterator end() const noexcept {
1486
+ return pimpl_->end();
1487
+ }
1488
+
1489
+ const_iterator cend() const noexcept {
1490
+ return pimpl_->cend();
1491
+ }
1492
+
1493
+ /**
1494
+ * Returns a reverse iterator to the last memory mapped byte, if a valid
1495
+ * memory mapping exists, otherwise this function call is undefined
1496
+ * behaviour.
1497
+ */
1498
+ template< access_mode A = AccessMode, typename = typename std::enable_if<A == access_mode::write>::type >
1499
+ reverse_iterator rbegin() noexcept {
1500
+ return pimpl_->rbegin();
1501
+ }
1502
+
1503
+ const_reverse_iterator rbegin() const noexcept {
1504
+ return pimpl_->rbegin();
1505
+ }
1506
+
1507
+ const_reverse_iterator crbegin() const noexcept {
1508
+ return pimpl_->crbegin();
1509
+ }
1510
+
1511
+ /**
1512
+ * Returns a reverse iterator past the first mapped byte, if a valid memory
1513
+ * mapping exists, otherwise this function call is undefined behaviour.
1514
+ */
1515
+ template< access_mode A = AccessMode, typename = typename std::enable_if<A == access_mode::write>::type >
1516
+ reverse_iterator rend() noexcept {
1517
+ return pimpl_->rend();
1518
+ }
1519
+
1520
+ const_reverse_iterator rend() const noexcept {
1521
+ return pimpl_->rend();
1522
+ }
1523
+
1524
+ const_reverse_iterator crend() const noexcept {
1525
+ return pimpl_->crend();
1526
+ }
1527
+
1528
+ /**
1529
+ * Returns a reference to the `i`th byte from the first requested byte (as returned
1530
+ * by `data`). If this is invoked when no valid memory mapping has been created
1531
+ * prior to this call, undefined behaviour ensues.
1532
+ */
1533
+ reference operator[](const size_type i) noexcept {
1534
+ return (*pimpl_)[i];
1535
+ }
1536
+
1537
+ const_reference operator[](const size_type i) const noexcept {
1538
+ return (*pimpl_)[i];
1539
+ }
1540
+
1541
+ /**
1542
+ * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the
1543
+ * reason is reported via `error` and the object remains in a state as if this
1544
+ * function hadn't been called.
1545
+ *
1546
+ * `path`, which must be a path to an existing file, is used to retrieve a file
1547
+ * handle (which is closed when the object destructs or `unmap` is called), which is
1548
+ * then used to memory map the requested region. Upon failure, `error` is set to
1549
+ * indicate the reason and the object remains in an unmapped state.
1550
+ *
1551
+ * `offset` is the number of bytes, relative to the start of the file, where the
1552
+ * mapping should begin. When specifying it, there is no need to worry about
1553
+ * providing a value that is aligned with the operating system's page allocation
1554
+ * granularity. This is adjusted by the implementation such that the first requested
1555
+ * byte (as returned by `data` or `begin`), so long as `offset` is valid, will be at
1556
+ * `offset` from the start of the file.
1557
+ *
1558
+ * `length` is the number of bytes to map. It may be `map_entire_file`, in which
1559
+ * case a mapping of the entire file is created.
1560
+ */
1561
+ template<typename String>
1562
+ void map(const String& path, const size_type offset, const size_type length, std::error_code& error) {
1563
+ map_impl(path, offset, length, error);
1564
+ }
1565
+
1566
+ /**
1567
+ * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the
1568
+ * reason is reported via `error` and the object remains in a state as if this
1569
+ * function hadn't been called.
1570
+ *
1571
+ * `path`, which must be a path to an existing file, is used to retrieve a file
1572
+ * handle (which is closed when the object destructs or `unmap` is called), which is
1573
+ * then used to memory map the requested region. Upon failure, `error` is set to
1574
+ * indicate the reason and the object remains in an unmapped state.
1575
+ *
1576
+ * The entire file is mapped.
1577
+ */
1578
+ template<typename String>
1579
+ void map(const String& path, std::error_code& error) {
1580
+ map_impl(path, 0, map_entire_file, error);
1581
+ }
1582
+
1583
+ /**
1584
+ * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the
1585
+ * reason is reported via `error` and the object remains in a state as if this
1586
+ * function hadn't been called.
1587
+ *
1588
+ * `handle`, which must be a valid file handle, which is used to memory map the
1589
+ * requested region. Upon failure, `error` is set to indicate the reason and the
1590
+ * object remains in an unmapped state.
1591
+ *
1592
+ * `offset` is the number of bytes, relative to the start of the file, where the
1593
+ * mapping should begin. When specifying it, there is no need to worry about
1594
+ * providing a value that is aligned with the operating system's page allocation
1595
+ * granularity. This is adjusted by the implementation such that the first requested
1596
+ * byte (as returned by `data` or `begin`), so long as `offset` is valid, will be at
1597
+ * `offset` from the start of the file.
1598
+ *
1599
+ * `length` is the number of bytes to map. It may be `map_entire_file`, in which
1600
+ * case a mapping of the entire file is created.
1601
+ */
1602
+ void map(const handle_type handle, const size_type offset, const size_type length, std::error_code& error) {
1603
+ map_impl(handle, offset, length, error);
1604
+ }
1605
+
1606
+ /**
1607
+ * Establishes a memory mapping with AccessMode. If the mapping is unsuccesful, the
1608
+ * reason is reported via `error` and the object remains in a state as if this
1609
+ * function hadn't been called.
1610
+ *
1611
+ * `handle`, which must be a valid file handle, which is used to memory map the
1612
+ * requested region. Upon failure, `error` is set to indicate the reason and the
1613
+ * object remains in an unmapped state.
1614
+ *
1615
+ * The entire file is mapped.
1616
+ */
1617
+ void map(const handle_type handle, std::error_code& error) {
1618
+ map_impl(handle, 0, map_entire_file, error);
1619
+ }
1620
+
1621
+ /**
1622
+ * If a valid memory mapping has been created prior to this call, this call
1623
+ * instructs the kernel to unmap the memory region and disassociate this object
1624
+ * from the file.
1625
+ *
1626
+ * The file handle associated with the file that is mapped is only closed if the
1627
+ * mapping was created using a file path. If, on the other hand, an existing
1628
+ * file handle was used to create the mapping, the file handle is not closed.
1629
+ */
1630
+ void unmap() {
1631
+ if (pimpl_)
1632
+ pimpl_->unmap();
1633
+ }
1634
+
1635
+ void swap(basic_shared_mmap& other) {
1636
+ pimpl_.swap(other.pimpl_);
1637
+ }
1638
+
1639
+ /** Flushes the memory mapped page to disk. Errors are reported via `error`. */
1640
+ template< access_mode A = AccessMode, typename = typename std::enable_if<A == access_mode::write>::type >
1641
+ void sync(std::error_code& error) {
1642
+ if (pimpl_)
1643
+ pimpl_->sync(error);
1644
+ }
1645
+
1646
+ /** All operators compare the underlying `basic_mmap`'s addresses. */
1647
+
1648
+ friend bool operator==(const basic_shared_mmap& a, const basic_shared_mmap& b) {
1649
+ return a.pimpl_ == b.pimpl_;
1650
+ }
1651
+
1652
+ friend bool operator!=(const basic_shared_mmap& a, const basic_shared_mmap& b) {
1653
+ return !(a == b);
1654
+ }
1655
+
1656
+ friend bool operator<(const basic_shared_mmap& a, const basic_shared_mmap& b) {
1657
+ return a.pimpl_ < b.pimpl_;
1658
+ }
1659
+
1660
+ friend bool operator<=(const basic_shared_mmap& a, const basic_shared_mmap& b) {
1661
+ return a.pimpl_ <= b.pimpl_;
1662
+ }
1663
+
1664
+ friend bool operator>(const basic_shared_mmap& a, const basic_shared_mmap& b) {
1665
+ return a.pimpl_ > b.pimpl_;
1666
+ }
1667
+
1668
+ friend bool operator>=(const basic_shared_mmap& a, const basic_shared_mmap& b) {
1669
+ return a.pimpl_ >= b.pimpl_;
1670
+ }
1671
+
1672
+ private:
1673
+
1674
+ template<typename MappingToken>
1675
+ void map_impl(const MappingToken& token, const size_type offset, const size_type length, std::error_code& error) {
1676
+ if (!pimpl_) {
1677
+ mmap_type mmap = make_mmap<mmap_type>(token, offset, length, error);
1678
+ if (error) {
1679
+ return;
1680
+ }
1681
+ pimpl_ = std::make_shared<mmap_type>(std::move(mmap));
1682
+ } else {
1683
+ pimpl_->map(token, offset, length, error);
1684
+ }
1685
+ }
1686
+ };
1687
+
1688
+ /**
1689
+ * This is the basis for all read-only mmap objects and should be preferred over
1690
+ * directly using basic_shared_mmap.
1691
+ */
1692
+ template<typename ByteT>
1693
+ using basic_shared_mmap_source = basic_shared_mmap<access_mode::read, ByteT>;
1694
+
1695
+ /**
1696
+ * This is the basis for all read-write mmap objects and should be preferred over
1697
+ * directly using basic_shared_mmap.
1698
+ */
1699
+ template<typename ByteT>
1700
+ using basic_shared_mmap_sink = basic_shared_mmap<access_mode::write, ByteT>;
1701
+
1702
+ /**
1703
+ * These aliases cover the most common use cases, both representing a raw byte stream
1704
+ * (either with a char or an unsigned char/uint8_t).
1705
+ */
1706
+ using shared_mmap_source = basic_shared_mmap_source<char>;
1707
+ using shared_ummap_source = basic_shared_mmap_source<unsigned char>;
1708
+
1709
+ using shared_mmap_sink = basic_shared_mmap_sink<char>;
1710
+ using shared_ummap_sink = basic_shared_mmap_sink<unsigned char>;
1711
+
1712
+ } // namespace mio
1713
+
1714
+ #endif // MIO_SHARED_MMAP_HEADER