84static_assert(
sizeof(
struct node) ==
LITE3_NODE_SIZE,
"sizeof(struct node) must equal LITE3_NODE_SIZE");
85static_assert(offsetof(
struct node, gen_type) == 0,
"Runtime type checks and LITE3_BYTES() & LITE3_STR() macros expect to read (struct node).gen_type field at offset 0");
86static_assert(
sizeof(((
struct node *)0)->gen_type) ==
sizeof(uint32_t),
"LITE3_BYTES() & LITE3_STR() macros expect to read (struct node).gen_type as uint32_t");
87static_assert(offsetof(
struct node, size_kc) ==
LITE3_NODE_SIZE_KC_OFFSET,
"Offset of (struct node).size_kc must equal LITE3_NODE_SIZE_KC_OFFSET");
88static_assert(
sizeof(((
struct node *)0)->size_kc) ==
sizeof(uint32_t),
"Node size checks expect to read (struct node).size_kc as uint32_t");
89static_assert(
sizeof(((
struct node *)0)->gen_type) ==
sizeof(((
lite3_iter *)0)->gen),
"Iterator expects to read (struct node).gen_type as uint32_t");
91#define LITE3_NODE_TYPE_SHIFT 0
92#define LITE3_NODE_TYPE_MASK ((u32)((1 << 8) - 1))
94#define LITE3_NODE_GEN_SHIFT 8
95#define LITE3_NODE_GEN_MASK ((u32)~((1 << 8) - 1))
97#define LITE3_NODE_KEY_COUNT_MAX ((int)(sizeof(((struct node *)0)->hashes) / sizeof(u32)))
98#define LITE3_NODE_KEY_COUNT_MIN ((int)(LITE3_NODE_KEY_COUNT_MAX / 2))
100#define LITE3_NODE_KEY_COUNT_SHIFT 0
102#define LITE3_NODE_KEY_COUNT_MASK ((u32)((1 << 3) - 1))
109#define LITE3_KEY_TAG_SIZE_MIN 1
110#define LITE3_KEY_TAG_SIZE_MAX 4
111#define LITE3_KEY_TAG_SIZE_MASK ((1 << 2) - 1)
112#define LITE3_KEY_TAG_SIZE_SHIFT 0
114#define LITE3_KEY_TAG_KEY_SIZE_MASK (~((1 << 2) - 1))
115#define LITE3_KEY_TAG_KEY_SIZE_SHIFT 2
125static inline int _verify_key(
128 const char *restrict key,
131 size_t *restrict inout_ofs,
132 size_t *restrict out_key_tag_size)
134 if (LITE3_UNLIKELY(LITE3_KEY_TAG_SIZE_MAX > buflen || *inout_ofs > buflen - LITE3_KEY_TAG_SIZE_MAX)) {
135 LITE3_PRINT_ERROR(
"KEY ENTRY OUT OF BOUNDS\n");
139 size_t _key_tag_size = (size_t)((*((u8 *)(buf + *inout_ofs)) & LITE3_KEY_TAG_SIZE_MASK) + 1);
141 if (key_tag_size != _key_tag_size) {
142 LITE3_PRINT_ERROR(
"KEY TAG SIZE DOES NOT MATCH\n");
147 size_t _key_size = 0;
148 memcpy(&_key_size, buf + *inout_ofs, _key_tag_size);
149 _key_size >>= LITE3_KEY_TAG_KEY_SIZE_SHIFT;
150 *inout_ofs += _key_tag_size;
152 if (LITE3_UNLIKELY(_key_size > buflen || *inout_ofs > buflen - _key_size)) {
153 LITE3_PRINT_ERROR(
"KEY ENTRY OUT OF BOUNDS\n");
159 (
const char *)(buf + *inout_ofs),
161 (key_size < _key_size) ? key_size : _key_size
163 if (LITE3_UNLIKELY(cmp != 0)) {
164 LITE3_PRINT_ERROR(
"HASH COLLISION\n");
165 return LITE3_VERIFY_KEY_HASH_COLLISION;
168 *inout_ofs += _key_size;
169 if (out_key_tag_size)
170 *out_key_tag_size = _key_tag_size;
171 return LITE3_VERIFY_KEY_OK;
181static inline int _verify_val(
184 size_t *restrict inout_ofs)
186 if (LITE3_UNLIKELY(LITE3_VAL_SIZE > buflen || *inout_ofs > buflen - LITE3_VAL_SIZE)) {
187 LITE3_PRINT_ERROR(
"VALUE OUT OF BOUNDS\n");
194 LITE3_PRINT_ERROR(
"VALUE TYPE INVALID\n");
198 size_t _val_entry_size = LITE3_VAL_SIZE + lite3_type_sizes[type];
200 if (LITE3_UNLIKELY(_val_entry_size > buflen || *inout_ofs > buflen - _val_entry_size)) {
201 LITE3_PRINT_ERROR(
"VALUE OUT OF BOUNDS\n");
206 size_t byte_count = 0;
207 memcpy(&byte_count, buf + *inout_ofs + LITE3_VAL_SIZE, lite3_type_sizes[
LITE3_TYPE_BYTES]);
208 _val_entry_size += byte_count;
209 if (LITE3_UNLIKELY(_val_entry_size > buflen || *inout_ofs > buflen - _val_entry_size)) {
210 LITE3_PRINT_ERROR(
"VALUE OUT OF BOUNDS\n");
215 *inout_ofs += _val_entry_size;
220 const unsigned char *buf,
223 const char *restrict key,
224 lite3_key_data key_data,
229 LITE3_PRINT_DEBUG(
"GET\tkey: %s\n", key);
231 LITE3_PRINT_DEBUG(
"GET\tindex: %u\n", key_data.hash);
233 LITE3_PRINT_DEBUG(
"GET INVALID: EXPECTING ARRAY OR OBJECT TYPE\n");
237 size_t key_tag_size = (size_t)((!!(key_data.size >> (16 - LITE3_KEY_TAG_KEY_SIZE_SHIFT)) << 1)
238 + !!(key_data.size >> (8 - LITE3_KEY_TAG_KEY_SIZE_SHIFT))
242 for (uint32_t attempt = 0; attempt < probe_attempts; attempt++) {
244 lite3_key_data attempt_key = key_data;
245 attempt_key.hash = key_data.hash + attempt * attempt;
247 LITE3_PRINT_DEBUG(
"probe attempt: %u\thash: %u\n", attempt, attempt_key.hash);
252 if (LITE3_UNLIKELY(((uintptr_t)
node & LITE3_NODE_ALIGNMENT_MASK) != 0)) {
253 LITE3_PRINT_ERROR(
"NODE OFFSET NOT ALIGNED TO LITE3_NODE_ALIGNMENT\n");
262 key_count =
node->size_kc & LITE3_NODE_KEY_COUNT_MASK;
264 while (i < key_count && node->hashes[i] < attempt_key.hash)
266 if (i < key_count && node->hashes[i] == attempt_key.hash) {
267 size_t target_ofs =
node->kv_ofs[i];
269 int verify = _verify_key(buf, buflen, key, (
size_t)attempt_key.size, key_tag_size, &target_ofs, NULL);
270 if (verify == LITE3_VERIFY_KEY_HASH_COLLISION)
275 size_t val_start_ofs = target_ofs;
276 if (_verify_val(buf, buflen, &target_ofs) < 0)
278 *out = (
lite3_val *)(buf + val_start_ofs);
281 if (
node->child_ofs[0]) {
282 size_t next_node_ofs = (size_t)
node->child_ofs[i];
285 if (LITE3_UNLIKELY(((uintptr_t)
node & LITE3_NODE_ALIGNMENT_MASK) != 0)) {
286 LITE3_PRINT_ERROR(
"NODE OFFSET NOT ALIGNED TO LITE3_NODE_ALIGNMENT\n");
291 LITE3_PRINT_ERROR(
"NODE WALK OFFSET OUT OF BOUNDS\n");
296 LITE3_PRINT_ERROR(
"NODE WALKS EXCEEDED LITE3_TREE_HEIGHT_MAX\n");
301 LITE3_PRINT_ERROR(
"KEY NOT FOUND\n");
307 LITE3_PRINT_ERROR(
"LITE3_HASH_PROBE_MAX LIMIT REACHED\n");
312int lite3_iter_create_impl(
const unsigned char *buf,
size_t buflen,
size_t ofs,
lite3_iter *out)
314 LITE3_PRINT_DEBUG(
"CREATE ITER\n");
318 if (LITE3_UNLIKELY(((uintptr_t)
node & LITE3_NODE_ALIGNMENT_MASK) != 0)) {
319 LITE3_PRINT_ERROR(
"NODE OFFSET NOT ALIGNED TO LITE3_NODE_ALIGNMENT\n");
326 LITE3_PRINT_ERROR(
"INVALID ARGUMENT: EXPECTING ARRAY OR OBJECT TYPE\n");
330 out->gen = ((
struct node *)buf)->gen_type;
332 out->node_ofs[0] = (u32)ofs;
335 while (
node->child_ofs[0]) {
336 u32 next_node_ofs =
node->child_ofs[0];
340 if (LITE3_UNLIKELY(((uintptr_t)
node & LITE3_NODE_ALIGNMENT_MASK) != 0)) {
341 LITE3_PRINT_ERROR(
"NODE OFFSET NOT ALIGNED TO LITE3_NODE_ALIGNMENT\n");
346 LITE3_PRINT_ERROR(
"NODE WALKS EXCEEDED LITE3_TREE_HEIGHT_MAX\n");
350 if (LITE3_UNLIKELY((
size_t)next_node_ofs > buflen -
LITE3_NODE_SIZE)) {
351 LITE3_PRINT_ERROR(
"NODE WALK OFFSET OUT OF BOUNDS\n");
355 out->node_ofs[out->depth] = next_node_ofs;
356 out->node_i[out->depth] = 0;
358 #ifdef LITE3_PREFETCHING
359 __builtin_prefetch(buf +
node->kv_ofs[0], 0, 0);
360 __builtin_prefetch(buf +
node->kv_ofs[0] + 64, 0, 0);
361 __builtin_prefetch(buf +
node->kv_ofs[1], 0, 0);
362 __builtin_prefetch(buf +
node->kv_ofs[1] + 64, 0, 0);
363 __builtin_prefetch(buf +
node->kv_ofs[2], 0, 0);
364 __builtin_prefetch(buf +
node->kv_ofs[2] + 64, 0, 0);
371 if (LITE3_UNLIKELY(iter->gen != ((
struct node *)buf)->gen_type)) {
372 LITE3_PRINT_ERROR(
"ITERATOR INVALID: iter->gen != node->gen_type (BUFFER MUTATION INVALIDATES ITERATORS)\n");
379 if (LITE3_UNLIKELY(((uintptr_t)
node & LITE3_NODE_ALIGNMENT_MASK) != 0)) {
380 LITE3_PRINT_ERROR(
"NODE OFFSET NOT ALIGNED TO LITE3_NODE_ALIGNMENT\n");
387 LITE3_PRINT_ERROR(
"INVALID ARGUMENT: EXPECTING ARRAY OR OBJECT TYPE\n");
391 if (iter->depth == 0 && (iter->node_i[iter->depth] == (
node->size_kc & LITE3_NODE_KEY_COUNT_MASK))) {
394 size_t target_ofs =
node->kv_ofs[iter->node_i[iter->depth]];
399 size_t key_start_ofs = target_ofs;
400 if ((ret = _verify_key(buf, buflen, NULL, 0, 0, &target_ofs, &key_tag_size)) < 0)
402 out_key->
gen = iter->gen;
404 memcpy(&out_key->
len, buf + key_start_ofs, key_tag_size);
406 out_key->
ptr = (
const char *)(buf + key_start_ofs + key_tag_size);
409 size_t val_start_ofs = target_ofs;
410 if ((ret = _verify_val(buf, buflen, &target_ofs)) < 0)
412 *out_val_ofs = val_start_ofs;
415 ++iter->node_i[iter->depth];
417 while (
node->child_ofs[iter->node_i[iter->depth]]) {
418 u32 next_node_ofs =
node->child_ofs[iter->node_i[iter->depth]];
422 if (LITE3_UNLIKELY(((uintptr_t)
node & LITE3_NODE_ALIGNMENT_MASK) != 0)) {
423 LITE3_PRINT_ERROR(
"NODE OFFSET NOT ALIGNED TO LITE3_NODE_ALIGNMENT\n");
428 LITE3_PRINT_ERROR(
"NODE WALKS EXCEEDED LITE3_TREE_HEIGHT_MAX\n");
432 if (LITE3_UNLIKELY((
size_t)next_node_ofs > buflen -
LITE3_NODE_SIZE)) {
433 LITE3_PRINT_ERROR(
"NODE WALK OFFSET OUT OF BOUNDS\n");
437 iter->node_ofs[iter->depth] = next_node_ofs;
438 iter->node_i[iter->depth] = 0;
440 while (iter->depth > 0 && (iter->node_i[iter->depth] == (
node->size_kc & LITE3_NODE_KEY_COUNT_MASK))) {
444 if (LITE3_UNLIKELY(((uintptr_t)
node & LITE3_NODE_ALIGNMENT_MASK) != 0)) {
445 LITE3_PRINT_ERROR(
"NODE OFFSET NOT ALIGNED TO LITE3_NODE_ALIGNMENT\n");
449 #ifdef LITE3_PREFETCHING
450 __builtin_prefetch(buf +
node->child_ofs[(iter->node_i[iter->depth] + 1) & LITE3_NODE_KEY_COUNT_MASK], 0, 2);
451 __builtin_prefetch(buf +
node->child_ofs[(iter->node_i[iter->depth] + 1) & LITE3_NODE_KEY_COUNT_MASK] + 64, 0, 2);
452 __builtin_prefetch(buf +
node->child_ofs[(iter->node_i[iter->depth] + 2) & LITE3_NODE_KEY_COUNT_MASK], 0, 2);
453 __builtin_prefetch(buf +
node->child_ofs[(iter->node_i[iter->depth] + 2) & LITE3_NODE_KEY_COUNT_MASK] + 64, 0, 2);
456 #ifdef LITE3_PREFETCHING
457 __builtin_prefetch(buf +
node->kv_ofs[(iter->node_i[iter->depth] + 0) & LITE3_NODE_KEY_COUNT_MASK], 0, 0);
458 __builtin_prefetch(buf +
node->kv_ofs[(iter->node_i[iter->depth] + 0) & LITE3_NODE_KEY_COUNT_MASK] + 64, 0, 0);
459 __builtin_prefetch(buf +
node->kv_ofs[(iter->node_i[iter->depth] + 1) & LITE3_NODE_KEY_COUNT_MASK], 0, 0);
460 __builtin_prefetch(buf +
node->kv_ofs[(iter->node_i[iter->depth] + 1) & LITE3_NODE_KEY_COUNT_MASK] + 64, 0, 0);
461 __builtin_prefetch(buf +
node->kv_ofs[(iter->node_i[iter->depth] + 2) & LITE3_NODE_KEY_COUNT_MASK], 0, 0);
462 __builtin_prefetch(buf +
node->kv_ofs[(iter->node_i[iter->depth] + 2) & LITE3_NODE_KEY_COUNT_MASK] + 64, 0, 0);
468static inline void _lite3_init_impl(
unsigned char *buf,
size_t ofs,
enum lite3_type type)
470 LITE3_PRINT_DEBUG(
"INITIALIZE %s\n", type ==
LITE3_TYPE_OBJECT ?
"OBJECT" :
"ARRAY");
473 node->gen_type = type & LITE3_NODE_TYPE_MASK;
474 node->size_kc = 0x00;
475 #ifdef LITE3_ZERO_MEM_EXTRA
476 memset(
node->hashes, LITE3_ZERO_MEM_8,
sizeof(((
struct node *)0)->hashes));
477 memset(
node->kv_ofs, LITE3_ZERO_MEM_8,
sizeof(((
struct node *)0)->kv_ofs));
479 memset(
node->child_ofs, 0x00,
sizeof(((
struct node *)0)->child_ofs));
482int lite3_init_obj(
unsigned char *buf,
size_t *restrict out_buflen,
size_t bufsz)
485 LITE3_PRINT_ERROR(
"INVALID ARGUMENT: bufsz < LITE3_NODE_SIZE\n");
494int lite3_init_arr(
unsigned char *buf,
size_t *restrict out_buflen,
size_t bufsz)
497 LITE3_PRINT_ERROR(
"INVALID ARGUMENT: bufsz < LITE3_NODE_SIZE\n");
519 size_t *restrict inout_buflen,
522 const char *restrict key,
523 lite3_key_data key_data,
529 LITE3_PRINT_DEBUG(
"SET\tkey: %s\n", key);
531 LITE3_PRINT_DEBUG(
"SET\tindex: %u\n", key_data.hash);
533 LITE3_PRINT_DEBUG(
"SET INVALID: EXPECTING ARRAY OR OBJECT TYPE\n");
537 size_t key_tag_size = (size_t)((!!(key_data.size >> (16 - LITE3_KEY_TAG_KEY_SIZE_SHIFT)) << 1)
538 + !!(key_data.size >> (8 - LITE3_KEY_TAG_KEY_SIZE_SHIFT))
540 size_t base_entry_size = key_tag_size + (size_t)key_data.size + LITE3_VAL_SIZE + val_len;
544 if (LITE3_UNLIKELY(((uintptr_t)root & LITE3_NODE_ALIGNMENT_MASK) != 0)) {
545 LITE3_PRINT_ERROR(
"NODE OFFSET NOT ALIGNED TO LITE3_NODE_ALIGNMENT\n");
550 u32 gen = root->gen_type >> LITE3_NODE_GEN_SHIFT;
552 root->gen_type = (root->gen_type & ~LITE3_NODE_GEN_MASK) | (gen << LITE3_NODE_GEN_SHIFT);
555 for (uint32_t attempt = 0; attempt < probe_attempts; attempt++) {
557 lite3_key_data attempt_key = key_data;
558 attempt_key.hash = key_data.hash + attempt * attempt;
560 LITE3_PRINT_DEBUG(
"probe attempt: %u\thash: %u\n", attempt, attempt_key.hash);
563 size_t entry_size = base_entry_size;
564 struct node *restrict parent = NULL;
572 if ((
node->size_kc & LITE3_NODE_KEY_COUNT_MASK) == LITE3_NODE_KEY_COUNT_MAX) {
574 size_t buflen_aligned = (*inout_buflen + LITE3_NODE_ALIGNMENT_MASK) & ~(
size_t)LITE3_NODE_ALIGNMENT_MASK;
577 if (LITE3_UNLIKELY(new_node_size > bufsz || buflen_aligned > bufsz - new_node_size)) {
578 LITE3_PRINT_ERROR(
"NO BUFFER SPACE FOR NODE SPLIT\n");
582 *inout_buflen = buflen_aligned;
585 LITE3_PRINT_DEBUG(
"NEW ROOT\n");
589 if (LITE3_UNLIKELY(((uintptr_t)
node & LITE3_NODE_ALIGNMENT_MASK) != 0)) {
590 LITE3_PRINT_ERROR(
"NODE OFFSET NOT ALIGNED TO LITE3_NODE_ALIGNMENT\n");
596 if (LITE3_UNLIKELY(((uintptr_t)parent & LITE3_NODE_ALIGNMENT_MASK) != 0)) {
597 LITE3_PRINT_ERROR(
"NODE OFFSET NOT ALIGNED TO LITE3_NODE_ALIGNMENT\n");
601 #ifdef LITE3_ZERO_MEM_EXTRA
602 memset(parent->hashes, LITE3_ZERO_MEM_8,
sizeof(((
struct node *)0)->hashes));
603 memset(parent->kv_ofs, LITE3_ZERO_MEM_8,
sizeof(((
struct node *)0)->kv_ofs));
604 memset(parent->child_ofs, 0x00,
sizeof(((
struct node *)0)->child_ofs));
606 parent->size_kc &= ~LITE3_NODE_KEY_COUNT_MASK;
607 parent->child_ofs[0] = (u32)*inout_buflen;
612 LITE3_PRINT_DEBUG(
"SPLIT NODE\n");
613 for (
int j = key_count; j > i; j--) {
614 parent->hashes[j] = parent->hashes[j - 1];
615 parent->kv_ofs[j] = parent->kv_ofs[j - 1];
616 parent->child_ofs[j + 1] = parent->child_ofs[j];
618 parent->hashes[i] =
node->hashes[LITE3_NODE_KEY_COUNT_MIN];
619 parent->kv_ofs[i] =
node->kv_ofs[LITE3_NODE_KEY_COUNT_MIN];
620 parent->child_ofs[i + 1] = (u32)*inout_buflen;
621 parent->size_kc = (parent->size_kc & ~LITE3_NODE_KEY_COUNT_MASK)
622 | ((parent->size_kc + 1) & LITE3_NODE_KEY_COUNT_MASK);
623 #ifdef LITE3_ZERO_MEM_EXTRA
624 node->hashes[LITE3_NODE_KEY_COUNT_MIN] = LITE3_ZERO_MEM_32;
625 node->kv_ofs[LITE3_NODE_KEY_COUNT_MIN] = LITE3_ZERO_MEM_32;
629 if (LITE3_UNLIKELY(((uintptr_t)sibling & LITE3_NODE_ALIGNMENT_MASK) != 0)) {
630 LITE3_PRINT_ERROR(
"NODE OFFSET NOT ALIGNED TO LITE3_NODE_ALIGNMENT\n");
634 #ifdef LITE3_ZERO_MEM_EXTRA
635 memset(sibling->hashes, LITE3_ZERO_MEM_8,
sizeof(((
struct node *)0)->hashes));
636 memset(sibling->kv_ofs, LITE3_ZERO_MEM_8,
sizeof(((
struct node *)0)->kv_ofs));
638 sibling->gen_type = ((
struct node *)(buf + ofs))->gen_type & LITE3_NODE_TYPE_MASK;
639 sibling->size_kc = LITE3_NODE_KEY_COUNT_MIN & LITE3_NODE_KEY_COUNT_MASK;
640 node->size_kc = LITE3_NODE_KEY_COUNT_MIN & LITE3_NODE_KEY_COUNT_MASK;
641 memset(sibling->child_ofs, 0x00,
sizeof(((
struct node *)0)->child_ofs));
642 sibling->child_ofs[0] =
node->child_ofs[LITE3_NODE_KEY_COUNT_MIN + 1];
643 node->child_ofs[LITE3_NODE_KEY_COUNT_MIN + 1] = 0x00;
644 for (
int j = 0; j < LITE3_NODE_KEY_COUNT_MIN; j++) {
645 sibling->hashes[j] =
node->hashes[j + LITE3_NODE_KEY_COUNT_MIN + 1];
646 sibling->kv_ofs[j] =
node->kv_ofs[j + LITE3_NODE_KEY_COUNT_MIN + 1];
647 sibling->child_ofs[j + 1] =
node->child_ofs[j + LITE3_NODE_KEY_COUNT_MIN + 2];
648 #ifdef LITE3_ZERO_MEM_EXTRA
649 node->hashes[j + LITE3_NODE_KEY_COUNT_MIN + 1] = LITE3_ZERO_MEM_32;
650 node->kv_ofs[j + LITE3_NODE_KEY_COUNT_MIN + 1] = LITE3_ZERO_MEM_32;
651 node->child_ofs[j + LITE3_NODE_KEY_COUNT_MIN + 2] = 0x00000000;
655 if (attempt_key.hash > parent->hashes[i]) {
658 if (LITE3_UNLIKELY(((uintptr_t)
node & LITE3_NODE_ALIGNMENT_MASK) != 0)) {
659 LITE3_PRINT_ERROR(
"NODE OFFSET NOT ALIGNED TO LITE3_NODE_ALIGNMENT\n");
663 }
else if (attempt_key.hash == parent->hashes[i]) {
665 LITE3_PRINT_DEBUG(
"GOTO SKIP\n");
670 key_count =
node->size_kc & LITE3_NODE_KEY_COUNT_MASK;
672 while (i < key_count && node->hashes[i] < attempt_key.hash)
675 LITE3_PRINT_DEBUG(
"i: %i\tkc: %i\tnode->hashes[i]: %u\n", i, key_count,
node->hashes[i]);
677 if (i < key_count && node->hashes[i] == attempt_key.hash) {
679 size_t target_ofs =
node->kv_ofs[i];
680 size_t key_start_ofs = target_ofs;
682 int verify = _verify_key(buf, *inout_buflen, key, (
size_t)attempt_key.size, key_tag_size, &target_ofs, NULL);
683 if (verify == LITE3_VERIFY_KEY_HASH_COLLISION)
688 size_t val_start_ofs = target_ofs;
689 if (_verify_val(buf, *inout_buflen, &target_ofs) < 0)
691 if (val_len >= target_ofs - val_start_ofs) {
692 size_t alignment_mask = val_len == lite3_type_sizes[
LITE3_TYPE_OBJECT] ? (size_t)LITE3_NODE_ALIGNMENT_MASK : 0;
693 size_t unaligned_val_ofs = *inout_buflen + key_tag_size + (size_t)attempt_key.size;
694 size_t alignment_padding = ((unaligned_val_ofs + alignment_mask) & ~alignment_mask) - unaligned_val_ofs;
695 entry_size += alignment_padding;
696 if (LITE3_UNLIKELY(entry_size > bufsz || *inout_buflen > bufsz - entry_size)) {
697 LITE3_PRINT_ERROR(
"NO BUFFER SPACE FOR ENTRY INSERTION\n");
702 #ifdef LITE3_ZERO_MEM_DELETED
703 memset(buf +
node->kv_ofs[i], LITE3_ZERO_MEM_8, target_ofs - key_start_ofs);
705 #ifdef LITE3_ZERO_MEM_EXTRA
706 memset(buf + *inout_buflen, LITE3_ZERO_MEM_8, alignment_padding);
708 *inout_buflen += alignment_padding;
709 node->kv_ofs[i] = (u32)*inout_buflen;
713 #ifdef LITE3_ZERO_MEM_DELETED
714 memset(buf + val_start_ofs, LITE3_ZERO_MEM_8, target_ofs - val_start_ofs);
716 *out = (
lite3_val *)(buf + val_start_ofs);
720 if (
node->child_ofs[0]) {
721 size_t next_node_ofs = (size_t)
node->child_ofs[i];
726 if (LITE3_UNLIKELY(((uintptr_t)
node & LITE3_NODE_ALIGNMENT_MASK) != 0)) {
727 LITE3_PRINT_ERROR(
"NODE OFFSET NOT ALIGNED TO LITE3_NODE_ALIGNMENT\n");
732 LITE3_PRINT_ERROR(
"NODE WALK OFFSET OUT OF BOUNDS\n");
737 LITE3_PRINT_ERROR(
"NODE WALKS EXCEEDED LITE3_TREE_HEIGHT_MAX\n");
742 size_t alignment_mask = val_len == lite3_type_sizes[
LITE3_TYPE_OBJECT] ? (size_t)LITE3_NODE_ALIGNMENT_MASK : 0;
743 size_t unaligned_val_ofs = *inout_buflen + key_tag_size + (size_t)attempt_key.size;
744 size_t alignment_padding = ((unaligned_val_ofs + alignment_mask) & ~alignment_mask) - unaligned_val_ofs;
745 entry_size += alignment_padding;
746 if (LITE3_UNLIKELY(entry_size > bufsz || *inout_buflen > bufsz - entry_size)) {
747 LITE3_PRINT_ERROR(
"NO BUFFER SPACE FOR ENTRY INSERTION\n");
751 for (
int j = key_count; j > i; j--) {
752 node->hashes[j] =
node->hashes[j - 1];
753 node->kv_ofs[j] =
node->kv_ofs[j - 1];
755 LITE3_PRINT_DEBUG(
"INSERTING HASH: %u\ti: %i\n", attempt_key.hash, i);
756 node->hashes[i] = attempt_key.hash;
757 node->size_kc = (
node->size_kc & ~LITE3_NODE_KEY_COUNT_MASK)
758 | ((
node->size_kc + 1) & LITE3_NODE_KEY_COUNT_MASK);
759 #ifdef LITE3_ZERO_MEM_EXTRA
760 memset(buf + *inout_buflen, LITE3_ZERO_MEM_8, alignment_padding);
762 *inout_buflen += alignment_padding;
763 node->kv_ofs[i] = (u32)*inout_buflen;
766 u32 size = root->size_kc >> LITE3_NODE_SIZE_SHIFT;
768 root->size_kc = (root->size_kc & ~LITE3_NODE_SIZE_MASK) | (size << LITE3_NODE_SIZE_SHIFT);
775 size_t key_size_tmp = (attempt_key.size << LITE3_KEY_TAG_KEY_SIZE_SHIFT) | (key_tag_size - 1);
776 memcpy(buf + *inout_buflen, &key_size_tmp, key_tag_size);
777 *inout_buflen += key_tag_size;
778 memcpy(buf + *inout_buflen, key, (
size_t)attempt_key.size);
779 *inout_buflen += (size_t)attempt_key.size;
781 *out = (
lite3_val *)(buf + *inout_buflen);
782 *inout_buflen += LITE3_VAL_SIZE + val_len;
783 LITE3_PRINT_DEBUG(
"OK\n");
786 LITE3_PRINT_ERROR(
"LITE3_HASH_PROBE_MAX LIMIT REACHED\n");
791int lite3_set_obj_impl(
unsigned char *buf,
size_t *restrict inout_buflen,
size_t ofs,
size_t bufsz,
const char *restrict key, lite3_key_data key_data,
size_t *restrict out_ofs)
795 if ((ret = lite3_set_impl(buf, inout_buflen, ofs, bufsz, key, key_data, lite3_type_sizes[
LITE3_TYPE_OBJECT], &val)) < 0)
797 size_t init_ofs = (size_t)((u8 *)val - buf);
804int lite3_set_arr_impl(
unsigned char *buf,
size_t *restrict inout_buflen,
size_t ofs,
size_t bufsz,
const char *restrict key, lite3_key_data key_data,
size_t *restrict out_ofs)
808 if ((ret = lite3_set_impl(buf, inout_buflen, ofs, bufsz, key, key_data, lite3_type_sizes[
LITE3_TYPE_ARRAY], &val)) < 0)
810 size_t init_ofs = (size_t)((u8 *)val - buf);
817int lite3_arr_append_obj_impl(
unsigned char *buf,
size_t *restrict inout_buflen,
size_t ofs,
size_t bufsz,
size_t *restrict out_ofs)
819 u32 size = ((
struct node *)(buf + ofs))->size_kc >> LITE3_NODE_SIZE_SHIFT;
820 lite3_key_data key_data = {
826 if ((ret = lite3_set_impl(buf, inout_buflen, ofs, bufsz, NULL, key_data, lite3_type_sizes[
LITE3_TYPE_OBJECT], &val)) < 0)
828 size_t init_ofs = (size_t)((u8 *)val - buf);
835int lite3_arr_append_arr_impl(
unsigned char *buf,
size_t *restrict inout_buflen,
size_t ofs,
size_t bufsz,
size_t *restrict out_ofs)
837 u32 size = ((
struct node *)(buf + ofs))->size_kc >> LITE3_NODE_SIZE_SHIFT;
838 lite3_key_data key_data = {
844 if ((ret = lite3_set_impl(buf, inout_buflen, ofs, bufsz, NULL, key_data, lite3_type_sizes[
LITE3_TYPE_ARRAY], &val)) < 0)
846 size_t init_ofs = (size_t)((u8 *)val - buf);
853int lite3_arr_set_obj_impl(
unsigned char *buf,
size_t *restrict inout_buflen,
size_t ofs,
size_t bufsz, uint32_t index,
size_t *restrict out_ofs)
855 u32 size = ((
struct node *)(buf + ofs))->size_kc >> LITE3_NODE_SIZE_SHIFT;
856 if (LITE3_UNLIKELY(index > size)) {
857 LITE3_PRINT_ERROR(
"INVALID ARGUMENT: ARRAY INDEX %u OUT OF BOUNDS (size == %u)\n", index, size);
861 lite3_key_data key_data = {
867 if ((ret = lite3_set_impl(buf, inout_buflen, ofs, bufsz, NULL, key_data, lite3_type_sizes[
LITE3_TYPE_OBJECT], &val)) < 0)
869 size_t init_ofs = (size_t)((u8 *)val - buf);
876int lite3_arr_set_arr_impl(
unsigned char *buf,
size_t *restrict inout_buflen,
size_t ofs,
size_t bufsz, uint32_t index,
size_t *restrict out_ofs)
878 u32 size = ((
struct node *)(buf + ofs))->size_kc >> LITE3_NODE_SIZE_SHIFT;
879 if (LITE3_UNLIKELY(index > size)) {
880 LITE3_PRINT_ERROR(
"INVALID ARGUMENT: ARRAY INDEX %u OUT OF BOUNDS (size == %u)\n", index, size);
884 lite3_key_data key_data = {
890 if ((ret = lite3_set_impl(buf, inout_buflen, ofs, bufsz, NULL, key_data, lite3_type_sizes[
LITE3_TYPE_ARRAY], &val)) < 0)
892 size_t init_ofs = (size_t)((u8 *)val - buf);
#define LITE3_TREE_HEIGHT_MAX
Maximum B-tree height.
#define LITE3_HASH_PROBE_MAX
Enable hash probing to tolerate 32-bit hash collisions.
#define LITE3_NODE_ALIGNMENT
B-tree node alignment configuration.
#define LITE3_NODE_SIZE
B-tree node size setting.
#define LITE3_NODE_SIZE_KC_OFFSET
Offset of the size_kc field inside struct node.
#define LITE3_ITER_ITEM
Return value of lite3_iter_next(); iterator produced an item, continue;.
#define LITE3_ITER_DONE
Return value of lite3_iter_next(); iterator finished; stop.
int lite3_iter_next(const unsigned char *buf, size_t buflen, lite3_iter *iter, lite3_str *out_key, size_t *out_val_ofs)
Get the next item from a lite3 iterator.
lite3_type
enum containing all Lite³ types
@ LITE3_TYPE_ARRAY
maps to 'array' type in JSON
@ LITE3_TYPE_INVALID
any type value equal or greater than this is considered invalid
@ LITE3_TYPE_STRING
maps to 'string' type in JSON
@ LITE3_TYPE_BYTES
coverted to base64 string in JSON
@ LITE3_TYPE_OBJECT
maps to 'object' type in JSON
Struct containing iterator state.
Struct holding a reference to a string inside a Lite³ buffer.
uint32_t len
char array length (characters, exclusive of NULL-terminator)
const char * ptr
char array pointer to string inside Lite³ buffer
uint32_t gen
generation of the Lite³ buffer when this struct was returned
Struct representing a value inside a Lite³ buffer.