1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
|
#ifndef ART_ART_H
#define ART_ART_H
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
/*
* This file contains an implementation of an Adaptive Radix Tree as described
* in https://db.in.tum.de/~leis/papers/ART.pdf.
*
* The ART contains the keys in _byte lexographical_ order.
*
* Other features:
* * Fixed 48 bit key length: all keys are assumed to be be 48 bits in size.
* This allows us to put the key and key prefixes directly in nodes, reducing
* indirection at no additional memory overhead.
* * Key compression: the only inner nodes created are at points where key
* chunks _differ_. This means that if there are two entries with different
* high 48 bits, then there is only one inner node containing the common key
* prefix, and two leaves.
* * Mostly pointer-free: nodes are referred to by index rather than pointer,
* so that the structure can be deserialized with a backing buffer.
*/
// Fixed length of keys in the ART. All keys are assumed to be of this length.
#define ART_KEY_BYTES 6
#ifdef __cplusplus
extern "C" {
namespace roaring {
namespace internal {
#endif
typedef uint8_t art_key_chunk_t;
// Internal node reference type. Contains the node typecode in the low 8 bits,
// and the index in the relevant node array in the high 48 bits. Has a value of
// CROARING_ART_NULL_REF when pointing to a non-existent node.
typedef uint64_t art_ref_t;
typedef void art_node_t;
/**
* The ART is empty when root is a null ref.
*
* Each node type has its own dynamic array of node structs, indexed by
* art_ref_t. The arrays are expanded as needed, and shrink only when
* `shrink_to_fit` is called.
*/
typedef struct art_s {
art_ref_t root;
// Indexed by node typecode, thus 1 larger than they need to be for
// convenience. `first_free` indicates the index where the first free node
// lives, which may be equal to the capacity.
uint64_t first_free[6];
uint64_t capacities[6];
art_node_t *nodes[6];
} art_t;
typedef uint64_t art_val_t;
/**
* Compares two keys, returns their relative order:
* * Key 1 < key 2: returns a negative value
* * Key 1 == key 2: returns 0
* * Key 1 > key 2: returns a positive value
*/
int art_compare_keys(const art_key_chunk_t key1[],
const art_key_chunk_t key2[]);
/**
* Initializes the ART.
*/
void art_init_cleared(art_t *art);
/**
* Inserts the given key and value. Returns a pointer to the value inserted,
* valid as long as the ART is not modified.
*/
art_val_t *art_insert(art_t *art, const art_key_chunk_t *key, art_val_t val);
/**
* Returns true if a value was erased. Sets `*erased_val` to the value erased,
* if any.
*/
bool art_erase(art_t *art, const art_key_chunk_t *key, art_val_t *erased_val);
/**
* Returns the value associated with the given key, NULL if not found.
*/
art_val_t *art_find(const art_t *art, const art_key_chunk_t *key);
/**
* Returns true if the ART is empty.
*/
bool art_is_empty(const art_t *art);
/**
* Frees the contents of the ART. Should not be called when using
* `art_deserialize_frozen_safe`.
*/
void art_free(art_t *art);
/**
* Prints the ART using printf, useful for debugging.
*/
void art_printf(const art_t *art);
/**
* Callback for validating the value stored in a leaf. `context` is a
* user-provided value passed to the callback without modification.
*
* Should return true if the value is valid, false otherwise
* If false is returned, `*reason` should be set to a static string describing
* the reason for the failure.
*/
typedef bool (*art_validate_cb_t)(const art_val_t val, const char **reason,
void *context);
/**
* Validate the ART tree, ensuring it is internally consistent. `context` is a
* user-provided value passed to the callback without modification.
*/
bool art_internal_validate(const art_t *art, const char **reason,
art_validate_cb_t validate_cb, void *context);
/**
* ART-internal iterator bookkeeping. Users should treat this as an opaque type.
*/
typedef struct art_iterator_frame_s {
art_ref_t ref;
uint8_t index_in_node;
} art_iterator_frame_t;
/**
* Users should only access `key` and `value` in iterators. The iterator is
* valid when `value != NULL`.
*/
typedef struct art_iterator_s {
art_key_chunk_t key[ART_KEY_BYTES];
art_val_t *value;
art_t *art;
uint8_t depth; // Key depth
uint8_t frame; // Node depth
// State for each node in the ART the iterator has travelled from the root.
// This is `ART_KEY_BYTES + 1` because it includes state for the leaf too.
art_iterator_frame_t frames[ART_KEY_BYTES + 1];
} art_iterator_t;
/**
* Creates an iterator initialzed to the first or last entry in the ART,
* depending on `first`. The iterator is not valid if there are no entries in
* the ART.
*/
art_iterator_t art_init_iterator(art_t *art, bool first);
/**
* Returns an initialized iterator positioned at a key equal to or greater than
* the given key, if it exists.
*/
art_iterator_t art_lower_bound(art_t *art, const art_key_chunk_t *key);
/**
* Returns an initialized iterator positioned at a key greater than the given
* key, if it exists.
*/
art_iterator_t art_upper_bound(art_t *art, const art_key_chunk_t *key);
/**
* The following iterator movement functions return true if a new entry was
* encountered.
*/
bool art_iterator_move(art_iterator_t *iterator, bool forward);
bool art_iterator_next(art_iterator_t *iterator);
bool art_iterator_prev(art_iterator_t *iterator);
/**
* Moves the iterator forward to a key equal to or greater than the given key.
*/
bool art_iterator_lower_bound(art_iterator_t *iterator,
const art_key_chunk_t *key);
/**
* Insert the value and positions the iterator at the key.
*/
void art_iterator_insert(art_iterator_t *iterator, const art_key_chunk_t *key,
art_val_t val);
/**
* Erase the value pointed at by the iterator. Moves the iterator to the next
* leaf.
* Returns true if a value was erased. Sets `*erased_val` to the value erased,
* if any.
*/
bool art_iterator_erase(art_iterator_t *iterator, art_val_t *erased_val);
/**
* Shrinks the internal arrays in the ART to remove any unused elements. Returns
* the number of bytes freed.
*/
size_t art_shrink_to_fit(art_t *art);
/**
* Returns true if the ART has no unused elements.
*/
bool art_is_shrunken(const art_t *art);
/**
* Returns the serialized size in bytes.
* Requires `art_shrink_to_fit` to be called first.
*/
size_t art_size_in_bytes(const art_t *art);
/**
* Serializes the ART and returns the number of bytes written. Returns 0 on
* error. Requires `art_shrink_to_fit` to be called first.
*/
size_t art_serialize(const art_t *art, char *buf);
/**
* Deserializes the ART from a serialized buffer, reading up to `maxbytes`
* bytes. Returns 0 on error. Requires `buf` to be 8 byte aligned.
*
* An ART deserialized in this way should only be used in a readonly context.The
* underlying buffer must not be freed before the ART. `art_free` should not be
* called on the ART deserialized in this way.
*/
size_t art_frozen_view(const char *buf, size_t maxbytes, art_t *art);
#ifdef __cplusplus
} // extern "C"
} // namespace roaring
} // namespace internal
#endif
#endif
|