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_MIN > buflen || *inout_ofs > buflen - LITE3_KEY_TAG_SIZE_MIN)) {
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 (LITE3_UNLIKELY(_key_tag_size > buflen || *inout_ofs > buflen - _key_tag_size)) {
142 LITE3_PRINT_ERROR(
"KEY ENTRY OUT OF BOUNDS\n");
147 if (key_tag_size != _key_tag_size) {
148 LITE3_PRINT_ERROR(
"KEY TAG SIZE DOES NOT MATCH\n");
153 size_t _key_size = 0;
154 memcpy(&_key_size, buf + *inout_ofs, _key_tag_size);
155 _key_size >>= LITE3_KEY_TAG_KEY_SIZE_SHIFT;
156 *inout_ofs += _key_tag_size;
158 if (LITE3_UNLIKELY(_key_size > buflen || *inout_ofs > buflen - _key_size)) {
159 LITE3_PRINT_ERROR(
"KEY ENTRY OUT OF BOUNDS\n");
165 (
const char *)(buf + *inout_ofs),
167 (key_size < _key_size) ? key_size : _key_size
169 if (LITE3_UNLIKELY(cmp != 0)) {
170 LITE3_PRINT_ERROR(
"HASH COLLISION\n");
171 return LITE3_VERIFY_KEY_HASH_COLLISION;
174 *inout_ofs += _key_size;
175 if (out_key_tag_size)
176 *out_key_tag_size = _key_tag_size;
177 return LITE3_VERIFY_KEY_OK;
187static inline int _verify_val(
190 size_t *restrict inout_ofs)
192 if (LITE3_UNLIKELY(LITE3_VAL_SIZE > buflen || *inout_ofs > buflen - LITE3_VAL_SIZE)) {
193 LITE3_PRINT_ERROR(
"VALUE OUT OF BOUNDS\n");
200 LITE3_PRINT_ERROR(
"VALUE TYPE INVALID\n");
204 size_t _val_entry_size = LITE3_VAL_SIZE + lite3_type_sizes[type];
206 if (LITE3_UNLIKELY(_val_entry_size > buflen || *inout_ofs > buflen - _val_entry_size)) {
207 LITE3_PRINT_ERROR(
"VALUE OUT OF BOUNDS\n");
212 size_t byte_count = 0;
213 memcpy(&byte_count, buf + *inout_ofs + LITE3_VAL_SIZE, lite3_type_sizes[
LITE3_TYPE_BYTES]);
214 _val_entry_size += byte_count;
215 if (LITE3_UNLIKELY(_val_entry_size > buflen || *inout_ofs > buflen - _val_entry_size)) {
216 LITE3_PRINT_ERROR(
"VALUE OUT OF BOUNDS\n");
221 *inout_ofs += _val_entry_size;
226 const unsigned char *buf,
229 const char *restrict key,
230 lite3_key_data key_data,
235 LITE3_PRINT_DEBUG(
"GET\tkey: %s\n", key);
237 LITE3_PRINT_DEBUG(
"GET\tindex: %u\n", key_data.hash);
239 LITE3_PRINT_DEBUG(
"GET INVALID: EXPECTING ARRAY OR OBJECT TYPE\n");
243 size_t key_tag_size = (size_t)((!!(key_data.size >> (16 - LITE3_KEY_TAG_KEY_SIZE_SHIFT)) << 1)
244 + !!(key_data.size >> (8 - LITE3_KEY_TAG_KEY_SIZE_SHIFT))
248 for (uint32_t attempt = 0; attempt < probe_attempts; attempt++) {
250 lite3_key_data attempt_key = key_data;
251 attempt_key.hash = key_data.hash + attempt * attempt;
256 if (LITE3_UNLIKELY(((uintptr_t)
node & LITE3_NODE_ALIGNMENT_MASK) != 0)) {
257 LITE3_PRINT_ERROR(
"NODE OFFSET NOT ALIGNED TO LITE3_NODE_ALIGNMENT\n");
266 key_count =
node->size_kc & LITE3_NODE_KEY_COUNT_MASK;
268 while (i < key_count && node->hashes[i] < attempt_key.hash)
270 if (i < key_count && node->hashes[i] == attempt_key.hash) {
271 size_t target_ofs =
node->kv_ofs[i];
273 int verify = _verify_key(buf, buflen, key, (
size_t)attempt_key.size, key_tag_size, &target_ofs, NULL);
274 if (verify == LITE3_VERIFY_KEY_HASH_COLLISION)
279 size_t val_start_ofs = target_ofs;
280 if (_verify_val(buf, buflen, &target_ofs) < 0)
282 *out = (
lite3_val *)(buf + val_start_ofs);
285 if (
node->child_ofs[0]) {
286 size_t next_node_ofs = (size_t)
node->child_ofs[i];
289 if (LITE3_UNLIKELY(((uintptr_t)
node & LITE3_NODE_ALIGNMENT_MASK) != 0)) {
290 LITE3_PRINT_ERROR(
"NODE OFFSET NOT ALIGNED TO LITE3_NODE_ALIGNMENT\n");
295 LITE3_PRINT_ERROR(
"NODE WALK OFFSET OUT OF BOUNDS\n");
300 LITE3_PRINT_ERROR(
"NODE WALKS EXCEEDED LITE3_TREE_HEIGHT_MAX\n");
305 LITE3_PRINT_ERROR(
"KEY NOT FOUND\n");
311 LITE3_PRINT_ERROR(
"LITE3_HASH_PROBE_MAX LIMIT REACHED\n");
316int lite3_iter_create_impl(
const unsigned char *buf,
size_t buflen,
size_t ofs,
lite3_iter *out)
318 LITE3_PRINT_DEBUG(
"CREATE ITER\n");
322 if (LITE3_UNLIKELY(((uintptr_t)
node & LITE3_NODE_ALIGNMENT_MASK) != 0)) {
323 LITE3_PRINT_ERROR(
"NODE OFFSET NOT ALIGNED TO LITE3_NODE_ALIGNMENT\n");
330 LITE3_PRINT_ERROR(
"INVALID ARGUMENT: EXPECTING ARRAY OR OBJECT TYPE\n");
334 out->gen = ((
struct node *)buf)->gen_type;
336 out->node_ofs[0] = (u32)ofs;
339 while (
node->child_ofs[0]) {
340 u32 next_node_ofs =
node->child_ofs[0];
344 if (LITE3_UNLIKELY(((uintptr_t)
node & LITE3_NODE_ALIGNMENT_MASK) != 0)) {
345 LITE3_PRINT_ERROR(
"NODE OFFSET NOT ALIGNED TO LITE3_NODE_ALIGNMENT\n");
350 LITE3_PRINT_ERROR(
"NODE WALKS EXCEEDED LITE3_TREE_HEIGHT_MAX\n");
354 if (LITE3_UNLIKELY((
size_t)next_node_ofs > buflen -
LITE3_NODE_SIZE)) {
355 LITE3_PRINT_ERROR(
"NODE WALK OFFSET OUT OF BOUNDS\n");
359 out->node_ofs[out->depth] = next_node_ofs;
360 out->node_i[out->depth] = 0;
362 #ifdef LITE3_PREFETCHING
363 __builtin_prefetch(buf +
node->kv_ofs[0], 0, 0);
364 __builtin_prefetch(buf +
node->kv_ofs[0] + 64, 0, 0);
365 __builtin_prefetch(buf +
node->kv_ofs[1], 0, 0);
366 __builtin_prefetch(buf +
node->kv_ofs[1] + 64, 0, 0);
367 __builtin_prefetch(buf +
node->kv_ofs[2], 0, 0);
368 __builtin_prefetch(buf +
node->kv_ofs[2] + 64, 0, 0);
375 if (LITE3_UNLIKELY(iter->gen != ((
struct node *)buf)->gen_type)) {
376 LITE3_PRINT_ERROR(
"ITERATOR INVALID: iter->gen != node->gen_type (BUFFER MUTATION INVALIDATES ITERATORS)\n");
383 if (LITE3_UNLIKELY(((uintptr_t)
node & LITE3_NODE_ALIGNMENT_MASK) != 0)) {
384 LITE3_PRINT_ERROR(
"NODE OFFSET NOT ALIGNED TO LITE3_NODE_ALIGNMENT\n");
391 LITE3_PRINT_ERROR(
"INVALID ARGUMENT: EXPECTING ARRAY OR OBJECT TYPE\n");
395 if (iter->depth == 0 && (iter->node_i[iter->depth] == (
node->size_kc & LITE3_NODE_KEY_COUNT_MASK))) {
398 size_t target_ofs =
node->kv_ofs[iter->node_i[iter->depth]];
403 size_t key_start_ofs = target_ofs;
404 if ((ret = _verify_key(buf, buflen, NULL, 0, 0, &target_ofs, &key_tag_size)) < 0)
407 out_key->
gen = iter->gen;
409 memcpy(&out_key->
len, buf + key_start_ofs, key_tag_size);
411 out_key->
ptr = (
const char *)(buf + key_start_ofs + key_tag_size);
415 size_t val_start_ofs = target_ofs;
416 if ((ret = _verify_val(buf, buflen, &target_ofs)) < 0)
418 *out_val_ofs = val_start_ofs;
421 ++iter->node_i[iter->depth];
423 while (
node->child_ofs[iter->node_i[iter->depth]]) {
424 u32 next_node_ofs =
node->child_ofs[iter->node_i[iter->depth]];
428 if (LITE3_UNLIKELY(((uintptr_t)
node & LITE3_NODE_ALIGNMENT_MASK) != 0)) {
429 LITE3_PRINT_ERROR(
"NODE OFFSET NOT ALIGNED TO LITE3_NODE_ALIGNMENT\n");
434 LITE3_PRINT_ERROR(
"NODE WALKS EXCEEDED LITE3_TREE_HEIGHT_MAX\n");
438 if (LITE3_UNLIKELY((
size_t)next_node_ofs > buflen -
LITE3_NODE_SIZE)) {
439 LITE3_PRINT_ERROR(
"NODE WALK OFFSET OUT OF BOUNDS\n");
443 iter->node_ofs[iter->depth] = next_node_ofs;
444 iter->node_i[iter->depth] = 0;
446 while (iter->depth > 0 && (iter->node_i[iter->depth] == (
node->size_kc & LITE3_NODE_KEY_COUNT_MASK))) {
450 if (LITE3_UNLIKELY(((uintptr_t)
node & LITE3_NODE_ALIGNMENT_MASK) != 0)) {
451 LITE3_PRINT_ERROR(
"NODE OFFSET NOT ALIGNED TO LITE3_NODE_ALIGNMENT\n");
455 #ifdef LITE3_PREFETCHING
456 __builtin_prefetch(buf +
node->child_ofs[(u32)(iter->node_i[iter->depth] + 1) & LITE3_NODE_KEY_COUNT_MASK], 0, 2);
457 __builtin_prefetch(buf +
node->child_ofs[(u32)(iter->node_i[iter->depth] + 1) & LITE3_NODE_KEY_COUNT_MASK] + 64, 0, 2);
458 __builtin_prefetch(buf +
node->child_ofs[(u32)(iter->node_i[iter->depth] + 2) & LITE3_NODE_KEY_COUNT_MASK], 0, 2);
459 __builtin_prefetch(buf +
node->child_ofs[(u32)(iter->node_i[iter->depth] + 2) & LITE3_NODE_KEY_COUNT_MASK] + 64, 0, 2);
462 #ifdef LITE3_PREFETCHING
463 __builtin_prefetch(buf +
node->kv_ofs[(u32)(iter->node_i[iter->depth] + 0) & LITE3_NODE_KEY_COUNT_MASK], 0, 0);
464 __builtin_prefetch(buf +
node->kv_ofs[(u32)(iter->node_i[iter->depth] + 0) & LITE3_NODE_KEY_COUNT_MASK] + 64, 0, 0);
465 __builtin_prefetch(buf +
node->kv_ofs[(u32)(iter->node_i[iter->depth] + 1) & LITE3_NODE_KEY_COUNT_MASK], 0, 0);
466 __builtin_prefetch(buf +
node->kv_ofs[(u32)(iter->node_i[iter->depth] + 1) & LITE3_NODE_KEY_COUNT_MASK] + 64, 0, 0);
467 __builtin_prefetch(buf +
node->kv_ofs[(u32)(iter->node_i[iter->depth] + 2) & LITE3_NODE_KEY_COUNT_MASK], 0, 0);
468 __builtin_prefetch(buf +
node->kv_ofs[(u32)(iter->node_i[iter->depth] + 2) & LITE3_NODE_KEY_COUNT_MASK] + 64, 0, 0);
474static inline void _lite3_init_impl(
unsigned char *buf,
size_t ofs,
enum lite3_type type)
476 LITE3_PRINT_DEBUG(
"INITIALIZE %s\n", type ==
LITE3_TYPE_OBJECT ?
"OBJECT" :
"ARRAY");
479 node->gen_type = type & LITE3_NODE_TYPE_MASK;
480 node->size_kc = 0x00;
481 #ifdef LITE3_ZERO_MEM_EXTRA
482 memset(
node->hashes, LITE3_ZERO_MEM_8,
sizeof(((
struct node *)0)->hashes));
483 memset(
node->kv_ofs, LITE3_ZERO_MEM_8,
sizeof(((
struct node *)0)->kv_ofs));
485 memset(
node->child_ofs, 0x00,
sizeof(((
struct node *)0)->child_ofs));
488int lite3_init_obj(
unsigned char *buf,
size_t *restrict out_buflen,
size_t bufsz)
491 LITE3_PRINT_ERROR(
"INVALID ARGUMENT: bufsz < LITE3_NODE_SIZE\n");
500int lite3_init_arr(
unsigned char *buf,
size_t *restrict out_buflen,
size_t bufsz)
503 LITE3_PRINT_ERROR(
"INVALID ARGUMENT: bufsz < LITE3_NODE_SIZE\n");
525 size_t *restrict inout_buflen,
528 const char *restrict key,
529 lite3_key_data key_data,
535 LITE3_PRINT_DEBUG(
"SET\tkey: %s\n", key);
537 LITE3_PRINT_DEBUG(
"SET\tindex: %u\n", key_data.hash);
539 LITE3_PRINT_DEBUG(
"SET INVALID: EXPECTING ARRAY OR OBJECT TYPE\n");
543 size_t key_tag_size = (size_t)((!!(key_data.size >> (16 - LITE3_KEY_TAG_KEY_SIZE_SHIFT)) << 1)
544 + !!(key_data.size >> (8 - LITE3_KEY_TAG_KEY_SIZE_SHIFT))
546 size_t base_entry_size = key_tag_size + (size_t)key_data.size + LITE3_VAL_SIZE + val_len;
550 if (LITE3_UNLIKELY(((uintptr_t)root & LITE3_NODE_ALIGNMENT_MASK) != 0)) {
551 LITE3_PRINT_ERROR(
"NODE OFFSET NOT ALIGNED TO LITE3_NODE_ALIGNMENT\n");
556 u32 gen = root->gen_type >> LITE3_NODE_GEN_SHIFT;
558 root->gen_type = (root->gen_type & ~LITE3_NODE_GEN_MASK) | (gen << LITE3_NODE_GEN_SHIFT);
561 for (uint32_t attempt = 0; attempt < probe_attempts; attempt++) {
563 lite3_key_data attempt_key = key_data;
564 attempt_key.hash = key_data.hash + attempt * attempt;
568 size_t entry_size = base_entry_size;
569 struct node *restrict parent = NULL;
577 if ((
node->size_kc & LITE3_NODE_KEY_COUNT_MASK) == LITE3_NODE_KEY_COUNT_MAX) {
579 size_t buflen_aligned = (*inout_buflen + LITE3_NODE_ALIGNMENT_MASK) & ~(
size_t)LITE3_NODE_ALIGNMENT_MASK;
582 if (LITE3_UNLIKELY(new_node_size > bufsz || buflen_aligned > bufsz - new_node_size)) {
583 LITE3_PRINT_ERROR(
"NO BUFFER SPACE FOR NODE SPLIT\n");
587 *inout_buflen = buflen_aligned;
590 LITE3_PRINT_DEBUG(
"NEW ROOT\n");
594 if (LITE3_UNLIKELY(((uintptr_t)
node & LITE3_NODE_ALIGNMENT_MASK) != 0)) {
595 LITE3_PRINT_ERROR(
"NODE OFFSET NOT ALIGNED TO LITE3_NODE_ALIGNMENT\n");
601 if (LITE3_UNLIKELY(((uintptr_t)parent & LITE3_NODE_ALIGNMENT_MASK) != 0)) {
602 LITE3_PRINT_ERROR(
"NODE OFFSET NOT ALIGNED TO LITE3_NODE_ALIGNMENT\n");
606 #ifdef LITE3_ZERO_MEM_EXTRA
607 memset(parent->hashes, LITE3_ZERO_MEM_8,
sizeof(((
struct node *)0)->hashes));
608 memset(parent->kv_ofs, LITE3_ZERO_MEM_8,
sizeof(((
struct node *)0)->kv_ofs));
609 memset(parent->child_ofs, 0x00,
sizeof(((
struct node *)0)->child_ofs));
611 parent->size_kc &= ~LITE3_NODE_KEY_COUNT_MASK;
612 parent->child_ofs[0] = (u32)*inout_buflen;
617 LITE3_PRINT_DEBUG(
"SPLIT NODE\n");
618 for (
int j = key_count; j > i; j--) {
619 parent->hashes[j] = parent->hashes[j - 1];
620 parent->kv_ofs[j] = parent->kv_ofs[j - 1];
621 parent->child_ofs[j + 1] = parent->child_ofs[j];
623 parent->hashes[i] =
node->hashes[LITE3_NODE_KEY_COUNT_MIN];
624 parent->kv_ofs[i] =
node->kv_ofs[LITE3_NODE_KEY_COUNT_MIN];
625 parent->child_ofs[i + 1] = (u32)*inout_buflen;
626 parent->size_kc = (parent->size_kc & ~LITE3_NODE_KEY_COUNT_MASK)
627 | ((parent->size_kc + 1) & LITE3_NODE_KEY_COUNT_MASK);
628 #ifdef LITE3_ZERO_MEM_EXTRA
629 node->hashes[LITE3_NODE_KEY_COUNT_MIN] = LITE3_ZERO_MEM_32;
630 node->kv_ofs[LITE3_NODE_KEY_COUNT_MIN] = LITE3_ZERO_MEM_32;
634 if (LITE3_UNLIKELY(((uintptr_t)sibling & LITE3_NODE_ALIGNMENT_MASK) != 0)) {
635 LITE3_PRINT_ERROR(
"NODE OFFSET NOT ALIGNED TO LITE3_NODE_ALIGNMENT\n");
639 #ifdef LITE3_ZERO_MEM_EXTRA
640 memset(sibling->hashes, LITE3_ZERO_MEM_8,
sizeof(((
struct node *)0)->hashes));
641 memset(sibling->kv_ofs, LITE3_ZERO_MEM_8,
sizeof(((
struct node *)0)->kv_ofs));
643 sibling->gen_type = ((
struct node *)(buf + ofs))->gen_type & LITE3_NODE_TYPE_MASK;
644 sibling->size_kc = LITE3_NODE_KEY_COUNT_MIN & LITE3_NODE_KEY_COUNT_MASK;
645 node->size_kc = LITE3_NODE_KEY_COUNT_MIN & LITE3_NODE_KEY_COUNT_MASK;
646 memset(sibling->child_ofs, 0x00,
sizeof(((
struct node *)0)->child_ofs));
647 sibling->child_ofs[0] =
node->child_ofs[LITE3_NODE_KEY_COUNT_MIN + 1];
648 node->child_ofs[LITE3_NODE_KEY_COUNT_MIN + 1] = 0x00;
649 for (
int j = 0; j < LITE3_NODE_KEY_COUNT_MIN; j++) {
650 sibling->hashes[j] =
node->hashes[j + LITE3_NODE_KEY_COUNT_MIN + 1];
651 sibling->kv_ofs[j] =
node->kv_ofs[j + LITE3_NODE_KEY_COUNT_MIN + 1];
652 sibling->child_ofs[j + 1] =
node->child_ofs[j + LITE3_NODE_KEY_COUNT_MIN + 2];
653 #ifdef LITE3_ZERO_MEM_EXTRA
654 node->hashes[j + LITE3_NODE_KEY_COUNT_MIN + 1] = LITE3_ZERO_MEM_32;
655 node->kv_ofs[j + LITE3_NODE_KEY_COUNT_MIN + 1] = LITE3_ZERO_MEM_32;
656 node->child_ofs[j + LITE3_NODE_KEY_COUNT_MIN + 2] = 0x00000000;
660 if (attempt_key.hash > parent->hashes[i]) {
663 if (LITE3_UNLIKELY(((uintptr_t)
node & LITE3_NODE_ALIGNMENT_MASK) != 0)) {
664 LITE3_PRINT_ERROR(
"NODE OFFSET NOT ALIGNED TO LITE3_NODE_ALIGNMENT\n");
668 }
else if (attempt_key.hash == parent->hashes[i]) {
670 LITE3_PRINT_DEBUG(
"GOTO SKIP\n");
675 key_count =
node->size_kc & LITE3_NODE_KEY_COUNT_MASK;
677 while (i < key_count && node->hashes[i] < attempt_key.hash)
682 if (i < key_count && node->hashes[i] == attempt_key.hash) {
685 size_t target_ofs =
node->kv_ofs[i];
686 size_t key_start_ofs = target_ofs;
688 int verify = _verify_key(buf, *inout_buflen, key, (
size_t)attempt_key.size, key_tag_size, &target_ofs, NULL);
689 if (verify == LITE3_VERIFY_KEY_HASH_COLLISION)
694 size_t val_start_ofs = target_ofs;
695 if (_verify_val(buf, *inout_buflen, &target_ofs) < 0)
697 if (val_len >= target_ofs - val_start_ofs) {
698 size_t alignment_mask = val_len == lite3_type_sizes[
LITE3_TYPE_OBJECT] ? (size_t)LITE3_NODE_ALIGNMENT_MASK : 0;
699 size_t unaligned_val_ofs = *inout_buflen + key_tag_size + (size_t)attempt_key.size;
700 size_t alignment_padding = ((unaligned_val_ofs + alignment_mask) & ~alignment_mask) - unaligned_val_ofs;
701 entry_size += alignment_padding;
702 if (LITE3_UNLIKELY(entry_size > bufsz || *inout_buflen > bufsz - entry_size)) {
703 LITE3_PRINT_ERROR(
"NO BUFFER SPACE FOR ENTRY INSERTION\n");
708 #ifdef LITE3_ZERO_MEM_DELETED
709 memset(buf +
node->kv_ofs[i], LITE3_ZERO_MEM_8, target_ofs - key_start_ofs);
711 #ifdef LITE3_ZERO_MEM_EXTRA
712 memset(buf + *inout_buflen, LITE3_ZERO_MEM_8, alignment_padding);
714 *inout_buflen += alignment_padding;
715 node->kv_ofs[i] = (u32)*inout_buflen;
719 #ifdef LITE3_ZERO_MEM_DELETED
720 memset(buf + val_start_ofs, LITE3_ZERO_MEM_8, target_ofs - val_start_ofs);
722 *out = (
lite3_val *)(buf + val_start_ofs);
726 if (
node->child_ofs[0]) {
727 size_t next_node_ofs = (size_t)
node->child_ofs[i];
732 if (LITE3_UNLIKELY(((uintptr_t)
node & LITE3_NODE_ALIGNMENT_MASK) != 0)) {
733 LITE3_PRINT_ERROR(
"NODE OFFSET NOT ALIGNED TO LITE3_NODE_ALIGNMENT\n");
738 LITE3_PRINT_ERROR(
"NODE WALK OFFSET OUT OF BOUNDS\n");
743 LITE3_PRINT_ERROR(
"NODE WALKS EXCEEDED LITE3_TREE_HEIGHT_MAX\n");
748 size_t alignment_mask = val_len == lite3_type_sizes[
LITE3_TYPE_OBJECT] ? (size_t)LITE3_NODE_ALIGNMENT_MASK : 0;
749 size_t unaligned_val_ofs = *inout_buflen + key_tag_size + (size_t)attempt_key.size;
750 size_t alignment_padding = ((unaligned_val_ofs + alignment_mask) & ~alignment_mask) - unaligned_val_ofs;
751 entry_size += alignment_padding;
752 if (LITE3_UNLIKELY(entry_size > bufsz || *inout_buflen > bufsz - entry_size)) {
753 LITE3_PRINT_ERROR(
"NO BUFFER SPACE FOR ENTRY INSERTION\n");
757 for (
int j = key_count; j > i; j--) {
758 node->hashes[j] =
node->hashes[j - 1];
759 node->kv_ofs[j] =
node->kv_ofs[j - 1];
762 node->hashes[i] = attempt_key.hash;
763 node->size_kc = (
node->size_kc & ~LITE3_NODE_KEY_COUNT_MASK)
764 | ((
node->size_kc + 1) & LITE3_NODE_KEY_COUNT_MASK);
765 #ifdef LITE3_ZERO_MEM_EXTRA
766 memset(buf + *inout_buflen, LITE3_ZERO_MEM_8, alignment_padding);
768 *inout_buflen += alignment_padding;
769 node->kv_ofs[i] = (u32)*inout_buflen;
772 u32 size = root->size_kc >> LITE3_NODE_SIZE_SHIFT;
774 root->size_kc = (root->size_kc & ~LITE3_NODE_SIZE_MASK) | (size << LITE3_NODE_SIZE_SHIFT);
781 size_t key_size_tmp = (attempt_key.size << LITE3_KEY_TAG_KEY_SIZE_SHIFT) | (key_tag_size - 1);
782 memcpy(buf + *inout_buflen, &key_size_tmp, key_tag_size);
783 *inout_buflen += key_tag_size;
784 memcpy(buf + *inout_buflen, key, (
size_t)attempt_key.size);
785 *inout_buflen += (size_t)attempt_key.size;
787 *out = (
lite3_val *)(buf + *inout_buflen);
788 *inout_buflen += LITE3_VAL_SIZE + val_len;
789 LITE3_PRINT_DEBUG(
"OK\n");
792 LITE3_PRINT_ERROR(
"LITE3_HASH_PROBE_MAX LIMIT REACHED\n");
797int 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)
801 if ((ret = lite3_set_impl(buf, inout_buflen, ofs, bufsz, key, key_data, lite3_type_sizes[
LITE3_TYPE_OBJECT], &val)) < 0)
803 size_t init_ofs = (size_t)((u8 *)val - buf);
810int 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)
814 if ((ret = lite3_set_impl(buf, inout_buflen, ofs, bufsz, key, key_data, lite3_type_sizes[
LITE3_TYPE_ARRAY], &val)) < 0)
816 size_t init_ofs = (size_t)((u8 *)val - buf);
823int lite3_arr_append_obj_impl(
unsigned char *buf,
size_t *restrict inout_buflen,
size_t ofs,
size_t bufsz,
size_t *restrict out_ofs)
825 u32 size = ((
struct node *)(buf + ofs))->size_kc >> LITE3_NODE_SIZE_SHIFT;
826 lite3_key_data key_data = {
832 if ((ret = lite3_set_impl(buf, inout_buflen, ofs, bufsz, NULL, key_data, lite3_type_sizes[
LITE3_TYPE_OBJECT], &val)) < 0)
834 size_t init_ofs = (size_t)((u8 *)val - buf);
841int lite3_arr_append_arr_impl(
unsigned char *buf,
size_t *restrict inout_buflen,
size_t ofs,
size_t bufsz,
size_t *restrict out_ofs)
843 u32 size = ((
struct node *)(buf + ofs))->size_kc >> LITE3_NODE_SIZE_SHIFT;
844 lite3_key_data key_data = {
850 if ((ret = lite3_set_impl(buf, inout_buflen, ofs, bufsz, NULL, key_data, lite3_type_sizes[
LITE3_TYPE_ARRAY], &val)) < 0)
852 size_t init_ofs = (size_t)((u8 *)val - buf);
859int 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)
861 u32 size = ((
struct node *)(buf + ofs))->size_kc >> LITE3_NODE_SIZE_SHIFT;
862 if (LITE3_UNLIKELY(index > size)) {
863 LITE3_PRINT_ERROR(
"INVALID ARGUMENT: ARRAY INDEX %u OUT OF BOUNDS (size == %u)\n", index, size);
867 lite3_key_data key_data = {
873 if ((ret = lite3_set_impl(buf, inout_buflen, ofs, bufsz, NULL, key_data, lite3_type_sizes[
LITE3_TYPE_OBJECT], &val)) < 0)
875 size_t init_ofs = (size_t)((u8 *)val - buf);
882int 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)
884 u32 size = ((
struct node *)(buf + ofs))->size_kc >> LITE3_NODE_SIZE_SHIFT;
885 if (LITE3_UNLIKELY(index > size)) {
886 LITE3_PRINT_ERROR(
"INVALID ARGUMENT: ARRAY INDEX %u OUT OF BOUNDS (size == %u)\n", index, size);
890 lite3_key_data key_data = {
896 if ((ret = lite3_set_impl(buf, inout_buflen, ofs, bufsz, NULL, key_data, lite3_type_sizes[
LITE3_TYPE_ARRAY], &val)) < 0)
898 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.
#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.