mirror of
				https://github.com/isar/libmdbx.git
				synced 2025-10-31 15:38:57 +08:00 
			
		
		
		
	mdbx++: Add support for C++17 polymorphic allocators.
Change-Id: I76054829551c247a4d8f81288fc47db47ead0288
This commit is contained in:
		
							
								
								
									
										223
									
								
								src/mdbx.c++
									
									
									
									
									
								
							
							
						
						
									
										223
									
								
								src/mdbx.c++
									
									
									
									
									
								
							| @@ -25,7 +25,6 @@ | |||||||
| #include "internals.h" | #include "internals.h" | ||||||
|  |  | ||||||
| #include <atomic> | #include <atomic> | ||||||
| #include <sstream> |  | ||||||
| #include <system_error> | #include <system_error> | ||||||
|  |  | ||||||
| #if defined(__has_include) && __has_include(<version>) | #if defined(__has_include) && __has_include(<version>) | ||||||
| @@ -150,10 +149,11 @@ __cold std::string format_va(const char *fmt, va_list ap) { | |||||||
| #endif | #endif | ||||||
|   assert(needed >= 0); |   assert(needed >= 0); | ||||||
|   std::string result; |   std::string result; | ||||||
|   result.reserve((size_t)needed + 1); |   result.reserve(size_t(needed + 1)); | ||||||
|   result.resize((size_t)needed, '\0'); |   result.resize(size_t(needed), '\0'); | ||||||
|   assert((int)result.capacity() > needed); |   assert(int(result.capacity()) > needed); | ||||||
|   int actual = vsnprintf((char *)result.data(), result.capacity(), fmt, ones); |   int actual = vsnprintf(const_cast<char *>(result.data()), result.capacity(), | ||||||
|  |                          fmt, ones); | ||||||
|   assert(actual == needed); |   assert(actual == needed); | ||||||
|   (void)actual; |   (void)actual; | ||||||
|   va_end(ones); |   va_end(ones); | ||||||
| @@ -275,6 +275,10 @@ namespace mdbx { | |||||||
|       "mdbx:: exceeded the maximal length of data/slice/buffer"); |       "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 | __cold exception::exception(const error &error) noexcept | ||||||
|     : base(error.what()), error_(error) {} |     : 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 { | bool slice::is_base64() const noexcept { | ||||||
|   NOT_IMPLEMENTED(); |   NOT_IMPLEMENTED(); | ||||||
|   return true; |   return true; | ||||||
| @@ -445,149 +504,13 @@ bool slice::is_printable(bool allow_utf8) const noexcept { | |||||||
|   return allow_utf8; |   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) { | template class LIBMDBX_API_TYPE buffer<default_allocator>; | ||||||
|   if (unlikely(head_room > max_length || tail_room > max_length || |  | ||||||
|                head_room + tail_room > max_length - slice_.length())) |  | ||||||
|     throw_max_length_exceeded(); |  | ||||||
|  |  | ||||||
|   const size_t whole = head_room + slice_.length() + tail_room; | #if defined(__cpp_lib_memory_resource) && __cpp_lib_memory_resource >= 201603L | ||||||
|   if (whole == 0) | template class LIBMDBX_API_TYPE buffer<polymorphic_allocator>; | ||||||
|     silo_.clear(); | #endif /* __cpp_lib_memory_resource >= 201603L */ | ||||||
|   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; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| //------------------------------------------------------------------------------ | //------------------------------------------------------------------------------ | ||||||
|  |  | ||||||
| @@ -858,10 +781,6 @@ __cold ::std::ostream &operator<<(::std::ostream &, const pair &) { | |||||||
|   NOT_IMPLEMENTED(); |   NOT_IMPLEMENTED(); | ||||||
| } | } | ||||||
|  |  | ||||||
| __cold ::std::ostream &operator<<(::std::ostream &, const buffer &) { |  | ||||||
|   NOT_IMPLEMENTED(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| __cold ::std::ostream &operator<<(::std::ostream &, const env_ref::geometry &) { | __cold ::std::ostream &operator<<(::std::ostream &, const env_ref::geometry &) { | ||||||
|   NOT_IMPLEMENTED(); |   NOT_IMPLEMENTED(); | ||||||
| } | } | ||||||
| @@ -954,12 +873,6 @@ __cold string to_string(const ::mdbx::pair &value) { | |||||||
|   return out.str(); |   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) { | __cold string to_string(const ::mdbx::env_ref::geometry &value) { | ||||||
|   ostringstream out; |   ostringstream out; | ||||||
|   out << value; |   out << value; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user