mdbx: add pure- & const-function attributes to C API.

Change-Id: Ie4d1742f3d4717a0cd1fd5677b9b1ae641193d45
This commit is contained in:
Leonid Yuriev 2020-08-21 18:01:16 +03:00
parent 100ac532ed
commit 0a75417d5f
5 changed files with 238 additions and 154 deletions

221
mdbx.h
View File

@ -137,6 +137,100 @@ typedef pthread_t mdbx_tid_t;
#define __has_attribute(x) (0) #define __has_attribute(x) (0)
#endif /* __has_attribute */ #endif /* __has_attribute */
#ifndef __has_cpp_attribute
#define __has_cpp_attribute(x) 0
#endif /* __has_cpp_attribute */
#ifndef __has_feature
#define __has_feature(x) (0)
#endif /* __has_feature */
#ifndef __has_extension
#define __has_extension(x) (0)
#endif /* __has_extension */
#ifndef __has_builtin
#define __has_builtin(x) (0)
#endif /* __has_builtin */
#ifndef __pure_function
/** Many functions have no effects except the return value and their
* return value depends only on the parameters and/or global variables.
* Such a function can be subject to common subexpression elimination
* and loop optimization just as an arithmetic operator would be.
* These functions should be declared with the attribute pure. */
#if (defined(__GNUC__) || __has_attribute(__pure__)) && \
(!defined(__clang__) /* https://bugs.llvm.org/show_bug.cgi?id=43275 */ \
|| !defined(__cplusplus) || !__has_feature(cxx_exceptions))
#define __pure_function __attribute__((__pure__))
#elif defined(__cplusplus) && __has_cpp_attribute(gnu::pure) && \
(!defined(__clang__) || !__has_feature(cxx_exceptions))
#define __pure_function [[gnu::pure]]
#else
#define __pure_function
#endif
#endif /* __pure_function */
#ifndef __nothrow_pure_function
/** Like \ref __pure_function with addition `noexcept` restriction
* that is compatible to CLANG and proposed [[pure]]. */
#if defined(__GNUC__) || \
(__has_attribute(__pure__) && __has_attribute(__nothrow__))
#define __nothrow_pure_function __attribute__((__pure__, __nothrow__))
#elif defined(__cplusplus) && __has_cpp_attribute(gnu::pure)
#if __has_cpp_attribute(gnu::nothrow)
#define __nothrow_pure_function [[gnu::pure, gnu::nothrow]]
#else
#define __nothrow_pure_function [[gnu::pure]]
#endif
#elif defined(__cplusplus) && __has_cpp_attribute(pure)
#define __nothrow_pure_function [[pure]]
#else
#define __nothrow_pure_function
#endif
#endif /* __nothrow_pure_function */
#ifndef __const_function
/** Many functions do not examine any values except their arguments,
* and have no effects except the return value. Basically this is just
* slightly more strict class than the PURE attribute, since function
* is not allowed to read global memory.
*
* Note that a function that has pointer arguments and examines the
* data pointed to must not be declared const. Likewise, a function
* that calls a non-const function usually must not be const.
* It does not make sense for a const function to return void. */
#if (defined(__GNUC__) || __has_attribute(__pure__)) && \
(!defined(__clang__) /* https://bugs.llvm.org/show_bug.cgi?id=43275 */ \
|| !defined(__cplusplus) || !__has_feature(cxx_exceptions))
#define __const_function __attribute__((__const__))
#elif defined(__cplusplus) && __has_cpp_attribute(gnu::const) && \
(!defined(__clang__) || !__has_feature(cxx_exceptions))
#define __const_function [[gnu::const]]
#else
#define __const_function __pure_function
#endif
#endif /* __const_function */
#ifndef __nothrow_const_function
/** Like \ref __const_function with addition `noexcept` restriction
* that is compatible to CLANG and future [[const]]. */
#if defined(__GNUC__) || \
(__has_attribute(__const__) && __has_attribute(__nothrow__))
#define __nothrow_const_function __attribute__((__const__, __nothrow__))
#elif defined(__cplusplus) && __has_cpp_attribute(gnu::const)
#if __has_cpp_attribute(gnu::nothrow)
#define __nothrow_pure_function [[gnu::const, gnu::nothrow]]
#else
#define __nothrow_pure_function [[gnu::const]]
#endif
#elif defined(__cplusplus) && __has_cpp_attribute(const)
#define __nothrow_const_function [[const]]
#else
#define __nothrow_const_function __nothrow_pure_function
#endif
#endif /* __nothrow_pure_function */
#ifndef MDBX_DEPRECATED #ifndef MDBX_DEPRECATED
#ifdef __deprecated #ifdef __deprecated
#define MDBX_DEPRECATED __deprecated #define MDBX_DEPRECATED __deprecated
@ -2138,40 +2232,47 @@ LIBMDBX_API int mdbx_is_readahead_reasonable(size_t volume,
/** Returns the minimal database page size in bytes. /** Returns the minimal database page size in bytes.
* \ingroup c_statinfo */ * \ingroup c_statinfo */
__inline intptr_t mdbx_limits_pgsize_min(void) { return MDBX_MIN_PAGESIZE; } __nothrow_const_function __inline intptr_t mdbx_limits_pgsize_min(void) {
return MDBX_MIN_PAGESIZE;
}
/** Returns the maximal database page size in bytes. /** Returns the maximal database page size in bytes.
* \ingroup c_statinfo */ * \ingroup c_statinfo */
__inline intptr_t mdbx_limits_pgsize_max(void) { return MDBX_MAX_PAGESIZE; } __nothrow_const_function __inline intptr_t mdbx_limits_pgsize_max(void) {
return MDBX_MAX_PAGESIZE;
}
/** Returns minimal database size in bytes for given page size, /** Returns minimal database size in bytes for given page size,
* or -1 if pagesize is invalid. * or -1 if pagesize is invalid.
* \ingroup c_statinfo */ * \ingroup c_statinfo */
LIBMDBX_API intptr_t mdbx_limits_dbsize_min(intptr_t pagesize); __nothrow_const_function LIBMDBX_API intptr_t
mdbx_limits_dbsize_min(intptr_t pagesize);
/** Returns maximal database size in bytes for given page size, /** Returns maximal database size in bytes for given page size,
* or -1 if pagesize is invalid. * or -1 if pagesize is invalid.
* \ingroup c_statinfo */ * \ingroup c_statinfo */
LIBMDBX_API intptr_t mdbx_limits_dbsize_max(intptr_t pagesize); __nothrow_const_function LIBMDBX_API intptr_t
mdbx_limits_dbsize_max(intptr_t pagesize);
/** Returns maximal key size in bytes for given page size /** Returns maximal key size in bytes for given page size
* and database flags, or -1 if pagesize is invalid. * and database flags, or -1 if pagesize is invalid.
* \ingroup c_statinfo * \ingroup c_statinfo
* \see db_flags */ * \see db_flags */
LIBMDBX_API intptr_t mdbx_limits_keysize_max(intptr_t pagesize, __nothrow_const_function LIBMDBX_API intptr_t
MDBX_db_flags_t flags); mdbx_limits_keysize_max(intptr_t pagesize, MDBX_db_flags_t flags);
/** Returns maximal data size in bytes for given page size /** Returns maximal data size in bytes for given page size
* and database flags, or -1 if pagesize is invalid. * and database flags, or -1 if pagesize is invalid.
* \ingroup c_statinfo * \ingroup c_statinfo
* \see db_flags */ * \see db_flags */
LIBMDBX_API intptr_t mdbx_limits_valsize_max(intptr_t pagesize, __nothrow_const_function LIBMDBX_API intptr_t
MDBX_db_flags_t flags); mdbx_limits_valsize_max(intptr_t pagesize, MDBX_db_flags_t flags);
/** Returns maximal write transaction size (i.e. limit for summary volume of /** Returns maximal write transaction size (i.e. limit for summary volume of
* dirty pages) in bytes for given page size, or -1 if pagesize is invalid. * dirty pages) in bytes for given page size, or -1 if pagesize is invalid.
* \ingroup c_statinfo */ * \ingroup c_statinfo */
LIBMDBX_API intptr_t mdbx_limits_txnsize_max(intptr_t pagesize); __nothrow_const_function LIBMDBX_API intptr_t
mdbx_limits_txnsize_max(intptr_t pagesize);
/** Set the maximum number of threads/reader slots for the environment. /** Set the maximum number of threads/reader slots for the environment.
* \ingroup c_settings * \ingroup c_settings
@ -2253,8 +2354,8 @@ LIBMDBX_API int mdbx_env_get_maxdbs(MDBX_env *env, MDBX_dbi *dbs);
* *
* \returns The maximum size of a key can write, * \returns The maximum size of a key can write,
* or -1 if something is wrong. */ * or -1 if something is wrong. */
LIBMDBX_API int mdbx_env_get_maxkeysize_ex(const MDBX_env *env, __nothrow_pure_function LIBMDBX_API int
MDBX_db_flags_t flags); mdbx_env_get_maxkeysize_ex(const MDBX_env *env, MDBX_db_flags_t flags);
/** Get the maximum size of data we can write. /** Get the maximum size of data we can write.
* \ingroup c_statinfo * \ingroup c_statinfo
@ -2265,13 +2366,14 @@ LIBMDBX_API int mdbx_env_get_maxkeysize_ex(const MDBX_env *env,
* *
* \returns The maximum size of a data can write, * \returns The maximum size of a data can write,
* or -1 if something is wrong. */ * or -1 if something is wrong. */
LIBMDBX_API int mdbx_env_get_maxvalsize_ex(const MDBX_env *env, __nothrow_pure_function LIBMDBX_API int
MDBX_db_flags_t flags); mdbx_env_get_maxvalsize_ex(const MDBX_env *env, MDBX_db_flags_t flags);
/** \deprecated Please use \ref mdbx_env_get_maxkeysize_ex() /** \deprecated Please use \ref mdbx_env_get_maxkeysize_ex()
* and/or \ref mdbx_env_get_maxvalsize_ex() * and/or \ref mdbx_env_get_maxvalsize_ex()
* \ingroup c_statinfo */ * \ingroup c_statinfo */
MDBX_DEPRECATED LIBMDBX_API int mdbx_env_get_maxkeysize(const MDBX_env *env); __nothrow_pure_function MDBX_DEPRECATED LIBMDBX_API int
mdbx_env_get_maxkeysize(const MDBX_env *env);
/** Set application information associated with the \ref MDBX_env. /** Set application information associated with the \ref MDBX_env.
* \ingroup c_settings * \ingroup c_settings
@ -2289,7 +2391,8 @@ LIBMDBX_API int mdbx_env_set_userctx(MDBX_env *env, void *ctx);
* *
* \param [in] env An environment handle returned by \ref mdbx_env_create() * \param [in] env An environment handle returned by \ref mdbx_env_create()
* \returns The pointer set by \ref mdbx_env_set_userctx(). */ * \returns The pointer set by \ref mdbx_env_set_userctx(). */
LIBMDBX_API void *mdbx_env_get_userctx(const MDBX_env *env); __nothrow_pure_function LIBMDBX_API void *
mdbx_env_get_userctx(const MDBX_env *env);
/** Create a transaction for use with the environment. /** Create a transaction for use with the environment.
* \ingroup c_transactions * \ingroup c_transactions
@ -2414,7 +2517,7 @@ LIBMDBX_API int mdbx_txn_info(const MDBX_txn *txn, MDBX_txn_info *info,
* \ingroup c_transactions * \ingroup c_transactions
* *
* \param [in] txn A transaction handle returned by \ref mdbx_txn_begin() */ * \param [in] txn A transaction handle returned by \ref mdbx_txn_begin() */
LIBMDBX_API MDBX_env *mdbx_txn_env(const MDBX_txn *txn); __nothrow_pure_function LIBMDBX_API MDBX_env *mdbx_txn_env(const MDBX_txn *txn);
/** Return the transaction's flags. /** Return the transaction's flags.
* \ingroup c_transactions * \ingroup c_transactions
@ -2425,7 +2528,7 @@ LIBMDBX_API MDBX_env *mdbx_txn_env(const MDBX_txn *txn);
* *
* \returns A transaction flags, valid if input is an valid transaction, * \returns A transaction flags, valid if input is an valid transaction,
* otherwise -1. */ * otherwise -1. */
LIBMDBX_API int mdbx_txn_flags(const MDBX_txn *txn); __nothrow_pure_function LIBMDBX_API int mdbx_txn_flags(const MDBX_txn *txn);
/** Return the transaction's ID. /** Return the transaction's ID.
* \ingroup c_statinfo * \ingroup c_statinfo
@ -2438,7 +2541,7 @@ LIBMDBX_API int mdbx_txn_flags(const MDBX_txn *txn);
* *
* \returns A transaction ID, valid if input is an active transaction, * \returns A transaction ID, valid if input is an active transaction,
* otherwise 0. */ * otherwise 0. */
LIBMDBX_API uint64_t mdbx_txn_id(const MDBX_txn *txn); __nothrow_pure_function LIBMDBX_API uint64_t mdbx_txn_id(const MDBX_txn *txn);
/** Commit all the operations of a transaction into the database. /** Commit all the operations of a transaction into the database.
* \ingroup c_transactions * \ingroup c_transactions
@ -2748,15 +2851,28 @@ mdbx_dbi_open_ex(MDBX_txn *txn, const char *name, MDBX_db_flags_t flags,
* and IEEE754 double values in one index for JSON-numbers with restriction for * and IEEE754 double values in one index for JSON-numbers with restriction for
* integer numbers range corresponding to RFC-7159, i.e. \f$[-2^{53}+1, * integer numbers range corresponding to RFC-7159, i.e. \f$[-2^{53}+1,
* 2^{53}-1]\f$. See bottom of page 6 at https://tools.ietf.org/html/rfc7159 */ * 2^{53}-1]\f$. See bottom of page 6 at https://tools.ietf.org/html/rfc7159 */
LIBMDBX_API uint64_t mdbx_key_from_jsonInteger(const int64_t json_integer); __nothrow_const_function LIBMDBX_API uint64_t
LIBMDBX_API uint64_t mdbx_key_from_double(const double ieee754_64bit); mdbx_key_from_jsonInteger(const int64_t json_integer);
LIBMDBX_API uint64_t mdbx_key_from_ptrdouble(const double *const ieee754_64bit);
LIBMDBX_API uint32_t mdbx_key_from_float(const float ieee754_32bit); __nothrow_const_function LIBMDBX_API uint64_t
LIBMDBX_API uint32_t mdbx_key_from_ptrfloat(const float *const ieee754_32bit); mdbx_key_from_double(const double ieee754_64bit);
__inline uint64_t mdbx_key_from_int64(const int64_t i64) {
__nothrow_pure_function LIBMDBX_API uint64_t
mdbx_key_from_ptrdouble(const double *const ieee754_64bit);
__nothrow_const_function LIBMDBX_API uint32_t
mdbx_key_from_float(const float ieee754_32bit);
__nothrow_const_function LIBMDBX_API uint32_t
mdbx_key_from_ptrfloat(const float *const ieee754_32bit);
__nothrow_const_function __inline uint64_t
mdbx_key_from_int64(const int64_t i64) {
return UINT64_C(0x8000000000000000) + i64; return UINT64_C(0x8000000000000000) + i64;
} }
__inline uint32_t mdbx_key_from_int32(const int32_t i32) {
__nothrow_const_function __inline uint32_t
mdbx_key_from_int32(const int32_t i32) {
return UINT32_C(0x80000000) + i32; return UINT32_C(0x80000000) + i32;
} }
/** @} */ /** @} */
@ -2764,11 +2880,16 @@ __inline uint32_t mdbx_key_from_int32(const int32_t i32) {
/** \defgroup key2value Key-to-Value functions to avoid custom comparators /** \defgroup key2value Key-to-Value functions to avoid custom comparators
* \see value2key * \see value2key
* @{ */ * @{ */
LIBMDBX_API int64_t mdbx_jsonInteger_from_key(const MDBX_val); __nothrow_pure_function LIBMDBX_API int64_t
LIBMDBX_API double mdbx_double_from_key(const MDBX_val); mdbx_jsonInteger_from_key(const MDBX_val);
LIBMDBX_API float mdbx_float_from_key(const MDBX_val);
LIBMDBX_API int32_t mdbx_int32_from_key(const MDBX_val); __nothrow_pure_function LIBMDBX_API double mdbx_double_from_key(const MDBX_val);
LIBMDBX_API int64_t mdbx_int64_from_key(const MDBX_val);
__nothrow_pure_function LIBMDBX_API float mdbx_float_from_key(const MDBX_val);
__nothrow_pure_function LIBMDBX_API int32_t mdbx_int32_from_key(const MDBX_val);
__nothrow_pure_function LIBMDBX_API int64_t mdbx_int64_from_key(const MDBX_val);
/** @} */ /** @} */
/** Retrieve statistics for a database. /** Retrieve statistics for a database.
@ -3181,7 +3302,8 @@ LIBMDBX_API int mdbx_cursor_renew(MDBX_txn *txn, MDBX_cursor *cursor);
* \ingroup c_cursors * \ingroup c_cursors
* *
* \param [in] cursor A cursor handle returned by \ref mdbx_cursor_open(). */ * \param [in] cursor A cursor handle returned by \ref mdbx_cursor_open(). */
LIBMDBX_API MDBX_txn *mdbx_cursor_txn(const MDBX_cursor *cursor); __nothrow_pure_function LIBMDBX_API MDBX_txn *
mdbx_cursor_txn(const MDBX_cursor *cursor);
/** Return the cursor's database handle. /** Return the cursor's database handle.
* \ingroup c_cursors * \ingroup c_cursors
@ -3347,7 +3469,8 @@ LIBMDBX_API int mdbx_cursor_count(const MDBX_cursor *cursor, size_t *pcount);
* positioned * positioned
* \retval MDBX_RESULT_FALSE A data is available * \retval MDBX_RESULT_FALSE A data is available
* \retval Otherwise the error code */ * \retval Otherwise the error code */
LIBMDBX_API int mdbx_cursor_eof(const MDBX_cursor *cursor); __nothrow_pure_function LIBMDBX_API int
mdbx_cursor_eof(const MDBX_cursor *cursor);
/** Determines whether the cursor is pointed to the first key-value pair or /** Determines whether the cursor is pointed to the first key-value pair or
* not. * not.
@ -3358,9 +3481,10 @@ LIBMDBX_API int mdbx_cursor_eof(const MDBX_cursor *cursor);
* \returns A MDBX_RESULT_TRUE or MDBX_RESULT_FALSE value, * \returns A MDBX_RESULT_TRUE or MDBX_RESULT_FALSE value,
* otherwise the error code: * otherwise the error code:
* \retval MDBX_RESULT_TRUE Cursor positioned to the first key-value pair * \retval MDBX_RESULT_TRUE Cursor positioned to the first key-value pair
* \retval MDBX_RESULT_FALSE Cursor NOT positioned to the first key-value pair * \retval MDBX_RESULT_FALSE Cursor NOT positioned to the first key-value
* \retval Otherwise the error code */ * pair \retval Otherwise the error code */
LIBMDBX_API int mdbx_cursor_on_first(const MDBX_cursor *cursor); __nothrow_pure_function LIBMDBX_API int
mdbx_cursor_on_first(const MDBX_cursor *cursor);
/** Determines whether the cursor is pointed to the last key-value pair or not. /** Determines whether the cursor is pointed to the last key-value pair or not.
* \ingroup c_cursors * \ingroup c_cursors
@ -3372,7 +3496,8 @@ LIBMDBX_API int mdbx_cursor_on_first(const MDBX_cursor *cursor);
* \retval MDBX_RESULT_TRUE Cursor positioned to the last key-value pair * \retval MDBX_RESULT_TRUE Cursor positioned to the last key-value pair
* \retval MDBX_RESULT_FALSE Cursor NOT positioned to the last key-value pair * \retval MDBX_RESULT_FALSE Cursor NOT positioned to the last key-value pair
* \retval Otherwise the error code */ * \retval Otherwise the error code */
LIBMDBX_API int mdbx_cursor_on_last(const MDBX_cursor *cursor); __nothrow_pure_function LIBMDBX_API int
mdbx_cursor_on_last(const MDBX_cursor *cursor);
/** \addtogroup c_rqest /** \addtogroup c_rqest
* \details \note The estimation result varies greatly depending on the filling * \details \note The estimation result varies greatly depending on the filling
@ -3512,7 +3637,8 @@ LIBMDBX_API int mdbx_estimate_range(MDBX_txn *txn, MDBX_dbi dbi,
* \retval MDBX_RESULT_TRUE Given address is on the dirty page. * \retval MDBX_RESULT_TRUE Given address is on the dirty page.
* \retval MDBX_RESULT_FALSE Given address is NOT on the dirty page. * \retval MDBX_RESULT_FALSE Given address is NOT on the dirty page.
* \retval Otherwise the error code. */ * \retval Otherwise the error code. */
LIBMDBX_API int mdbx_is_dirty(const MDBX_txn *txn, const void *ptr); __nothrow_pure_function LIBMDBX_API int mdbx_is_dirty(const MDBX_txn *txn,
const void *ptr);
/** Sequence generation for a database. /** Sequence generation for a database.
* \ingroup c_crud * \ingroup c_crud
@ -3552,12 +3678,15 @@ LIBMDBX_API int mdbx_dbi_sequence(MDBX_txn *txn, MDBX_dbi dbi, uint64_t *result,
* \param [in] b The second item to compare. * \param [in] b The second item to compare.
* *
* \returns < 0 if a < b, 0 if a == b, > 0 if a > b */ * \returns < 0 if a < b, 0 if a == b, > 0 if a > b */
LIBMDBX_API int mdbx_cmp(const MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *a, __nothrow_pure_function LIBMDBX_API int mdbx_cmp(const MDBX_txn *txn,
const MDBX_val *b); MDBX_dbi dbi,
const MDBX_val *a,
const MDBX_val *b);
/** Returns default internal key's comparator for given database flags. /** Returns default internal key's comparator for given database flags.
* \ingroup c_extra */ * \ingroup c_extra */
LIBMDBX_API MDBX_cmp_func *mdbx_get_keycmp(MDBX_db_flags_t flags); __nothrow_const_function LIBMDBX_API MDBX_cmp_func *
mdbx_get_keycmp(MDBX_db_flags_t flags);
/** Compare two data items according to a particular database. /** Compare two data items according to a particular database.
* \ingroup c_crud * \ingroup c_crud
@ -3573,12 +3702,15 @@ LIBMDBX_API MDBX_cmp_func *mdbx_get_keycmp(MDBX_db_flags_t flags);
* \param [in] b The second item to compare. * \param [in] b The second item to compare.
* *
* \returns < 0 if a < b, 0 if a == b, > 0 if a > b */ * \returns < 0 if a < b, 0 if a == b, > 0 if a > b */
LIBMDBX_API int mdbx_dcmp(const MDBX_txn *txn, MDBX_dbi dbi, const MDBX_val *a, __nothrow_pure_function LIBMDBX_API int mdbx_dcmp(const MDBX_txn *txn,
const MDBX_val *b); MDBX_dbi dbi,
const MDBX_val *a,
const MDBX_val *b);
/** Returns default internal data's comparator for given database flags /** Returns default internal data's comparator for given database flags
* \ingroup c_extra */ * \ingroup c_extra */
LIBMDBX_API MDBX_cmp_func *mdbx_get_datacmp(MDBX_db_flags_t flags); __nothrow_const_function LIBMDBX_API MDBX_cmp_func *
mdbx_get_datacmp(MDBX_db_flags_t flags);
/** A callback function used to enumerate the reader lock table. /** A callback function used to enumerate the reader lock table.
* \ingroup c_statinfo * \ingroup c_statinfo
@ -3764,7 +3896,8 @@ LIBMDBX_API int mdbx_env_set_oomfunc(MDBX_env *env, MDBX_oom_func *oom_func);
* \param [in] env An environment handle returned by \ref mdbx_env_create(). * \param [in] env An environment handle returned by \ref mdbx_env_create().
* *
* \returns A MDBX_oom_func function or NULL if disabled. */ * \returns A MDBX_oom_func function or NULL if disabled. */
LIBMDBX_API MDBX_oom_func *mdbx_env_get_oomfunc(const MDBX_env *env); __nothrow_pure_function LIBMDBX_API MDBX_oom_func *
mdbx_env_get_oomfunc(const MDBX_env *env);
/** \defgroup btree_traversal B-tree Traversal /** \defgroup btree_traversal B-tree Traversal
* This is internal API for mdbx_chk tool. You should avoid to use it, except * This is internal API for mdbx_chk tool. You should avoid to use it, except

View File

@ -40,7 +40,7 @@
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
* Internal inlines */ * Internal inlines */
static __pure_function unsigned log2n(size_t value) { __nothrow_const_function static unsigned log2n(size_t value) {
assert(value > 0 && value < INT32_MAX && is_powerof2(value)); assert(value > 0 && value < INT32_MAX && is_powerof2(value));
assert((value & -(int32_t)value) == value); assert((value & -(int32_t)value) == value);
#if __GNUC_PREREQ(4, 1) || __has_builtin(__builtin_ctzl) #if __GNUC_PREREQ(4, 1) || __has_builtin(__builtin_ctzl)
@ -60,14 +60,14 @@ static __pure_function unsigned log2n(size_t value) {
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
* Unaligned access */ * Unaligned access */
static __pure_function __maybe_unused __always_inline unsigned __nothrow_const_function static __maybe_unused __always_inline unsigned
field_alignment(unsigned alignment_baseline, size_t field_offset) { field_alignment(unsigned alignment_baseline, size_t field_offset) {
unsigned merge = alignment_baseline | (unsigned)field_offset; unsigned merge = alignment_baseline | (unsigned)field_offset;
return merge & -(int)merge; return merge & -(int)merge;
} }
/* read-thunk for UB-sanitizer */ /* read-thunk for UB-sanitizer */
static __pure_function __always_inline uint8_t __nothrow_pure_function static __always_inline uint8_t
peek_u8(const uint8_t *const __restrict ptr) { peek_u8(const uint8_t *const __restrict ptr) {
return *ptr; return *ptr;
} }
@ -78,7 +78,7 @@ static __always_inline void poke_u8(uint8_t *const __restrict ptr,
*ptr = v; *ptr = v;
} }
static __pure_function __always_inline uint16_t __nothrow_pure_function static __always_inline uint16_t
unaligned_peek_u16(const unsigned expected_alignment, const void *const ptr) { unaligned_peek_u16(const unsigned expected_alignment, const void *const ptr) {
assert((uintptr_t)ptr % expected_alignment == 0); assert((uintptr_t)ptr % expected_alignment == 0);
if (MDBX_UNALIGNED_OK || (expected_alignment % sizeof(uint16_t)) == 0) if (MDBX_UNALIGNED_OK || (expected_alignment % sizeof(uint16_t)) == 0)
@ -100,7 +100,7 @@ unaligned_poke_u16(const unsigned expected_alignment,
memcpy(ptr, &v, sizeof(v)); memcpy(ptr, &v, sizeof(v));
} }
static __pure_function __always_inline uint32_t unaligned_peek_u32( __nothrow_pure_function static __always_inline uint32_t unaligned_peek_u32(
const unsigned expected_alignment, const void *const __restrict ptr) { const unsigned expected_alignment, const void *const __restrict ptr) {
assert((uintptr_t)ptr % expected_alignment == 0); assert((uintptr_t)ptr % expected_alignment == 0);
if (MDBX_UNALIGNED_OK || (expected_alignment % sizeof(uint32_t)) == 0) if (MDBX_UNALIGNED_OK || (expected_alignment % sizeof(uint32_t)) == 0)
@ -132,7 +132,7 @@ unaligned_poke_u32(const unsigned expected_alignment,
memcpy(ptr, &v, sizeof(v)); memcpy(ptr, &v, sizeof(v));
} }
static __pure_function __always_inline uint64_t unaligned_peek_u64( __nothrow_pure_function static __always_inline uint64_t unaligned_peek_u64(
const unsigned expected_alignment, const void *const __restrict ptr) { const unsigned expected_alignment, const void *const __restrict ptr) {
assert((uintptr_t)ptr % expected_alignment == 0); assert((uintptr_t)ptr % expected_alignment == 0);
if (MDBX_UNALIGNED_OK || (expected_alignment % sizeof(uint64_t)) == 0) if (MDBX_UNALIGNED_OK || (expected_alignment % sizeof(uint64_t)) == 0)
@ -185,7 +185,7 @@ unaligned_poke_u64(const unsigned expected_alignment,
unaligned_poke_u64(1, (char *)(ptr) + offsetof(struct, field), value) unaligned_poke_u64(1, (char *)(ptr) + offsetof(struct, field), value)
/* Get the page number pointed to by a branch node */ /* Get the page number pointed to by a branch node */
static __pure_function __always_inline pgno_t __nothrow_pure_function static __always_inline pgno_t
node_pgno(const MDBX_node *const __restrict node) { node_pgno(const MDBX_node *const __restrict node) {
pgno_t pgno = UNALIGNED_PEEK_32(node, MDBX_node, mn_pgno32); pgno_t pgno = UNALIGNED_PEEK_32(node, MDBX_node, mn_pgno32);
if (sizeof(pgno) > 4) if (sizeof(pgno) > 4)
@ -205,7 +205,7 @@ static __always_inline void node_set_pgno(MDBX_node *const __restrict node,
} }
/* Get the size of the data in a leaf node */ /* Get the size of the data in a leaf node */
static __pure_function __always_inline size_t __nothrow_pure_function static __always_inline size_t
node_ds(const MDBX_node *const __restrict node) { node_ds(const MDBX_node *const __restrict node) {
return UNALIGNED_PEEK_32(node, MDBX_node, mn_dsize); return UNALIGNED_PEEK_32(node, MDBX_node, mn_dsize);
} }
@ -218,7 +218,7 @@ static __always_inline void node_set_ds(MDBX_node *const __restrict node,
} }
/* The size of a key in a node */ /* The size of a key in a node */
static __pure_function __always_inline size_t __nothrow_pure_function static __always_inline size_t
node_ks(const MDBX_node *const __restrict node) { node_ks(const MDBX_node *const __restrict node) {
return UNALIGNED_PEEK_16(node, MDBX_node, mn_ksize); return UNALIGNED_PEEK_16(node, MDBX_node, mn_ksize);
} }
@ -230,7 +230,7 @@ static __always_inline void node_set_ks(MDBX_node *const __restrict node,
UNALIGNED_POKE_16(node, MDBX_node, mn_ksize, (uint16_t)size); UNALIGNED_POKE_16(node, MDBX_node, mn_ksize, (uint16_t)size);
} }
static __pure_function __always_inline uint8_t __nothrow_pure_function static __always_inline uint8_t
node_flags(const MDBX_node *const __restrict node) { node_flags(const MDBX_node *const __restrict node) {
return UNALIGNED_PEEK_8(node, MDBX_node, mn_flags); return UNALIGNED_PEEK_8(node, MDBX_node, mn_flags);
} }
@ -244,29 +244,29 @@ static __always_inline void node_set_flags(MDBX_node *const __restrict node,
#define NODESIZE offsetof(MDBX_node, mn_data) #define NODESIZE offsetof(MDBX_node, mn_data)
/* Address of the key for the node */ /* Address of the key for the node */
static __pure_function __always_inline void * __nothrow_pure_function static __always_inline void *
node_key(const MDBX_node *const __restrict node) { node_key(const MDBX_node *const __restrict node) {
return (char *)node + NODESIZE; return (char *)node + NODESIZE;
} }
/* Address of the data for a node */ /* Address of the data for a node */
static __pure_function __always_inline void * __nothrow_pure_function static __always_inline void *
node_data(const MDBX_node *const __restrict node) { node_data(const MDBX_node *const __restrict node) {
return (char *)node_key(node) + node_ks(node); return (char *)node_key(node) + node_ks(node);
} }
/* Size of a node in a leaf page with a given key and data. /* Size of a node in a leaf page with a given key and data.
* This is node header plus key plus data size. */ * This is node header plus key plus data size. */
static __pure_function __always_inline size_t __nothrow_const_function static __always_inline size_t
node_size_len(const size_t key_len, const size_t value_len) { node_size_len(const size_t key_len, const size_t value_len) {
return NODESIZE + EVEN(key_len + value_len); return NODESIZE + EVEN(key_len + value_len);
} }
static __pure_function __always_inline size_t node_size(const MDBX_val *key, __nothrow_pure_function static __always_inline size_t
const MDBX_val *value) { node_size(const MDBX_val *key, const MDBX_val *value) {
return node_size_len(key ? key->iov_len : 0, value ? value->iov_len : 0); return node_size_len(key ? key->iov_len : 0, value ? value->iov_len : 0);
} }
static __pure_function __always_inline pgno_t __nothrow_pure_function static __always_inline pgno_t
peek_pgno(const void *const __restrict ptr) { peek_pgno(const void *const __restrict ptr) {
if (sizeof(pgno_t) == sizeof(uint32_t)) if (sizeof(pgno_t) == sizeof(uint32_t))
return (pgno_t)unaligned_peek_u32(1, ptr); return (pgno_t)unaligned_peek_u32(1, ptr);
@ -289,7 +289,7 @@ static __always_inline void poke_pgno(void *const __restrict ptr,
memcpy(ptr, &pgno, sizeof(pgno)); memcpy(ptr, &pgno, sizeof(pgno));
} }
static __pure_function __always_inline pgno_t __nothrow_pure_function static __always_inline pgno_t
node_largedata_pgno(const MDBX_node *const __restrict node) { node_largedata_pgno(const MDBX_node *const __restrict node) {
assert(node_flags(node) & F_BIGDATA); assert(node_flags(node) & F_BIGDATA);
return peek_pgno(node_data(node)); return peek_pgno(node_data(node));
@ -411,9 +411,8 @@ __cold intptr_t mdbx_limits_valsize_max(intptr_t pagesize,
* size will only include the key and not the data. Sizes are always * size will only include the key and not the data. Sizes are always
* rounded up to an even number of bytes, to guarantee 2-byte alignment * rounded up to an even number of bytes, to guarantee 2-byte alignment
* of the MDBX_node headers. */ * of the MDBX_node headers. */
static __pure_function __always_inline size_t leaf_size(const MDBX_env *env, __nothrow_pure_function static __always_inline size_t
const MDBX_val *key, leaf_size(const MDBX_env *env, const MDBX_val *key, const MDBX_val *data) {
const MDBX_val *data) {
size_t node_bytes = node_size(key, data); size_t node_bytes = node_size(key, data);
/* NOTE: The actual limit is LEAF_NODEMAX(env->me_psize), but it reasonable to /* NOTE: The actual limit is LEAF_NODEMAX(env->me_psize), but it reasonable to
* use env->me_branch_nodemax (which is 3 times less) as the treshold because: * use env->me_branch_nodemax (which is 3 times less) as the treshold because:
@ -455,8 +454,8 @@ static __pure_function __always_inline size_t leaf_size(const MDBX_env *env,
* [in] key The key for the node. * [in] key The key for the node.
* *
* Returns The number of bytes needed to store the node. */ * Returns The number of bytes needed to store the node. */
static __pure_function __always_inline size_t branch_size(const MDBX_env *env, __nothrow_pure_function static __always_inline size_t
const MDBX_val *key) { branch_size(const MDBX_env *env, const MDBX_val *key) {
/* Size of a node in a branch page with a given key. /* Size of a node in a branch page with a given key.
* This is just the node header plus the key, there is no data. */ * This is just the node header plus the key, there is no data. */
size_t node_bytes = node_size(key, nullptr); size_t node_bytes = node_size(key, nullptr);
@ -471,7 +470,7 @@ static __pure_function __always_inline size_t branch_size(const MDBX_env *env,
return node_bytes + sizeof(indx_t); return node_bytes + sizeof(indx_t);
} }
static __pure_function __always_inline uint16_t __nothrow_const_function static __always_inline uint16_t
flags_db2sub(uint16_t db_flags) { flags_db2sub(uint16_t db_flags) {
uint16_t sub_flags = db_flags & MDBX_DUPFIXED; uint16_t sub_flags = db_flags & MDBX_DUPFIXED;
@ -492,81 +491,84 @@ flags_db2sub(uint16_t db_flags) {
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
static __pure_function __always_inline size_t pgno2bytes(const MDBX_env *env, __nothrow_pure_function static __always_inline size_t
pgno_t pgno) { pgno2bytes(const MDBX_env *env, pgno_t pgno) {
mdbx_assert(env, (1u << env->me_psize2log) == env->me_psize); mdbx_assert(env, (1u << env->me_psize2log) == env->me_psize);
return ((size_t)pgno) << env->me_psize2log; return ((size_t)pgno) << env->me_psize2log;
} }
static __pure_function __always_inline MDBX_page *pgno2page(const MDBX_env *env, __nothrow_pure_function static __always_inline MDBX_page *
pgno_t pgno) { pgno2page(const MDBX_env *env, pgno_t pgno) {
return (MDBX_page *)(env->me_map + pgno2bytes(env, pgno)); return (MDBX_page *)(env->me_map + pgno2bytes(env, pgno));
} }
static __pure_function __always_inline pgno_t bytes2pgno(const MDBX_env *env, __nothrow_pure_function static __always_inline pgno_t
size_t bytes) { bytes2pgno(const MDBX_env *env, size_t bytes) {
mdbx_assert(env, (env->me_psize >> env->me_psize2log) == 1); mdbx_assert(env, (env->me_psize >> env->me_psize2log) == 1);
return (pgno_t)(bytes >> env->me_psize2log); return (pgno_t)(bytes >> env->me_psize2log);
} }
static __pure_function size_t pgno_align2os_bytes(const MDBX_env *env, __nothrow_pure_function static size_t pgno_align2os_bytes(const MDBX_env *env,
pgno_t pgno) { pgno_t pgno) {
return ceil_powerof2(pgno2bytes(env, pgno), env->me_os_psize); return ceil_powerof2(pgno2bytes(env, pgno), env->me_os_psize);
} }
static __pure_function pgno_t pgno_align2os_pgno(const MDBX_env *env, __nothrow_pure_function static pgno_t pgno_align2os_pgno(const MDBX_env *env,
pgno_t pgno) { pgno_t pgno) {
return bytes2pgno(env, pgno_align2os_bytes(env, pgno)); return bytes2pgno(env, pgno_align2os_bytes(env, pgno));
} }
static __pure_function size_t bytes_align2os_bytes(const MDBX_env *env, __nothrow_pure_function static size_t bytes_align2os_bytes(const MDBX_env *env,
size_t bytes) { size_t bytes) {
return ceil_powerof2(ceil_powerof2(bytes, env->me_psize), env->me_os_psize); return ceil_powerof2(ceil_powerof2(bytes, env->me_psize), env->me_os_psize);
} }
/* Address of first usable data byte in a page, after the header */ /* Address of first usable data byte in a page, after the header */
static __pure_function __always_inline void *page_data(const MDBX_page *mp) { __nothrow_pure_function static __always_inline void *
page_data(const MDBX_page *mp) {
return (char *)mp + PAGEHDRSZ; return (char *)mp + PAGEHDRSZ;
} }
static __pure_function __always_inline const MDBX_page * __nothrow_pure_function static __always_inline const MDBX_page *
data_page(const void *data) { data_page(const void *data) {
return container_of(data, MDBX_page, mp_ptrs); return container_of(data, MDBX_page, mp_ptrs);
} }
static __pure_function __always_inline MDBX_meta *page_meta(MDBX_page *mp) { __nothrow_pure_function static __always_inline MDBX_meta *
page_meta(MDBX_page *mp) {
return (MDBX_meta *)page_data(mp); return (MDBX_meta *)page_data(mp);
} }
/* Number of nodes on a page */ /* Number of nodes on a page */
static __pure_function __always_inline unsigned __nothrow_pure_function static __always_inline unsigned
page_numkeys(const MDBX_page *mp) { page_numkeys(const MDBX_page *mp) {
return mp->mp_lower >> 1; return mp->mp_lower >> 1;
} }
/* The amount of space remaining in the page */ /* The amount of space remaining in the page */
static __pure_function __always_inline unsigned page_room(const MDBX_page *mp) { __nothrow_pure_function static __always_inline unsigned
page_room(const MDBX_page *mp) {
return mp->mp_upper - mp->mp_lower; return mp->mp_upper - mp->mp_lower;
} }
static __pure_function __always_inline unsigned __nothrow_pure_function static __always_inline unsigned
page_space(const MDBX_env *env) { page_space(const MDBX_env *env) {
STATIC_ASSERT(PAGEHDRSZ % 2 == 0); STATIC_ASSERT(PAGEHDRSZ % 2 == 0);
return env->me_psize - PAGEHDRSZ; return env->me_psize - PAGEHDRSZ;
} }
static __pure_function __always_inline unsigned page_used(const MDBX_env *env, __nothrow_pure_function static __always_inline unsigned
const MDBX_page *mp) { page_used(const MDBX_env *env, const MDBX_page *mp) {
return page_space(env) - page_room(mp); return page_space(env) - page_room(mp);
} }
/* The percentage of space used in the page, in a percents. */ /* The percentage of space used in the page, in a percents. */
static __pure_function __maybe_unused __inline double __nothrow_pure_function static __maybe_unused __inline double
page_fill(const MDBX_env *env, const MDBX_page *mp) { page_fill(const MDBX_env *env, const MDBX_page *mp) {
return page_used(env, mp) * 100.0 / page_space(env); return page_used(env, mp) * 100.0 / page_space(env);
} }
static __pure_function __inline bool __nothrow_pure_function static __inline bool
page_fill_enough(const MDBX_page *mp, unsigned spaceleft_threshold, page_fill_enough(const MDBX_page *mp, unsigned spaceleft_threshold,
unsigned minkeys_threshold) { unsigned minkeys_threshold) {
return page_room(mp) < spaceleft_threshold && return page_room(mp) < spaceleft_threshold &&
@ -574,14 +576,14 @@ page_fill_enough(const MDBX_page *mp, unsigned spaceleft_threshold,
} }
/* The number of overflow pages needed to store the given size. */ /* The number of overflow pages needed to store the given size. */
static __pure_function __always_inline pgno_t __nothrow_pure_function static __always_inline pgno_t
number_of_ovpages(const MDBX_env *env, size_t bytes) { number_of_ovpages(const MDBX_env *env, size_t bytes) {
return bytes2pgno(env, PAGEHDRSZ - 1 + bytes) + 1; return bytes2pgno(env, PAGEHDRSZ - 1 + bytes) + 1;
} }
/* Address of node i in page p */ /* Address of node i in page p */
static __pure_function __always_inline MDBX_node *page_node(const MDBX_page *mp, __nothrow_pure_function static __always_inline MDBX_node *
unsigned i) { page_node(const MDBX_page *mp, unsigned i) {
assert((mp->mp_flags & (P_LEAF2 | P_OVERFLOW | P_META)) == 0); assert((mp->mp_flags & (P_LEAF2 | P_OVERFLOW | P_META)) == 0);
assert(page_numkeys(mp) > (unsigned)(i)); assert(page_numkeys(mp) > (unsigned)(i));
assert(mp->mp_ptrs[i] % 2 == 0); assert(mp->mp_ptrs[i] % 2 == 0);
@ -591,7 +593,7 @@ static __pure_function __always_inline MDBX_node *page_node(const MDBX_page *mp,
/* The address of a key in a LEAF2 page. /* The address of a key in a LEAF2 page.
* LEAF2 pages are used for MDBX_DUPFIXED sorted-duplicate sub-DBs. * LEAF2 pages are used for MDBX_DUPFIXED sorted-duplicate sub-DBs.
* There are no node headers, keys are stored contiguously. */ * There are no node headers, keys are stored contiguously. */
static __pure_function __always_inline void * __nothrow_pure_function static __always_inline void *
page_leaf2key(const MDBX_page *mp, unsigned i, size_t keysize) { page_leaf2key(const MDBX_page *mp, unsigned i, size_t keysize) {
assert((mp->mp_flags & (P_BRANCH | P_LEAF | P_LEAF2 | P_OVERFLOW | P_META)) == assert((mp->mp_flags & (P_BRANCH | P_LEAF | P_LEAF2 | P_OVERFLOW | P_META)) ==
(P_LEAF | P_LEAF2)); (P_LEAF | P_LEAF2));
@ -1362,7 +1364,7 @@ static __inline void lcklist_unlock(void) {
#endif #endif
} }
static uint64_t rrxmrrxmsx_0(uint64_t v) { __nothrow_const_function static uint64_t rrxmrrxmsx_0(uint64_t v) {
/* Pelle Evensen's mixer, https://bit.ly/2HOfynt */ /* Pelle Evensen's mixer, https://bit.ly/2HOfynt */
v ^= (v << 39 | v >> 25) ^ (v << 14 | v >> 50); v ^= (v << 39 | v >> 25) ^ (v << 14 | v >> 50);
v *= UINT64_C(0xA24BAED4963EE407); v *= UINT64_C(0xA24BAED4963EE407);

View File

@ -43,22 +43,6 @@
# endif # endif
#endif /* __GLIBC_PREREQ */ #endif /* __GLIBC_PREREQ */
#ifndef __has_attribute
# define __has_attribute(x) (0)
#endif
#ifndef __has_feature
# define __has_feature(x) (0)
#endif
#ifndef __has_extension
# define __has_extension(x) (0)
#endif
#ifndef __has_builtin
# define __has_builtin(x) (0)
#endif
#ifndef __has_warning #ifndef __has_warning
# define __has_warning(x) (0) # define __has_warning(x) (0)
#endif #endif
@ -67,10 +51,6 @@
# define __has_include(x) (0) # define __has_include(x) (0)
#endif #endif
#ifndef __has_cpp_attribute
# define __has_cpp_attribute(x) (0)
#endif
#if __has_feature(thread_sanitizer) #if __has_feature(thread_sanitizer)
# define __SANITIZE_THREAD__ 1 # define __SANITIZE_THREAD__ 1
#endif #endif
@ -196,40 +176,6 @@
# endif # endif
#endif /* __nothrow */ #endif /* __nothrow */
#ifndef __pure_function
/* Many functions have no effects except the return value and their
* return value depends only on the parameters and/or global variables.
* Such a function can be subject to common subexpression elimination
* and loop optimization just as an arithmetic operator would be.
* These functions should be declared with the attribute pure. */
# if (defined(__GNUC__) || __has_attribute(__pure__)) && \
(!defined(__clang__) /* https://bugs.llvm.org/show_bug.cgi?id=43275 */ \
|| !defined(__cplusplus) || !__has_feature(cxx_exceptions))
# define __pure_function __attribute__((__pure__))
# else
# define __pure_function
# endif
#endif /* __pure_function */
#ifndef __const_function
/* Many functions do not examine any values except their arguments,
* and have no effects except the return value. Basically this is just
* slightly more strict class than the PURE attribute, since function
* is not allowed to read global memory.
*
* Note that a function that has pointer arguments and examines the
* data pointed to must not be declared const. Likewise, a function
* that calls a non-const function usually must not be const.
* It does not make sense for a const function to return void. */
# if (defined(__GNUC__) || __has_attribute(__pure__)) && \
(!defined(__clang__) /* https://bugs.llvm.org/show_bug.cgi?id=43275 */ \
|| !defined(__cplusplus) || !__has_feature(cxx_exceptions))
# define __const_function __attribute__((__const__))
# else
# define __const_function
# endif
#endif /* __const_function */
#ifndef __hidden #ifndef __hidden
# if defined(__GNUC__) || __has_attribute(__visibility__) # if defined(__GNUC__) || __has_attribute(__visibility__)
# define __hidden __attribute__((__visibility__("hidden"))) # define __hidden __attribute__((__visibility__("hidden")))

View File

@ -1354,12 +1354,14 @@ typedef struct MDBX_node {
/* Do not spill pages to disk if txn is getting full, may fail instead */ /* Do not spill pages to disk if txn is getting full, may fail instead */
#define MDBX_NOSPILL 0x8000 #define MDBX_NOSPILL 0x8000
static __maybe_unused __inline pgno_t pgno_add(pgno_t base, pgno_t augend) { __nothrow_const_function static __maybe_unused __inline pgno_t
pgno_add(pgno_t base, pgno_t augend) {
assert(base <= MAX_PAGENO); assert(base <= MAX_PAGENO);
return (augend < MAX_PAGENO - base) ? base + augend : MAX_PAGENO; return (augend < MAX_PAGENO - base) ? base + augend : MAX_PAGENO;
} }
static __maybe_unused __inline pgno_t pgno_sub(pgno_t base, pgno_t subtrahend) { __nothrow_const_function static __maybe_unused __inline pgno_t
pgno_sub(pgno_t base, pgno_t subtrahend) {
assert(base >= MIN_PAGENO); assert(base >= MIN_PAGENO);
return (subtrahend < base - MIN_PAGENO) ? base - subtrahend : MIN_PAGENO; return (subtrahend < base - MIN_PAGENO) ? base - subtrahend : MIN_PAGENO;
} }
@ -1373,18 +1375,18 @@ static __maybe_unused __inline void mdbx_jitter4testing(bool tiny) {
#endif #endif
} }
static __pure_function __always_inline __maybe_unused bool __nothrow_const_function static __always_inline __maybe_unused bool
is_powerof2(size_t x) { is_powerof2(size_t x) {
return (x & (x - 1)) == 0; return (x & (x - 1)) == 0;
} }
static __pure_function __always_inline __maybe_unused size_t __nothrow_const_function static __always_inline __maybe_unused size_t
floor_powerof2(size_t value, size_t granularity) { floor_powerof2(size_t value, size_t granularity) {
assert(is_powerof2(granularity)); assert(is_powerof2(granularity));
return value & ~(granularity - 1); return value & ~(granularity - 1);
} }
static __pure_function __always_inline __maybe_unused size_t __nothrow_const_function static __always_inline __maybe_unused size_t
ceil_powerof2(size_t value, size_t granularity) { ceil_powerof2(size_t value, size_t granularity) {
return floor_powerof2(value + granularity - 1, granularity); return floor_powerof2(value + granularity - 1, granularity);
} }

View File

@ -511,7 +511,8 @@ MDBX_INTERNAL_VAR bool
/* Get the size of a memory page for the system. /* Get the size of a memory page for the system.
* This is the basic size that the platform's memory manager uses, and is * This is the basic size that the platform's memory manager uses, and is
* fundamental to the use of memory-mapped files. */ * fundamental to the use of memory-mapped files. */
static __maybe_unused __inline size_t mdbx_syspagesize(void) { __nothrow_const_function static __maybe_unused __inline size_t
mdbx_syspagesize(void) {
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
SYSTEM_INFO si; SYSTEM_INFO si;
GetSystemInfo(&si); GetSystemInfo(&si);