You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1914 lines
46 KiB
C

/* This is free and unencumbered software released into the public domain. */
#ifndef LMDBXX_H
#define LMDBXX_H
/**
* <lmdb++.h> - C++11 wrapper for LMDB.
*
* @author Arto Bendiken <arto@bendiken.net>
* @see https://sourceforge.net/projects/lmdbxx/
*/
#ifndef __cplusplus
#error "<lmdb++.h> requires a C++ compiler"
#endif
#if __cplusplus < 201103L
#if !defined(_MSC_VER) || _MSC_VER < 1900
#error "<lmdb++.h> requires a C++11 compiler (CXXFLAGS='-std=c++11')"
#endif // _MSC_VER check
#endif
////////////////////////////////////////////////////////////////////////////////
#include <lmdb.h> /* for MDB_*, mdb_*() */
#ifdef LMDBXX_DEBUG
#include <cassert> /* for assert() */
#endif
#include <cstddef> /* for std::size_t */
#include <cstdio> /* for std::snprintf() */
#include <cstring> /* for std::strlen() */
#include <stdexcept> /* for std::runtime_error */
#include <string> /* for std::string */
#include <type_traits> /* for std::is_pod<> */
namespace lmdb {
using mode = mdb_mode_t;
}
////////////////////////////////////////////////////////////////////////////////
/* Error Handling */
namespace lmdb {
class error;
class logic_error;
class fatal_error;
class runtime_error;
class key_exist_error;
class not_found_error;
class corrupted_error;
class panic_error;
class version_mismatch_error;
class map_full_error;
class bad_dbi_error;
}
/**
* Base class for LMDB exception conditions.
*
* @see http://symas.com/mdb/doc/group__errors.html
*/
class lmdb::error : public std::runtime_error {
protected:
const int _code;
public:
/**
* Throws an error based on the given LMDB return code.
*/
[[noreturn]] static inline void raise(const char* origin, int rc);
/**
* Constructor.
*/
error(const char* const origin,
const int rc) noexcept
: runtime_error{origin},
_code{rc} {}
/**
* Returns the underlying LMDB error code.
*/
int code() const noexcept {
return _code;
}
/**
* Returns the origin of the LMDB error.
*/
const char* origin() const noexcept {
return runtime_error::what();
}
/**
* Returns the underlying LMDB error code.
*/
virtual const char* what() const noexcept {
static thread_local char buffer[1024];
std::snprintf(buffer, sizeof(buffer),
"%s: %s", origin(), ::mdb_strerror(code()));
return buffer;
}
};
/**
* Base class for logic error conditions.
*/
class lmdb::logic_error : public lmdb::error {
public:
using error::error;
};
/**
* Base class for fatal error conditions.
*/
class lmdb::fatal_error : public lmdb::error {
public:
using error::error;
};
/**
* Base class for runtime error conditions.
*/
class lmdb::runtime_error : public lmdb::error {
public:
using error::error;
};
/**
* Exception class for `MDB_KEYEXIST` errors.
*
* @see http://symas.com/mdb/doc/group__errors.html#ga05dc5bbcc7da81a7345bd8676e8e0e3b
*/
class lmdb::key_exist_error final : public lmdb::runtime_error {
public:
using runtime_error::runtime_error;
};
/**
* Exception class for `MDB_NOTFOUND` errors.
*
* @see http://symas.com/mdb/doc/group__errors.html#gabeb52e4c4be21b329e31c4add1b71926
*/
class lmdb::not_found_error final : public lmdb::runtime_error {
public:
using runtime_error::runtime_error;
};
/**
* Exception class for `MDB_CORRUPTED` errors.
*
* @see http://symas.com/mdb/doc/group__errors.html#gaf8148bf1b85f58e264e57194bafb03ef
*/
class lmdb::corrupted_error final : public lmdb::fatal_error {
public:
using fatal_error::fatal_error;
};
/**
* Exception class for `MDB_PANIC` errors.
*
* @see http://symas.com/mdb/doc/group__errors.html#gae37b9aedcb3767faba3de8c1cf6d3473
*/
class lmdb::panic_error final : public lmdb::fatal_error {
public:
using fatal_error::fatal_error;
};
/**
* Exception class for `MDB_VERSION_MISMATCH` errors.
*
* @see http://symas.com/mdb/doc/group__errors.html#ga909b2db047fa90fb0d37a78f86a6f99b
*/
class lmdb::version_mismatch_error final : public lmdb::fatal_error {
public:
using fatal_error::fatal_error;
};
/**
* Exception class for `MDB_MAP_FULL` errors.
*
* @see http://symas.com/mdb/doc/group__errors.html#ga0a83370402a060c9175100d4bbfb9f25
*/
class lmdb::map_full_error final : public lmdb::runtime_error {
public:
using runtime_error::runtime_error;
};
/**
* Exception class for `MDB_BAD_DBI` errors.
*
* @since 0.9.14 (2014/09/20)
* @see http://symas.com/mdb/doc/group__errors.html#gab4c82e050391b60a18a5df08d22a7083
*/
class lmdb::bad_dbi_error final : public lmdb::runtime_error {
public:
using runtime_error::runtime_error;
};
inline void
lmdb::error::raise(const char* const origin,
const int rc) {
switch (rc) {
case MDB_KEYEXIST: throw key_exist_error{origin, rc};
case MDB_NOTFOUND: throw not_found_error{origin, rc};
case MDB_CORRUPTED: throw corrupted_error{origin, rc};
case MDB_PANIC: throw panic_error{origin, rc};
case MDB_VERSION_MISMATCH: throw version_mismatch_error{origin, rc};
case MDB_MAP_FULL: throw map_full_error{origin, rc};
#ifdef MDB_BAD_DBI
case MDB_BAD_DBI: throw bad_dbi_error{origin, rc};
#endif
default: throw lmdb::runtime_error{origin, rc};
}
}
////////////////////////////////////////////////////////////////////////////////
/* Procedural Interface: Metadata */
namespace lmdb {
// TODO: mdb_version()
// TODO: mdb_strerror()
}
////////////////////////////////////////////////////////////////////////////////
/* Procedural Interface: Environment */
namespace lmdb {
static inline void env_create(MDB_env** env);
static inline void env_open(MDB_env* env,
const char* path, unsigned int flags, mode mode);
#if MDB_VERSION_FULL >= MDB_VERINT(0, 9, 14)
static inline void env_copy(MDB_env* env, const char* path, unsigned int flags);
static inline void env_copy_fd(MDB_env* env, mdb_filehandle_t fd, unsigned int flags);
#else
static inline void env_copy(MDB_env* env, const char* path);
static inline void env_copy_fd(MDB_env* env, mdb_filehandle_t fd);
#endif
static inline void env_stat(MDB_env* env, MDB_stat* stat);
static inline void env_info(MDB_env* env, MDB_envinfo* stat);
static inline void env_sync(MDB_env* env, bool force);
static inline void env_close(MDB_env* env) noexcept;
static inline void env_set_flags(MDB_env* env, unsigned int flags, bool onoff);
static inline void env_get_flags(MDB_env* env, unsigned int* flags);
static inline void env_get_path(MDB_env* env, const char** path);
static inline void env_get_fd(MDB_env* env, mdb_filehandle_t* fd);
static inline void env_set_mapsize(MDB_env* env, std::size_t size);
static inline void env_set_max_readers(MDB_env* env, unsigned int count);
static inline void env_get_max_readers(MDB_env* env, unsigned int* count);
static inline void env_set_max_dbs(MDB_env* env, MDB_dbi count);
static inline unsigned int env_get_max_keysize(MDB_env* env);
#if MDB_VERSION_FULL >= MDB_VERINT(0, 9, 11)
static inline void env_set_userctx(MDB_env* env, void* ctx);
static inline void* env_get_userctx(MDB_env* env);
#endif
// TODO: mdb_env_set_assert()
// TODO: mdb_reader_list()
// TODO: mdb_reader_check()
}
/**
* @throws lmdb::error on failure
* @see http://symas.com/mdb/doc/group__mdb.html#gaad6be3d8dcd4ea01f8df436f41d158d4
*/
static inline void
lmdb::env_create(MDB_env** env) {
const int rc = ::mdb_env_create(env);
if (rc != MDB_SUCCESS) {
error::raise("mdb_env_create", rc);
}
}
/**
* @throws lmdb::error on failure
* @see http://symas.com/mdb/doc/group__mdb.html#ga32a193c6bf4d7d5c5d579e71f22e9340
*/
static inline void
lmdb::env_open(MDB_env* const env,
const char* const path,
const unsigned int flags,
const mode mode) {
const int rc = ::mdb_env_open(env, path, flags, mode);
if (rc != MDB_SUCCESS) {
error::raise("mdb_env_open", rc);
}
}
/**
* @throws lmdb::error on failure
* @see http://symas.com/mdb/doc/group__mdb.html#ga3bf50d7793b36aaddf6b481a44e24244
* @see http://symas.com/mdb/doc/group__mdb.html#ga5d51d6130325f7353db0955dbedbc378
*/
static inline void
lmdb::env_copy(MDB_env* const env,
#if MDB_VERSION_FULL >= MDB_VERINT(0, 9, 14)
const char* const path,
const unsigned int flags = 0) {
const int rc = ::mdb_env_copy2(env, path, flags);
#else
const char* const path) {
const int rc = ::mdb_env_copy(env, path);
#endif
if (rc != MDB_SUCCESS) {
error::raise("mdb_env_copy2", rc);
}
}
/**
* @throws lmdb::error on failure
* @see http://symas.com/mdb/doc/group__mdb.html#ga5040d0de1f14000fa01fc0b522ff1f86
* @see http://symas.com/mdb/doc/group__mdb.html#ga470b0bcc64ac417de5de5930f20b1a28
*/
static inline void
lmdb::env_copy_fd(MDB_env* const env,
#if MDB_VERSION_FULL >= MDB_VERINT(0, 9, 14)
const mdb_filehandle_t fd,
const unsigned int flags = 0) {
const int rc = ::mdb_env_copyfd2(env, fd, flags);
#else
const mdb_filehandle_t fd) {
const int rc = ::mdb_env_copyfd(env, fd);
#endif
if (rc != MDB_SUCCESS) {
error::raise("mdb_env_copyfd2", rc);
}
}
/**
* @throws lmdb::error on failure
* @see http://symas.com/mdb/doc/group__mdb.html#gaf881dca452050efbd434cd16e4bae255
*/
static inline void
lmdb::env_stat(MDB_env* const env,
MDB_stat* const stat) {
const int rc = ::mdb_env_stat(env, stat);
if (rc != MDB_SUCCESS) {
error::raise("mdb_env_stat", rc);
}
}
/**
* @throws lmdb::error on failure
* @see http://symas.com/mdb/doc/group__mdb.html#ga18769362c7e7d6cf91889a028a5c5947
*/
static inline void
lmdb::env_info(MDB_env* const env,
MDB_envinfo* const stat) {
const int rc = ::mdb_env_info(env, stat);
if (rc != MDB_SUCCESS) {
error::raise("mdb_env_info", rc);
}
}
/**
* @throws lmdb::error on failure
* @see http://symas.com/mdb/doc/group__mdb.html#ga85e61f05aa68b520cc6c3b981dba5037
*/
static inline void
lmdb::env_sync(MDB_env* const env,
const bool force = true) {
const int rc = ::mdb_env_sync(env, force);
if (rc != MDB_SUCCESS) {
error::raise("mdb_env_sync", rc);
}
}
/**
* @see http://symas.com/mdb/doc/group__mdb.html#ga4366c43ada8874588b6a62fbda2d1e95
*/
static inline void
lmdb::env_close(MDB_env* const env) noexcept {
::mdb_env_close(env);
}
/**
* @throws lmdb::error on failure
* @see http://symas.com/mdb/doc/group__mdb.html#ga83f66cf02bfd42119451e9468dc58445
*/
static inline void
lmdb::env_set_flags(MDB_env* const env,
const unsigned int flags,
const bool onoff = true) {
const int rc = ::mdb_env_set_flags(env, flags, onoff ? 1 : 0);
if (rc != MDB_SUCCESS) {
error::raise("mdb_env_set_flags", rc);
}
}
/**
* @throws lmdb::error on failure
* @see http://symas.com/mdb/doc/group__mdb.html#ga2733aefc6f50beb49dd0c6eb19b067d9
*/
static inline void
lmdb::env_get_flags(MDB_env* const env,
unsigned int* const flags) {
const int rc = ::mdb_env_get_flags(env, flags);
if (rc != MDB_SUCCESS) {
error::raise("mdb_env_get_flags", rc);
}
}
/**
* @throws lmdb::error on failure
* @see http://symas.com/mdb/doc/group__mdb.html#gac699fdd8c4f8013577cb933fb6a757fe
*/
static inline void
lmdb::env_get_path(MDB_env* const env,
const char** path) {
const int rc = ::mdb_env_get_path(env, path);
if (rc != MDB_SUCCESS) {
error::raise("mdb_env_get_path", rc);
}
}
/**
* @throws lmdb::error on failure
* @see http://symas.com/mdb/doc/group__mdb.html#gaf1570e7c0e5a5d860fef1032cec7d5f2
*/
static inline void
lmdb::env_get_fd(MDB_env* const env,
mdb_filehandle_t* const fd) {
const int rc = ::mdb_env_get_fd(env, fd);
if (rc != MDB_SUCCESS) {
error::raise("mdb_env_get_fd", rc);
}
}
/**
* @throws lmdb::error on failure
* @see http://symas.com/mdb/doc/group__mdb.html#gaa2506ec8dab3d969b0e609cd82e619e5
*/
static inline void
lmdb::env_set_mapsize(MDB_env* const env,
const std::size_t size) {
const int rc = ::mdb_env_set_mapsize(env, size);
if (rc != MDB_SUCCESS) {
error::raise("mdb_env_set_mapsize", rc);
}
}
/**
* @throws lmdb::error on failure
* @see http://symas.com/mdb/doc/group__mdb.html#gae687966c24b790630be2a41573fe40e2
*/
static inline void
lmdb::env_set_max_readers(MDB_env* const env,
const unsigned int count) {
const int rc = ::mdb_env_set_maxreaders(env, count);
if (rc != MDB_SUCCESS) {
error::raise("mdb_env_set_maxreaders", rc);
}
}
/**
* @throws lmdb::error on failure
* @see http://symas.com/mdb/doc/group__mdb.html#ga70e143cf11760d869f754c9c9956e6cc
*/
static inline void
lmdb::env_get_max_readers(MDB_env* const env,
unsigned int* const count) {
const int rc = ::mdb_env_get_maxreaders(env, count);
if (rc != MDB_SUCCESS) {
error::raise("mdb_env_get_maxreaders", rc);
}
}
/**
* @throws lmdb::error on failure
* @see http://symas.com/mdb/doc/group__mdb.html#gaa2fc2f1f37cb1115e733b62cab2fcdbc
*/
static inline void
lmdb::env_set_max_dbs(MDB_env* const env,
const MDB_dbi count) {
const int rc = ::mdb_env_set_maxdbs(env, count);
if (rc != MDB_SUCCESS) {
error::raise("mdb_env_set_maxdbs", rc);
}
}
/**
* @see http://symas.com/mdb/doc/group__mdb.html#gaaf0be004f33828bf2fb09d77eb3cef94
*/
static inline unsigned int
lmdb::env_get_max_keysize(MDB_env* const env) {
const int rc = ::mdb_env_get_maxkeysize(env);
#ifdef LMDBXX_DEBUG
assert(rc >= 0);
#endif
return static_cast<unsigned int>(rc);
}
#if MDB_VERSION_FULL >= MDB_VERINT(0, 9, 11)
/**
* @throws lmdb::error on failure
* @since 0.9.11 (2014/01/15)
* @see http://symas.com/mdb/doc/group__mdb.html#gaf2fe09eb9c96eeb915a76bf713eecc46
*/
static inline void
lmdb::env_set_userctx(MDB_env* const env,
void* const ctx) {
const int rc = ::mdb_env_set_userctx(env, ctx);
if (rc != MDB_SUCCESS) {
error::raise("mdb_env_set_userctx", rc);
}
}
#endif
#if MDB_VERSION_FULL >= MDB_VERINT(0, 9, 11)
/**
* @since 0.9.11 (2014/01/15)
* @see http://symas.com/mdb/doc/group__mdb.html#ga45df6a4fb150cda2316b5ae224ba52f1
*/
static inline void*
lmdb::env_get_userctx(MDB_env* const env) {
return ::mdb_env_get_userctx(env);
}
#endif
////////////////////////////////////////////////////////////////////////////////
/* Procedural Interface: Transactions */
namespace lmdb {
static inline void txn_begin(
MDB_env* env, MDB_txn* parent, unsigned int flags, MDB_txn** txn);
static inline MDB_env* txn_env(MDB_txn* txn) noexcept;
#ifdef LMDBXX_TXN_ID
static inline std::size_t txn_id(MDB_txn* txn) noexcept;
#endif
static inline void txn_commit(MDB_txn* txn);
static inline void txn_abort(MDB_txn* txn) noexcept;
static inline void txn_reset(MDB_txn* txn) noexcept;
static inline void txn_renew(MDB_txn* txn);
}
/**
* @throws lmdb::error on failure
* @see http://symas.com/mdb/doc/group__mdb.html#gad7ea55da06b77513609efebd44b26920
*/
static inline void
lmdb::txn_begin(MDB_env* const env,
MDB_txn* const parent,
const unsigned int flags,
MDB_txn** txn) {
const int rc = ::mdb_txn_begin(env, parent, flags, txn);
if (rc != MDB_SUCCESS) {
error::raise("mdb_txn_begin", rc);
}
}
/**
* @see http://symas.com/mdb/doc/group__mdb.html#gaeb17735b8aaa2938a78a45cab85c06a0
*/
static inline MDB_env*
lmdb::txn_env(MDB_txn* const txn) noexcept {
return ::mdb_txn_env(txn);
}
#ifdef LMDBXX_TXN_ID
/**
* @note Only available in HEAD, not yet in any 0.9.x release (as of 0.9.16).
*/
static inline std::size_t
lmdb::txn_id(MDB_txn* const txn) noexcept {
return ::mdb_txn_id(txn);
}
#endif
/**
* @throws lmdb::error on failure
* @see http://symas.com/mdb/doc/group__mdb.html#ga846fbd6f46105617ac9f4d76476f6597
*/
static inline void
lmdb::txn_commit(MDB_txn* const txn) {
const int rc = ::mdb_txn_commit(txn);
if (rc != MDB_SUCCESS) {
error::raise("mdb_txn_commit", rc);
}
}
/**
* @see http://symas.com/mdb/doc/group__mdb.html#ga73a5938ae4c3239ee11efa07eb22b882
*/
static inline void
lmdb::txn_abort(MDB_txn* const txn) noexcept {
::mdb_txn_abort(txn);
}
/**
* @see http://symas.com/mdb/doc/group__mdb.html#ga02b06706f8a66249769503c4e88c56cd
*/
static inline void
lmdb::txn_reset(MDB_txn* const txn) noexcept {
::mdb_txn_reset(txn);
}
/**
* @throws lmdb::error on failure
* @see http://symas.com/mdb/doc/group__mdb.html#ga6c6f917959517ede1c504cf7c720ce6d
*/
static inline void
lmdb::txn_renew(MDB_txn* const txn) {
const int rc = ::mdb_txn_renew(txn);
if (rc != MDB_SUCCESS) {
error::raise("mdb_txn_renew", rc);
}
}
////////////////////////////////////////////////////////////////////////////////
/* Procedural Interface: Databases */
namespace lmdb {
static inline void dbi_open(
MDB_txn* txn, const char* name, unsigned int flags, MDB_dbi* dbi);
static inline void dbi_stat(MDB_txn* txn, MDB_dbi dbi, MDB_stat* stat);
static inline void dbi_flags(MDB_txn* txn, MDB_dbi dbi, unsigned int* flags);
static inline void dbi_close(MDB_env* env, MDB_dbi dbi) noexcept;
static inline void dbi_drop(MDB_txn* txn, MDB_dbi dbi, bool del);
static inline void dbi_set_compare(MDB_txn* txn, MDB_dbi dbi, MDB_cmp_func* cmp);
static inline void dbi_set_dupsort(MDB_txn* txn, MDB_dbi dbi, MDB_cmp_func* cmp);
static inline void dbi_set_relfunc(MDB_txn* txn, MDB_dbi dbi, MDB_rel_func* rel);
static inline void dbi_set_relctx(MDB_txn* txn, MDB_dbi dbi, void* ctx);
static inline bool dbi_get(MDB_txn* txn, MDB_dbi dbi, const MDB_val* key, MDB_val* data);
static inline bool dbi_put(MDB_txn* txn, MDB_dbi dbi, const MDB_val* key, MDB_val* data, unsigned int flags);
static inline bool dbi_del(MDB_txn* txn, MDB_dbi dbi, const MDB_val* key, const MDB_val* data);
// TODO: mdb_cmp()
// TODO: mdb_dcmp()
}
/**
* @throws lmdb::error on failure
* @see http://symas.com/mdb/doc/group__mdb.html#gac08cad5b096925642ca359a6d6f0562a
*/
static inline void
lmdb::dbi_open(MDB_txn* const txn,
const char* const name,
const unsigned int flags,
MDB_dbi* const dbi) {
const int rc = ::mdb_dbi_open(txn, name, flags, dbi);
if (rc != MDB_SUCCESS) {
error::raise("mdb_dbi_open", rc);
}
}
/**
* @throws lmdb::error on failure
* @see http://symas.com/mdb/doc/group__mdb.html#gae6c1069febe94299769dbdd032fadef6
*/
static inline void
lmdb::dbi_stat(MDB_txn* const txn,
const MDB_dbi dbi,
MDB_stat* const result) {
const int rc = ::mdb_stat(txn, dbi, result);
if (rc != MDB_SUCCESS) {
error::raise("mdb_stat", rc);
}
}
/**
* @throws lmdb::error on failure
* @see http://symas.com/mdb/doc/group__mdb.html#ga95ba4cb721035478a8705e57b91ae4d4
*/
static inline void
lmdb::dbi_flags(MDB_txn* const txn,
const MDB_dbi dbi,
unsigned int* const flags) {
const int rc = ::mdb_dbi_flags(txn, dbi, flags);
if (rc != MDB_SUCCESS) {
error::raise("mdb_dbi_flags", rc);
}
}
/**
* @see http://symas.com/mdb/doc/group__mdb.html#ga52dd98d0c542378370cd6b712ff961b5
*/
static inline void
lmdb::dbi_close(MDB_env* const env,
const MDB_dbi dbi) noexcept {
::mdb_dbi_close(env, dbi);
}
/**
* @see http://symas.com/mdb/doc/group__mdb.html#gab966fab3840fc54a6571dfb32b00f2db
*/
static inline void
lmdb::dbi_drop(MDB_txn* const txn,
const MDB_dbi dbi,
const bool del = false) {
const int rc = ::mdb_drop(txn, dbi, del ? 1 : 0);
if (rc != MDB_SUCCESS) {
error::raise("mdb_drop", rc);
}
}
/**
* @throws lmdb::error on failure
* @see http://symas.com/mdb/doc/group__mdb.html#ga68e47ffcf72eceec553c72b1784ee0fe
*/
static inline void
lmdb::dbi_set_compare(MDB_txn* const txn,
const MDB_dbi dbi,
MDB_cmp_func* const cmp = nullptr) {
const int rc = ::mdb_set_compare(txn, dbi, cmp);
if (rc != MDB_SUCCESS) {
error::raise("mdb_set_compare", rc);
}
}
/**
* @throws lmdb::error on failure
* @see http://symas.com/mdb/doc/group__mdb.html#gacef4ec3dab0bbd9bc978b73c19c879ae
*/
static inline void
lmdb::dbi_set_dupsort(MDB_txn* const txn,
const MDB_dbi dbi,
MDB_cmp_func* const cmp = nullptr) {
const int rc = ::mdb_set_dupsort(txn, dbi, cmp);
if (rc != MDB_SUCCESS) {
error::raise("mdb_set_dupsort", rc);
}
}
/**
* @throws lmdb::error on failure
* @see http://symas.com/mdb/doc/group__mdb.html#ga697d82c7afe79f142207ad5adcdebfeb
*/
static inline void
lmdb::dbi_set_relfunc(MDB_txn* const txn,
const MDB_dbi dbi,
MDB_rel_func* const rel) {
const int rc = ::mdb_set_relfunc(txn, dbi, rel);
if (rc != MDB_SUCCESS) {
error::raise("mdb_set_relfunc", rc);
}
}
/**
* @throws lmdb::error on failure
* @see http://symas.com/mdb/doc/group__mdb.html#ga7c34246308cee01724a1839a8f5cc594
*/
static inline void
lmdb::dbi_set_relctx(MDB_txn* const txn,
const MDB_dbi dbi,
void* const ctx) {
const int rc = ::mdb_set_relctx(txn, dbi, ctx);
if (rc != MDB_SUCCESS) {
error::raise("mdb_set_relctx", rc);
}
}
/**
* @retval true if the key/value pair was retrieved
* @retval false if the key wasn't found
* @see http://symas.com/mdb/doc/group__mdb.html#ga8bf10cd91d3f3a83a34d04ce6b07992d
*/
static inline bool
lmdb::dbi_get(MDB_txn* const txn,
const MDB_dbi dbi,
const MDB_val* const key,
MDB_val* const data) {
const int rc = ::mdb_get(txn, dbi, const_cast<MDB_val*>(key), data);
if (rc != MDB_SUCCESS && rc != MDB_NOTFOUND) {
error::raise("mdb_get", rc);
}
return (rc == MDB_SUCCESS);
}
/**
* @retval true if the key/value pair was inserted
* @retval false if the key already existed
* @see http://symas.com/mdb/doc/group__mdb.html#ga4fa8573d9236d54687c61827ebf8cac0
*/
static inline bool
lmdb::dbi_put(MDB_txn* const txn,
const MDB_dbi dbi,
const MDB_val* const key,
MDB_val* const data,
const unsigned int flags = 0) {
const int rc = ::mdb_put(txn, dbi, const_cast<MDB_val*>(key), data, flags);
if (rc != MDB_SUCCESS && rc != MDB_KEYEXIST) {
error::raise("mdb_put", rc);
}
return (rc == MDB_SUCCESS);
}
/**
* @retval true if the key/value pair was removed
* @retval false if the key wasn't found
* @see http://symas.com/mdb/doc/group__mdb.html#gab8182f9360ea69ac0afd4a4eaab1ddb0
*/
static inline bool
lmdb::dbi_del(MDB_txn* const txn,
const MDB_dbi dbi,
const MDB_val* const key,
const MDB_val* const data = nullptr) {
const int rc = ::mdb_del(txn, dbi, const_cast<MDB_val*>(key), const_cast<MDB_val*>(data));
if (rc != MDB_SUCCESS && rc != MDB_NOTFOUND) {
error::raise("mdb_del", rc);
}
return (rc == MDB_SUCCESS);
}
////////////////////////////////////////////////////////////////////////////////
/* Procedural Interface: Cursors */
namespace lmdb {
static inline void cursor_open(MDB_txn* txn, MDB_dbi dbi, MDB_cursor** cursor);
static inline void cursor_close(MDB_cursor* cursor) noexcept;
static inline void cursor_renew(MDB_txn* txn, MDB_cursor* cursor);
static inline MDB_txn* cursor_txn(MDB_cursor* cursor) noexcept;
static inline MDB_dbi cursor_dbi(MDB_cursor* cursor) noexcept;
static inline bool cursor_get(MDB_cursor* cursor, MDB_val* key, MDB_val* data, MDB_cursor_op op);
static inline void cursor_put(MDB_cursor* cursor, MDB_val* key, MDB_val* data, unsigned int flags);
static inline void cursor_del(MDB_cursor* cursor, unsigned int flags);
static inline void cursor_count(MDB_cursor* cursor, std::size_t& count);
}
/**
* @throws lmdb::error on failure
* @see http://symas.com/mdb/doc/group__mdb.html#ga9ff5d7bd42557fd5ee235dc1d62613aa
*/
static inline void
lmdb::cursor_open(MDB_txn* const txn,
const MDB_dbi dbi,
MDB_cursor** const cursor) {
const int rc = ::mdb_cursor_open(txn, dbi, cursor);
if (rc != MDB_SUCCESS) {
error::raise("mdb_cursor_open", rc);
}
}
/**
* @see http://symas.com/mdb/doc/group__mdb.html#gad685f5d73c052715c7bd859cc4c05188
*/
static inline void
lmdb::cursor_close(MDB_cursor* const cursor) noexcept {
::mdb_cursor_close(cursor);
}
/**
* @throws lmdb::error on failure
* @see http://symas.com/mdb/doc/group__mdb.html#gac8b57befb68793070c85ea813df481af
*/
static inline void
lmdb::cursor_renew(MDB_txn* const txn,
MDB_cursor* const cursor) {
const int rc = ::mdb_cursor_renew(txn, cursor);
if (rc != MDB_SUCCESS) {
error::raise("mdb_cursor_renew", rc);
}
}
/**
* @see http://symas.com/mdb/doc/group__mdb.html#ga7bf0d458f7f36b5232fcb368ebda79e0
*/
static inline MDB_txn*
lmdb::cursor_txn(MDB_cursor* const cursor) noexcept {
return ::mdb_cursor_txn(cursor);
}
/**
* @see http://symas.com/mdb/doc/group__mdb.html#ga2f7092cf70ee816fb3d2c3267a732372
*/
static inline MDB_dbi
lmdb::cursor_dbi(MDB_cursor* const cursor) noexcept {
return ::mdb_cursor_dbi(cursor);
}
/**
* @throws lmdb::error on failure
* @see http://symas.com/mdb/doc/group__mdb.html#ga48df35fb102536b32dfbb801a47b4cb0
*/
static inline bool
lmdb::cursor_get(MDB_cursor* const cursor,
MDB_val* const key,
MDB_val* const data,
const MDB_cursor_op op) {
const int rc = ::mdb_cursor_get(cursor, key, data, op);
if (rc != MDB_SUCCESS && rc != MDB_NOTFOUND) {
error::raise("mdb_cursor_get", rc);
}
return (rc == MDB_SUCCESS);
}
/**
* @throws lmdb::error on failure
* @see http://symas.com/mdb/doc/group__mdb.html#ga1f83ccb40011837ff37cc32be01ad91e
*/
static inline void
lmdb::cursor_put(MDB_cursor* const cursor,
MDB_val* const key,
MDB_val* const data,
const unsigned int flags = 0) {
const int rc = ::mdb_cursor_put(cursor, key, data, flags);
if (rc != MDB_SUCCESS) {
error::raise("mdb_cursor_put", rc);
}
}
/**
* @throws lmdb::error on failure
* @see http://symas.com/mdb/doc/group__mdb.html#ga26a52d3efcfd72e5bf6bd6960bf75f95
*/
static inline void
lmdb::cursor_del(MDB_cursor* const cursor,
const unsigned int flags = 0) {
const int rc = ::mdb_cursor_del(cursor, flags);
if (rc != MDB_SUCCESS) {
error::raise("mdb_cursor_del", rc);
}
}
/**
* @throws lmdb::error on failure
* @see http://symas.com/mdb/doc/group__mdb.html#ga4041fd1e1862c6b7d5f10590b86ffbe2
*/
static inline void
lmdb::cursor_count(MDB_cursor* const cursor,
std::size_t& count) {
const int rc = ::mdb_cursor_count(cursor, &count);
if (rc != MDB_SUCCESS) {
error::raise("mdb_cursor_count", rc);
}
}
////////////////////////////////////////////////////////////////////////////////
/* Resource Interface: Values */
namespace lmdb {
class val;
}
/**
* Wrapper class for `MDB_val` structures.
*
* @note Instances of this class are movable and copyable both.
* @see http://symas.com/mdb/doc/group__mdb.html#structMDB__val
*/
class lmdb::val {
protected:
MDB_val _val;
public:
/**
* Default constructor.
*/
val() noexcept = default;
/**
* Constructor.
*/
val(const std::string& data) noexcept
: val{data.data(), data.size()} {}
/**
* Constructor.
*/
val(const char* const data) noexcept
: val{data, std::strlen(data)} {}
/**
* Constructor.
*/
val(const void* const data,
const std::size_t size) noexcept
: _val{size, const_cast<void*>(data)} {}
/**
* Move constructor.
*/
val(val&& other) noexcept = default;
/**
* Move assignment operator.
*/
val& operator=(val&& other) noexcept = default;
/**
* Destructor.
*/
~val() noexcept = default;
/**
* Returns an `MDB_val*` pointer.
*/
operator MDB_val*() noexcept {
return &_val;
}
/**
* Returns an `MDB_val*` pointer.
*/
operator const MDB_val*() const noexcept {
return &_val;
}
/**
* Determines whether this value is empty.
*/
bool empty() const noexcept {
return size() == 0;
}
/**
* Returns the size of the data.
*/
std::size_t size() const noexcept {
return _val.mv_size;
}
/**
* Returns a pointer to the data.
*/
template<typename T>
T* data() noexcept {
return reinterpret_cast<T*>(_val.mv_data);
}
/**
* Returns a pointer to the data.
*/
template<typename T>
const T* data() const noexcept {
return reinterpret_cast<T*>(_val.mv_data);
}
/**
* Returns a pointer to the data.
*/
char* data() noexcept {
return reinterpret_cast<char*>(_val.mv_data);
}
/**
* Returns a pointer to the data.
*/
const char* data() const noexcept {
return reinterpret_cast<char*>(_val.mv_data);
}
/**
* Assigns the value.
*/
template<typename T>
val& assign(const T* const data,
const std::size_t size) noexcept {
_val.mv_size = size;
_val.mv_data = const_cast<void*>(reinterpret_cast<const void*>(data));
return *this;
}
/**
* Assigns the value.
*/
val& assign(const char* const data) noexcept {
return assign(data, std::strlen(data));
}
/**
* Assigns the value.
*/
val& assign(const std::string& data) noexcept {
return assign(data.data(), data.size());
}
};
#if !(defined(__COVERITY__) || defined(_MSC_VER))
static_assert(std::is_pod<lmdb::val>::value, "lmdb::val must be a POD type");
static_assert(sizeof(lmdb::val) == sizeof(MDB_val), "sizeof(lmdb::val) != sizeof(MDB_val)");
#endif
////////////////////////////////////////////////////////////////////////////////
/* Resource Interface: Environment */
namespace lmdb {
class env;
}
/**
* Resource class for `MDB_env*` handles.
*
* @note Instances of this class are movable, but not copyable.
* @see http://symas.com/mdb/doc/group__internal.html#structMDB__env
*/
class lmdb::env {
protected:
MDB_env* _handle{nullptr};
public:
static constexpr unsigned int default_flags = 0;
static constexpr mode default_mode = 0644; /* -rw-r--r-- */
/**
* Creates a new LMDB environment.
*
* @param flags
* @throws lmdb::error on failure
*/
static env create(const unsigned int flags = default_flags) {
MDB_env* handle{nullptr};
lmdb::env_create(&handle);
#ifdef LMDBXX_DEBUG
assert(handle != nullptr);
#endif
if (flags) {
try {
lmdb::env_set_flags(handle, flags);
}
catch (const lmdb::error&) {
lmdb::env_close(handle);
throw;
}
}
return env{handle};
}
/**
* Constructor.
*
* @param handle a valid `MDB_env*` handle
*/
env(MDB_env* const handle) noexcept
: _handle{handle} {}
/**
* Move constructor.
*/
env(env&& other) noexcept {
std::swap(_handle, other._handle);
}
/**
* Move assignment operator.
*/
env& operator=(env&& other) noexcept {
if (this != &other) {
std::swap(_handle, other._handle);
}
return *this;
}
/**
* Destructor.
*/
~env() noexcept {
try { close(); } catch (...) {}
}
/**
* Returns the underlying `MDB_env*` handle.
*/
operator MDB_env*() const noexcept {
return _handle;
}
/**
* Returns the underlying `MDB_env*` handle.
*/
MDB_env* handle() const noexcept {
return _handle;
}
/**
* Flushes data buffers to disk.
*
* @param force
* @throws lmdb::error on failure
*/
void sync(const bool force = true) {
lmdb::env_sync(handle(), force);
}
/**
* Closes this environment, releasing the memory map.
*
* @note this method is idempotent
* @post `handle() == nullptr`
*/
void close() noexcept {
if (handle()) {
lmdb::env_close(handle());
_handle = nullptr;
}
}
/**
* Opens this environment.
*
* @param path
* @param flags
* @param mode
* @throws lmdb::error on failure
*/
env& open(const char* const path,
const unsigned int flags = default_flags,
const mode mode = default_mode) {
lmdb::env_open(handle(), path, flags, mode);
return *this;
}
/**
* @param flags
* @param onoff
* @throws lmdb::error on failure
*/
env& set_flags(const unsigned int flags,
const bool onoff = true) {
lmdb::env_set_flags(handle(), flags, onoff);
return *this;
}
/**
* @param size
* @throws lmdb::error on failure
*/
env& set_mapsize(const std::size_t size) {
lmdb::env_set_mapsize(handle(), size);
return *this;
}
/**
* @param count
* @throws lmdb::error on failure
*/
env& set_max_readers(const unsigned int count) {
lmdb::env_set_max_readers(handle(), count);
return *this;
}
/**
* @param count
* @throws lmdb::error on failure
*/
env& set_max_dbs(const MDB_dbi count) {
lmdb::env_set_max_dbs(handle(), count);
return *this;
}
};
////////////////////////////////////////////////////////////////////////////////
/* Resource Interface: Transactions */
namespace lmdb {
class txn;
}
/**
* Resource class for `MDB_txn*` handles.
*
* @note Instances of this class are movable, but not copyable.
* @see http://symas.com/mdb/doc/group__internal.html#structMDB__txn
*/
class lmdb::txn {
protected:
MDB_txn* _handle{nullptr};
public:
static constexpr unsigned int default_flags = 0;
/**
* Creates a new LMDB transaction.
*
* @param env the environment handle
* @param parent
* @param flags
* @throws lmdb::error on failure
*/
static txn begin(MDB_env* const env,
MDB_txn* const parent = nullptr,
const unsigned int flags = default_flags) {
MDB_txn* handle{nullptr};
lmdb::txn_begin(env, parent, flags, &handle);
#ifdef LMDBXX_DEBUG
assert(handle != nullptr);
#endif
return txn{handle};
}
/**
* Constructor.
*
* @param handle a valid `MDB_txn*` handle
*/
txn(MDB_txn* const handle) noexcept
: _handle{handle} {}
/**
* Move constructor.
*/
txn(txn&& other) noexcept {
std::swap(_handle, other._handle);
}
/**
* Move assignment operator.
*/
txn& operator=(txn&& other) noexcept {
if (this != &other) {
std::swap(_handle, other._handle);
}
return *this;
}
/**
* Destructor.
*/
~txn() noexcept {
if (_handle) {
try { abort(); } catch (...) {}
_handle = nullptr;
}
}
/**
* Returns the underlying `MDB_txn*` handle.
*/
operator MDB_txn*() const noexcept {
return _handle;
}
/**
* Returns the underlying `MDB_txn*` handle.
*/
MDB_txn* handle() const noexcept {
return _handle;
}
/**
* Returns the transaction's `MDB_env*` handle.
*/
MDB_env* env() const noexcept {
return lmdb::txn_env(handle());
}
/**
* Commits this transaction.
*
* @throws lmdb::error on failure
* @post `handle() == nullptr`
*/
void commit() {
lmdb::txn_commit(_handle);
_handle = nullptr;
}
/**
* Aborts this transaction.
*
* @post `handle() == nullptr`
*/
void abort() noexcept {
lmdb::txn_abort(_handle);
_handle = nullptr;
}
/**
* Resets this read-only transaction.
*/
void reset() noexcept {
lmdb::txn_reset(_handle);
}
/**
* Renews this read-only transaction.
*
* @throws lmdb::error on failure
*/
void renew() {
lmdb::txn_renew(_handle);
}
};
////////////////////////////////////////////////////////////////////////////////
/* Resource Interface: Databases */
namespace lmdb {
class dbi;
}
/**
* Resource class for `MDB_dbi` handles.
*
* @note Instances of this class are movable, but not copyable.
* @see http://symas.com/mdb/doc/group__mdb.html#gadbe68a06c448dfb62da16443d251a78b
*/
class lmdb::dbi {
protected:
MDB_dbi _handle{0};
public:
static constexpr unsigned int default_flags = 0;
static constexpr unsigned int default_put_flags = 0;
/**
* Opens a database handle.
*
* @param txn the transaction handle
* @param name
* @param flags
* @throws lmdb::error on failure
*/
static dbi
open(MDB_txn* const txn,
const char* const name = nullptr,
const unsigned int flags = default_flags) {
MDB_dbi handle{};
lmdb::dbi_open(txn, name, flags, &handle);
return dbi{handle};
}
/**
* Constructor.
*
* @param handle a valid `MDB_dbi` handle
*/
dbi(const MDB_dbi handle) noexcept
: _handle{handle} {}
/**
* Move constructor.
*/
dbi(dbi&& other) noexcept {
std::swap(_handle, other._handle);
}
/**
* Move assignment operator.
*/
dbi& operator=(dbi&& other) noexcept {
if (this != &other) {
std::swap(_handle, other._handle);
}
return *this;
}
/**
* Destructor.
*/
~dbi() noexcept {
if (_handle) {
/* No need to call close() here. */
}
}
/**
* Returns the underlying `MDB_dbi` handle.
*/
operator MDB_dbi() const noexcept {
return _handle;
}
/**
* Returns the underlying `MDB_dbi` handle.
*/
MDB_dbi handle() const noexcept {
return _handle;
}
/**
* Returns statistics for this database.
*
* @param txn a transaction handle
* @throws lmdb::error on failure
*/
MDB_stat stat(MDB_txn* const txn) const {
MDB_stat result;
lmdb::dbi_stat(txn, handle(), &result);
return result;
}
/**
* Retrieves the flags for this database handle.
*
* @param txn a transaction handle
* @throws lmdb::error on failure
*/
unsigned int flags(MDB_txn* const txn) const {
unsigned int result{};
lmdb::dbi_flags(txn, handle(), &result);
return result;
}
/**
* Returns the number of records in this database.
*
* @param txn a transaction handle
* @throws lmdb::error on failure
*/
std::size_t size(MDB_txn* const txn) const {
return stat(txn).ms_entries;
}
/**
* @param txn a transaction handle
* @param del
* @throws lmdb::error on failure
*/
void drop(MDB_txn* const txn,
const bool del = false) {
lmdb::dbi_drop(txn, handle(), del);
}
/**
* Sets a custom key comparison function for this database.
*
* @param txn a transaction handle
* @param cmp the comparison function
* @throws lmdb::error on failure
*/
dbi& set_compare(MDB_txn* const txn,
MDB_cmp_func* const cmp = nullptr) {
lmdb::dbi_set_compare(txn, handle(), cmp);
return *this;
}
/**
* Retrieves a key/value pair from this database.
*
* @param txn a transaction handle
* @param key
* @param data
* @throws lmdb::error on failure
*/
bool get(MDB_txn* const txn,
const val& key,
val& data) {
return lmdb::dbi_get(txn, handle(), key, data);
}
/**
* Retrieves a key from this database.
*
* @param txn a transaction handle
* @param key
* @throws lmdb::error on failure
*/
template<typename K>
bool get(MDB_txn* const txn,
const K& key) const {
const lmdb::val k{&key, sizeof(K)};
lmdb::val v{};
return lmdb::dbi_get(txn, handle(), k, v);
}
/**
* Retrieves a key/value pair from this database.
*
* @param txn a transaction handle
* @param key
* @param val
* @throws lmdb::error on failure
*/
template<typename K, typename V>
bool get(MDB_txn* const txn,
const K& key,
V& val) const {
const lmdb::val k{&key, sizeof(K)};
lmdb::val v{};
const bool result = lmdb::dbi_get(txn, handle(), k, v);
if (result) {
val = *v.data<const V>();
}
return result;
}
/**
* Retrieves a key/value pair from this database.
*
* @param txn a transaction handle
* @param key a NUL-terminated string key
* @param val
* @throws lmdb::error on failure
*/
template<typename V>
bool get(MDB_txn* const txn,
const char* const key,
V& val) const {
const lmdb::val k{key, std::strlen(key)};
lmdb::val v{};
const bool result = lmdb::dbi_get(txn, handle(), k, v);
if (result) {
val = *v.data<const V>();
}
return result;
}
/**
* Stores a key/value pair into this database.
*
* @param txn a transaction handle
* @param key
* @param data
* @param flags
* @throws lmdb::error on failure
*/
bool put(MDB_txn* const txn,
const val& key,
val& data,
const unsigned int flags = default_put_flags) {
return lmdb::dbi_put(txn, handle(), key, data, flags);
}
/**
* Stores a key into this database.
*
* @param txn a transaction handle
* @param key
* @param flags
* @throws lmdb::error on failure
*/
template<typename K>
bool put(MDB_txn* const txn,
const K& key,
const unsigned int flags = default_put_flags) {
const lmdb::val k{&key, sizeof(K)};
lmdb::val v{};
return lmdb::dbi_put(txn, handle(), k, v, flags);
}
/**
* Stores a key/value pair into this database.
*
* @param txn a transaction handle
* @param key
* @param val
* @param flags
* @throws lmdb::error on failure
*/
template<typename K, typename V>
bool put(MDB_txn* const txn,
const K& key,
const V& val,
const unsigned int flags = default_put_flags) {
const lmdb::val k{&key, sizeof(K)};
lmdb::val v{&val, sizeof(V)};
return lmdb::dbi_put(txn, handle(), k, v, flags);
}
/**
* Stores a key/value pair into this database.
*
* @param txn a transaction handle
* @param key a NUL-terminated string key
* @param val
* @param flags
* @throws lmdb::error on failure
*/
template<typename V>
bool put(MDB_txn* const txn,
const char* const key,
const V& val,
const unsigned int flags = default_put_flags) {
const lmdb::val k{key, std::strlen(key)};
lmdb::val v{&val, sizeof(V)};
return lmdb::dbi_put(txn, handle(), k, v, flags);
}
/**
* Stores a key/value pair into this database.
*
* @param txn a transaction handle
* @param key a NUL-terminated string key
* @param val a NUL-terminated string key
* @param flags
* @throws lmdb::error on failure
*/
bool put(MDB_txn* const txn,
const char* const key,
const char* const val,
const unsigned int flags = default_put_flags) {
const lmdb::val k{key, std::strlen(key)};
lmdb::val v{val, std::strlen(val)};
return lmdb::dbi_put(txn, handle(), k, v, flags);
}
/**
* Removes a key/value pair from this database.
*
* @param txn a transaction handle
* @param key
* @throws lmdb::error on failure
*/
bool del(MDB_txn* const txn,
const val& key) {
return lmdb::dbi_del(txn, handle(), key);
}
/**
* Removes a key/value pair from this database.
*
* @param txn a transaction handle
* @param key
* @throws lmdb::error on failure
*/
template<typename K>
bool del(MDB_txn* const txn,
const K& key) {
const lmdb::val k{&key, sizeof(K)};
return lmdb::dbi_del(txn, handle(), k);
}
};
////////////////////////////////////////////////////////////////////////////////
/* Resource Interface: Cursors */
namespace lmdb {
class cursor;
}
/**
* Resource class for `MDB_cursor*` handles.
*
* @note Instances of this class are movable, but not copyable.
* @see http://symas.com/mdb/doc/group__internal.html#structMDB__cursor
*/
class lmdb::cursor {
protected:
MDB_cursor* _handle{nullptr};
public:
static constexpr unsigned int default_flags = 0;
/**
* Creates an LMDB cursor.
*
* @param txn the transaction handle
* @param dbi the database handle
* @throws lmdb::error on failure
*/
static cursor
open(MDB_txn* const txn,
const MDB_dbi dbi) {
MDB_cursor* handle{};
lmdb::cursor_open(txn, dbi, &handle);
#ifdef LMDBXX_DEBUG
assert(handle != nullptr);
#endif
return cursor{handle};
}
/**
* Constructor.
*
* @param handle a valid `MDB_cursor*` handle
*/
cursor(MDB_cursor* const handle) noexcept
: _handle{handle} {}
/**
* Move constructor.
*/
cursor(cursor&& other) noexcept {
std::swap(_handle, other._handle);
}
/**
* Move assignment operator.
*/
cursor& operator=(cursor&& other) noexcept {
if (this != &other) {
std::swap(_handle, other._handle);
}
return *this;
}
/**
* Destructor.
*/
~cursor() noexcept {
try { close(); } catch (...) {}
}
/**
* Returns the underlying `MDB_cursor*` handle.
*/
operator MDB_cursor*() const noexcept {
return _handle;
}
/**
* Returns the underlying `MDB_cursor*` handle.
*/
MDB_cursor* handle() const noexcept {
return _handle;
}
/**
* Closes this cursor.
*
* @note this method is idempotent
* @post `handle() == nullptr`
*/
void close() noexcept {
if (_handle) {
lmdb::cursor_close(_handle);
_handle = nullptr;
}
}
/**
* Renews this cursor.
*
* @param txn the transaction scope
* @throws lmdb::error on failure
*/
void renew(MDB_txn* const txn) {
lmdb::cursor_renew(txn, handle());
}
/**
* Returns the cursor's transaction handle.
*/
MDB_txn* txn() const noexcept {
return lmdb::cursor_txn(handle());
}
/**
* Returns the cursor's database handle.
*/
MDB_dbi dbi() const noexcept {
return lmdb::cursor_dbi(handle());
}
/**
* Retrieves a key from the database.
*
* @param key
* @param op
* @throws lmdb::error on failure
*/
bool get(MDB_val* const key,
const MDB_cursor_op op) {
return get(key, nullptr, op);
}
/**
* Retrieves a key from the database.
*
* @param key
* @param op
* @throws lmdb::error on failure
*/
bool get(lmdb::val& key,
const MDB_cursor_op op) {
return get(key, nullptr, op);
}
/**
* Retrieves a key/value pair from the database.
*
* @param key
* @param val (may be `nullptr`)
* @param op
* @throws lmdb::error on failure
*/
bool get(MDB_val* const key,
MDB_val* const val,
const MDB_cursor_op op) {
return lmdb::cursor_get(handle(), key, val, op);
}
/**
* Retrieves a key/value pair from the database.
*
* @param key
* @param val
* @param op
* @throws lmdb::error on failure
*/
bool get(lmdb::val& key,
lmdb::val& val,
const MDB_cursor_op op) {
return lmdb::cursor_get(handle(), key, val, op);
}
/**
* Retrieves a key/value pair from the database.
*
* @param key
* @param val
* @param op
* @throws lmdb::error on failure
*/
bool get(std::string& key,
std::string& val,
const MDB_cursor_op op) {
lmdb::val k{}, v{};
const bool found = get(k, v, op);
if (found) {
key.assign(k.data(), k.size());
val.assign(v.data(), v.size());
}
return found;
}
/**
* Positions this cursor at the given key.
*
* @param key
* @param op
* @throws lmdb::error on failure
*/
template<typename K>
bool find(const K& key,
const MDB_cursor_op op = MDB_SET) {
lmdb::val k{&key, sizeof(K)};
return get(k, nullptr, op);
}
};
////////////////////////////////////////////////////////////////////////////////
#endif /* LMDBXX_H */