mdbxmou 0.1.26

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 (220) hide show
  1. package/.github/workflows/ci.yml +32 -0
  2. package/.github/workflows/publish.yml +27 -0
  3. package/.gitmodules +3 -0
  4. package/CMakeLists.txt +53 -0
  5. package/LICENSE +201 -0
  6. package/README.md +639 -0
  7. package/build.js +11 -0
  8. package/deps/libmdbx/.clang-format +3 -0
  9. package/deps/libmdbx/.cmake-format.yaml +3 -0
  10. package/deps/libmdbx/.le.ini +40 -0
  11. package/deps/libmdbx/CMakeLists.txt +1269 -0
  12. package/deps/libmdbx/COPYRIGHT +159 -0
  13. package/deps/libmdbx/ChangeLog.md +2786 -0
  14. package/deps/libmdbx/GNUmakefile +950 -0
  15. package/deps/libmdbx/LICENSE +177 -0
  16. package/deps/libmdbx/Makefile +16 -0
  17. package/deps/libmdbx/NOTICE +39 -0
  18. package/deps/libmdbx/README.md +863 -0
  19. package/deps/libmdbx/TODO.md +43 -0
  20. package/deps/libmdbx/cmake/compiler.cmake +1221 -0
  21. package/deps/libmdbx/cmake/profile.cmake +58 -0
  22. package/deps/libmdbx/cmake/utils.cmake +524 -0
  23. package/deps/libmdbx/conanfile.py +323 -0
  24. package/deps/libmdbx/docs/Doxyfile.in +2734 -0
  25. package/deps/libmdbx/docs/_preface.md +47 -0
  26. package/deps/libmdbx/docs/_restrictions.md +248 -0
  27. package/deps/libmdbx/docs/_starting.md +245 -0
  28. package/deps/libmdbx/docs/_toc.md +34 -0
  29. package/deps/libmdbx/docs/header.html +96 -0
  30. package/deps/libmdbx/example/CMakeLists.txt +6 -0
  31. package/deps/libmdbx/example/README.md +1 -0
  32. package/deps/libmdbx/example/example-mdbx.c +154 -0
  33. package/deps/libmdbx/example/sample-bdb.txt +77 -0
  34. package/deps/libmdbx/mdbx.h +6655 -0
  35. package/deps/libmdbx/mdbx.h++ +6428 -0
  36. package/deps/libmdbx/packages/buildroot/0001-package-libmdbx-new-package-library-database.patch +173 -0
  37. package/deps/libmdbx/src/alloy.c +54 -0
  38. package/deps/libmdbx/src/api-cold.c +543 -0
  39. package/deps/libmdbx/src/api-copy.c +912 -0
  40. package/deps/libmdbx/src/api-cursor.c +754 -0
  41. package/deps/libmdbx/src/api-dbi.c +315 -0
  42. package/deps/libmdbx/src/api-env.c +1434 -0
  43. package/deps/libmdbx/src/api-extra.c +165 -0
  44. package/deps/libmdbx/src/api-key-transform.c +197 -0
  45. package/deps/libmdbx/src/api-misc.c +286 -0
  46. package/deps/libmdbx/src/api-opts.c +575 -0
  47. package/deps/libmdbx/src/api-range-estimate.c +365 -0
  48. package/deps/libmdbx/src/api-txn-data.c +454 -0
  49. package/deps/libmdbx/src/api-txn.c +921 -0
  50. package/deps/libmdbx/src/atomics-ops.h +364 -0
  51. package/deps/libmdbx/src/atomics-types.h +97 -0
  52. package/deps/libmdbx/src/audit.c +109 -0
  53. package/deps/libmdbx/src/bits.md +34 -0
  54. package/deps/libmdbx/src/chk.c +1796 -0
  55. package/deps/libmdbx/src/cogs.c +309 -0
  56. package/deps/libmdbx/src/cogs.h +506 -0
  57. package/deps/libmdbx/src/coherency.c +170 -0
  58. package/deps/libmdbx/src/config.h.in +88 -0
  59. package/deps/libmdbx/src/cursor.c +2396 -0
  60. package/deps/libmdbx/src/cursor.h +391 -0
  61. package/deps/libmdbx/src/dbi.c +717 -0
  62. package/deps/libmdbx/src/dbi.h +142 -0
  63. package/deps/libmdbx/src/debug_begin.h +36 -0
  64. package/deps/libmdbx/src/debug_end.h +15 -0
  65. package/deps/libmdbx/src/dpl.c +486 -0
  66. package/deps/libmdbx/src/dpl.h +134 -0
  67. package/deps/libmdbx/src/dxb.c +1335 -0
  68. package/deps/libmdbx/src/env.c +607 -0
  69. package/deps/libmdbx/src/essentials.h +125 -0
  70. package/deps/libmdbx/src/gc-get.c +1345 -0
  71. package/deps/libmdbx/src/gc-put.c +970 -0
  72. package/deps/libmdbx/src/gc.h +40 -0
  73. package/deps/libmdbx/src/global.c +474 -0
  74. package/deps/libmdbx/src/internals.h +585 -0
  75. package/deps/libmdbx/src/layout-dxb.h +288 -0
  76. package/deps/libmdbx/src/layout-lck.h +289 -0
  77. package/deps/libmdbx/src/lck-posix.c +859 -0
  78. package/deps/libmdbx/src/lck-windows.c +607 -0
  79. package/deps/libmdbx/src/lck.c +174 -0
  80. package/deps/libmdbx/src/lck.h +110 -0
  81. package/deps/libmdbx/src/logging_and_debug.c +250 -0
  82. package/deps/libmdbx/src/logging_and_debug.h +159 -0
  83. package/deps/libmdbx/src/man1/mdbx_chk.1 +106 -0
  84. package/deps/libmdbx/src/man1/mdbx_copy.1 +95 -0
  85. package/deps/libmdbx/src/man1/mdbx_drop.1 +48 -0
  86. package/deps/libmdbx/src/man1/mdbx_dump.1 +101 -0
  87. package/deps/libmdbx/src/man1/mdbx_load.1 +105 -0
  88. package/deps/libmdbx/src/man1/mdbx_stat.1 +86 -0
  89. package/deps/libmdbx/src/mdbx.c++ +1837 -0
  90. package/deps/libmdbx/src/meta.c +656 -0
  91. package/deps/libmdbx/src/meta.h +168 -0
  92. package/deps/libmdbx/src/mvcc-readers.c +414 -0
  93. package/deps/libmdbx/src/node.c +365 -0
  94. package/deps/libmdbx/src/node.h +102 -0
  95. package/deps/libmdbx/src/ntdll.def +1246 -0
  96. package/deps/libmdbx/src/options.h +534 -0
  97. package/deps/libmdbx/src/osal.c +3485 -0
  98. package/deps/libmdbx/src/osal.h +587 -0
  99. package/deps/libmdbx/src/page-get.c +483 -0
  100. package/deps/libmdbx/src/page-iov.c +185 -0
  101. package/deps/libmdbx/src/page-iov.h +34 -0
  102. package/deps/libmdbx/src/page-ops.c +744 -0
  103. package/deps/libmdbx/src/page-ops.h +142 -0
  104. package/deps/libmdbx/src/pnl.c +236 -0
  105. package/deps/libmdbx/src/pnl.h +146 -0
  106. package/deps/libmdbx/src/preface.h +990 -0
  107. package/deps/libmdbx/src/proto.h +105 -0
  108. package/deps/libmdbx/src/refund.c +212 -0
  109. package/deps/libmdbx/src/sort.h +484 -0
  110. package/deps/libmdbx/src/spill.c +431 -0
  111. package/deps/libmdbx/src/spill.h +74 -0
  112. package/deps/libmdbx/src/table.c +107 -0
  113. package/deps/libmdbx/src/tls.c +551 -0
  114. package/deps/libmdbx/src/tls.h +43 -0
  115. package/deps/libmdbx/src/tools/chk.c +673 -0
  116. package/deps/libmdbx/src/tools/copy.c +166 -0
  117. package/deps/libmdbx/src/tools/drop.c +199 -0
  118. package/deps/libmdbx/src/tools/dump.c +515 -0
  119. package/deps/libmdbx/src/tools/load.c +831 -0
  120. package/deps/libmdbx/src/tools/stat.c +516 -0
  121. package/deps/libmdbx/src/tools/wingetopt.c +87 -0
  122. package/deps/libmdbx/src/tools/wingetopt.h +30 -0
  123. package/deps/libmdbx/src/tree-ops.c +1554 -0
  124. package/deps/libmdbx/src/tree-search.c +140 -0
  125. package/deps/libmdbx/src/txl.c +99 -0
  126. package/deps/libmdbx/src/txl.h +26 -0
  127. package/deps/libmdbx/src/txn.c +1083 -0
  128. package/deps/libmdbx/src/unaligned.h +205 -0
  129. package/deps/libmdbx/src/utils.c +32 -0
  130. package/deps/libmdbx/src/utils.h +76 -0
  131. package/deps/libmdbx/src/version.c.in +44 -0
  132. package/deps/libmdbx/src/walk.c +290 -0
  133. package/deps/libmdbx/src/walk.h +20 -0
  134. package/deps/libmdbx/src/windows-import.c +152 -0
  135. package/deps/libmdbx/src/windows-import.h +128 -0
  136. package/deps/libmdbx/test/CMakeLists.txt +317 -0
  137. package/deps/libmdbx/test/append.c++ +237 -0
  138. package/deps/libmdbx/test/base.h++ +92 -0
  139. package/deps/libmdbx/test/battery-tmux.sh +64 -0
  140. package/deps/libmdbx/test/cases.c++ +118 -0
  141. package/deps/libmdbx/test/chrono.c++ +134 -0
  142. package/deps/libmdbx/test/chrono.h++ +85 -0
  143. package/deps/libmdbx/test/config.c++ +643 -0
  144. package/deps/libmdbx/test/config.h++ +334 -0
  145. package/deps/libmdbx/test/copy.c++ +62 -0
  146. package/deps/libmdbx/test/dead.c++ +39 -0
  147. package/deps/libmdbx/test/dump-load.sh +40 -0
  148. package/deps/libmdbx/test/extra/crunched_delete.c++ +409 -0
  149. package/deps/libmdbx/test/extra/cursor_closing.c++ +410 -0
  150. package/deps/libmdbx/test/extra/dbi.c++ +229 -0
  151. package/deps/libmdbx/test/extra/doubtless_positioning.c++ +253 -0
  152. package/deps/libmdbx/test/extra/dupfix_addodd.c +94 -0
  153. package/deps/libmdbx/test/extra/dupfix_multiple.c++ +311 -0
  154. package/deps/libmdbx/test/extra/early_close_dbi.c++ +137 -0
  155. package/deps/libmdbx/test/extra/hex_base64_base58.c++ +118 -0
  156. package/deps/libmdbx/test/extra/maindb_ordinal.c++ +61 -0
  157. package/deps/libmdbx/test/extra/open.c++ +96 -0
  158. package/deps/libmdbx/test/extra/pcrf/README.md +2 -0
  159. package/deps/libmdbx/test/extra/pcrf/pcrf_test.c +380 -0
  160. package/deps/libmdbx/test/extra/probe.c++ +10 -0
  161. package/deps/libmdbx/test/extra/txn.c++ +407 -0
  162. package/deps/libmdbx/test/extra/upsert_alldups.c +193 -0
  163. package/deps/libmdbx/test/fork.c++ +263 -0
  164. package/deps/libmdbx/test/hill.c++ +447 -0
  165. package/deps/libmdbx/test/jitter.c++ +197 -0
  166. package/deps/libmdbx/test/keygen.c++ +393 -0
  167. package/deps/libmdbx/test/keygen.h++ +130 -0
  168. package/deps/libmdbx/test/log.c++ +358 -0
  169. package/deps/libmdbx/test/log.h++ +91 -0
  170. package/deps/libmdbx/test/main.c++ +706 -0
  171. package/deps/libmdbx/test/nested.c++ +318 -0
  172. package/deps/libmdbx/test/osal-unix.c++ +647 -0
  173. package/deps/libmdbx/test/osal-windows.c++ +440 -0
  174. package/deps/libmdbx/test/osal.h++ +41 -0
  175. package/deps/libmdbx/test/stochastic.sh +690 -0
  176. package/deps/libmdbx/test/stub/LICENSE +24 -0
  177. package/deps/libmdbx/test/stub/README.md +8 -0
  178. package/deps/libmdbx/test/stub/pthread_barrier.c +104 -0
  179. package/deps/libmdbx/test/stub/pthread_barrier.h +77 -0
  180. package/deps/libmdbx/test/test.c++ +1551 -0
  181. package/deps/libmdbx/test/test.h++ +298 -0
  182. package/deps/libmdbx/test/tmux.conf +3 -0
  183. package/deps/libmdbx/test/try.c++ +30 -0
  184. package/deps/libmdbx/test/ttl.c++ +240 -0
  185. package/deps/libmdbx/test/utils.c++ +203 -0
  186. package/deps/libmdbx/test/utils.h++ +326 -0
  187. package/deps/libmdbx/test/valgrind_suppress.txt +536 -0
  188. package/lib/mdbx_evn_async.js +211 -0
  189. package/lib/mdbx_worker.js +195 -0
  190. package/lib/nativemou.js +6 -0
  191. package/package.json +38 -0
  192. package/src/async/envmou_close.cpp +34 -0
  193. package/src/async/envmou_close.hpp +32 -0
  194. package/src/async/envmou_copy_to.cpp +29 -0
  195. package/src/async/envmou_copy_to.hpp +38 -0
  196. package/src/async/envmou_keys.cpp +201 -0
  197. package/src/async/envmou_keys.hpp +50 -0
  198. package/src/async/envmou_open.cpp +38 -0
  199. package/src/async/envmou_open.hpp +33 -0
  200. package/src/async/envmou_query.cpp +167 -0
  201. package/src/async/envmou_query.hpp +53 -0
  202. package/src/dbimou.cpp +522 -0
  203. package/src/dbimou.hpp +82 -0
  204. package/src/env_arg0.hpp +24 -0
  205. package/src/envmou.cpp +445 -0
  206. package/src/envmou.hpp +116 -0
  207. package/src/modulemou.cpp +113 -0
  208. package/src/querymou.cpp +177 -0
  209. package/src/querymou.hpp +93 -0
  210. package/src/txnmou.cpp +254 -0
  211. package/src/txnmou.hpp +122 -0
  212. package/src/typemou.hpp +239 -0
  213. package/src/valuemou.hpp +194 -0
  214. package/test/async.js +67 -0
  215. package/test/e3.js +38 -0
  216. package/test/e4.js +89 -0
  217. package/test/e5.js +162 -0
  218. package/test/test-batch-ops.js +243 -0
  219. package/test/test-cursor-mode.js +84 -0
  220. package/test/test-multi-mode.js +87 -0
