1 /********************************************************************/
2 /* */
3 /* hsh_rtl.c Primitive actions for the hash map type. */
4 /* Copyright (C) 1989 - 2016, 2018 Thomas Mertes */
5 /* */
6 /* This file is part of the Seed7 Runtime Library. */
7 /* */
8 /* The Seed7 Runtime Library is free software; you can */
9 /* redistribute it and/or modify it under the terms of the GNU */
10 /* Lesser General Public License as published by the Free Software */
11 /* Foundation; either version 2.1 of the License, or (at your */
12 /* option) any later version. */
13 /* */
14 /* The Seed7 Runtime Library is distributed in the hope that it */
15 /* will be useful, but WITHOUT ANY WARRANTY; without even the */
16 /* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR */
17 /* PURPOSE. See the GNU Lesser General Public License for more */
18 /* details. */
19 /* */
20 /* You should have received a copy of the GNU Lesser General */
21 /* Public License along with this program; if not, write to the */
22 /* Free Software Foundation, Inc., 51 Franklin Street, */
23 /* Fifth Floor, Boston, MA 02110-1301, USA. */
24 /* */
25 /* Module: Seed7 Runtime Library */
26 /* File: seed7/src/hsh_rtl.c */
27 /* Changes: 2005, 2006, 2007, 2013, 2016 Thomas Mertes */
28 /* Content: Primitive actions for the hash map type. */
29 /* */
30 /* The functions from this file should only be used in compiled */
31 /* Seed7 programs. The interpreter should not use functions of */
32 /* this file. */
33 /* */
34 /* The functions in this file use type declarations from the */
35 /* include file data_rtl.h instead of data.h. Therefore the types */
36 /* rtlHashElemType and rtlHashType are declared different than the */
37 /* types hashElemType and hashType in the interpreter. */
38 /* */
39 /********************************************************************/
40
41 #define LOG_FUNCTIONS 0
42 #define VERBOSE_EXCEPTIONS 0
43
44 #include "version.h"
45
46 #include "stdlib.h"
47 #include "stdio.h"
48 #include "string.h"
49
50 #include "common.h"
51 #include "data_rtl.h"
52 #include "heaputl.h"
53 #include "striutl.h"
54 #include "rtl_err.h"
55 #include "int_rtl.h"
56
57 #undef EXTERN
58 #define EXTERN
59 #include "hsh_rtl.h"
60
61
62 #define TABLE_BITS 10
63 #define TABLE_SIZE(bits) ((unsigned int) 1 << (bits))
64 #define TABLE_MASK(bits) (TABLE_SIZE(bits)-1)
65
66
67
free_helem(const const_rtlHashElemType old_helem,const destrFuncType key_destr_func,const destrFuncType data_destr_func)68 static memSizeType free_helem (const const_rtlHashElemType old_helem,
69 const destrFuncType key_destr_func, const destrFuncType data_destr_func)
70
71 {
72 memSizeType freed = 1;
73
74 /* free_helem */
75 key_destr_func(old_helem->key.value.genericValue);
76 data_destr_func(old_helem->data.value.genericValue);
77 if (old_helem->next_less != NULL) {
78 freed += free_helem(old_helem->next_less, key_destr_func,
79 data_destr_func);
80 } /* if */
81 if (old_helem->next_greater != NULL) {
82 freed += free_helem(old_helem->next_greater, key_destr_func,
83 data_destr_func);
84 } /* if */
85 FREE_RECORD(old_helem, rtlHashElemRecord, count.rtl_helem);
86 return freed;
87 } /* free_helem */
88
89
90
free_hash(const const_rtlHashType old_hash,const destrFuncType key_destr_func,const destrFuncType data_destr_func)91 static void free_hash (const const_rtlHashType old_hash,
92 const destrFuncType key_destr_func, const destrFuncType data_destr_func)
93
94 {
95 memSizeType to_free;
96 unsigned int number;
97 const rtlHashElemType *table;
98
99 /* free_hash */
100 if (old_hash != NULL) {
101 to_free = old_hash->size;
102 if (to_free != 0) {
103 number = old_hash->table_size;
104 table = old_hash->table;
105 do {
106 do {
107 number--;
108 } while (table[number] == NULL);
109 to_free -= free_helem(table[number], key_destr_func, data_destr_func);
110 } while (to_free != 0);
111 } /* if */
112 FREE_RTL_HASH(old_hash, old_hash->table_size);
113 } /* if */
114 } /* free_hash */
115
116
117
new_helem(genericType key,genericType data,const createFuncType key_create_func,const createFuncType data_create_func,errInfoType * err_info)118 static rtlHashElemType new_helem (genericType key, genericType data,
119 const createFuncType key_create_func, const createFuncType data_create_func,
120 errInfoType *err_info)
121
122 {
123 rtlHashElemType helem;
124
125 /* new_helem */
126 /* printf("new_helem(" FMT_U_GEN ", " FMT_U_GEN ")\n", key, data); */
127 if (unlikely(!ALLOC_RECORD(helem, rtlHashElemRecord, count.rtl_helem))) {
128 *err_info = MEMORY_ERROR;
129 } else {
130 helem->key.value.genericValue = key_create_func(key);
131 helem->data.value.genericValue = data_create_func(data);
132 helem->next_less = NULL;
133 helem->next_greater = NULL;
134 /* printf("new_helem(" FMT_U_GEN ", " FMT_U_GEN ")\n",
135 helem->key.value.genericValue,
136 helem->data.value.genericValue); */
137 } /* if */
138 return helem;
139 } /* new_helem */
140
141
142
new_hash(unsigned int bits)143 static rtlHashType new_hash (unsigned int bits)
144
145 {
146 rtlHashType hash;
147
148 /* new_hash */
149 if (likely(ALLOC_RTL_HASH(hash, TABLE_SIZE(bits)))) {
150 hash->bits = bits;
151 hash->mask = TABLE_MASK(bits);
152 hash->table_size = TABLE_SIZE(bits);
153 hash->size = 0;
154 memset(hash->table, 0, hash->table_size * sizeof(rtlHashElemType));
155 } /* if */
156 return hash;
157 } /* new_hash */
158
159
160
create_helem(const const_rtlHashElemType source_helem,const createFuncType key_create_func,const createFuncType data_create_func,errInfoType * err_info)161 static rtlHashElemType create_helem (const const_rtlHashElemType source_helem,
162 const createFuncType key_create_func, const createFuncType data_create_func,
163 errInfoType *err_info)
164
165 {
166 rtlHashElemType dest_helem;
167
168 /* create_helem */
169 if (unlikely(!ALLOC_RECORD(dest_helem, rtlHashElemRecord, count.rtl_helem))) {
170 *err_info = MEMORY_ERROR;
171 } else {
172 dest_helem->key.value.genericValue =
173 key_create_func(source_helem->key.value.genericValue);
174 dest_helem->data.value.genericValue =
175 data_create_func(source_helem->data.value.genericValue);
176 if (source_helem->next_less != NULL) {
177 dest_helem->next_less = create_helem(source_helem->next_less,
178 key_create_func, data_create_func, err_info);
179 } else {
180 dest_helem->next_less = NULL;
181 } /* if */
182 if (source_helem->next_greater != NULL) {
183 dest_helem->next_greater = create_helem(source_helem->next_greater,
184 key_create_func, data_create_func, err_info);
185 } else {
186 dest_helem->next_greater = NULL;
187 } /* if */
188 } /* if */
189 return dest_helem;
190 } /* create_helem */
191
192
193
create_hash(const const_rtlHashType source_hash,const createFuncType key_create_func,const createFuncType data_create_func,errInfoType * err_info)194 static rtlHashType create_hash (const const_rtlHashType source_hash,
195 const createFuncType key_create_func, const createFuncType data_create_func,
196 errInfoType *err_info)
197
198 {
199 unsigned int table_size;
200 unsigned int number;
201 const rtlHashElemType *source_helem;
202 rtlHashElemType *dest_helem;
203 rtlHashType dest_hash;
204
205 /* create_hash */
206 table_size = source_hash->table_size;
207 if (unlikely(!ALLOC_RTL_HASH(dest_hash, table_size))) {
208 *err_info = MEMORY_ERROR;
209 } else {
210 dest_hash->bits = source_hash->bits;
211 dest_hash->mask = source_hash->mask;
212 dest_hash->table_size = table_size;
213 dest_hash->size = source_hash->size;
214 if (source_hash->size == 0) {
215 memset(dest_hash->table, 0, table_size * sizeof(rtlHashElemType));
216 } else {
217 number = table_size;
218 source_helem = &source_hash->table[0];
219 dest_helem = &dest_hash->table[0];
220 while (number > 0) {
221 while (number > 0 && *source_helem == NULL) {
222 *dest_helem = NULL;
223 number--;
224 source_helem++;
225 dest_helem++;
226 } /* while */
227 if (number > 0 && *source_helem != NULL) {
228 *dest_helem = create_helem(*source_helem, key_create_func,
229 data_create_func, err_info);
230 number--;
231 source_helem++;
232 dest_helem++;
233 } /* if */
234 } /* while */
235 } /* if */
236 } /* if */
237 return dest_hash;
238 } /* create_hash */
239
240
241
copy_hash(const rtlHashType dest_hash,const const_rtlHashType source_hash,const createFuncType key_create_func,const createFuncType data_create_func,const destrFuncType key_destr_func,const destrFuncType data_destr_func,errInfoType * err_info)242 static void copy_hash (const rtlHashType dest_hash, const const_rtlHashType source_hash,
243 const createFuncType key_create_func, const createFuncType data_create_func,
244 const destrFuncType key_destr_func, const destrFuncType data_destr_func,
245 errInfoType *err_info)
246
247 {
248 unsigned int number;
249 const rtlHashElemType *source_helem;
250 rtlHashElemType *dest_helem;
251
252 /* copy_hash */
253 logFunction(printf("copy_hash(" FMT_X_MEM ", " FMT_X_MEM ")\n",
254 (memSizeType) dest_hash, (memSizeType) source_hash););
255 dest_hash->bits = source_hash->bits;
256 dest_hash->mask = source_hash->mask;
257 dest_hash->size = source_hash->size;
258 number = source_hash->table_size;
259 source_helem = &source_hash->table[0];
260 dest_helem = &dest_hash->table[0];
261 while (number > 0 && *err_info == OKAY_NO_ERROR) {
262 if (*dest_helem != NULL) {
263 free_helem(*dest_helem, key_destr_func, data_destr_func);
264 } /* if */
265 if (*source_helem != NULL) {
266 *dest_helem = create_helem(*source_helem, key_create_func, data_create_func,
267 err_info);
268 } else {
269 *dest_helem = NULL;
270 } /* if */
271 number--;
272 source_helem++;
273 dest_helem++;
274 } /* while */
275 logFunction(printf("copy_hash -->\n"););
276 } /* copy_hash */
277
278
279
keys_helem(const rtlArrayType key_array,memSizeType arr_pos,const_rtlHashElemType curr_helem,const createFuncType key_create_func)280 static memSizeType keys_helem (const rtlArrayType key_array,
281 memSizeType arr_pos, const_rtlHashElemType curr_helem,
282 const createFuncType key_create_func)
283
284 { /* keys_helem */
285 do {
286 arr_pos--;
287 key_array->arr[arr_pos].value.genericValue =
288 key_create_func(curr_helem->key.value.genericValue);
289 if (curr_helem->next_less != NULL) {
290 arr_pos = keys_helem(key_array, arr_pos, curr_helem->next_less,
291 key_create_func);
292 } /* if */
293 curr_helem = curr_helem->next_greater;
294 } while (curr_helem != NULL);
295 return arr_pos;
296 } /* keys_helem */
297
298
299
keys_hash(const const_rtlHashType curr_hash,const createFuncType key_create_func)300 static inline rtlArrayType keys_hash (const const_rtlHashType curr_hash,
301 const createFuncType key_create_func)
302
303 {
304 memSizeType arr_pos;
305 memSizeType number;
306 const rtlHashElemType *table;
307 rtlArrayType key_array;
308
309 /* keys_hash */
310 if (unlikely(curr_hash->size > INTTYPE_MAX ||
311 !ALLOC_RTL_ARRAY(key_array, curr_hash->size))) {
312 raise_error(MEMORY_ERROR);
313 key_array = NULL;
314 } else {
315 key_array->min_position = 1;
316 key_array->max_position = (intType) curr_hash->size;
317 if (curr_hash->size != 0) {
318 arr_pos = curr_hash->size;
319 number = curr_hash->table_size;
320 table = curr_hash->table;
321 do {
322 do {
323 number--;
324 } while (table[number] == NULL);
325 arr_pos = keys_helem(key_array, arr_pos, table[number],
326 key_create_func);
327 } while (arr_pos != 0);
328 } /* if */
329 } /* if */
330 return key_array;
331 } /* keys_hash */
332
333
334
values_helem(const rtlArrayType value_array,memSizeType arr_pos,const_rtlHashElemType curr_helem,const createFuncType value_create_func)335 static memSizeType values_helem (const rtlArrayType value_array,
336 memSizeType arr_pos, const_rtlHashElemType curr_helem,
337 const createFuncType value_create_func)
338
339 { /* values_helem */
340 do {
341 arr_pos--;
342 value_array->arr[arr_pos].value.genericValue =
343 value_create_func(curr_helem->data.value.genericValue);
344 if (curr_helem->next_less != NULL) {
345 arr_pos = values_helem(value_array, arr_pos, curr_helem->next_less,
346 value_create_func);
347 } /* if */
348 curr_helem = curr_helem->next_greater;
349 } while (curr_helem != NULL);
350 return arr_pos;
351 } /* values_helem */
352
353
354
values_hash(const const_rtlHashType curr_hash,const createFuncType value_create_func)355 static inline rtlArrayType values_hash (const const_rtlHashType curr_hash,
356 const createFuncType value_create_func)
357
358 {
359 memSizeType arr_pos;
360 memSizeType number;
361 const rtlHashElemType *table;
362 rtlArrayType value_array;
363
364 /* values_hash */
365 if (unlikely(curr_hash->size > INTTYPE_MAX ||
366 !ALLOC_RTL_ARRAY(value_array, curr_hash->size))) {
367 raise_error(MEMORY_ERROR);
368 value_array = NULL;
369 } else {
370 value_array->min_position = 1;
371 value_array->max_position = (intType) curr_hash->size;
372 if (curr_hash->size != 0) {
373 arr_pos = curr_hash->size;
374 number = curr_hash->table_size;
375 table = curr_hash->table;
376 do {
377 do {
378 number--;
379 } while (table[number] == NULL);
380 arr_pos = values_helem(value_array, arr_pos, table[number],
381 value_create_func);
382 } while (arr_pos != 0);
383 } /* if */
384 } /* if */
385 return value_array;
386 } /* values_hash */
387
388
389
get_helem_elem(const_rtlHashElemType * hash_elem,memSizeType arr_pos,const_rtlHashElemType curr_helem)390 static memSizeType get_helem_elem (const_rtlHashElemType *hash_elem,
391 memSizeType arr_pos, const_rtlHashElemType curr_helem)
392
393 { /* get_helem_elem */
394 do {
395 arr_pos--;
396 if (arr_pos == 0) {
397 *hash_elem = curr_helem;
398 } else {
399 if (curr_helem->next_less != NULL) {
400 arr_pos = get_helem_elem(hash_elem, arr_pos, curr_helem->next_less);
401 } /* if */
402 curr_helem = curr_helem->next_greater;
403 } /* if */
404 } while (curr_helem != NULL && arr_pos != 0);
405 return arr_pos;
406 } /* get_helem_elem */
407
408
409
get_hash_elem(const const_rtlHashType curr_hash,memSizeType arr_pos)410 static inline const_rtlHashElemType get_hash_elem (const const_rtlHashType curr_hash,
411 memSizeType arr_pos)
412
413 {
414 memSizeType number;
415 const rtlHashElemType *table;
416 const_rtlHashElemType hash_elem = NULL;
417
418 /* get_hash_elem */
419 if (arr_pos >= 1 && arr_pos <= curr_hash->size) {
420 number = curr_hash->table_size;
421 table = curr_hash->table;
422 do {
423 do {
424 number--;
425 } while (table[number] == NULL);
426 arr_pos = get_helem_elem(&hash_elem, arr_pos, table[number]);
427 } while (arr_pos != 0);
428 } /* if */
429 return hash_elem;
430 } /* get_hash_elem */
431
432
433
434 #ifdef OUT_OF_ORDER
dump_helem(const_rtlHashElemType curr_helem)435 static void dump_helem (const_rtlHashElemType curr_helem)
436
437 { /* dump_helem */
438 printf("key: %ld, %lx, %f / value: %ld, %lx, %f\n",
439 curr_helem->key.value.intValue,
440 curr_helem->key.value.genericValue,
441 curr_helem->key.value.floatValue,
442 curr_helem->data.value.intValue,
443 curr_helem->data.value.genericValue,
444 curr_helem->data.value.floatValue);
445 if (curr_helem->next_less != NULL) {
446 dump_helem(curr_helem->next_less);
447 } /* if */
448 if (curr_helem->next_greater != NULL) {
449 dump_helem(curr_helem->next_greater);
450 } /* if */
451 } /* dump_helem */
452
453
454
dump_hash(const const_rtlHashType curr_hash)455 static void dump_hash (const const_rtlHashType curr_hash)
456
457 {
458 memSizeType number;
459 const rtlHashElemType *curr_helem;
460
461 /* dump_hash */
462 number = curr_hash->table_size;
463 curr_helem = &curr_hash->table[0];
464 while (number > 0) {
465 if (*curr_helem != NULL) {
466 dump_helem(*curr_helem);
467 } /* if */
468 number--;
469 curr_helem++;
470 } /* while */
471 } /* dump_hash */
472 #endif
473
474
475
476 /**
477 * Hash membership test.
478 * Determine if 'aKey' is a member of the hash map 'aHashMap'.
479 * @return TRUE if 'aKey' is a member of 'aHashMap',
480 * FALSE otherwise.
481 */
hshContains(const const_rtlHashType aHashMap,const genericType aKey,intType hashcode,compareType cmp_func)482 boolType hshContains (const const_rtlHashType aHashMap, const genericType aKey,
483 intType hashcode, compareType cmp_func)
484
485 {
486 const_rtlHashElemType hashelem;
487 intType cmp;
488 boolType result = FALSE;
489
490 /* hshContains */
491 logFunction(printf("hshContains(" FMT_X_MEM ", " FMT_U_GEN ", " FMT_U ")\n",
492 (memSizeType) aHashMap, aKey, hashcode););
493 hashelem = aHashMap->table[(unsigned int) hashcode & aHashMap->mask];
494 while (hashelem != NULL) {
495 /*
496 printf("sizeof(hashelem->key.value.genericValue)=%lu\n",
497 sizeof(hashelem->key.value.genericValue));
498 printf("sizeof(aKey)=%lu\n", sizeof(aKey));
499 printf("%llX\n", hashelem->key.value.genericValue);
500 printf("%lX\n", (long unsigned) hashelem->key.value.genericValue);
501 printf("%llX\n", aKey);
502 printf("%lX\n", (long unsigned) aKey);
503 */
504 cmp = cmp_func(hashelem->key.value.genericValue, aKey);
505 if (cmp < 0) {
506 hashelem = hashelem->next_less;
507 } else if (unlikely(cmp == 0)) {
508 result = TRUE;
509 hashelem = NULL;
510 } else {
511 hashelem = hashelem->next_greater;
512 } /* if */
513 } /* while */
514 logFunction(printf("hshContains(" FMT_X_MEM ", " FMT_U_GEN ", " FMT_U ") --> %d\n",
515 (memSizeType) aHashMap, aKey, hashcode, result););
516 return result;
517 } /* hshContains */
518
519
520
521 /**
522 * Assign source to *dest.
523 * A copy function assumes that *dest contains a legal value.
524 * @exception MEMORY_ERROR Not enough memory to create dest.
525 */
hshCpy(rtlHashType * const dest,const const_rtlHashType source,const createFuncType key_create_func,const destrFuncType key_destr_func,const createFuncType data_create_func,const destrFuncType data_destr_func)526 void hshCpy (rtlHashType *const dest, const const_rtlHashType source,
527 const createFuncType key_create_func, const destrFuncType key_destr_func,
528 const createFuncType data_create_func, const destrFuncType data_destr_func)
529
530 {
531 errInfoType err_info = OKAY_NO_ERROR;
532
533 /* hshCpy */
534 logFunction(printf("hshCpy(" FMT_X_MEM ", " FMT_X_MEM ")\n",
535 (memSizeType) *dest, (memSizeType) source););
536 if ((*dest)->table_size == source->table_size) {
537 /* The following check avoids an error for: aHash := aHash; */
538 if (*dest != source) {
539 copy_hash(*dest, source,
540 key_create_func, data_create_func,
541 key_destr_func, data_destr_func, &err_info);
542 } /* if */
543 } else {
544 free_hash(*dest, key_destr_func, data_destr_func);
545 *dest = create_hash(source,
546 key_create_func, data_create_func, &err_info);
547 } /* if */
548 if (unlikely(err_info != OKAY_NO_ERROR)) {
549 free_hash(*dest, key_destr_func, data_destr_func);
550 *dest = NULL;
551 raise_error(MEMORY_ERROR);
552 } /* if */
553 logFunction(printf("hshCpy -->\n"););
554 } /* hshCpy */
555
556
557
558 /**
559 * Return a copy of source, that can be assigned to a new destination.
560 * It is assumed that the destination of the assignment is undefined.
561 * Create functions can be used to initialize Seed7 constants.
562 * @return a copy of source.
563 * @exception MEMORY_ERROR Not enough memory to represent the result.
564 */
hshCreate(const const_rtlHashType source,const createFuncType key_create_func,const destrFuncType key_destr_func,const createFuncType data_create_func,const destrFuncType data_destr_func)565 rtlHashType hshCreate (const const_rtlHashType source,
566 const createFuncType key_create_func, const destrFuncType key_destr_func,
567 const createFuncType data_create_func, const destrFuncType data_destr_func)
568
569 {
570 errInfoType err_info = OKAY_NO_ERROR;
571 rtlHashType result;
572
573 /* hshCreate */
574 result = create_hash(source,
575 key_create_func, data_create_func, &err_info);
576 if (unlikely(err_info != OKAY_NO_ERROR)) {
577 free_hash(result, key_destr_func, data_destr_func);
578 result = NULL;
579 raise_error(MEMORY_ERROR);
580 } /* if */
581 return result;
582 } /* hshCreate */
583
584
585
586 /**
587 * Free the memory referred by 'old_hash'.
588 * After hshDestr is left 'old_hash' refers to not existing memory.
589 * The memory where 'old_hash' is stored can be freed afterwards.
590 */
hshDestr(const const_rtlHashType old_hash,const destrFuncType key_destr_func,const destrFuncType data_destr_func)591 void hshDestr (const const_rtlHashType old_hash, const destrFuncType key_destr_func,
592 const destrFuncType data_destr_func)
593
594 { /* hshDestr */
595 logFunction(printf("hshDestr(" FMT_X_MEM ")\n", (memSizeType) old_hash););
596 free_hash(old_hash, key_destr_func, data_destr_func);
597 logFunction(printf("hshDestr -->\n"););
598 } /* hshDestr */
599
600
601
602 /**
603 * Create an empty hash table.
604 * @return an empty hash table.
605 * @exception MEMORY_ERROR Not enough memory for the result.
606 */
hshEmpty(void)607 rtlHashType hshEmpty (void)
608
609 {
610 rtlHashType result;
611
612 /* hshEmpty */
613 result = new_hash(TABLE_BITS);
614 if (unlikely(result == NULL)) {
615 raise_error(MEMORY_ERROR);
616 } /* if */
617 return result;
618 } /* hshEmpty */
619
620
621
622 /**
623 * Remove the element with the key 'aKey' from the hash map 'aHashMap'.
624 */
hshExcl(const rtlHashType aHashMap,const genericType aKey,intType hashcode,compareType cmp_func,const destrFuncType key_destr_func,const destrFuncType data_destr_func)625 void hshExcl (const rtlHashType aHashMap, const genericType aKey,
626 intType hashcode, compareType cmp_func, const destrFuncType key_destr_func,
627 const destrFuncType data_destr_func)
628
629 {
630 rtlHashElemType *delete_pos;
631 rtlHashElemType hashelem;
632 rtlHashElemType greater_hashelems;
633 rtlHashElemType old_hashelem;
634 intType cmp;
635
636 /* hshExcl */
637 logFunction(printf("hshExcl(" FMT_X_MEM ", " FMT_U_GEN ", "
638 FMT_U ") size=" FMT_U_MEM "\n",
639 (memSizeType) aHashMap, aKey, hashcode, aHashMap->size););
640 delete_pos = &aHashMap->table[(unsigned int) hashcode & aHashMap->mask];
641 hashelem = aHashMap->table[(unsigned int) hashcode & aHashMap->mask];
642 while (hashelem != NULL) {
643 cmp = cmp_func(hashelem->key.value.genericValue, aKey);
644 if (cmp < 0) {
645 delete_pos = &hashelem->next_less;
646 hashelem = hashelem->next_less;
647 } else if (unlikely(cmp == 0)) {
648 old_hashelem = hashelem;
649 if (hashelem->next_less == NULL) {
650 *delete_pos = hashelem->next_greater;
651 } else if (hashelem->next_greater == NULL) {
652 *delete_pos = hashelem->next_less;
653 } else {
654 *delete_pos = hashelem->next_less;
655 greater_hashelems = hashelem->next_greater;
656 hashelem = hashelem->next_less;
657 while (hashelem->next_greater != NULL) {
658 hashelem = hashelem->next_greater;
659 } /* while */
660 hashelem->next_greater = greater_hashelems;
661 } /* if */
662 old_hashelem->next_less = NULL;
663 old_hashelem->next_greater = NULL;
664 free_helem(old_hashelem, key_destr_func, data_destr_func);
665 aHashMap->size--;
666 hashelem = NULL;
667 } else {
668 delete_pos = &hashelem->next_greater;
669 hashelem = hashelem->next_greater;
670 } /* if */
671 } /* while */
672 logFunction(printf("hshExcl(" FMT_X_MEM ", " FMT_U_GEN ", "
673 FMT_U ") size=" FMT_U_MEM " -->\n",
674 (memSizeType) aHashMap, aKey, hashcode, aHashMap->size););
675 } /* hshExcl */
676
677
678
679 /**
680 * Access one value from the hash table 'aHashMap'.
681 * @return the element with the key 'aKey' from 'aHashMap'.
682 * @exception RANGE_ERROR If 'aHashMap' does not have an element
683 * with the key 'aKey'.
684 */
hshIdx(const const_rtlHashType aHashMap,const genericType aKey,intType hashcode,compareType cmp_func)685 genericType hshIdx (const const_rtlHashType aHashMap, const genericType aKey,
686 intType hashcode, compareType cmp_func)
687
688 {
689 rtlHashElemType hashelem;
690 rtlHashElemType result_hashelem = NULL;
691 intType cmp;
692 genericType result;
693
694 /* hshIdx */
695 logFunction(printf("hshIdx(" FMT_X_MEM ", " FMT_U_GEN ", " FMT_U ")\n",
696 (memSizeType) aHashMap, aKey, hashcode););
697 hashelem = aHashMap->table[(unsigned int) hashcode & aHashMap->mask];
698 while (hashelem != NULL) {
699 cmp = cmp_func(hashelem->key.value.genericValue, aKey);
700 if (cmp < 0) {
701 hashelem = hashelem->next_less;
702 } else if (unlikely(cmp == 0)) {
703 result_hashelem = hashelem;
704 hashelem = NULL;
705 } else {
706 hashelem = hashelem->next_greater;
707 } /* if */
708 } /* while */
709 if (unlikely(result_hashelem == NULL)) {
710 logError(printf("hshIdx(" FMT_X_MEM ", " FMT_U_GEN ", " FMT_U "): "
711 "Hashmap does not have an element with the key.\n",
712 (memSizeType) aHashMap, aKey, hashcode););
713 raise_error(RANGE_ERROR);
714 result = 0;
715 } else {
716 result = result_hashelem->data.value.genericValue;
717 } /* if */
718 logFunction(printf("hshIdx(" FMT_X_MEM ", " FMT_U_GEN ", "
719 FMT_U ") --> " FMT_X_GEN " (" FMT_X_GEN ")\n",
720 (memSizeType) aHashMap, aKey, hashcode, result,
721 (result != 0 ?
722 ((const_rtlObjectType *) &result)->value.genericValue :
723 (genericType) 0)););
724 return result;
725 } /* hshIdx */
726
727
728
729 /**
730 * Determine the address of a value from the hash table 'aHashMap'.
731 * @return the address of the element with the key 'aKey' from 'aHashMap'.
732 * @exception RANGE_ERROR If 'aHashMap' does not have an element
733 * with the key 'aKey'.
734 */
hshIdxAddr(const const_rtlHashType aHashMap,const genericType aKey,intType hashcode,compareType cmp_func)735 rtlObjectType *hshIdxAddr (const const_rtlHashType aHashMap,
736 const genericType aKey, intType hashcode, compareType cmp_func)
737
738 {
739 rtlHashElemType hashelem;
740 rtlHashElemType result_hashelem = NULL;
741 intType cmp;
742 rtlObjectType *result;
743
744 /* hshIdxAddr */
745 logFunction(printf("hshIdxAddr(" FMT_X_MEM ", " FMT_U_GEN ", " FMT_U ")\n",
746 (memSizeType) aHashMap, aKey, hashcode););
747 hashelem = aHashMap->table[(unsigned int) hashcode & aHashMap->mask];
748 while (hashelem != NULL) {
749 cmp = cmp_func(hashelem->key.value.genericValue, aKey);
750 /* printf(". %llu %llu cmp=%d\n",
751 (unsigned long long) hashelem->key.value.genericValue,
752 (unsigned long long) aKey, cmp); */
753 if (cmp < 0) {
754 hashelem = hashelem->next_less;
755 } else if (unlikely(cmp == 0)) {
756 result_hashelem = hashelem;
757 hashelem = NULL;
758 } else {
759 hashelem = hashelem->next_greater;
760 } /* if */
761 } /* while */
762 if (unlikely(result_hashelem == NULL)) {
763 logError(printf("hshIdxAddr(" FMT_X_MEM ", " FMT_U_GEN ", " FMT_U "): "
764 "Hashmap does not have an element with the key.\n",
765 (memSizeType) aHashMap, aKey, hashcode););
766 raise_error(RANGE_ERROR);
767 result = NULL;
768 } else {
769 result = &result_hashelem->data;
770 } /* if */
771 logFunction(printf("hshIdxAddr(" FMT_X_MEM ", " FMT_U_GEN ", "
772 FMT_U ") --> " FMT_U_MEM " (" FMT_X_GEN ", %f)\n",
773 (memSizeType) aHashMap, aKey, hashcode, (memSizeType) result,
774 result != NULL ? result->value.genericValue : (genericType) 0,
775 result != NULL ? result->value.floatValue : 0.0););
776 return result;
777 } /* hshIdxAddr */
778
779
780
781 /**
782 * Determine the address of a value from the hash table 'aHashMap'.
783 * @return the address of the element with the key 'aKey' from 'aHashMap' or
784 * NULL if 'aHashMap' does not have an element with the key 'aKey'.
785 */
hshIdxAddr2(const const_rtlHashType aHashMap,const genericType aKey,intType hashcode,compareType cmp_func)786 rtlObjectType *hshIdxAddr2 (const const_rtlHashType aHashMap,
787 const genericType aKey, intType hashcode, compareType cmp_func)
788
789 {
790 rtlHashElemType hashelem;
791 rtlHashElemType result_hashelem = NULL;
792 intType cmp;
793 rtlObjectType *result;
794
795 /* hshIdxAddr2 */
796 logFunction(printf("hshIdxAddr2(" FMT_X_MEM ", " FMT_U_GEN ", " FMT_U ")\n",
797 (memSizeType) aHashMap, aKey, hashcode););
798 hashelem = aHashMap->table[(unsigned int) hashcode & aHashMap->mask];
799 while (hashelem != NULL) {
800 cmp = cmp_func(hashelem->key.value.genericValue, aKey);
801 /* printf(". %llu %llu cmp=%d\n",
802 (unsigned long long) hashelem->key.value.genericValue,
803 (unsigned long long) aKey, cmp); */
804 if (cmp < 0) {
805 hashelem = hashelem->next_less;
806 } else if (unlikely(cmp == 0)) {
807 result_hashelem = hashelem;
808 hashelem = NULL;
809 } else {
810 hashelem = hashelem->next_greater;
811 } /* if */
812 } /* while */
813 if (result_hashelem != NULL) {
814 result = &result_hashelem->data;
815 } else {
816 result = NULL;
817 } /* if */
818 logFunction(printf("hshIdxAddr2(" FMT_X_MEM ", " FMT_U_GEN ", "
819 FMT_U ") --> " FMT_U_MEM " (" FMT_X_GEN ", %f)\n",
820 (memSizeType) aHashMap, aKey, hashcode, (memSizeType) result,
821 result != NULL ? result->value.genericValue : (genericType) 0,
822 result != NULL ? result->value.floatValue : 0.0););
823 return result;
824 } /* hshIdxAddr2 */
825
826
827
828 /**
829 * Search for 'aKey' in 'aHashMap'.
830 * If 'aKey' is element of 'aHashMap' the corresponding value is returned.
831 * If 'aKey' is not element of 'aHashMap' then 'defaultData' is stored
832 * as value of 'aKey' in 'aHashMap' and 'defaultData' is returned.
833 * @return the value stored for 'aKey' in 'aHashMap', or
834 * 'defaultData', if 'aKey' is not a member of 'aHashMap'.
835 */
hshIdxEnterDefault(const rtlHashType aHashMap,const genericType aKey,const genericType defaultData,intType hashcode)836 genericType hshIdxEnterDefault (const rtlHashType aHashMap,
837 const genericType aKey, const genericType defaultData, intType hashcode)
838
839 {
840 rtlHashElemType hashelem;
841 rtlHashElemType result_hashelem;
842 errInfoType err_info = OKAY_NO_ERROR;
843 genericType result;
844
845 /* hshIdxEnterDefault */
846 logFunction(printf("hshIdxEnterDefault(" FMT_X_MEM ", " FMT_U_GEN ", "
847 FMT_U_GEN ", " FMT_U ")\n",
848 (memSizeType) aHashMap, aKey, defaultData, hashcode););
849 hashelem = aHashMap->table[(unsigned int) hashcode & aHashMap->mask];
850 if (hashelem == NULL) {
851 result_hashelem = new_helem(aKey, defaultData,
852 (createFuncType) &genericCreate,
853 (createFuncType) &genericCreate, &err_info);
854 aHashMap->table[(unsigned int) hashcode & aHashMap->mask] = result_hashelem;
855 aHashMap->size++;
856 } else {
857 do {
858 /* printf("key=%llX\n", hashelem->key.value.genericValue); */
859 if (hashelem->key.value.genericValue < aKey) {
860 if (hashelem->next_less == NULL) {
861 result_hashelem = new_helem(aKey, defaultData,
862 (createFuncType) &genericCreate,
863 (createFuncType) &genericCreate, &err_info);
864 hashelem->next_less = result_hashelem;
865 aHashMap->size++;
866 hashelem = NULL;
867 } else {
868 hashelem = hashelem->next_less;
869 } /* if */
870 } else if (unlikely(hashelem->key.value.genericValue == aKey)) {
871 result_hashelem = hashelem;
872 hashelem = NULL;
873 } else {
874 if (hashelem->next_greater == NULL) {
875 result_hashelem = new_helem(aKey, defaultData,
876 (createFuncType) &genericCreate,
877 (createFuncType) &genericCreate, &err_info);
878 hashelem->next_greater = result_hashelem;
879 aHashMap->size++;
880 hashelem = NULL;
881 } else {
882 hashelem = hashelem->next_greater;
883 } /* if */
884 } /* if */
885 } while (hashelem != NULL);
886 } /* if */
887 if (unlikely(err_info != OKAY_NO_ERROR)) {
888 aHashMap->size--;
889 raise_error(MEMORY_ERROR);
890 result = 0;
891 } else {
892 result = result_hashelem->data.value.genericValue;
893 } /* if */
894 logFunction(printf("hshIdxEnterDefault(" FMT_X_MEM ", " FMT_U_GEN ", "
895 FMT_U_GEN ", " FMT_U ") --> " FMT_U_GEN "\n",
896 (memSizeType) aHashMap, aKey, defaultData,
897 hashcode, result););
898 return result;
899 } /* hshIdxEnterDefault */
900
901
902
903 /**
904 * Search for 'aKey' in 'aHashMap'.
905 * If 'aKey' is element of 'aHashMap' the corresponding value is returned.
906 * If 'aKey' is not element of 'aHashMap' then 'defaultData' is returned.
907 * @return the value stored for 'aKey' in 'aHashMap', or
908 * 'defaultData', if 'aKey' is not a member of 'aHashMap'.
909 */
hshIdxWithDefault(const const_rtlHashType aHashMap,const genericType aKey,const genericType defaultData,intType hashcode,compareType cmp_func)910 genericType hshIdxWithDefault (const const_rtlHashType aHashMap, const genericType aKey,
911 const genericType defaultData, intType hashcode, compareType cmp_func)
912
913 {
914 rtlHashElemType hashelem;
915 rtlHashElemType result_hashelem = NULL;
916 intType cmp;
917 genericType result;
918
919 /* hshIdxWithDefault */
920 logFunction(printf("hshIdxWithDefault(" FMT_X_MEM ", " FMT_U_GEN ", "
921 FMT_U_GEN ", " FMT_U ")\n",
922 (memSizeType) aHashMap, aKey, defaultData, hashcode););
923 hashelem = aHashMap->table[(unsigned int) hashcode & aHashMap->mask];
924 while (hashelem != NULL) {
925 cmp = cmp_func(hashelem->key.value.genericValue, aKey);
926 if (cmp < 0) {
927 hashelem = hashelem->next_less;
928 } else if (unlikely(cmp == 0)) {
929 result_hashelem = hashelem;
930 hashelem = NULL;
931 } else {
932 hashelem = hashelem->next_greater;
933 } /* if */
934 } /* while */
935 if (result_hashelem != NULL) {
936 result = result_hashelem->data.value.genericValue;
937 } else {
938 result = defaultData;
939 } /* if */
940 logFunction(printf("hshIdxWithDefault(" FMT_X_MEM ", " FMT_U_GEN ", "
941 FMT_U_GEN ", " FMT_U ") --> " FMT_U_GEN "\n",
942 (memSizeType) aHashMap, aKey, defaultData,
943 hashcode, result););
944 return result;
945 } /* hshIdxWithDefault */
946
947
948
949 /**
950 * Search for 'aKey' in 'aHashMap'.
951 * If 'aKey' is element of 'aHashMap' the corresponding value is returned.
952 * If 'aKey' is not element of 'aHashMap' then 0 is returned.
953 * @return the value stored for 'aKey' in 'aHashMap', or
954 * 0, if 'aKey' is not a member of 'aHashMap'.
955 */
hshIdxDefault0(const const_rtlHashType aHashMap,const genericType aKey,intType hashcode,compareType cmp_func)956 genericType hshIdxDefault0 (const const_rtlHashType aHashMap, const genericType aKey,
957 intType hashcode, compareType cmp_func)
958
959 {
960 rtlHashElemType hashelem;
961 intType cmp;
962 genericType result;
963
964 /* hshIdxDefault0 */
965 logFunction(printf("hshIdxDefault0(" FMT_X_MEM ", " FMT_U_GEN ", " FMT_U ")\n",
966 (memSizeType) aHashMap, aKey, hashcode););
967 hashelem = aHashMap->table[(unsigned int) hashcode & aHashMap->mask];
968 while (hashelem != NULL) {
969 cmp = cmp_func(hashelem->key.value.genericValue, aKey);
970 if (cmp < 0) {
971 hashelem = hashelem->next_less;
972 } else if (unlikely(cmp == 0)) {
973 result = hashelem->data.value.genericValue;
974 logFunction(printf("hshIdxDefault0(" FMT_X_MEM ", " FMT_U_GEN ", "
975 FMT_U ") --> " FMT_U_GEN "\n",
976 (memSizeType) aHashMap, aKey, hashcode, result););
977 return result;
978 } else {
979 hashelem = hashelem->next_greater;
980 } /* if */
981 } /* while */
982 logFunction(printf("hshIdxDefault0(" FMT_X_MEM ", " FMT_U_GEN ", "
983 FMT_U ") --> 0\n",
984 (memSizeType) aHashMap, aKey, hashcode););
985 return 0;
986 } /* hshIdxDefault0 */
987
988
989
990 /**
991 * Add 'data' with the key 'aKey' to the hash map 'aHashMap'.
992 * If an element with the key 'aKey' already exists,
993 * it is overwritten with 'data'.
994 * @exception MEMORY_ERROR If there is not enough memory.
995 */
hshIncl(const rtlHashType aHashMap,const genericType aKey,const genericType data,intType hashcode,compareType cmp_func,const createFuncType key_create_func,const createFuncType data_create_func,const copyFuncType data_copy_func)996 void hshIncl (const rtlHashType aHashMap, const genericType aKey,
997 const genericType data, intType hashcode, compareType cmp_func,
998 const createFuncType key_create_func, const createFuncType data_create_func,
999 const copyFuncType data_copy_func)
1000
1001 {
1002 rtlHashElemType hashelem;
1003 intType cmp;
1004 errInfoType err_info = OKAY_NO_ERROR;
1005
1006 /* hshIncl */
1007 logFunction(printf("hshIncl(" FMT_X_MEM ", " FMT_U_GEN ", "
1008 FMT_U_GEN ", " FMT_U ") size=" FMT_U_MEM "\n",
1009 (memSizeType) aHashMap, aKey, data, hashcode, aHashMap->size););
1010 hashelem = aHashMap->table[(unsigned int) hashcode & aHashMap->mask];
1011 if (hashelem == NULL) {
1012 aHashMap->table[(unsigned int) hashcode & aHashMap->mask] = new_helem(aKey, data,
1013 key_create_func, data_create_func, &err_info);
1014 /*
1015 hashelem = aHashMap->table[(unsigned int) hashcode & aHashMap->mask];
1016 printf("aKey=%llX\n", (unsigned long long) aKey);
1017 printf("new hashelem: aKey=%llX, data=%llX\n",
1018 hashelem->key.value.intValue, hashelem->data.value.intValue);
1019 printf("cmp = %d\n", (int) cmp_func(hashelem->key.value.genericValue, aKey));
1020 */
1021 aHashMap->size++;
1022 } else {
1023 do {
1024 cmp = cmp_func(hashelem->key.value.genericValue, aKey);
1025 if (cmp < 0) {
1026 if (hashelem->next_less == NULL) {
1027 hashelem->next_less = new_helem(aKey, data,
1028 key_create_func, data_create_func, &err_info);
1029 aHashMap->size++;
1030 hashelem = NULL;
1031 } else {
1032 hashelem = hashelem->next_less;
1033 } /* if */
1034 } else if (unlikely(cmp == 0)) {
1035 data_copy_func(&hashelem->data.value.genericValue, data);
1036 hashelem = NULL;
1037 } else {
1038 if (hashelem->next_greater == NULL) {
1039 hashelem->next_greater = new_helem(aKey, data,
1040 key_create_func, data_create_func, &err_info);
1041 aHashMap->size++;
1042 hashelem = NULL;
1043 } else {
1044 hashelem = hashelem->next_greater;
1045 } /* if */
1046 } /* if */
1047 } while (hashelem != NULL);
1048 } /* if */
1049 if (unlikely(err_info != OKAY_NO_ERROR)) {
1050 aHashMap->size--;
1051 raise_error(MEMORY_ERROR);
1052 } /* if */
1053 logFunction(printf("hshIncl(" FMT_X_MEM ", " FMT_U_GEN ", "
1054 FMT_U_GEN ", " FMT_U ") size=" FMT_U_MEM " -->\n",
1055 (memSizeType) aHashMap, aKey, data, hashcode, aHashMap->size););
1056 } /* hshIncl */
1057
1058
1059
1060 /**
1061 * Obtain the keys of the hash map 'aHashMap'.
1062 * @return the keys of the hash map.
1063 */
hshKeys(const const_rtlHashType aHashMap,const createFuncType key_create_func,const destrFuncType key_destr_func)1064 rtlArrayType hshKeys (const const_rtlHashType aHashMap,
1065 const createFuncType key_create_func, const destrFuncType key_destr_func)
1066
1067 {
1068 rtlArrayType key_array;
1069
1070 /* hshKeys */
1071 key_array = keys_hash(aHashMap, key_create_func);
1072 return key_array;
1073 } /* hshKeys */
1074
1075
1076
1077 /**
1078 * Compute pseudo-random hash table element from 'aHashMap'.
1079 * The hash table element contains key and value.
1080 * The random values are uniform distributed.
1081 * @return a random hash table element such that hshRand(aHashMap) in aHashMap holds.
1082 * @exception RANGE_ERROR If 'aHashMap' is empty.
1083 */
hshRand(const const_rtlHashType aHashMap)1084 const_rtlHashElemType hshRand (const const_rtlHashType aHashMap)
1085
1086 {
1087 memSizeType num_elements;
1088 memSizeType elem_index;
1089 const_rtlHashElemType result;
1090
1091 /* hshRand */
1092 logFunction(printf("hshRand(" FMT_U_MEM ")\n",
1093 (memSizeType) aHashMap););
1094 num_elements = aHashMap->size;
1095 if (unlikely(num_elements == 0)) {
1096 logError(printf("hshRand(): Hash map is empty.\n"););
1097 raise_error(RANGE_ERROR);
1098 return NULL;
1099 } else {
1100 elem_index = (memSizeType) (uintType)
1101 intRand((intType) 1, (intType) num_elements);
1102 /* printf("elem_index " FMT_U_MEM "\n", elem_index); */
1103 result = get_hash_elem(aHashMap, elem_index);
1104 } /* if */
1105 logFunction(printf("hshRand --> " FMT_U_MEM "\n",
1106 (memSizeType) result););
1107 return result;
1108 } /* hshRand */
1109
1110
1111
1112 /**
1113 * Add 'data' with the key 'aKey' to the hash map 'aHashMap'.
1114 * If an element with the key 'aKey' already exists,
1115 * it is overwritten with 'data'.
1116 * @param data New value, a temporary value which is used or returned.
1117 * @return the old element with the key 'aKey' or
1118 * the new data value if no old element existed.
1119 * @exception MEMORY_ERROR If there is not enough memory.
1120 */
hshUpdate(const rtlHashType aHashMap,const genericType aKey,const genericType data,intType hashcode,compareType cmp_func,const createFuncType key_create_func,const createFuncType data_create_func)1121 genericType hshUpdate (const rtlHashType aHashMap, const genericType aKey,
1122 const genericType data, intType hashcode, compareType cmp_func,
1123 const createFuncType key_create_func, const createFuncType data_create_func)
1124
1125 {
1126 rtlHashElemType hashelem;
1127 intType cmp;
1128 errInfoType err_info = OKAY_NO_ERROR;
1129 genericType result;
1130
1131 /* hshUpdate */
1132 logFunction(printf("hshUpdate(" FMT_X_MEM ", " FMT_U_GEN ", "
1133 FMT_U_GEN ", " FMT_U ") size=" FMT_U_MEM "\n",
1134 (memSizeType) aHashMap, aKey, data, hashcode, aHashMap->size););
1135 hashelem = aHashMap->table[(unsigned int) hashcode & aHashMap->mask];
1136 if (hashelem == NULL) {
1137 aHashMap->table[(unsigned int) hashcode & aHashMap->mask] = new_helem(aKey, data,
1138 key_create_func, data_create_func, &err_info);
1139 aHashMap->size++;
1140 result = data;
1141 } else {
1142 do {
1143 cmp = cmp_func(hashelem->key.value.genericValue, aKey);
1144 if (cmp < 0) {
1145 if (hashelem->next_less == NULL) {
1146 hashelem->next_less = new_helem(aKey, data,
1147 key_create_func, data_create_func, &err_info);
1148 aHashMap->size++;
1149 result = data;
1150 hashelem = NULL;
1151 } else {
1152 hashelem = hashelem->next_less;
1153 } /* if */
1154 } else if (unlikely(cmp == 0)) {
1155 result = hashelem->data.value.genericValue;
1156 hashelem->data.value.genericValue = data;
1157 hashelem = NULL;
1158 } else {
1159 if (hashelem->next_greater == NULL) {
1160 hashelem->next_greater = new_helem(aKey, data,
1161 key_create_func, data_create_func, &err_info);
1162 aHashMap->size++;
1163 result = data;
1164 hashelem = NULL;
1165 } else {
1166 hashelem = hashelem->next_greater;
1167 } /* if */
1168 } /* if */
1169 } while (hashelem != NULL);
1170 } /* if */
1171 if (unlikely(err_info != OKAY_NO_ERROR)) {
1172 aHashMap->size--;
1173 raise_error(MEMORY_ERROR);
1174 } /* if */
1175 logFunction(printf("hshUpdate(" FMT_X_MEM ", " FMT_U_GEN ", "
1176 FMT_U_GEN ", " FMT_U ") size=" FMT_U_MEM " -->\n",
1177 (memSizeType) aHashMap, aKey, data, hashcode, aHashMap->size););
1178 return result;
1179 } /* hshUpdate */
1180
1181
1182
1183 /**
1184 * Obtain the values of the hash map 'aHashMap'.
1185 * @return the values of the hash map.
1186 */
hshValues(const const_rtlHashType aHashMap,const createFuncType value_create_func,const destrFuncType value_destr_func)1187 rtlArrayType hshValues (const const_rtlHashType aHashMap,
1188 const createFuncType value_create_func, const destrFuncType value_destr_func)
1189
1190 {
1191 rtlArrayType value_array;
1192
1193 /* hshValues */
1194 value_array = values_hash(aHashMap, value_create_func);
1195 return value_array;
1196 } /* hshValues */
1197