1
|
|
2
|
|
3
|
|
4
|
|
5
|
|
6
|
|
7
|
|
8
|
/// - Elbrus LCC >= 1.23 (http://www.mcst.ru/lcc); |
9
|
|
10
|
|
11
|
|
12
|
|
13
|
|
14
|
|
15
|
|
16
|
|
17
|
/// The origin has been migrated to https://gitflic.ru/project/erthink/libmdbx |
18
|
|
19
|
|
20
|
/// simultaneously blocking access for many developers. |
21
|
|
22
|
|
23
|
|
24
|
#pragma once |
25
|
|
26
|
/* Workaround for modern libstdc++ with CLANG < 4.x */ |
27
|
#if defined(__SIZEOF_INT128__) && !defined(__GLIBCXX_TYPE_INT_N_0) && \ |
28
|
defined(__clang__) && __clang_major__ < 4 |
29
|
#define __GLIBCXX_BITSIZE_INT_N_0 128 |
30
|
#define __GLIBCXX_TYPE_INT_N_0 __int128 |
31
|
#endif |
32
|
|
33
|
#if !defined(__cplusplus) || __cplusplus < 201103L |
34
|
#if !defined(_MSC_VER) || _MSC_VER < 1900 |
35
|
#error "C++11 compiler or better is required" |
36
|
#elif _MSC_VER >= 1910 |
37
|
#error \ |
38
|
"Please add `/Zc:__cplusplus` to MSVC compiler options to enforce it conform ISO C++" |
39
|
#endif |
40
|
#endif |
41
|
|
42
|
#if (defined(_WIN32) || defined(_WIN64)) && MDBX_WITHOUT_MSVC_CRT |
43
|
#error \ |
44
|
"CRT is required for C++ API, the MDBX_WITHOUT_MSVC_CRT option must be disabled" |
45
|
#endif |
46
|
|
47
|
#ifndef __has_include |
48
|
#define __has_include(header) (0) |
49
|
#endif |
50
|
|
51
|
#if __has_include(<version>) |
52
|
#include <version> |
53
|
#endif |
54
|
|
55
|
|
56
|
#ifndef NOMINMAX |
57
|
#define NOMINMAX |
58
|
#endif |
59
|
|
60
|
#include <algorithm> // for std::min/max |
61
|
#include <cassert> // for assert() |
62
|
#include <climits> // for CHAR_BIT |
63
|
#include <cstring> // for std::strlen, str:memcmp |
64
|
#include <exception> // for std::exception_ptr |
65
|
#include <ostream> // for std::ostream |
66
|
#include <sstream> // for std::ostringstream |
67
|
#include <stdexcept> // for std::invalid_argument |
68
|
#include <string> // for std::string |
69
|
#include <type_traits> // for std::is_pod<>, etc. |
70
|
#include <utility> // for std::make_pair |
71
|
#include <vector> // for std::vector<> as template args |
72
|
|
73
|
#if defined(__cpp_lib_memory_resource) && __cpp_lib_memory_resource >= 201603L |
74
|
#include <memory_resource> |
75
|
#endif |
76
|
|
77
|
#if defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L |
78
|
#include <string_view> |
79
|
#endif |
80
|
|
81
|
#if defined(__cpp_lib_filesystem) && __cpp_lib_filesystem >= 201703L |
82
|
#include <filesystem> |
83
|
#elif __has_include(<experimental/filesystem>) |
84
|
#include <experimental/filesystem> |
85
|
#endif |
86
|
|
87
|
#include "mdbx.h" |
88
|
|
89
|
#if (defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L) || \ |
90
|
(defined(__cpp_lib_endian) && __cpp_lib_endian >= 201907L) || \ |
91
|
(defined(__cpp_lib_bitops) && __cpp_lib_bitops >= 201907L) || \ |
92
|
(defined(__cpp_lib_int_pow2) && __cpp_lib_int_pow2 >= 202002L) |
93
|
#include <bit> |
94
|
#elif !(defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \ |
95
|
defined(__ORDER_BIG_ENDIAN__)) |
96
|
#if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && defined(__BIG_ENDIAN) |
97
|
#define __ORDER_LITTLE_ENDIAN__ __LITTLE_ENDIAN |
98
|
#define __ORDER_BIG_ENDIAN__ __BIG_ENDIAN |
99
|
#define __BYTE_ORDER__ __BYTE_ORDER |
100
|
#elif defined(_BYTE_ORDER) && defined(_LITTLE_ENDIAN) && defined(_BIG_ENDIAN) |
101
|
#define __ORDER_LITTLE_ENDIAN__ _LITTLE_ENDIAN |
102
|
#define __ORDER_BIG_ENDIAN__ _BIG_ENDIAN |
103
|
#define __BYTE_ORDER__ _BYTE_ORDER |
104
|
#else |
105
|
#define __ORDER_LITTLE_ENDIAN__ 1234 |
106
|
#define __ORDER_BIG_ENDIAN__ 4321 |
107
|
#if defined(__LITTLE_ENDIAN__) || \ |
108
|
(defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)) || \ |
109
|
defined(__ARMEL__) || defined(__THUMBEL__) || defined(__AARCH64EL__) || \ |
110
|
defined(__MIPSEL__) || defined(_MIPSEL) || defined(__MIPSEL) || \ |
111
|
defined(_M_ARM) || defined(_M_ARM64) || defined(__e2k__) || \ |
112
|
defined(__elbrus_4c__) || defined(__elbrus_8c__) || defined(__bfin__) || \ |
113
|
defined(__BFIN__) || defined(__ia64__) || defined(_IA64) || \ |
114
|
defined(__IA64__) || defined(__ia64) || defined(_M_IA64) || \ |
115
|
defined(__itanium__) || defined(__ia32__) || defined(__CYGWIN__) || \ |
116
|
defined(_WIN64) || defined(_WIN32) || defined(__TOS_WIN__) || \ |
117
|
defined(__WINDOWS__) |
118
|
#define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ |
119
|
#elif defined(__BIG_ENDIAN__) || \ |
120
|
(defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)) || \ |
121
|
defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) || \ |
122
|
defined(__MIPSEB__) || defined(_MIPSEB) || defined(__MIPSEB) || \ |
123
|
defined(__m68k__) || defined(M68000) || defined(__hppa__) || \ |
124
|
defined(__hppa) || defined(__HPPA__) || defined(__sparc__) || \ |
125
|
defined(__sparc) || defined(__370__) || defined(__THW_370__) || \ |
126
|
defined(__s390__) || defined(__s390x__) || defined(__SYSC_ZARCH__) |
127
|
#define __BYTE_ORDER__ __ORDER_BIG_ENDIAN__ |
128
|
#endif |
129
|
#endif |
130
|
#endif |
131
|
|
132
|
/** Workaround for old compilers without properly support for `C++17 constexpr`. |
133
|
*/ |
134
|
#if defined(DOXYGEN) |
135
|
#define MDBX_CXX17_CONSTEXPR constexpr |
136
|
#elif defined(__cpp_constexpr) && __cpp_constexpr >= 201603L && \ |
137
|
((defined(_MSC_VER) && _MSC_VER >= 1915) || \ |
138
|
(defined(__clang__) && __clang_major__ > 5) || \ |
139
|
(defined(__GNUC__) && __GNUC__ > 7) || \ |
140
|
(!defined(__GNUC__) && !defined(__clang__) && !defined(_MSC_VER))) |
141
|
#define MDBX_CXX17_CONSTEXPR constexpr |
142
|
#else |
143
|
#define MDBX_CXX17_CONSTEXPR inline |
144
|
#endif |
145
|
|
146
|
/** Workaround for old compilers without properly support for C++20 `constexpr`. |
147
|
*/ |
148
|
#if defined(DOXYGEN) |
149
|
#define MDBX_CXX20_CONSTEXPR constexpr |
150
|
#elif defined(__cpp_lib_is_constant_evaluated) && \ |
151
|
__cpp_lib_is_constant_evaluated >= 201811L && \ |
152
|
defined(__cpp_lib_constexpr_string) && \ |
153
|
__cpp_lib_constexpr_string >= 201907L |
154
|
#define MDBX_CXX20_CONSTEXPR constexpr |
155
|
#else |
156
|
#define MDBX_CXX20_CONSTEXPR inline |
157
|
#endif |
158
|
|
159
|
/** Workaround for old compilers without support assertion inside `constexpr` |
160
|
* functions. */ |
161
|
#if defined(CONSTEXPR_ASSERT) |
162
|
#define MDBX_CONSTEXPR_ASSERT(expr) CONSTEXPR_ASSERT(expr) |
163
|
#elif defined NDEBUG |
164
|
#define MDBX_CONSTEXPR_ASSERT(expr) void(0) |
165
|
#else |
166
|
#define MDBX_CONSTEXPR_ASSERT(expr) \ |
167
|
((expr) ? void(0) : [] { assert(!#expr); }()) |
168
|
#endif |
169
|
|
170
|
#ifndef MDBX_LIKELY |
171
|
#if defined(DOXYGEN) || \ |
172
|
(defined(__GNUC__) || __has_builtin(__builtin_expect)) && \ |
173
|
!defined(__COVERITY__) |
174
|
#define MDBX_LIKELY(cond) __builtin_expect(!!(cond), 1) |
175
|
#else |
176
|
#define MDBX_LIKELY(x) (x) |
177
|
#endif |
178
|
#endif |
179
|
|
180
|
#ifndef MDBX_UNLIKELY |
181
|
#if defined(DOXYGEN) || \ |
182
|
(defined(__GNUC__) || __has_builtin(__builtin_expect)) && \ |
183
|
!defined(__COVERITY__) |
184
|
#define MDBX_UNLIKELY(cond) __builtin_expect(!!(cond), 0) |
185
|
#else |
186
|
#define MDBX_UNLIKELY(x) (x) |
187
|
#endif |
188
|
#endif |
189
|
|
190
|
/** Workaround for old compilers without properly support for C++20 `if |
191
|
* constexpr`. */ |
192
|
#if defined(DOXYGEN) |
193
|
#define MDBX_IF_CONSTEXPR constexpr |
194
|
#elif defined(__cpp_if_constexpr) && __cpp_if_constexpr >= 201606L |
195
|
#define MDBX_IF_CONSTEXPR constexpr |
196
|
#else |
197
|
#define MDBX_IF_CONSTEXPR |
198
|
#endif |
199
|
|
200
|
#if defined(DOXYGEN) || \ |
201
|
(__has_cpp_attribute(fallthrough) && \ |
202
|
(!defined(__clang__) || __clang__ > 4)) || \ |
203
|
__cplusplus >= 201703L |
204
|
#define MDBX_CXX17_FALLTHROUGH [[fallthrough]] |
205
|
#else |
206
|
#define MDBX_CXX17_FALLTHROUGH |
207
|
#endif |
208
|
|
209
|
#if defined(DOXYGEN) || (__has_cpp_attribute(likely) >= 201803L && \ |
210
|
(!defined(__GNUC__) || __GNUC__ > 9)) |
211
|
#define MDBX_CXX20_LIKELY [[likely]] |
212
|
#else |
213
|
#define MDBX_CXX20_LIKELY |
214
|
#endif |
215
|
|
216
|
#ifndef MDBX_CXX20_UNLIKELY |
217
|
#if defined(DOXYGEN) || (__has_cpp_attribute(unlikely) >= 201803L && \ |
218
|
(!defined(__GNUC__) || __GNUC__ > 9)) |
219
|
#define MDBX_CXX20_UNLIKELY [[unlikely]] |
220
|
#else |
221
|
#define MDBX_CXX20_UNLIKELY |
222
|
#endif |
223
|
#endif |
224
|
|
225
|
#ifndef MDBX_HAVE_CXX20_CONCEPTS |
226
|
#if defined(DOXYGEN) || \ |
227
|
(defined(__cpp_lib_concepts) && __cpp_lib_concepts >= 202002L) |
228
|
#include <concepts> |
229
|
#define MDBX_HAVE_CXX20_CONCEPTS 1 |
230
|
#else |
231
|
#define MDBX_HAVE_CXX20_CONCEPTS 0 |
232
|
#endif |
233
|
#endif |
234
|
|
235
|
#ifndef MDBX_CXX20_CONCEPT |
236
|
#if MDBX_HAVE_CXX20_CONCEPTS |
237
|
#define MDBX_CXX20_CONCEPT(CONCEPT, NAME) CONCEPT NAME |
238
|
#else |
239
|
#define MDBX_CXX20_CONCEPT(CONCEPT, NAME) typename NAME |
240
|
#endif |
241
|
#endif |
242
|
|
243
|
#ifndef MDBX_ASSERT_CXX20_CONCEPT_SATISFIED |
244
|
#if MDBX_HAVE_CXX20_CONCEPTS |
245
|
#define MDBX_ASSERT_CXX20_CONCEPT_SATISFIED(CONCEPT, TYPE) \ |
246
|
static_assert(CONCEPT<TYPE>) |
247
|
#else |
248
|
#define MDBX_ASSERT_CXX20_CONCEPT_SATISFIED(CONCEPT, NAME) \ |
249
|
static_assert(true, MDBX_STRINGIFY(CONCEPT) "<" MDBX_STRINGIFY(TYPE) ">") |
250
|
#endif |
251
|
#endif |
252
|
|
253
|
#ifdef _MSC_VER |
254
|
#pragma warning(push, 4) |
255
|
#pragma warning(disable : 4127) |
256
|
#pragma warning(disable : 4251) /* 'std::FOO' needs to have dll-interface to \ |
257
|
be used by clients of 'mdbx::BAR' */ |
258
|
#pragma warning(disable : 4275) /* non dll-interface 'std::FOO' used as \ |
259
|
base for dll-interface 'mdbx::BAR' */ |
260
|
/* MSVC is mad and can generate this warning for its own intermediate |
261
|
* automatically generated code, which becomes unreachable after some kinds of |
262
|
* optimization (copy elision, etc). */ |
263
|
#pragma warning(disable : 4702) |
264
|
#endif |
265
|
|
266
|
#if defined(__LCC__) && __LCC__ >= 126 |
267
|
#pragma diagnostic push |
268
|
#if __LCC__ < 127 |
269
|
#pragma diag_suppress 3058 /* workaround: call to is_constant_evaluated() \ |
270
|
appearing in a constant expression `true` */ |
271
|
#pragma diag_suppress 3060 /* workaround: call to is_constant_evaluated() \ |
272
|
appearing in a constant expression `false` */ |
273
|
#endif |
274
|
#endif |
275
|
|
276
|
|
277
|
|
278
|
|
279
|
namespace mdbx { |
280
|
|
281
|
|
282
|
|
283
|
|
284
|
|
285
|
|
286
|
#if defined(DOXYGEN) || (defined(__cpp_char8_t) && __cpp_char8_t >= 201811) |
287
|
|
288
|
|
289
|
|
290
|
// Please see https://libmdbx.dqdkfa.ru/dead-github/issues/263 |
291
|
// for reasoning of the use of `char8_t` type and switching to `__restrict__`. |
292
|
using byte = char8_t; |
293
|
#else |
294
|
|
295
|
|
296
|
using byte = unsigned char; |
297
|
#endif |
298
|
|
299
|
#if defined(__cpp_lib_endian) && __cpp_lib_endian >= 201907L |
300
|
using endian = ::std::endian; |
301
|
#elif defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \ |
302
|
defined(__ORDER_BIG_ENDIAN__) |
303
|
enum class endian { |
304
|
little = __ORDER_LITTLE_ENDIAN__, |
305
|
big = __ORDER_BIG_ENDIAN__, |
306
|
native = __BYTE_ORDER__ |
307
|
}; |
308
|
#else |
309
|
#error \ |
310
|
"Please use a C++ compiler provides byte order information or C++20 support" |
311
|
#endif |
312
|
|
313
|
|
314
|
using version_info = ::MDBX_version_info; |
315
|
|
316
|
MDBX_CXX11_CONSTEXPR const version_info &get_version() noexcept; |
317
|
|
318
|
using build_info = ::MDBX_build_info; |
319
|
|
320
|
MDBX_CXX11_CONSTEXPR const build_info &get_build() noexcept; |
321
|
|
322
|
|
323
|
static MDBX_CXX17_CONSTEXPR size_t strlen(const char *c_str) noexcept; |
324
|
|
325
|
|
326
|
static MDBX_CXX20_CONSTEXPR void *memcpy(void *dest, const void *src, |
327
|
size_t bytes) noexcept; |
328
|
|
329
|
static MDBX_CXX20_CONSTEXPR int memcmp(const void *a, const void *b, |
330
|
size_t bytes) noexcept; |
331
|
|
332
|
|
333
|
|
334
|
using legacy_allocator = ::std::string::allocator_type; |
335
|
|
336
|
struct slice; |
337
|
struct default_capacity_policy; |
338
|
template <class ALLOCATOR = legacy_allocator, |
339
|
class CAPACITY_POLICY = default_capacity_policy> |
340
|
class buffer; |
341
|
class env; |
342
|
class env_managed; |
343
|
class txn; |
344
|
class txn_managed; |
345
|
class cursor; |
346
|
class cursor_managed; |
347
|
|
348
|
#if defined(DOXYGEN) || \ |
349
|
(defined(__cpp_lib_memory_resource) && \ |
350
|
__cpp_lib_memory_resource >= 201603L && _GLIBCXX_USE_CXX11_ABI) |
351
|
/// \brief Default polymorphic allocator for modern code. |
352
|
using polymorphic_allocator = ::std::pmr::string::allocator_type; |
353
|
#endif |
354
|
|
355
|
|
356
|
template <class ALLOCATOR = legacy_allocator> |
357
|
using string = ::std::basic_string<char, ::std::char_traits<char>, ALLOCATOR>; |
358
|
|
359
|
using filehandle = ::mdbx_filehandle_t; |
360
|
#if defined(DOXYGEN) || \ |
361
|
(defined(__cpp_lib_filesystem) && __cpp_lib_filesystem >= 201703L && \ |
362
|
(!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || \ |
363
|
__MAC_OS_X_VERSION_MIN_REQUIRED >= 101500) && \ |
364
|
(!defined(__IPHONE_OS_VERSION_MIN_REQUIRED) || \ |
365
|
__IPHONE_OS_VERSION_MIN_REQUIRED >= 130100)) |
366
|
namespace filesystem = ::std::filesystem; |
367
|
/// \brief Defined if `mdbx::filesystem::path` is available. |
368
|
/// \details If defined, it is always `mdbx::filesystem::path`, |
369
|
/// which in turn can be refs to `std::filesystem::path` |
370
|
/// or `std::experimental::filesystem::path`. |
371
|
/// Nonetheless `MDBX_STD_FILESYSTEM_PATH` not defined if the `::mdbx::path` |
372
|
/// is fallbacked to c `std::string` or `std::wstring`. |
373
|
#define MDBX_STD_FILESYSTEM_PATH ::mdbx::filesystem::path |
374
|
#elif defined(__cpp_lib_experimental_filesystem) && \ |
375
|
__cpp_lib_experimental_filesystem >= 201406L |
376
|
namespace filesystem = ::std::experimental::filesystem; |
377
|
#define MDBX_STD_FILESYSTEM_PATH ::mdbx::filesystem::path |
378
|
#endif |
379
|
|
380
|
#ifdef MDBX_STD_FILESYSTEM_PATH |
381
|
using path = MDBX_STD_FILESYSTEM_PATH; |
382
|
#elif defined(_WIN32) || defined(_WIN64) |
383
|
using path = ::std::wstring; |
384
|
#else |
385
|
using path = ::std::string; |
386
|
#endif |
387
|
|
388
|
/// \defgroup cxx_exceptions exceptions and errors |
389
|
|
390
|
|
391
|
|
392
|
|
393
|
|
394
|
|
395
|
class LIBMDBX_API_TYPE exception_thunk { |
396
|
::std::exception_ptr captured_; |
397
|
|
398
|
public: |
399
|
exception_thunk() noexcept = default; |
400
|
exception_thunk(const exception_thunk &) = delete; |
401
|
exception_thunk(exception_thunk &&) = delete; |
402
|
exception_thunk &operator=(const exception_thunk &) = delete; |
403
|
exception_thunk &operator=(exception_thunk &&) = delete; |
404
|
inline bool is_clean() const noexcept; |
405
|
inline void capture() noexcept; |
406
|
inline void rethrow_captured() const; |
407
|
}; |
408
|
|
409
|
/// \brief Implements error information and throwing corresponding exceptions. |
410
|
class LIBMDBX_API_TYPE error { |
411
|
MDBX_error_t code_; |
412
|
inline error &operator=(MDBX_error_t error_code) noexcept; |
413
|
|
414
|
public: |
415
|
MDBX_CXX11_CONSTEXPR error(MDBX_error_t error_code) noexcept; |
416
|
error(const error &) = default; |
417
|
error(error &&) = default; |
418
|
error &operator=(const error &) = default; |
419
|
error &operator=(error &&) = default; |
420
|
|
421
|
MDBX_CXX11_CONSTEXPR friend bool operator==(const error &a, |
422
|
const error &b) noexcept; |
423
|
MDBX_CXX11_CONSTEXPR friend bool operator!=(const error &a, |
424
|
const error &b) noexcept; |
425
|
|
426
|
MDBX_CXX11_CONSTEXPR bool is_success() const noexcept; |
427
|
MDBX_CXX11_CONSTEXPR bool is_result_true() const noexcept; |
428
|
MDBX_CXX11_CONSTEXPR bool is_result_false() const noexcept; |
429
|
MDBX_CXX11_CONSTEXPR bool is_failure() const noexcept; |
430
|
|
431
|
|
432
|
MDBX_CXX11_CONSTEXPR MDBX_error_t code() const noexcept; |
433
|
|
434
|
/// \brief Returns message for MDBX's errors only and "SYSTEM" for others. |
435
|
const char *what() const noexcept; |
436
|
|
437
|
/// \brief Returns message for any errors. |
438
|
::std::string message() const; |
439
|
|
440
|
/// \brief Returns true for MDBX's errors. |
441
|
MDBX_CXX11_CONSTEXPR bool is_mdbx_error() const noexcept; |
442
|
|
443
|
[[noreturn]] void panic(const char *context_where_when, |
444
|
const char *func_who_what) const noexcept; |
445
|
[[noreturn]] void throw_exception() const; |
446
|
[[noreturn]] static inline void throw_exception(int error_code); |
447
|
inline void throw_on_failure() const; |
448
|
inline void success_or_throw() const; |
449
|
inline void success_or_throw(const exception_thunk &) const; |
450
|
inline void panic_on_failure(const char *context_where, |
451
|
const char *func_who) const noexcept; |
452
|
inline void success_or_panic(const char *context_where, |
453
|
const char *func_who) const noexcept; |
454
|
static inline void throw_on_nullptr(const void *ptr, MDBX_error_t error_code); |
455
|
static inline void success_or_throw(MDBX_error_t error_code); |
456
|
static void success_or_throw(int error_code) { |
457
|
success_or_throw(static_cast<MDBX_error_t>(error_code)); |
458
|
} |
459
|
static inline void throw_on_failure(int error_code); |
460
|
static inline bool boolean_or_throw(int error_code); |
461
|
static inline void success_or_throw(int error_code, const exception_thunk &); |
462
|
static inline void panic_on_failure(int error_code, const char *context_where, |
463
|
const char *func_who) noexcept; |
464
|
static inline void success_or_panic(int error_code, const char *context_where, |
465
|
const char *func_who) noexcept; |
466
|
}; |
467
|
|
468
|
/// \brief Base class for all libmdbx's exceptions that are corresponds |
469
|
|
470
|
|
471
|
|
472
|
class LIBMDBX_API_TYPE exception : public ::std::runtime_error { |
473
|
using base = ::std::runtime_error; |
474
|
::mdbx::error error_; |
475
|
|
476
|
public: |
477
|
exception(const ::mdbx::error &) noexcept; |
478
|
exception(const exception &) = default; |
479
|
exception(exception &&) = default; |
480
|
exception &operator=(const exception &) = default; |
481
|
exception &operator=(exception &&) = default; |
482
|
virtual ~exception() noexcept; |
483
|
const ::mdbx::error error() const noexcept { return error_; } |
484
|
}; |
485
|
|
486
|
|
487
|
/// in dangerous unrecoverable cases. |
488
|
class LIBMDBX_API_TYPE fatal : public exception { |
489
|
using base = exception; |
490
|
|
491
|
public: |
492
|
fatal(const ::mdbx::error &) noexcept; |
493
|
fatal(const exception &src) noexcept : fatal(src.error()) {} |
494
|
fatal(exception &&src) noexcept : fatal(src.error()) {} |
495
|
fatal(const fatal &src) noexcept : fatal(src.error()) {} |
496
|
fatal(fatal &&src) noexcept : fatal(src.error()) {} |
497
|
fatal &operator=(fatal &&) = default; |
498
|
fatal &operator=(const fatal &) = default; |
499
|
virtual ~fatal() noexcept; |
500
|
}; |
501
|
|
502
|
#define MDBX_DECLARE_EXCEPTION(NAME) \ |
503
|
struct LIBMDBX_API_TYPE NAME : public exception { \ |
504
|
NAME(const ::mdbx::error &); \ |
505
|
virtual ~NAME() noexcept; \ |
506
|
} |
507
|
MDBX_DECLARE_EXCEPTION(bad_map_id); |
508
|
MDBX_DECLARE_EXCEPTION(bad_transaction); |
509
|
MDBX_DECLARE_EXCEPTION(bad_value_size); |
510
|
MDBX_DECLARE_EXCEPTION(db_corrupted); |
511
|
MDBX_DECLARE_EXCEPTION(db_full); |
512
|
MDBX_DECLARE_EXCEPTION(db_invalid); |
513
|
MDBX_DECLARE_EXCEPTION(db_too_large); |
514
|
MDBX_DECLARE_EXCEPTION(db_unable_extend); |
515
|
MDBX_DECLARE_EXCEPTION(db_version_mismatch); |
516
|
MDBX_DECLARE_EXCEPTION(db_wanna_write_for_recovery); |
517
|
MDBX_DECLARE_EXCEPTION(incompatible_operation); |
518
|
MDBX_DECLARE_EXCEPTION(internal_page_full); |
519
|
MDBX_DECLARE_EXCEPTION(internal_problem); |
520
|
MDBX_DECLARE_EXCEPTION(key_exists); |
521
|
MDBX_DECLARE_EXCEPTION(key_mismatch); |
522
|
MDBX_DECLARE_EXCEPTION(max_maps_reached); |
523
|
MDBX_DECLARE_EXCEPTION(max_readers_reached); |
524
|
MDBX_DECLARE_EXCEPTION(multivalue); |
525
|
MDBX_DECLARE_EXCEPTION(no_data); |
526
|
MDBX_DECLARE_EXCEPTION(not_found); |
527
|
MDBX_DECLARE_EXCEPTION(operation_not_permitted); |
528
|
MDBX_DECLARE_EXCEPTION(permission_denied_or_not_writeable); |
529
|
MDBX_DECLARE_EXCEPTION(reader_slot_busy); |
530
|
MDBX_DECLARE_EXCEPTION(remote_media); |
531
|
MDBX_DECLARE_EXCEPTION(something_busy); |
532
|
MDBX_DECLARE_EXCEPTION(thread_mismatch); |
533
|
MDBX_DECLARE_EXCEPTION(transaction_full); |
534
|
MDBX_DECLARE_EXCEPTION(transaction_overlapping); |
535
|
#undef MDBX_DECLARE_EXCEPTION |
536
|
|
537
|
[[noreturn]] LIBMDBX_API void throw_too_small_target_buffer(); |
538
|
[[noreturn]] LIBMDBX_API void throw_max_length_exceeded(); |
539
|
[[noreturn]] LIBMDBX_API void throw_out_range(); |
540
|
[[noreturn]] LIBMDBX_API void throw_allocators_mismatch(); |
541
|
static MDBX_CXX14_CONSTEXPR size_t check_length(size_t bytes); |
542
|
static MDBX_CXX14_CONSTEXPR size_t check_length(size_t headroom, |
543
|
size_t payload); |
544
|
static MDBX_CXX14_CONSTEXPR size_t check_length(size_t headroom, size_t payload, |
545
|
size_t tailroom); |
546
|
|
547
|
/// end of cxx_exceptions @} |
548
|
|
549
|
|
550
|
|
551
|
/// \defgroup cxx_data slices and buffers |
552
|
|
553
|
|
554
|
#if MDBX_HAVE_CXX20_CONCEPTS |
555
|
|
556
|
template <typename T> |
557
|
concept MutableByteProducer = requires(T a, char array[42]) { |
558
|
{ a.is_empty() } -> std::same_as<bool>; |
559
|
{ a.envisage_result_length() } -> std::same_as<size_t>; |
560
|
{ a.write_bytes(&array[0], size_t(42)) } -> std::same_as<char *>; |
561
|
}; |
562
|
|
563
|
template <typename T> |
564
|
concept ImmutableByteProducer = requires(const T &a, char array[42]) { |
565
|
{ a.is_empty() } -> std::same_as<bool>; |
566
|
{ a.envisage_result_length() } -> std::same_as<size_t>; |
567
|
{ a.write_bytes(&array[0], size_t(42)) } -> std::same_as<char *>; |
568
|
}; |
569
|
|
570
|
template <typename T> |
571
|
concept SliceTranscoder = ImmutableByteProducer<T> && |
572
|
requires(const slice &source, const T &a) { |
573
|
T(source); |
574
|
{ a.is_erroneous() } -> std::same_as<bool>; |
575
|
}; |
576
|
|
577
|
#endif |
578
|
|
579
|
template <class ALLOCATOR = legacy_allocator, |
580
|
typename CAPACITY_POLICY = default_capacity_policy, |
581
|
MDBX_CXX20_CONCEPT(MutableByteProducer, PRODUCER)> |
582
|
inline buffer<ALLOCATOR, CAPACITY_POLICY> |
583
|
make_buffer(PRODUCER &producer, const ALLOCATOR &allocator = ALLOCATOR()); |
584
|
|
585
|
template <class ALLOCATOR = legacy_allocator, |
586
|
typename CAPACITY_POLICY = default_capacity_policy, |
587
|
MDBX_CXX20_CONCEPT(ImmutableByteProducer, PRODUCER)> |
588
|
inline buffer<ALLOCATOR, CAPACITY_POLICY> |
589
|
make_buffer(const PRODUCER &producer, const ALLOCATOR &allocator = ALLOCATOR()); |
590
|
|
591
|
template <class ALLOCATOR = legacy_allocator, |
592
|
MDBX_CXX20_CONCEPT(MutableByteProducer, PRODUCER)> |
593
|
inline string<ALLOCATOR> make_string(PRODUCER &producer, |
594
|
const ALLOCATOR &allocator = ALLOCATOR()); |
595
|
|
596
|
template <class ALLOCATOR = legacy_allocator, |
597
|
MDBX_CXX20_CONCEPT(ImmutableByteProducer, PRODUCER)> |
598
|
inline string<ALLOCATOR> make_string(const PRODUCER &producer, |
599
|
const ALLOCATOR &allocator = ALLOCATOR()); |
600
|
|
601
|
|
602
|
|
603
|
/// The `slice` is similar in many ways to `std::string_view`, but it |
604
|
|
605
|
|
606
|
|
607
|
|
608
|
struct LIBMDBX_API_TYPE slice : public ::MDBX_val { |
609
|
/// \todo slice& operator<<(slice&, ...) for reading |
610
|
/// \todo key-to-value (parse/unpack) functions |
611
|
/// \todo template<class X> key(X); for decoding keys while reading |
612
|
|
613
|
enum { max_length = MDBX_MAXDATASIZE }; |
614
|
|
615
|
|
616
|
MDBX_CXX11_CONSTEXPR slice() noexcept; |
617
|
|
618
|
|
619
|
|
620
|
MDBX_CXX14_CONSTEXPR slice(const void *ptr, size_t bytes); |
621
|
|
622
|
/// \brief Create a slice that refers to [begin,end] of memory bytes. |
623
|
MDBX_CXX14_CONSTEXPR slice(const void *begin, const void *end); |
624
|
|
625
|
|
626
|
template <size_t SIZE> |
627
|
MDBX_CXX14_CONSTEXPR slice(const char (&text)[SIZE]) : slice(text, SIZE - 1) { |
628
|
MDBX_CONSTEXPR_ASSERT(SIZE > 0 && text[SIZE - 1] == '\0'); |
629
|
} |
630
|
|
631
|
explicit MDBX_CXX17_CONSTEXPR slice(const char *c_str); |
632
|
|
633
|
|
634
|
/// \note 'explicit' to avoid reference to the temporary std::string instance. |
635
|
template <class CHAR, class T, class A> |
636
|
explicit MDBX_CXX20_CONSTEXPR |
637
|
slice(const ::std::basic_string<CHAR, T, A> &str) |
638
|
: slice(str.data(), str.length() * sizeof(CHAR)) {} |
639
|
|
640
|
MDBX_CXX14_CONSTEXPR slice(const MDBX_val &src); |
641
|
MDBX_CXX11_CONSTEXPR slice(const slice &) noexcept = default; |
642
|
MDBX_CXX14_CONSTEXPR slice(MDBX_val &&src); |
643
|
MDBX_CXX14_CONSTEXPR slice(slice &&src) noexcept; |
644
|
|
645
|
#if defined(DOXYGEN) || \ |
646
|
(defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L) |
647
|
|
648
|
template <class CHAR, class T> |
649
|
MDBX_CXX14_CONSTEXPR slice(const ::std::basic_string_view<CHAR, T> &sv) |
650
|
: slice(sv.data(), sv.data() + sv.length()) {} |
651
|
|
652
|
template <class CHAR, class T> |
653
|
slice(::std::basic_string_view<CHAR, T> &&sv) : slice(sv) { |
654
|
sv = {}; |
655
|
} |
656
|
#endif |
657
|
|
658
|
template <size_t SIZE> |
659
|
static MDBX_CXX14_CONSTEXPR slice wrap(const char (&text)[SIZE]) { |
660
|
return slice(text); |
661
|
} |
662
|
|
663
|
template <typename POD> |
664
|
MDBX_CXX14_CONSTEXPR static slice wrap(const POD &pod) { |
665
|
static_assert(::std::is_standard_layout<POD>::value && |
666
|
!::std::is_pointer<POD>::value, |
667
|
"Must be a standard layout type!"); |
668
|
return slice(&pod, sizeof(pod)); |
669
|
} |
670
|
|
671
|
inline slice &assign(const void *ptr, size_t bytes); |
672
|
inline slice &assign(const slice &src) noexcept; |
673
|
inline slice &assign(const ::MDBX_val &src); |
674
|
inline slice &assign(slice &&src) noexcept; |
675
|
inline slice &assign(::MDBX_val &&src); |
676
|
inline slice &assign(const void *begin, const void *end); |
677
|
template <class CHAR, class T, class ALLOCATOR> |
678
|
slice &assign(const ::std::basic_string<CHAR, T, ALLOCATOR> &str) { |
679
|
return assign(str.data(), str.length() * sizeof(CHAR)); |
680
|
} |
681
|
inline slice &assign(const char *c_str); |
682
|
#if defined(DOXYGEN) || \ |
683
|
(defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L) |
684
|
template <class CHAR, class T> |
685
|
slice &assign(const ::std::basic_string_view<CHAR, T> &view) { |
686
|
return assign(view.begin(), view.end()); |
687
|
} |
688
|
template <class CHAR, class T> |
689
|
slice &assign(::std::basic_string_view<CHAR, T> &&view) { |
690
|
assign(view); |
691
|
view = {}; |
692
|
return *this; |
693
|
} |
694
|
#endif |
695
|
|
696
|
slice &operator=(const slice &) noexcept = default; |
697
|
inline slice &operator=(slice &&src) noexcept; |
698
|
inline slice &operator=(::MDBX_val &&src); |
699
|
|
700
|
#if defined(DOXYGEN) || \ |
701
|
(defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L) |
702
|
template <class CHAR, class T> |
703
|
slice &operator=(const ::std::basic_string_view<CHAR, T> &view) { |
704
|
return assign(view); |
705
|
} |
706
|
|
707
|
template <class CHAR, class T> |
708
|
slice &operator=(::std::basic_string_view<CHAR, T> &&view) { |
709
|
return assign(view); |
710
|
} |
711
|
|
712
|
|
713
|
template <class CHAR = char, class T = ::std::char_traits<CHAR>> |
714
|
MDBX_CXX11_CONSTEXPR ::std::basic_string_view<CHAR, T> |
715
|
string_view() const noexcept { |
716
|
static_assert(sizeof(CHAR) == 1, "Must be single byte characters"); |
717
|
return ::std::basic_string_view<CHAR, T>(char_ptr(), length()); |
718
|
} |
719
|
|
720
|
|
721
|
template <class CHAR, class T> |
722
|
MDBX_CXX11_CONSTEXPR explicit |
723
|
operator ::std::basic_string_view<CHAR, T>() const noexcept { |
724
|
return this->string_view<CHAR, T>(); |
725
|
} |
726
|
#endif |
727
|
|
728
|
template <class CHAR = char, class T = ::std::char_traits<CHAR>, |
729
|
class ALLOCATOR = legacy_allocator> |
730
|
MDBX_CXX20_CONSTEXPR ::std::basic_string<CHAR, T, ALLOCATOR> |
731
|
as_string(const ALLOCATOR &allocator = ALLOCATOR()) const { |
732
|
static_assert(sizeof(CHAR) == 1, "Must be single byte characters"); |
733
|
return ::std::basic_string<CHAR, T, ALLOCATOR>(char_ptr(), length(), |
734
|
allocator); |
735
|
} |
736
|
|
737
|
template <class CHAR, class T, class ALLOCATOR> |
738
|
MDBX_CXX20_CONSTEXPR explicit |
739
|
operator ::std::basic_string<CHAR, T, ALLOCATOR>() const { |
740
|
return as_string<CHAR, T, ALLOCATOR>(); |
741
|
} |
742
|
|
743
|
|
744
|
template <class ALLOCATOR = legacy_allocator> |
745
|
inline string<ALLOCATOR> |
746
|
as_hex_string(bool uppercase = false, unsigned wrap_width = 0, |
747
|
const ALLOCATOR &allocator = ALLOCATOR()) const; |
748
|
|
749
|
|
750
|
|
751
|
template <class ALLOCATOR = legacy_allocator> |
752
|
inline string<ALLOCATOR> |
753
|
as_base58_string(unsigned wrap_width = 0, |
754
|
const ALLOCATOR &allocator = ALLOCATOR()) const; |
755
|
|
756
|
|
757
|
|
758
|
template <class ALLOCATOR = legacy_allocator> |
759
|
inline string<ALLOCATOR> |
760
|
as_base64_string(unsigned wrap_width = 0, |
761
|
const ALLOCATOR &allocator = ALLOCATOR()) const; |
762
|
|
763
|
|
764
|
template <class ALLOCATOR = legacy_allocator, |
765
|
class CAPACITY_POLICY = default_capacity_policy> |
766
|
inline buffer<ALLOCATOR, CAPACITY_POLICY> |
767
|
encode_hex(bool uppercase = false, unsigned wrap_width = 0, |
768
|
const ALLOCATOR &allocator = ALLOCATOR()) const; |
769
|
|
770
|
|
771
|
|
772
|
template <class ALLOCATOR = legacy_allocator, |
773
|
class CAPACITY_POLICY = default_capacity_policy> |
774
|
inline buffer<ALLOCATOR, CAPACITY_POLICY> |
775
|
encode_base58(unsigned wrap_width = 0, |
776
|
const ALLOCATOR &allocator = ALLOCATOR()) const; |
777
|
|
778
|
|
779
|
|
780
|
template <class ALLOCATOR = legacy_allocator, |
781
|
class CAPACITY_POLICY = default_capacity_policy> |
782
|
inline buffer<ALLOCATOR, CAPACITY_POLICY> |
783
|
encode_base64(unsigned wrap_width = 0, |
784
|
const ALLOCATOR &allocator = ALLOCATOR()) const; |
785
|
|
786
|
|
787
|
template <class ALLOCATOR = legacy_allocator, |
788
|
class CAPACITY_POLICY = default_capacity_policy> |
789
|
inline buffer<ALLOCATOR, CAPACITY_POLICY> |
790
|
hex_decode(bool ignore_spaces = false, |
791
|
const ALLOCATOR &allocator = ALLOCATOR()) const; |
792
|
|
793
|
/// \brief Decodes [Base58](https://en.wikipedia.org/wiki/Base58) dump |
794
|
|
795
|
template <class ALLOCATOR = legacy_allocator, |
796
|
class CAPACITY_POLICY = default_capacity_policy> |
797
|
inline buffer<ALLOCATOR, CAPACITY_POLICY> |
798
|
base58_decode(bool ignore_spaces = false, |
799
|
const ALLOCATOR &allocator = ALLOCATOR()) const; |
800
|
|
801
|
/// \brief Decodes [Base64](https://en.wikipedia.org/wiki/Base64) dump |
802
|
|
803
|
template <class ALLOCATOR = legacy_allocator, |
804
|
class CAPACITY_POLICY = default_capacity_policy> |
805
|
inline buffer<ALLOCATOR, CAPACITY_POLICY> |
806
|
base64_decode(bool ignore_spaces = false, |
807
|
const ALLOCATOR &allocator = ALLOCATOR()) const; |
808
|
|
809
|
|
810
|
/// \param [in] disable_utf8 By default if `disable_utf8` is `false` function |
811
|
|
812
|
/// sequences. Otherwise, if if `disable_utf8` is `true` function checks that |
813
|
|
814
|
MDBX_NOTHROW_PURE_FUNCTION bool |
815
|
is_printable(bool disable_utf8 = false) const noexcept; |
816
|
|
817
|
|
818
|
/// \param [in] ignore_spaces If `true` function will skips spaces surrounding |
819
|
|
820
|
|
821
|
inline MDBX_NOTHROW_PURE_FUNCTION bool |
822
|
is_hex(bool ignore_spaces = false) const noexcept; |
823
|
|
824
|
|
825
|
/// [Base58](https://en.wikipedia.org/wiki/Base58) dump. |
826
|
/// \param [in] ignore_spaces If `true` function will skips spaces surrounding |
827
|
|
828
|
|
829
|
inline MDBX_NOTHROW_PURE_FUNCTION bool |
830
|
is_base58(bool ignore_spaces = false) const noexcept; |
831
|
|
832
|
|
833
|
/// [Base64](https://en.wikipedia.org/wiki/Base64) dump. |
834
|
/// \param [in] ignore_spaces If `true` function will skips spaces surrounding |
835
|
|
836
|
|
837
|
inline MDBX_NOTHROW_PURE_FUNCTION bool |
838
|
is_base64(bool ignore_spaces = false) const noexcept; |
839
|
|
840
|
inline void swap(slice &other) noexcept; |
841
|
|
842
|
#if defined(DOXYGEN) || \ |
843
|
(defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L) |
844
|
template <class CHAR, class T> |
845
|
void swap(::std::basic_string_view<CHAR, T> &view) noexcept { |
846
|
static_assert(sizeof(CHAR) == 1, "Must be single byte characters"); |
847
|
const auto temp = ::std::basic_string_view<CHAR, T>(*this); |
848
|
*this = view; |
849
|
view = temp; |
850
|
} |
851
|
#endif |
852
|
|
853
|
|
854
|
MDBX_CXX11_CONSTEXPR const byte *byte_ptr() const noexcept; |
855
|
MDBX_CXX11_CONSTEXPR byte *byte_ptr() noexcept; |
856
|
|
857
|
|
858
|
MDBX_CXX11_CONSTEXPR const byte *end_byte_ptr() const noexcept; |
859
|
MDBX_CXX11_CONSTEXPR byte *end_byte_ptr() noexcept; |
860
|
|
861
|
|
862
|
MDBX_CXX11_CONSTEXPR const char *char_ptr() const noexcept; |
863
|
MDBX_CXX11_CONSTEXPR char *char_ptr() noexcept; |
864
|
|
865
|
|
866
|
MDBX_CXX11_CONSTEXPR const char *end_char_ptr() const noexcept; |
867
|
MDBX_CXX11_CONSTEXPR char *end_char_ptr() noexcept; |
868
|
|
869
|
|
870
|
MDBX_CXX11_CONSTEXPR const void *data() const noexcept; |
871
|
MDBX_CXX11_CONSTEXPR void *data() noexcept; |
872
|
|
873
|
|
874
|
MDBX_CXX11_CONSTEXPR const void *end() const noexcept; |
875
|
MDBX_CXX11_CONSTEXPR void *end() noexcept; |
876
|
|
877
|
|
878
|
MDBX_CXX11_CONSTEXPR size_t length() const noexcept; |
879
|
|
880
|
|
881
|
MDBX_CXX14_CONSTEXPR slice &set_length(size_t bytes); |
882
|
|
883
|
|
884
|
MDBX_CXX14_CONSTEXPR slice &set_end(const void *ptr); |
885
|
|
886
|
|
887
|
MDBX_CXX11_CONSTEXPR bool empty() const noexcept; |
888
|
|
889
|
|
890
|
MDBX_CXX11_CONSTEXPR bool is_null() const noexcept; |
891
|
|
892
|
|
893
|
MDBX_CXX11_CONSTEXPR size_t size() const noexcept; |
894
|
|
895
|
/// \brief Returns true if slice is not empty. |
896
|
MDBX_CXX11_CONSTEXPR operator bool() const noexcept; |
897
|
|
898
|
/// \brief Depletes content of slice and make it invalid. |
899
|
MDBX_CXX14_CONSTEXPR void invalidate() noexcept; |
900
|
|
901
|
|
902
|
MDBX_CXX14_CONSTEXPR void clear() noexcept; |
903
|
|
904
|
|
905
|
/// \pre REQUIRES: `n <= size()` |
906
|
inline void remove_prefix(size_t n) noexcept; |
907
|
|
908
|
|
909
|
/// \pre REQUIRES: `n <= size()` |
910
|
inline void remove_suffix(size_t n) noexcept; |
911
|
|
912
|
|
913
|
/// \throws std::out_of_range if `n > size()` |
914
|
inline void safe_remove_prefix(size_t n); |
915
|
|
916
|
|
917
|
/// \throws std::out_of_range if `n > size()` |
918
|
inline void safe_remove_suffix(size_t n); |
919
|
|
920
|
|
921
|
MDBX_NOTHROW_PURE_FUNCTION MDBX_CXX14_CONSTEXPR bool |
922
|
starts_with(const slice &prefix) const noexcept; |
923
|
|
924
|
|
925
|
MDBX_NOTHROW_PURE_FUNCTION MDBX_CXX14_CONSTEXPR bool |
926
|
ends_with(const slice &suffix) const noexcept; |
927
|
|
928
|
|
929
|
/// \pre REQUIRES: `n < size()` |
930
|
MDBX_CXX11_CONSTEXPR byte operator[](size_t n) const noexcept; |
931
|
|
932
|
|
933
|
/// \throws std::out_of_range if `n >= size()` |
934
|
MDBX_CXX11_CONSTEXPR byte at(size_t n) const; |
935
|
|
936
|
|
937
|
/// \pre REQUIRES: `n <= size()` |
938
|
MDBX_CXX14_CONSTEXPR slice head(size_t n) const noexcept; |
939
|
|
940
|
|
941
|
/// \pre REQUIRES: `n <= size()` |
942
|
MDBX_CXX14_CONSTEXPR slice tail(size_t n) const noexcept; |
943
|
|
944
|
|
945
|
/// \pre REQUIRES: `from + n <= size()` |
946
|
MDBX_CXX14_CONSTEXPR slice middle(size_t from, size_t n) const noexcept; |
947
|
|
948
|
|
949
|
/// \throws std::out_of_range if `n >= size()` |
950
|
MDBX_CXX14_CONSTEXPR slice safe_head(size_t n) const; |
951
|
|
952
|
|
953
|
/// \throws std::out_of_range if `n >= size()` |
954
|
MDBX_CXX14_CONSTEXPR slice safe_tail(size_t n) const; |
955
|
|
956
|
|
957
|
/// \throws std::out_of_range if `from + n >= size()` |
958
|
MDBX_CXX14_CONSTEXPR slice safe_middle(size_t from, size_t n) const; |
959
|
|
960
|
|
961
|
/// \attention Function implementation and returned hash values may changed |
962
|
|
963
|
/// values obtained from this function shouldn't be persisted anywhere. |
964
|
MDBX_NOTHROW_PURE_FUNCTION MDBX_CXX14_CONSTEXPR size_t |
965
|
hash_value() const noexcept; |
966
|
|
967
|
|
968
|
/// \details Firstly compares length and if it equal then compare content |
969
|
/// lexicographically. \return value: |
970
|
/// `== 0` if `a` the same as `b`; |
971
|
/// `< 0` if `a` shorter than `b`, |
972
|
/// or the same length and lexicographically less than `b`; |
973
|
/// `> 0` if `a` longer than `b`, |
974
|
/// or the same length and lexicographically great than `b`. |
975
|
MDBX_NOTHROW_PURE_FUNCTION static MDBX_CXX14_CONSTEXPR intptr_t |
976
|
compare_fast(const slice &a, const slice &b) noexcept; |
977
|
|
978
|
|
979
|
/// \return value: |
980
|
/// `== 0` if `a` lexicographically equal `b`; |
981
|
/// `< 0` if `a` lexicographically less than `b`; |
982
|
/// `> 0` if `a` lexicographically great than `b`. |
983
|
MDBX_NOTHROW_PURE_FUNCTION static MDBX_CXX14_CONSTEXPR intptr_t |
984
|
compare_lexicographically(const slice &a, const slice &b) noexcept; |
985
|
friend MDBX_CXX14_CONSTEXPR bool operator==(const slice &a, |
986
|
const slice &b) noexcept; |
987
|
friend MDBX_CXX14_CONSTEXPR bool operator<(const slice &a, |
988
|
const slice &b) noexcept; |
989
|
friend MDBX_CXX14_CONSTEXPR bool operator>(const slice &a, |
990
|
const slice &b) noexcept; |
991
|
friend MDBX_CXX14_CONSTEXPR bool operator<=(const slice &a, |
992
|
const slice &b) noexcept; |
993
|
friend MDBX_CXX14_CONSTEXPR bool operator>=(const slice &a, |
994
|
const slice &b) noexcept; |
995
|
friend MDBX_CXX14_CONSTEXPR bool operator!=(const slice &a, |
996
|
const slice &b) noexcept; |
997
|
|
998
|
/// \brief Checks the slice is not refers to null address or has zero length. |
999
|
MDBX_CXX11_CONSTEXPR bool is_valid() const noexcept { |
1,000
|
return !(iov_base == nullptr && iov_len != 0); |
1,001
|
} |
1,002
|
|
1,003
|
|
1,004
|
|
1,005
|
MDBX_CXX14_CONSTEXPR static slice invalid() noexcept { |
1,006
|
return slice(size_t(-1)); |
1,007
|
} |
1,008
|
|
1,009
|
protected: |
1,010
|
MDBX_CXX11_CONSTEXPR slice(size_t invalid_length) noexcept |
1,011
|
: ::MDBX_val({nullptr, invalid_length}) {} |
1,012
|
}; |
1,013
|
|
1,014
|
|
1,015
|
|
1,016
|
namespace allocation_aware_details { |
1,017
|
|
1,018
|
template <typename A> constexpr bool allocator_is_always_equal() noexcept { |
1,019
|
#if defined(__cpp_lib_allocator_traits_is_always_equal) && \ |
1,020
|
__cpp_lib_allocator_traits_is_always_equal >= 201411L |
1,021
|
return ::std::allocator_traits<A>::is_always_equal::value; |
1,022
|
#else |
1,023
|
return ::std::is_empty<A>::value; |
1,024
|
#endif |
1,025
|
} |
1,026
|
|
1,027
|
template <typename T, typename A = typename T::allocator_type, |
1,028
|
bool PoCMA = ::std::allocator_traits< |
1,029
|
A>::propagate_on_container_move_assignment::value> |
1,030
|
struct move_assign_alloc; |
1,031
|
|
1,032
|
template <typename T, typename A> struct move_assign_alloc<T, A, false> { |
1,033
|
static constexpr bool is_nothrow() noexcept { |
1,034
|
return allocator_is_always_equal<A>(); |
1,035
|
} |
1,036
|
static MDBX_CXX20_CONSTEXPR bool is_moveable(T *target, T &source) noexcept { |
1,037
|
return allocator_is_always_equal<A>() || |
1,038
|
target->get_allocator() == source.get_allocator(); |
1,039
|
} |
1,040
|
static MDBX_CXX20_CONSTEXPR void propagate(T *target, T &source) noexcept { |
1,041
|
assert(target->get_allocator() != source.get_allocator()); |
1,042
|
(void)target; |
1,043
|
(void)source; |
1,044
|
} |
1,045
|
}; |
1,046
|
|
1,047
|
template <typename T, typename A> struct move_assign_alloc<T, A, true> { |
1,048
|
static constexpr bool is_nothrow() noexcept { |
1,049
|
return allocator_is_always_equal<A>() || |
1,050
|
::std::is_nothrow_move_assignable<A>::value; |
1,051
|
} |
1,052
|
static constexpr bool is_moveable(T *, T &) noexcept { return true; } |
1,053
|
static MDBX_CXX20_CONSTEXPR void propagate(T *target, T &source) { |
1,054
|
assert(target->get_allocator() != source.get_allocator()); |
1,055
|
target->get_allocator() = ::std::move(source.get_allocator()); |
1,056
|
} |
1,057
|
}; |
1,058
|
|
1,059
|
template <typename T, typename A = typename T::allocator_type, |
1,060
|
bool PoCCA = ::std::allocator_traits< |
1,061
|
A>::propagate_on_container_copy_assignment::value> |
1,062
|
struct copy_assign_alloc; |
1,063
|
|
1,064
|
template <typename T, typename A> struct copy_assign_alloc<T, A, false> { |
1,065
|
static constexpr bool is_nothrow() noexcept { return false; } |
1,066
|
static MDBX_CXX20_CONSTEXPR void propagate(T *target, |
1,067
|
const T &source) noexcept { |
1,068
|
assert(target->get_allocator() != source.get_allocator()); |
1,069
|
(void)target; |
1,070
|
(void)source; |
1,071
|
} |
1,072
|
}; |
1,073
|
|
1,074
|
template <typename T, typename A> struct copy_assign_alloc<T, A, true> { |
1,075
|
static constexpr bool is_nothrow() noexcept { |
1,076
|
return allocator_is_always_equal<A>() || |
1,077
|
::std::is_nothrow_copy_assignable<A>::value; |
1,078
|
} |
1,079
|
static MDBX_CXX20_CONSTEXPR void |
1,080
|
propagate(T *target, const T &source) noexcept(is_nothrow()) { |
1,081
|
if MDBX_IF_CONSTEXPR (!allocator_is_always_equal<A>()) { |
1,082
|
if (MDBX_UNLIKELY(target->get_allocator() != source.get_allocator())) |
1,083
|
MDBX_CXX20_UNLIKELY target->get_allocator() = |
1,084
|
::std::allocator_traits<A>::select_on_container_copy_construction( |
1,085
|
source.get_allocator()); |
1,086
|
} else { |
1,087
|
/* gag for buggy compilers */ |
1,088
|
(void)target; |
1,089
|
(void)source; |
1,090
|
} |
1,091
|
} |
1,092
|
}; |
1,093
|
|
1,094
|
template <typename T, typename A = typename T::allocator_type, |
1,095
|
bool PoCS = |
1,096
|
::std::allocator_traits<A>::propagate_on_container_swap::value> |
1,097
|
struct swap_alloc; |
1,098
|
|
1,099
|
template <typename T, typename A> struct swap_alloc<T, A, false> { |
1,100
|
static constexpr bool is_nothrow() noexcept { |
1,101
|
return allocator_is_always_equal<A>(); |
1,102
|
} |
1,103
|
static MDBX_CXX20_CONSTEXPR void propagate(T *target, |
1,104
|
T &source) noexcept(is_nothrow()) { |
1,105
|
if MDBX_IF_CONSTEXPR (!allocator_is_always_equal<A>()) { |
1,106
|
if (MDBX_UNLIKELY(target->get_allocator() != source.get_allocator())) |
1,107
|
MDBX_CXX20_UNLIKELY throw_allocators_mismatch(); |
1,108
|
} else { |
1,109
|
/* gag for buggy compilers */ |
1,110
|
(void)target; |
1,111
|
(void)source; |
1,112
|
} |
1,113
|
} |
1,114
|
}; |
1,115
|
|
1,116
|
template <typename T, typename A> struct swap_alloc<T, A, true> { |
1,117
|
static constexpr bool is_nothrow() noexcept { |
1,118
|
return allocator_is_always_equal<A>() || |
1,119
|
#if defined(__cpp_lib_is_swappable) && __cpp_lib_is_swappable >= 201603L |
1,120
|
::std::is_nothrow_swappable<A>() || |
1,121
|
#endif |
1,122
|
(::std::is_nothrow_move_constructible<A>::value && |
1,123
|
::std::is_nothrow_move_assignable<A>::value); |
1,124
|
} |
1,125
|
static MDBX_CXX20_CONSTEXPR void propagate(T *target, |
1,126
|
T &source) noexcept(is_nothrow()) { |
1,127
|
if MDBX_IF_CONSTEXPR (!allocator_is_always_equal<A>()) { |
1,128
|
if (MDBX_UNLIKELY(target->get_allocator() != source.get_allocator())) |
1,129
|
MDBX_CXX20_UNLIKELY ::std::swap(*target, source); |
1,130
|
} else { |
1,131
|
/* gag for buggy compilers */ |
1,132
|
(void)target; |
1,133
|
(void)source; |
1,134
|
} |
1,135
|
} |
1,136
|
}; |
1,137
|
|
1,138
|
} |
1,139
|
|
1,140
|
struct default_capacity_policy { |
1,141
|
enum : size_t { |
1,142
|
extra_inplace_storage = 0, |
1,143
|
pettiness_threshold = 64, |
1,144
|
max_reserve = 65536 |
1,145
|
}; |
1,146
|
|
1,147
|
static MDBX_CXX11_CONSTEXPR size_t round(const size_t value) { |
1,148
|
static_assert((pettiness_threshold & (pettiness_threshold - 1)) == 0, |
1,149
|
"pettiness_threshold must be a power of 2"); |
1,150
|
static_assert(pettiness_threshold % 2 == 0, |
1,151
|
"pettiness_threshold must be even"); |
1,152
|
static_assert(pettiness_threshold >= sizeof(uint64_t), |
1,153
|
"pettiness_threshold must be > 7"); |
1,154
|
constexpr const auto pettiness_mask = ~size_t(pettiness_threshold - 1); |
1,155
|
return (value + pettiness_threshold - 1) & pettiness_mask; |
1,156
|
} |
1,157
|
|
1,158
|
static MDBX_CXX11_CONSTEXPR size_t advise(const size_t current, |
1,159
|
const size_t wanna) { |
1,160
|
static_assert(max_reserve % pettiness_threshold == 0, |
1,161
|
"max_reserve must be a multiple of pettiness_threshold"); |
1,162
|
static_assert(max_reserve / 3 > pettiness_threshold, |
1,163
|
"max_reserve must be > pettiness_threshold * 3"); |
1,164
|
if (wanna > current) |
1,165
|
|
1,166
|
return round(wanna + ::std::min(size_t(max_reserve), current)); |
1,167
|
|
1,168
|
if (current - wanna > |
1,169
|
|
1,170
|
* but not less than pettiness_threshold */ |
1,171
|
::std::min(wanna + pettiness_threshold, size_t(max_reserve))) |
1,172
|
return round(wanna); |
1,173
|
|
1,174
|
|
1,175
|
return current; |
1,176
|
} |
1,177
|
}; |
1,178
|
|
1,179
|
/// \brief Hexadecimal encoder which satisfy \ref SliceTranscoder concept. |
1,180
|
struct LIBMDBX_API to_hex { |
1,181
|
const slice source; |
1,182
|
const bool uppercase = false; |
1,183
|
const unsigned wrap_width = 0; |
1,184
|
MDBX_CXX11_CONSTEXPR to_hex(const slice &source, bool uppercase = false, |
1,185
|
unsigned wrap_width = 0) noexcept |
1,186
|
: source(source), uppercase(uppercase), wrap_width(wrap_width) { |
1,187
|
MDBX_ASSERT_CXX20_CONCEPT_SATISFIED(SliceTranscoder, to_hex); |
1,188
|
} |
1,189
|
|
1,190
|
|
1,191
|
template <class ALLOCATOR = legacy_allocator> |
1,192
|
string<ALLOCATOR> as_string(const ALLOCATOR &allocator = ALLOCATOR()) const { |
1,193
|
return make_string<ALLOCATOR>(*this, allocator); |
1,194
|
} |
1,195
|
|
1,196
|
|
1,197
|
template <class ALLOCATOR = legacy_allocator, |
1,198
|
typename CAPACITY_POLICY = default_capacity_policy> |
1,199
|
buffer<ALLOCATOR, CAPACITY_POLICY> |
1,200
|
as_buffer(const ALLOCATOR &allocator = ALLOCATOR()) const { |
1,201
|
return make_buffer<ALLOCATOR>(*this, allocator); |
1,202
|
} |
1,203
|
|
1,204
|
/// \brief Returns the buffer size in bytes needed for hexadecimal |
1,205
|
|
1,206
|
MDBX_CXX11_CONSTEXPR size_t envisage_result_length() const noexcept { |
1,207
|
const size_t bytes = source.length() << 1; |
1,208
|
return wrap_width ? bytes + bytes / wrap_width : bytes; |
1,209
|
} |
1,210
|
|
1,211
|
|
1,212
|
/// \throws std::length_error if given buffer is too small. |
1,213
|
char *write_bytes(char *dest, size_t dest_size) const; |
1,214
|
|
1,215
|
|
1,216
|
/// \throws std::ios_base::failure corresponding to std::ostream::write() |
1,217
|
|
1,218
|
::std::ostream &output(::std::ostream &out) const; |
1,219
|
|
1,220
|
|
1,221
|
|
1,222
|
bool is_empty() const noexcept { return source.empty(); } |
1,223
|
|
1,224
|
|
1,225
|
/// and could be encoded or unexpectedly not. |
1,226
|
bool is_erroneous() const noexcept { return false; } |
1,227
|
}; |
1,228
|
|
1,229
|
/// \brief [Base58](https://en.wikipedia.org/wiki/Base58) encoder which satisfy |
1,230
|
|
1,231
|
struct LIBMDBX_API to_base58 { |
1,232
|
const slice source; |
1,233
|
const unsigned wrap_width = 0; |
1,234
|
MDBX_CXX11_CONSTEXPR |
1,235
|
to_base58(const slice &source, unsigned wrap_width = 0) noexcept |
1,236
|
: source(source), wrap_width(wrap_width) { |
1,237
|
MDBX_ASSERT_CXX20_CONCEPT_SATISFIED(SliceTranscoder, to_base58); |
1,238
|
} |
1,239
|
|
1,240
|
|
1,241
|
|
1,242
|
template <class ALLOCATOR = legacy_allocator> |
1,243
|
string<ALLOCATOR> as_string(const ALLOCATOR &allocator = ALLOCATOR()) const { |
1,244
|
return make_string<ALLOCATOR>(*this, allocator); |
1,245
|
} |
1,246
|
|
1,247
|
|
1,248
|
|
1,249
|
template <class ALLOCATOR = legacy_allocator, |
1,250
|
typename CAPACITY_POLICY = default_capacity_policy> |
1,251
|
buffer<ALLOCATOR, CAPACITY_POLICY> |
1,252
|
as_buffer(const ALLOCATOR &allocator = ALLOCATOR()) const { |
1,253
|
return make_buffer<ALLOCATOR>(*this, allocator); |
1,254
|
} |
1,255
|
|
1,256
|
/// \brief Returns the buffer size in bytes needed for |
1,257
|
/// [Base58](https://en.wikipedia.org/wiki/Base58) dump of passed slice. |
1,258
|
MDBX_CXX11_CONSTEXPR size_t envisage_result_length() const noexcept { |
1,259
|
const size_t bytes = |
1,260
|
source.length() / 8 * 11 + (source.length() % 8 * 43 + 31) / 32; |
1,261
|
return wrap_width ? bytes + bytes / wrap_width : bytes; |
1,262
|
} |
1,263
|
|
1,264
|
|
1,265
|
|
1,266
|
/// \throws std::length_error if given buffer is too small. |
1,267
|
char *write_bytes(char *dest, size_t dest_size) const; |
1,268
|
|
1,269
|
/// \brief Output [Base58](https://en.wikipedia.org/wiki/Base58) |
1,270
|
|
1,271
|
/// \throws std::ios_base::failure corresponding to std::ostream::write() |
1,272
|
|
1,273
|
::std::ostream &output(::std::ostream &out) const; |
1,274
|
|
1,275
|
|
1,276
|
|
1,277
|
bool is_empty() const noexcept { return source.empty(); } |
1,278
|
|
1,279
|
|
1,280
|
/// and could be encoded or unexpectedly not. |
1,281
|
bool is_erroneous() const noexcept { return false; } |
1,282
|
}; |
1,283
|
|
1,284
|
/// \brief [Base64](https://en.wikipedia.org/wiki/Base64) encoder which satisfy |
1,285
|
|
1,286
|
struct LIBMDBX_API to_base64 { |
1,287
|
const slice source; |
1,288
|
const unsigned wrap_width = 0; |
1,289
|
MDBX_CXX11_CONSTEXPR |
1,290
|
to_base64(const slice &source, unsigned wrap_width = 0) noexcept |
1,291
|
: source(source), wrap_width(wrap_width) { |
1,292
|
MDBX_ASSERT_CXX20_CONCEPT_SATISFIED(SliceTranscoder, to_base64); |
1,293
|
} |
1,294
|
|
1,295
|
|
1,296
|
|
1,297
|
template <class ALLOCATOR = legacy_allocator> |
1,298
|
string<ALLOCATOR> as_string(const ALLOCATOR &allocator = ALLOCATOR()) const { |
1,299
|
return make_string<ALLOCATOR>(*this, allocator); |
1,300
|
} |
1,301
|
|
1,302
|
|
1,303
|
|
1,304
|
template <class ALLOCATOR = legacy_allocator, |
1,305
|
typename CAPACITY_POLICY = default_capacity_policy> |
1,306
|
buffer<ALLOCATOR, CAPACITY_POLICY> |
1,307
|
as_buffer(const ALLOCATOR &allocator = ALLOCATOR()) const { |
1,308
|
return make_buffer<ALLOCATOR>(*this, allocator); |
1,309
|
} |
1,310
|
|
1,311
|
/// \brief Returns the buffer size in bytes needed for |
1,312
|
/// [Base64](https://en.wikipedia.org/wiki/Base64) dump of passed slice. |
1,313
|
MDBX_CXX11_CONSTEXPR size_t envisage_result_length() const noexcept { |
1,314
|
const size_t bytes = (source.length() + 2) / 3 * 4; |
1,315
|
return wrap_width ? bytes + bytes / wrap_width : bytes; |
1,316
|
} |
1,317
|
|
1,318
|
|
1,319
|
|
1,320
|
/// \throws std::length_error if given buffer is too small. |
1,321
|
char *write_bytes(char *dest, size_t dest_size) const; |
1,322
|
|
1,323
|
/// \brief Output [Base64](https://en.wikipedia.org/wiki/Base64) |
1,324
|
|
1,325
|
/// \throws std::ios_base::failure corresponding to std::ostream::write() |
1,326
|
|
1,327
|
::std::ostream &output(::std::ostream &out) const; |
1,328
|
|
1,329
|
|
1,330
|
|
1,331
|
bool is_empty() const noexcept { return source.empty(); } |
1,332
|
|
1,333
|
|
1,334
|
/// and could be encoded or unexpectedly not. |
1,335
|
bool is_erroneous() const noexcept { return false; } |
1,336
|
}; |
1,337
|
|
1,338
|
inline ::std::ostream &operator<<(::std::ostream &out, const to_hex &wrapper) { |
1,339
|
return wrapper.output(out); |
1,340
|
} |
1,341
|
inline ::std::ostream &operator<<(::std::ostream &out, |
1,342
|
const to_base58 &wrapper) { |
1,343
|
return wrapper.output(out); |
1,344
|
} |
1,345
|
inline ::std::ostream &operator<<(::std::ostream &out, |
1,346
|
const to_base64 &wrapper) { |
1,347
|
return wrapper.output(out); |
1,348
|
} |
1,349
|
|
1,350
|
/// \brief Hexadecimal decoder which satisfy \ref SliceTranscoder concept. |
1,351
|
struct LIBMDBX_API from_hex { |
1,352
|
const slice source; |
1,353
|
const bool ignore_spaces = false; |
1,354
|
MDBX_CXX11_CONSTEXPR from_hex(const slice &source, |
1,355
|
bool ignore_spaces = false) noexcept |
1,356
|
: source(source), ignore_spaces(ignore_spaces) { |
1,357
|
MDBX_ASSERT_CXX20_CONCEPT_SATISFIED(SliceTranscoder, from_hex); |
1,358
|
} |
1,359
|
|
1,360
|
|
1,361
|
template <class ALLOCATOR = legacy_allocator> |
1,362
|
string<ALLOCATOR> as_string(const ALLOCATOR &allocator = ALLOCATOR()) const { |
1,363
|
return make_string<ALLOCATOR>(*this, allocator); |
1,364
|
} |
1,365
|
|
1,366
|
|
1,367
|
template <class ALLOCATOR = legacy_allocator, |
1,368
|
typename CAPACITY_POLICY = default_capacity_policy> |
1,369
|
buffer<ALLOCATOR, CAPACITY_POLICY> |
1,370
|
as_buffer(const ALLOCATOR &allocator = ALLOCATOR()) const { |
1,371
|
return make_buffer<ALLOCATOR>(*this, allocator); |
1,372
|
} |
1,373
|
|
1,374
|
|
1,375
|
|
1,376
|
MDBX_CXX11_CONSTEXPR size_t envisage_result_length() const noexcept { |
1,377
|
return source.length() >> 1; |
1,378
|
} |
1,379
|
|
1,380
|
|
1,381
|
|
1,382
|
/// \throws std::length_error if given buffer is too small. |
1,383
|
char *write_bytes(char *dest, size_t dest_size) const; |
1,384
|
|
1,385
|
|
1,386
|
|
1,387
|
bool is_empty() const noexcept { return source.empty(); } |
1,388
|
|
1,389
|
|
1,390
|
/// dump, and therefore there could be decoded or not. |
1,391
|
bool is_erroneous() const noexcept; |
1,392
|
}; |
1,393
|
|
1,394
|
/// \brief [Base58](https://en.wikipedia.org/wiki/Base58) decoder which satisfy |
1,395
|
|
1,396
|
struct LIBMDBX_API from_base58 { |
1,397
|
const slice source; |
1,398
|
const bool ignore_spaces = false; |
1,399
|
MDBX_CXX11_CONSTEXPR from_base58(const slice &source, |
1,400
|
bool ignore_spaces = false) noexcept |
1,401
|
: source(source), ignore_spaces(ignore_spaces) { |
1,402
|
MDBX_ASSERT_CXX20_CONCEPT_SATISFIED(SliceTranscoder, from_base58); |
1,403
|
} |
1,404
|
|
1,405
|
|
1,406
|
|
1,407
|
template <class ALLOCATOR = legacy_allocator> |
1,408
|
string<ALLOCATOR> as_string(const ALLOCATOR &allocator = ALLOCATOR()) const { |
1,409
|
return make_string<ALLOCATOR>(*this, allocator); |
1,410
|
} |
1,411
|
|
1,412
|
|
1,413
|
|
1,414
|
template <class ALLOCATOR = legacy_allocator, |
1,415
|
typename CAPACITY_POLICY = default_capacity_policy> |
1,416
|
buffer<ALLOCATOR, CAPACITY_POLICY> |
1,417
|
as_buffer(const ALLOCATOR &allocator = ALLOCATOR()) const { |
1,418
|
return make_buffer<ALLOCATOR>(*this, allocator); |
1,419
|
} |
1,420
|
|
1,421
|
|
1,422
|
|
1,423
|
|
1,424
|
MDBX_CXX11_CONSTEXPR size_t envisage_result_length() const noexcept { |
1,425
|
return source.length() / 11 * 8 + source.length() % 11 * 32 / 43; |
1,426
|
} |
1,427
|
|
1,428
|
|
1,429
|
|
1,430
|
/// \throws std::length_error if given buffer is too small. |
1,431
|
char *write_bytes(char *dest, size_t dest_size) const; |
1,432
|
|
1,433
|
|
1,434
|
|
1,435
|
bool is_empty() const noexcept { return source.empty(); } |
1,436
|
|
1,437
|
|
1,438
|
/// [Base58](https://en.wikipedia.org/wiki/Base58) dump, and therefore there |
1,439
|
/// could be decoded or not. |
1,440
|
bool is_erroneous() const noexcept; |
1,441
|
}; |
1,442
|
|
1,443
|
/// \brief [Base64](https://en.wikipedia.org/wiki/Base64) decoder which satisfy |
1,444
|
|
1,445
|
struct LIBMDBX_API from_base64 { |
1,446
|
const slice source; |
1,447
|
const bool ignore_spaces = false; |
1,448
|
MDBX_CXX11_CONSTEXPR from_base64(const slice &source, |
1,449
|
bool ignore_spaces = false) noexcept |
1,450
|
: source(source), ignore_spaces(ignore_spaces) { |
1,451
|
MDBX_ASSERT_CXX20_CONCEPT_SATISFIED(SliceTranscoder, from_base64); |
1,452
|
} |
1,453
|
|
1,454
|
|
1,455
|
|
1,456
|
template <class ALLOCATOR = legacy_allocator> |
1,457
|
string<ALLOCATOR> as_string(const ALLOCATOR &allocator = ALLOCATOR()) const { |
1,458
|
return make_string<ALLOCATOR>(*this, allocator); |
1,459
|
} |
1,460
|
|
1,461
|
|
1,462
|
|
1,463
|
template <class ALLOCATOR = legacy_allocator, |
1,464
|
typename CAPACITY_POLICY = default_capacity_policy> |
1,465
|
buffer<ALLOCATOR, CAPACITY_POLICY> |
1,466
|
as_buffer(const ALLOCATOR &allocator = ALLOCATOR()) const { |
1,467
|
return make_buffer<ALLOCATOR>(*this, allocator); |
1,468
|
} |
1,469
|
|
1,470
|
|
1,471
|
|
1,472
|
|
1,473
|
MDBX_CXX11_CONSTEXPR size_t envisage_result_length() const noexcept { |
1,474
|
return (source.length() + 3) / 4 * 3; |
1,475
|
} |
1,476
|
|
1,477
|
|
1,478
|
|
1,479
|
/// \throws std::length_error if given buffer is too small. |
1,480
|
char *write_bytes(char *dest, size_t dest_size) const; |
1,481
|
|
1,482
|
|
1,483
|
|
1,484
|
bool is_empty() const noexcept { return source.empty(); } |
1,485
|
|
1,486
|
|
1,487
|
/// [Base64](https://en.wikipedia.org/wiki/Base64) dump, and therefore there |
1,488
|
/// could be decoded or not. |
1,489
|
bool is_erroneous() const noexcept; |
1,490
|
}; |
1,491
|
|
1,492
|
|
1,493
|
template <class ALLOCATOR, typename CAPACITY_POLICY> class buffer { |
1,494
|
public: |
1,495
|
#if !defined(_MSC_VER) || _MSC_VER > 1900 |
1,496
|
using allocator_type = typename ::std::allocator_traits< |
1,497
|
ALLOCATOR>::template rebind_alloc<uint64_t>; |
1,498
|
#else |
1,499
|
using allocator_type = typename ALLOCATOR::template rebind<uint64_t>::other; |
1,500
|
#endif |
1,501
|
using allocator_traits = ::std::allocator_traits<allocator_type>; |
1,502
|
using reservation_policy = CAPACITY_POLICY; |
1,503
|
enum : size_t { |
1,504
|
max_length = MDBX_MAXDATASIZE, |
1,505
|
max_capacity = (max_length / 3u * 4u + 1023u) & ~size_t(1023), |
1,506
|
extra_inplace_storage = reservation_policy::extra_inplace_storage, |
1,507
|
pettiness_threshold = reservation_policy::pettiness_threshold |
1,508
|
}; |
1,509
|
|
1,510
|
private: |
1,511
|
friend class txn; |
1,512
|
struct silo; |
1,513
|
using move_assign_alloc = |
1,514
|
allocation_aware_details::move_assign_alloc<silo, allocator_type>; |
1,515
|
using copy_assign_alloc = |
1,516
|
allocation_aware_details::copy_assign_alloc<silo, allocator_type>; |
1,517
|
using swap_alloc = allocation_aware_details::swap_alloc<silo, allocator_type>; |
1,518
|
struct silo /* Empty Base Class Optimization */ : public allocator_type { |
1,519
|
MDBX_CXX20_CONSTEXPR const allocator_type &get_allocator() const noexcept { |
1,520
|
return *this; |
1,521
|
} |
1,522
|
MDBX_CXX20_CONSTEXPR allocator_type &get_allocator() noexcept { |
1,523
|
return *this; |
1,524
|
} |
1,525
|
|
1,526
|
using allocator_pointer = typename allocator_traits::pointer; |
1,527
|
using allocator_const_pointer = typename allocator_traits::const_pointer; |
1,528
|
|
1,529
|
MDBX_CXX20_CONSTEXPR ::std::pair<allocator_pointer, size_t> |
1,530
|
allocate_storage(size_t bytes) { |
1,531
|
assert(bytes >= sizeof(bin)); |
1,532
|
constexpr size_t unit = sizeof(typename allocator_type::value_type); |
1,533
|
static_assert((unit & (unit - 1)) == 0, |
1,534
|
"size of ALLOCATOR::value_type should be a power of 2"); |
1,535
|
static_assert(unit > 0, "size of ALLOCATOR::value_type must be > 0"); |
1,536
|
const size_t n = (bytes + unit - 1) / unit; |
1,537
|
return ::std::make_pair(allocator_traits::allocate(get_allocator(), n), |
1,538
|
n * unit); |
1,539
|
} |
1,540
|
MDBX_CXX20_CONSTEXPR void deallocate_storage(allocator_pointer ptr, |
1,541
|
size_t bytes) { |
1,542
|
constexpr size_t unit = sizeof(typename allocator_type::value_type); |
1,543
|
assert(ptr && bytes >= sizeof(bin) && bytes >= unit && bytes % unit == 0); |
1,544
|
allocator_traits::deallocate(get_allocator(), ptr, bytes / unit); |
1,545
|
} |
1,546
|
|
1,547
|
static MDBX_CXX17_CONSTEXPR void * |
1,548
|
to_address(allocator_pointer ptr) noexcept { |
1,549
|
#if defined(__cpp_lib_to_address) && __cpp_lib_to_address >= 201711L |
1,550
|
return static_cast<void *>(::std::to_address(ptr)); |
1,551
|
#else |
1,552
|
return static_cast<void *>(::std::addressof(*ptr)); |
1,553
|
#endif |
1,554
|
} |
1,555
|
static MDBX_CXX17_CONSTEXPR const void * |
1,556
|
to_address(allocator_const_pointer ptr) noexcept { |
1,557
|
#if defined(__cpp_lib_to_address) && __cpp_lib_to_address >= 201711L |
1,558
|
return static_cast<const void *>(::std::to_address(ptr)); |
1,559
|
#else |
1,560
|
return static_cast<const void *>(::std::addressof(*ptr)); |
1,561
|
#endif |
1,562
|
} |
1,563
|
|
1,564
|
union bin { |
1,565
|
struct allocated { |
1,566
|
allocator_pointer ptr_; |
1,567
|
size_t capacity_bytes_; |
1,568
|
constexpr allocated(allocator_pointer ptr, size_t bytes) noexcept |
1,569
|
: ptr_(ptr), capacity_bytes_(bytes) {} |
1,570
|
constexpr allocated(const allocated &) noexcept = default; |
1,571
|
constexpr allocated(allocated &&) noexcept = default; |
1,572
|
MDBX_CXX17_CONSTEXPR allocated & |
1,573
|
operator=(const allocated &) noexcept = default; |
1,574
|
MDBX_CXX17_CONSTEXPR allocated & |
1,575
|
operator=(allocated &&) noexcept = default; |
1,576
|
}; |
1,577
|
|
1,578
|
allocated allocated_; |
1,579
|
uint64_t align_hint_; |
1,580
|
byte inplace_[(sizeof(allocated) + extra_inplace_storage + 7u) & |
1,581
|
~size_t(7)]; |
1,582
|
|
1,583
|
static constexpr bool |
1,584
|
is_suitable_for_inplace(size_t capacity_bytes) noexcept { |
1,585
|
static_assert(sizeof(bin) == sizeof(inplace_), "WTF?"); |
1,586
|
return capacity_bytes < sizeof(bin); |
1,587
|
} |
1,588
|
|
1,589
|
enum : byte { |
1,590
|
/* Little Endian: |
1,591
|
* last byte is the most significant byte of u_.allocated.cap, |
1,592
|
* so use higher bit of capacity as the inplace-flag */ |
1,593
|
le_lastbyte_mask = 0x80, |
1,594
|
/* Big Endian: |
1,595
|
* last byte is the least significant byte of u_.allocated.cap, |
1,596
|
* so use lower bit of capacity as the inplace-flag. */ |
1,597
|
be_lastbyte_mask = 0x01 |
1,598
|
}; |
1,599
|
|
1,600
|
static constexpr byte inplace_lastbyte_mask() noexcept { |
1,601
|
static_assert( |
1,602
|
endian::native == endian::little || endian::native == endian::big, |
1,603
|
"Only the little-endian or big-endian bytes order are supported"); |
1,604
|
return (endian::native == endian::little) ? le_lastbyte_mask |
1,605
|
: be_lastbyte_mask; |
1,606
|
} |
1,607
|
constexpr byte lastbyte() const noexcept { |
1,608
|
return inplace_[sizeof(bin) - 1]; |
1,609
|
} |
1,610
|
MDBX_CXX17_CONSTEXPR byte &lastbyte() noexcept { |
1,611
|
return inplace_[sizeof(bin) - 1]; |
1,612
|
} |
1,613
|
|
1,614
|
constexpr bool is_inplace() const noexcept { |
1,615
|
return (lastbyte() & inplace_lastbyte_mask()) != 0; |
1,616
|
} |
1,617
|
constexpr bool is_allocated() const noexcept { return !is_inplace(); } |
1,618
|
|
1,619
|
template <bool destroy_ptr> |
1,620
|
MDBX_CXX17_CONSTEXPR byte *make_inplace() noexcept { |
1,621
|
if (destroy_ptr) { |
1,622
|
MDBX_CONSTEXPR_ASSERT(is_allocated()); |
1,623
|
|
1,624
|
allocated_.~allocated(); |
1,625
|
} |
1,626
|
if (::std::is_trivial<allocator_pointer>::value) |
1,627
|
/* workaround for "uninitialized" warning from some compilers */ |
1,628
|
::std::memset(&allocated_.ptr_, 0, sizeof(allocated_.ptr_)); |
1,629
|
lastbyte() = inplace_lastbyte_mask(); |
1,630
|
MDBX_CONSTEXPR_ASSERT(is_inplace() && address() == inplace_ && |
1,631
|
is_suitable_for_inplace(capacity())); |
1,632
|
return address(); |
1,633
|
} |
1,634
|
|
1,635
|
template <bool construct_ptr> |
1,636
|
MDBX_CXX17_CONSTEXPR byte * |
1,637
|
make_allocated(allocator_pointer ptr, size_t capacity_bytes) noexcept { |
1,638
|
MDBX_CONSTEXPR_ASSERT( |
1,639
|
(capacity_bytes & be_lastbyte_mask) == 0 && |
1,640
|
((capacity_bytes >> |
1,641
|
(sizeof(allocated_.capacity_bytes_) - 1) * CHAR_BIT) & |
1,642
|
le_lastbyte_mask) == 0); |
1,643
|
if (construct_ptr) |
1,644
|
|
1,645
|
new (&allocated_) allocated(ptr, capacity_bytes); |
1,646
|
else { |
1,647
|
MDBX_CONSTEXPR_ASSERT(is_allocated()); |
1,648
|
allocated_.ptr_ = ptr; |
1,649
|
allocated_.capacity_bytes_ = capacity_bytes; |
1,650
|
} |
1,651
|
MDBX_CONSTEXPR_ASSERT(is_allocated() && address() == to_address(ptr) && |
1,652
|
capacity() == capacity_bytes); |
1,653
|
return address(); |
1,654
|
} |
1,655
|
|
1,656
|
MDBX_CXX20_CONSTEXPR bin(size_t capacity_bytes = 0) noexcept { |
1,657
|
MDBX_CONSTEXPR_ASSERT(is_suitable_for_inplace(capacity_bytes)); |
1,658
|
make_inplace<false>(); |
1,659
|
(void)capacity_bytes; |
1,660
|
} |
1,661
|
MDBX_CXX20_CONSTEXPR bin(allocator_pointer ptr, |
1,662
|
size_t capacity_bytes) noexcept { |
1,663
|
MDBX_CONSTEXPR_ASSERT(!is_suitable_for_inplace(capacity_bytes)); |
1,664
|
make_allocated<true>(ptr, capacity_bytes); |
1,665
|
} |
1,666
|
MDBX_CXX20_CONSTEXPR ~bin() { |
1,667
|
if (is_allocated()) |
1,668
|
|
1,669
|
allocated_.~allocated(); |
1,670
|
} |
1,671
|
MDBX_CXX20_CONSTEXPR bin(bin &&ditto) noexcept { |
1,672
|
if (ditto.is_inplace()) { |
1,673
|
|
1,674
|
|
1,675
|
memcpy(inplace_, ditto.inplace_, sizeof(inplace_)); |
1,676
|
MDBX_CONSTEXPR_ASSERT(is_inplace()); |
1,677
|
} else { |
1,678
|
new (&allocated_) allocated(::std::move(ditto.allocated_)); |
1,679
|
ditto.make_inplace<true>(); |
1,680
|
MDBX_CONSTEXPR_ASSERT(is_allocated()); |
1,681
|
} |
1,682
|
} |
1,683
|
|
1,684
|
MDBX_CXX17_CONSTEXPR bin &operator=(const bin &ditto) noexcept { |
1,685
|
if (ditto.is_inplace()) { |
1,686
|
|
1,687
|
|
1,688
|
if (is_allocated()) |
1,689
|
|
1,690
|
allocated_.~allocated(); |
1,691
|
memcpy(inplace_, ditto.inplace_, sizeof(inplace_)); |
1,692
|
MDBX_CONSTEXPR_ASSERT(is_inplace()); |
1,693
|
} else if (is_inplace()) |
1,694
|
make_allocated<true>(ditto.allocated_.ptr_, |
1,695
|
ditto.allocated_.capacity_bytes_); |
1,696
|
else |
1,697
|
make_allocated<false>(ditto.allocated_.ptr_, |
1,698
|
ditto.allocated_.capacity_bytes_); |
1,699
|
return *this; |
1,700
|
} |
1,701
|
|
1,702
|
MDBX_CXX17_CONSTEXPR bin &operator=(bin &&ditto) noexcept { |
1,703
|
operator=(const_cast<const bin &>(ditto)); |
1,704
|
if (ditto.is_allocated()) |
1,705
|
ditto.make_inplace<true>(); |
1,706
|
return *this; |
1,707
|
} |
1,708
|
|
1,709
|
static MDBX_CXX20_CONSTEXPR size_t advise_capacity(const size_t current, |
1,710
|
const size_t wanna) { |
1,711
|
if (MDBX_UNLIKELY(wanna > max_capacity)) |
1,712
|
MDBX_CXX20_UNLIKELY throw_max_length_exceeded(); |
1,713
|
|
1,714
|
const size_t advised = reservation_policy::advise(current, wanna); |
1,715
|
assert(advised >= wanna); |
1,716
|
return ::std::min(size_t(max_capacity), |
1,717
|
::std::max(sizeof(bin) - 1, advised)); |
1,718
|
} |
1,719
|
|
1,720
|
constexpr const byte *address() const noexcept { |
1,721
|
return is_inplace() |
1,722
|
? inplace_ |
1,723
|
: static_cast<const byte *>(to_address(allocated_.ptr_)); |
1,724
|
} |
1,725
|
MDBX_CXX17_CONSTEXPR byte *address() noexcept { |
1,726
|
return is_inplace() ? inplace_ |
1,727
|
: static_cast<byte *>(to_address(allocated_.ptr_)); |
1,728
|
} |
1,729
|
constexpr size_t capacity() const noexcept { |
1,730
|
return is_inplace() ? sizeof(bin) - 1 : allocated_.capacity_bytes_; |
1,731
|
} |
1,732
|
} bin_; |
1,733
|
|
1,734
|
MDBX_CXX20_CONSTEXPR void *init(size_t capacity) { |
1,735
|
capacity = bin::advise_capacity(0, capacity); |
1,736
|
if (bin_.is_suitable_for_inplace(capacity)) |
1,737
|
new (&bin_) bin(); |
1,738
|
else { |
1,739
|
const auto pair = allocate_storage(capacity); |
1,740
|
assert(pair.second >= capacity); |
1,741
|
new (&bin_) bin(pair.first, pair.second); |
1,742
|
} |
1,743
|
return bin_.address(); |
1,744
|
} |
1,745
|
|
1,746
|
MDBX_CXX20_CONSTEXPR void release() noexcept { |
1,747
|
if (bin_.is_allocated()) { |
1,748
|
deallocate_storage(bin_.allocated_.ptr_, |
1,749
|
bin_.allocated_.capacity_bytes_); |
1,750
|
bin_.template make_inplace<true>(); |
1,751
|
} |
1,752
|
} |
1,753
|
|
1,754
|
template <bool external_content> |
1,755
|