@@ -0,0 +1,1837 @@
1
+ /// \copyright SPDX-License-Identifier: Apache-2.0
2
+ /// \author Леонид Юрьев aka Leonid Yuriev <leo@yuriev.ru> \date 2020-2025
3
+ ///
4
+ /// \brief Non-inline part of the libmdbx C++ API
5
+ ///
6
+
7
+ #include "essentials.h"
8
+
9
+ #if !defined(MDBX_BUILD_CXX) || MDBX_BUILD_CXX != 1
10
+ #error "Build is misconfigured! Expecting MDBX_BUILD_CXX=1 for C++ API."
11
+ #endif /* MDBX_BUILD_CXX*/
12
+
13
+ /* Workaround for MSVC' header `extern "C"` vs `std::` redefinition bug */
14
+ #if defined(_MSC_VER)
15
+ #if defined(__SANITIZE_ADDRESS__) && !defined(_DISABLE_VECTOR_ANNOTATION)
16
+ #define _DISABLE_VECTOR_ANNOTATION
17
+ #endif /* _DISABLE_VECTOR_ANNOTATION */
18
+ #ifndef _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING
19
+ #define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING
20
+ #endif /* #define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING */
21
+ #endif /* _MSC_VER */
22
+
23
+ #include "../mdbx.h++"
24
+
25
+ #include <array>
26
+ #include <atomic>
27
+ #include <cctype> // for isxdigit(), etc
28
+ #include <system_error>
29
+
30
+ namespace {
31
+
32
+ #if 0 /* Unused for now */
33
+
34
+ class trouble_location {
35
+
36
+ #ifndef TROUBLE_PROVIDE_LINENO
37
+ #define TROUBLE_PROVIDE_LINENO 1
38
+ #endif
39
+
40
+ #ifndef TROUBLE_PROVIDE_CONDITION
41
+ #define TROUBLE_PROVIDE_CONDITION 1
42
+ #endif
43
+
44
+ #ifndef TROUBLE_PROVIDE_FUNCTION
45
+ #define TROUBLE_PROVIDE_FUNCTION 1
46
+ #endif
47
+
48
+ #ifndef TROUBLE_PROVIDE_FILENAME
49
+ #define TROUBLE_PROVIDE_FILENAME 1
50
+ #endif
51
+
52
+ #if TROUBLE_PROVIDE_LINENO
53
+ const unsigned line_;
54
+ #endif
55
+ #if TROUBLE_PROVIDE_CONDITION
56
+ const char *const condition_;
57
+ #endif
58
+ #if TROUBLE_PROVIDE_FUNCTION
59
+ const char *const function_;
60
+ #endif
61
+ #if TROUBLE_PROVIDE_FILENAME
62
+ const char *const filename_;
63
+ #endif
64
+
65
+ public:
66
+ MDBX_CXX11_CONSTEXPR trouble_location(unsigned line, const char *condition, const char *function,
67
+ const char *filename)
68
+ :
69
+ #if TROUBLE_PROVIDE_LINENO
70
+ line_(line)
71
+ #endif
72
+ #if TROUBLE_PROVIDE_CONDITION
73
+ ,
74
+ condition_(condition)
75
+ #endif
76
+ #if TROUBLE_PROVIDE_FUNCTION
77
+ ,
78
+ function_(function)
79
+ #endif
80
+ #if TROUBLE_PROVIDE_FILENAME
81
+ ,
82
+ filename_(filename)
83
+ #endif
84
+ {
85
+ #if !TROUBLE_PROVIDE_LINENO
86
+ (void)line;
87
+ #endif
88
+ #if !TROUBLE_PROVIDE_CONDITION
89
+ (void)condition;
90
+ #endif
91
+ #if !TROUBLE_PROVIDE_FUNCTION
92
+ (void)function;
93
+ #endif
94
+ #if !TROUBLE_PROVIDE_FILENAME
95
+ (void)filename;
96
+ #endif
97
+ }
98
+
99
+ trouble_location(const trouble_location &&) = delete;
100
+
101
+ unsigned line() const {
102
+ #if TROUBLE_PROVIDE_LINENO
103
+ return line_;
104
+ #else
105
+ return 0;
106
+ #endif
107
+ }
108
+
109
+ const char *condition() const {
110
+ #if TROUBLE_PROVIDE_CONDITION
111
+ return condition_;
112
+ #else
113
+ return "";
114
+ #endif
115
+ }
116
+
117
+ const char *function() const {
118
+ #if TROUBLE_PROVIDE_FUNCTION
119
+ return function_;
120
+ #else
121
+ return "";
122
+ #endif
123
+ }
124
+
125
+ const char *filename() const {
126
+ #if TROUBLE_PROVIDE_FILENAME
127
+ return filename_;
128
+ #else
129
+ return "";
130
+ #endif
131
+ }
132
+ };
133
+
134
+ //------------------------------------------------------------------------------
135
+
136
+ __cold std::string format_va(const char *fmt, va_list ap) {
137
+ va_list ones;
138
+ va_copy(ones, ap);
139
+ #ifdef _MSC_VER
140
+ int needed = _vscprintf(fmt, ap);
141
+ #else
142
+ int needed = vsnprintf(nullptr, 0, fmt, ap);
143
+ #endif
144
+ assert(needed >= 0);
145
+ std::string result;
146
+ result.reserve(size_t(needed + 1));
147
+ result.resize(size_t(needed), '\0');
148
+ assert(int(result.capacity()) > needed);
149
+ int actual = vsnprintf(const_cast<char *>(result.data()), result.capacity(), fmt, ones);
150
+ assert(actual == needed);
151
+ (void)actual;
152
+ va_end(ones);
153
+ return result;
154
+ }
155
+
156
+ __cold std::string format(const char *fmt, ...) {
157
+ va_list ap;
158
+ va_start(ap, fmt);
159
+ std::string result = format_va(fmt, ap);
160
+ va_end(ap);
161
+ return result;
162
+ }
163
+
164
+ class bug : public std::runtime_error {
165
+ const trouble_location &location_;
166
+
167
+ public:
168
+ bug(const trouble_location &) noexcept;
169
+ /* temporary workaround for "private field 'FOO' is not used" from CLANG
170
+ * and for "function 'BAR' was declared but never referenced" from LCC. */
171
+ #ifndef __LCC__
172
+ const trouble_location &location() const noexcept { return location_; }
173
+ #endif
174
+ virtual ~bug() noexcept;
175
+ };
176
+
177
+ __cold bug::bug(const trouble_location &location) noexcept
178
+ : std::runtime_error(format("mdbx.bug: %s.%s at %s:%u", location.function(), location.condition(),
179
+ location.filename(), location.line())),
180
+ location_(location) {}
181
+
182
+ __cold bug::~bug() noexcept {}
183
+
184
+ [[maybe_unused, noreturn]] __cold void raise_bug(const trouble_location &what_and_where) { throw bug(what_and_where); }
185
+
186
+ #define RAISE_BUG(line, condition, function, file) \
187
+ do { \
188
+ static MDBX_CXX11_CONSTEXPR_VAR trouble_location bug(line, condition, function, file); \
189
+ raise_bug(bug); \
190
+ } while (0)
191
+
192
+ #undef ENSURE
193
+ #define ENSURE(condition) \
194
+ do \
195
+ if (MDBX_UNLIKELY(!(condition))) \
196
+ MDBX_CXX20_UNLIKELY RAISE_BUG(__LINE__, #condition, __func__, __FILE__); \
197
+ while (0)
198
+
199
+ #define NOT_IMPLEMENTED() RAISE_BUG(__LINE__, "not_implemented", __func__, __FILE__);
200
+
201
+ #endif /* Unused*/
202
+
203
+ struct line_wrapper {
204
+ char *line, *ptr;
205
+ line_wrapper(char *buf) noexcept : line(buf), ptr(buf) {}
206
+ void put(char c, size_t wrap_width) noexcept {
207
+ *ptr++ = c;
208
+ if (wrap_width && ptr >= wrap_width + line) {
209
+ *ptr++ = '\n';
210
+ line = ptr;
211
+ }
212
+ }
213
+ void put(const ::mdbx::slice &chunk, size_t wrap_width) noexcept {
214
+ if (!wrap_width || wrap_width > (ptr - line) + chunk.length()) {
215
+ memcpy(ptr, chunk.data(), chunk.length());
216
+ ptr += chunk.length();
217
+ } else {
218
+ for (size_t i = 0; i < chunk.length(); ++i)
219
+ put(chunk.char_ptr()[i], wrap_width);
220
+ }
221
+ }
222
+ };
223
+
224
+ template <typename TYPE, unsigned INPLACE_BYTES = unsigned(sizeof(void *) * 64)> struct temp_buffer {
225
+ TYPE inplace[(INPLACE_BYTES + sizeof(TYPE) - 1) / sizeof(TYPE)];
226
+ const size_t size;
227
+ TYPE *const area;
228
+ temp_buffer(size_t bytes)
229
+ : size((bytes + sizeof(TYPE) - 1) / sizeof(TYPE)), area((bytes > sizeof(inplace)) ? new TYPE[size] : inplace) {
230
+ memset(area, 0, sizeof(TYPE) * size);
231
+ }
232
+ ~temp_buffer() {
233
+ if (area != inplace)
234
+ delete[] area;
235
+ }
236
+ TYPE *end() const { return area + size; }
237
+ };
238
+
239
+ } // namespace
240
+
241
+ #ifndef MDBX_CXX_ENDL
242
+ /* Манипулятор std::endl выталкивате буфферизированый вывод, что здесь не
243
+ * требуется.
244
+ *
245
+ * Кроме этого, при сборке libmdbx для символов по-умолчанию выключается
246
+ * видимость вне DSO, из-за чего обращение к std::endl иногда укачивает
247
+ * линковщики, если комплятор ошибочно формируют direct access к global weak
248
+ * symbol, коим является std::endl. */
249
+ #if 0
250
+ #define MDBX_CXX_ENDL ::std::endl
251
+ #else
252
+ #define MDBX_CXX_ENDL "\n"
253
+ #endif
254
+ #endif /* MDBX_CXX_ENDL */
255
+
256
+ //------------------------------------------------------------------------------
257
+
258
+ namespace mdbx {
259
+
260
+ [[noreturn]] __cold void throw_max_length_exceeded() {
261
+ throw std::length_error("mdbx:: Exceeded the maximal length of data/slice/buffer.");
262
+ }
263
+
264
+ [[noreturn]] __cold void throw_too_small_target_buffer() {
265
+ throw std::length_error("mdbx:: The target buffer is too small.");
266
+ }
267
+
268
+ [[noreturn]] __cold void throw_out_range() {
269
+ throw std::out_of_range("mdbx:: Slice or buffer method was called with "
270
+ "an argument that exceeds the length.");
271
+ }
272
+
273
+ [[noreturn]] __cold void throw_allocators_mismatch() {
274
+ throw std::logic_error("mdbx:: An allocators mismatch, so an object could not be transferred "
275
+ "into an incompatible memory allocation scheme.");
276
+ }
277
+
278
+ [[noreturn]] __cold void throw_incomparable_cursors() {
279
+ throw std::logic_error("mdbx:: incomparable and/or invalid cursors to compare positions.");
280
+ }
281
+
282
+ [[noreturn]] __cold void throw_bad_value_size() { throw bad_value_size(MDBX_BAD_VALSIZE); }
283
+
284
+ __cold exception::exception(const ::mdbx::error &error) noexcept : base(error.what()), error_(error) {}
285
+
286
+ __cold exception::~exception() noexcept {}
287
+
288
+ static std::atomic_int fatal_countdown;
289
+
290
+ __cold fatal::fatal(const ::mdbx::error &error) noexcept : base(error) { ++fatal_countdown; }
291
+
292
+ __cold fatal::~fatal() noexcept {
293
+ if (--fatal_countdown == 0)
294
+ std::terminate();
295
+ }
296
+
297
+ #define DEFINE_EXCEPTION(NAME) \
298
+ __cold NAME::NAME(const ::mdbx::error &rc) : exception(rc) {} \
299
+ __cold NAME::~NAME() noexcept {}
300
+
301
+ DEFINE_EXCEPTION(bad_map_id)
302
+ DEFINE_EXCEPTION(bad_transaction)
303
+ DEFINE_EXCEPTION(bad_value_size)
304
+ DEFINE_EXCEPTION(db_corrupted)
305
+ DEFINE_EXCEPTION(db_full)
306
+ DEFINE_EXCEPTION(db_invalid)
307
+ DEFINE_EXCEPTION(db_too_large)
308
+ DEFINE_EXCEPTION(db_unable_extend)
309
+ DEFINE_EXCEPTION(db_version_mismatch)
310
+ DEFINE_EXCEPTION(db_wanna_write_for_recovery)
311
+ DEFINE_EXCEPTION(incompatible_operation)
312
+ DEFINE_EXCEPTION(internal_page_full)
313
+ DEFINE_EXCEPTION(internal_problem)
314
+ DEFINE_EXCEPTION(key_exists)
315
+ DEFINE_EXCEPTION(key_mismatch)
316
+ DEFINE_EXCEPTION(max_maps_reached)
317
+ DEFINE_EXCEPTION(max_readers_reached)
318
+ DEFINE_EXCEPTION(multivalue)
319
+ DEFINE_EXCEPTION(no_data)
320
+ DEFINE_EXCEPTION(not_found)
321
+ DEFINE_EXCEPTION(operation_not_permitted)
322
+ DEFINE_EXCEPTION(permission_denied_or_not_writeable)
323
+ DEFINE_EXCEPTION(reader_slot_busy)
324
+ DEFINE_EXCEPTION(remote_media)
325
+ DEFINE_EXCEPTION(something_busy)
326
+ DEFINE_EXCEPTION(thread_mismatch)
327
+ DEFINE_EXCEPTION(transaction_full)
328
+ DEFINE_EXCEPTION(transaction_overlapping)
329
+ DEFINE_EXCEPTION(duplicated_lck_file)
330
+ DEFINE_EXCEPTION(dangling_map_id)
331
+ DEFINE_EXCEPTION(transaction_ousted)
332
+ DEFINE_EXCEPTION(mvcc_retarded)
333
+ #undef DEFINE_EXCEPTION
334
+
335
+ __cold const char *error::what() const noexcept {
336
+ if (is_mdbx_error())
337
+ return mdbx_liberr2str(code());
338
+
339
+ switch (code()) {
340
+ #define ERROR_CASE(CODE) \
341
+ case CODE: \
342
+ return MDBX_STRINGIFY(CODE)
343
+ ERROR_CASE(MDBX_ENODATA);
344
+ ERROR_CASE(MDBX_EINVAL);
345
+ ERROR_CASE(MDBX_EACCESS);
346
+ ERROR_CASE(MDBX_ENOMEM);
347
+ ERROR_CASE(MDBX_EROFS);
348
+ ERROR_CASE(MDBX_ENOSYS);
349
+ ERROR_CASE(MDBX_EIO);
350
+ ERROR_CASE(MDBX_EPERM);
351
+ ERROR_CASE(MDBX_EINTR);
352
+ ERROR_CASE(MDBX_ENOFILE);
353
+ ERROR_CASE(MDBX_EREMOTE);
354
+ ERROR_CASE(MDBX_EDEADLK);
355
+ #undef ERROR_CASE
356
+ default:
357
+ return "SYSTEM";
358
+ }
359
+ }
360
+
361
+ __cold std::string error::message() const {
362
+ char buf[1024];
363
+ const char *msg = ::mdbx_strerror_r(code(), buf, sizeof(buf));
364
+ return std::string(msg ? msg : "unknown");
365
+ }
366
+
367
+ [[noreturn]] __cold void error::panic(const char *context, const char *func) const noexcept {
368
+ assert(code() != MDBX_SUCCESS);
369
+ ::mdbx_panic("mdbx::%s.%s(): \"%s\" (%d)", context, func, what(), code());
370
+ std::terminate();
371
+ }
372
+
373
+ __cold void error::throw_exception() const {
374
+ switch (code()) {
375
+ case MDBX_EINVAL:
376
+ throw std::invalid_argument("MDBX_EINVAL");
377
+ case MDBX_ENOMEM:
378
+ throw std::bad_alloc();
379
+ case MDBX_SUCCESS:
380
+ static_assert(MDBX_SUCCESS == MDBX_RESULT_FALSE, "WTF?");
381
+ throw std::logic_error("MDBX_SUCCESS (MDBX_RESULT_FALSE)");
382
+ case MDBX_RESULT_TRUE:
383
+ throw std::logic_error("MDBX_RESULT_TRUE");
384
+ #define CASE_EXCEPTION(NAME, CODE) \
385
+ case CODE: \
386
+ throw NAME(code())
387
+ CASE_EXCEPTION(bad_map_id, MDBX_BAD_DBI);
388
+ CASE_EXCEPTION(bad_transaction, MDBX_BAD_TXN);
389
+ CASE_EXCEPTION(bad_value_size, MDBX_BAD_VALSIZE);
390
+ CASE_EXCEPTION(db_corrupted, MDBX_CORRUPTED);
391
+ CASE_EXCEPTION(db_corrupted, MDBX_CURSOR_FULL); /* branch-pages loop */
392
+ CASE_EXCEPTION(db_corrupted, MDBX_PAGE_NOTFOUND);
393
+ CASE_EXCEPTION(db_full, MDBX_MAP_FULL);
394
+ CASE_EXCEPTION(db_invalid, MDBX_INVALID);
395
+ CASE_EXCEPTION(db_too_large, MDBX_TOO_LARGE);
396
+ CASE_EXCEPTION(db_unable_extend, MDBX_UNABLE_EXTEND_MAPSIZE);
397
+ CASE_EXCEPTION(db_version_mismatch, MDBX_VERSION_MISMATCH);
398
+ CASE_EXCEPTION(db_wanna_write_for_recovery, MDBX_WANNA_RECOVERY);
399
+ CASE_EXCEPTION(fatal, MDBX_EBADSIGN);
400
+ CASE_EXCEPTION(fatal, MDBX_PANIC);
401
+ CASE_EXCEPTION(incompatible_operation, MDBX_INCOMPATIBLE);
402
+ CASE_EXCEPTION(internal_page_full, MDBX_PAGE_FULL);
403
+ CASE_EXCEPTION(internal_problem, MDBX_PROBLEM);
404
+ CASE_EXCEPTION(key_exists, MDBX_KEYEXIST);
405
+ CASE_EXCEPTION(key_mismatch, MDBX_EKEYMISMATCH);
406
+ CASE_EXCEPTION(max_maps_reached, MDBX_DBS_FULL);
407
+ CASE_EXCEPTION(max_readers_reached, MDBX_READERS_FULL);
408
+ CASE_EXCEPTION(multivalue, MDBX_EMULTIVAL);
409
+ CASE_EXCEPTION(no_data, MDBX_ENODATA);
410
+ CASE_EXCEPTION(not_found, MDBX_NOTFOUND);
411
+ CASE_EXCEPTION(operation_not_permitted, MDBX_EPERM);
412
+ CASE_EXCEPTION(permission_denied_or_not_writeable, MDBX_EACCESS);
413
+ CASE_EXCEPTION(reader_slot_busy, MDBX_BAD_RSLOT);
414
+ CASE_EXCEPTION(remote_media, MDBX_EREMOTE);
415
+ CASE_EXCEPTION(something_busy, MDBX_BUSY);
416
+ CASE_EXCEPTION(thread_mismatch, MDBX_THREAD_MISMATCH);
417
+ CASE_EXCEPTION(transaction_full, MDBX_TXN_FULL);
418
+ CASE_EXCEPTION(transaction_overlapping, MDBX_TXN_OVERLAPPING);
419
+ CASE_EXCEPTION(duplicated_lck_file, MDBX_DUPLICATED_CLK);
420
+ CASE_EXCEPTION(dangling_map_id, MDBX_DANGLING_DBI);
421
+ CASE_EXCEPTION(transaction_ousted, MDBX_OUSTED);
422
+ CASE_EXCEPTION(mvcc_retarded, MDBX_MVCC_RETARDED);
423
+ #undef CASE_EXCEPTION
424
+ default:
425
+ if (is_mdbx_error())
426
+ throw exception(*this);
427
+ throw std::system_error(std::error_code(code(), std::system_category()));
428
+ }
429
+ }
430
+
431
+ //------------------------------------------------------------------------------
432
+
433
+ bool slice::is_printable(bool disable_utf8) const noexcept {
434
+ enum : byte {
435
+ LS = 4, // shift for UTF8 sequence length
436
+ P_ = 1 << LS, // printable ASCII flag
437
+ N_ = 0, // non-printable ASCII
438
+ second_range_mask = P_ - 1, // mask for range flag
439
+ r80_BF = 0, // flag for UTF8 2nd byte range
440
+ rA0_BF = 1, // flag for UTF8 2nd byte range
441
+ r80_9F = 2, // flag for UTF8 2nd byte range
442
+ r90_BF = 3, // flag for UTF8 2nd byte range
443
+ r80_8F = 4, // flag for UTF8 2nd byte range
444
+
445
+ // valid utf-8 byte sequences
446
+ // http://www.unicode.org/versions/Unicode6.0.0/ch03.pdf - page 94
447
+ // Code | Bytes | | |
448
+ // Points | 1st | 2nd | 3rd |4th
449
+ // --------------------|--------|--------|--------|---
450
+ C2 = 2 << LS | r80_BF, // U+000080..U+0007FF | C2..DF | 80..BF | |
451
+ E0 = 3 << LS | rA0_BF, // U+000800..U+000FFF | E0 | A0..BF | 80..BF |
452
+ E1 = 3 << LS | r80_BF, // U+001000..U+00CFFF | E1..EC | 80..BF | 80..BF |
453
+ ED = 3 << LS | r80_9F, // U+00D000..U+00D7FF | ED | 80..9F | 80..BF |
454
+ EE = 3 << LS | r80_BF, // U+00E000..U+00FFFF | EE..EF | 80..BF | 80..BF |
455
+ F0 = 4 << LS | r90_BF, // U+010000..U+03FFFF | F0 | 90..BF | 80..BF |...
456
+ F1 = 4 << LS | r80_BF, // U+040000..U+0FFFFF | F1..F3 | 80..BF | 80..BF |...
457
+ F4 = 4 << LS | r80_BF, // U+100000..U+10FFFF | F4 | 80..8F | 80..BF |...
458
+ };
459
+
460
+ static const byte range_from[] = {0x80, 0xA0, 0x80, 0x90, 0x80};
461
+ static const byte range_to[] = {0xBF, 0xBF, 0x9F, 0xBF, 0x8F};
462
+
463
+ static const byte map[256] = {
464
+ // 1 2 3 4 5 6 7 8 9 a b c d e f
465
+ N_, N_, N_, N_, N_, N_, N_, N_, N_, N_, N_, N_, N_, N_, N_, N_, // 00
466
+ N_, N_, N_, N_, N_, N_, N_, N_, N_, N_, N_, N_, N_, N_, N_, N_, // 10
467
+ P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, // 20
468
+ P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, // 30
469
+ P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, // 40
470
+ P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, // 50
471
+ P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, // 60
472
+ P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, N_, // 70
473
+ N_, N_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, N_, P_, N_, // 80
474
+ N_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, N_, P_, P_, // 90
475
+ P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, // a0
476
+ P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, // b0
477
+ P_, P_, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, // c0
478
+ C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, C2, // df
479
+ E0, E1, E1, E1, E1, E1, E1, E1, E1, E1, E1, E1, E1, ED, EE, EE, // e0
480
+ F0, F1, F1, F1, F4, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_, P_ // f0
481
+ };
482
+
483
+ if (MDBX_UNLIKELY(length() < 1))
484
+ MDBX_CXX20_UNLIKELY return false;
485
+
486
+ auto src = byte_ptr();
487
+ const auto end = src + length();
488
+ if (MDBX_UNLIKELY(disable_utf8)) {
489
+ do
490
+ if (MDBX_UNLIKELY((P_ & map[*src]) == 0))
491
+ MDBX_CXX20_UNLIKELY return false;
492
+ while (++src < end);
493
+ return true;
494
+ }
495
+
496
+ do {
497
+ const auto bits = map[*src];
498
+ const auto second_from = range_from[bits & second_range_mask];
499
+ const auto second_to = range_to[bits & second_range_mask];
500
+ switch (bits >> LS) {
501
+ default:
502
+ MDBX_CXX20_UNLIKELY return false;
503
+ case 1:
504
+ src += 1;
505
+ continue;
506
+ case 2:
507
+ if (MDBX_UNLIKELY(src + 1 >= end))
508
+ MDBX_CXX20_UNLIKELY return false;
509
+ if (MDBX_UNLIKELY(src[1] < second_from || src[1] > second_to))
510
+ MDBX_CXX20_UNLIKELY return false;
511
+ src += 2;
512
+ continue;
513
+ case 3:
514
+ if (MDBX_UNLIKELY(src + 3 >= end))
515
+ MDBX_CXX20_UNLIKELY return false;
516
+ if (MDBX_UNLIKELY(src[1] < second_from || src[1] > second_to))
517
+ MDBX_CXX20_UNLIKELY return false;
518
+ if (MDBX_UNLIKELY(src[2] < 0x80 || src[2] > 0xBF))
519
+ MDBX_CXX20_UNLIKELY return false;
520
+ src += 3;
521
+ continue;
522
+ case 4:
523
+ if (MDBX_UNLIKELY(src + 4 >= end))
524
+ MDBX_CXX20_UNLIKELY return false;
525
+ if (MDBX_UNLIKELY(src[1] < second_from || src[1] > second_to))
526
+ MDBX_CXX20_UNLIKELY return false;
527
+ if (MDBX_UNLIKELY(src[2] < 0x80 || src[2] > 0xBF))
528
+ MDBX_CXX20_UNLIKELY return false;
529
+ if (MDBX_UNLIKELY(src[3] < 0x80 || src[3] > 0xBF))
530
+ MDBX_CXX20_UNLIKELY return false;
531
+ src += 4;
532
+ continue;
533
+ }
534
+ } while (src < end);
535
+
536
+ return true;
537
+ }
538
+
539
+ #ifdef MDBX_U128_TYPE
540
+ MDBX_U128_TYPE slice::as_uint128_adapt() const {
541
+ static_assert(sizeof(MDBX_U128_TYPE) == 16, "WTF?");
542
+ if (size() == 16) {
543
+ MDBX_U128_TYPE r;
544
+ memcpy(&r, data(), sizeof(r));
545
+ return r;
546
+ } else
547
+ return as_uint64_adapt();
548
+ }
549
+ #endif /* MDBX_U128_TYPE */
550
+
551
+ uint64_t slice::as_uint64_adapt() const {
552
+ static_assert(sizeof(uint64_t) == 8, "WTF?");
553
+ if (size() == 8) {
554
+ uint64_t r;
555
+ memcpy(&r, data(), sizeof(r));
556
+ return r;
557
+ } else
558
+ return as_uint32_adapt();
559
+ }
560
+
561
+ uint32_t slice::as_uint32_adapt() const {
562
+ static_assert(sizeof(uint32_t) == 4, "WTF?");
563
+ if (size() == 4) {
564
+ uint32_t r;
565
+ memcpy(&r, data(), sizeof(r));
566
+ return r;
567
+ } else
568
+ return as_uint16_adapt();
569
+ }
570
+
571
+ uint16_t slice::as_uint16_adapt() const {
572
+ static_assert(sizeof(uint16_t) == 2, "WTF?");
573
+ if (size() == 2) {
574
+ uint16_t r;
575
+ memcpy(&r, data(), sizeof(r));
576
+ return r;
577
+ } else
578
+ return as_uint8_adapt();
579
+ }
580
+
581
+ uint8_t slice::as_uint8_adapt() const {
582
+ static_assert(sizeof(uint8_t) == 1, "WTF?");
583
+ if (size() == 1)
584
+ return *static_cast<const uint8_t *>(data());
585
+ else if (size() == 0)
586
+ return 0;
587
+ else
588
+ MDBX_CXX20_UNLIKELY throw_bad_value_size();
589
+ }
590
+
591
+ #ifdef MDBX_I128_TYPE
592
+ MDBX_I128_TYPE slice::as_int128_adapt() const {
593
+ static_assert(sizeof(MDBX_I128_TYPE) == 16, "WTF?");
594
+ if (size() == 16) {
595
+ MDBX_I128_TYPE r;
596
+ memcpy(&r, data(), sizeof(r));
597
+ return r;
598
+ } else
599
+ return as_int64_adapt();
600
+ }
601
+ #endif /* MDBX_I128_TYPE */
602
+
603
+ int64_t slice::as_int64_adapt() const {
604
+ static_assert(sizeof(int64_t) == 8, "WTF?");
605
+ if (size() == 8) {
606
+ uint64_t r;
607
+ memcpy(&r, data(), sizeof(r));
608
+ return r;
609
+ } else
610
+ return as_int32_adapt();
611
+ }
612
+
613
+ int32_t slice::as_int32_adapt() const {
614
+ static_assert(sizeof(int32_t) == 4, "WTF?");
615
+ if (size() == 4) {
616
+ int32_t r;
617
+ memcpy(&r, data(), sizeof(r));
618
+ return r;
619
+ } else
620
+ return as_int16_adapt();
621
+ }
622
+
623
+ int16_t slice::as_int16_adapt() const {
624
+ static_assert(sizeof(int16_t) == 2, "WTF?");
625
+ if (size() == 2) {
626
+ int16_t r;
627
+ memcpy(&r, data(), sizeof(r));
628
+ return r;
629
+ } else
630
+ return as_int8_adapt();
631
+ }
632
+
633
+ int8_t slice::as_int8_adapt() const {
634
+ if (size() == 1)
635
+ return *static_cast<const int8_t *>(data());
636
+ else if (size() == 0)
637
+ return 0;
638
+ else
639
+ MDBX_CXX20_UNLIKELY throw_bad_value_size();
640
+ }
641
+
642
+ //------------------------------------------------------------------------------
643
+
644
+ char *to_hex::write_bytes(char *__restrict const dest, size_t dest_size) const {
645
+ if (MDBX_UNLIKELY(envisage_result_length() > dest_size))
646
+ MDBX_CXX20_UNLIKELY throw_too_small_target_buffer();
647
+
648
+ auto ptr = dest;
649
+ auto src = source.byte_ptr();
650
+ const char alpha_shift = (uppercase ? 'A' : 'a') - '9' - 1;
651
+ auto line = ptr;
652
+ for (const auto end = source.end_byte_ptr(); src != end; ++src) {
653
+ if (wrap_width && size_t(ptr - line) >= wrap_width) {
654
+ *ptr = '\n';
655
+ line = ++ptr;
656
+ }
657
+ const int8_t hi = *src >> 4;
658
+ const int8_t lo = *src & 15;
659
+ ptr[0] = char('0' + hi + (((9 - hi) >> 7) & alpha_shift));
660
+ ptr[1] = char('0' + lo + (((9 - lo) >> 7) & alpha_shift));
661
+ ptr += 2;
662
+ assert(ptr <= dest + dest_size);
663
+ }
664
+ return ptr;
665
+ }
666
+
667
+ ::std::ostream &to_hex::output(::std::ostream &out) const {
668
+ if (MDBX_LIKELY(!is_empty()))
669
+ MDBX_CXX20_LIKELY {
670
+ ::std::ostream::sentry sentry(out);
671
+ auto src = source.byte_ptr();
672
+ const char alpha_shift = (uppercase ? 'A' : 'a') - '9' - 1;
673
+ unsigned width = 0;
674
+ for (const auto end = source.end_byte_ptr(); src != end; ++src) {
675
+ if (wrap_width && width >= wrap_width) {
676
+ out << MDBX_CXX_ENDL;
677
+ width = 0;
678
+ }
679
+ const int8_t hi = *src >> 4;
680
+ const int8_t lo = *src & 15;
681
+ out.put(char('0' + hi + (((9 - hi) >> 7) & alpha_shift)));
682
+ out.put(char('0' + lo + (((9 - lo) >> 7) & alpha_shift)));
683
+ width += 2;
684
+ }
685
+ }
686
+ return out;
687
+ }
688
+
689
+ char *from_hex::write_bytes(char *__restrict const dest, size_t dest_size) const {
690
+ if (MDBX_UNLIKELY(source.length() % 2 && !ignore_spaces))
691
+ MDBX_CXX20_UNLIKELY throw std::domain_error("mdbx::from_hex:: odd length of hexadecimal string");
692
+ if (MDBX_UNLIKELY(envisage_result_length() > dest_size))
693
+ MDBX_CXX20_UNLIKELY throw_too_small_target_buffer();
694
+
695
+ auto ptr = dest;
696
+ auto src = source.byte_ptr();
697
+ for (auto left = source.length(); left > 0;) {
698
+ if (MDBX_UNLIKELY(*src <= ' ') && MDBX_LIKELY(ignore_spaces && isspace(*src))) {
699
+ ++src;
700
+ --left;
701
+ continue;
702
+ }
703
+
704
+ if (MDBX_UNLIKELY(left < 1 || !isxdigit(src[0]) || !isxdigit(src[1])))
705
+ MDBX_CXX20_UNLIKELY throw std::domain_error("mdbx::from_hex:: invalid hexadecimal string");
706
+
707
+ int8_t hi = src[0];
708
+ hi = (hi | 0x20) - 'a';
709
+ hi += 10 + ((hi >> 7) & 39);
710
+
711
+ int8_t lo = src[1];
712
+ lo = (lo | 0x20) - 'a';
713
+ lo += 10 + ((lo >> 7) & 39);
714
+
715
+ *ptr++ = hi << 4 | lo;
716
+ src += 2;
717
+ left -= 2;
718
+ assert(ptr <= dest + dest_size);
719
+ }
720
+ return ptr;
721
+ }
722
+
723
+ bool from_hex::is_erroneous() const noexcept {
724
+ if (MDBX_UNLIKELY(source.length() % 2 && !ignore_spaces))
725
+ MDBX_CXX20_UNLIKELY return true;
726
+
727
+ bool got = false;
728
+ auto src = source.byte_ptr();
729
+ for (auto left = source.length(); left > 0;) {
730
+ if (MDBX_UNLIKELY(*src <= ' ') && MDBX_LIKELY(ignore_spaces && isspace(*src))) {
731
+ ++src;
732
+ --left;
733
+ continue;
734
+ }
735
+
736
+ if (MDBX_UNLIKELY(left < 1 || !isxdigit(src[0]) || !isxdigit(src[1])))
737
+ MDBX_CXX20_UNLIKELY return true;
738
+
739
+ got = true;
740
+ src += 2;
741
+ left -= 2;
742
+ }
743
+ return !got;
744
+ }
745
+
746
+ //------------------------------------------------------------------------------
747
+
748
+ enum : signed char {
749
+ OO /* ASCII NUL */ = -8,
750
+ EQ /* BASE64 '=' pad */ = -4,
751
+ SP /* SPACE */ = -2,
752
+ IL /* invalid */ = -1
753
+ };
754
+
755
+ #if MDBX_WORDBITS > 32
756
+ using b58_uint = uint_fast64_t;
757
+ #else
758
+ using b58_uint = uint_fast32_t;
759
+ #endif
760
+
761
+ struct b58_buffer : public temp_buffer<b58_uint> {
762
+ b58_buffer(size_t bytes, size_t estimation_ratio_numerator, size_t estimation_ratio_denominator, size_t extra = 0)
763
+ : temp_buffer(
764
+ (/* пересчитываем по указанной пропорции */
765
+ bytes =
766
+ (bytes * estimation_ratio_numerator + estimation_ratio_denominator - 1) / estimation_ratio_denominator,
767
+ /* учитываем резервный старший байт в каждом слове */
768
+ ((bytes + sizeof(b58_uint) - 2) / (sizeof(b58_uint) - 1) * sizeof(b58_uint) + extra) * sizeof(b58_uint))) {
769
+ }
770
+ };
771
+
772
+ static byte b58_8to11(b58_uint &v) noexcept {
773
+ static const char b58_alphabet[58] = {'1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
774
+ 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
775
+ 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm',
776
+ 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
777
+
778
+ const auto i = size_t(v % 58);
779
+ v /= 58;
780
+ return b58_alphabet[i];
781
+ }
782
+
783
+ static slice b58_encode(b58_buffer &buf, const byte *begin, const byte *end) {
784
+ auto high = buf.end();
785
+ const auto modulo = b58_uint((sizeof(b58_uint) > 4) ? UINT64_C(0x1A636A90B07A00) /* 58^9 */
786
+ : UINT32_C(0xACAD10) /* 58^4 */);
787
+ static_assert(sizeof(modulo) == 4 || sizeof(modulo) == 8, "WTF?");
788
+ while (begin < end) {
789
+ b58_uint carry = *begin++;
790
+ auto ptr = buf.end();
791
+ do {
792
+ assert(ptr > buf.area);
793
+ carry += *--ptr << CHAR_BIT;
794
+ *ptr = carry % modulo;
795
+ carry /= modulo;
796
+ } while (carry || ptr > high);
797
+ high = ptr;
798
+ }
799
+
800
+ byte *output = static_cast<byte *>(static_cast<void *>(buf.area));
801
+ auto ptr = output;
802
+ for (auto porous = high; porous < buf.end();) {
803
+ auto chunk = *porous++;
804
+ static_assert(sizeof(chunk) == 4 || sizeof(chunk) == 8, "WTF?");
805
+ assert(chunk < modulo);
806
+ if (sizeof(chunk) > 4) {
807
+ ptr[8] = b58_8to11(chunk);
808
+ ptr[7] = b58_8to11(chunk);
809
+ ptr[6] = b58_8to11(chunk);
810
+ ptr[5] = b58_8to11(chunk);
811
+ ptr[4] = b58_8to11(chunk);
812
+ ptr[3] = b58_8to11(chunk);
813
+ ptr[2] = b58_8to11(chunk);
814
+ ptr[1] = b58_8to11(chunk);
815
+ ptr[0] = b58_8to11(chunk);
816
+ ptr += 9;
817
+ } else {
818
+ ptr[3] = b58_8to11(chunk);
819
+ ptr[2] = b58_8to11(chunk);
820
+ ptr[1] = b58_8to11(chunk);
821
+ ptr[0] = b58_8to11(chunk);
822
+ ptr += 4;
823
+ }
824
+ assert(static_cast<void *>(ptr) < static_cast<void *>(porous));
825
+ }
826
+
827
+ while (output < ptr && *output == '1')
828
+ ++output;
829
+ return slice(output, ptr);
830
+ }
831
+
832
+ char *to_base58::write_bytes(char *__restrict const dest, size_t dest_size) const {
833
+ if (MDBX_UNLIKELY(envisage_result_length() > dest_size))
834
+ MDBX_CXX20_UNLIKELY throw_too_small_target_buffer();
835
+
836
+ auto begin = source.byte_ptr();
837
+ auto end = source.end_byte_ptr();
838
+ line_wrapper wrapper(dest);
839
+ while (MDBX_LIKELY(begin < end) && *begin == 0) {
840
+ wrapper.put('1', wrap_width);
841
+ assert(wrapper.ptr <= dest + dest_size);
842
+ ++begin;
843
+ }
844
+
845
+ b58_buffer buf(end - begin, 11, 8);
846
+ wrapper.put(b58_encode(buf, begin, end), wrap_width);
847
+ return wrapper.ptr;
848
+ }
849
+
850
+ ::std::ostream &to_base58::output(::std::ostream &out) const {
851
+ if (MDBX_LIKELY(!is_empty()))
852
+ MDBX_CXX20_LIKELY {
853
+ ::std::ostream::sentry sentry(out);
854
+ auto begin = source.byte_ptr();
855
+ auto end = source.end_byte_ptr();
856
+ unsigned width = 0;
857
+ while (MDBX_LIKELY(begin < end) && *begin == 0) {
858
+ out.put('1');
859
+ if (wrap_width && ++width >= wrap_width) {
860
+ out << MDBX_CXX_ENDL;
861
+ width = 0;
862
+ }
863
+ ++begin;
864
+ }
865
+
866
+ b58_buffer buf(end - begin, 11, 8);
867
+ const auto chunk = b58_encode(buf, begin, end);
868
+ if (!wrap_width || wrap_width > width + chunk.length())
869
+ out.write(chunk.char_ptr(), chunk.length());
870
+ else {
871
+ for (size_t i = 0; i < chunk.length(); ++i) {
872
+ out.put(chunk.char_ptr()[i]);
873
+ if (wrap_width && ++width >= wrap_width) {
874
+ out << MDBX_CXX_ENDL;
875
+ width = 0;
876
+ }
877
+ }
878
+ }
879
+ }
880
+ return out;
881
+ }
882
+
883
+ const signed char b58_map[256] = {
884
+ // 1 2 3 4 5 6 7 8 9 a b c d e f
885
+ OO, IL, IL, IL, IL, IL, IL, IL, IL, SP, SP, SP, SP, SP, IL, IL, // 00
886
+ IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, // 10
887
+ SP, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, // 20
888
+ IL, 0, 1, 2, 3, 4, 5, 6, 7, 8, IL, IL, IL, IL, IL, IL, // 30
889
+ IL, 9, 10, 11, 12, 13, 14, 15, 16, IL, 17, 18, 19, 20, 21, IL, // 40
890
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, IL, IL, IL, IL, IL, // 50
891
+ IL, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, IL, 44, 45, 46, // 60
892
+ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, IL, IL, IL, IL, IL, // 70
893
+ IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, // 80
894
+ IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, // 90
895
+ IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, // a0
896
+ IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, // b0
897
+ IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, // c0
898
+ IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, // d0
899
+ IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, // e0
900
+ IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL // f0
901
+ };
902
+
903
+ static slice b58_decode(b58_buffer &buf, const byte *begin, const byte *end, bool ignore_spaces) {
904
+ auto high = buf.end();
905
+ while (begin < end) {
906
+ const auto c = b58_map[*begin++];
907
+ if (MDBX_LIKELY(c >= 0)) {
908
+ b58_uint carry = c;
909
+ auto ptr = buf.end();
910
+ do {
911
+ assert(ptr > buf.area);
912
+ carry += *--ptr * 58;
913
+ *ptr = carry & (~b58_uint(0) >> CHAR_BIT);
914
+ carry >>= CHAR_BIT * (sizeof(carry) - 1);
915
+ } while (carry || ptr > high);
916
+ high = ptr;
917
+ } else if (MDBX_UNLIKELY(!ignore_spaces || !isspace(begin[-1])))
918
+ MDBX_CXX20_UNLIKELY
919
+ throw std::domain_error("mdbx::from_base58:: invalid base58 string");
920
+ }
921
+
922
+ byte *output = static_cast<byte *>(static_cast<void *>(buf.area));
923
+ auto ptr = output;
924
+ for (auto porous = high; porous < buf.end(); ++porous) {
925
+ auto chunk = *porous;
926
+ static_assert(sizeof(chunk) == 4 || sizeof(chunk) == 8, "WTF?");
927
+ assert(chunk <= (~b58_uint(0) >> CHAR_BIT));
928
+ if (sizeof(chunk) > 4) {
929
+ *ptr++ = byte(uint_fast64_t(chunk) >> CHAR_BIT * 6);
930
+ *ptr++ = byte(uint_fast64_t(chunk) >> CHAR_BIT * 5);
931
+ *ptr++ = byte(uint_fast64_t(chunk) >> CHAR_BIT * 4);
932
+ *ptr++ = byte(chunk >> CHAR_BIT * 3);
933
+ }
934
+ *ptr++ = byte(chunk >> CHAR_BIT * 2);
935
+ *ptr++ = byte(chunk >> CHAR_BIT * 1);
936
+ *ptr++ = byte(chunk >> CHAR_BIT * 0);
937
+ }
938
+
939
+ while (output < ptr && *output == 0)
940
+ ++output;
941
+ return slice(output, ptr);
942
+ }
943
+
944
+ char *from_base58::write_bytes(char *__restrict const dest, size_t dest_size) const {
945
+ if (MDBX_UNLIKELY(envisage_result_length() > dest_size))
946
+ MDBX_CXX20_UNLIKELY throw_too_small_target_buffer();
947
+
948
+ auto ptr = dest;
949
+ auto begin = source.byte_ptr();
950
+ auto const end = source.end_byte_ptr();
951
+ while (begin < end && *begin <= '1') {
952
+ if (MDBX_LIKELY(*begin == '1'))
953
+ MDBX_CXX20_LIKELY *ptr++ = 0;
954
+ else if (MDBX_UNLIKELY(!ignore_spaces || !isspace(*begin)))
955
+ MDBX_CXX20_UNLIKELY
956
+ throw std::domain_error("mdbx::from_base58:: invalid base58 string");
957
+ ++begin;
958
+ }
959
+
960
+ b58_buffer buf(end - begin, 47, 64);
961
+ auto slice = b58_decode(buf, begin, end, ignore_spaces);
962
+ memcpy(ptr, slice.data(), slice.length());
963
+ return ptr + slice.length();
964
+ }
965
+
966
+ bool from_base58::is_erroneous() const noexcept {
967
+ auto begin = source.byte_ptr();
968
+ auto const end = source.end_byte_ptr();
969
+ while (begin < end) {
970
+ if (MDBX_UNLIKELY(b58_map[*begin] < 0 && !(ignore_spaces && isspace(*begin))))
971
+ return true;
972
+ ++begin;
973
+ }
974
+ return false;
975
+ }
976
+
977
+ //------------------------------------------------------------------------------
978
+
979
+ static inline void b64_3to4(const byte x, const byte y, const byte z, char *__restrict dest) noexcept {
980
+ static const byte alphabet[64] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
981
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
982
+ 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
983
+ 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
984
+ dest[0] = alphabet[(x & 0xfc) >> 2];
985
+ dest[1] = alphabet[((x & 0x03) << 4) + ((y & 0xf0) >> 4)];
986
+ dest[2] = alphabet[((y & 0x0f) << 2) + ((z & 0xc0) >> 6)];
987
+ dest[3] = alphabet[z & 0x3f];
988
+ }
989
+
990
+ char *to_base64::write_bytes(char *__restrict const dest, size_t dest_size) const {
991
+ if (MDBX_UNLIKELY(envisage_result_length() > dest_size))
992
+ MDBX_CXX20_UNLIKELY throw_too_small_target_buffer();
993
+
994
+ auto ptr = dest;
995
+ auto src = source.byte_ptr();
996
+ size_t left = source.length();
997
+ auto line = ptr;
998
+ while (true) {
999
+ switch (left) {
1000
+ default:
1001
+ MDBX_CXX20_LIKELY left -= 3;
1002
+ b64_3to4(src[0], src[1], src[2], ptr);
1003
+ ptr += 4;
1004
+ src += 3;
1005
+ if (wrap_width && size_t(ptr - line) >= wrap_width && left) {
1006
+ *ptr = '\n';
1007
+ line = ++ptr;
1008
+ }
1009
+ assert(ptr <= dest + dest_size);
1010
+ continue;
1011
+ case 2:
1012
+ b64_3to4(src[0], src[1], 0, ptr);
1013
+ ptr[3] = '=';
1014
+ assert(ptr + 4 <= dest + dest_size);
1015
+ return ptr + 4;
1016
+ case 1:
1017
+ b64_3to4(src[0], 0, 0, ptr);
1018
+ ptr[2] = ptr[3] = '=';
1019
+ assert(ptr + 4 <= dest + dest_size);
1020
+ return ptr + 4;
1021
+ case 0:
1022
+ return ptr;
1023
+ }
1024
+ }
1025
+ }
1026
+
1027
+ ::std::ostream &to_base64::output(::std::ostream &out) const {
1028
+ if (MDBX_LIKELY(!is_empty()))
1029
+ MDBX_CXX20_LIKELY {
1030
+ ::std::ostream::sentry sentry(out);
1031
+ auto src = source.byte_ptr();
1032
+ size_t left = source.length();
1033
+ unsigned width = 0;
1034
+ std::array<char, 4> buf;
1035
+
1036
+ while (true) {
1037
+ switch (left) {
1038
+ default:
1039
+ MDBX_CXX20_LIKELY left -= 3;
1040
+ b64_3to4(src[0], src[1], src[2], &buf.front());
1041
+ src += 3;
1042
+ out.write(&buf.front(), 4);
1043
+ if (wrap_width && (width += 4) >= wrap_width && left) {
1044
+ out << MDBX_CXX_ENDL;
1045
+ width = 0;
1046
+ }
1047
+ continue;
1048
+ case 2:
1049
+ b64_3to4(src[0], src[1], 0, &buf.front());
1050
+ buf[3] = '=';
1051
+ return out.write(&buf.front(), 4);
1052
+ case 1:
1053
+ b64_3to4(src[0], 0, 0, &buf.front());
1054
+ buf[2] = buf[3] = '=';
1055
+ return out.write(&buf.front(), 4);
1056
+ case 0:
1057
+ return out;
1058
+ }
1059
+ }
1060
+ }
1061
+ return out;
1062
+ }
1063
+
1064
+ static const signed char b64_map[256] = {
1065
+ // 1 2 3 4 5 6 7 8 9 a b c d e f
1066
+ OO, IL, IL, IL, IL, IL, IL, IL, IL, SP, SP, SP, SP, SP, IL, IL, // 00
1067
+ IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, // 10
1068
+ SP, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, 62, IL, IL, IL, 63, // 20
1069
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, IL, IL, IL, EQ, IL, IL, // 30
1070
+ IL, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 40
1071
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, IL, IL, IL, IL, IL, // 50
1072
+ IL, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 60
1073
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, IL, IL, IL, IL, IL, // 70
1074
+ IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, // 80
1075
+ IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, // 90
1076
+ IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, // a0
1077
+ IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, // b0
1078
+ IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, // c0
1079
+ IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, // d0
1080
+ IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, // e0
1081
+ IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL, IL // f0
1082
+ };
1083
+
1084
+ static inline signed char b64_4to3(signed char a, signed char b, signed char c, signed char d,
1085
+ char *__restrict dest) noexcept {
1086
+ dest[0] = byte((a << 2) + ((b & 0x30) >> 4));
1087
+ dest[1] = byte(((b & 0xf) << 4) + ((c & 0x3c) >> 2));
1088
+ dest[2] = byte(((c & 0x3) << 6) + d);
1089
+ return a | b | c | d;
1090
+ }
1091
+
1092
+ char *from_base64::write_bytes(char *__restrict const dest, size_t dest_size) const {
1093
+ if (MDBX_UNLIKELY(source.length() % 4 && !ignore_spaces))
1094
+ MDBX_CXX20_UNLIKELY throw std::domain_error("mdbx::from_base64:: odd length of base64 string");
1095
+ if (MDBX_UNLIKELY(envisage_result_length() > dest_size))
1096
+ MDBX_CXX20_UNLIKELY throw_too_small_target_buffer();
1097
+
1098
+ auto ptr = dest;
1099
+ auto src = source.byte_ptr();
1100
+ for (auto left = source.length(); left > 0;) {
1101
+ if (MDBX_UNLIKELY(*src <= ' ') && MDBX_LIKELY(ignore_spaces && isspace(*src))) {
1102
+ ++src;
1103
+ --left;
1104
+ continue;
1105
+ }
1106
+
1107
+ if (MDBX_UNLIKELY(left < 3))
1108
+ MDBX_CXX20_UNLIKELY {
1109
+ bailout:
1110
+ throw std::domain_error("mdbx::from_base64:: invalid base64 string");
1111
+ }
1112
+ const signed char a = b64_map[src[0]], b = b64_map[src[1]], c = b64_map[src[2]], d = b64_map[src[3]];
1113
+ if (MDBX_UNLIKELY(b64_4to3(a, b, c, d, ptr) < 0)) {
1114
+ if (left == 4 && (a | b) >= 0 && d == EQ) {
1115
+ if (c >= 0) {
1116
+ assert(ptr + 2 <= dest + dest_size);
1117
+ return ptr + 2;
1118
+ }
1119
+ if (c == d) {
1120
+ assert(ptr + 1 <= dest + dest_size);
1121
+ return ptr + 1;
1122
+ }
1123
+ }
1124
+ MDBX_CXX20_UNLIKELY goto bailout;
1125
+ }
1126
+ src += 4;
1127
+ left -= 4;
1128
+ ptr += 3;
1129
+ assert(ptr <= dest + dest_size);
1130
+ }
1131
+ return ptr;
1132
+ }
1133
+
1134
+ bool from_base64::is_erroneous() const noexcept {
1135
+ if (MDBX_UNLIKELY(source.length() % 4 && !ignore_spaces))
1136
+ MDBX_CXX20_UNLIKELY return true;
1137
+
1138
+ bool got = false;
1139
+ auto src = source.byte_ptr();
1140
+ for (auto left = source.length(); left > 0;) {
1141
+ if (MDBX_UNLIKELY(*src <= ' ') && MDBX_LIKELY(ignore_spaces && isspace(*src))) {
1142
+ ++src;
1143
+ --left;
1144
+ continue;
1145
+ }
1146
+
1147
+ if (MDBX_UNLIKELY(left < 3))
1148
+ MDBX_CXX20_UNLIKELY return false;
1149
+ const signed char a = b64_map[src[0]], b = b64_map[src[1]], c = b64_map[src[2]], d = b64_map[src[3]];
1150
+ if (MDBX_UNLIKELY((a | b | c | d) < 0))
1151
+ MDBX_CXX20_UNLIKELY {
1152
+ if (left == 4 && (a | b) >= 0 && d == EQ && (c >= 0 || c == d))
1153
+ return false;
1154
+ return true;
1155
+ }
1156
+ got = true;
1157
+ src += 4;
1158
+ left -= 4;
1159
+ }
1160
+ return !got;
1161
+ }
1162
+
1163
+ //------------------------------------------------------------------------------
1164
+
1165
+ #if defined(_MSC_VER)
1166
+ #pragma warning(push)
1167
+ /* warning C4251: 'mdbx::buffer<...>::silo_':
1168
+ * struct 'mdbx::buffer<..>::silo' needs to have dll-interface to be used by clients of class 'mdbx::buffer<...>'
1169
+ *
1170
+ * Microsoft не хочет признавать ошибки и пересматривать приятные решения, поэтому MSVC продолжает кошмарить
1171
+ * и стращать разработчиков предупреждениями, тем самым перекладывая ответственность на их плечи.
1172
+ *
1173
+ * В данном случае предупреждение выдаётся из-за инстанцирования std::string::allocator_type::pointer и
1174
+ * std::pmr::string::allocator_type::pointer внутри mdbx::buffer<..>::silo. А так как эти типы являются частью
1175
+ * стандартной библиотеки C++ они всегда будут доступны и без необходимости их инстанцирования и экспорта из libmdbx.
1176
+ *
1177
+ * Поэтому нет других вариантов как заглушить это предупреждение и еще раз плюнуть в сторону microsoft. */
1178
+ #pragma warning(disable : 4251)
1179
+ #endif /* MSVC */
1180
+
1181
+ MDBX_INSTALL_API_TEMPLATE(LIBMDBX_API_TYPE, buffer<legacy_allocator>);
1182
+
1183
+ #if defined(__cpp_lib_memory_resource) && __cpp_lib_memory_resource >= 201603L && _GLIBCXX_USE_CXX11_ABI
1184
+ MDBX_INSTALL_API_TEMPLATE(LIBMDBX_API_TYPE, buffer<polymorphic_allocator>);
1185
+ #endif /* __cpp_lib_memory_resource >= 201603L */
1186
+
1187
+ #if defined(_MSC_VER)
1188
+ #pragma warning(pop)
1189
+ #endif /* MSVC */
1190
+
1191
+ //------------------------------------------------------------------------------
1192
+
1193
+ static inline MDBX_env_flags_t mode2flags(env::mode mode) {
1194
+ switch (mode) {
1195
+ default:
1196
+ MDBX_CXX20_UNLIKELY throw std::invalid_argument("db::mode is invalid");
1197
+ case env::mode::readonly:
1198
+ return MDBX_RDONLY;
1199
+ case env::mode::write_file_io:
1200
+ return MDBX_ENV_DEFAULTS;
1201
+ case env::mode::write_mapped_io:
1202
+ return MDBX_WRITEMAP;
1203
+ }
1204
+ }
1205
+
1206
+ __cold MDBX_env_flags_t env::operate_parameters::make_flags(bool accede, bool use_subdirectory) const {
1207
+ MDBX_env_flags_t flags = mode2flags(mode);
1208
+ if (accede)
1209
+ flags |= MDBX_ACCEDE;
1210
+ if (!use_subdirectory)
1211
+ flags |= MDBX_NOSUBDIR;
1212
+ if (options.exclusive)
1213
+ flags |= MDBX_EXCLUSIVE;
1214
+ if (options.no_sticky_threads)
1215
+ flags |= MDBX_NOSTICKYTHREADS;
1216
+ if (options.disable_readahead)
1217
+ flags |= MDBX_NORDAHEAD;
1218
+ if (options.disable_clear_memory)
1219
+ flags |= MDBX_NOMEMINIT;
1220
+ if (options.enable_validation)
1221
+ flags |= MDBX_VALIDATION;
1222
+
1223
+ if (mode != readonly) {
1224
+ if (options.nested_write_transactions)
1225
+ flags &= ~MDBX_WRITEMAP;
1226
+ if (reclaiming.coalesce)
1227
+ flags |= MDBX_COALESCE;
1228
+ if (reclaiming.lifo)
1229
+ flags |= MDBX_LIFORECLAIM;
1230
+ switch (durability) {
1231
+ default:
1232
+ MDBX_CXX20_UNLIKELY throw std::invalid_argument("db::durability is invalid");
1233
+ case env::durability::robust_synchronous:
1234
+ break;
1235
+ case env::durability::half_synchronous_weak_last:
1236
+ flags |= MDBX_NOMETASYNC;
1237
+ break;
1238
+ case env::durability::lazy_weak_tail:
1239
+ static_assert(MDBX_MAPASYNC == MDBX_SAFE_NOSYNC, "WTF? Obsolete C API?");
1240
+ flags |= MDBX_SAFE_NOSYNC;
1241
+ break;
1242
+ case env::durability::whole_fragile:
1243
+ flags |= MDBX_UTTERLY_NOSYNC;
1244
+ break;
1245
+ }
1246
+ }
1247
+ return flags;
1248
+ }
1249
+
1250
+ env::mode env::operate_parameters::mode_from_flags(MDBX_env_flags_t flags) noexcept {
1251
+ if (flags & MDBX_RDONLY)
1252
+ return env::mode::readonly;
1253
+ return (flags & MDBX_WRITEMAP) ? env::mode::write_mapped_io : env::mode::write_file_io;
1254
+ }
1255
+
1256
+ env::durability env::operate_parameters::durability_from_flags(MDBX_env_flags_t flags) noexcept {
1257
+ if ((flags & MDBX_UTTERLY_NOSYNC) == MDBX_UTTERLY_NOSYNC)
1258
+ return env::durability::whole_fragile;
1259
+ if (flags & MDBX_SAFE_NOSYNC)
1260
+ return env::durability::lazy_weak_tail;
1261
+ if (flags & MDBX_NOMETASYNC)
1262
+ return env::durability::half_synchronous_weak_last;
1263
+ return env::durability::robust_synchronous;
1264
+ }
1265
+
1266
+ env::reclaiming_options::reclaiming_options(MDBX_env_flags_t flags) noexcept
1267
+ : lifo((flags & MDBX_LIFORECLAIM) ? true : false), coalesce((flags & MDBX_COALESCE) ? true : false) {}
1268
+
1269
+ env::operate_options::operate_options(MDBX_env_flags_t flags) noexcept
1270
+ : no_sticky_threads(((flags & (MDBX_NOSTICKYTHREADS | MDBX_EXCLUSIVE)) == MDBX_NOSTICKYTHREADS) ? true : false),
1271
+ nested_write_transactions((flags & (MDBX_WRITEMAP | MDBX_RDONLY)) ? false : true),
1272
+ exclusive((flags & MDBX_EXCLUSIVE) ? true : false), disable_readahead((flags & MDBX_NORDAHEAD) ? true : false),
1273
+ disable_clear_memory((flags & MDBX_NOMEMINIT) ? true : false) {}
1274
+
1275
+ bool env::is_pristine() const { return get_stat().ms_mod_txnid == 0 && get_info().mi_recent_txnid == INITIAL_TXNID; }
1276
+
1277
+ bool env::is_empty() const { return get_stat().ms_leaf_pages == 0; }
1278
+
1279
+ __cold env &env::copy(filehandle fd, bool compactify, bool force_dynamic_size) {
1280
+ error::success_or_throw(::mdbx_env_copy2fd(handle_, fd,
1281
+ (compactify ? MDBX_CP_COMPACT : MDBX_CP_DEFAULTS) |
1282
+ (force_dynamic_size ? MDBX_CP_FORCE_DYNAMIC_SIZE : MDBX_CP_DEFAULTS)));
1283
+ return *this;
1284
+ }
1285
+
1286
+ __cold env &env::copy(const char *destination, bool compactify, bool force_dynamic_size) {
1287
+ error::success_or_throw(::mdbx_env_copy(handle_, destination,
1288
+ (compactify ? MDBX_CP_COMPACT : MDBX_CP_DEFAULTS) |
1289
+ (force_dynamic_size ? MDBX_CP_FORCE_DYNAMIC_SIZE : MDBX_CP_DEFAULTS)));
1290
+ return *this;
1291
+ }
1292
+
1293
+ __cold env &env::copy(const ::std::string &destination, bool compactify, bool force_dynamic_size) {
1294
+ return copy(destination.c_str(), compactify, force_dynamic_size);
1295
+ }
1296
+
1297
+ #if defined(_WIN32) || defined(_WIN64)
1298
+ __cold env &env::copy(const wchar_t *destination, bool compactify, bool force_dynamic_size) {
1299
+ error::success_or_throw(::mdbx_env_copyW(handle_, destination,
1300
+ (compactify ? MDBX_CP_COMPACT : MDBX_CP_DEFAULTS) |
1301
+ (force_dynamic_size ? MDBX_CP_FORCE_DYNAMIC_SIZE : MDBX_CP_DEFAULTS)));
1302
+ return *this;
1303
+ }
1304
+
1305
+ env &env::copy(const ::std::wstring &destination, bool compactify, bool force_dynamic_size) {
1306
+ return copy(destination.c_str(), compactify, force_dynamic_size);
1307
+ }
1308
+ #endif /* Windows */
1309
+
1310
+ #ifdef MDBX_STD_FILESYSTEM_PATH
1311
+ __cold env &env::copy(const MDBX_STD_FILESYSTEM_PATH &destination, bool compactify, bool force_dynamic_size) {
1312
+ return copy(destination.native(), compactify, force_dynamic_size);
1313
+ }
1314
+ #endif /* MDBX_STD_FILESYSTEM_PATH */
1315
+
1316
+ __cold path env::get_path() const {
1317
+ #if defined(_WIN32) || defined(_WIN64)
1318
+ const wchar_t *c_wstr;
1319
+ error::success_or_throw(::mdbx_env_get_pathW(handle_, &c_wstr));
1320
+ static_assert(sizeof(path::value_type) == sizeof(wchar_t), "Oops");
1321
+ return path(c_wstr);
1322
+ #else
1323
+ const char *c_str;
1324
+ error::success_or_throw(::mdbx_env_get_path(handle_, &c_str));
1325
+ static_assert(sizeof(path::value_type) == sizeof(char), "Oops");
1326
+ return path(c_str);
1327
+ #endif
1328
+ }
1329
+
1330
+ __cold bool env::remove(const char *pathname, const remove_mode mode) {
1331
+ return !error::boolean_or_throw(::mdbx_env_delete(pathname, MDBX_env_delete_mode_t(mode)));
1332
+ }
1333
+
1334
+ __cold bool env::remove(const ::std::string &pathname, const remove_mode mode) {
1335
+ return remove(pathname.c_str(), mode);
1336
+ }
1337
+
1338
+ #if defined(_WIN32) || defined(_WIN64)
1339
+ __cold bool env::remove(const wchar_t *pathname, const remove_mode mode) {
1340
+ return !error::boolean_or_throw(::mdbx_env_deleteW(pathname, MDBX_env_delete_mode_t(mode)));
1341
+ }
1342
+
1343
+ __cold bool env::remove(const ::std::wstring &pathname, const remove_mode mode) {
1344
+ return remove(pathname.c_str(), mode);
1345
+ }
1346
+ #endif /* Windows */
1347
+
1348
+ #ifdef MDBX_STD_FILESYSTEM_PATH
1349
+ __cold bool env::remove(const MDBX_STD_FILESYSTEM_PATH &pathname, const remove_mode mode) {
1350
+ return remove(pathname.native(), mode);
1351
+ }
1352
+ #endif /* MDBX_STD_FILESYSTEM_PATH */
1353
+
1354
+ //------------------------------------------------------------------------------
1355
+
1356
+ static inline MDBX_env *create_env() {
1357
+ MDBX_env *ptr;
1358
+ error::success_or_throw(::mdbx_env_create(&ptr));
1359
+ assert(ptr != nullptr);
1360
+ return ptr;
1361
+ }
1362
+
1363
+ __cold env_managed::~env_managed() noexcept {
1364
+ if (MDBX_UNLIKELY(handle_))
1365
+ MDBX_CXX20_UNLIKELY error::success_or_panic(::mdbx_env_close(handle_), "mdbx::~env()", "mdbx_env_close");
1366
+ }
1367
+
1368
+ __cold void env_managed::close(bool dont_sync) {
1369
+ const error rc = static_cast<MDBX_error_t>(::mdbx_env_close_ex(handle_, dont_sync));
1370
+ switch (rc.code()) {
1371
+ case MDBX_EBADSIGN:
1372
+ MDBX_CXX20_UNLIKELY handle_ = nullptr;
1373
+ __fallthrough /* fall through */;
1374
+ default:
1375
+ MDBX_CXX20_UNLIKELY rc.throw_exception();
1376
+ case MDBX_SUCCESS:
1377
+ MDBX_CXX20_LIKELY handle_ = nullptr;
1378
+ }
1379
+ }
1380
+
1381
+ __cold void env_managed::setup(unsigned max_maps, unsigned max_readers) {
1382
+ if (max_readers > 0)
1383
+ error::success_or_throw(::mdbx_env_set_maxreaders(handle_, max_readers));
1384
+ if (max_maps > 0)
1385
+ error::success_or_throw(::mdbx_env_set_maxdbs(handle_, max_maps));
1386
+ }
1387
+
1388
+ __cold env_managed::env_managed(const char *pathname, const operate_parameters &op, bool accede)
1389
+ : env_managed(create_env()) {
1390
+ setup(op.max_maps, op.max_readers);
1391
+ error::success_or_throw(::mdbx_env_open(handle_, pathname, op.make_flags(accede), 0));
1392
+
1393
+ if (op.options.nested_write_transactions && !get_options().nested_write_transactions)
1394
+ MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_INCOMPATIBLE);
1395
+ }
1396
+
1397
+ __cold env_managed::env_managed(const char *pathname, const env_managed::create_parameters &cp,
1398
+ const env::operate_parameters &op, bool accede)
1399
+ : env_managed(create_env()) {
1400
+ setup(op.max_maps, op.max_readers);
1401
+ set_geometry(cp.geometry);
1402
+ error::success_or_throw(
1403
+ ::mdbx_env_open(handle_, pathname, op.make_flags(accede, cp.use_subdirectory), cp.file_mode_bits));
1404
+
1405
+ if (op.options.nested_write_transactions && !get_options().nested_write_transactions)
1406
+ MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_INCOMPATIBLE);
1407
+ }
1408
+
1409
+ __cold env_managed::env_managed(const ::std::string &pathname, const operate_parameters &op, bool accede)
1410
+ : env_managed(pathname.c_str(), op, accede) {}
1411
+
1412
+ __cold env_managed::env_managed(const ::std::string &pathname, const env_managed::create_parameters &cp,
1413
+ const env::operate_parameters &op, bool accede)
1414
+ : env_managed(pathname.c_str(), cp, op, accede) {}
1415
+
1416
+ #if defined(_WIN32) || defined(_WIN64)
1417
+ __cold env_managed::env_managed(const wchar_t *pathname, const operate_parameters &op, bool accede)
1418
+ : env_managed(create_env()) {
1419
+ setup(op.max_maps, op.max_readers);
1420
+ error::success_or_throw(::mdbx_env_openW(handle_, pathname, op.make_flags(accede), 0));
1421
+
1422
+ if (op.options.nested_write_transactions && !get_options().nested_write_transactions)
1423
+ MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_INCOMPATIBLE);
1424
+ }
1425
+
1426
+ __cold env_managed::env_managed(const wchar_t *pathname, const env_managed::create_parameters &cp,
1427
+ const env::operate_parameters &op, bool accede)
1428
+ : env_managed(create_env()) {
1429
+ setup(op.max_maps, op.max_readers);
1430
+ set_geometry(cp.geometry);
1431
+ error::success_or_throw(
1432
+ ::mdbx_env_openW(handle_, pathname, op.make_flags(accede, cp.use_subdirectory), cp.file_mode_bits));
1433
+
1434
+ if (op.options.nested_write_transactions && !get_options().nested_write_transactions)
1435
+ MDBX_CXX20_UNLIKELY error::throw_exception(MDBX_INCOMPATIBLE);
1436
+ }
1437
+
1438
+ __cold env_managed::env_managed(const ::std::wstring &pathname, const operate_parameters &op, bool accede)
1439
+ : env_managed(pathname.c_str(), op, accede) {}
1440
+
1441
+ __cold env_managed::env_managed(const ::std::wstring &pathname, const env_managed::create_parameters &cp,
1442
+ const env::operate_parameters &op, bool accede)
1443
+ : env_managed(pathname.c_str(), cp, op, accede) {}
1444
+ #endif /* Windows */
1445
+
1446
+ #ifdef MDBX_STD_FILESYSTEM_PATH
1447
+ __cold env_managed::env_managed(const MDBX_STD_FILESYSTEM_PATH &pathname, const operate_parameters &op, bool accede)
1448
+ : env_managed(pathname.native(), op, accede) {}
1449
+
1450
+ __cold env_managed::env_managed(const MDBX_STD_FILESYSTEM_PATH &pathname, const env_managed::create_parameters &cp,
1451
+ const env::operate_parameters &op, bool accede)
1452
+ : env_managed(pathname.native(), cp, op, accede) {}
1453
+ #endif /* MDBX_STD_FILESYSTEM_PATH */
1454
+
1455
+ //------------------------------------------------------------------------------
1456
+
1457
+ txn_managed txn::start_nested() {
1458
+ MDBX_txn *nested;
1459
+ error::throw_on_nullptr(handle_, MDBX_BAD_TXN);
1460
+ error::success_or_throw(::mdbx_txn_begin(mdbx_txn_env(handle_), handle_, MDBX_TXN_READWRITE, &nested));
1461
+ assert(nested != nullptr);
1462
+ return txn_managed(nested);
1463
+ }
1464
+
1465
+ txn_managed::~txn_managed() noexcept {
1466
+ if (MDBX_UNLIKELY(handle_))
1467
+ MDBX_CXX20_UNLIKELY error::success_or_panic(::mdbx_txn_abort(handle_), "mdbx::~txn", "mdbx_txn_abort");
1468
+ }
1469
+
1470
+ void txn_managed::abort() {
1471
+ const error err = static_cast<MDBX_error_t>(::mdbx_txn_abort(handle_));
1472
+ if (MDBX_LIKELY(err.code() != MDBX_THREAD_MISMATCH))
1473
+ MDBX_CXX20_LIKELY handle_ = nullptr;
1474
+ if (MDBX_UNLIKELY(err.code() != MDBX_SUCCESS))
1475
+ MDBX_CXX20_UNLIKELY err.throw_exception();
1476
+ }
1477
+
1478
+ void txn_managed::commit() {
1479
+ const error err = static_cast<MDBX_error_t>(::mdbx_txn_commit(handle_));
1480
+ if (MDBX_LIKELY(err.code() != MDBX_THREAD_MISMATCH))
1481
+ MDBX_CXX20_LIKELY handle_ = nullptr;
1482
+ if (MDBX_UNLIKELY(err.code() != MDBX_SUCCESS))
1483
+ MDBX_CXX20_UNLIKELY err.throw_exception();
1484
+ }
1485
+
1486
+ void txn_managed::commit(commit_latency *latency) {
1487
+ const error err = static_cast<MDBX_error_t>(::mdbx_txn_commit_ex(handle_, latency));
1488
+ if (MDBX_LIKELY(err.code() != MDBX_THREAD_MISMATCH))
1489
+ MDBX_CXX20_LIKELY handle_ = nullptr;
1490
+ if (MDBX_UNLIKELY(err.code() != MDBX_SUCCESS))
1491
+ MDBX_CXX20_UNLIKELY err.throw_exception();
1492
+ }
1493
+
1494
+ void txn_managed::commit_embark_read() {
1495
+ auto env = this->env();
1496
+ commit();
1497
+ error::success_or_throw(::mdbx_txn_begin(env, nullptr, MDBX_TXN_RDONLY, &handle_));
1498
+ }
1499
+
1500
+ //------------------------------------------------------------------------------
1501
+
1502
+ __cold bool txn::drop_map(const char *name, bool throw_if_absent) {
1503
+ map_handle map;
1504
+ const int err = ::mdbx_dbi_open(handle_, name, MDBX_DB_ACCEDE, &map.dbi);
1505
+ switch (err) {
1506
+ case MDBX_SUCCESS:
1507
+ drop_map(map);
1508
+ return true;
1509
+ case MDBX_NOTFOUND:
1510
+ case MDBX_BAD_DBI:
1511
+ if (!throw_if_absent)
1512
+ return false;
1513
+ MDBX_CXX17_FALLTHROUGH /* fallthrough */;
1514
+ default:
1515
+ MDBX_CXX20_UNLIKELY error::throw_exception(err);
1516
+ }
1517
+ }
1518
+
1519
+ __cold bool txn::clear_map(const char *name, bool throw_if_absent) {
1520
+ map_handle map;
1521
+ const int err = ::mdbx_dbi_open(handle_, name, MDBX_DB_ACCEDE, &map.dbi);
1522
+ switch (err) {
1523
+ case MDBX_SUCCESS:
1524
+ clear_map(map);
1525
+ return true;
1526
+ case MDBX_NOTFOUND:
1527
+ case MDBX_BAD_DBI:
1528
+ if (!throw_if_absent)
1529
+ return false;
1530
+ MDBX_CXX17_FALLTHROUGH /* fallthrough */;
1531
+ default:
1532
+ MDBX_CXX20_UNLIKELY error::throw_exception(err);
1533
+ }
1534
+ }
1535
+
1536
+ __cold bool txn::rename_map(const char *old_name, const char *new_name, bool throw_if_absent) {
1537
+ map_handle map;
1538
+ const int err = ::mdbx_dbi_open(handle_, old_name, MDBX_DB_ACCEDE, &map.dbi);
1539
+ switch (err) {
1540
+ case MDBX_SUCCESS:
1541
+ rename_map(map, new_name);
1542
+ return true;
1543
+ case MDBX_NOTFOUND:
1544
+ case MDBX_BAD_DBI:
1545
+ if (!throw_if_absent)
1546
+ return false;
1547
+ MDBX_CXX17_FALLTHROUGH /* fallthrough */;
1548
+ default:
1549
+ MDBX_CXX20_UNLIKELY error::throw_exception(err);
1550
+ }
1551
+ }
1552
+
1553
+ __cold bool txn::drop_map(const ::mdbx::slice &name, bool throw_if_absent) {
1554
+ map_handle map;
1555
+ const int err = ::mdbx_dbi_open2(handle_, name, MDBX_DB_ACCEDE, &map.dbi);
1556
+ switch (err) {
1557
+ case MDBX_SUCCESS:
1558
+ drop_map(map);
1559
+ return true;
1560
+ case MDBX_NOTFOUND:
1561
+ case MDBX_BAD_DBI:
1562
+ if (!throw_if_absent)
1563
+ return false;
1564
+ MDBX_CXX17_FALLTHROUGH /* fallthrough */;
1565
+ default:
1566
+ MDBX_CXX20_UNLIKELY error::throw_exception(err);
1567
+ }
1568
+ }
1569
+
1570
+ __cold bool txn::clear_map(const ::mdbx::slice &name, bool throw_if_absent) {
1571
+ map_handle map;
1572
+ const int err = ::mdbx_dbi_open2(handle_, name, MDBX_DB_ACCEDE, &map.dbi);
1573
+ switch (err) {
1574
+ case MDBX_SUCCESS:
1575
+ clear_map(map);
1576
+ return true;
1577
+ case MDBX_NOTFOUND:
1578
+ case MDBX_BAD_DBI:
1579
+ if (!throw_if_absent)
1580
+ return false;
1581
+ MDBX_CXX17_FALLTHROUGH /* fallthrough */;
1582
+ default:
1583
+ MDBX_CXX20_UNLIKELY error::throw_exception(err);
1584
+ }
1585
+ }
1586
+
1587
+ __cold bool txn::rename_map(const ::mdbx::slice &old_name, const ::mdbx::slice &new_name, bool throw_if_absent) {
1588
+ map_handle map;
1589
+ const int err = ::mdbx_dbi_open2(handle_, old_name, MDBX_DB_ACCEDE, &map.dbi);
1590
+ switch (err) {
1591
+ case MDBX_SUCCESS:
1592
+ rename_map(map, new_name);
1593
+ return true;
1594
+ case MDBX_NOTFOUND:
1595
+ case MDBX_BAD_DBI:
1596
+ if (!throw_if_absent)
1597
+ return false;
1598
+ MDBX_CXX17_FALLTHROUGH /* fallthrough */;
1599
+ default:
1600
+ MDBX_CXX20_UNLIKELY error::throw_exception(err);
1601
+ }
1602
+ }
1603
+
1604
+ __cold bool txn::rename_map(const ::std::string &old_name, const ::std::string &new_name, bool throw_if_absent) {
1605
+ return rename_map(::mdbx::slice(old_name), ::mdbx::slice(new_name), throw_if_absent);
1606
+ }
1607
+
1608
+ //------------------------------------------------------------------------------
1609
+
1610
+ __cold ::std::ostream &operator<<(::std::ostream &out, const slice &it) {
1611
+ out << "{";
1612
+ if (!it.is_valid())
1613
+ out << "INVALID." << it.length();
1614
+ else if (it.is_null())
1615
+ out << "NULL";
1616
+ else if (it.empty())
1617
+ out << "EMPTY->" << it.data();
1618
+ else {
1619
+ const slice root(it.head(std::min(it.length(), size_t(64))));
1620
+ out << it.length() << ".";
1621
+ if (root.is_printable())
1622
+ (out << "\"").write(root.char_ptr(), root.length()) << "\"";
1623
+ else
1624
+ out << root.encode_base58();
1625
+ if (root.length() < it.length())
1626
+ out << "...";
1627
+ }
1628
+ return out << "}";
1629
+ }
1630
+
1631
+ __cold ::std::ostream &operator<<(::std::ostream &out, const pair &it) {
1632
+ return out << "{" << it.key << " => " << it.value << "}";
1633
+ }
1634
+
1635
+ __cold ::std::ostream &operator<<(::std::ostream &out, const pair_result &it) {
1636
+ return out << "{" << (it.done ? "done: " : "non-done: ") << it.key << " => " << it.value << "}";
1637
+ }
1638
+
1639
+ __cold ::std::ostream &operator<<(::std::ostream &out, const ::mdbx::env::geometry::size &it) {
1640
+ switch (it.bytes) {
1641
+ case ::mdbx::env::geometry::default_value:
1642
+ return out << "default";
1643
+ case ::mdbx::env::geometry::minimal_value:
1644
+ return out << "minimal";
1645
+ case ::mdbx::env::geometry::maximal_value:
1646
+ return out << "maximal";
1647
+ }
1648
+
1649
+ const auto bytes = (it.bytes < 0) ? out << "-", size_t(-it.bytes) : size_t(it.bytes);
1650
+ struct {
1651
+ size_t one;
1652
+ const char *suffix;
1653
+ } static const scales[] = {
1654
+ #if MDBX_WORDBITS > 32
1655
+ {env_managed::geometry::EiB, "EiB"},
1656
+ {env_managed::geometry::EB, "EB"},
1657
+ {env_managed::geometry::PiB, "PiB"},
1658
+ {env_managed::geometry::PB, "PB"},
1659
+ {env_managed::geometry::TiB, "TiB"},
1660
+ {env_managed::geometry::TB, "TB"},
1661
+ #endif
1662
+ {env_managed::geometry::GiB, "GiB"},
1663
+ {env_managed::geometry::GB, "GB"},
1664
+ {env_managed::geometry::MiB, "MiB"},
1665
+ {env_managed::geometry::MB, "MB"},
1666
+ {env_managed::geometry::KiB, "KiB"},
1667
+ {env_managed::geometry::kB, "kB"},
1668
+ {1, " bytes"}};
1669
+
1670
+ for (const auto i : scales)
1671
+ if (bytes % i.one == 0)
1672
+ return out << bytes / i.one << i.suffix;
1673
+
1674
+ assert(false);
1675
+ __unreachable();
1676
+ return out;
1677
+ }
1678
+
1679
+ __cold ::std::ostream &operator<<(::std::ostream &out, const env::geometry &it) {
1680
+ return //
1681
+ out << "\tlower " << env::geometry::size(it.size_lower) //
1682
+ << ",\n\tnow " << env::geometry::size(it.size_now) //
1683
+ << ",\n\tupper " << env::geometry::size(it.size_upper) //
1684
+ << ",\n\tgrowth " << env::geometry::size(it.growth_step) //
1685
+ << ",\n\tshrink " << env::geometry::size(it.shrink_threshold) //
1686
+ << ",\n\tpagesize " << env::geometry::size(it.pagesize) << "\n";
1687
+ }
1688
+
1689
+ __cold ::std::ostream &operator<<(::std::ostream &out, const env::operate_parameters &it) {
1690
+ return out << "{\n" //
1691
+ << "\tmax_maps " << it.max_maps //
1692
+ << ",\n\tmax_readers " << it.max_readers //
1693
+ << ",\n\tmode " << it.mode //
1694
+ << ",\n\tdurability " << it.durability //
1695
+ << ",\n\treclaiming " << it.reclaiming //
1696
+ << ",\n\toptions " << it.options //
1697
+ << "\n}";
1698
+ }
1699
+
1700
+ __cold ::std::ostream &operator<<(::std::ostream &out, const env::mode &it) {
1701
+ switch (it) {
1702
+ case env::mode::readonly:
1703
+ return out << "readonly";
1704
+ case env::mode::write_file_io:
1705
+ return out << "write_file_io";
1706
+ case env::mode::write_mapped_io:
1707
+ return out << "write_mapped_io";
1708
+ default:
1709
+ return out << "mdbx::env::mode::invalid";
1710
+ }
1711
+ }
1712
+
1713
+ __cold ::std::ostream &operator<<(::std::ostream &out, const env::durability &it) {
1714
+ switch (it) {
1715
+ case env::durability::robust_synchronous:
1716
+ return out << "robust_synchronous";
1717
+ case env::durability::half_synchronous_weak_last:
1718
+ return out << "half_synchronous_weak_last";
1719
+ case env::durability::lazy_weak_tail:
1720
+ return out << "lazy_weak_tail";
1721
+ case env::durability::whole_fragile:
1722
+ return out << "whole_fragile";
1723
+ default:
1724
+ return out << "mdbx::env::durability::invalid";
1725
+ }
1726
+ }
1727
+
1728
+ __cold ::std::ostream &operator<<(::std::ostream &out, const env::reclaiming_options &it) {
1729
+ return out << "{" //
1730
+ << "lifo: " << (it.lifo ? "yes" : "no") //
1731
+ << ", coalesce: " << (it.coalesce ? "yes" : "no") //
1732
+ << "}";
1733
+ }
1734
+
1735
+ __cold ::std::ostream &operator<<(::std::ostream &out, const env::operate_options &it) {
1736
+ static const char comma[] = ", ";
1737
+ const char *delimiter = "";
1738
+ out << "{";
1739
+ if (it.no_sticky_threads) {
1740
+ out << delimiter << "no_sticky_threads";
1741
+ delimiter = comma;
1742
+ }
1743
+ if (it.nested_write_transactions) {
1744
+ out << delimiter << "nested_write_transactions";
1745
+ delimiter = comma;
1746
+ }
1747
+ if (it.exclusive) {
1748
+ out << delimiter << "exclusive";
1749
+ delimiter = comma;
1750
+ }
1751
+ if (it.disable_readahead) {
1752
+ out << delimiter << "disable_readahead";
1753
+ delimiter = comma;
1754
+ }
1755
+ if (it.disable_clear_memory) {
1756
+ out << delimiter << "disable_clear_memory";
1757
+ delimiter = comma;
1758
+ }
1759
+ if (delimiter != comma)
1760
+ out << "default";
1761
+ return out << "}";
1762
+ }
1763
+
1764
+ __cold ::std::ostream &operator<<(::std::ostream &out, const env_managed::create_parameters &it) {
1765
+ return out << "{\n" //
1766
+ << "\tfile_mode " << std::oct << it.file_mode_bits << std::dec //
1767
+ << ",\n\tsubdirectory " << (it.use_subdirectory ? "yes" : "no") //
1768
+ << ",\n"
1769
+ << it.geometry << "}";
1770
+ }
1771
+
1772
+ __cold ::std::ostream &operator<<(::std::ostream &out, const MDBX_log_level_t &it) {
1773
+ switch (it) {
1774
+ case MDBX_LOG_FATAL:
1775
+ return out << "LOG_FATAL";
1776
+ case MDBX_LOG_ERROR:
1777
+ return out << "LOG_ERROR";
1778
+ case MDBX_LOG_WARN:
1779
+ return out << "LOG_WARN";
1780
+ case MDBX_LOG_NOTICE:
1781
+ return out << "LOG_NOTICE";
1782
+ case MDBX_LOG_VERBOSE:
1783
+ return out << "LOG_VERBOSE";
1784
+ case MDBX_LOG_DEBUG:
1785
+ return out << "LOG_DEBUG";
1786
+ case MDBX_LOG_TRACE:
1787
+ return out << "LOG_TRACE";
1788
+ case MDBX_LOG_EXTRA:
1789
+ return out << "LOG_EXTRA";
1790
+ case MDBX_LOG_DONTCHANGE:
1791
+ return out << "LOG_DONTCHANGE";
1792
+ default:
1793
+ return out << "mdbx::log_level::invalid";
1794
+ }
1795
+ }
1796
+
1797
+ __cold ::std::ostream &operator<<(::std::ostream &out, const MDBX_debug_flags_t &it) {
1798
+ if (it == MDBX_DBG_DONTCHANGE)
1799
+ return out << "DBG_DONTCHANGE";
1800
+
1801
+ static const char comma[] = "|";
1802
+ const char *delimiter = "";
1803
+ out << "{";
1804
+ if (it & MDBX_DBG_ASSERT) {
1805
+ out << delimiter << "DBG_ASSERT";
1806
+ delimiter = comma;
1807
+ }
1808
+ if (it & MDBX_DBG_AUDIT) {
1809
+ out << delimiter << "DBG_AUDIT";
1810
+ delimiter = comma;
1811
+ }
1812
+ if (it & MDBX_DBG_JITTER) {
1813
+ out << delimiter << "DBG_JITTER";
1814
+ delimiter = comma;
1815
+ }
1816
+ if (it & MDBX_DBG_DUMP) {
1817
+ out << delimiter << "DBG_DUMP";
1818
+ delimiter = comma;
1819
+ }
1820
+ if (it & MDBX_DBG_LEGACY_MULTIOPEN) {
1821
+ out << delimiter << "DBG_LEGACY_MULTIOPEN";
1822
+ delimiter = comma;
1823
+ }
1824
+ if (it & MDBX_DBG_LEGACY_OVERLAP) {
1825
+ out << delimiter << "DBG_LEGACY_OVERLAP";
1826
+ delimiter = comma;
1827
+ }
1828
+ if (delimiter != comma)
1829
+ out << "DBG_NONE";
1830
+ return out << "}";
1831
+ }
1832
+
1833
+ __cold ::std::ostream &operator<<(::std::ostream &out, const ::mdbx::error &err) {
1834
+ return out << err.what() << " (" << long(err.code()) << ")";
1835
+ }
1836
+
1837
+ } // namespace mdbx