1 // ================================================================
2 // Array-only (open addressing) multi-level hash map, with linear probing for collisions.
3 // All keys, and terminal-level values, are mlrvals.
4 //
5 // Notes:
6 // * null key is not supported.
7 // * null value is not supported.
8 //
9 // See also:
10 // * http://en.wikipedia.org/wiki/Hash_table
11 // * http://docs.oracle.com/javase/6/docs/api/java/util/Map.html
12 // ================================================================
13 
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 
18 #include "lib/mlr_globals.h"
19 #include "lib/mlrutil.h"
20 #include "containers/mlhmmv.h"
21 #include "lib/mvfuncs.h"
22 
23 // ================================================================
24 // Allow compile-time override, e.g using gcc -D.
25 
26 #ifndef LOAD_FACTOR
27 #define LOAD_FACTOR          0.7
28 #endif
29 
30 #ifndef ENLARGEMENT_FACTOR
31 #define ENLARGEMENT_FACTOR   2
32 #endif
33 
34 #define OCCUPIED             0xa4
35 #define DELETED              0xb8
36 #define EMPTY                0xce
37 
38 // ================================================================
39 static int  mlhmmv_hash_func(mv_t* plevel_key);
40 static void json_decimal_print       (FILE* ostream, char* s, double parsed);
41 static void json_print_string_escaped(FILE* ostream, char* s);
42 
43 // ----------------------------------------------------------------
44 static void mlhmmv_level_init(mlhmmv_level_t  *plevel, int length);
45 
46 // ----------------------------------------------------------------
47 static int mlhmmv_level_find_index_for_key(mlhmmv_level_t* plevel, mv_t* plevel_key, int* pideal_index);
48 
49 static mlhmmv_level_entry_t* mlhmmv_level_look_up_and_ref_entry(
50 	mlhmmv_level_t* plevel, sllmve_t* prestkeys, int* perror);
51 
52 static mlhmmv_level_entry_t* mlhmmv_level_get_next_level_entry(mlhmmv_level_t* plevel, mv_t* plevel_key, int* pindex);
53 static mlhmmv_xvalue_t*      mlhmmv_level_get_next_level_xvalue(mlhmmv_level_t* plevel, mv_t* plevel_key);
54 
55 static mlhmmv_level_t* mlhmmv_level_ref_or_create(mlhmmv_level_t* plevel, sllmve_t* prest_keys);
56 static mlhmmv_level_t* mlhmmv_level_get_or_create_no_enlarge(mlhmmv_level_t* plevel, sllmve_t* prest_keys);
57 
58 static void mlhmmv_level_enlarge(mlhmmv_level_t* plevel);
59 static void mlhmmv_level_move(mlhmmv_level_t* plevel, mv_t* plevel_key, mlhmmv_xvalue_t* plevel_value);
60 
61 static void mlhmmv_level_put_xvalue_no_enlarge(mlhmmv_level_t* plevel, sllmve_t* prest_keys, mlhmmv_xvalue_t* pvalue);
62 static void mlhmmv_level_put_terminal_no_enlarge(mlhmmv_level_t* plevel, sllmve_t* prest_keys, mv_t* pterminal_value);
63 
64 static void mlhmmv_level_to_lrecs_across_records(
65 	mlhmmv_level_t* plevel,
66 	char*           prefix,
67 	sllmve_t*       prestnames,
68 	lrec_t*         ptemplate,
69 	sllv_t*         poutrecs,
70 	int             do_full_prefixing,
71 	char*           flatten_separator);
72 
73 static void mlhmmv_level_to_lrec_within_record(
74 	mlhmmv_level_t* plevel,
75 	char*           prefix,
76 	lrec_t*         poutrec,
77 	int             do_full_prefixing,
78 	char*           flatten_separator);
79 
80 static void mlhhmv_levels_to_lrecs_lashed_across_records(
81 	mlhmmv_level_t** plevels,
82 	char**           prefixes,
83 	int              num_levels,
84 	sllmve_t*        prestnames,
85 	lrec_t*          ptemplate,
86 	sllv_t*          poutrecs,
87 	int              do_full_prefixing,
88 	char*            flatten_separator);
89 
90 static void mlhhmv_levels_to_lrecs_lashed_within_records(
91 	mlhmmv_level_t** pplevels,
92 	char**           prefixes,
93 	int              num_levels,
94 	lrec_t*          poutrec,
95 	int              do_full_prefixing,
96 	char*            flatten_separator);
97 
98 static void mlhmmv_level_print_single_line(mlhmmv_level_t* plevel, int depth,
99 	int do_final_comma, int quote_keys_always, int quote_values_always,
100 	FILE* ostream);
101 
102 // ----------------------------------------------------------------
103 static void mlhmmv_root_put_xvalue(mlhmmv_root_t* pmap, sllmv_t* pmvkeys, mlhmmv_xvalue_t* pvalue);
104 
105 // ================================================================
106 typedef int mlhmmv_typed_hash_func(mv_t* pa);
mlhmmv_string_hash_func(mv_t * pa)107 static int mlhmmv_string_hash_func(mv_t* pa) {
108 	return mlr_string_hash_func(pa->u.strv);
109 }
mlhmmv_int_hash_func(mv_t * pa)110 static int mlhmmv_int_hash_func(mv_t* pa) {
111 	return pa->u.intv;
112 }
mlhmmv_other_hash_func(mv_t * pa)113 static int mlhmmv_other_hash_func(mv_t* pa) {
114 	fprintf(stderr, "%s: map keys must be of type %s or %s; got %s.\n",
115 		MLR_GLOBALS.bargv0,
116 		mt_describe_type(MT_STRING),
117 		mt_describe_type(MT_INT),
118 		mt_describe_type(pa->type));
119 	exit(1);
120 }
121 static mlhmmv_typed_hash_func* mlhmmv_hash_func_dispositions[MT_DIM] = {
122 	/*ERROR*/  mlhmmv_other_hash_func,
123 	/*ABSENT*/ mlhmmv_other_hash_func,
124 	/*EMPTY*/  mlhmmv_other_hash_func,
125 	/*STRING*/ mlhmmv_string_hash_func,
126 	/*INT*/    mlhmmv_int_hash_func,
127 	/*FLOAT*/  mlhmmv_other_hash_func,
128 	/*BOOL*/   mlhmmv_other_hash_func,
129 };
mlhmmv_hash_func(mv_t * pa)130 static int mlhmmv_hash_func(mv_t* pa) {
131 	return mlhmmv_hash_func_dispositions[pa->type](pa);
132 }
133 
134 // ================================================================
mlhmmv_print_terminal(mv_t * pmv,int quote_keys_always,int quote_values_always,FILE * ostream)135 void mlhmmv_print_terminal(mv_t* pmv, int quote_keys_always, int quote_values_always,
136 	FILE* ostream)
137 {
138 	char* level_value_string = mv_alloc_format_val(pmv);
139 	if (quote_values_always) {
140 		json_print_string_escaped(ostream, level_value_string);
141 	} else if (pmv->type == MT_STRING) {
142 		double parsed;
143 		if (mlr_try_float_from_string(level_value_string, &parsed)) {
144 			json_decimal_print(ostream, level_value_string, parsed);
145 		} else if (streq(level_value_string, "true") || streq(level_value_string, "false")) {
146 			fprintf(ostream, "%s", level_value_string);
147 		} else {
148 			json_print_string_escaped(ostream, level_value_string);
149 		}
150 	} else {
151 		fprintf(ostream, "%s", level_value_string);
152 	}
153 	free(level_value_string);
154 }
155 
156 // 0.123 is valid JSON; .123 is not. Meanwhile Miller is a format-converter tool
157 // so if there is perfectly legitimate CSV/DKVP/etc. data to be JSON-formatted,
158 // we make it JSON-compliant.
159 //
160 // Precondition: the caller has already checked that the string represents a number.
json_decimal_print(FILE * ostream,char * s,double parsed)161 static void json_decimal_print(FILE* ostream, char* s, double parsed) {
162 	if (s[0] == '.') {
163 		fprintf(ostream, "0%s", s);
164 	} else if (s[0] == '-' && s[1] == '.') {
165 		fprintf(ostream, "-0.%s", &s[2]);
166 	} else {
167 		fprintf(ostream, "%s", s);
168 	}
169 }
170 
json_print_string_escaped(FILE * ostream,char * s)171 static void json_print_string_escaped(FILE* ostream, char* s) {
172 	fputc('"', ostream);
173 	for (char* p = s; *p; p++) {
174 		char c = *p;
175 		switch (c) {
176 		case '"':
177 			fputc('\\', ostream);
178 			fputc('"', ostream);
179 			break;
180 		case '\\':
181 			fputc('\\', ostream);
182 			fputc('\\', ostream);
183 			break;
184 		case '\n':
185 			fputc('\\', ostream);
186 			fputc('n', ostream);
187 			break;
188 		case '\r':
189 			fputc('\\', ostream);
190 			fputc('r', ostream);
191 			break;
192 		case '\t':
193 			fputc('\\', ostream);
194 			fputc('t', ostream);
195 			break;
196 		case '\b':
197 			fputc('\\', ostream);
198 			fputc('b', ostream);
199 			break;
200 		case '\f':
201 			fputc('\\', ostream);
202 			fputc('f', ostream);
203 			break;
204 		default:
205 			fputc(c, ostream);
206 			break;
207 		}
208 	}
209 	fputc('"', ostream);
210 }
211 
212 // ================================================================
mlhmmv_xvalue_alloc_empty_map()213 mlhmmv_xvalue_t mlhmmv_xvalue_alloc_empty_map() {
214 	mlhmmv_xvalue_t xval = (mlhmmv_xvalue_t) {
215 		.is_terminal = FALSE,
216 		.terminal_mlrval= mv_absent(),
217 		.pnext_level = mlhmmv_level_alloc()
218 	};
219 	return xval;
220 }
221 
222 // ----------------------------------------------------------------
mlhmmv_xvalue_reset(mlhmmv_xvalue_t * pxvalue)223 void mlhmmv_xvalue_reset(mlhmmv_xvalue_t* pxvalue) {
224 	pxvalue->is_terminal     = TRUE;
225 	pxvalue->terminal_mlrval = mv_absent();
226 	pxvalue->pnext_level     = NULL;
227 }
228 
229 // ----------------------------------------------------------------
mlhmmv_xvalue_copy(mlhmmv_xvalue_t * pvalue)230 mlhmmv_xvalue_t mlhmmv_xvalue_copy(mlhmmv_xvalue_t* pvalue) {
231 	if (pvalue->is_terminal) {
232 		return (mlhmmv_xvalue_t) {
233 			.is_terminal = TRUE,
234 			.terminal_mlrval = mv_copy(&pvalue->terminal_mlrval),
235 			.pnext_level = NULL,
236 		};
237 
238 	} else {
239 		mlhmmv_level_t* psrc_level = pvalue->pnext_level;
240 		mlhmmv_level_t* pdst_level = mlr_malloc_or_die(sizeof(mlhmmv_level_t));
241 
242 		mlhmmv_level_init(pdst_level, MLHMMV_INITIAL_ARRAY_LENGTH);
243 
244 		for (
245 			mlhmmv_level_entry_t* psubentry = psrc_level->phead;
246 			psubentry != NULL;
247 			psubentry = psubentry->pnext)
248 		{
249 			mlhmmv_xvalue_t next_value = mlhmmv_xvalue_copy(&psubentry->level_xvalue);
250 			mlhmmv_level_put_xvalue_singly_keyed(pdst_level, &psubentry->level_key, &next_value);
251 		}
252 
253 		return (mlhmmv_xvalue_t) {
254 			.is_terminal = FALSE,
255 			.terminal_mlrval = mv_absent(),
256 			.pnext_level = pdst_level,
257 		};
258 	}
259 }
260 
261 // ----------------------------------------------------------------
mlhmmv_xvalue_free(mlhmmv_xvalue_t * pxvalue)262 void mlhmmv_xvalue_free(mlhmmv_xvalue_t* pxvalue) {
263 	if (pxvalue->is_terminal) {
264 		mv_free(&pxvalue->terminal_mlrval);
265 	} else if (pxvalue->pnext_level != NULL) {
266 		mlhmmv_level_free(pxvalue->pnext_level);
267 		pxvalue->pnext_level = NULL;
268 	}
269 }
270 
271 // ----------------------------------------------------------------
mlhmmv_xvalue_describe_type_simple(mlhmmv_xvalue_t * pxvalue)272 char* mlhmmv_xvalue_describe_type_simple(mlhmmv_xvalue_t* pxvalue) {
273 	if (pxvalue->is_terminal) {
274 		return mt_describe_type_simple(pxvalue->terminal_mlrval.type);
275 	} else {
276 		return "map";
277 	}
278 }
279 
mlhmmv_xvalue_copy_keys_indexed(mlhmmv_xvalue_t * pmvalue,sllmv_t * pmvkeys)280 sllv_t* mlhmmv_xvalue_copy_keys_indexed(mlhmmv_xvalue_t* pmvalue, sllmv_t* pmvkeys) { // xxx code dedupe
281 	int error;
282 	if (pmvkeys == NULL || pmvkeys->length == 0) {
283 		return mlhmmv_xvalue_copy_keys_nonindexed(pmvalue);
284 	} else if (pmvalue->is_terminal) { // xxx copy this check up to oosvar case too
285 		return sllv_alloc();
286 	} else {
287 		mlhmmv_level_entry_t* pfromentry = mlhmmv_level_look_up_and_ref_entry(pmvalue->pnext_level,
288 			pmvkeys->phead, &error);
289 		if (pfromentry != NULL) {
290 			return mlhmmv_xvalue_copy_keys_nonindexed(&pfromentry->level_xvalue);
291 		} else {
292 			return sllv_alloc();
293 		}
294 	}
295 }
296 
mlhmmv_xvalue_copy_keys_nonindexed(mlhmmv_xvalue_t * pvalue)297 sllv_t* mlhmmv_xvalue_copy_keys_nonindexed(mlhmmv_xvalue_t* pvalue) {
298 	sllv_t* pkeys = sllv_alloc();
299 
300 	if (!pvalue->is_terminal) {
301 		mlhmmv_level_t* pnext_level = pvalue->pnext_level;
302 		for (mlhmmv_level_entry_t* pe = pnext_level->phead; pe != NULL; pe = pe->pnext) {
303 			mv_t* p = mv_alloc_copy(&pe->level_key);
304 			sllv_append(pkeys, p);
305 		}
306 	}
307 
308 	return pkeys;
309 }
310 
311 // ----------------------------------------------------------------
mlhmmv_xvalues_to_lrecs_lashed(mlhmmv_xvalue_t ** ptop_values,int num_submaps,mv_t * pbasenames,sllmv_t * pnames,sllv_t * poutrecs,int do_full_prefixing,char * flatten_separator)312 void mlhmmv_xvalues_to_lrecs_lashed(mlhmmv_xvalue_t** ptop_values, int num_submaps, mv_t* pbasenames, sllmv_t* pnames,
313 	sllv_t* poutrecs, int do_full_prefixing, char* flatten_separator)
314 {
315 
316 	// First is primary and rest are lashed to it (lookups with same keys as primary).
317 	if (ptop_values[0] == NULL) {
318 		// No such entry in the mlhmmv results in no output records
319 	} else if (ptop_values[0]->is_terminal && mv_is_present(&ptop_values[0]->terminal_mlrval)) {
320 		lrec_t* poutrec = lrec_unbacked_alloc();
321 		for (int i = 0; i < num_submaps; i++) {
322 			// E.g. '@v = 3' at the top level of the mlhmmv.
323 			if (ptop_values[i]->is_terminal && mv_is_present(&ptop_values[i]->terminal_mlrval)) {
324 				lrec_put(poutrec,
325 					mv_alloc_format_val(&pbasenames[i]),
326 					mv_alloc_format_val(&ptop_values[i]->terminal_mlrval), FREE_ENTRY_KEY|FREE_ENTRY_VALUE);
327 			}
328 		}
329 		sllv_append(poutrecs, poutrec);
330 	} else {
331 		// E.g. '@v = {...}' at the top level of the map, where the map is an oosvar
332 		// submap keyed by oosvar-name 'v', or a localvar value, or a map literal.  This
333 		// needs to be flattened down to an lrec which is a list of key-value pairs.  We
334 		// recursively invoke mlhhmv_levels_to_lrecs_lashed_across_records for each of the
335 		// name-list entries, one map level deeper each call, then from there invoke
336 		// mlhhmv_levels_to_lrecs_lashed_within_records on any remaining map levels.
337 		lrec_t* ptemplate = lrec_unbacked_alloc();
338 
339 		mlhmmv_level_t** ppnext_levels = mlr_malloc_or_die(num_submaps * sizeof(mlhmmv_level_t*));
340 		char** oosvar_names = mlr_malloc_or_die(num_submaps * sizeof(char*));
341 		for (int i = 0; i < num_submaps; i++) {
342 			if (ptop_values[i] == NULL || ptop_values[i]->is_terminal) {
343 				ppnext_levels[i] = NULL;
344 				oosvar_names[i] = NULL;
345 			} else {
346 				ppnext_levels[i] = ptop_values[i]->pnext_level;
347 				oosvar_names[i] = mv_alloc_format_val(&pbasenames[i]);
348 			}
349 		}
350 
351 		mlhhmv_levels_to_lrecs_lashed_across_records(ppnext_levels, oosvar_names, num_submaps,
352 			pnames->phead, ptemplate, poutrecs, do_full_prefixing, flatten_separator);
353 
354 		for (int i = 0; i < num_submaps; i++) {
355 			free(oosvar_names[i]);
356 		}
357 		free(oosvar_names);
358 		free(ppnext_levels);
359 
360 		lrec_free(ptemplate);
361 	}
362 }
363 
364 // ================================================================
mlhmmv_level_alloc()365 mlhmmv_level_t* mlhmmv_level_alloc() {
366 	mlhmmv_level_t* plevel = mlr_malloc_or_die(sizeof(mlhmmv_level_t));
367 	mlhmmv_level_init(plevel, MLHMMV_INITIAL_ARRAY_LENGTH);
368 	return plevel;
369 }
370 
371 // ----------------------------------------------------------------
mlhmmv_level_init(mlhmmv_level_t * plevel,int length)372 static void mlhmmv_level_init(mlhmmv_level_t *plevel, int length) {
373 	plevel->num_occupied = 0;
374 	plevel->num_freed    = 0;
375 	plevel->array_length = length;
376 
377 	plevel->entries      = (mlhmmv_level_entry_t*)mlr_malloc_or_die(sizeof(mlhmmv_level_entry_t) * length);
378 	// Don't do mlhmmv_level_entry_clear() of all entries at init time, since this has a
379 	// drastic effect on the time needed to construct an empty map (and miller
380 	// constructs an awful lot of those). The attributes there are don't-cares
381 	// if the corresponding entry state is EMPTY. They are set on put, and
382 	// mutated on remove.
383 
384 	plevel->states       = (mlhmmv_level_entry_state_t*)mlr_malloc_or_die(sizeof(mlhmmv_level_entry_state_t) * length);
385 	memset(plevel->states, EMPTY, length);
386 
387 	plevel->phead        = NULL;
388 	plevel->ptail        = NULL;
389 }
390 
391 // ----------------------------------------------------------------
mlhmmv_level_free(mlhmmv_level_t * plevel)392 void mlhmmv_level_free(mlhmmv_level_t* plevel) {
393 	for (mlhmmv_level_entry_t* pentry = plevel->phead; pentry != NULL; pentry = pentry->pnext) {
394 		mv_free(&pentry->level_key);
395 		if (pentry->level_xvalue.is_terminal) {
396 			mv_free(&pentry->level_xvalue.terminal_mlrval);
397 		} else {
398 			mlhmmv_level_free(pentry->level_xvalue.pnext_level);
399 		}
400 	}
401 	free(plevel->entries);
402 	free(plevel->states);
403 	plevel->entries      = NULL;
404 	plevel->num_occupied = 0;
405 	plevel->num_freed    = 0;
406 	plevel->array_length = 0;
407 	free(plevel);
408 }
409 
410 // ----------------------------------------------------------------
mlhmmv_level_clear(mlhmmv_level_t * plevel)411 void mlhmmv_level_clear(mlhmmv_level_t* plevel) {
412 	if (plevel->phead == NULL)
413 		return;
414 
415 	for (mlhmmv_level_entry_t* pentry = plevel->phead; pentry != NULL; pentry = pentry->pnext) {
416 		if (pentry->level_xvalue.is_terminal) {
417 			mv_free(&pentry->level_xvalue.terminal_mlrval);
418 		} else {
419 			mlhmmv_level_free(pentry->level_xvalue.pnext_level);
420 		}
421 		mv_free(&pentry->level_key);
422 	}
423 	plevel->num_occupied = 0;
424 	plevel->num_freed    = 0;
425 	plevel->phead        = NULL;
426 	plevel->ptail        = NULL;
427 
428 	memset(plevel->states, EMPTY, plevel->array_length);
429 }
430 
431 // ----------------------------------------------------------------
mlhmmv_level_has_key(mlhmmv_level_t * plevel,mv_t * plevel_key)432 int mlhmmv_level_has_key(mlhmmv_level_t* plevel, mv_t* plevel_key) {
433 	int ideal_index = 0;
434 	int index = mlhmmv_level_find_index_for_key(plevel, plevel_key, &ideal_index);
435 	if (plevel->states[index] == OCCUPIED)
436 		return TRUE;
437 	else if (plevel->states[index] == EMPTY)
438 		return FALSE;
439 	else {
440 		fprintf(stderr, "%s: mlhmmv_level_find_index_for_key did not find end of chain\n", MLR_GLOBALS.bargv0);
441 		exit(1);
442 	}
443 }
444 
445 // ----------------------------------------------------------------
446 // Returns >=0 for where the key is *or* should go (end of chain).
447 
mlhmmv_level_find_index_for_key(mlhmmv_level_t * plevel,mv_t * plevel_key,int * pideal_index)448 static int mlhmmv_level_find_index_for_key(mlhmmv_level_t* plevel, mv_t* plevel_key, int* pideal_index) {
449 	int hash = mlhmmv_hash_func(plevel_key);
450 	int index = mlr_canonical_mod(hash, plevel->array_length);
451 	*pideal_index = index;
452 	int num_tries = 0;
453 
454 	while (TRUE) {
455 		mlhmmv_level_entry_t* pentry = &plevel->entries[index];
456 		if (plevel->states[index] == OCCUPIED) {
457 			mv_t* ekey = &pentry->level_key;
458 			// Existing key found in chain.
459 			if (mv_equals_si(plevel_key, ekey))
460 				return index;
461 		} else if (plevel->states[index] == EMPTY) {
462 			return index;
463 		}
464 
465 		// If the current entry has been freed, i.e. previously occupied,
466 		// the sought index may be further down the chain.  So we must
467 		// continue looking.
468 		if (++num_tries >= plevel->array_length) {
469 			fprintf(stderr,
470 				"%s: Coding error:  table full even after enlargement.\n", MLR_GLOBALS.bargv0);
471 			exit(1);
472 		}
473 
474 		// Linear probing.
475 		if (++index >= plevel->array_length)
476 			index = 0;
477 	}
478 	MLR_INTERNAL_CODING_ERROR();
479 	return -1; // not reached
480 }
481 
482 // ----------------------------------------------------------------
mlhmmv_level_look_up_and_ref_entry(mlhmmv_level_t * plevel,sllmve_t * prestkeys,int * perror)483 static mlhmmv_level_entry_t* mlhmmv_level_look_up_and_ref_entry(mlhmmv_level_t* plevel,
484 	sllmve_t* prestkeys, int* perror)
485 {
486 	if (perror)
487 		*perror = MLHMMV_ERROR_NONE;
488 	if (prestkeys == NULL) {
489 		if (perror)
490 			*perror = MLHMMV_ERROR_KEYLIST_TOO_SHALLOW;
491 		return NULL;
492 	}
493 	mlhmmv_level_entry_t* plevel_entry = mlhmmv_level_get_next_level_entry(plevel, &prestkeys->value, NULL);
494 	while (prestkeys->pnext != NULL) {
495 		if (plevel_entry == NULL) {
496 			return NULL;
497 		}
498 		if (plevel_entry->level_xvalue.is_terminal) {
499 			if (perror)
500 				*perror = MLHMMV_ERROR_KEYLIST_TOO_DEEP;
501 			return NULL;
502 		}
503 		plevel = plevel_entry->level_xvalue.pnext_level;
504 		prestkeys = prestkeys->pnext;
505 		plevel_entry = mlhmmv_level_get_next_level_entry(plevel_entry->level_xvalue.pnext_level,
506 			&prestkeys->value, NULL);
507 	}
508 	return plevel_entry;
509 }
510 
511 // ----------------------------------------------------------------
mlhmmv_level_get_next_level_entry(mlhmmv_level_t * plevel,mv_t * plevel_key,int * pindex)512 static mlhmmv_level_entry_t* mlhmmv_level_get_next_level_entry(mlhmmv_level_t* plevel, mv_t* plevel_key, int* pindex) {
513 	int ideal_index = 0;
514 	int index = mlhmmv_level_find_index_for_key(plevel, plevel_key, &ideal_index);
515 	mlhmmv_level_entry_t* pentry = &plevel->entries[index];
516 
517 	if (pindex != NULL)
518 		*pindex = index;
519 
520 	if (plevel->states[index] == OCCUPIED)
521 		return pentry;
522 	else if (plevel->states[index] == EMPTY)
523 		return NULL;
524 	else {
525 		fprintf(stderr, "%s: mlhmmv_level_find_index_for_key did not find end of chain\n", MLR_GLOBALS.bargv0);
526 		exit(1);
527 	}
528 }
529 
530 // ----------------------------------------------------------------
mlhmmv_level_get_next_level_xvalue(mlhmmv_level_t * plevel,mv_t * plevel_key)531 static mlhmmv_xvalue_t* mlhmmv_level_get_next_level_xvalue(mlhmmv_level_t* plevel, mv_t* plevel_key) {
532 	if (plevel == NULL)
533 		return NULL;
534 	mlhmmv_level_entry_t* pentry = mlhmmv_level_get_next_level_entry(plevel, plevel_key, NULL);
535 	if (pentry == NULL)
536 		return NULL;
537 	else
538 		return &pentry->level_xvalue;
539 }
540 
541 // ----------------------------------------------------------------
mlhmmv_level_look_up_and_ref_terminal(mlhmmv_level_t * plevel,sllmv_t * pmvkeys,int * perror)542 mv_t* mlhmmv_level_look_up_and_ref_terminal(mlhmmv_level_t* plevel, sllmv_t* pmvkeys, int* perror) {
543 	mlhmmv_level_entry_t* plevel_entry = mlhmmv_level_look_up_and_ref_entry(plevel, pmvkeys->phead, perror);
544 	if (plevel_entry == NULL) {
545 		return NULL;
546 	}
547 	if (!plevel_entry->level_xvalue.is_terminal) {
548 		*perror = MLHMMV_ERROR_KEYLIST_TOO_SHALLOW;
549 		return NULL;
550 	}
551 	return &plevel_entry->level_xvalue.terminal_mlrval;
552 }
553 
554 // ----------------------------------------------------------------
mlhmmv_level_look_up_and_ref_xvalue(mlhmmv_level_t * pstart_level,sllmv_t * pmvkeys,int * perror)555 mlhmmv_xvalue_t* mlhmmv_level_look_up_and_ref_xvalue(mlhmmv_level_t* pstart_level, sllmv_t* pmvkeys, int* perror) {
556 	*perror = MLHMMV_ERROR_NONE;
557 	sllmve_t* prest_keys = pmvkeys->phead;
558 	if (prest_keys == NULL) {
559 		*perror = MLHMMV_ERROR_KEYLIST_TOO_SHALLOW;
560 		return NULL;
561 	}
562 	mlhmmv_level_t* plevel = pstart_level;
563 	if (plevel == NULL) {
564 		return NULL;
565 	}
566 	mlhmmv_level_entry_t* plevel_entry = mlhmmv_level_get_next_level_entry(plevel, &prest_keys->value, NULL);
567 	while (prest_keys->pnext != NULL) {
568 		if (plevel_entry == NULL) {
569 			return NULL;
570 		} else {
571 			plevel = plevel_entry->level_xvalue.pnext_level;
572 			prest_keys = prest_keys->pnext;
573 			if (plevel == NULL)
574 				return NULL;
575 			plevel_entry = mlhmmv_level_get_next_level_entry(plevel, &prest_keys->value, NULL);
576 		}
577 	}
578 	if (plevel_entry == NULL) {
579 		*perror = MLHMMV_ERROR_KEYLIST_TOO_DEEP;
580 		return NULL;
581 	}
582 	return &plevel_entry->level_xvalue;
583 }
584 
585 // ----------------------------------------------------------------
mlhmmv_level_ref_or_create(mlhmmv_level_t * plevel,sllmve_t * prest_keys)586 static mlhmmv_level_t* mlhmmv_level_ref_or_create(mlhmmv_level_t* plevel, sllmve_t* prest_keys) {
587 	if ((plevel->num_occupied + plevel->num_freed) >= (plevel->array_length * LOAD_FACTOR))
588 		mlhmmv_level_enlarge(plevel);
589 	return mlhmmv_level_get_or_create_no_enlarge(plevel, prest_keys);
590 }
591 
592 // ----------------------------------------------------------------
mlhmmv_level_get_or_create_no_enlarge(mlhmmv_level_t * plevel,sllmve_t * prest_keys)593 static mlhmmv_level_t* mlhmmv_level_get_or_create_no_enlarge(mlhmmv_level_t* plevel, sllmve_t* prest_keys) {
594 	mv_t* plevel_key = &prest_keys->value;
595 	int ideal_index = 0;
596 	int index = mlhmmv_level_find_index_for_key(plevel, plevel_key, &ideal_index);
597 	mlhmmv_level_entry_t* pentry = &plevel->entries[index];
598 
599 	if (plevel->states[index] == EMPTY) { // End of chain.
600 
601 		plevel->states[index] = OCCUPIED;
602 		plevel->num_occupied++;
603 		pentry->ideal_index = ideal_index;
604 		pentry->level_key = mv_copy(plevel_key);
605 		pentry->level_xvalue.is_terminal = FALSE;
606 		pentry->level_xvalue.pnext_level = mlhmmv_level_alloc();
607 
608 		if (plevel->phead == NULL) { // First entry at this level
609 			pentry->pprev = NULL;
610 			pentry->pnext = NULL;
611 			plevel->phead = pentry;
612 			plevel->ptail = pentry;
613 		} else {                     // Subsequent entry at this level
614 			pentry->pprev = plevel->ptail;
615 			pentry->pnext = NULL;
616 			plevel->ptail->pnext = pentry;
617 			plevel->ptail = pentry;
618 		}
619 
620 		if (prest_keys->pnext != NULL) {
621 			// RECURSE
622 			return mlhmmv_level_ref_or_create(pentry->level_xvalue.pnext_level, prest_keys->pnext);
623 		} else {
624 			return pentry->level_xvalue.pnext_level;
625 		}
626 
627 	} else if (plevel->states[index] == OCCUPIED) { // Existing key found in chain
628 
629 		if (pentry->level_xvalue.is_terminal) {
630 			mv_free(&pentry->level_xvalue.terminal_mlrval);
631 			pentry->level_xvalue.is_terminal = FALSE;
632 			pentry->level_xvalue.pnext_level = mlhmmv_level_alloc();
633 		}
634 		if (prest_keys->pnext == NULL) {
635 			return pentry->level_xvalue.pnext_level;
636 		} else { // RECURSE
637 			return mlhmmv_level_ref_or_create(pentry->level_xvalue.pnext_level, prest_keys->pnext);
638 		}
639 
640 	} else {
641 		fprintf(stderr, "%s: mlhmmv_level_find_index_for_key did not find end of chain\n", MLR_GLOBALS.bargv0);
642 		exit(1);
643 	}
644 }
645 
646 // ----------------------------------------------------------------
mlhmmv_level_put_empty_map(mlhmmv_level_t * plevel,mv_t * pkey)647 mlhmmv_level_t* mlhmmv_level_put_empty_map(mlhmmv_level_t* plevel, mv_t* pkey) {
648 	int error;
649 	mv_t absent = mv_absent();
650 
651 	sllmve_t e = {
652 		.value      = *pkey,
653 		.free_flags = 0,
654 		.pnext      = NULL
655 	};
656 	mlhmmv_level_put_terminal(plevel, &e, &absent); // xxx optimize to avoid 2nd lookup
657 	sllmv_t s = {
658 		.phead = &e,
659 		.ptail = &e,
660 		.length = 1
661 	};
662 	mlhmmv_xvalue_t* pxval = mlhmmv_level_look_up_and_ref_xvalue(plevel, &s, &error);
663 	*pxval = mlhmmv_xvalue_alloc_empty_map();
664 	return pxval->pnext_level;
665 }
666 
667 // ----------------------------------------------------------------
mlhmmv_level_enlarge(mlhmmv_level_t * plevel)668 static void mlhmmv_level_enlarge(mlhmmv_level_t* plevel) {
669 	mlhmmv_level_entry_t*       old_entries = plevel->entries;
670 	mlhmmv_level_entry_state_t* old_states  = plevel->states;
671 	mlhmmv_level_entry_t*       old_head    = plevel->phead;
672 
673 	mlhmmv_level_init(plevel, plevel->array_length*ENLARGEMENT_FACTOR);
674 
675 	for (mlhmmv_level_entry_t* pentry = old_head; pentry != NULL; pentry = pentry->pnext) {
676 		mlhmmv_level_move(plevel, &pentry->level_key, &pentry->level_xvalue);
677 	}
678 	free(old_entries);
679 	free(old_states);
680 }
681 
682 // ----------------------------------------------------------------
683 // This is done only on map-level enlargement.
684 // Example:
685 // * level = map["a"], rest_keys = [2, "c"] ,   terminal_value = 4.
686 //                     rest_keys = ["e", "f"] , terminal_value = 7.
687 //                     rest_keys = [6] ,        terminal_value = "g".
688 //
689 // which is to say for the purposes of this routine
690 //
691 // * level = map["a"], level_key = 2,   level_xvalue = non-terminal ["c"] => terminal_value = 4.
692 //                     level_key = "e", level_xvalue = non-terminal ["f"] => terminal_value = 7.
693 //                     level_key = 6,   level_xvalue = terminal_value = "g".
694 
mlhmmv_level_move(mlhmmv_level_t * plevel,mv_t * plevel_key,mlhmmv_xvalue_t * plevel_value)695 static void mlhmmv_level_move(mlhmmv_level_t* plevel, mv_t* plevel_key, mlhmmv_xvalue_t* plevel_value) {
696 	int ideal_index = 0;
697 	int index = mlhmmv_level_find_index_for_key(plevel, plevel_key, &ideal_index);
698 	mlhmmv_level_entry_t* pentry = &plevel->entries[index];
699 
700 	if (plevel->states[index] == OCCUPIED) {
701 		// Existing key found in chain; put value.
702 		pentry->level_xvalue = *plevel_value;
703 
704 	} else if (plevel->states[index] == EMPTY) {
705 		// End of chain.
706 		pentry->ideal_index = ideal_index;
707 		pentry->level_key = *plevel_key;
708 		// For the put API, we copy data passed in. But for internal enlarges, we just need to move pointers around.
709 		pentry->level_xvalue = *plevel_value;
710 		plevel->states[index] = OCCUPIED;
711 
712 		if (plevel->phead == NULL) {
713 			pentry->pprev = NULL;
714 			pentry->pnext = NULL;
715 			plevel->phead = pentry;
716 			plevel->ptail = pentry;
717 		} else {
718 			pentry->pprev = plevel->ptail;
719 			pentry->pnext = NULL;
720 			plevel->ptail->pnext = pentry;
721 			plevel->ptail = pentry;
722 		}
723 		plevel->num_occupied++;
724 	}
725 	else {
726 		fprintf(stderr, "%s: mlhmmv_level_find_index_for_key did not find end of chain\n", MLR_GLOBALS.bargv0);
727 		exit(1);
728 	}
729 }
730 
731 // ----------------------------------------------------------------
mlhmmv_level_put_xvalue(mlhmmv_level_t * plevel,sllmve_t * prest_keys,mlhmmv_xvalue_t * pvalue)732 void mlhmmv_level_put_xvalue(mlhmmv_level_t* plevel, sllmve_t* prest_keys, mlhmmv_xvalue_t* pvalue) { // xxx 'copy' into name
733 	if ((plevel->num_occupied + plevel->num_freed) >= (plevel->array_length * LOAD_FACTOR))
734 		mlhmmv_level_enlarge(plevel);
735 	mlhmmv_level_put_xvalue_no_enlarge(plevel, prest_keys, pvalue);
736 }
737 
mlhmmv_level_put_xvalue_singly_keyed(mlhmmv_level_t * plevel,mv_t * pkey,mlhmmv_xvalue_t * pvalue)738 void mlhmmv_level_put_xvalue_singly_keyed(mlhmmv_level_t* plevel, mv_t* pkey, mlhmmv_xvalue_t* pvalue) {
739 	sllmve_t e = { .value = *pkey, .free_flags = 0, .pnext = NULL };
740 	mlhmmv_level_put_xvalue(plevel, &e, pvalue);
741 }
742 
743 // ----------------------------------------------------------------
mlhmmv_level_put_xvalue_no_enlarge(mlhmmv_level_t * plevel,sllmve_t * prest_keys,mlhmmv_xvalue_t * pvalue)744 static void mlhmmv_level_put_xvalue_no_enlarge(mlhmmv_level_t* plevel, sllmve_t* prest_keys,
745 	mlhmmv_xvalue_t* pvalue)
746 {
747 	mv_t* plevel_key = &prest_keys->value;
748 	int ideal_index = 0;
749 	int index = mlhmmv_level_find_index_for_key(plevel, plevel_key, &ideal_index);
750 	mlhmmv_level_entry_t* pentry = &plevel->entries[index];
751 
752 	if (plevel->states[index] == EMPTY) { // End of chain.
753 		pentry->ideal_index = ideal_index;
754 		pentry->level_key = mv_copy(plevel_key); // (xxx weird & needs explaining) key is copied ...
755 
756 		if (prest_keys->pnext == NULL) {
757 			pentry->level_xvalue = *pvalue; // (xxx weird & needs explaining) ... but the value is not copied
758 		} else {
759 			pentry->level_xvalue.is_terminal = FALSE;
760 			pentry->level_xvalue.pnext_level = mlhmmv_level_alloc();
761 		}
762 		plevel->states[index] = OCCUPIED;
763 
764 		if (plevel->phead == NULL) { // First entry at this level
765 			pentry->pprev = NULL;
766 			pentry->pnext = NULL;
767 			plevel->phead = pentry;
768 			plevel->ptail = pentry;
769 		} else {                     // Subsequent entry at this level
770 			pentry->pprev = plevel->ptail;
771 			pentry->pnext = NULL;
772 			plevel->ptail->pnext = pentry;
773 			plevel->ptail = pentry;
774 		}
775 
776 		plevel->num_occupied++;
777 		if (prest_keys->pnext != NULL) {
778 			// RECURSE
779 			mlhmmv_level_put_xvalue(pentry->level_xvalue.pnext_level, prest_keys->pnext, pvalue);
780 		}
781 
782 	} else if (plevel->states[index] == OCCUPIED) { // Existing key found in chain
783 		if (prest_keys->pnext == NULL) { // Place the terminal at this level
784 			if (pentry->level_xvalue.is_terminal) {
785 				mv_free(&pentry->level_xvalue.terminal_mlrval);
786 			} else {
787 				mlhmmv_level_free(pentry->level_xvalue.pnext_level);
788 			}
789 			pentry->level_xvalue = *pvalue;
790 
791 		} else { // The terminal will be placed at a deeper level
792 			if (pentry->level_xvalue.is_terminal) {
793 				mv_free(&pentry->level_xvalue.terminal_mlrval);
794 				pentry->level_xvalue.is_terminal = FALSE;
795 				pentry->level_xvalue.pnext_level = mlhmmv_level_alloc();
796 			}
797 			// RECURSE
798 			mlhmmv_level_put_xvalue(pentry->level_xvalue.pnext_level, prest_keys->pnext, pvalue);
799 		}
800 
801 	} else {
802 		fprintf(stderr, "%s: mlhmmv_level_find_index_for_key did not find end of chain\n", MLR_GLOBALS.bargv0);
803 		exit(1);
804 	}
805 }
806 
807 // ----------------------------------------------------------------
808 // Example on recursive calls:
809 // * level = map, rest_keys = ["a", 2, "c"] , terminal value = 4.
810 // * level = map["a"], rest_keys = [2, "c"] , terminal value = 4.
811 // * level = map["a"][2], rest_keys = ["c"] , terminal value = 4.
812 
mlhmmv_level_put_terminal(mlhmmv_level_t * plevel,sllmve_t * prest_keys,mv_t * pterminal_value)813 void mlhmmv_level_put_terminal(mlhmmv_level_t* plevel, sllmve_t* prest_keys, mv_t* pterminal_value) {
814 	if ((plevel->num_occupied + plevel->num_freed) >= (plevel->array_length * LOAD_FACTOR))
815 		mlhmmv_level_enlarge(plevel);
816 	mlhmmv_level_put_terminal_no_enlarge(plevel, prest_keys, pterminal_value);
817 }
818 
mlhmmv_level_put_terminal_singly_keyed(mlhmmv_level_t * plevel,mv_t * pkey,mv_t * pterminal_value)819 void mlhmmv_level_put_terminal_singly_keyed(mlhmmv_level_t* plevel, mv_t* pkey, mv_t* pterminal_value) {
820 	sllmve_t e = { .value = *pkey, .free_flags = 0, .pnext = NULL };
821 	mlhmmv_level_put_terminal(plevel, &e, pterminal_value);
822 }
823 
824 // ----------------------------------------------------------------
mlhmmv_level_put_terminal_no_enlarge(mlhmmv_level_t * plevel,sllmve_t * prest_keys,mv_t * pterminal_value)825 static void mlhmmv_level_put_terminal_no_enlarge(mlhmmv_level_t* plevel, sllmve_t* prest_keys, mv_t* pterminal_value) {
826 	mv_t* plevel_key = &prest_keys->value;
827 	int ideal_index = 0;
828 	int index = mlhmmv_level_find_index_for_key(plevel, plevel_key, &ideal_index);
829 	mlhmmv_level_entry_t* pentry = &plevel->entries[index];
830 
831 	if (plevel->states[index] == EMPTY) { // End of chain.
832 		pentry->ideal_index = ideal_index;
833 		pentry->level_key = mv_copy(plevel_key); // <------------------------- copy key
834 
835 		if (prest_keys->pnext == NULL) {
836 			pentry->level_xvalue.is_terminal = TRUE;
837 			pentry->level_xvalue.terminal_mlrval = mv_copy(pterminal_value); // <--------------- copy value
838 		} else {
839 			pentry->level_xvalue.is_terminal = FALSE;
840 			pentry->level_xvalue.pnext_level = mlhmmv_level_alloc();
841 		}
842 		plevel->states[index] = OCCUPIED;
843 
844 		if (plevel->phead == NULL) { // First entry at this level
845 			pentry->pprev = NULL;
846 			pentry->pnext = NULL;
847 			plevel->phead = pentry;
848 			plevel->ptail = pentry;
849 		} else {                     // Subsequent entry at this level
850 			pentry->pprev = plevel->ptail;
851 			pentry->pnext = NULL;
852 			plevel->ptail->pnext = pentry;
853 			plevel->ptail = pentry;
854 		}
855 
856 		plevel->num_occupied++;
857 		if (prest_keys->pnext != NULL) {
858 			// RECURSE
859 			mlhmmv_level_put_terminal(pentry->level_xvalue.pnext_level, prest_keys->pnext, pterminal_value);
860 		}
861 
862 	} else if (plevel->states[index] == OCCUPIED) { // Existing key found in chain
863 		if (prest_keys->pnext == NULL) { // Place the terminal at this level
864 			if (pentry->level_xvalue.is_terminal) {
865 				mv_free(&pentry->level_xvalue.terminal_mlrval);
866 			} else {
867 				mlhmmv_level_free(pentry->level_xvalue.pnext_level);
868 			}
869 			pentry->level_xvalue.is_terminal = TRUE;
870 			pentry->level_xvalue.terminal_mlrval = mv_copy(pterminal_value); // <--------------- copy value
871 
872 		} else { // The terminal will be placed at a deeper level
873 			if (pentry->level_xvalue.is_terminal) {
874 				mv_free(&pentry->level_xvalue.terminal_mlrval);
875 				pentry->level_xvalue.is_terminal = FALSE;
876 				pentry->level_xvalue.pnext_level = mlhmmv_level_alloc();
877 			}
878 			// RECURSE
879 			mlhmmv_level_put_terminal(pentry->level_xvalue.pnext_level, prest_keys->pnext, pterminal_value);
880 		}
881 
882 	} else {
883 		fprintf(stderr, "%s: mlhmmv_level_find_index_for_key did not find end of chain\n", MLR_GLOBALS.bargv0);
884 		exit(1);
885 	}
886 }
887 
888 // ----------------------------------------------------------------
mlhmmv_level_to_lrecs(mlhmmv_level_t * plevel,sllmv_t * pkeys,sllmv_t * pnames,sllv_t * poutrecs,int do_full_prefixing,char * flatten_separator)889 void mlhmmv_level_to_lrecs(mlhmmv_level_t* plevel, sllmv_t* pkeys, sllmv_t* pnames, sllv_t* poutrecs,
890 	int do_full_prefixing, char* flatten_separator)
891 {
892 	mv_t* pfirstkey = &pkeys->phead->value;
893 
894 	mlhmmv_level_entry_t* ptop_entry = mlhmmv_level_look_up_and_ref_entry(plevel, pkeys->phead, NULL);
895 
896 	if (ptop_entry == NULL) {
897 		// No such entry in the mlhmmv results in no output records
898 	} else if (ptop_entry->level_xvalue.is_terminal) {
899 		// E.g. '@v = 3' at the top level of the mlhmmv.
900 		lrec_t* poutrec = lrec_unbacked_alloc();
901 		lrec_put(poutrec,
902 			mv_alloc_format_val(pfirstkey),
903 			mv_alloc_format_val(&ptop_entry->level_xvalue.terminal_mlrval), FREE_ENTRY_KEY|FREE_ENTRY_VALUE);
904 		sllv_append(poutrecs, poutrec);
905 	} else {
906 		// E.g. '@v = {...}' at the top level of the mlhmmv: the map value keyed by oosvar-name 'v' is itself a hashmap.
907 		// This needs to be flattened down to an lrec which is a list of key-value pairs.  We recursively invoke
908 		// mlhmmv_level_to_lrecs_across_records for each of the name-list entries, one map level deeper each call, then
909 		// from there invoke mlhmmv_level_to_lrec_within_record on any remaining map levels.
910 		lrec_t* ptemplate = lrec_unbacked_alloc();
911 		char* oosvar_name = mv_alloc_format_val(pfirstkey);
912 		mlhmmv_level_to_lrecs_across_records(ptop_entry->level_xvalue.pnext_level, oosvar_name, pnames->phead,
913 			ptemplate, poutrecs, do_full_prefixing, flatten_separator);
914 		free(oosvar_name);
915 		lrec_free(ptemplate);
916 	}
917 }
918 
919 // ----------------------------------------------------------------
mlhmmv_level_to_lrecs_across_records(mlhmmv_level_t * plevel,char * prefix,sllmve_t * prestnames,lrec_t * ptemplate,sllv_t * poutrecs,int do_full_prefixing,char * flatten_separator)920 static void mlhmmv_level_to_lrecs_across_records(
921 	mlhmmv_level_t* plevel,
922 	char*           prefix,
923 	sllmve_t*       prestnames,
924 	lrec_t*         ptemplate,
925 	sllv_t*         poutrecs,
926 	int             do_full_prefixing,
927 	char*           flatten_separator)
928 {
929 	if (prestnames != NULL) {
930 		// If there is a namelist entry, pull it out to its own field on the output lrecs.
931 		for (mlhmmv_level_entry_t* pe = plevel->phead; pe != NULL; pe = pe->pnext) {
932 			mlhmmv_xvalue_t* plevel_value = &pe->level_xvalue;
933 			lrec_t* pnextrec = lrec_copy(ptemplate);
934 			lrec_put(pnextrec,
935 				mv_alloc_format_val(&prestnames->value),
936 				mv_alloc_format_val(&pe->level_key), FREE_ENTRY_KEY|FREE_ENTRY_VALUE);
937 			if (plevel_value->is_terminal) {
938 				lrec_put(pnextrec,
939 					mlr_strdup_or_die(prefix),
940 					mv_alloc_format_val(&plevel_value->terminal_mlrval), FREE_ENTRY_KEY|FREE_ENTRY_VALUE);
941 				sllv_append(poutrecs, pnextrec);
942 			} else {
943 				mlhmmv_level_to_lrecs_across_records(pe->level_xvalue.pnext_level,
944 					prefix, prestnames->pnext, pnextrec, poutrecs, do_full_prefixing, flatten_separator);
945 				lrec_free(pnextrec);
946 			}
947 		}
948 
949 	} else {
950 		// If there are no more remaining namelist entries, flatten remaining map levels using the join separator
951 		// (default ":") and use them to create lrec values.
952 		lrec_t* pnextrec = lrec_copy(ptemplate);
953 		int emit = TRUE;
954 		for (mlhmmv_level_entry_t* pe = plevel->phead; pe != NULL; pe = pe->pnext) {
955 			mlhmmv_xvalue_t* plevel_value = &pe->level_xvalue;
956 			if (plevel_value->is_terminal) {
957 				char* temp = mv_alloc_format_val(&pe->level_key);
958 				char* next_prefix = do_full_prefixing
959 					? mlr_paste_3_strings(prefix, flatten_separator, temp)
960 					: mlr_strdup_or_die(temp);
961 				free(temp);
962 				lrec_put(pnextrec,
963 					next_prefix,
964 					mv_alloc_format_val(&plevel_value->terminal_mlrval),
965 					FREE_ENTRY_KEY|FREE_ENTRY_VALUE);
966 			} else if (do_full_prefixing) {
967 				char* temp = mv_alloc_format_val(&pe->level_key);
968 				char* next_prefix = mlr_paste_3_strings(prefix, flatten_separator, temp);
969 				free(temp);
970 				mlhmmv_level_to_lrec_within_record(plevel_value->pnext_level, next_prefix, pnextrec,
971 					do_full_prefixing, flatten_separator);
972 				free(next_prefix);
973 			} else {
974 				mlhmmv_level_to_lrecs_across_records(pe->level_xvalue.pnext_level,
975 					prefix, NULL, pnextrec, poutrecs, do_full_prefixing, flatten_separator);
976 				emit = FALSE;
977 			}
978 		}
979 		if (emit)
980 			sllv_append(poutrecs, pnextrec);
981 		else
982 			lrec_free(pnextrec);
983 	}
984 }
985 
986 // ----------------------------------------------------------------
mlhmmv_level_to_lrec_within_record(mlhmmv_level_t * plevel,char * prefix,lrec_t * poutrec,int do_full_prefixing,char * flatten_separator)987 static void mlhmmv_level_to_lrec_within_record(
988 	mlhmmv_level_t* plevel,
989 	char*           prefix,
990 	lrec_t*         poutrec,
991 	int             do_full_prefixing,
992 	char*           flatten_separator)
993 {
994 	for (mlhmmv_level_entry_t* pe = plevel->phead; pe != NULL; pe = pe->pnext) {
995 		mlhmmv_xvalue_t* plevel_value = &pe->level_xvalue;
996 		char* temp = mv_alloc_format_val(&pe->level_key);
997 		char* next_prefix = do_full_prefixing
998 			? mlr_paste_3_strings(prefix, flatten_separator, temp)
999 			: mlr_strdup_or_die(temp);
1000 		free(temp);
1001 		if (plevel_value->is_terminal) {
1002 			lrec_put(poutrec,
1003 				next_prefix,
1004 				mv_alloc_format_val(&plevel_value->terminal_mlrval),
1005 				FREE_ENTRY_KEY|FREE_ENTRY_VALUE);
1006 		} else {
1007 			mlhmmv_level_to_lrec_within_record(plevel_value->pnext_level, next_prefix, poutrec,
1008 				do_full_prefixing, flatten_separator);
1009 			free(next_prefix);
1010 		}
1011 	}
1012 }
1013 
1014 // ----------------------------------------------------------------
mlhhmv_levels_to_lrecs_lashed_across_records(mlhmmv_level_t ** pplevels,char ** prefixes,int num_levels,sllmve_t * prestnames,lrec_t * ptemplate,sllv_t * poutrecs,int do_full_prefixing,char * flatten_separator)1015 static void mlhhmv_levels_to_lrecs_lashed_across_records(
1016 	mlhmmv_level_t** pplevels,
1017 	char**           prefixes,
1018 	int              num_levels,
1019 	sllmve_t*        prestnames,
1020 	lrec_t*          ptemplate,
1021 	sllv_t*          poutrecs,
1022 	int              do_full_prefixing,
1023 	char*            flatten_separator)
1024 {
1025 	if (prestnames != NULL) {
1026 		// If there is a namelist entry, pull it out to its own field on the output lrecs.
1027 		// First is iterated over and the rest are lashed (lookups with same keys as primary).
1028 		if (pplevels[0] != NULL) {
1029 			for (mlhmmv_level_entry_t* pe = pplevels[0]->phead; pe != NULL; pe = pe->pnext) {
1030 				mlhmmv_xvalue_t* pfirst_level_value = &pe->level_xvalue;
1031 				lrec_t* pnextrec = lrec_copy(ptemplate);
1032 				lrec_put(pnextrec,
1033 					mv_alloc_format_val(&prestnames->value),
1034 					mv_alloc_format_val(&pe->level_key), FREE_ENTRY_KEY|FREE_ENTRY_VALUE);
1035 
1036 				if (pfirst_level_value->is_terminal) {
1037 					for (int i = 0; i < num_levels; i++) {
1038 						mlhmmv_xvalue_t* plevel_value = mlhmmv_level_get_next_level_xvalue(pplevels[i], &pe->level_key);
1039 						if (plevel_value != NULL && plevel_value->is_terminal) {
1040 							lrec_put(pnextrec,
1041 								mlr_strdup_or_die(prefixes[i]),
1042 								mv_alloc_format_val(&plevel_value->terminal_mlrval), FREE_ENTRY_KEY|FREE_ENTRY_VALUE);
1043 						}
1044 					}
1045 					sllv_append(poutrecs, pnextrec);
1046 				} else {
1047 					mlhmmv_level_t** ppnext_levels = mlr_malloc_or_die(num_levels * sizeof(mlhmmv_level_t*));
1048 					for (int i = 0; i < num_levels; i++) {
1049 						mlhmmv_xvalue_t* plevel_value = mlhmmv_level_get_next_level_xvalue(pplevels[i], &pe->level_key);
1050 						if (plevel_value == NULL || plevel_value->is_terminal) {
1051 							ppnext_levels[i] = NULL;
1052 						} else {
1053 							ppnext_levels[i] = plevel_value->pnext_level;
1054 						}
1055 					}
1056 
1057 					mlhhmv_levels_to_lrecs_lashed_across_records(ppnext_levels, prefixes, num_levels,
1058 						prestnames->pnext, pnextrec, poutrecs, do_full_prefixing, flatten_separator);
1059 
1060 					free(ppnext_levels);
1061 					lrec_free(pnextrec);
1062 				}
1063 			}
1064 		}
1065 
1066 	} else if (pplevels[0] != NULL) {
1067 		// If there are no more remaining namelist entries, flatten remaining map levels using the join separator
1068 		// (default ":") and use them to create lrec values.
1069 		lrec_t* pnextrec = lrec_copy(ptemplate);
1070 		int emit = TRUE;
1071 		for (mlhmmv_level_entry_t* pe = pplevels[0]->phead; pe != NULL; pe = pe->pnext) {
1072 			if (pe->level_xvalue.is_terminal) {
1073 				char* temp = mv_alloc_format_val(&pe->level_key);
1074 				for (int i = 0; i < num_levels; i++) {
1075 					mlhmmv_xvalue_t* plevel_value = mlhmmv_level_get_next_level_xvalue(pplevels[i], &pe->level_key);
1076 					if (plevel_value != NULL && plevel_value->is_terminal) {
1077 						char* name = do_full_prefixing
1078 							? mlr_paste_3_strings(prefixes[i], flatten_separator, temp)
1079 							: mlr_strdup_or_die(temp);
1080 						lrec_put(pnextrec,
1081 							name,
1082 							mv_alloc_format_val(&plevel_value->terminal_mlrval),
1083 							FREE_ENTRY_KEY|FREE_ENTRY_VALUE);
1084 					}
1085 				}
1086 				free(temp);
1087 			} else if (do_full_prefixing) {
1088 				char* temp = mv_alloc_format_val(&pe->level_key);
1089 				mlhmmv_level_t** ppnext_levels = mlr_malloc_or_die(num_levels * sizeof(mlhmmv_level_t*));
1090 				char** next_prefixes = mlr_malloc_or_die(num_levels * sizeof(char*));
1091 				for (int i = 0; i < num_levels; i++) {
1092 					mlhmmv_xvalue_t* plevel_value = mlhmmv_level_get_next_level_xvalue(pplevels[i], &pe->level_key);
1093 					if (plevel_value != NULL && !plevel_value->is_terminal) {
1094 						ppnext_levels[i] = plevel_value->pnext_level;
1095 						next_prefixes[i] = mlr_paste_3_strings(prefixes[i], flatten_separator, temp);
1096 					} else {
1097 						ppnext_levels[i] = NULL;
1098 						next_prefixes[i] = NULL;
1099 					}
1100 				}
1101 
1102 				mlhhmv_levels_to_lrecs_lashed_within_records(ppnext_levels, next_prefixes, num_levels,
1103 					pnextrec, do_full_prefixing, flatten_separator);
1104 
1105 				for (int i = 0; i < num_levels; i++) {
1106 					free(next_prefixes[i]);
1107 				}
1108 				free(next_prefixes);
1109 				free(ppnext_levels);
1110 				free(temp);
1111 			} else {
1112 				mlhmmv_level_t** ppnext_levels = mlr_malloc_or_die(num_levels * sizeof(mlhmmv_level_t*));
1113 				for (int i = 0; i < num_levels; i++) {
1114 					mlhmmv_xvalue_t* plevel_value = mlhmmv_level_get_next_level_xvalue(pplevels[i], &pe->level_key);
1115 					if (plevel_value->is_terminal) {
1116 						ppnext_levels[i] = NULL;
1117 					} else {
1118 						ppnext_levels[i] = plevel_value->pnext_level;
1119 					}
1120 				}
1121 
1122 				mlhhmv_levels_to_lrecs_lashed_across_records(ppnext_levels, prefixes, num_levels,
1123 					NULL, pnextrec, poutrecs, do_full_prefixing, flatten_separator);
1124 
1125 				free(ppnext_levels);
1126 				emit = FALSE;
1127 			}
1128 		}
1129 		if (emit)
1130 			sllv_append(poutrecs, pnextrec);
1131 		else
1132 			lrec_free(pnextrec);
1133 	}
1134 }
1135 
1136 // ----------------------------------------------------------------
mlhhmv_levels_to_lrecs_lashed_within_records(mlhmmv_level_t ** pplevels,char ** prefixes,int num_levels,lrec_t * poutrec,int do_full_prefixing,char * flatten_separator)1137 static void mlhhmv_levels_to_lrecs_lashed_within_records(
1138 	mlhmmv_level_t** pplevels,
1139 	char**           prefixes,
1140 	int              num_levels,
1141 	lrec_t*          poutrec,
1142 	int              do_full_prefixing,
1143 	char*            flatten_separator)
1144 {
1145 	for (mlhmmv_level_entry_t* pe = pplevels[0]->phead; pe != NULL; pe = pe->pnext) {
1146 		mlhmmv_xvalue_t* pfirst_level_value = &pe->level_xvalue;
1147 		char* temp = mv_alloc_format_val(&pe->level_key);
1148 		if (pfirst_level_value->is_terminal) {
1149 			for (int i = 0; i < num_levels; i++) {
1150 				mlhmmv_xvalue_t* plevel_value = mlhmmv_level_get_next_level_xvalue(pplevels[i], &pe->level_key);
1151 				if (plevel_value != NULL && plevel_value->is_terminal) {
1152 					char* name = do_full_prefixing
1153 						? mlr_paste_3_strings(prefixes[i], flatten_separator, temp)
1154 						: mlr_strdup_or_die(temp);
1155 					lrec_put(poutrec,
1156 						name,
1157 						mv_alloc_format_val(&plevel_value->terminal_mlrval),
1158 						FREE_ENTRY_KEY|FREE_ENTRY_VALUE);
1159 				}
1160 			}
1161 		} else {
1162 			mlhmmv_level_t** ppnext_levels = mlr_malloc_or_die(num_levels * sizeof(mlhmmv_level_t*));
1163 			char** next_prefixes = mlr_malloc_or_die(num_levels * sizeof(char*));
1164 			for (int i = 0; i < num_levels; i++) {
1165 				mlhmmv_xvalue_t* plevel_value = mlhmmv_level_get_next_level_xvalue(pplevels[i], &pe->level_key);
1166 				if (plevel_value->is_terminal) {
1167 					ppnext_levels[i] = NULL;
1168 					next_prefixes[i] = NULL;
1169 				} else {
1170 					ppnext_levels[i] = plevel_value->pnext_level;
1171 					next_prefixes[i] = do_full_prefixing
1172 						? mlr_paste_3_strings(prefixes[i], flatten_separator, temp)
1173 						: mlr_strdup_or_die(temp);
1174 				}
1175 			}
1176 
1177 			mlhhmv_levels_to_lrecs_lashed_within_records(ppnext_levels, next_prefixes, num_levels,
1178 				poutrec, do_full_prefixing, flatten_separator);
1179 
1180 			for (int i = 0; i < num_levels; i++) {
1181 				free(next_prefixes[i]);
1182 			}
1183 			free(next_prefixes);
1184 			free(ppnext_levels);
1185 		}
1186 		free(temp);
1187 	}
1188 }
1189 
1190 // ----------------------------------------------------------------
mlhmmv_level_print_stacked(mlhmmv_level_t * plevel,int depth,int do_final_comma,int quote_keys_always,int quote_values_always,char * line_indent,char * line_term,FILE * ostream)1191 void mlhmmv_level_print_stacked(mlhmmv_level_t* plevel, int depth,
1192 	int do_final_comma, int quote_keys_always, int quote_values_always,
1193 	char* line_indent, char* line_term, FILE* ostream)
1194 {
1195 	if (plevel == NULL) {
1196 		return;
1197 	}
1198 	static char* leader = "  ";
1199 	// Top-level opening brace goes on a line by itself; subsequents on the same line after the level key.
1200 	if (depth == 0)
1201 		fprintf(ostream, "%s{%s", line_indent, line_term);
1202 	for (mlhmmv_level_entry_t* pentry = plevel->phead; pentry != NULL; pentry = pentry->pnext) {
1203 		fprintf(ostream, "%s", line_indent);
1204 		for (int i = 0; i <= depth; i++)
1205 			fprintf(ostream, "%s", leader);
1206 		char* level_key_string = mv_alloc_format_val(&pentry->level_key);
1207 		if (quote_keys_always || mv_is_string_or_empty(&pentry->level_key)) {
1208 			json_print_string_escaped(ostream, level_key_string);
1209 		} else {
1210 			fputs(level_key_string, ostream);
1211 		}
1212 		free(level_key_string);
1213 		fprintf(ostream, ": ");
1214 
1215 		if (pentry->level_xvalue.is_terminal) {
1216 			mlhmmv_print_terminal(&pentry->level_xvalue.terminal_mlrval, quote_keys_always,
1217 				quote_values_always, ostream);
1218 
1219 			if (pentry->pnext != NULL)
1220 				fprintf(ostream, ",%s", line_term);
1221 			else
1222 				fprintf(ostream, "%s", line_term);
1223 		} else {
1224 			fprintf(ostream, "%s{%s", line_indent, line_term);
1225 			mlhmmv_level_print_stacked(pentry->level_xvalue.pnext_level, depth + 1,
1226 				pentry->pnext != NULL, quote_keys_always, quote_values_always,
1227 				line_indent, line_term,
1228 				ostream);
1229 		}
1230 	}
1231 	for (int i = 0; i < depth; i++)
1232 		fprintf(ostream, "%s", leader);
1233 	if (do_final_comma)
1234 		fprintf(ostream, "%s},%s", line_indent, line_term);
1235 	else
1236 		fprintf(ostream, "%s}%s", line_indent, line_term);
1237 }
1238 
1239 // ----------------------------------------------------------------
mlhmmv_level_print_single_line(mlhmmv_level_t * plevel,int depth,int do_final_comma,int quote_keys_always,int quote_values_always,FILE * ostream)1240 static void mlhmmv_level_print_single_line(mlhmmv_level_t* plevel, int depth,
1241 	int do_final_comma, int quote_keys_always, int quote_values_always,
1242 	FILE* ostream)
1243 {
1244 	// Top-level opening brace goes on a line by itself; subsequents on the same line after the level key.
1245 	if (depth == 0)
1246 		fprintf(ostream, "{ ");
1247 	for (mlhmmv_level_entry_t* pentry = plevel->phead; pentry != NULL; pentry = pentry->pnext) {
1248 		char* level_key_string = mv_alloc_format_val(&pentry->level_key);
1249 		if (quote_keys_always || mv_is_string_or_empty(&pentry->level_key)) {
1250 			json_print_string_escaped(ostream, level_key_string);
1251 		} else {
1252 			fputs(level_key_string, ostream);
1253 		}
1254 		free(level_key_string);
1255 		fprintf(ostream, ": ");
1256 
1257 		if (pentry->level_xvalue.is_terminal) {
1258 			char* level_value_string = mv_alloc_format_val(&pentry->level_xvalue.terminal_mlrval);
1259 
1260 			if (quote_values_always) {
1261 				json_print_string_escaped(ostream,level_value_string);
1262 			} else if (pentry->level_xvalue.terminal_mlrval.type == MT_STRING) {
1263 				double parsed;
1264 				if (mlr_try_float_from_string(level_value_string, &parsed)) {
1265 					json_decimal_print(ostream, level_value_string, parsed);
1266 				} else if (streq(level_value_string, "true") || streq(level_value_string, "false")) {
1267 					fprintf(ostream, "%s", level_value_string);
1268 				} else {
1269 					json_print_string_escaped(ostream,level_value_string);
1270 				}
1271 			} else {
1272 				fprintf(ostream, "%s", level_value_string);
1273 			}
1274 
1275 			free(level_value_string);
1276 			if (pentry->pnext != NULL)
1277 				fprintf(ostream, ", ");
1278 		} else {
1279 			fprintf(ostream, "{");
1280 			mlhmmv_level_print_single_line(pentry->level_xvalue.pnext_level, depth + 1,
1281 				pentry->pnext != NULL, quote_keys_always, quote_values_always, ostream);
1282 		}
1283 	}
1284 	if (do_final_comma)
1285 		fprintf(ostream, " },");
1286 	else
1287 		fprintf(ostream, " }");
1288 }
1289 
1290 // ----------------------------------------------------------------
mlhmmv_level_remove(mlhmmv_level_t * plevel,sllmve_t * prestkeys)1291 void mlhmmv_level_remove(mlhmmv_level_t* plevel, sllmve_t* prestkeys) {
1292 	if (plevel == NULL) // nonesuch
1293 		return;
1294 	if (prestkeys == NULL) // restkeys too short
1295 		return;
1296 
1297 	int index = -1;
1298 	mlhmmv_level_entry_t* pentry = mlhmmv_level_get_next_level_entry(plevel, &prestkeys->value, &index);
1299 	if (pentry == NULL)
1300 		return;
1301 
1302 	if (prestkeys->pnext != NULL) {
1303 		// Keep recursing until end of restkeys.
1304 		if (pentry->level_xvalue.is_terminal) // restkeys too long
1305 			return;
1306 		mlhmmv_level_remove(pentry->level_xvalue.pnext_level, prestkeys->pnext);
1307 
1308 	} else {
1309 		// 1. Excise the node and its descendants from the storage tree
1310 		if (plevel->states[index] != OCCUPIED) {
1311 			fprintf(stderr, "%s: mlhmmv_root_remove: did not find end of chain.\n", MLR_GLOBALS.bargv0);
1312 			exit(1);
1313 		}
1314 
1315 		mv_free(&pentry->level_key);
1316 		pentry->ideal_index = -1;
1317 		plevel->states[index] = DELETED;
1318 
1319 		if (pentry == plevel->phead) {
1320 			if (pentry == plevel->ptail) {
1321 				plevel->phead = NULL;
1322 				plevel->ptail = NULL;
1323 			} else {
1324 				plevel->phead = pentry->pnext;
1325 				pentry->pnext->pprev = NULL;
1326 			}
1327 		} else if (pentry == plevel->ptail) {
1328 				plevel->ptail = pentry->pprev;
1329 				pentry->pprev->pnext = NULL;
1330 		} else {
1331 			pentry->pprev->pnext = pentry->pnext;
1332 			pentry->pnext->pprev = pentry->pprev;
1333 		}
1334 
1335 		plevel->num_freed++;
1336 		plevel->num_occupied--;
1337 
1338 		// 2. Free the memory for the node and its descendants
1339 		if (pentry->level_xvalue.is_terminal) {
1340 			mv_free(&pentry->level_xvalue.terminal_mlrval);
1341 		} else {
1342 			mlhmmv_level_free(pentry->level_xvalue.pnext_level);
1343 		}
1344 	}
1345 }
1346 
1347 // ================================================================
mlhmmv_root_alloc()1348 mlhmmv_root_t* mlhmmv_root_alloc() {
1349 	mlhmmv_root_t* pmap = mlr_malloc_or_die(sizeof(mlhmmv_root_t));
1350 	pmap->root_xvalue = mlhmmv_xvalue_alloc_empty_map();
1351 	return pmap;
1352 }
1353 
1354 // ----------------------------------------------------------------
mlhmmv_root_free(mlhmmv_root_t * pmap)1355 void mlhmmv_root_free(mlhmmv_root_t* pmap) {
1356 	if (pmap == NULL)
1357 		return;
1358 	mlhmmv_level_free(pmap->root_xvalue.pnext_level);
1359 	free(pmap);
1360 }
1361 
1362 // ----------------------------------------------------------------
mlhmmv_root_clear(mlhmmv_root_t * pmap)1363 void mlhmmv_root_clear(mlhmmv_root_t* pmap) {
1364 	mlhmmv_level_clear(pmap->root_xvalue.pnext_level);
1365 }
1366 
1367 // ----------------------------------------------------------------
mlhmmv_root_look_up_and_ref_terminal(mlhmmv_root_t * pmap,sllmv_t * pmvkeys,int * perror)1368 mv_t* mlhmmv_root_look_up_and_ref_terminal(mlhmmv_root_t* pmap, sllmv_t* pmvkeys, int* perror) {
1369 	mlhmmv_level_entry_t* plevel_entry = mlhmmv_level_look_up_and_ref_entry(pmap->root_xvalue.pnext_level,
1370 		pmvkeys->phead, perror);
1371 	if (plevel_entry == NULL) {
1372 		return NULL;
1373 	}
1374 	if (!plevel_entry->level_xvalue.is_terminal) {
1375 		*perror = MLHMMV_ERROR_KEYLIST_TOO_SHALLOW;
1376 		return NULL;
1377 	}
1378 	return &plevel_entry->level_xvalue.terminal_mlrval;
1379 }
1380 
1381 // ----------------------------------------------------------------
1382 // Example on recursive calls:
1383 // * level = map, rest_keys = ["a", 2, "c"]
1384 // * level = map["a"], rest_keys = [2, "c"]
1385 // * level = map["a"][2], rest_keys = ["c"]
mlhmmv_root_look_up_or_create_then_ref_level(mlhmmv_root_t * pmap,sllmv_t * pmvkeys)1386 mlhmmv_level_t* mlhmmv_root_look_up_or_create_then_ref_level(mlhmmv_root_t* pmap, sllmv_t* pmvkeys) {
1387 	return mlhmmv_level_ref_or_create(pmap->root_xvalue.pnext_level, pmvkeys->phead);
1388 }
1389 
1390 // ----------------------------------------------------------------
1391 // Example: keys = ["a", 2, "c"] and value = 4.
mlhmmv_root_put_terminal(mlhmmv_root_t * pmap,sllmv_t * pmvkeys,mv_t * pterminal_value)1392 void mlhmmv_root_put_terminal(mlhmmv_root_t* pmap, sllmv_t* pmvkeys, mv_t* pterminal_value) {
1393 	mlhmmv_level_put_terminal(pmap->root_xvalue.pnext_level, pmvkeys->phead, pterminal_value);
1394 }
1395 
1396 // ----------------------------------------------------------------
mlhmmv_root_put_xvalue(mlhmmv_root_t * pmap,sllmv_t * pmvkeys,mlhmmv_xvalue_t * pvalue)1397 static void mlhmmv_root_put_xvalue(mlhmmv_root_t* pmap, sllmv_t* pmvkeys, mlhmmv_xvalue_t* pvalue) {
1398 	mlhmmv_level_put_xvalue(pmap->root_xvalue.pnext_level, pmvkeys->phead, pvalue);
1399 }
1400 
1401 // ----------------------------------------------------------------
mlhmmv_root_copy_submap(mlhmmv_root_t * pmap,sllmv_t * ptokeys,sllmv_t * pfromkeys)1402 void mlhmmv_root_copy_submap(mlhmmv_root_t* pmap, sllmv_t* ptokeys, sllmv_t* pfromkeys) {
1403 	int error = 0;
1404 	mlhmmv_level_entry_t* pfromentry = mlhmmv_level_look_up_and_ref_entry(pmap->root_xvalue.pnext_level,
1405 		pfromkeys->phead, &error);
1406 	if (pfromentry != NULL) {
1407 		mlhmmv_xvalue_t submap = mlhmmv_xvalue_copy(&pfromentry->level_xvalue);
1408 		mlhmmv_root_put_xvalue(pmap, ptokeys, &submap);
1409 	}
1410 }
1411 
1412 // ----------------------------------------------------------------
mlhmmv_root_copy_keys_from_submap(mlhmmv_root_t * pmap,sllmv_t * pmvkeys)1413 sllv_t* mlhmmv_root_copy_keys_from_submap(mlhmmv_root_t* pmap, sllmv_t* pmvkeys) {
1414 	int error;
1415 	if (pmvkeys->length == 0) {
1416 		mlhmmv_xvalue_t root_value = (mlhmmv_xvalue_t) {
1417 			.is_terminal = FALSE,
1418 			.terminal_mlrval = mv_absent(),
1419 			.pnext_level = pmap->root_xvalue.pnext_level,
1420 		};
1421 		return mlhmmv_xvalue_copy_keys_nonindexed(&root_value);
1422 	} else {
1423 		mlhmmv_level_entry_t* pfromentry = mlhmmv_level_look_up_and_ref_entry(
1424 			pmap->root_xvalue.pnext_level, pmvkeys->phead, &error);
1425 		if (pfromentry != NULL) {
1426 			return mlhmmv_xvalue_copy_keys_nonindexed(&pfromentry->level_xvalue);
1427 		} else {
1428 			return sllv_alloc();
1429 		}
1430 	}
1431 }
1432 
1433 // ----------------------------------------------------------------
1434 // Removes entries from a specified level downward, unsetting any maps which become empty as a result.  For example, if
1435 // e.g. a=>b=>c=>4 and the c level is to be removed, then all up-nodes are emptied out & should be pruned.
1436 // * If restkeys too long (e.g. 'unset $a["b"]["c"]' with data "a":"b":3): do nothing.
1437 // * If restkeys just right: (e.g. 'unset $a["b"]' with data "a":"b":3) remove the terminal mlrval.
1438 // * If restkeys is too short: (e.g. 'unset $a["b"]' with data "a":"b":"c":4): remove the level and all below.
1439 
mlhmmv_root_remove(mlhmmv_root_t * pmap,sllmv_t * prestkeys)1440 void mlhmmv_root_remove(mlhmmv_root_t* pmap, sllmv_t* prestkeys) {
1441 	if (prestkeys == NULL) {
1442 		return;
1443 	} else if (prestkeys->phead == NULL) {
1444 		mlhmmv_level_free(pmap->root_xvalue.pnext_level);
1445 		pmap->root_xvalue.pnext_level = mlhmmv_level_alloc();
1446 		return;
1447 	} else {
1448 		mlhmmv_level_remove(pmap->root_xvalue.pnext_level, prestkeys->phead);
1449 	}
1450 }
1451 
1452 // ----------------------------------------------------------------
1453 // For 'emit all' and 'emitp all'.
mlhmmv_root_all_to_lrecs(mlhmmv_root_t * pmap,sllmv_t * pnames,sllv_t * poutrecs,int do_full_prefixing,char * flatten_separator)1454 void mlhmmv_root_all_to_lrecs(mlhmmv_root_t* pmap, sllmv_t* pnames, sllv_t* poutrecs, int do_full_prefixing,
1455 	char* flatten_separator)
1456 {
1457 	for (mlhmmv_level_entry_t* pentry = pmap->root_xvalue.pnext_level->phead; pentry != NULL; pentry = pentry->pnext) {
1458 		sllmv_t* pkey = sllmv_single_no_free(&pentry->level_key);
1459 		mlhmmv_root_partial_to_lrecs(pmap, pkey, pnames, poutrecs, do_full_prefixing, flatten_separator);
1460 		sllmv_free(pkey);
1461 	}
1462 }
1463 
1464 // ----------------------------------------------------------------
1465 // For 'emit' and 'emitp': the latter has do_full_prefixing == TRUE.  These allocate lrecs, appended to the poutrecs
1466 // list.
1467 
1468 // * pmap is the base-level oosvar multi-level hashmap.
1469 // * pkeys specify the level in the mlhmmv at which to produce data.
1470 // * pnames is used to pull subsequent-level keys out into separate fields.
1471 // * In case pnames isn't long enough to reach a terminal mlrval level in the mlhmmv,
1472 //   do_full_prefixing specifies whether to concatenate nested mlhmmv keys into single lrec keys.
1473 //
1474 // Examples:
1475 
1476 // * pkeys reaches a terminal level:
1477 //
1478 //   $ mlr --opprint put -q '@sum += $x; end { emit @sum }' ../data/small
1479 //   sum
1480 //   4.536294
1481 
1482 // * pkeys reaches terminal levels:
1483 //
1484 //   $ mlr --opprint put -q '@sum[$a][$b] += $x; end { emit @sum, "a", "b" }' ../data/small
1485 //   a   b   sum
1486 //   pan pan 0.346790
1487 //   pan wye 0.502626
1488 //   eks pan 0.758680
1489 //   eks wye 0.381399
1490 //   eks zee 0.611784
1491 //   wye wye 0.204603
1492 //   wye pan 0.573289
1493 //   zee pan 0.527126
1494 //   zee wye 0.598554
1495 //   hat wye 0.031442
1496 
1497 // * pkeys reaches non-terminal levels: non-prefixed:
1498 //
1499 //   $ mlr --opprint put -q '@sum[$a][$b] += $x; end { emit @sum, "a" }' ../data/small
1500 //   a   pan      wye
1501 //   pan 0.346790 0.502626
1502 //
1503 //   a   pan      wye      zee
1504 //   eks 0.758680 0.381399 0.611784
1505 //
1506 //   a   wye      pan
1507 //   wye 0.204603 0.573289
1508 //
1509 //   a   pan      wye
1510 //   zee 0.527126 0.598554
1511 //
1512 //   a   wye
1513 //   hat 0.031442
1514 
1515 // * pkeys reaches non-terminal levels: prefixed:
1516 //
1517 //   $ mlr --opprint put -q '@sum[$a][$b] += $x; end { emitp @sum, "a" }' ../data/small
1518 //   a   sum:pan  sum:wye
1519 //   pan 0.346790 0.502626
1520 //
1521 //   a   sum:pan  sum:wye  sum:zee
1522 //   eks 0.758680 0.381399 0.611784
1523 //
1524 //   a   sum:wye  sum:pan
1525 //   wye 0.204603 0.573289
1526 //
1527 //   a   sum:pan  sum:wye
1528 //   zee 0.527126 0.598554
1529 //
1530 //   a   sum:wye
1531 //   hat 0.031442
1532 
mlhmmv_root_partial_to_lrecs(mlhmmv_root_t * pmap,sllmv_t * pkeys,sllmv_t * pnames,sllv_t * poutrecs,int do_full_prefixing,char * flatten_separator)1533 void mlhmmv_root_partial_to_lrecs(mlhmmv_root_t* pmap, sllmv_t* pkeys, sllmv_t* pnames, sllv_t* poutrecs,
1534 	int do_full_prefixing, char* flatten_separator)
1535 {
1536 	// There should be at least the oosvar basename, e.g. '@a[b][c]' or '@a[b]' or '@a' but not '@'.
1537 	MLR_INTERNAL_CODING_ERROR_IF(pkeys == NULL);
1538 	MLR_INTERNAL_CODING_ERROR_IF(pkeys->phead == NULL);
1539 
1540 	mlhmmv_level_to_lrecs(pmap->root_xvalue.pnext_level, pkeys, pnames, poutrecs, do_full_prefixing,
1541 		flatten_separator);
1542 }
1543 
1544 // ----------------------------------------------------------------
1545 // This is simply JSON. Example output:
1546 // {
1547 //   "0":  {
1548 //     "fghij":  {
1549 //       "0":  17
1550 //     }
1551 //   },
1552 //   "3":  4,
1553 //   "abcde":  {
1554 //     "-6":  7
1555 //   }
1556 // }
1557 
mlhmmv_root_print_json_stacked(mlhmmv_root_t * pmap,int quote_keys_always,int quote_values_always,char * line_indent,char * line_term,FILE * ostream)1558 void mlhmmv_root_print_json_stacked(mlhmmv_root_t* pmap, int quote_keys_always, int quote_values_always,
1559 	char* line_indent, char* line_term, FILE* ostream)
1560 {
1561 	mlhmmv_level_print_stacked(pmap->root_xvalue.pnext_level, 0, FALSE, quote_keys_always,
1562 		quote_values_always, line_indent, line_term, ostream);
1563 }
1564 
1565 // ----------------------------------------------------------------
mlhmmv_root_print_json_single_lines(mlhmmv_root_t * pmap,int quote_keys_always,int quote_values_always,char * line_term,FILE * ostream)1566 void mlhmmv_root_print_json_single_lines(mlhmmv_root_t* pmap, int quote_keys_always, int quote_values_always,
1567 	char* line_term, FILE* ostream)
1568 {
1569 	mlhmmv_level_print_single_line(pmap->root_xvalue.pnext_level, 0, FALSE, quote_keys_always,
1570 		quote_values_always, ostream);
1571 	fprintf(ostream, "%s", line_term);
1572 }
1573 
1574 // Used for emit of localvars. Puts the xvalue in a single-key-value-pair map
1575 // keyed by the specified name. The xvalue is referenced, not copied.
mlhmmv_wrap_name_and_xvalue(mv_t * pname,mlhmmv_xvalue_t * pxval)1576 mlhmmv_root_t* mlhmmv_wrap_name_and_xvalue(mv_t* pname, mlhmmv_xvalue_t* pxval) {
1577 	mlhmmv_root_t* pmap = mlhmmv_root_alloc();
1578 	mlhmmv_level_put_xvalue_singly_keyed(pmap->root_xvalue.pnext_level, pname, pxval);
1579 	return pmap;
1580 }
1581 
1582 // Used for takedown of the temporary map returned by mlhmmv_wrap_name_and_xvalue. Since the xvalue there
1583 // is referenced, not copied, mlhmmv_xvalue_free would prematurely free the xvalue. This method releases
1584 // the xvalue so that the remaining, map-internal structures can be freed correctly.
mlhmmv_unwrap_name_and_xvalue(mlhmmv_root_t * pmap)1585 void mlhmmv_unwrap_name_and_xvalue(mlhmmv_root_t* pmap)
1586 {
1587 	mlhmmv_level_t* plevel = pmap->root_xvalue.pnext_level;
1588 	mlhmmv_level_entry_t* pentry = plevel->phead;
1589 	mv_free(&pentry->level_key);
1590 	plevel->phead = NULL;
1591 	plevel->ptail = NULL;
1592 	plevel->num_occupied = 0;
1593 	mlhmmv_root_free(pmap);
1594 }
1595