Port B+TREE to new memory model

This commit is contained in:
Patrick Pelissier committed 2025-05-07 21:02:23 +02:00
1 parent 6e828eabaf
commit bcc9f2c894
2 files changed
+85 -81

No files matched your search

+71 -71
View File
@@ -343,6 +343,7 @@
M_BPTR33_DEF_IT(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t) \ M_BPTR33_DEF_IT(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t) \
M_BPTR33_DEF_EXT(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t) \ M_BPTR33_DEF_EXT(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t) \
M_EMPLACE_ASS_ARRAY_OR_QUEUE_DEF(M_INV(isMap), name, tree_t, key_oplist, value_oplist) M_EMPLACE_ASS_ARRAY_OR_QUEUE_DEF(M_INV(isMap), name, tree_t, key_oplist, value_oplist)
/* TODO: Check if key type has not disabled INIT_MOVE */
/* Define the types of a B+Tree */ /* Define the types of a B+Tree */
#define M_BPTR33_DEF_TYPE(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t) \ #define M_BPTR33_DEF_TYPE(name, N, key_t, key_oplist, value_t, value_oplist, isMap, isMulti, tree_t, node_t, pit_t, it_t, subtype_t) \
@@ -406,7 +407,7 @@
\ \
/* Allocate a new node */ \ /* Allocate a new node */ \
/* TODO: Can be specialized to alloc for leaf or for non leaf */ \ /* TODO: Can be specialized to alloc for leaf or for non leaf */ \
M_INLINE node_t M_F(name, _new_node)(void) \ M_INLINE node_t M_F(name, _new_node)(M_P_EXPAND_void) \
{ \ { \
M_STATIC_ASSERT(N >= 2, M_LIB_ILLEGAL_PARAM, \ M_STATIC_ASSERT(N >= 2, M_LIB_ILLEGAL_PARAM, \
"Number of items per node shall be >= 2."); \ "Number of items per node shall be >= 2."); \
@@ -420,9 +421,9 @@
return n; \ return n; \
} \ } \
\ \
M_INLINE void M_F(name, _init)(tree_t b) \ M_P(void, name, _init, tree_t b) \
{ \ { \
b->root = M_F(name, _new_node)(); \ b->root = M_F(name, _new_node)(M_R_EXPAND_void); \
b->size = 0; \ b->size = 0; \
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \ M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
} \ } \
@@ -443,7 +444,7 @@
return num; \ return num; \
} \ } \
\ \
M_INLINE void M_F(name, _reset)(tree_t b) \ M_P(void, name, _reset, tree_t b) \
{ \ { \
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \ M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
node_t next, n = b->root; \ node_t next, n = b->root; \
@@ -486,19 +487,19 @@
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \ M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
} \ } \
\ \
M_INLINE void M_F(name, _clear)(tree_t b) \ M_P(void, name, _clear, tree_t b) \
{ \ { \
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \ M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
M_F(name, _reset)(b); \ M_F(name, _reset)M_R(b); \
/* Once the tree is clean, only the root remains */ \ /* Once the tree is clean, only the root remains */ \
M_CALL_DEL(key_oplist, b->root); \ M_CALL_DEL(key_oplist, b->root); \
b->root = NULL; \ b->root = NULL; \
} \ } \
\ \
/* Copy recursively the node 'o' of root node 'root' */ \ /* Copy recursively the node 'o' of root node 'root' */ \
M_INLINE node_t M_F(name, _copy_node)(const node_t o, const node_t root) \ M_P(node_t, name, _copy_node, const node_t o, const node_t root) \
{ \ { \
node_t n = M_F(name, _new_node)(); \ node_t n = M_F(name, _new_node)(M_R_EXPAND_void); \
/* Set default number of keys and type to copy */ \ /* Set default number of keys and type to copy */ \
n->num = o->num; \ n->num = o->num; \
/* By default it is not linked to its brother. \ /* By default it is not linked to its brother. \
@@ -520,7 +521,7 @@
/* Copy recursively the associated nodes if it is not a leaf */ \ /* Copy recursively the associated nodes if it is not a leaf */ \
for(int i = 0; i <= num; i++) { \ for(int i = 0; i <= num; i++) { \
M_ASSERT(o->kind.node[i] != root); \ M_ASSERT(o->kind.node[i] != root); \
n->kind.node[i] = M_F(name, _copy_node)(o->kind.node[i], root); \ n->kind.node[i] = M_F(name, _copy_node)M_R(o->kind.node[i], root); \
} \ } \
/* The copied nodes don't have their next field correct */ \ /* The copied nodes don't have their next field correct */ \
/* Fix the next field for the copied nodes */ \ /* Fix the next field for the copied nodes */ \
@@ -542,22 +543,22 @@
return n; \ return n; \
} \ } \
\ \
M_INLINE void M_F(name, _init_set)(tree_t b, const tree_t o) \ M_P(void, name, _init_set, tree_t b, const tree_t o) \
{ \ { \
M_BPTR33_CONTRACT(N, isMulti, key_oplist, o); \ M_BPTR33_CONTRACT(N, isMulti, key_oplist, o); \
M_ASSERT (b != NULL); \ M_ASSERT (b != NULL); \
/* Just copy recursively the root node */ \ /* Just copy recursively the root node */ \
b->root = M_F(name, _copy_node)(o->root, o->root); \ b->root = M_F(name, _copy_node)M_R(o->root, o->root); \
b->size = o->size; \ b->size = o->size; \
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \ M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
} \ } \
\ \
M_INLINE void M_F(name, _set)(tree_t b, const tree_t o) \ M_P(void, name, _set, tree_t b, const tree_t o) \
{ \ { \
/* NOTE: We could reuse the already allocated nodes of 'b'. \ /* NOTE: We could reuse the already allocated nodes of 'b'. \
Not sure if it worth the effort */ \ Not sure if it worth the effort */ \
M_F(name, _clear)(b); \ M_F(name, _clear)M_R(b); \
M_F(name, _init_set)(b, o); \ M_F(name, _init_set)M_R(b, o); \
} \ } \
\ \
M_INLINE bool M_F(name, _empty_p)(const tree_t b) \ M_INLINE bool M_F(name, _empty_p)(const tree_t b) \
@@ -573,7 +574,7 @@
return b->size; \ return b->size; \
} \ } \
\ \
M_INLINE node_t M_F(name, _search_for_leaf)(pit_t pit, const tree_t b, key_t const key) \ M_INLINE node_t M_F(name, _i_search_for_leaf)(pit_t pit, const tree_t b, key_t const key) \
{ \ { \
node_t n = b->root; \ node_t n = b->root; \
int np = 0; \ int np = 0; \
@@ -607,7 +608,7 @@
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \ M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
pit_t pit; \ pit_t pit; \
/* Get the leaf node where the key can be */ \ /* Get the leaf node where the key can be */ \
node_t n = M_F(name, _search_for_leaf)(pit, b, key); \ node_t n = M_F(name, _i_search_for_leaf)(pit, b, key); \
int cmp = 0; \ int cmp = 0; \
M_BPTR33_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \ M_BPTR33_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \
/* Search in the leaf for key */ \ /* Search in the leaf for key */ \
@@ -627,11 +628,11 @@
return M_CONST_CAST(value_t, M_F(name, _get)(b, key)); \ return M_CONST_CAST(value_t, M_F(name, _get)(b, key)); \
} \ } \
\ \
M_INLINE int \ M_P(int, name, _i_search_and_insert_in_leaf, node_t n, key_t const key \
M_F(name, _search_and_insert_in_leaf)(node_t n, key_t const key \
M_IF(isMap)( M_DEFERRED_COMMA value_t const value,) ) \ M_IF(isMap)( M_DEFERRED_COMMA value_t const value,) ) \
{ \ { \
M_ASSERT (M_F(name, _is_leaf)(n)); \ M_ASSERT (M_F(name, _is_leaf)(n)); \
M_ASSERT_POOL(); \
int i, num = M_F(name, _get_num)(n); \ int i, num = M_F(name, _get_num)(n); \
M_ASSERT (num <= N); \ M_ASSERT (num <= N); \
/* Search for the key in the node n (a leaf) for insertion */ \ /* Search for the key in the node n (a leaf) for insertion */ \
@@ -659,10 +660,10 @@
return i; \ return i; \
} \ } \
\ \
M_INLINE int \ M_P(int, name, _i_search_and_insert_in_node, node_t n, node_t l, key_t key) \
M_F(name, _search_and_insert_in_node)(node_t n, node_t l, key_t key) \
{ \ { \
M_ASSERT (!M_F(name, _is_leaf)(n)); \ M_ASSERT (!M_F(name, _is_leaf)(n)); \
M_ASSERT_POOL(); \
int i, num = M_F(name, _get_num)(n); \ int i, num = M_F(name, _get_num)(n); \
M_ASSERT (num <= N); \ M_ASSERT (num <= N); \
/* Search for the key in the node n (not a leaf) for insertion */ \ /* Search for the key in the node n (not a leaf) for insertion */ \
@@ -682,16 +683,16 @@
return i; \ return i; \
} \ } \
\ \
M_INLINE void \ M_IF(isMap)( \
M_IF(isMap)(M_F(name, _set_at),M_F(name,_push))(tree_t b, key_t const key \ M_P(void, name, _set_at, tree_t b, key_t const key, value_t const value) , \
M_IF(isMap)(M_DEFERRED_COMMA value_t const value,)) \ M_P(void, name, _push, tree_t b, key_t const key) ) \
{ \ { \
pit_t pit; \ pit_t pit; \
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \ M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
node_t leaf = M_F(name, _search_for_leaf)(pit, b, key); \ node_t leaf = M_F(name, _i_search_for_leaf)(pit, b, key); \
/* Insert key into the leaf.*/ \ /* Insert key into the leaf.*/ \
/* NOTE: Even if there is N elements, we can still add one more.*/ \ /* NOTE: Even if there is N elements, we can still add one more.*/ \
int i = M_F(name, _search_and_insert_in_leaf)(leaf, key M_IF (isMap)(M_DEFERRED_COMMA value,)); \ int i = M_F(name, _i_search_and_insert_in_leaf)M_R(leaf, key M_IF (isMap)(M_DEFERRED_COMMA value,)); \
if (i < 0) { \ if (i < 0) { \
/* Nothing to do anymore. key already exists in the tree. \ /* Nothing to do anymore. key already exists in the tree. \
value has been updated if needed */ \ value has been updated if needed */ \
@@ -713,7 +714,7 @@
/* leaf is full: need to slip the leaf in two */ \ /* leaf is full: need to slip the leaf in two */ \
int nnum = (N + 1) / 2; \ int nnum = (N + 1) / 2; \
num = N + 1 - nnum; \ num = N + 1 - nnum; \
node_t nleaf = M_F(name, _new_node)(); \ node_t nleaf = M_F(name, _new_node)(M_R_EXPAND_void); \
/* Move half objects to the new node */ \ /* Move half objects to the new node */ \
memmove(&nleaf->key[0], &leaf->key[num], sizeof(key_t)*(unsigned int)nnum); \ memmove(&nleaf->key[0], &leaf->key[num], sizeof(key_t)*(unsigned int)nnum); \
M_IF(isMap)(memmove(&nleaf->kind.value[0], &leaf->kind.value[num], sizeof(value_t)*(unsigned int)nnum);,) \ M_IF(isMap)(memmove(&nleaf->kind.value[0], &leaf->kind.value[num], sizeof(value_t)*(unsigned int)nnum);,) \
@@ -728,7 +729,7 @@
while (true) { \ while (true) { \
if (pit->num == 0) { \ if (pit->num == 0) { \
/* We reach root ==> Need to increase the height of the tree.*/ \ /* We reach root ==> Need to increase the height of the tree.*/ \
node_t parent = M_F(name, _new_node)(); \ node_t parent = M_F(name, _new_node)(M_R_EXPAND_void); \
parent->num = 1; \ parent->num = 1; \
/* TBC: DO_INIT_MOVE instead ? If key was in a node !*/ \ /* TBC: DO_INIT_MOVE instead ? If key was in a node !*/ \
M_CALL_INIT_SET(key_oplist, parent->key[0], *key_ptr); \ M_CALL_INIT_SET(key_oplist, parent->key[0], *key_ptr); \
@@ -741,7 +742,7 @@
/* Non root node. Get the parent node */ \ /* Non root node. Get the parent node */ \
node_t parent = pit->parent[--pit->num]; \ node_t parent = pit->parent[--pit->num]; \
/* Insert into parent (It is big enough to receive temporary one more) */ \ /* Insert into parent (It is big enough to receive temporary one more) */ \
i = M_F(name, _search_and_insert_in_node)(parent, leaf, *key_ptr); \ i = M_F(name, _i_search_and_insert_in_node)M_R(parent, leaf, *key_ptr); \
parent->kind.node[i] = leaf; \ parent->kind.node[i] = leaf; \
parent->kind.node[i+1] = nleaf; \ parent->kind.node[i+1] = nleaf; \
/* Test if parent node is full? */ \ /* Test if parent node is full? */ \
@@ -754,7 +755,7 @@
int nnp = N / 2; \ int nnp = N / 2; \
int np = N - nnp; \ int np = N - nnp; \
M_ASSERT (nnp > 0 && np > 0 && nnp+np+1 == N+1); \ M_ASSERT (nnp > 0 && np > 0 && nnp+np+1 == N+1); \
node_t nparent = M_F(name, _new_node)(); \ node_t nparent = M_F(name, _new_node)(M_R_EXPAND_void); \
/* Move half items to new node (Like a classic B-TREE) \ /* Move half items to new node (Like a classic B-TREE) \
and the median key to the grand-parent*/ \ and the median key to the grand-parent*/ \
memmove(&nparent->key[0], &parent->key[np+1], sizeof(key_t)*(unsigned int)nnp); \ memmove(&nparent->key[0], &parent->key[np+1], sizeof(key_t)*(unsigned int)nnp); \
@@ -772,7 +773,7 @@
} \ } \
} \ } \
\ \
M_INLINE value_t *M_F(name, _safe_get)(tree_t b, key_t const key) \ M_P(value_t *, name, _safe_get, tree_t b, key_t const key) \
{ \ { \
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \ M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
/* Not optimized implementation */ \ /* Not optimized implementation */ \
@@ -781,7 +782,7 @@
M_IF(isMap)( \ M_IF(isMap)( \
value_t v; \ value_t v; \
M_CALL_INIT(value_oplist, v); \ M_CALL_INIT(value_oplist, v); \
M_F(name, _set_at)(b, key, v); \ M_F(name, _set_at)M_R(b, key, v); \
M_CALL_CLEAR(value_oplist, v); \ M_CALL_CLEAR(value_oplist, v); \
, \ , \
M_F(name, _push)(b, key); \ M_F(name, _push)(b, key); \
@@ -791,10 +792,10 @@
return ret; \ return ret; \
} \ } \
\ \
M_INLINE int \ M_P(int, name, _i_search_and_remove_in_leaf, node_t n, key_t const key) \
M_F(name, _search_and_remove_in_leaf)(node_t n, key_t const key) \
{ \ { \
M_ASSERT(M_F(name, _is_leaf)(n)); \ M_ASSERT(M_F(name, _is_leaf)(n)); \
M_ASSERT_POOL(); \
const int num = M_F(name, _get_num)(n); \ const int num = M_F(name, _get_num)(n); \
for(int i = 0; i < num; i++) { \ for(int i = 0; i < num; i++) { \
const int cmp = M_CALL_CMP(key_oplist, key, n->key[i]); \ const int cmp = M_CALL_CMP(key_oplist, key, n->key[i]); \
@@ -811,10 +812,11 @@
return -1; /* Not found */ \ return -1; /* Not found */ \
} \ } \
\ \
M_INLINE void M_F(name, _left_shift)(node_t parent, int k) \ M_P(void, name, _i_left_shift, node_t parent, int k) \
{ \ { \
M_ASSERT (parent != NULL && !M_F(name, _is_leaf)(parent)); \ M_ASSERT (parent != NULL && !M_F(name, _is_leaf)(parent)); \
M_ASSERT (0 <= k && k < M_F(name, _get_num)(parent)); \ M_ASSERT (0 <= k && k < M_F(name, _get_num)(parent)); \
M_ASSERT_POOL(); \
node_t left = parent->kind.node[k]; \ node_t left = parent->kind.node[k]; \
node_t right = parent->kind.node[k+1]; \ node_t right = parent->kind.node[k+1]; \
M_ASSERT (left != NULL && right != NULL); \ M_ASSERT (left != NULL && right != NULL); \
@@ -846,10 +848,11 @@
M_ASSERT (left->num != 0); \ M_ASSERT (left->num != 0); \
} \ } \
\ \
M_INLINE void M_F(name, _right_shift)(node_t parent, int k) \ M_P(void, name, _i_right_shift, node_t parent, int k) \
{ \ { \
M_ASSERT (parent != NULL && !M_F(name, _is_leaf)(parent)); \ M_ASSERT (parent != NULL && !M_F(name, _is_leaf)(parent)); \
M_ASSERT (0 <= k && k < M_F(name, _get_num)(parent)); \ M_ASSERT (0 <= k && k < M_F(name, _get_num)(parent)); \
M_ASSERT_POOL(); \
node_t left = parent->kind.node[k]; \ node_t left = parent->kind.node[k]; \
node_t right = parent->kind.node[k+1]; \ node_t right = parent->kind.node[k+1]; \
M_ASSERT (left != NULL && right != NULL); \ M_ASSERT (left != NULL && right != NULL); \
@@ -880,7 +883,7 @@
M_ASSERT (left->num != 0); \ M_ASSERT (left->num != 0); \
} \ } \
\ \
M_INLINE void M_F(name, _merge_node)(node_t parent, int k, bool leaf) \ M_P(void, name, _i_merge_node, node_t parent, int k, bool leaf) \
{ \ { \
M_ASSERT (parent != NULL && !M_F(name, _is_leaf)(parent)); \ M_ASSERT (parent != NULL && !M_F(name, _is_leaf)(parent)); \
M_ASSERT (0 <= k && k < M_F(name, _get_num(parent))); \ M_ASSERT (0 <= k && k < M_F(name, _get_num(parent))); \
@@ -916,7 +919,7 @@
/* We can also cache the index when we descend the tree. \ /* We can also cache the index when we descend the tree. \
TODO: Bench if this is worth the effort.*/ \ TODO: Bench if this is worth the effort.*/ \
M_INLINE int \ M_INLINE int \
M_F(name, _search_for_node)(node_t parent, node_t child) \ M_F(name, _i_search_for_node)(node_t parent, node_t child) \
{ \ { \
M_ASSERT (!M_F(name, _is_leaf)(parent)); \ M_ASSERT (!M_F(name, _is_leaf)(parent)); \
int i = 0; \ int i = 0; \
@@ -928,12 +931,12 @@
} \ } \
} \ } \
\ \
M_INLINE bool M_F(name, _erase)(tree_t b, key_t const key) \ M_P(bool, name, _erase, tree_t b, key_t const key) \
{ \ { \
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \ M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
pit_t pit; \ pit_t pit; \
node_t leaf = M_F(name, _search_for_leaf)(pit, b, key); \ node_t leaf = M_F(name, _i_search_for_leaf)(pit, b, key); \
int k = M_F(name, _search_and_remove_in_leaf)(leaf, key); \ int k = M_F(name, _i_search_and_remove_in_leaf)M_R(leaf, key); \
/* If key is not found ==> erase failed */ \ /* If key is not found ==> erase failed */ \
if (k < 0) return false; \ if (k < 0) return false; \
/* Remove one item from the B+TREE */ \ /* Remove one item from the B+TREE */ \
@@ -949,15 +952,15 @@
/* Search for node 'leaf' in parent */ \ /* Search for node 'leaf' in parent */ \
node_t parent = pit->parent[--pit->num]; \ node_t parent = pit->parent[--pit->num]; \
M_ASSERT (parent != NULL); \ M_ASSERT (parent != NULL); \
k = M_F(name, _search_for_node)(parent, leaf); \ k = M_F(name, _i_search_for_node)(parent, leaf); \
/* Look for the neighbour of the removed key. */ \ /* Look for the neighbour of the removed key. */ \
/* if we can steal one key from them to keep our node balanced */ \ /* if we can steal one key from them to keep our node balanced */ \
if (k > 0 && M_F(name, _get_num)(parent->kind.node[k-1]) > N/2) { \ if (k > 0 && M_F(name, _get_num)(parent->kind.node[k-1]) > N/2) { \
M_F(name, _left_shift)(parent, k-1); \ M_F(name, _i_left_shift)M_R(parent, k-1); \
return true; \ return true; \
} else if (k < M_F(name, _get_num)(parent) \ } else if (k < M_F(name, _get_num)(parent) \
&& M_F(name, _get_num)(parent->kind.node[k+1]) > N/2) { \ && M_F(name, _get_num)(parent->kind.node[k+1]) > N/2) { \
M_F(name, _right_shift)(parent, k); \ M_F(name, _i_right_shift)M_R(parent, k); \
return true; \ return true; \
} \ } \
/* Merge both nodes, removing 'k' from parent */ \ /* Merge both nodes, removing 'k' from parent */ \
@@ -965,7 +968,7 @@
k--; \ k--; \
M_ASSERT(k >= 0 && k < M_F(name, _get_num)(parent)); \ M_ASSERT(k >= 0 && k < M_F(name, _get_num)(parent)); \
/* Merge 'k' & 'k+1' & remove 'k' from parent */ \ /* Merge 'k' & 'k+1' & remove 'k' from parent */ \
M_F(name, _merge_node)(parent, k, pass1); \ M_F(name, _i_merge_node)M_R(parent, k, pass1); \
/* Check if we need to continue */ \ /* Check if we need to continue */ \
if (M_F(name, _get_num)(parent) >= N/2) \ if (M_F(name, _get_num)(parent) >= N/2) \
return true; \ return true; \
@@ -984,16 +987,17 @@
} \ } \
} \ } \
\ \
M_INLINE bool M_F(name, _pop_at)(value_t *ptr, tree_t b, key_t const key) \ M_P(bool, name, _pop_at, value_t *ptr, tree_t b, key_t const key) \
{ \ { \
if (ptr != NULL) { \ if (ptr != NULL) { \
/* Not optimized tree parsing */ \
value_t *ref = M_F(name, _get)(b, key); \ value_t *ref = M_F(name, _get)(b, key); \
if (ref == NULL) { \ if (ref == NULL) { \
return false; \ return false; \
} \ } \
M_CALL_SET(value_oplist, *ptr, *ref); \ M_CALL_SET(value_oplist, *ptr, *ref); \
} \ } \
return M_F(name, _erase)(b, key); \ return M_F(name, _erase)M_R(b, key); \
} \ } \
\ \
M_INLINE value_t * \ M_INLINE value_t * \
@@ -1046,13 +1050,12 @@
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \ M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
} \ } \
\ \
M_INLINE void \ M_P(void, name, _move, tree_t b, tree_t ref) \
M_F(name, _move)(tree_t b, tree_t ref) \
{ \ { \
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \ M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
M_BPTR33_CONTRACT(N, isMulti, key_oplist, ref); \ M_BPTR33_CONTRACT(N, isMulti, key_oplist, ref); \
M_ASSERT (b != ref); \ M_ASSERT (b != ref); \
M_F(name,_clear)(b); \ M_F(name,_clear)M_R(b); \
M_F(name,_init_move)(b, ref); \ M_F(name,_init_move)(b, ref); \
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \ M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
} \ } \
@@ -1161,7 +1164,7 @@
M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \ M_BPTR33_CONTRACT(N, isMulti, key_oplist, b); \
M_ASSERT (it != NULL); \ M_ASSERT (it != NULL); \
pit_t pit; \ pit_t pit; \
node_t n = M_F(name, _search_for_leaf)(pit, b, key); \ node_t n = M_F(name, _i_search_for_leaf)(pit, b, key); \
it->node = n; \ it->node = n; \
int i; \ int i; \
M_BPTR33_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \ M_BPTR33_NODE_CONTRACT(N, isMulti, key_oplist, n, b->root); \
@@ -1259,29 +1262,29 @@
, /* NO HASH METHOD */ ) \ , /* NO HASH METHOD */ ) \
\ \
M_IF_METHOD_BOTH(GET_STR, key_oplist, value_oplist)( \ M_IF_METHOD_BOTH(GET_STR, key_oplist, value_oplist)( \
M_INLINE void M_F(name, _get_str)(m_string_t str, \ M_P(void, name, _get_str, m_string_t str, const tree_t t1, bool append) \
const tree_t t1, bool append) { \ { \
M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \ M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \
M_ASSERT(str != NULL); \ M_ASSERT(str != NULL); \
(append ? m_string_cat_cstr : m_string_set_cstr) (str, "["); \ (append ? m_string_cat_cstr : m_string_set_cstr) M_R(str, "["); \
bool commaToPrint = false; \ bool commaToPrint = false; \
it_t it; \ it_t it; \
for (M_F(name, _it)(it, t1) ; \ for (M_F(name, _it)(it, t1) ; \
!M_F(name, _end_p)(it); \ !M_F(name, _end_p)(it); \
M_F(name, _next)(it)) { \ M_F(name, _next)(it)) { \
if (commaToPrint) \ if (commaToPrint) \
m_string_push_back (str, M_GET_SEPARATOR key_oplist); \ m_string_push_back M_R(str, M_GET_SEPARATOR key_oplist); \
commaToPrint = true; \ commaToPrint = true; \
subtype_t const *ref1 = M_F(name, _cref)(it); \ subtype_t const *ref1 = M_F(name, _cref)(it); \
M_IF(isMap)( \ M_IF(isMap)( \
M_CALL_GET_STR(key_oplist, str, *ref1->key_ptr, true); \ M_CALL_GET_STR(key_oplist, str, *ref1->key_ptr, true); \
m_string_cat_cstr(str, ":"); \ m_string_cat_cstr M_R(str, ":"); \
M_CALL_GET_STR(value_oplist,str, *ref1->value_ptr, true) \ M_CALL_GET_STR(value_oplist,str, *ref1->value_ptr, true) \
, \ , \
M_CALL_GET_STR(key_oplist, str, *ref1, true); \ M_CALL_GET_STR(key_oplist, str, *ref1, true); \
); \ ); \
} \ } \
m_string_push_back (str, ']'); \ m_string_push_back M_R(str, ']'); \
} \ } \
, /* NO GET_STR */ ) \ , /* NO GET_STR */ ) \
\ \
@@ -1314,12 +1317,11 @@
, /* no out_str */ ) \ , /* no out_str */ ) \
\ \
M_IF_METHOD_BOTH(PARSE_STR, key_oplist, value_oplist)( \ M_IF_METHOD_BOTH(PARSE_STR, key_oplist, value_oplist)( \
M_INLINE bool \ M_P(bool, name, _parse_str, tree_t t1, const char str[], const char **endp) \
M_F(name, _parse_str)(tree_t t1, const char str[], const char **endp) \
{ \ { \
M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \ M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \
M_ASSERT (str != NULL); \ M_ASSERT (str != NULL); \
M_F(name,_reset)(t1); \ M_F(name,_reset)M_R(t1); \
int c = *str++; \ int c = *str++; \
if (M_UNLIKELY (c != '[')) { c = 0; goto exit; } \ if (M_UNLIKELY (c != '[')) { c = 0; goto exit; } \
c = *str++; \ c = *str++; \
@@ -1335,9 +1337,9 @@
b = M_CALL_PARSE_STR(value_oplist, value, str, &str); \ b = M_CALL_PARSE_STR(value_oplist, value, str, &str); \
c = m_core_str_nospace(&str); \ c = m_core_str_nospace(&str); \
if (b == false || c == 0) { c = 0; break; } \ if (b == false || c == 0) { c = 0; break; } \
M_F(name, _set_at)(t1, key, value); \ M_F(name, _set_at)M_R(t1, key, value); \
, \ , \
M_F(name, _push)(t1, key); \ M_F(name, _push)M_R(t1, key); \
) \ ) \
} while (c == M_GET_SEPARATOR key_oplist); \ } while (c == M_GET_SEPARATOR key_oplist); \
} \ } \
@@ -1349,12 +1351,11 @@
, /* no parse_str */ ) \ , /* no parse_str */ ) \
\ \
M_IF_METHOD_BOTH(IN_STR, key_oplist, value_oplist)( \ M_IF_METHOD_BOTH(IN_STR, key_oplist, value_oplist)( \
M_INLINE bool \ M_P(bool, name, _in_str, tree_t t1, FILE *file) \
M_F(name, _in_str)(tree_t t1, FILE *file) \
{ \ { \
M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \ M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \
M_ASSERT (file != NULL); \ M_ASSERT (file != NULL); \
M_F(name,_reset)(t1); \ M_F(name,_reset)M_R(t1); \
int c = fgetc(file); \ int c = fgetc(file); \
if (M_UNLIKELY (c != '[')) return false; \ if (M_UNLIKELY (c != '[')) return false; \
c = fgetc(file); \ c = fgetc(file); \
@@ -1371,9 +1372,9 @@
b = M_CALL_IN_STR(value_oplist,value, file); \ b = M_CALL_IN_STR(value_oplist,value, file); \
c = m_core_fgetc_nospace(file); \ c = m_core_fgetc_nospace(file); \
if (b == false || c == EOF) { c = 0; break; } \ if (b == false || c == EOF) { c = 0; break; } \
M_F(name, _set_at)(t1, key, value) \ M_F(name, _set_at)M_R(t1, key, value) \
, \ , \
M_F(name, _push)(t1, key) \ M_F(name, _push)M_R(t1, key) \
); \ ); \
} while (c == M_GET_SEPARATOR key_oplist); \ } while (c == M_GET_SEPARATOR key_oplist); \
} \ } \
@@ -1427,15 +1428,14 @@
, /* no OUT_SERIAL */ ) \ , /* no OUT_SERIAL */ ) \
\ \
M_IF_METHOD_BOTH(IN_SERIAL, key_oplist, value_oplist)( \ M_IF_METHOD_BOTH(IN_SERIAL, key_oplist, value_oplist)( \
M_INLINE m_serial_return_code_t \ M_P(m_serial_return_code_t, name, _in_serial, tree_t t1, m_serial_read_t f) \
M_F(name, _in_serial)(tree_t t1, m_serial_read_t f) \
{ \ { \
M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \ M_BPTR33_CONTRACT(N, isMulti, key_oplist, t1); \
M_ASSERT (f != NULL && f->m_interface != NULL); \ M_ASSERT (f != NULL && f->m_interface != NULL); \
m_serial_local_t local; \ m_serial_local_t local; \
m_serial_return_code_t ret; \ m_serial_return_code_t ret; \
size_t estimated_size = 0; \ size_t estimated_size = 0; \
M_F(name,_reset)(t1); \ M_F(name,_reset)M_R(t1); \
M_QLET(1, key, key_t, key_oplist) \ M_QLET(1, key, key_t, key_oplist) \
M_IF(isMap)(M_QLET(2, value, value_t, value_oplist) , /*nothing*/) { \ M_IF(isMap)(M_QLET(2, value, value_t, value_oplist) , /*nothing*/) { \
M_IF(isMap)( \ M_IF(isMap)( \
@@ -1448,7 +1448,7 @@
if (ret != M_SERIAL_OK_CONTINUE) break; \ if (ret != M_SERIAL_OK_CONTINUE) break; \
ret = M_CALL_IN_SERIAL(value_oplist, value, f); \ ret = M_CALL_IN_SERIAL(value_oplist, value, f); \
if (ret != M_SERIAL_OK_DONE) break; \ if (ret != M_SERIAL_OK_DONE) break; \
M_F(name, _set_at)(t1, key, value); \ M_F(name, _set_at)M_R(t1, key, value); \
} while ((ret = f->m_interface->read_map_next(local, f)) == M_SERIAL_OK_CONTINUE); \ } while ((ret = f->m_interface->read_map_next(local, f)) == M_SERIAL_OK_CONTINUE); \
, /* queue style */ \ , /* queue style */ \
ret = f->m_interface->read_array_start(local, f, &estimated_size); \ ret = f->m_interface->read_array_start(local, f, &estimated_size); \
@@ -1456,7 +1456,7 @@
do { \ do { \
ret = M_CALL_IN_SERIAL(key_oplist, key, f); \ ret = M_CALL_IN_SERIAL(key_oplist, key, f); \
if (ret != M_SERIAL_OK_DONE) break; \ if (ret != M_SERIAL_OK_DONE) break; \
M_F(name, _push)(t1, key); \ M_F(name, _push)M_R(t1, key); \
} while ((ret = f->m_interface->read_array_next(local, f)) == M_SERIAL_OK_CONTINUE); \ } while ((ret = f->m_interface->read_array_next(local, f)) == M_SERIAL_OK_CONTINUE); \
) /* End of IF isMap */ \ ) /* End of IF isMap */ \
} \ } \
+14 -10
View File
@@ -412,33 +412,37 @@ M_BEGIN_PROTECTED_CODE
#endif #endif
// FIXME: Rename to M_USE_MEMORY_CONTEXT?
#ifndef M_USE_POOL #ifndef M_USE_POOL
// Memory pool parameter not used for memory function. Stub it with 0 as it won't be used (global definition). // Memory pool parameter not used for memory function. Stub it with 0 as it won't be used (global definition).
# define M_P_EXPAND # define M_P_EXPAND
# define M_P_EXPAND_void void
# define M_R_EXPAND # define M_R_EXPAND
# define M_R_EXPAND_void
# define M_R # define M_R
# define M_ASSERT_POOL() # define M_ASSERT_POOL()
#else #else
// Memory pool parameter is used for function using memory. (local definition to the function). // Memory pool parameter is used for function using memory. (local definition to the function).
// Expand to a prototype to a function that may not trigger exception // Expand to a prototype to a function that may not trigger exception
# define M_P_EXPAND M_USE_POOL m_pool, # define M_P_EXPAND M_USE_POOL m_pool,
# define M_P_EXPAND_void M_USE_POOL m_pool
# define M_R_EXPAND m_pool , # define M_R_EXPAND m_pool ,
# define M_R_EXPAND_void m_pool
# define M_R(...) (m_pool, __VA_ARGS__) # define M_R(...) (m_pool, __VA_ARGS__)
# define M_ASSERT_POOL() (void) m_pool # define M_ASSERT_POOL() (void) m_pool
#endif #endif
// Expand to a prototype of a function that may trigger exception / accept memory context // M_P: Expand to a prototype of a function that may trigger exception / accept memory context
// TODO: If not M_F, M_INLINE overloaded and no M_P_EXPAND, simplify M_P // M_N: Expand to a prototype of a function that may not trigger exception or accept memory context
// (faster build: 0.54s instead of 0.80s in extreme expanding // If not M_F, no overloaded M_INLINE and no M_P_EXPAND, simplify M_P
// (faster build: 0.54s instead of 0.80s in extreme expanding)
#if !defined(M_USE_POOL) && !defined(M_F) && !defined(M_USE_FINE_GRAINED_LINKAGE) && !defined(M_USE_DEF) && !defined(M_USE_DECL)
# define M_P(rettype, name, suffix, ...) static inline rettype name ## suffix(__VA_ARGS__)
# define M_N(rettype, name, suffix, ...) static inline rettype name ## suffix(__VA_ARGS__)
#else
# define M_P(rettype, name, suffix, ...) M_INLINE rettype M_F(name, suffix)(M_P_EXPAND __VA_ARGS__) # define M_P(rettype, name, suffix, ...) M_INLINE rettype M_F(name, suffix)(M_P_EXPAND __VA_ARGS__)
//#define M_P(rettype, name, suffix, ...) static inline rettype name ## suffix(__VA_ARGS__)
// Expand to a prototype of a function that may not trigger exception or accept memory context
# define M_N(rettype, name, suffix, ...) M_INLINE rettype M_F(name, suffix)(__VA_ARGS__) # define M_N(rettype, name, suffix, ...) M_INLINE rettype M_F(name, suffix)(__VA_ARGS__)
#endif
// TODO: Add for API special, the support of the POOL special keyword ==> m_pool
// Or document m_pool directly? Can still be overriden later.
// TODO: Add for all Assertions: M_ASSERT_POOL() // TODO: Add for all Assertions: M_ASSERT_POOL()
// to avoid warnings about unused parameter m_pool. // to avoid warnings about unused parameter m_pool.