libmdbx/src/mdbx.c++

979 lines
27 KiB
C++
Raw Normal View History

/*
* Copyright 2020 Leonid Yuriev <leo@yuriev.ru>
* and other libmdbx authors: please see AUTHORS file.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted only as authorized by the OpenLDAP
* Public License.
*
* A copy of this license is available in the file LICENSE in the
* top-level directory of the distribution or, alternatively, at
* <http://www.OpenLDAP.org/license.html>. */
//
// Non-inline part of the libmdbx C++ API (preliminary draft)
//
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "../mdbx.h++"
#include "defs.h"
#include "internals.h"
#include <atomic>
#include <system_error>
#if defined(__has_include) && __has_include(<version>)
#include <version>
#endif
#if defined(__cpp_lib_filesystem) && __cpp_lib_filesystem >= 201703L
#include <filesystem>
#endif /* __cpp_lib_filesystem >= 201703L */
namespace {
class trouble_location {
#ifndef TROUBLE_PROVIDE_LINENO
#define TROUBLE_PROVIDE_LINENO 1
#endif
#ifndef TROUBLE_PROVIDE_CONDITION
#define TROUBLE_PROVIDE_CONDITION 1
#endif
#ifndef TROUBLE_PROVIDE_FUNCTION
#define TROUBLE_PROVIDE_FUNCTION 1
#endif
#ifndef TROUBLE_PROVIDE_FILENAME
#define TROUBLE_PROVIDE_FILENAME 1
#endif
#if TROUBLE_PROVIDE_LINENO
const unsigned line_;
#endif
#if TROUBLE_PROVIDE_CONDITION
const char *const condition_;
#endif
#if TROUBLE_PROVIDE_FUNCTION
const char *const function_;
#endif
#if TROUBLE_PROVIDE_FILENAME
const char *const filename_;
#endif
public:
cxx11_constexpr trouble_location(unsigned line, const char *condition,
const char *function, const char *filename)
:
#if TROUBLE_PROVIDE_LINENO
line_(line)
#endif
#if TROUBLE_PROVIDE_CONDITION
,
condition_(condition)
#endif
#if TROUBLE_PROVIDE_FUNCTION
,
function_(function)
#endif
#if TROUBLE_PROVIDE_FILENAME
,
filename_(filename)
#endif
{
#if !TROUBLE_PROVIDE_LINENO
(void)line;
#endif
#if !TROUBLE_PROVIDE_CONDITION
(void)condition;
#endif
#if !TROUBLE_PROVIDE_FUNCTION
(void)function;
#endif
#if !TROUBLE_PROVIDE_FILENAME
(void)filename;
#endif
}
trouble_location(const trouble_location &&) = delete;
unsigned line() const {
#if TROUBLE_PROVIDE_LINENO
return line_;
#else
return 0;
#endif
}
const char *condition() const {
#if TROUBLE_PROVIDE_CONDITION
return condition_;
#else
return "";
#endif
}
const char *function() const {
#if TROUBLE_PROVIDE_FUNCTION
return function_;
#else
return "";
#endif
}
const char *filename() const {
#if TROUBLE_PROVIDE_FILENAME
return filename_;
#else
return "";
#endif
}
};
//------------------------------------------------------------------------------
__cold std::string format_va(const char *fmt, va_list ap) {
va_list ones;
va_copy(ones, ap);
#ifdef _MSC_VER
int needed = _vscprintf(fmt, ap);
#else
int needed = vsnprintf(nullptr, 0, fmt, 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(const_cast<char *>(result.data()), result.capacity(),
fmt, ones);
assert(actual == needed);
(void)actual;
va_end(ones);
return result;
}
__cold std::string format(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
std::string result = format_va(fmt, ap);
va_end(ap);
return result;
}
class bug : public std::runtime_error {
const trouble_location &location_;
public:
bug(const trouble_location &) noexcept;
/* temporary workaround for "private field 'FOO' is not used" from CLANG
* and for "function 'BAR' was declared but never referenced" fomr LCC. */
#ifndef __LCC__
const trouble_location &location() const noexcept { return location_; }
#endif
virtual ~bug() noexcept;
};
__cold bug::bug(const trouble_location &location) noexcept
: std::runtime_error(format("mdbx.bug: %s.%s at %s:%u", location.function(),
location.condition(), location.filename(),
location.line())),
location_(location) {}
__cold bug::~bug() noexcept {}
[[noreturn]] __cold void raise_bug(const trouble_location &what_and_where) {
throw bug(what_and_where);
}
#define RAISE_BUG(line, condition, function, file) \
do { \
static cxx11_constexpr_var trouble_location bug(line, condition, function, \
file); \
raise_bug(bug); \
} while (0)
#define ENSURE(condition) \
do \
if (unlikely(!(condition))) \
RAISE_BUG(__LINE__, #condition, __func__, __FILE__); \
while (0)
#define NOT_IMPLEMENTED() \
RAISE_BUG(__LINE__, "not_implemented", __func__, __FILE__);
//------------------------------------------------------------------------------
template <typename PATH> struct path_to_pchar {
const std::string str;
path_to_pchar(const PATH &path) : str(path.generic_string()) {}
operator const char *() const { return str.c_str(); }
};
template <typename PATH> PATH pchar_to_path(const char *c_str) {
return PATH(c_str);
}
template <> struct path_to_pchar<std::string> {
const char *const ptr;
path_to_pchar(const std::string &path) : ptr(path.c_str()) {}
operator const char *() const { return ptr; }
};
#if defined(_WIN32) || defined(_WIN64)
template <> struct path_to_pchar<std::wstring> {
std::string str;
path_to_pchar(const std::wstring &path) {
if (!path.empty()) {
const int chars =
WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, path.data(),
int(path.size()), nullptr, 0, nullptr, nullptr);
if (chars == 0)
mdbx::error::throw_exception(GetLastError());
str.append(chars, '\0');
WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, path.data(),
int(path.size()), const_cast<char *>(str.data()),
chars, nullptr, nullptr);
}
}
operator const char *() const { return str.c_str(); }
};
template <> std::wstring pchar_to_path<std::wstring>(const char *c_str) {
std::wstring wstr;
if (c_str && *c_str) {
const int chars = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, c_str,
int(strlen(c_str)), nullptr, 0);
if (chars == 0)
mdbx::error::throw_exception(GetLastError());
wstr.append(chars, '\0');
MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, c_str,
int(strlen(c_str)), const_cast<wchar_t *>(wstr.data()),
chars);
}
return wstr;
}
#endif /* Windows */
} // namespace
//------------------------------------------------------------------------------
namespace mdbx {
[[noreturn]] __cold void throw_max_length_exceeded() {
throw std::length_error(
"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) {}
__cold exception::~exception() noexcept {}
static std::atomic_int fatal_countdown;
__cold fatal::fatal(const error &error_) noexcept : error_(error_) {
++fatal_countdown;
}
__cold fatal::fatal(const fatal &src) noexcept : error_(src.error_) {
++fatal_countdown;
}
__cold fatal::fatal(fatal &&src) noexcept : error_(src.error_) {
++fatal_countdown;
}
__cold fatal::~fatal() noexcept {
if (--fatal_countdown == 0)
std::terminate();
}
__cold const char *fatal::what() const noexcept { return error_.what(); }
#define DEFINE_EXCEPTION(NAME) \
__cold NAME::NAME(const error &rc) : exception(rc) {} \
__cold NAME::~NAME() noexcept {}
DEFINE_EXCEPTION(bad_map_id)
DEFINE_EXCEPTION(bad_transaction)
DEFINE_EXCEPTION(bad_value_size)
DEFINE_EXCEPTION(db_corrupted)
DEFINE_EXCEPTION(db_full)
DEFINE_EXCEPTION(db_invalid)
DEFINE_EXCEPTION(db_too_large)
DEFINE_EXCEPTION(db_unable_extend)
DEFINE_EXCEPTION(db_version_mismatch)
DEFINE_EXCEPTION(db_wanna_write_for_recovery)
DEFINE_EXCEPTION(incompatible_operation)
DEFINE_EXCEPTION(internal_page_full)
DEFINE_EXCEPTION(internal_problem)
DEFINE_EXCEPTION(key_exists)
DEFINE_EXCEPTION(key_mismatch)
DEFINE_EXCEPTION(max_maps_reached)
DEFINE_EXCEPTION(max_readers_reached)
DEFINE_EXCEPTION(multivalue)
DEFINE_EXCEPTION(no_data)
DEFINE_EXCEPTION(not_found)
DEFINE_EXCEPTION(operation_not_permited)
DEFINE_EXCEPTION(permission_denied_or_not_writeable)
DEFINE_EXCEPTION(reader_slot_busy)
DEFINE_EXCEPTION(remote_media)
DEFINE_EXCEPTION(something_busy)
DEFINE_EXCEPTION(thread_mismatch)
DEFINE_EXCEPTION(transaction_full)
DEFINE_EXCEPTION(transaction_overlapping)
#undef DEFINE_EXCEPTION
__cold const char *error::what() const noexcept {
if (is_mdbx_error())
return mdbx_liberr2str(code());
switch (code()) {
#define ERROR_CASE(CODE) \
case CODE: \
return STRINGIFY(CODE)
ERROR_CASE(MDBX_ENODATA);
ERROR_CASE(MDBX_EINVAL);
ERROR_CASE(MDBX_EACCESS);
ERROR_CASE(MDBX_ENOMEM);
ERROR_CASE(MDBX_EROFS);
ERROR_CASE(MDBX_ENOSYS);
ERROR_CASE(MDBX_EIO);
ERROR_CASE(MDBX_EPERM);
ERROR_CASE(MDBX_EINTR);
ERROR_CASE(MDBX_ENOFILE);
ERROR_CASE(MDBX_EREMOTE);
#undef ERROR_CASE
default:
return "SYSTEM";
}
}
__cold std::string error::message() const {
char buf[1024];
const char *msg = ::mdbx_strerror_r(code(), buf, sizeof(buf));
return std::string(msg ? msg : "unknown");
}
[[noreturn]] __cold void error::panic(const char *context,
const char *func) const noexcept {
assert(code() != MDBX_SUCCESS);
::mdbx_panic("mdbx::%s.%s() failed: \"%s\" (%d)", context, func, what(),
code());
std::terminate();
}
__cold void error::throw_exception() const {
switch (code()) {
case MDBX_EINVAL:
throw std::invalid_argument("mdbx");
case MDBX_ENOMEM:
throw std::bad_alloc();
case MDBX_SUCCESS:
static_assert(MDBX_SUCCESS == MDBX_RESULT_FALSE, "WTF?");
throw std::logic_error("MDBX_SUCCESS (MDBX_RESULT_FALSE)");
case MDBX_RESULT_TRUE:
throw std::logic_error("MDBX_RESULT_TRUE");
#define CASE_EXCEPTION(NAME, CODE) \
case CODE: \
throw NAME(code())
CASE_EXCEPTION(bad_map_id, MDBX_BAD_DBI);
CASE_EXCEPTION(bad_transaction, MDBX_BAD_TXN);
CASE_EXCEPTION(bad_value_size, MDBX_BAD_VALSIZE);
CASE_EXCEPTION(db_corrupted, MDBX_CORRUPTED);
CASE_EXCEPTION(db_corrupted, MDBX_CURSOR_FULL); /* branch-pages loop */
CASE_EXCEPTION(db_corrupted, MDBX_PAGE_NOTFOUND);
CASE_EXCEPTION(db_full, MDBX_MAP_FULL);
CASE_EXCEPTION(db_invalid, MDBX_INVALID);
CASE_EXCEPTION(db_too_large, MDBX_TOO_LARGE);
CASE_EXCEPTION(db_unable_extend, MDBX_UNABLE_EXTEND_MAPSIZE);
CASE_EXCEPTION(db_version_mismatch, MDBX_VERSION_MISMATCH);
CASE_EXCEPTION(db_wanna_write_for_recovery, MDBX_WANNA_RECOVERY);
CASE_EXCEPTION(fatal, MDBX_EBADSIGN);
CASE_EXCEPTION(fatal, MDBX_PANIC);
CASE_EXCEPTION(incompatible_operation, MDBX_INCOMPATIBLE);
CASE_EXCEPTION(internal_page_full, MDBX_PAGE_FULL);
CASE_EXCEPTION(internal_problem, MDBX_PROBLEM);
CASE_EXCEPTION(key_mismatch, MDBX_EKEYMISMATCH);
CASE_EXCEPTION(max_maps_reached, MDBX_DBS_FULL);
CASE_EXCEPTION(max_readers_reached, MDBX_READERS_FULL);
CASE_EXCEPTION(multivalue, MDBX_EMULTIVAL);
CASE_EXCEPTION(no_data, MDBX_ENODATA);
CASE_EXCEPTION(not_found, MDBX_NOTFOUND);
CASE_EXCEPTION(operation_not_permited, MDBX_EPERM);
CASE_EXCEPTION(permission_denied_or_not_writeable, MDBX_EACCESS);
CASE_EXCEPTION(reader_slot_busy, MDBX_BAD_RSLOT);
CASE_EXCEPTION(remote_media, MDBX_EREMOTE);
CASE_EXCEPTION(something_busy, MDBX_BUSY);
CASE_EXCEPTION(thread_mismatch, MDBX_THREAD_MISMATCH);
CASE_EXCEPTION(transaction_full, MDBX_TXN_FULL);
CASE_EXCEPTION(transaction_overlapping, MDBX_TXN_OVERLAPPING);
#undef CASE_EXCEPTION
default:
if (is_mdbx_error())
throw exception(*this);
throw std::system_error(std::error_code(code(), std::system_category()));
}
}
//------------------------------------------------------------------------------
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;
}
bool slice::is_hex() const noexcept {
NOT_IMPLEMENTED();
return true;
}
bool slice::is_printable(bool allow_utf8) const noexcept {
NOT_IMPLEMENTED();
return allow_utf8;
}
//------------------------------------------------------------------------------
template class LIBMDBX_API_TYPE buffer<default_allocator>;
#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 */
//------------------------------------------------------------------------------
size_t env_ref::default_pagesize() noexcept { return ::mdbx_syspagesize(); }
static inline MDBX_env_flags_t mode2flags(env_ref::mode mode) {
switch (mode) {
default:
cxx20_attribute_unlikely throw std::invalid_argument("db::mode is invalid");
case env_ref::mode::readonly:
return MDBX_RDONLY;
case env_ref::mode::write_file_io:
return MDBX_ENV_DEFAULTS;
case env_ref::mode::write_mapped_io:
return MDBX_WRITEMAP;
}
}
__cold MDBX_env_flags_t env_ref::operate_parameters::make_flags(
bool accede, bool use_subdirectory) const {
MDBX_env_flags_t flags = mode2flags(mode);
if (accede)
flags |= MDBX_ACCEDE;
if (!use_subdirectory)
flags |= MDBX_NOSUBDIR;
if (options.exclusive)
flags |= MDBX_EXCLUSIVE;
if (options.orphan_read_transactions)
flags |= MDBX_NOTLS;
if (options.disable_readahead)
flags |= MDBX_NORDAHEAD;
if (options.disable_clear_memory)
flags |= MDBX_NOMEMINIT;
if (mode != readonly) {
if (options.nested_write_transactions)
flags &= ~MDBX_WRITEMAP;
if (reclaiming.coalesce)
flags |= MDBX_COALESCE;
if (reclaiming.lifo)
flags |= MDBX_LIFORECLAIM;
switch (durability) {
default:
cxx20_attribute_unlikely throw std::invalid_argument(
"db::durability is invalid");
case env_ref::durability::robust_synchronous:
break;
case env_ref::durability::half_synchronous_weak_last:
flags |= MDBX_NOMETASYNC;
break;
case env_ref::durability::lazy_weak_tail:
flags |= (flags & MDBX_WRITEMAP) ? MDBX_MAPASYNC : MDBX_SAFE_NOSYNC;
break;
case env_ref::durability::whole_fragile:
flags |= MDBX_UTTERLY_NOSYNC;
break;
}
}
return flags;
}
env_ref::mode
env_ref::operate_parameters::mode_from_flags(MDBX_env_flags_t) noexcept {
NOT_IMPLEMENTED();
}
env_ref::durability
env_ref::operate_parameters::durability_from_flags(MDBX_env_flags_t) noexcept {
NOT_IMPLEMENTED();
}
env_ref::reclaiming_options::reclaiming_options(MDBX_env_flags_t) noexcept {
NOT_IMPLEMENTED();
}
env_ref::operate_options::operate_options(MDBX_env_flags_t) noexcept {
NOT_IMPLEMENTED();
}
env_ref::operate_parameters::operate_parameters(const env_ref &) {
NOT_IMPLEMENTED();
}
bool env_ref::is_pristine() const {
return get_stat().ms_mod_txnid == 0 &&
get_info().mi_recent_txnid == INITIAL_TXNID;
}
bool env_ref::is_empty() const { return get_stat().ms_branch_pages == 0; }
env_ref &env_ref::copy(const path &destination, bool compactify,
bool force_dynamic_size) {
const path_to_pchar<path> utf8(destination);
error::success_or_throw(
::mdbx_env_copy(handle_, utf8,
(compactify ? MDBX_CP_COMPACT : MDBX_CP_DEFAULTS) |
(force_dynamic_size ? MDBX_CP_FORCE_DYNAMIC_SIZE
: MDBX_CP_DEFAULTS)));
return *this;
}
env_ref &env_ref::copy(filehandle fd, bool compactify,
bool force_dynamic_size) {
error::success_or_throw(
::mdbx_env_copy2fd(handle_, fd,
(compactify ? MDBX_CP_COMPACT : MDBX_CP_DEFAULTS) |
(force_dynamic_size ? MDBX_CP_FORCE_DYNAMIC_SIZE
: MDBX_CP_DEFAULTS)));
return *this;
}
path env_ref::get_path() const {
const char *c_str;
error::success_or_throw(::mdbx_env_get_path(handle_, &c_str));
return pchar_to_path<path>(c_str);
}
//------------------------------------------------------------------------------
static inline MDBX_env *create_env() {
MDBX_env *ptr;
error::success_or_throw(::mdbx_env_create(&ptr));
assert(ptr != nullptr);
return ptr;
}
env::~env() noexcept {
if (handle_)
error::success_or_panic(::mdbx_env_close(handle_), "mdbx::~env()",
"mdbx_env_close");
}
void env::close(bool dont_sync) {
const error rc =
static_cast<MDBX_error_t>(::mdbx_env_close_ex(handle_, dont_sync));
switch (rc.code()) {
case MDBX_EBADSIGN:
handle_ = nullptr;
__fallthrough /* fall through */;
default:
rc.throw_exception();
case MDBX_SUCCESS:
handle_ = nullptr;
}
}
__cold void env::setup(unsigned max_maps, unsigned max_readers) {
if (max_readers > 0)
error::success_or_throw(::mdbx_env_set_maxreaders(handle_, max_readers));
if (max_maps > 0)
error::success_or_throw(::mdbx_env_set_maxdbs(handle_, max_maps));
}
__cold env::env(const path &pathname, const operate_parameters &op, bool accede)
: env(create_env()) {
setup(op.max_maps, op.max_readers);
const path_to_pchar<path> utf8(pathname);
error::success_or_throw(
::mdbx_env_open(handle_, utf8, op.make_flags(accede), 0));
// if (po.options.nested_write_transactions && (flags() & MDBX_WRITEMAP))
// error::throw_exception(MDBX_INCOMPATIBLE);
}
__cold env::env(const path &pathname, const env_ref::create_parameters &cp,
const env_ref::operate_parameters &op, bool accede)
: env(create_env()) {
setup(op.max_maps, op.max_readers);
const path_to_pchar<path> utf8(pathname);
set_geometry(cp.geometry);
error::success_or_throw(
::mdbx_env_open(handle_, utf8, op.make_flags(accede, cp.use_subdirectory),
cp.file_mode_bits));
// if (po.options.nested_write_transactions && (flags() & MDBX_WRITEMAP))
// error::throw_exception(MDBX_INCOMPATIBLE);
}
//------------------------------------------------------------------------------
txn txn_ref::start_nested() {
MDBX_txn *nested;
error::throw_on_nullptr(handle_, MDBX_BAD_TXN);
error::success_or_throw(::mdbx_txn_begin(mdbx_txn_env(handle_), handle_,
MDBX_TXN_READWRITE, &nested));
assert(nested != nullptr);
return txn(nested);
}
txn::~txn() noexcept {
if (handle_)
error::success_or_panic(::mdbx_txn_abort(handle_), "mdbx::~txn",
"mdbx_txn_abort");
}
void txn::abort() {
const error err = static_cast<MDBX_error_t>(::mdbx_txn_abort(handle_));
if (unlikely(err.code() != MDBX_SUCCESS)) {
if (err.code() != MDBX_THREAD_MISMATCH)
handle_ = nullptr;
err.throw_exception();
}
}
void txn::commit() {
const error err = static_cast<MDBX_error_t>(::mdbx_txn_commit(handle_));
if (unlikely(err.code() != MDBX_SUCCESS)) {
if (err.code() != MDBX_THREAD_MISMATCH)
handle_ = nullptr;
err.throw_exception();
}
}
//------------------------------------------------------------------------------
bool txn_ref::drop_map(const char *name, bool ignore_nonexists) {
map_handle map;
const int err = ::mdbx_dbi_open(handle_, name, MDBX_DB_ACCEDE, &map.dbi);
switch (err) {
case MDBX_SUCCESS:
drop_map(map);
return true;
case MDBX_NOTFOUND:
case MDBX_BAD_DBI:
if (ignore_nonexists)
return false;
cxx17_attribute_fallthrough /* fallthrough */;
default:
cxx20_attribute_unlikely error::throw_exception(err);
}
}
bool txn_ref::clear_map(const char *name, bool ignore_nonexists) {
map_handle map;
const int err = ::mdbx_dbi_open(handle_, name, MDBX_DB_ACCEDE, &map.dbi);
switch (err) {
case MDBX_SUCCESS:
clear_map(map);
return true;
case MDBX_NOTFOUND:
case MDBX_BAD_DBI:
if (ignore_nonexists)
return false;
cxx17_attribute_fallthrough /* fallthrough */;
default:
cxx20_attribute_unlikely error::throw_exception(err);
}
}
//------------------------------------------------------------------------------
void cursor::close() {
if (mdbx_unlikely(!handle_))
error::throw_exception(MDBX_EINVAL);
::mdbx_cursor_close(handle_);
handle_ = nullptr;
}
cursor::~cursor() noexcept { ::mdbx_cursor_close(handle_); }
//------------------------------------------------------------------------------
__cold ::std::ostream &operator<<(::std::ostream &, const slice &) {
NOT_IMPLEMENTED();
}
__cold ::std::ostream &operator<<(::std::ostream &, const pair &) {
NOT_IMPLEMENTED();
}
__cold ::std::ostream &operator<<(::std::ostream &, const env_ref::geometry &) {
NOT_IMPLEMENTED();
}
__cold ::std::ostream &operator<<(::std::ostream &,
const env_ref::operate_parameters &) {
NOT_IMPLEMENTED();
}
__cold ::std::ostream &operator<<(::std::ostream &, const env_ref::mode &) {
NOT_IMPLEMENTED();
}
__cold ::std::ostream &operator<<(::std::ostream &,
const env_ref::durability &) {
NOT_IMPLEMENTED();
}
__cold ::std::ostream &operator<<(::std::ostream &,
const env_ref::reclaiming_options &) {
NOT_IMPLEMENTED();
}
__cold ::std::ostream &operator<<(::std::ostream &,
const env_ref::operate_options &) {
NOT_IMPLEMENTED();
}
__cold ::std::ostream &operator<<(::std::ostream &,
const env_ref::create_parameters &) {
NOT_IMPLEMENTED();
}
__cold ::std::ostream &operator<<(::std::ostream &, const MDBX_log_level_t &) {
NOT_IMPLEMENTED();
}
__cold ::std::ostream &operator<<(::std::ostream &,
const MDBX_debug_flags_t &) {
NOT_IMPLEMENTED();
}
__cold ::std::ostream &operator<<(::std::ostream &, const MDBX_error_t &) {
NOT_IMPLEMENTED();
}
__cold ::std::ostream &operator<<(::std::ostream &, const MDBX_env_flags_t &) {
NOT_IMPLEMENTED();
}
__cold ::std::ostream &operator<<(::std::ostream &, const MDBX_txn_flags_t &) {
NOT_IMPLEMENTED();
}
__cold ::std::ostream &operator<<(::std::ostream &, const MDBX_db_flags_t &) {
NOT_IMPLEMENTED();
}
__cold ::std::ostream &operator<<(::std::ostream &, const MDBX_put_flags_t &) {
NOT_IMPLEMENTED();
}
__cold ::std::ostream &operator<<(::std::ostream &, const MDBX_copy_flags_t &) {
NOT_IMPLEMENTED();
}
__cold ::std::ostream &operator<<(::std::ostream &, const MDBX_cursor_op &) {
NOT_IMPLEMENTED();
}
__cold ::std::ostream &operator<<(::std::ostream &, const MDBX_dbi_state_t &) {
NOT_IMPLEMENTED();
}
} // namespace mdbx
//------------------------------------------------------------------------------
namespace std {
__cold string to_string(const ::mdbx::slice &value) {
ostringstream out;
out << value;
return out.str();
}
__cold string to_string(const ::mdbx::pair &value) {
ostringstream out;
out << value;
return out.str();
}
__cold string to_string(const ::mdbx::env_ref::geometry &value) {
ostringstream out;
out << value;
return out.str();
}
__cold string to_string(const ::mdbx::env_ref::operate_parameters &value) {
ostringstream out;
out << value;
return out.str();
}
__cold string to_string(const ::mdbx::env_ref::mode &value) {
ostringstream out;
out << value;
return out.str();
}
__cold string to_string(const ::mdbx::env_ref::durability &value) {
ostringstream out;
out << value;
return out.str();
}
__cold string to_string(const ::mdbx::env_ref::reclaiming_options &value) {
ostringstream out;
out << value;
return out.str();
}
__cold string to_string(const ::mdbx::env_ref::operate_options &value) {
ostringstream out;
out << value;
return out.str();
}
__cold string to_string(const ::mdbx::env_ref::create_parameters &value) {
ostringstream out;
out << value;
return out.str();
}
__cold string to_string(const MDBX_log_level_t &value) {
ostringstream out;
out << value;
return out.str();
}
__cold string to_string(const MDBX_debug_flags_t &value) {
ostringstream out;
out << value;
return out.str();
}
__cold string to_string(const MDBX_error_t &value) {
ostringstream out;
out << value;
return out.str();
}
__cold string to_string(const MDBX_env_flags_t &value) {
ostringstream out;
out << value;
return out.str();
}
__cold string to_string(const MDBX_txn_flags_t &value) {
ostringstream out;
out << value;
return out.str();
}
__cold string to_string(const MDBX_db_flags_t &value) {
ostringstream out;
out << value;
return out.str();
}
__cold string to_string(const MDBX_put_flags_t &value) {
ostringstream out;
out << value;
return out.str();
}
__cold string to_string(const MDBX_copy_flags_t &value) {
ostringstream out;
out << value;
return out.str();
}
__cold string to_string(const MDBX_cursor_op &value) {
ostringstream out;
out << value;
return out.str();
}
__cold string to_string(const MDBX_dbi_state_t &value) {
ostringstream out;
out << value;
return out.str();
}
} // namespace std