Line data Source code
1 : #include "fd_pod.h"
2 :
3 : /* FD_POD_PATH_SPLIT splits the path into a leading key prefix and a
4 : suffix. On return, prefix_len is the number of bytes in a strlen
5 : sense of the leading key prefix. If delim is '.', suffix points to
6 : the first byte of the path suffix. If delim is '\0', the path is
7 : just a single key with no suffix and suffix should be ignored. This
8 : macro is not robust. */
9 :
10 30073752 : #define FD_POD_PATH_SPLIT( path, prefix_len, delim, suffix ) do { \
11 30073752 : suffix = path; \
12 145736415 : for(;;) { \
13 145736415 : delim = suffix[0]; \
14 145736415 : if( FD_UNLIKELY( (delim=='.') | (!delim) ) ) break; \
15 145736415 : suffix++; \
16 115662663 : } \
17 30073752 : prefix_len = (ulong)(suffix - path); \
18 30073752 : suffix++; \
19 30073752 : } while(0)
20 :
21 : /* FD_POD_FOR_ALL_BEGIN / FD_POD_FOR_ALL_END iterates over all key-val
22 : pairs in a pod. Each iteration:
23 :
24 : uchar * pair points to the first byte of the encoded key-val pair
25 : uchar * next points to the one after the last byte of the encoded key-val pair
26 : ulong ksz is the SVW encoded width of the key_sz field
27 : ulong key_sz is the strlen(key)+1 of the key
28 : char * key is points to the first byte of the key cstr
29 : int val_type is the type of val associated with this key (FD_POD_VAL_TYPE_*)
30 : ulong vsz is the SVW encoded width of the val_sz field
31 : ulong val_sz is the number of bytes in the encoded value
32 : void * val points to the first byte of the encoded val
33 :
34 : The actual iteration process does not depend on these values.
35 : (E.g. caller can mangle these without impact the iteration.)
36 :
37 : There are also variables:
38 : ulong _csz is the SWV encoded width of the pod header variables
39 : ulong _used is the number of bytes used in the pod
40 : ulong _cursor is the next byte to process in the iteration
41 : ulong _stop is one after the last byte to process in the iteration
42 :
43 : This macro is not robust. */
44 :
45 : #define FD_POD_FOR_ALL_BEGIN( pod, pair, next, ksz, key_sz, key, val_type, vsz, val_sz, val ) \
46 704327799 : do { \
47 704327799 : ulong _csz = fd_ulong_svw_dec_sz( pod ); \
48 704327799 : ulong _used = fd_ulong_svw_dec_fixed( pod + _csz, _csz ); \
49 704327799 : uchar * _cursor = (uchar *)(pod + _csz*3UL); \
50 704327799 : uchar * _stop = (uchar *)(pod + _used); \
51 1984565784 : while( _cursor<_stop ) { \
52 1303928016 : pair = _cursor; (void)pair; \
53 1303928016 : ksz = fd_ulong_svw_dec_sz( _cursor ); \
54 1303928016 : key_sz = fd_ulong_svw_dec_fixed( _cursor, ksz ); _cursor += ksz; \
55 1303928016 : key = (char *)_cursor; _cursor += key_sz; (void)key; \
56 1303928016 : val_type = (int)_cursor[0]; _cursor += 1; (void)val_type; \
57 1303928016 : vsz = fd_ulong_svw_dec_sz( _cursor ); \
58 1303928016 : val_sz = fd_ulong_svw_dec_fixed( _cursor, vsz ); _cursor += vsz; \
59 1303928016 : val = (void *)_cursor; _cursor += val_sz; (void)val; \
60 1303928016 : next = _cursor; (void)next; \
61 :
62 : #define FD_POD_FOR_ALL_END \
63 1303928016 : } \
64 704327799 : } while(0)
65 :
66 : fd_pod_info_t *
67 : fd_pod_list( uchar const * FD_RESTRICT pod,
68 457380 : fd_pod_info_t * FD_RESTRICT info ) {
69 457380 : if( FD_UNLIKELY( !pod ) ) return NULL;
70 :
71 457380 : ulong idx = 0UL;
72 :
73 457380 : uchar const * pair; uchar const * next;
74 457380 : ulong ksz; ulong key_sz; char const * key; int val_type;
75 457380 : ulong vsz; ulong val_sz; void const * val;
76 16818084 : FD_POD_FOR_ALL_BEGIN( pod, pair, next, ksz, key_sz, key, val_type, vsz, val_sz, val ) {
77 :
78 16818084 : info[idx].key_sz = key_sz;
79 16818084 : info[idx].key = key;
80 16818084 : info[idx].val_type = val_type;
81 16818084 : info[idx].val_sz = val_sz;
82 16818084 : info[idx].val = val;
83 16818084 : info[idx].parent = NULL;
84 16818084 : idx++;
85 :
86 16818084 : } FD_POD_FOR_ALL_END;
87 :
88 457380 : return info;
89 457380 : }
90 :
91 : ulong
92 6 : fd_pod_cnt_subpod( uchar const * FD_RESTRICT pod ) {
93 6 : if( FD_UNLIKELY( !pod ) ) return 0UL;
94 :
95 6 : ulong cnt = 0UL;
96 :
97 6 : uchar const * pair; uchar const * next;
98 6 : ulong ksz; ulong key_sz; char const * key; int val_type;
99 6 : ulong vsz; ulong val_sz; void const * val;
100 51 : FD_POD_FOR_ALL_BEGIN( pod, pair, next, ksz, key_sz, key, val_type, vsz, val_sz, val ) {
101 51 : cnt += (ulong)(val_type==FD_POD_VAL_TYPE_SUBPOD);
102 51 : } FD_POD_FOR_ALL_END;
103 :
104 6 : return cnt;
105 6 : }
106 :
107 : ulong
108 505290042 : fd_pod_cnt_recursive( uchar const * FD_RESTRICT pod ) {
109 505290042 : if( FD_UNLIKELY( !pod ) ) return 0UL;
110 :
111 505290042 : ulong cnt = 0UL;
112 :
113 505290042 : uchar const * pair; uchar const * next;
114 505290042 : ulong ksz; ulong key_sz; char const * key; int val_type;
115 505290042 : ulong vsz; ulong val_sz; void const * val;
116 1078568358 : FD_POD_FOR_ALL_BEGIN( pod, pair, next, ksz, key_sz, key, val_type, vsz, val_sz, val ) {
117 1078568358 : cnt++;
118 1078568358 : if( val_type==FD_POD_VAL_TYPE_SUBPOD ) cnt += fd_pod_cnt_recursive( (uchar *)val );
119 1078568358 : } FD_POD_FOR_ALL_END;
120 :
121 505290042 : return cnt;
122 505290042 : }
123 :
124 : static fd_pod_info_t *
125 : fd_pod_list_recursive_node( fd_pod_info_t * FD_RESTRICT parent,
126 : uchar const * FD_RESTRICT pod,
127 728898 : fd_pod_info_t * FD_RESTRICT info ) {
128 :
129 728898 : uchar const * pair; uchar const * next;
130 728898 : ulong ksz; ulong key_sz; char const * key; int val_type;
131 728898 : ulong vsz; ulong val_sz; void const * val;
132 1533312 : FD_POD_FOR_ALL_BEGIN( pod, pair, next, ksz, key_sz, key, val_type, vsz, val_sz, val ) {
133 :
134 1533312 : info->key_sz = key_sz;
135 1533312 : info->key = key;
136 1533312 : info->val_type = val_type;
137 1533312 : info->val_sz = val_sz;
138 1533312 : info->val = val;
139 1533312 : info->parent = parent;
140 1533312 : info++;
141 :
142 1533312 : if( val_type==FD_POD_VAL_TYPE_SUBPOD ) info = fd_pod_list_recursive_node( info-1, (uchar *)val, info );
143 :
144 1533312 : } FD_POD_FOR_ALL_END;
145 :
146 728898 : return info;
147 728898 : }
148 :
149 : fd_pod_info_t *
150 : fd_pod_list_recursive( uchar const * FD_RESTRICT pod,
151 26769 : fd_pod_info_t * FD_RESTRICT info ) {
152 26769 : if( FD_UNLIKELY( !pod ) ) return info;
153 26769 : fd_pod_list_recursive_node( NULL, pod, info );
154 26769 : return info;
155 26769 : }
156 :
157 : int
158 : fd_pod_query( uchar const * FD_RESTRICT pod,
159 : char const * FD_RESTRICT path,
160 23594316 : fd_pod_info_t * FD_RESTRICT opt_info ) {
161 23594316 : if( FD_UNLIKELY( (!pod) | (!path) ) ) return FD_POD_ERR_INVAL;
162 :
163 23594316 : ulong prefix_len; char delim; char const * suffix;
164 23594316 : FD_POD_PATH_SPLIT( path, prefix_len, delim, suffix );
165 :
166 23594316 : uchar const * pair; uchar const * next;
167 23594316 : ulong ksz; ulong key_sz; char const * key; int val_type;
168 23594316 : ulong vsz; ulong val_sz; void const * val;
169 481516119 : FD_POD_FOR_ALL_BEGIN( pod, pair, next, ksz, key_sz, key, val_type, vsz, val_sz, val ) {
170 :
171 481516119 : if( ((key_sz-1UL)==prefix_len) && !memcmp( key, path, prefix_len ) ) { /* Found leading key in pod */
172 :
173 22449147 : if( !delim ) { /* Path was a single key, return it */
174 :
175 17060859 : if( opt_info ) {
176 17060859 : opt_info->key_sz = key_sz;
177 17060859 : opt_info->key = key;
178 17060859 : opt_info->val_type = val_type;
179 17060859 : opt_info->val_sz = val_sz;
180 17060859 : opt_info->val = val;
181 17060859 : opt_info->parent = NULL;
182 17060859 : }
183 17060859 : return FD_POD_SUCCESS;
184 :
185 17060859 : } else { /* Path had a suffix. Recurse into the subpod */
186 :
187 5388288 : if( FD_UNLIKELY( val_type!=FD_POD_VAL_TYPE_SUBPOD ) ) return FD_POD_ERR_TYPE;
188 5056332 : return fd_pod_query( (uchar const *)val, suffix, opt_info );
189 :
190 5388288 : }
191 22449147 : }
192 :
193 481516119 : } FD_POD_FOR_ALL_END;
194 :
195 1145169 : return FD_POD_ERR_RESOLVE;
196 23594316 : }
197 :
198 : char const *
199 18 : fd_pod_strerror( int err ) {
200 18 : switch( err ) {
201 3 : case FD_POD_SUCCESS: return "success";
202 3 : case FD_POD_ERR_INVAL: return "bad input args";
203 3 : case FD_POD_ERR_TYPE: return "path contained an unexpected type key";
204 3 : case FD_POD_ERR_RESOLVE: return "path did not resolve to a key";
205 3 : case FD_POD_ERR_FULL: return "pod too full";
206 3 : default: break;
207 18 : }
208 3 : return "unknown";
209 18 : }
210 :
211 : ulong
212 : fd_pod_resize( uchar * pod,
213 49689 : ulong new_max ) {
214 49689 : if( FD_UNLIKELY( !pod ) ) return 0UL;
215 :
216 49689 : ulong csz = fd_ulong_svw_dec_sz( pod );
217 : //ulong max = fd_ulong_svw_dec_fixed( pod, csz );
218 49689 : ulong used = fd_ulong_svw_dec_fixed( pod + csz, csz ); if( FD_UNLIKELY( used>new_max ) ) return 0UL;
219 49689 : ulong cnt = fd_ulong_svw_dec_fixed( pod + csz*2UL, csz );
220 49689 : ulong bdy_sz = used - csz*3UL;
221 :
222 49689 : ulong new_csz;
223 49689 : ulong new_used;
224 49689 : for(;;) {
225 49689 : new_csz = fd_ulong_svw_enc_sz( new_max );
226 49689 : new_used = new_csz*3UL + bdy_sz;
227 49689 : if( FD_LIKELY( new_used<=new_max ) ) break;
228 : /* Resized header was too large ... try a smaller new_max */
229 0 : new_max--;
230 0 : }
231 :
232 49689 : memmove( pod + new_csz*3UL, pod + csz*3UL, bdy_sz );
233 49689 : fd_ulong_svw_enc_fixed( pod, new_csz, new_max );
234 49689 : fd_ulong_svw_enc_fixed( pod + new_csz, new_csz, new_used );
235 49689 : fd_ulong_svw_enc_fixed( pod + new_csz*2UL, new_csz, cnt );
236 49689 : return new_max;
237 49689 : }
238 :
239 : ulong
240 : fd_pod_compact( uchar * pod,
241 167777721 : int full ) {
242 167777721 : if( FD_UNLIKELY( !pod ) ) return 0UL;
243 :
244 : /* Compact the body */
245 :
246 167777721 : ulong csz = fd_ulong_svw_dec_sz( pod );
247 167777721 : ulong max = fd_ulong_svw_dec_fixed( pod, csz );
248 167777721 : ulong cnt = fd_ulong_svw_dec_fixed( pod + csz*2UL, csz );
249 167777721 : uchar * bdy = pod + csz*3UL;
250 :
251 167777721 : uchar * pair; uchar * next = bdy;
252 167777721 : ulong ksz; ulong key_sz; char const * key; int val_type;
253 167777721 : ulong vsz; ulong val_sz; void * val;
254 358351737 : FD_POD_FOR_ALL_BEGIN( pod, pair, next, ksz, key_sz, key, val_type, vsz, val_sz, val ) {
255 :
256 : /* Compact the pair */
257 :
258 358351737 : ulong new_key_sz = strlen( key ) + 1UL; /* <=key_sz */
259 358351737 : ulong new_ksz = fd_ulong_svw_enc_sz( new_key_sz );
260 :
261 358351737 : ulong new_val_sz;
262 358351737 : if( val_type==FD_POD_VAL_TYPE_SUBPOD ) {
263 167548605 : uchar * subpod = (uchar *)val;
264 167548605 : fd_pod_compact( subpod, 1 /*full*/ ); /* Yes, do not pass through the user provided value of full */
265 167548605 : new_val_sz = fd_pod_max( subpod ); /* ==fd_pod_used at this point */
266 167548605 : } else if( val_type==FD_POD_VAL_TYPE_CSTR ) {
267 1537479 : new_val_sz = val_sz ? (strlen( (char *)val )+1UL) : 0UL;
268 21487932 : } else {
269 21487932 : new_val_sz = val_sz;
270 21487932 : }
271 : /* Note: new_val_sz<=val_sz */
272 358351737 : ulong new_vsz = fd_ulong_svw_enc_sz( new_val_sz );
273 :
274 358351737 : uchar * new_cursor = pair;
275 358351737 : fd_ulong_svw_enc_fixed( new_cursor, new_ksz, new_key_sz ); new_cursor += new_ksz;
276 358351737 : memmove( new_cursor, key, new_key_sz ); new_cursor += new_key_sz;
277 358351737 : new_cursor[0] = (uchar)val_type; new_cursor += 1;
278 358351737 : fd_ulong_svw_enc_fixed( new_cursor, new_vsz, new_val_sz ); new_cursor += new_vsz;
279 358351737 : memmove( new_cursor, val, new_val_sz ); new_cursor += new_val_sz;
280 :
281 : /* Compact the trailing space */
282 :
283 358351737 : ulong rem = (ulong)(_stop-next);
284 358351737 : memmove( new_cursor, next, rem );
285 :
286 : /* Update the iterator internals */
287 :
288 358351737 : next = new_cursor;
289 358351737 : _cursor = new_cursor;
290 358351737 : _stop = new_cursor + rem;
291 358351737 : _used = (ulong)(_stop - pod);
292 358351737 : } FD_POD_FOR_ALL_END;
293 :
294 167777721 : ulong new_bdy_sz = (ulong)(next - bdy);
295 :
296 : /* Compact the header and (if full) trailing padding */
297 :
298 167777721 : ulong new_csz;
299 167777721 : ulong new_max;
300 167777721 : ulong new_used;
301 :
302 167777721 : if( !full ) {
303 204282 : new_csz = fd_ulong_svw_enc_sz( max ); /* <=csz */
304 204282 : new_max = max;
305 204282 : new_used = new_csz*3UL + new_bdy_sz;
306 167573439 : } else {
307 167573439 : new_csz = 1UL;
308 244922970 : for(;;) {
309 244922970 : /**/ new_max = new_csz*3UL + new_bdy_sz;
310 244922970 : ulong test_csz = fd_ulong_svw_enc_sz( new_max );
311 244922970 : if( FD_LIKELY( test_csz==new_csz ) ) break;
312 77349531 : new_csz = test_csz;
313 77349531 : }
314 167573439 : new_used = new_max;
315 167573439 : }
316 :
317 167777721 : memmove( pod + new_csz*3UL, bdy, new_bdy_sz );
318 167777721 : fd_ulong_svw_enc_fixed( pod, new_csz, new_max );
319 167777721 : fd_ulong_svw_enc_fixed( pod + new_csz, new_csz, new_used );
320 167777721 : fd_ulong_svw_enc_fixed( pod + new_csz*2UL, new_csz, cnt );
321 :
322 167777721 : return new_max;
323 167777721 : }
324 :
325 : int
326 984 : fd_cstr_to_pod_val_type( char const * cstr ) {
327 984 : if( FD_UNLIKELY( !cstr ) ) return FD_POD_ERR_INVAL;
328 981 : if( !fd_cstr_casecmp( cstr, "subpod" ) ) return FD_POD_VAL_TYPE_SUBPOD;
329 975 : if( !fd_cstr_casecmp( cstr, "buf" ) ) return FD_POD_VAL_TYPE_BUF;
330 969 : if( !fd_cstr_casecmp( cstr, "cstr" ) ) return FD_POD_VAL_TYPE_CSTR;
331 948 : if( !fd_cstr_casecmp( cstr, "char" ) ) return FD_POD_VAL_TYPE_CHAR;
332 933 : if( !fd_cstr_casecmp( cstr, "schar" ) ) return FD_POD_VAL_TYPE_SCHAR;
333 918 : if( !fd_cstr_casecmp( cstr, "short" ) ) return FD_POD_VAL_TYPE_SHORT;
334 903 : if( !fd_cstr_casecmp( cstr, "int" ) ) return FD_POD_VAL_TYPE_INT;
335 888 : if( !fd_cstr_casecmp( cstr, "long" ) ) return FD_POD_VAL_TYPE_LONG;
336 873 : if( !fd_cstr_casecmp( cstr, "int128" ) ) return FD_POD_VAL_TYPE_INT128;
337 867 : if( !fd_cstr_casecmp( cstr, "uchar" ) ) return FD_POD_VAL_TYPE_UCHAR;
338 852 : if( !fd_cstr_casecmp( cstr, "ushort" ) ) return FD_POD_VAL_TYPE_USHORT;
339 837 : if( !fd_cstr_casecmp( cstr, "uint" ) ) return FD_POD_VAL_TYPE_UINT;
340 822 : if( !fd_cstr_casecmp( cstr, "ulong" ) ) return FD_POD_VAL_TYPE_ULONG;
341 807 : if( !fd_cstr_casecmp( cstr, "uint128" ) ) return FD_POD_VAL_TYPE_UINT128;
342 801 : if( !fd_cstr_casecmp( cstr, "float" ) ) return FD_POD_VAL_TYPE_FLOAT;
343 783 : if( !fd_cstr_casecmp( cstr, "double" ) ) return FD_POD_VAL_TYPE_DOUBLE;
344 : /* FIXME: ADD FD_CSTR_NCASECMP */
345 777 : if( !strncmp( cstr, "user", 4UL ) || !strncmp( cstr, "USER", 4UL ) || !strncmp( cstr, "User", 4UL ) ) {
346 774 : int val_type = fd_cstr_to_int( cstr+4UL );
347 774 : if( FD_LIKELY( ((0<=val_type) & (val_type<=255)) ) ) return val_type;
348 774 : }
349 9 : return FD_POD_ERR_INVAL;
350 777 : }
351 :
352 : char *
353 : fd_pod_val_type_to_cstr( int val_type,
354 921 : char * cstr ) {
355 921 : if( FD_UNLIKELY( !cstr ) ) return NULL;
356 921 : switch( val_type ) {
357 69 : case FD_POD_VAL_TYPE_SUBPOD: return strcpy( cstr, "subpod" );
358 9 : case FD_POD_VAL_TYPE_BUF: return strcpy( cstr, "buf" );
359 21 : case FD_POD_VAL_TYPE_CSTR: return strcpy( cstr, "cstr" );
360 9 : case FD_POD_VAL_TYPE_CHAR: return strcpy( cstr, "char" );
361 9 : case FD_POD_VAL_TYPE_SCHAR: return strcpy( cstr, "schar" );
362 9 : case FD_POD_VAL_TYPE_SHORT: return strcpy( cstr, "short" );
363 9 : case FD_POD_VAL_TYPE_INT: return strcpy( cstr, "int" );
364 9 : case FD_POD_VAL_TYPE_LONG: return strcpy( cstr, "long" );
365 3 : case FD_POD_VAL_TYPE_INT128: return strcpy( cstr, "int128" );
366 9 : case FD_POD_VAL_TYPE_UCHAR: return strcpy( cstr, "uchar" );
367 9 : case FD_POD_VAL_TYPE_USHORT: return strcpy( cstr, "ushort" );
368 9 : case FD_POD_VAL_TYPE_UINT: return strcpy( cstr, "uint" );
369 6 : case FD_POD_VAL_TYPE_ULONG: return strcpy( cstr, "ulong" );
370 3 : case FD_POD_VAL_TYPE_UINT128: return strcpy( cstr, "uint128" );
371 15 : case FD_POD_VAL_TYPE_FLOAT: return strcpy( cstr, "float" );
372 3 : case FD_POD_VAL_TYPE_DOUBLE: return strcpy( cstr, "double" );
373 720 : default: break;
374 921 : }
375 720 : if( FD_UNLIKELY( !((0<=val_type) & (val_type<=255)) ) ) return NULL;
376 720 : return fd_cstr_printf( cstr, FD_POD_VAL_TYPE_CSTR_MAX, NULL, "user%i", val_type );
377 720 : }
378 :
379 : /* fd_pod_subpod_grow increases the amount of space for key-val pairs
380 : in the deepest nested subpod on the subpod path by needed bytes.
381 : This operation can impact the location of items all the subpods along
382 : the path. On success, returns FD_POD_SUCCESS. On failure, returns
383 : FD_POD_ERR* */
384 :
385 : struct fd_pod_subpod_path;
386 : typedef struct fd_pod_subpod_path fd_pod_subpod_path_t;
387 :
388 : struct fd_pod_subpod_path {
389 : uchar * pod; /* Points to the subpod val of subpod key-val pair */
390 : fd_pod_subpod_path_t * parent; /* Points to the subpod that contains the subpod (NULL if this subpod is in the root pod) */
391 : };
392 :
393 : static int
394 : fd_pod_subpod_grow( fd_pod_subpod_path_t * node,
395 26830953 : ulong needed ) { /* How much more space is needed for key-val pairs (i.e. in the body) */
396 26830953 : if( FD_UNLIKELY( !needed ) ) return FD_POD_SUCCESS; /* Don't need anything */
397 :
398 26830953 : fd_pod_subpod_path_t * parent = node->parent;
399 26830953 : if( FD_UNLIKELY( !parent ) ) return FD_POD_ERR_FULL; /* Can't grow the root pod */
400 :
401 : /* Compute how much larger the parent's val footprint needs to be,
402 : accounting for the possibility that this pod's header might need to
403 : expand and/or the parent's val_sz encoding might also need to
404 : expand. */
405 :
406 26824929 : uchar * pod = node->pod;
407 :
408 26824929 : ulong vsz = fd_ulong_svw_dec_tail_sz( pod );
409 26824929 : ulong val_sz = fd_ulong_svw_dec_fixed( pod - vsz, vsz );
410 :
411 26824929 : ulong csz = fd_ulong_svw_dec_sz( pod );
412 26824929 : ulong max = fd_ulong_svw_dec_fixed( pod, csz ); /* <=val_sz */
413 26824929 : ulong used = fd_ulong_svw_dec_fixed( pod + csz, csz );
414 26824929 : ulong cnt = fd_ulong_svw_dec_fixed( pod + csz*2UL, csz );
415 26824929 : ulong bdy_sz = used - csz*3UL;
416 :
417 26824929 : ulong new_bdy_max = max + needed - csz*3UL;
418 26824929 : ulong new_csz = csz;
419 26824929 : ulong new_max;
420 28728198 : for(;;) {
421 28728198 : new_max = new_csz*3UL + new_bdy_max;
422 28728198 : ulong test_csz = fd_ulong_svw_enc_sz( new_max );
423 28728198 : if( FD_LIKELY( test_csz==new_csz ) ) break;
424 1903269 : new_csz = test_csz;
425 1903269 : }
426 26824929 : ulong new_used = new_csz*3UL + bdy_sz;
427 :
428 26824929 : if( new_max<=val_sz ) { /* Can grow this pod without touching our parent */
429 :
430 : /* Repack the pod */
431 :
432 0 : uchar * cursor = pod + new_max;
433 :
434 0 : cursor -= new_bdy_max; memmove( cursor, pod + 3UL*csz, bdy_sz );
435 0 : cursor -= new_csz; fd_ulong_svw_enc_fixed( cursor, new_csz, cnt );
436 0 : cursor -= new_csz; fd_ulong_svw_enc_fixed( cursor, new_csz, new_used );
437 0 : cursor -= new_csz; fd_ulong_svw_enc_fixed( cursor, new_csz, new_max );
438 :
439 0 : return FD_POD_SUCCESS;
440 0 : }
441 :
442 : /* fd_ulong_max below is to eliminate a very rare edge cases at a
443 : minuscule temporary cost in packing efficiency (compact can handle
444 : it). The edge case is the ideal new_val_footprint is at most the
445 : current val_footprint but the current val_sz can't be encoded in
446 : the ideal new_val_footprint. In this case, we'd need to repack the
447 : rest of the pod to use a smaller val sz but we don't have enough
448 : info to do that here (which would actually be correcting for a
449 : previous packing inefficiency). We avoid the edge case by not
450 : letting new_vsz be less than vsz (such that the current val_sz is
451 : always encodable in the new format). In short, this defers cleanup
452 : of the preexisting packing inefficiency to compact and does not
453 : make it worse. */
454 :
455 26824929 : ulong new_vsz = fd_ulong_max( fd_ulong_svw_enc_sz( new_max ), vsz );
456 :
457 26824929 : ulong val_footprint = vsz + val_sz;
458 26824929 : ulong new_val_footprint = new_vsz + new_max;
459 26824929 : if( new_val_footprint<=val_footprint ) { /* Can grow this pod without growing our parent but have to recode val_sz */
460 :
461 : /* Repack the pod */
462 :
463 0 : uchar * cursor = pod - vsz + new_val_footprint;
464 :
465 0 : cursor -= new_bdy_max; memmove( cursor, pod + 3UL*csz, bdy_sz );
466 0 : cursor -= new_csz; fd_ulong_svw_enc_fixed( cursor, new_csz, cnt );
467 0 : cursor -= new_csz; fd_ulong_svw_enc_fixed( cursor, new_csz, new_used );
468 0 : cursor -= new_csz; fd_ulong_svw_enc_fixed( cursor, new_csz, new_max );
469 0 : cursor -= new_vsz; fd_ulong_svw_enc_fixed( cursor, new_vsz, val_sz );
470 :
471 0 : return FD_POD_SUCCESS;
472 0 : }
473 :
474 : /* Have to repack the parent to grow this pod */
475 :
476 26824929 : uchar * parent_pod = parent->pod;
477 26824929 : ulong parent_csz = fd_ulong_svw_dec_sz( parent_pod );
478 26824929 : ulong parent_max = fd_ulong_svw_dec_fixed( parent_pod, parent_csz );
479 26824929 : ulong parent_used = fd_ulong_svw_dec_fixed( parent_pod + parent_csz, parent_csz );
480 26824929 : ulong parent_avail = parent_max - parent_used;
481 26824929 : ulong parent_needed = new_val_footprint - val_footprint;
482 26824929 : if( parent_avail < parent_needed ) { /* Need to grow the parent (and maybe their parent and ...) to grow this pod */
483 :
484 22489659 : int err = fd_pod_subpod_grow( parent, parent_needed-parent_avail );
485 22489659 : if( FD_UNLIKELY( err ) ) return err;
486 :
487 : /* Determine where the parent and this pod ended up after growth */
488 :
489 22451028 : ulong pod_off = (ulong)(pod - parent_pod) - parent_csz*3UL; /* Original offset pod relative to the parent body */
490 :
491 22451028 : parent_pod = parent->pod;
492 22451028 : parent_csz = fd_ulong_svw_dec_sz( parent_pod );
493 : //parent_max = fd_ulong_svw_dec_fixed( parent_pod, parent_csz );
494 22451028 : parent_used = fd_ulong_svw_dec_fixed( parent_pod + parent_csz, parent_csz );
495 : //parent_avail = parent_max - parent_used;
496 :
497 22451028 : pod = parent_pod + parent_csz*3UL + pod_off;
498 22451028 : }
499 :
500 : /* At this point, our parent has enough room to accommodate growing
501 : this pod. Repack the parent pod and grow this pod. */
502 :
503 26786298 : uchar * parent_next = pod + max;
504 26786298 : uchar * parent_stop = parent_pod + parent_used;
505 26786298 : uchar * cursor = parent_stop + parent_needed;
506 26786298 : ulong rem = (ulong)(parent_stop - parent_next);
507 :
508 26786298 : cursor -= rem; memmove( cursor, parent_next, rem );
509 26786298 : cursor -= new_bdy_max; memmove( cursor, pod + csz*3UL, bdy_sz );
510 26786298 : cursor -= new_csz; fd_ulong_svw_enc_fixed( cursor, new_csz, cnt );
511 26786298 : cursor -= new_csz; fd_ulong_svw_enc_fixed( cursor, new_csz, new_used );
512 26786298 : cursor -= new_csz; fd_ulong_svw_enc_fixed( cursor, new_csz, new_max ); node->pod = cursor;
513 26786298 : cursor -= new_vsz; fd_ulong_svw_enc_fixed( cursor, new_vsz, new_max );
514 :
515 26786298 : fd_ulong_svw_enc_fixed( parent_pod + parent_csz, parent_csz, parent_used + parent_needed );
516 :
517 26786298 : return FD_POD_SUCCESS;
518 26824929 : }
519 :
520 : static uchar *
521 : fd_pod_private_alloc_node( fd_pod_subpod_path_t * FD_RESTRICT parent,
522 : uchar * FD_RESTRICT pod,
523 : char const * FD_RESTRICT path,
524 : int new_val_type,
525 5364348 : ulong new_val_sz ) {
526 5364348 : fd_pod_subpod_path_t node[1];
527 5364348 : node->pod = pod;
528 5364348 : node->parent = parent;
529 :
530 5364348 : ulong prefix_len; char delim; char const * suffix;
531 5364348 : FD_POD_PATH_SPLIT( path, prefix_len, delim, suffix );
532 :
533 5364348 : uchar * pair; uchar * next;
534 5364348 : ulong ksz; ulong key_sz; char * key; int val_type;
535 5364348 : ulong vsz; ulong val_sz; void * val;
536 41088012 : FD_POD_FOR_ALL_BEGIN( pod, pair, next, ksz, key_sz, key, val_type, vsz, val_sz, val ) {
537 :
538 41088012 : if( ((key_sz-1UL)==prefix_len) && !memcmp( key, path, prefix_len ) ) { /* Found leading key in pod */
539 :
540 708435 : if( !delim ) { /* Path was a single key. Fail as key already in pod. */
541 :
542 31842 : return NULL;
543 :
544 676593 : } else { /* Path had a suffix. Recurse into the subpod */
545 :
546 676593 : if( FD_UNLIKELY( val_type!=FD_POD_VAL_TYPE_SUBPOD ) ) return NULL;
547 355629 : return fd_pod_private_alloc_node( node, (uchar *)val, suffix, new_val_type, new_val_sz );
548 :
549 676593 : }
550 708435 : }
551 41088012 : } FD_POD_FOR_ALL_END;
552 :
553 : /* Leading key not found in pod. */
554 :
555 : /* Extract the pod header */
556 :
557 4655913 : ulong csz = fd_ulong_svw_dec_sz( pod );
558 4655913 : ulong max = fd_ulong_svw_dec_fixed( pod, csz );
559 4655913 : ulong used = fd_ulong_svw_dec_fixed( pod + csz, csz );
560 4655913 : ulong avail = max - used;
561 :
562 4655913 : if( delim ) { /* Path had a suffix. */
563 :
564 : /* Compute the amount of space needed in this pod to hold the
565 : subpod. FIXME: IDEALLY WE'D DO A "DRESS REHEARSAL" TO FIGURE OUT
566 : TIGHTLY THE MAX AMOUNT FOR THE REST OF THE ALLOC AND SAVE TIME
567 : FROM HAVING TO GROW PODS REPEATEDLY FOR A DEEPLY NESTED PATH.
568 : THIS WOULD ALSO PREVENT ANY MODIFICATIONS BEING MADE TO THE POD
569 : UNLESS THE ALLOC IS SUCCESSFUL (AS IT IS, THIS MIGHT LEAVE SOME
570 : PATH THAT TERMINATES ON AN EMPTY POD, WHICH IS THEORETICALLY FINE
571 : BUT POTENTIALLY NOT THE MOST DESIRABLE PRACTICALLY). */
572 :
573 4095153 : ulong subpod_max = FD_POD_FOOTPRINT_MIN;
574 :
575 4095153 : char const * subpod_key = path; /* Does not include terminating '\0', potentially has additional keys following. */
576 4095153 : ulong subpod_key_sz = prefix_len + 1UL;
577 4095153 : ulong subpod_ksz = fd_ulong_svw_enc_sz( subpod_key_sz );
578 4095153 : ulong subpod_val_sz = fd_pod_footprint( subpod_max );
579 4095153 : ulong subpod_vsz = fd_ulong_svw_enc_sz( subpod_val_sz );
580 :
581 4095153 : ulong needed = subpod_ksz + subpod_key_sz + 1UL /* subpod_val_type */ + subpod_vsz + subpod_val_sz;
582 :
583 : /* Expand the pod if necessary */
584 :
585 4095153 : if( needed > avail ) {
586 3815574 : int err = fd_pod_subpod_grow( node, needed-avail );
587 3815574 : if( FD_UNLIKELY( err ) ) return NULL;
588 3810636 : pod = node->pod;
589 3810636 : csz = fd_ulong_svw_dec_sz( pod );
590 : //max = fd_ulong_svw_dec_fixed( pod, csz );
591 3810636 : used = fd_ulong_svw_dec_fixed( pod + csz, csz );
592 : //avail = max - used;
593 3810636 : }
594 :
595 : /* Insert the subpod */
596 :
597 4090215 : uchar * cursor = pod + used;
598 4090215 : fd_ulong_svw_enc_fixed( cursor, subpod_ksz, subpod_key_sz ); cursor += subpod_ksz;
599 4090215 : fd_memcpy( cursor, subpod_key, subpod_key_sz-1UL );
600 4090215 : cursor[subpod_key_sz-1UL] = '\0'; cursor += subpod_key_sz; /* Handle terminating '\0' */
601 4090215 : cursor[0 ] = (uchar)FD_POD_VAL_TYPE_SUBPOD; cursor += 1;
602 4090215 : fd_ulong_svw_enc_fixed( cursor, subpod_vsz, subpod_val_sz ); cursor += subpod_vsz;
603 4090215 : uchar * subpod = fd_pod_join( fd_pod_new( cursor, subpod_max ) ); cursor += subpod_val_sz;
604 :
605 : /* Update the pod header */
606 :
607 4090215 : ulong cnt = fd_ulong_svw_dec_fixed( pod + csz*2UL, csz );
608 4090215 : fd_ulong_svw_enc_fixed( pod + csz, csz, (ulong)(cursor-pod) ); /* used */
609 4090215 : fd_ulong_svw_enc_fixed( pod + csz*2UL, csz, cnt + 1UL );
610 :
611 : /* Recurse into the subpod */
612 :
613 4090215 : return fd_pod_private_alloc_node( node, subpod, suffix, new_val_type, new_val_sz );
614 4095153 : }
615 :
616 : /* Path was a single key */
617 :
618 : /* Compute how much space we need in the pod for this val. */
619 :
620 560760 : char const * new_key = path;
621 560760 : ulong new_key_sz = prefix_len + 1UL;
622 560760 : ulong new_ksz = fd_ulong_svw_enc_sz( new_key_sz );
623 560760 : ulong new_vsz = fd_ulong_svw_enc_sz( new_val_sz );
624 :
625 560760 : ulong needed = new_ksz + new_key_sz + 1UL /* new_val_type */ + new_vsz + new_val_sz;
626 :
627 : /* Expand the pod if necessary */
628 :
629 560760 : if( needed > avail ) {
630 525720 : int err = fd_pod_subpod_grow( node, needed-avail );
631 525720 : if( FD_UNLIKELY( err ) ) return NULL;
632 524634 : pod = node->pod;
633 524634 : csz = fd_ulong_svw_dec_sz( pod );
634 : //max = fd_ulong_svw_dec_fixed( pod, csz );
635 524634 : used = fd_ulong_svw_dec_fixed( pod + csz, csz );
636 524634 : }
637 :
638 : /* Allocate the val */
639 :
640 559674 : uchar * cursor = pod + used;
641 559674 : fd_ulong_svw_enc_fixed( cursor, new_ksz, new_key_sz ); cursor += new_ksz;
642 559674 : fd_memcpy( cursor, new_key, new_key_sz ); cursor += new_key_sz;
643 559674 : cursor[0] = (uchar)new_val_type; cursor += 1;
644 559674 : fd_ulong_svw_enc_fixed( cursor, new_vsz, new_val_sz ); cursor += new_vsz;
645 559674 : uchar * new_val = cursor; cursor += new_val_sz;
646 :
647 : /* Update the pod header */
648 :
649 559674 : ulong cnt = fd_ulong_svw_dec_fixed( pod + csz*2UL, csz );
650 559674 : fd_ulong_svw_enc_fixed( pod + csz, csz, (ulong)(cursor-pod) ); /* used */
651 559674 : fd_ulong_svw_enc_fixed( pod + csz*2UL, csz, cnt + 1UL );
652 :
653 559674 : return new_val;
654 560760 : }
655 :
656 : ulong
657 : fd_pod_alloc( uchar * FD_RESTRICT pod,
658 : char const * FD_RESTRICT path,
659 : int val_type,
660 739077 : ulong val_sz ) {
661 739077 : if( FD_UNLIKELY( (!pod) | (!path) | (!((0<=val_type) & (val_type<=255))) ) ) return 0UL;
662 :
663 739077 : uchar * val = fd_pod_private_alloc_node( NULL, pod, path, val_type, val_sz );
664 739077 : if( FD_UNLIKELY( !val ) ) {
665 179427 : fd_pod_compact( pod, 0 /*partial*/ );
666 179427 : val = fd_pod_private_alloc_node( NULL, pod, path, val_type, val_sz );
667 179427 : if( FD_UNLIKELY( !val ) ) return 0UL;
668 179427 : }
669 :
670 559674 : return (ulong)(val-pod);
671 739077 : }
672 :
673 : int
674 : fd_pod_remove( uchar * FD_RESTRICT pod,
675 1115088 : char const * FD_RESTRICT path ) {
676 1115088 : if( FD_UNLIKELY( (!pod) | (!path) ) ) return FD_POD_ERR_INVAL;
677 :
678 1115088 : ulong prefix_len; char delim; char const * suffix;
679 1115088 : FD_POD_PATH_SPLIT( path, prefix_len, delim, suffix );
680 :
681 1115088 : uchar * pair; uchar * next;
682 1115088 : ulong ksz; ulong key_sz; char const * key; int val_type;
683 1115088 : ulong vsz; ulong val_sz; void * val;
684 30380142 : FD_POD_FOR_ALL_BEGIN( pod, pair, next, ksz, key_sz, key, val_type, vsz, val_sz, val ) {
685 :
686 30380142 : if( ((key_sz-1UL)==prefix_len) && !memcmp( key, path, prefix_len ) ) { /* Found leading key in pod */
687 :
688 532449 : if( !delim ) { /* Path was a single key, delete it */
689 :
690 17049 : ulong footprint = (ulong)( next - pair);
691 17049 : ulong rem = (ulong)(_stop - next);
692 17049 : memmove( pair, next, rem );
693 17049 : ulong cnt = fd_ulong_svw_dec_fixed( pod + _csz*2UL, _csz );
694 17049 : fd_ulong_svw_enc_fixed( pod + _csz, _csz, _used - footprint ); /* upd used */
695 17049 : fd_ulong_svw_enc_fixed( pod + _csz*2UL, _csz, cnt - 1UL ); /* upd cnt */
696 17049 : return FD_POD_SUCCESS;
697 :
698 515400 : } else { /* Path had a suffix. Recurse into the subpod */
699 :
700 515400 : if( FD_UNLIKELY( val_type!=FD_POD_VAL_TYPE_SUBPOD ) ) return FD_POD_ERR_TYPE;
701 343959 : return fd_pod_remove( (uchar *)val, suffix );
702 :
703 515400 : }
704 532449 : }
705 :
706 30380142 : } FD_POD_FOR_ALL_END;
707 :
708 582639 : return FD_POD_ERR_RESOLVE;
709 1115088 : }
710 :
711 : #undef FD_POD_FOR_ALL_END
712 : #undef FD_POD_FOR_ALL_BEGIN
713 : #undef FD_POD_PATH_SPLIT
714 :
|