2 Copyright (C) 2001-2010, Parrot Foundation.
7 src/hash.c - Hash table
11 A hashtable contains an array of bucket indexes. Buckets are nodes in a
12 linked list, each containing a C<void *> key and value. During hash
13 creation, the types of key and value as well as appropriate compare and
14 hashing functions can be set.
16 This hash implementation uses just one piece of malloced memory. The
17 C<< hash->buckets >> bucket store points to this region.
27 #include "parrot/parrot.h"
29 /* the number of entries above which it's faster to hash the hashval instead of
30 * looping over the used HashBuckets directly */
31 #define INITIAL_SIZE 8
33 /* HEADERIZER HFILE: include/parrot/hash.h */
35 /* HEADERIZER BEGIN: static */
36 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
38 static void expand_hash(PARROT_INTERP
, ARGMOD(Hash
*hash
))
39 __attribute__nonnull__(1)
40 __attribute__nonnull__(2)
43 PARROT_CANNOT_RETURN_NULL
44 static PMC
* get_integer_pmc(PARROT_INTERP
, INTVAL value
)
45 __attribute__nonnull__(1);
47 PARROT_CANNOT_RETURN_NULL
48 static PMC
* get_number_pmc(PARROT_INTERP
, FLOATVAL value
)
49 __attribute__nonnull__(1);
51 PARROT_CANNOT_RETURN_NULL
52 static PMC
* get_string_pmc(PARROT_INTERP
, ARGIN(STRING
*value
))
53 __attribute__nonnull__(1)
54 __attribute__nonnull__(2);
56 PARROT_WARN_UNUSED_RESULT
59 static int hash_compare(PARROT_INTERP
,
60 ARGIN(const Hash
*hash
),
61 ARGIN_NULLOK(void *a
),
62 ARGIN_NULLOK(void *b
))
63 __attribute__nonnull__(1)
64 __attribute__nonnull__(2);
66 PARROT_WARN_UNUSED_RESULT
69 static int hash_compare_cstring(SHIM_INTERP
,
72 __attribute__nonnull__(2)
73 __attribute__nonnull__(3);
75 PARROT_WARN_UNUSED_RESULT
78 static int hash_compare_int(SHIM_INTERP
,
79 ARGIN_NULLOK(const void *a
),
80 ARGIN_NULLOK(const void *b
));
82 PARROT_WARN_UNUSED_RESULT
85 static int hash_compare_pmc(PARROT_INTERP
, ARGIN(PMC
*a
), ARGIN(PMC
*b
))
86 __attribute__nonnull__(1)
87 __attribute__nonnull__(2)
88 __attribute__nonnull__(3);
90 PARROT_WARN_UNUSED_RESULT
93 static int hash_compare_pointer(SHIM_INTERP
,
94 ARGIN_NULLOK(const void *a
),
95 ARGIN_NULLOK(const void *b
));
97 PARROT_WARN_UNUSED_RESULT
100 static int hash_compare_string(PARROT_INTERP
,
101 ARGIN(const void *search_key
),
102 ARGIN_NULLOK(const void *bucket_key
))
103 __attribute__nonnull__(1)
104 __attribute__nonnull__(2);
106 PARROT_WARN_UNUSED_RESULT
107 static int hash_compare_string_enc(PARROT_INTERP
,
108 ARGIN(const void *search_key
),
109 ARGIN(const void *bucket_key
))
110 __attribute__nonnull__(1)
111 __attribute__nonnull__(2)
112 __attribute__nonnull__(3);
114 PARROT_WARN_UNUSED_RESULT
117 static size_t key_hash(PARROT_INTERP
,
118 ARGIN(const Hash
*hash
),
119 ARGIN_NULLOK(void *key
))
120 __attribute__nonnull__(1)
121 __attribute__nonnull__(2);
123 PARROT_WARN_UNUSED_RESULT
126 static size_t key_hash_cstring(SHIM_INTERP
,
127 ARGIN(const void *value
),
129 __attribute__nonnull__(2);
131 PARROT_WARN_UNUSED_RESULT
134 static size_t key_hash_int(SHIM_INTERP
,
135 ARGIN_NULLOK(const void *value
),
138 PARROT_WARN_UNUSED_RESULT
141 static size_t key_hash_PMC(PARROT_INTERP
,
144 __attribute__nonnull__(1)
145 __attribute__nonnull__(2);
147 PARROT_WARN_UNUSED_RESULT
150 static size_t key_hash_pointer(SHIM_INTERP
,
151 ARGIN(const void *value
),
153 __attribute__nonnull__(2);
155 PARROT_WARN_UNUSED_RESULT
158 static size_t key_hash_STRING(PARROT_INTERP
, ARGMOD(STRING
*s
), size_t seed
)
159 __attribute__nonnull__(1)
160 __attribute__nonnull__(2)
163 static void parrot_mark_hash_both(PARROT_INTERP
, ARGIN(Hash
*hash
))
164 __attribute__nonnull__(1)
165 __attribute__nonnull__(2);
167 static void parrot_mark_hash_keys(PARROT_INTERP
, ARGIN(Hash
*hash
))
168 __attribute__nonnull__(1)
169 __attribute__nonnull__(2);
171 static void parrot_mark_hash_values(PARROT_INTERP
, ARGIN(Hash
*hash
))
172 __attribute__nonnull__(1)
173 __attribute__nonnull__(2);
175 #define ASSERT_ARGS_expand_hash __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
176 PARROT_ASSERT_ARG(interp) \
177 , PARROT_ASSERT_ARG(hash))
178 #define ASSERT_ARGS_get_integer_pmc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
179 PARROT_ASSERT_ARG(interp))
180 #define ASSERT_ARGS_get_number_pmc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
181 PARROT_ASSERT_ARG(interp))
182 #define ASSERT_ARGS_get_string_pmc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
183 PARROT_ASSERT_ARG(interp) \
184 , PARROT_ASSERT_ARG(value))
185 #define ASSERT_ARGS_hash_compare __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
186 PARROT_ASSERT_ARG(interp) \
187 , PARROT_ASSERT_ARG(hash))
188 #define ASSERT_ARGS_hash_compare_cstring __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
189 PARROT_ASSERT_ARG(a) \
190 , PARROT_ASSERT_ARG(b))
191 #define ASSERT_ARGS_hash_compare_int __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
192 #define ASSERT_ARGS_hash_compare_pmc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
193 PARROT_ASSERT_ARG(interp) \
194 , PARROT_ASSERT_ARG(a) \
195 , PARROT_ASSERT_ARG(b))
196 #define ASSERT_ARGS_hash_compare_pointer __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
197 #define ASSERT_ARGS_hash_compare_string __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
198 PARROT_ASSERT_ARG(interp) \
199 , PARROT_ASSERT_ARG(search_key))
200 #define ASSERT_ARGS_hash_compare_string_enc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
201 PARROT_ASSERT_ARG(interp) \
202 , PARROT_ASSERT_ARG(search_key) \
203 , PARROT_ASSERT_ARG(bucket_key))
204 #define ASSERT_ARGS_key_hash __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
205 PARROT_ASSERT_ARG(interp) \
206 , PARROT_ASSERT_ARG(hash))
207 #define ASSERT_ARGS_key_hash_cstring __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
208 PARROT_ASSERT_ARG(value))
209 #define ASSERT_ARGS_key_hash_int __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
210 #define ASSERT_ARGS_key_hash_PMC __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
211 PARROT_ASSERT_ARG(interp) \
212 , PARROT_ASSERT_ARG(value))
213 #define ASSERT_ARGS_key_hash_pointer __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
214 PARROT_ASSERT_ARG(value))
215 #define ASSERT_ARGS_key_hash_STRING __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
216 PARROT_ASSERT_ARG(interp) \
217 , PARROT_ASSERT_ARG(s))
218 #define ASSERT_ARGS_parrot_mark_hash_both __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
219 PARROT_ASSERT_ARG(interp) \
220 , PARROT_ASSERT_ARG(hash))
221 #define ASSERT_ARGS_parrot_mark_hash_keys __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
222 PARROT_ASSERT_ARG(interp) \
223 , PARROT_ASSERT_ARG(hash))
224 #define ASSERT_ARGS_parrot_mark_hash_values __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
225 PARROT_ASSERT_ARG(interp) \
226 , PARROT_ASSERT_ARG(hash))
227 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
228 /* HEADERIZER END: static */
232 =item C<static size_t key_hash_STRING(PARROT_INTERP, STRING *s, size_t seed)>
234 Returns the hashed value of the key C<value>. See also string.c.
241 PARROT_WARN_UNUSED_RESULT
245 key_hash_STRING(PARROT_INTERP
, ARGMOD(STRING
*s
), size_t seed
)
247 ASSERT_ARGS(key_hash_STRING
)
252 return Parrot_str_to_hashval(interp
, s
);
258 =item C<static int hash_compare_string(PARROT_INTERP, const void *search_key,
259 const void *bucket_key)>
261 Compares the two strings, returning 0 if they are identical.
267 PARROT_WARN_UNUSED_RESULT
271 hash_compare_string(PARROT_INTERP
, ARGIN(const void *search_key
),
272 ARGIN_NULLOK(const void *bucket_key
))
274 ASSERT_ARGS(hash_compare_string
)
275 STRING
const *s1
= (STRING
const *)search_key
;
276 STRING
const *s2
= (STRING
const *)bucket_key
;
278 return STRING_equal(interp
, s1
, s2
) == 0;
284 =item C<static int hash_compare_string_enc(PARROT_INTERP, const void
285 *search_key, const void *bucket_key)>
287 Compare two strings. Returns 0 if they are identical. Considers differing
288 charset or encoding to be distinct.
292 PARROT_WARN_UNUSED_RESULT
294 hash_compare_string_enc(PARROT_INTERP
, ARGIN(const void *search_key
),
295 ARGIN(const void *bucket_key
))
297 ASSERT_ARGS(hash_compare_string_enc
)
298 STRING
const *s1
= (STRING
const *)search_key
;
299 STRING
const *s2
= (STRING
const *)bucket_key
;
301 if (s1
->hashval
!= s2
->hashval
)
303 if (s1
&& s2
&& s1
->encoding
!= s2
->encoding
)
306 return memcmp(s1
->strstart
, s2
->strstart
, s1
->bufused
);
312 =item C<static int hash_compare_pointer(PARROT_INTERP, const void *a, const void
315 Compares the two pointers, returning 0 if they are identical
321 PARROT_WARN_UNUSED_RESULT
325 hash_compare_pointer(SHIM_INTERP
, ARGIN_NULLOK(const void *a
), ARGIN_NULLOK(const void *b
))
327 ASSERT_ARGS(hash_compare_pointer
)
334 =item C<static size_t key_hash_pointer(PARROT_INTERP, const void *value, size_t
337 Returns a hashvalue for a pointer.
343 PARROT_WARN_UNUSED_RESULT
347 key_hash_pointer(SHIM_INTERP
, ARGIN(const void *value
), size_t seed
)
349 ASSERT_ARGS(key_hash_pointer
)
350 return ((size_t) value
) ^ seed
;
356 =item C<static size_t key_hash_cstring(PARROT_INTERP, const void *value, size_t
359 Creates and returns a hash value from a string.
361 Takes an interpreter, a pointer to a string, and a seed value.
362 Returns the hash value.
364 Used by parrot_new_cstring_hash.
370 PARROT_WARN_UNUSED_RESULT
374 key_hash_cstring(SHIM_INTERP
, ARGIN(const void *value
), size_t seed
)
376 ASSERT_ARGS(key_hash_cstring
)
377 const unsigned char *p
= (const unsigned char *) value
;
389 =item C<static int hash_compare_cstring(PARROT_INTERP, const char *a, const char
392 Compares two C strings for equality, returning -1, 0, and 1 if the first string
393 is less than, equal to, or greater than the second, respectively.
399 PARROT_WARN_UNUSED_RESULT
403 hash_compare_cstring(SHIM_INTERP
, ARGIN(const char *a
), ARGIN(const char *b
))
405 ASSERT_ARGS(hash_compare_cstring
)
412 =item C<static size_t key_hash_PMC(PARROT_INTERP, PMC *value, size_t seed)>
414 Returns a hashed value for an PMC key (passed as a void pointer, sadly).
420 PARROT_WARN_UNUSED_RESULT
424 key_hash_PMC(PARROT_INTERP
, ARGIN(PMC
*value
), SHIM(size_t seed
))
426 ASSERT_ARGS(key_hash_PMC
)
427 return VTABLE_hashvalue(interp
, value
);
432 =item C<static int hash_compare_pmc(PARROT_INTERP, PMC *a, PMC *b)>
434 Compares two PMC for equality, returning 0 if the first is equal to second.
435 Uses void pointers to store the PMC, sadly.
441 PARROT_WARN_UNUSED_RESULT
445 hash_compare_pmc(PARROT_INTERP
, ARGIN(PMC
*a
), ARGIN(PMC
*b
))
447 ASSERT_ARGS(hash_compare_pmc
)
449 /* If pointers are same - PMCs are same */
453 /* PMCs of different types are different */
454 if (a
->vtable
->base_type
!= b
->vtable
->base_type
)
457 return !VTABLE_is_equal(interp
, a
, b
);
462 =item C<static size_t key_hash_int(PARROT_INTERP, const void *value, size_t
465 Returns a hashed value for an integer key (passed as a void pointer, sadly).
471 PARROT_WARN_UNUSED_RESULT
475 key_hash_int(SHIM_INTERP
, ARGIN_NULLOK(const void *value
), size_t seed
)
477 ASSERT_ARGS(key_hash_int
)
478 return (size_t)value
^ seed
;
483 =item C<static int hash_compare_int(PARROT_INTERP, const void *a, const void
486 Compares two integers for equality, returning -1, 0, and 1 if the first is less
487 than, equal to, or greater than the second, respectively. Uses void pointers
488 to store the integers, sadly.
494 PARROT_WARN_UNUSED_RESULT
498 hash_compare_int(SHIM_INTERP
, ARGIN_NULLOK(const void *a
), ARGIN_NULLOK(const void *b
))
500 ASSERT_ARGS(hash_compare_int
)
506 =item C<static size_t key_hash(PARROT_INTERP, const Hash *hash, void *key)>
508 Generic function to get the hashvalue of a given key. It may dispatches to
509 key_hash_STRING, key_hash_cstring, etc. depending on hash->key_type.
516 PARROT_WARN_UNUSED_RESULT
520 key_hash(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN_NULLOK(void *key
))
522 ASSERT_ARGS(key_hash
)
524 if (hash
->key_type
== Hash_key_type_STRING
525 || hash
->key_type
== Hash_key_type_STRING_enc
)
526 return key_hash_STRING(interp
, (STRING
*)key
, hash
->seed
);
528 if (hash
->key_type
== Hash_key_type_cstring
)
529 return key_hash_cstring(interp
, (char *)key
, hash
->seed
);
531 if (hash
->key_type
== Hash_key_type_PMC
)
532 return VTABLE_hashvalue(interp
, (PMC
*)key
);
534 return ((size_t) key
) ^ hash
->seed
;
540 =item C<static int hash_compare(PARROT_INTERP, const Hash *hash, void *a, void
543 Generic function to compare values. It may dispatches to
544 hash_compare_string, hash_compare_cstring, etc. depending on hash->key_type.
551 PARROT_WARN_UNUSED_RESULT
555 hash_compare(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN_NULLOK(void *a
),
556 ARGIN_NULLOK(void *b
))
558 ASSERT_ARGS(hash_compare
)
563 if (hash
->key_type
== Hash_key_type_STRING
)
564 return hash_compare_string(interp
, (STRING
*)a
, (STRING
*)b
);
566 if (hash
->key_type
== Hash_key_type_STRING_enc
)
567 return hash_compare_string_enc(interp
, (STRING
*)a
, (STRING
*)b
);
569 if (hash
->key_type
== Hash_key_type_cstring
)
570 return strcmp((char *)a
, (char *)b
);
572 if (hash
->key_type
== Hash_key_type_PMC
)
573 return hash_compare_pmc(interp
, (PMC
*)a
, (PMC
*) b
);
580 =item C<void parrot_dump_hash(PARROT_INTERP, const Hash *hash)>
582 Prints out the hash in human-readable form, at least once someone implements
591 parrot_dump_hash(SHIM_INTERP
, SHIM(const Hash
*hash
))
593 ASSERT_ARGS(parrot_dump_hash
)
599 =item C<void parrot_mark_hash(PARROT_INTERP, Hash *hash)>
601 Marks the hash and its contents as live. Assumes that key and value are
602 non-null in all buckets.
610 parrot_mark_hash(PARROT_INTERP
, ARGMOD(Hash
*hash
))
612 ASSERT_ARGS(parrot_mark_hash
)
616 if (hash
->entry_type
== (PARROT_DATA_TYPE
) enum_hash_string
617 || hash
->entry_type
== (PARROT_DATA_TYPE
) enum_hash_pmc
)
620 if (hash
->key_type
== Hash_key_type_STRING
621 || hash
->key_type
== Hash_key_type_STRING_enc
622 || hash
->key_type
== Hash_key_type_PMC
623 || hash
->key_type
== Hash_key_type_PMC_ptr
)
628 parrot_mark_hash_both(interp
, hash
);
630 parrot_mark_hash_keys(interp
, hash
);
634 parrot_mark_hash_values(interp
, hash
);
641 =item C<static void parrot_mark_hash_keys(PARROT_INTERP, Hash *hash)>
643 Marks the hash and only its keys as live.
650 parrot_mark_hash_keys(PARROT_INTERP
, ARGIN(Hash
*hash
))
652 ASSERT_ARGS(parrot_mark_hash_keys
)
654 if (hash
->key_type
== Hash_key_type_STRING
655 || hash
->key_type
== Hash_key_type_STRING_enc
) {
656 parrot_hash_iterate(hash
,
657 PARROT_ASSERT(_bucket
->key
);
658 Parrot_gc_mark_STRING_alive(interp
, (STRING
*)_bucket
->key
););
661 parrot_hash_iterate(hash
,
662 PARROT_ASSERT(_bucket
->key
);
663 Parrot_gc_mark_PMC_alive(interp
, (PMC
*)_bucket
->key
););
670 =item C<static void parrot_mark_hash_values(PARROT_INTERP, Hash *hash)>
672 Marks the hash and only its values as live.
679 parrot_mark_hash_values(PARROT_INTERP
, ARGIN(Hash
*hash
))
681 ASSERT_ARGS(parrot_mark_hash_values
)
683 if (hash
->entry_type
== (PARROT_DATA_TYPE
) enum_hash_string
) {
684 parrot_hash_iterate(hash
,
685 PARROT_ASSERT(_bucket
->value
);
686 Parrot_gc_mark_STRING_alive(interp
, (STRING
*)_bucket
->value
););
688 else if (hash
->entry_type
== (PARROT_DATA_TYPE
) enum_hash_pmc
) {
689 parrot_hash_iterate(hash
,
690 PARROT_ASSERT(_bucket
->value
);
691 Parrot_gc_mark_PMC_alive(interp
, (PMC
*)_bucket
->value
););
698 =item C<static void parrot_mark_hash_both(PARROT_INTERP, Hash *hash)>
700 Marks the hash and both its keys and values as live.
707 parrot_mark_hash_both(PARROT_INTERP
, ARGIN(Hash
*hash
))
709 ASSERT_ARGS(parrot_mark_hash_both
)
711 if ((hash
->key_type
== Hash_key_type_STRING
712 || hash
->key_type
== Hash_key_type_STRING_enc
)
713 && hash
->entry_type
== (PARROT_DATA_TYPE
) enum_hash_pmc
) {
714 parrot_hash_iterate(hash
,
715 PARROT_ASSERT(_bucket
->key
);
716 Parrot_gc_mark_STRING_alive(interp
, (STRING
*)_bucket
->key
);
717 PARROT_ASSERT(_bucket
->value
);
718 Parrot_gc_mark_PMC_alive(interp
, (PMC
*)_bucket
->value
););
721 parrot_hash_iterate(hash
,
722 PARROT_ASSERT(_bucket
->key
);
723 Parrot_gc_mark_PObj_alive(interp
, (PObj
*)_bucket
->key
);
724 PARROT_ASSERT(_bucket
->value
);
725 Parrot_gc_mark_PObj_alive(interp
, (PObj
*)_bucket
->value
););
731 =item C<Hash * Parrot_hash_thaw(PARROT_INTERP, PMC *info)>
733 Visits the contents of a hash during freeze/thaw.
735 C<pinfo> is the visit info, (see include/parrot/pmc_freeze.h>).
741 PARROT_CANNOT_RETURN_NULL
742 PARROT_WARN_UNUSED_RESULT
745 Parrot_hash_thaw(PARROT_INTERP
, ARGMOD(PMC
*info
))
747 ASSERT_ARGS(Parrot_hash_thaw
)
749 const size_t num_entries
= VTABLE_shift_integer(interp
, info
);
750 const Hash_key_type key_type
= (Hash_key_type
)VTABLE_shift_integer(interp
, info
);
751 const PARROT_DATA_TYPE entry_type
= (PARROT_DATA_TYPE
)VTABLE_shift_integer(interp
, info
);
753 Hash
*hash
= parrot_create_hash_sized(interp
, entry_type
, key_type
, num_entries
);
755 /* special case for great speed */
756 if (key_type
== Hash_key_type_STRING
757 && entry_type
== enum_hash_int
) {
758 for (entry_index
= 0; entry_index
< num_entries
; ++entry_index
) {
759 STRING
* const key
= VTABLE_shift_string(interp
, info
);
760 const INTVAL i
= VTABLE_shift_integer(interp
, info
);
761 parrot_hash_put(interp
, hash
, (void *)key
, (void *)i
);
767 for (entry_index
= 0; entry_index
< num_entries
; ++entry_index
) {
771 case Hash_key_type_int
:
773 const INTVAL i_key
= VTABLE_shift_integer(interp
, info
);
777 case Hash_key_type_STRING
:
778 case Hash_key_type_STRING_enc
:
780 STRING
* const s_key
= VTABLE_shift_string(interp
, info
);
784 case Hash_key_type_PMC
:
785 case Hash_key_type_PMC_ptr
:
787 PMC
* const p_key
= VTABLE_shift_pmc(interp
, info
);
792 Parrot_ex_throw_from_c_args(interp
, NULL
, 1,
793 "unimplemented key type");
797 switch (entry_type
) {
800 const INTVAL i
= VTABLE_shift_integer(interp
, info
);
801 parrot_hash_put(interp
, hash
, key
, (void *)i
);
804 case enum_hash_string
:
806 STRING
* const s
= VTABLE_shift_string(interp
, info
);
807 parrot_hash_put(interp
, hash
, key
, (void *)s
);
812 PMC
* const p
= VTABLE_shift_pmc(interp
, info
);
813 parrot_hash_put(interp
, hash
, key
, (void *)p
);
817 Parrot_ex_throw_from_c_args(interp
, NULL
, 1,
818 "unimplemented value type");
829 =item C<void Parrot_hash_freeze(PARROT_INTERP, const Hash *hash, PMC *info)>
831 Freezes hash into a string.
833 Takes an interpreter, a pointer to the hash, and a pointer to the structure
834 containing the string start location.
841 Parrot_hash_freeze(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGMOD(PMC
*info
))
843 ASSERT_ARGS(Parrot_hash_freeze
)
844 const Hash_key_type key_type
= hash
->key_type
;
845 const PARROT_DATA_TYPE entry_type
= hash
->entry_type
;
846 const size_t entries
= hash
->entries
;
849 VTABLE_push_integer(interp
, info
, entries
);
850 VTABLE_push_integer(interp
, info
, key_type
);
851 VTABLE_push_integer(interp
, info
, entry_type
);
853 parrot_hash_iterate(hash
,
855 case Hash_key_type_int
:
856 VTABLE_push_integer(interp
, info
, (INTVAL
)_bucket
->key
);
858 case Hash_key_type_STRING
:
859 case Hash_key_type_STRING_enc
:
860 VTABLE_push_string(interp
, info
, (STRING
*)_bucket
->key
);
862 case Hash_key_type_PMC
:
863 case Hash_key_type_PMC_ptr
:
864 VTABLE_push_pmc(interp
, info
, (PMC
*)_bucket
->key
);
867 Parrot_ex_throw_from_c_args(interp
, NULL
, 1,
868 "unimplemented key type");
871 switch (entry_type
) {
873 VTABLE_push_integer(interp
, info
, (INTVAL
)_bucket
->value
);
875 case enum_hash_string
:
876 VTABLE_push_string(interp
, info
, (STRING
*)_bucket
->value
);
879 VTABLE_push_pmc(interp
, info
, (PMC
*)_bucket
->value
);
882 Parrot_ex_throw_from_c_args(interp
, NULL
, 1,
883 "unimplemented value type");
891 =item C<static void expand_hash(PARROT_INTERP, Hash *hash)>
893 Expands a hash when necessary.
895 For a hashtable of size N, we use C<MAXFULL_PERCENT> % of N as the
896 number of buckets. This way, as soon as we run out of buckets on the
897 free list, we know that it's time to resize the hashtable.
899 Algorithm for expansion: We exactly double the size of the hashtable.
900 Keys are assigned to buckets with the formula
902 bucket_index = hash(key) % parrot_hash_size
904 When doubling the size of the hashtable, we know that every key is either
905 already in the correct bucket, or belongs in the current bucket plus
906 C<parrot_hash_size> (the old C<parrot_hash_size>). In fact, because the
907 hashtable is always a power of two in size, it depends only on the next bit
908 in the hash value, after the ones previously used.
910 We scan through all the buckets in order, moving the buckets that need to be
911 moved. No bucket will be scanned twice, and the cache should be reasonably
912 happy because the hashtable accesses will be two parallel sequential scans.
913 (Of course, this also mucks with the C<< ->next >> pointers, and they'll be
921 expand_hash(PARROT_INTERP
, ARGMOD(Hash
*hash
))
923 ASSERT_ARGS(expand_hash
)
924 HashBucket
**new_index
, **index
;
925 HashBucket
*new_buckets
, *bucket
;
927 HashBucket
* const initial_offset
= (HashBucket
*)((char *)hash
+ sizeof (Hash
));
930 void * const old_mem
= hash
->buckets
;
931 const UINTVAL old_size
= hash
->mask
+ 1;
932 const UINTVAL new_size
= old_size
<< 1; /* Double. Right-shift is 2x */
933 const UINTVAL new_mask
= new_size
- 1;
937 allocate some less buckets
938 e.g. 3 buckets, 4 pointers:
940 +---+---+---+-+-+-+-+
942 +---+---+---+-+-+-+-+
944 | old_mem | hash->index
948 if (initial_offset
!= old_mem
) {
949 /* This buffer has been reallocated at least once before. */
950 new_mem
= Parrot_gc_reallocate_memory_chunk_with_interior_pointers(
952 HASH_ALLOC_SIZE(new_size
),
953 HASH_ALLOC_SIZE(old_size
));
955 new_buckets
= (HashBucket
*) new_mem
;
956 new_index
= (HashBucket
**)(new_buckets
+ N_BUCKETS(new_size
));
958 offset
= (char *)new_mem
- (char *)old_mem
;
960 /* old index is here */
961 index
= (HashBucket
**)(new_buckets
+ N_BUCKETS(old_size
));
962 /* reallocate index */
963 mem_sys_memcopy(new_index
, index
, sizeof (HashBucket
*) * old_size
);
965 /* clear second half of the buckets, freed by old the index */
966 memset(new_buckets
+ N_BUCKETS(old_size
), 0,
967 sizeof (HashBucket
*) * old_size
);
970 /* Allocate a new buffer. */
971 new_mem
= Parrot_gc_allocate_memory_chunk_with_interior_pointers(
972 interp
, HASH_ALLOC_SIZE(new_size
));
974 new_buckets
= (HashBucket
*) new_mem
;
975 new_index
= (HashBucket
**)(new_buckets
+ N_BUCKETS(new_size
));
977 offset
= (char *)new_buckets
- (char *)hash
->buckets
;
979 mem_sys_memcopy(new_buckets
, hash
->buckets
,
980 N_BUCKETS(old_size
) * sizeof (HashBucket
));
981 mem_sys_memcopy(new_index
, hash
->index
,
982 sizeof (HashBucket
*) * old_size
);
987 +---+---+---+---+---+---+-+-+-+-+-+-+-+-+
988 | buckets | old_index | new_index |
989 +---+---+---+---+---+---+-+-+-+-+-+-+-+-+
991 | new_mem | hash->index
994 /* update hash data */
995 hash
->index
= new_index
;
996 hash
->buckets
= new_buckets
;
997 hash
->mask
= new_mask
;
999 /* reloc pointers and recalc bucket indices */
1000 for (i
= 0; i
< old_size
; ++i
) {
1001 index
= new_index
+ i
;
1003 while (*index
!= NULL
) {
1007 bucket
= (HashBucket
*)((char *)*index
+ offset
);
1009 /* rehash the bucket */
1010 if (hash
->key_type
== Hash_key_type_STRING
1011 || hash
->key_type
== Hash_key_type_STRING_enc
) {
1012 STRING
*s
= (STRING
*)bucket
->key
;
1013 hashval
= s
->hashval
;
1016 hashval
= key_hash(interp
, hash
, bucket
->key
);
1019 new_loc
= hashval
& new_mask
;
1022 *index
= bucket
->next
;
1023 bucket
->next
= new_index
[new_loc
];
1024 new_index
[new_loc
] = bucket
;
1028 index
= &bucket
->next
;
1033 /* add new buckets to free_list
1034 * lowest bucket is top on free list and will be used first */
1036 bucket
= new_buckets
+ N_BUCKETS(old_size
);
1038 for (; bucket
< new_buckets
+ N_BUCKETS(new_size
) - 1; ++bucket
) {
1039 bucket
->next
= bucket
+ 1;
1040 bucket
->key
= bucket
->value
= NULL
;
1043 hash
->free_list
= new_buckets
+ N_BUCKETS(old_size
);
1044 bucket
->next
= NULL
;
1050 =item C<Hash* parrot_new_hash(PARROT_INTERP)>
1052 Creates a new Parrot STRING hash.
1059 PARROT_CANNOT_RETURN_NULL
1061 parrot_new_hash(PARROT_INTERP
)
1063 ASSERT_ARGS(parrot_new_hash
)
1064 return parrot_create_hash(interp
,
1066 Hash_key_type_STRING
);
1072 =item C<Hash* parrot_new_cstring_hash(PARROT_INTERP)>
1074 Creates a new C string hash in C<hptr>.
1081 PARROT_CANNOT_RETURN_NULL
1083 parrot_new_cstring_hash(PARROT_INTERP
)
1085 ASSERT_ARGS(parrot_new_cstring_hash
)
1086 return parrot_create_hash(interp
,
1088 Hash_key_type_cstring
);
1094 =item C<Hash * parrot_new_pointer_hash(PARROT_INTERP)>
1096 Create and return a new hash with void * keys and values.
1103 PARROT_CANNOT_RETURN_NULL
1105 parrot_new_pointer_hash(PARROT_INTERP
)
1107 ASSERT_ARGS(parrot_new_pointer_hash
)
1108 return parrot_create_hash(interp
,
1116 =item C<Hash* parrot_new_intval_hash(PARROT_INTERP)>
1118 Creates and returns new Hash PMC with INTVAL keys and values. C<flags> can be
1119 C<PObj_constant_FLAG> or 0.
1127 PARROT_WARN_UNUSED_RESULT
1128 PARROT_CANNOT_RETURN_NULL
1130 parrot_new_intval_hash(PARROT_INTERP
)
1132 ASSERT_ARGS(parrot_new_intval_hash
)
1133 return parrot_create_hash(interp
,
1140 =item C<Hash * parrot_create_hash(PARROT_INTERP, PARROT_DATA_TYPE val_type,
1141 Hash_key_type hkey_type)>
1143 Creates and initializes a hash. Function pointers determine its behaviors.
1145 Memory from this function must be freed.
1151 PARROT_CANNOT_RETURN_NULL
1152 PARROT_WARN_UNUSED_RESULT
1155 parrot_create_hash(PARROT_INTERP
, PARROT_DATA_TYPE val_type
, Hash_key_type hkey_type
)
1157 ASSERT_ARGS(parrot_create_hash
)
1158 return parrot_create_hash_sized(interp
, val_type
, hkey_type
, INITIAL_SIZE
);
1164 =item C<static UINTVAL round_up_pow2(UINTVAL x)>
1166 Round a value up to the nearest power of 2.
1174 round_up_pow2(UINTVAL x
) {
1184 =item C<Hash * parrot_create_hash_sized(PARROT_INTERP, PARROT_DATA_TYPE
1185 val_type, Hash_key_type hkey_type, UINTVAL size)>
1187 Creates and initializes a hash, similar to C<parrot_create_hash>.
1189 Preallocates at least C<size> buckets.
1195 PARROT_CANNOT_RETURN_NULL
1196 PARROT_WARN_UNUSED_RESULT
1199 parrot_create_hash_sized(PARROT_INTERP
, PARROT_DATA_TYPE val_type
, Hash_key_type hkey_type
,
1202 ASSERT_ARGS(parrot_create_hash_sized
)
1203 UINTVAL initial_buckets
= size
> INITIAL_SIZE
? round_up_pow2(size
) : INITIAL_SIZE
;
1205 void *alloc
= Parrot_gc_allocate_memory_chunk_with_interior_pointers(
1206 interp
, sizeof (Hash
) + HASH_ALLOC_SIZE(initial_buckets
));
1207 Hash
* const hash
= (Hash
*)alloc
;
1210 PARROT_ASSERT(initial_buckets
% 4 == 0);
1212 hash
->entry_type
= val_type
;
1213 hash
->key_type
= hkey_type
;
1214 hash
->seed
= interp
->hash_seed
;
1215 hash
->mask
= initial_buckets
- 1;
1218 bp
= (HashBucket
*)((char *)alloc
+ sizeof (Hash
));
1219 hash
->free_list
= NULL
;
1221 /* fill free_list from hi addresses so that we can use
1222 * buckets[i] directly in an OrderedHash, *if* nothing
1226 bp
+= N_BUCKETS(initial_buckets
);
1227 hash
->index
= (HashBucket
**)bp
;
1229 for (i
= 0, --bp
; i
< N_BUCKETS(initial_buckets
); ++i
, --bp
) {
1230 bp
->next
= hash
->free_list
;
1231 hash
->free_list
= bp
;
1239 =item C<void parrot_hash_destroy(PARROT_INTERP, Hash *hash)>
1241 Frees the memory allocated to the specified hash and its bucket store. Used by
1242 parrot_chash_destroy.
1244 Unlike the C library function free(), the hash function must not be NULL.
1252 parrot_hash_destroy(PARROT_INTERP
, ARGFREE_NOTNULL(Hash
*hash
))
1254 ASSERT_ARGS(parrot_hash_destroy
)
1255 HashBucket
* const bp
= (HashBucket
*)((char*)hash
+ sizeof (Hash
));
1256 if (bp
!= hash
->buckets
)
1257 mem_gc_free(interp
, hash
->buckets
);
1258 mem_gc_free(interp
, hash
);
1264 =item C<void parrot_chash_destroy(PARROT_INTERP, Hash *hash)>
1266 Deletes the specified hash by freeing the memory allocated to all the key-value
1267 pairs, and finally the hash itself.
1274 parrot_chash_destroy(PARROT_INTERP
, ARGMOD(Hash
*hash
))
1276 ASSERT_ARGS(parrot_chash_destroy
)
1277 parrot_hash_iterate(hash
,
1278 mem_gc_free(interp
, _bucket
->key
);
1279 mem_gc_free(interp
, _bucket
->value
););
1280 parrot_hash_destroy(interp
, hash
);
1286 =item C<void parrot_chash_destroy_values(PARROT_INTERP, Hash *hash, value_free
1289 Deletes the specified hash by freeing the memory allocated to all the key-value
1290 pairs, calling the provided callback to free the values, and finally the hash
1293 The callback returns C<void> and takes a C<void *>.
1300 parrot_chash_destroy_values(PARROT_INTERP
, ARGMOD(Hash
*hash
), NOTNULL(value_free func
))
1302 ASSERT_ARGS(parrot_chash_destroy_values
)
1305 parrot_hash_iterate(hash
,
1306 mem_gc_free(interp
, _bucket
->key
);
1307 func(_bucket
->value
););
1309 parrot_hash_destroy(interp
, hash
);
1315 =item C<INTVAL parrot_hash_size(PARROT_INTERP, const Hash *hash)>
1317 Returns the number of used entries in the hash.
1324 PARROT_WARN_UNUSED_RESULT
1325 PARROT_PURE_FUNCTION
1327 parrot_hash_size(SHIM_INTERP
, ARGIN(const Hash
*hash
))
1329 ASSERT_ARGS(parrot_hash_size
)
1331 return hash
->entries
;
1337 =item C<HashBucket * parrot_hash_get_bucket(PARROT_INTERP, const Hash *hash,
1340 Returns the bucket for C<key>, if found, and NULL otherwise.
1347 PARROT_WARN_UNUSED_RESULT
1348 PARROT_CAN_RETURN_NULL
1350 parrot_hash_get_bucket(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN_NULLOK(const void *key
))
1352 ASSERT_ARGS(parrot_hash_get_bucket
)
1356 if (hash
->entries
<= 0)
1359 if (hash
->key_type
== Hash_key_type_STRING
) {
1360 STRING
* const s
= (STRING
*)PARROT_const_cast(void *, key
);
1361 const size_t hashval
= key_hash_STRING(interp
, s
, hash
->seed
);
1363 bucket
= hash
->index
[hashval
& hash
->mask
];
1366 const STRING
*s2
= (const STRING
*)bucket
->key
;
1370 /* manually inline part of string_equal */
1371 if (hashval
== s2
->hashval
) {
1372 if (s
->encoding
== s2
->encoding
){
1373 if ((STRING_byte_length(s
) == STRING_byte_length(s2
))
1374 && (memcmp(s
->strstart
, s2
->strstart
, STRING_byte_length(s
)) == 0))
1376 } else if (STRING_equal(interp
, s
, s2
))
1380 bucket
= bucket
->next
;
1384 const size_t hashval
= key_hash(interp
, hash
,
1385 PARROT_const_cast(void *, key
));
1386 bucket
= hash
->index
[hashval
& hash
->mask
];
1389 if (hash_compare(interp
, hash
,
1390 PARROT_const_cast(void *, key
),
1393 bucket
= bucket
->next
;
1402 =item C<void * parrot_hash_get(PARROT_INTERP, const Hash *hash, const void
1405 Returns the value keyed by C<key>, or C<NULL> if no bucket is found.
1412 PARROT_WARN_UNUSED_RESULT
1413 PARROT_CAN_RETURN_NULL
1415 parrot_hash_get(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN(const void *key
))
1417 ASSERT_ARGS(parrot_hash_get
)
1418 const HashBucket
* const bucket
= parrot_hash_get_bucket(interp
, hash
, key
);
1419 return bucket
? bucket
->value
: NULL
;
1425 =item C<INTVAL parrot_hash_exists(PARROT_INTERP, const Hash *hash, void *key)>
1427 Returns whether the key exists in the hash.
1434 PARROT_WARN_UNUSED_RESULT
1436 parrot_hash_exists(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN(void *key
))
1438 ASSERT_ARGS(parrot_hash_exists
)
1439 const HashBucket
* const bucket
= parrot_hash_get_bucket(interp
, hash
, key
);
1440 return bucket
? 1 : 0;
1446 =item C<HashBucket* parrot_hash_put(PARROT_INTERP, Hash *hash, void *key, void
1449 Puts the key and value into the hash. Note that C<key> is B<not> copied.
1456 PARROT_IGNORABLE_RESULT
1457 PARROT_CANNOT_RETURN_NULL
1459 parrot_hash_put(PARROT_INTERP
, ARGMOD(Hash
*hash
),
1460 ARGIN_NULLOK(void *key
), ARGIN_NULLOK(void *value
))
1462 ASSERT_ARGS(parrot_hash_put
)
1466 if (hash
->key_type
== Hash_key_type_STRING
) {
1467 const STRING
* const s
= (STRING
*)key
;
1468 hashval
= key_hash_STRING(interp
, (STRING
*)key
, hash
->seed
);
1469 bucket
= hash
->index
[hashval
& hash
->mask
];
1472 const STRING
*s2
= (const STRING
*)bucket
->key
;
1475 /* manually inline part of string_equal */
1476 if (hashval
== s2
->hashval
) {
1477 if (s
->encoding
== s2
->encoding
) {
1478 if ((STRING_byte_length(s
) == STRING_byte_length(s2
))
1479 && (memcmp(s
->strstart
, s2
->strstart
, STRING_byte_length(s
)) == 0))
1481 } else if (STRING_equal(interp
, s
, s2
))
1484 bucket
= bucket
->next
;
1488 hashval
= key_hash(interp
, hash
, key
);
1489 bucket
= hash
->index
[hashval
& hash
->mask
];
1492 if (hash_compare(interp
, hash
, key
, bucket
->key
) == 0)
1494 bucket
= bucket
->next
;
1498 /* If we have a bucket already, put the value in it. Otherwise, we need
1499 to get a new bucket */
1501 bucket
->value
= value
;
1503 /* Get a new bucket off the free list. If the free list is empty, we
1504 expand the hash so we get more items on the free list */
1505 if (!hash
->free_list
)
1506 expand_hash(interp
, hash
);
1508 bucket
= hash
->free_list
;
1510 /* Add the value to the new bucket, increasing the count of elements */
1512 hash
->free_list
= bucket
->next
;
1514 bucket
->value
= value
;
1515 bucket
->next
= hash
->index
[hashval
& hash
->mask
];
1516 hash
->index
[hashval
& hash
->mask
] = bucket
;
1525 =item C<void parrot_hash_delete(PARROT_INTERP, Hash *hash, void *key)>
1527 Deletes the key from the hash.
1535 parrot_hash_delete(PARROT_INTERP
, ARGMOD(Hash
*hash
), ARGIN(void *key
))
1537 ASSERT_ARGS(parrot_hash_delete
)
1538 const UINTVAL hashval
= key_hash(interp
, hash
, key
) & hash
->mask
;
1539 HashBucket
**prev
= &hash
->index
[hashval
];
1541 for (; *prev
; prev
= &(*prev
)->next
) {
1542 HashBucket
*current
= *prev
;
1543 if (hash_compare(interp
, hash
, key
, current
->key
) == 0) {
1544 *prev
= current
->next
;
1546 current
->next
= hash
->free_list
;
1547 current
->key
= NULL
;
1548 hash
->free_list
= current
;
1558 =item C<void parrot_hash_clone(PARROT_INTERP, const Hash *hash, Hash *dest)>
1560 Clones C<hash> to C<dest>.
1568 parrot_hash_clone(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGOUT(Hash
*dest
))
1570 ASSERT_ARGS(parrot_hash_clone
)
1571 parrot_hash_clone_prunable(interp
, hash
, dest
, 1);
1576 =item C<void parrot_hash_clone_prunable(PARROT_INTERP, const Hash *hash, Hash
1579 helper function to Clone C<hash> to C<dest>
1581 allows deep cloning of PMC types if deep set
1588 parrot_hash_clone_prunable(PARROT_INTERP
, ARGIN(const Hash
*hash
),
1589 ARGOUT(Hash
*dest
), int deep
)
1591 ASSERT_ARGS(parrot_hash_clone_prunable
)
1593 parrot_hash_iterate(hash
,
1595 void * const key
= _bucket
->key
;
1597 switch (hash
->entry_type
) {
1598 case enum_type_STRING
:
1599 valtmp
= _bucket
->value
;
1603 if (PMC_IS_NULL((PMC
*)_bucket
->value
))
1604 valtmp
= (void *)PMCNULL
;
1607 valtmp
= (void *)VTABLE_clone(interp
, (PMC
*)_bucket
->value
);
1609 valtmp
= _bucket
->value
;
1612 case enum_type_undef
:
1614 case enum_type_INTVAL
:
1615 valtmp
= (void *)_bucket
->value
;
1619 valtmp
= NULL
; /* avoid warning */
1620 Parrot_ex_throw_from_c_args(interp
, NULL
, -1,
1621 "hash corruption: type = %d\n", hash
->entry_type
);
1624 parrot_hash_put(interp
, dest
, key
, valtmp
););
1629 =item C<static PMC* get_integer_pmc(PARROT_INTERP, INTVAL value)>
1631 Lookup the PMC type which is used for storing native integers.
1637 PARROT_CANNOT_RETURN_NULL
1639 get_integer_pmc(PARROT_INTERP
, INTVAL value
)
1641 ASSERT_ARGS(get_integer_pmc
)
1642 PMC
* const ret
= Parrot_pmc_new(interp
, Parrot_get_ctx_HLL_type(interp
, enum_class_Integer
));
1643 VTABLE_set_integer_native(interp
, ret
, value
);
1650 =item C<static PMC* get_number_pmc(PARROT_INTERP, FLOATVAL value)>
1652 Lookup the PMC type which is used for floating point numbers.
1658 PARROT_CANNOT_RETURN_NULL
1660 get_number_pmc(PARROT_INTERP
, FLOATVAL value
)
1662 ASSERT_ARGS(get_number_pmc
)
1663 PMC
* const ret
= Parrot_pmc_new(interp
, Parrot_get_ctx_HLL_type(interp
, enum_class_Float
));
1664 VTABLE_set_number_native(interp
, ret
, value
);
1670 =item C<static PMC * get_string_pmc(PARROT_INTERP, STRING *value)>
1672 Lookup the PMC type which is used for storing strings.
1678 PARROT_CANNOT_RETURN_NULL
1680 get_string_pmc(PARROT_INTERP
, ARGIN(STRING
*value
))
1682 ASSERT_ARGS(get_string_pmc
)
1683 PMC
* const ret
= Parrot_pmc_new(interp
, Parrot_get_ctx_HLL_type(interp
, enum_class_String
));
1684 VTABLE_set_string_native(interp
, ret
, value
);
1691 Poor-man polymorphic functions to convert something to something.
1693 There is bunch of functions to convert from passed value to stored keys type and to/from
1696 void *hash_key_from_TYPE convert to keys type.
1697 TYPE hash_key_to_TYPE convert from keys type.
1698 void *hash_value_from_TYPE convert to values type.
1699 TYPE hash_value_to_TYPE convert from values type.
1705 =item C<void* hash_key_from_int(PARROT_INTERP, const Hash *hash, INTVAL key)>
1707 Cast INTVAL to hash key.
1713 PARROT_CAN_RETURN_NULL
1715 hash_key_from_int(PARROT_INTERP
, ARGIN(const Hash
*hash
), INTVAL key
)
1717 ASSERT_ARGS(hash_key_from_int
)
1719 switch (hash
->key_type
) {
1720 case Hash_key_type_int
:
1723 /* Currently PMCs are stringified */
1724 case Hash_key_type_PMC
:
1725 case Hash_key_type_PMC_ptr
:
1726 ret
= (void *)get_integer_pmc(interp
, key
);
1728 case Hash_key_type_STRING
:
1729 case Hash_key_type_STRING_enc
:
1730 ret
= (void *)Parrot_str_from_int(interp
, key
);
1733 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
1734 "Hash: unsupported key_type");
1741 =item C<void* hash_key_from_string(PARROT_INTERP, const Hash *hash, STRING
1744 Cast STRING to hash key.
1750 PARROT_CAN_RETURN_NULL
1752 hash_key_from_string(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN(STRING
*key
))
1754 ASSERT_ARGS(hash_key_from_string
)
1756 switch (hash
->key_type
) {
1757 case Hash_key_type_int
:
1759 /* Pacify compiler about casting INVTAL to void */
1760 const INTVAL int_key
= Parrot_str_to_int(interp
, key
);
1761 ret
= INTVAL2PTR(void *, int_key
);
1765 case Hash_key_type_PMC
:
1766 case Hash_key_type_PMC_ptr
:
1767 ret
= get_string_pmc(interp
, key
);
1770 case Hash_key_type_STRING
:
1771 case Hash_key_type_STRING_enc
:
1776 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
1777 "Hash: unsupported key_type");
1784 =item C<void* hash_key_from_pmc(PARROT_INTERP, const Hash *hash, PMC *key)>
1786 Cast PMC* to hash key.
1792 PARROT_CAN_RETURN_NULL
1794 hash_key_from_pmc(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN(PMC
*key
))
1796 ASSERT_ARGS(hash_key_from_pmc
)
1798 switch (hash
->key_type
) {
1799 case Hash_key_type_int
:
1801 const INTVAL int_key
= VTABLE_get_integer(interp
, key
);
1802 ret
= INTVAL2PTR(void *, int_key
);
1805 case Hash_key_type_PMC
:
1806 case Hash_key_type_PMC_ptr
:
1808 /* Extract real value from Key (and box it if nessary) */
1809 if (key
->vtable
->base_type
== enum_class_Key
)
1810 switch (key_type(interp
, key
)) {
1811 case KEY_integer_FLAG
:
1812 key
= get_integer_pmc(interp
, key_integer(interp
, key
));
1814 case KEY_string_FLAG
:
1815 key
= get_string_pmc(interp
, key_string(interp
, key
));
1817 case KEY_number_FLAG
:
1818 key
= get_number_pmc(interp
, key_number(interp
, key
));
1821 key
= key_pmc(interp
, key
);
1824 /* It's impossible if Keys are same (and they are not) */
1825 /* So throw exception */
1826 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_INVALID_OPERATION
,
1827 "hash: unexpected type of Key");
1834 case Hash_key_type_STRING
:
1835 case Hash_key_type_STRING_enc
:
1837 STRING
* const tmp
= VTABLE_get_string(interp
, key
);
1838 if (STRING_IS_NULL(tmp
))
1839 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNEXPECTED_NULL
,
1840 "hash: can't use null as key");
1845 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
1846 "Hash: unsupported key_type");
1853 =item C<INTVAL hash_key_to_int(PARROT_INTERP, const Hash *hash, void *key)>
1855 Cast hash key to INTVAL.
1862 hash_key_to_int(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN_NULLOK(void *key
))
1864 ASSERT_ARGS(hash_key_to_int
)
1866 switch (hash
->key_type
) {
1867 case Hash_key_type_int
:
1870 case Hash_key_type_PMC
:
1871 case Hash_key_type_PMC_ptr
:
1872 ret
= VTABLE_get_integer(interp
, (PMC
*)key
);
1874 case Hash_key_type_STRING
:
1875 case Hash_key_type_STRING_enc
:
1876 ret
= Parrot_str_to_int(interp
, (STRING
*)key
);
1879 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
1880 "Hash: unsupported key_type");
1887 =item C<STRING* hash_key_to_string(PARROT_INTERP, const Hash *hash, void *key)>
1889 Cast hash key to STRING.
1895 PARROT_CANNOT_RETURN_NULL
1897 hash_key_to_string(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN_NULLOK(void *key
))
1899 ASSERT_ARGS(hash_key_to_string
)
1901 switch (hash
->key_type
) {
1902 case Hash_key_type_int
:
1903 ret
= Parrot_str_from_int(interp
, (INTVAL
)key
);
1906 case Hash_key_type_PMC
:
1907 case Hash_key_type_PMC_ptr
:
1908 ret
= VTABLE_get_string(interp
, (PMC
*)key
);
1911 case Hash_key_type_STRING
:
1912 case Hash_key_type_STRING_enc
:
1913 ret
= (STRING
*)key
;
1917 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
1918 "Hash: unsupported key_type");
1925 =item C<PMC* hash_key_to_pmc(PARROT_INTERP, const Hash * const hash, void *key)>
1927 Cast hash key to PMC*.
1933 PARROT_CANNOT_RETURN_NULL
1935 hash_key_to_pmc(PARROT_INTERP
, ARGIN(const Hash
* const hash
), ARGIN(void *key
))
1937 ASSERT_ARGS(hash_key_to_pmc
)
1939 switch (hash
->key_type
) {
1940 case Hash_key_type_int
:
1941 ret
= get_integer_pmc(interp
, (INTVAL
)key
);
1943 case Hash_key_type_PMC
:
1944 case Hash_key_type_PMC_ptr
:
1947 case Hash_key_type_STRING
:
1948 case Hash_key_type_STRING_enc
:
1949 ret
= get_string_pmc(interp
, (STRING
*)key
);
1952 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
1953 "Hash: unsupported key_type");
1958 /* Second part - convert from stored void* to real type */
1959 /* TODO: FLOATVALs converted into Float PMC for now */
1963 =item C<void* hash_value_from_int(PARROT_INTERP, const Hash *hash, INTVAL
1966 Cast INTVAL to hash value.
1972 PARROT_CAN_RETURN_NULL
1974 hash_value_from_int(PARROT_INTERP
, ARGIN(const Hash
*hash
), INTVAL value
)
1976 ASSERT_ARGS(hash_value_from_int
)
1978 switch (hash
->entry_type
) {
1979 case enum_type_INTVAL
:
1980 ret
= INTVAL2PTR(void *, value
);
1984 PMC
* const tmp
= get_integer_pmc(interp
, value
);
1988 case enum_type_STRING
:
1989 ret
= (void *)Parrot_str_from_int(interp
, value
);
1992 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
1993 "Hash: unsupported entry_type");
2000 =item C<void* hash_value_from_string(PARROT_INTERP, const Hash *hash, STRING
2003 Cast STRING to hash value.
2009 PARROT_CAN_RETURN_NULL
2011 hash_value_from_string(PARROT_INTERP
, ARGIN(const Hash
*hash
),
2012 ARGIN_NULLOK(STRING
*value
))
2014 ASSERT_ARGS(hash_value_from_string
)
2016 switch (hash
->entry_type
) {
2017 case enum_type_INTVAL
:
2019 const INTVAL int_val
= STRING_IS_NULL(value
) ?
2020 (INTVAL
) 0 : Parrot_str_to_int(interp
, value
);
2021 ret
= INTVAL2PTR(void *, int_val
);
2024 case enum_type_STRING
:
2025 ret
= (void *)value
;
2029 PMC
* const s
= STRING_IS_NULL(value
) ?
2030 PMCNULL
: get_string_pmc(interp
, value
);
2035 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
2036 "Hash: unsupported entry_type");
2043 =item C<void* hash_value_from_pmc(PARROT_INTERP, const Hash *hash, PMC *value)>
2045 Cast PMC to hash value.
2051 PARROT_CAN_RETURN_NULL
2053 hash_value_from_pmc(PARROT_INTERP
, ARGIN(const Hash
*hash
),
2054 ARGIN_NULLOK(PMC
*value
))
2056 ASSERT_ARGS(hash_value_from_pmc
)
2058 switch (hash
->entry_type
) {
2059 case enum_type_INTVAL
:
2061 const INTVAL int_val
= PMC_IS_NULL(value
) ?
2062 (INTVAL
) 0 : VTABLE_get_integer(interp
, value
);
2063 ret
= INTVAL2PTR(void *, int_val
);
2066 case enum_type_STRING
:
2067 ret
= PMC_IS_NULL(value
) ?
2068 PMCNULL
: (void *)VTABLE_get_string(interp
, value
);
2071 ret
= (void *)value
;
2074 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
2075 "Hash: unsupported entry_type");
2082 =item C<void* hash_value_from_number(PARROT_INTERP, const Hash *hash, FLOATVAL
2085 Cast FLOATVAL to hash value.
2091 PARROT_CAN_RETURN_NULL
2093 hash_value_from_number(PARROT_INTERP
, ARGIN(const Hash
*hash
), FLOATVAL value
)
2095 ASSERT_ARGS(hash_value_from_number
)
2097 switch (hash
->entry_type
) {
2098 case enum_type_INTVAL
:
2100 const INTVAL tmp
= value
;
2104 case enum_type_STRING
:
2105 ret
= (void *)Parrot_str_from_num(interp
, value
);
2109 PMC
* const tmp
= get_number_pmc(interp
, value
);
2114 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
2115 "Hash: unsupported entry_type");
2122 =item C<INTVAL hash_value_to_int(PARROT_INTERP, const Hash *hash, void *value)>
2124 Cast hash value to INTVAL.
2131 hash_value_to_int(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN_NULLOK(void *value
))
2133 ASSERT_ARGS(hash_value_to_int
)
2135 switch (hash
->entry_type
) {
2137 case enum_type_INTVAL
:
2138 ret
= (INTVAL
)value
;
2140 case enum_type_STRING
:
2141 ret
= Parrot_str_to_int(interp
, (STRING
*)value
);
2144 ret
= VTABLE_get_integer(interp
, (PMC
*)value
);
2147 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
2148 "Hash: unsupported entry_type");
2155 =item C<STRING* hash_value_to_string(PARROT_INTERP, const Hash *hash, void
2158 Cast hash value to STRING.
2164 PARROT_CANNOT_RETURN_NULL
2166 hash_value_to_string(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN_NULLOK(void *value
))
2168 ASSERT_ARGS(hash_value_to_string
)
2170 switch (hash
->entry_type
) {
2171 case enum_type_INTVAL
:
2172 ret
= Parrot_str_from_int(interp
, (INTVAL
)value
);
2174 case enum_type_STRING
:
2175 ret
= (STRING
*)value
;
2178 ret
= VTABLE_get_string(interp
, (PMC
*)value
);
2181 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
2182 "Hash: unsupported entry_type");
2189 =item C<PMC* hash_value_to_pmc(PARROT_INTERP, const Hash *hash, void *value)>
2191 Cast hash value to PMC.
2197 PARROT_CANNOT_RETURN_NULL
2199 hash_value_to_pmc(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN_NULLOK(void *value
))
2201 ASSERT_ARGS(hash_value_to_pmc
)
2203 switch (hash
->entry_type
) {
2204 case enum_type_INTVAL
:
2205 ret
= get_integer_pmc(interp
, (INTVAL
)value
);
2207 case enum_type_STRING
:
2208 ret
= get_string_pmc(interp
, (STRING
*)value
);
2214 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
2215 "Hash: unsupported entry_type");
2222 =item C<FLOATVAL hash_value_to_number(PARROT_INTERP, const Hash *hash, void
2225 Cast hash value to FLOATVAL.
2232 hash_value_to_number(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN_NULLOK(void *value
))
2234 ASSERT_ARGS(hash_value_to_number
)
2236 switch (hash
->entry_type
) {
2237 case enum_type_INTVAL
:
2239 /* Pacify compiler about casting */
2240 const INTVAL tmp
= (INTVAL
)value
;
2244 case enum_type_STRING
:
2245 ret
= Parrot_str_to_num(interp
, (STRING
*)value
);
2248 ret
= VTABLE_get_number(interp
, (PMC
*)value
);
2251 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
2252 "Hash: unsupported entry_type");
2263 F<docs/pdds/pdd08_keys.pod>.
2267 Future optimizations:
2271 =item * Stop reallocating the bucket pool, and instead add chunks on.
2272 (Saves pointer fixups and copying during C<realloc>.)
2274 =item * Hash contraction (don't if it's worth it)
2285 * c-file-style: "parrot"
2287 * vim: expandtab shiftwidth=4: