mdbx++: Add support for C++17 polymorphic allocators.

Change-Id: I76054829551c247a4d8f81288fc47db47ead0288
This commit is contained in:
Leonid Yuriev 2020-08-24 11:20:41 +03:00
parent 08faeda430
commit aa7695c513
2 changed files with 901 additions and 667 deletions

1345
mdbx.h++

File diff suppressed because it is too large Load Diff

View File

@ -25,7 +25,6 @@
#include "internals.h"
#include <atomic>
#include <sstream>
#include <system_error>
#if defined(__has_include) && __has_include(<version>)
@ -150,10 +149,11 @@ __cold std::string format_va(const char *fmt, va_list ap) {
#endif
assert(needed >= 0);
std::string result;
result.reserve((size_t)needed + 1);
result.resize((size_t)needed, '\0');
assert((int)result.capacity() > needed);
int actual = vsnprintf((char *)result.data(), result.capacity(), fmt, ones);
result.reserve(size_t(needed + 1));
result.resize(size_t(needed), '\0');
assert(int(result.capacity()) > needed);
int actual = vsnprintf(const_cast<char *>(result.data()), result.capacity(),
fmt, ones);
assert(actual == needed);
(void)actual;
va_end(ones);
@ -275,6 +275,10 @@ namespace mdbx {
"mdbx:: exceeded the maximal length of data/slice/buffer");
}
[[noreturn]] __cold void throw_too_small_target_buffer() {
throw std::length_error("mdbx:: the target buffer is too small");
}
__cold exception::exception(const error &error) noexcept
: base(error.what()), error_(error) {}
@ -430,6 +434,61 @@ __cold void error::throw_exception() const {
//------------------------------------------------------------------------------
char *slice::to_hex(char *dst, size_t dst_size, bool uppercase) const {
if (mdbx_unlikely((dst_size >> 1) < length()))
throw_too_small_target_buffer();
auto src = byte_ptr();
const auto end = src + length();
const char x0A = (uppercase ? 'A' : 'a') - 10;
while (src != end) {
const char high = *src >> 4;
const char low = *src & 15;
dst[0] = (high < 10) ? high + '0' : high + x0A;
dst[1] = (low < 10) ? low + '0' : low + x0A;
src += 1;
dst += 2;
}
return dst;
}
char *slice::from_hex(char *dest, size_t dest_size) const {
if (length() % 2)
throw std::invalid_argument(
"mdbx::from_hex:: odd length of hexadecimal string");
(void)dest;
(void)dest_size;
NOT_IMPLEMENTED();
return nullptr;
}
char *slice::to_base58(char *dest, size_t dest_size) const {
(void)dest;
(void)dest_size;
NOT_IMPLEMENTED();
return nullptr;
}
char *slice::from_base58(char *dest, size_t dest_size) const {
(void)dest;
(void)dest_size;
NOT_IMPLEMENTED();
return nullptr;
}
char *slice::to_base64(char *dest, size_t dest_size) const {
(void)dest;
(void)dest_size;
NOT_IMPLEMENTED();
return nullptr;
}
char *slice::from_base64(char *dest, size_t dest_size) const {
(void)dest;
(void)dest_size;
NOT_IMPLEMENTED();
return nullptr;
}
bool slice::is_base64() const noexcept {
NOT_IMPLEMENTED();
return true;
@ -445,149 +504,13 @@ bool slice::is_printable(bool allow_utf8) const noexcept {
return allow_utf8;
}
std::string slice::hex_string(bool uppercase) const {
std::string result;
if (length() > 0) {
result.reserve(length() * 2);
const uint8_t *ptr = static_cast<const uint8_t *>(data());
const uint8_t *const end = ptr + length();
const char x0A = (uppercase ? 'A' : 'a') - 10;
do {
char high = *ptr >> 4;
char low = *ptr & 15;
result.push_back((high < 10) ? high + '0' : high + x0A);
result.push_back((low < 10) ? low + '0' : low + x0A);
} while (++ptr < end);
}
return result;
}
std::string slice::base64_string() const {
std::string result;
NOT_IMPLEMENTED();
return result;
}
//------------------------------------------------------------------------------
void buffer::reserve(size_t head_room, size_t tail_room) {
if (unlikely(head_room > max_length || tail_room > max_length ||
head_room + tail_room > max_length - slice_.length()))
throw_max_length_exceeded();
template class LIBMDBX_API_TYPE buffer<default_allocator>;
const size_t whole = head_room + slice_.length() + tail_room;
if (whole == 0)
silo_.clear();
else if (is_reference() || slice_.empty()) {
silo_.reserve(whole);
silo_.append(head_room, '\0');
silo_.append(slice_.char_ptr(), slice_.length());
} else {
std::string buffer;
buffer.reserve(whole);
buffer.append(head_room, '\0');
buffer.append(slice_.char_ptr(), slice_.length());
silo_.assign(std::move(buffer));
}
slice_.iov_base = const_cast<char *>(silo_.data());
}
void buffer::insulate() {
assert(is_reference());
silo_.assign(slice_.char_ptr(), slice_.length());
slice_.iov_base = const_cast<char *>(silo_.data());
}
buffer &buffer::assign_reference(const void *ptr, size_t bytes) noexcept {
silo_.clear();
slice_.assign(ptr, bytes);
return *this;
}
buffer &buffer::assign_freestanding(const void *ptr, size_t bytes) {
silo_.assign(static_cast<const char *>(ptr), check_length(bytes));
slice_.assign(silo_);
return *this;
}
void buffer::clear() noexcept {
slice_.reset();
silo_.clear();
}
void buffer::shrink_to_fit() {
if (silo_.capacity() != length()) {
if (silo_.length() != length())
silo_.assign(char_ptr(), length());
silo_.shrink_to_fit();
slice_.assign(silo_);
}
}
void buffer::shrink() {
if (silo_.length() != length()) {
silo_.assign(char_ptr(), length());
slice_.assign(silo_);
}
}
int buffer::thunk::cb_copy(void *context, MDBX_val *target, const void *src,
size_t bytes) noexcept {
thunk *self = static_cast<thunk *>(context);
assert(self->is_clean());
try {
owner_of(static_cast<slice *>(target), &buffer::slice_)
->assign(src, bytes, false);
return MDBX_RESULT_FALSE;
} catch (... /* capture any exception to rethrow it over C code */) {
self->capture();
return MDBX_RESULT_TRUE;
}
}
buffer::buffer(size_t head_room, size_t tail_room) {
if (unlikely(head_room > max_length || tail_room > max_length ||
head_room + tail_room > max_length))
throw_max_length_exceeded();
silo_.reserve(head_room + tail_room);
silo_.append(head_room, '\0');
slice_.iov_base = const_cast<char *>(silo_.data());
assert(slice_.iov_len == 0);
}
buffer::buffer(size_t head_room, const slice &src, size_t tail_room) {
if (unlikely(head_room > max_length || tail_room > max_length ||
head_room + tail_room > max_length - slice_.length()))
throw_max_length_exceeded();
silo_.reserve(head_room + src.length() + tail_room);
silo_.append(head_room, '\0');
silo_.append(src.char_ptr(), src.length());
slice_.iov_base = const_cast<char *>(silo_.data());
slice_.iov_len = src.length();
}
buffer::buffer(size_t capacity) {
silo_.reserve(check_length(capacity));
slice_.iov_base = const_cast<char *>(silo_.data());
assert(slice_.iov_len == 0);
}
buffer::buffer(const txn_ref &txn, const slice &src)
: buffer(src, !txn.is_dirty(src.data())) {}
buffer buffer::decode_hex(const slice &hex) {
if (hex.length() % 2)
throw std::invalid_argument("odd length of hexadecimal string");
buffer result(hex.length() / 2);
NOT_IMPLEMENTED();
return result;
}
buffer buffer::decode_base64(const slice &base64) {
buffer result(base64.length() * 4 / 3);
NOT_IMPLEMENTED();
return result;
}
#if defined(__cpp_lib_memory_resource) && __cpp_lib_memory_resource >= 201603L
template class LIBMDBX_API_TYPE buffer<polymorphic_allocator>;
#endif /* __cpp_lib_memory_resource >= 201603L */
//------------------------------------------------------------------------------
@ -858,10 +781,6 @@ __cold ::std::ostream &operator<<(::std::ostream &, const pair &) {
NOT_IMPLEMENTED();
}
__cold ::std::ostream &operator<<(::std::ostream &, const buffer &) {
NOT_IMPLEMENTED();
}
__cold ::std::ostream &operator<<(::std::ostream &, const env_ref::geometry &) {
NOT_IMPLEMENTED();
}
@ -954,12 +873,6 @@ __cold string to_string(const ::mdbx::pair &value) {
return out.str();
}
__cold string to_string(const ::mdbx::buffer &value) {
ostringstream out;
out << value;
return out.str();
}
__cold string to_string(const ::mdbx::env_ref::geometry &value) {
ostringstream out;
out << value;