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 */
32 /* hash first allocation size */
33 #define INITIAL_SIZE 2
35 /* below this hash size we use fixed_size_allocator
36 * else we use system allocator */
37 #define SPLIT_POINT 16
39 /* HEADERIZER HFILE: include/parrot/hash.h */
41 /* HEADERIZER BEGIN: static */
42 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
44 static void allocate_buckets(PARROT_INTERP
,
46 ARGIN_NULLOK(const UINTVAL size
))
47 __attribute__nonnull__(1)
48 __attribute__nonnull__(2)
51 static void expand_hash(PARROT_INTERP
, ARGMOD(Hash
*hash
))
52 __attribute__nonnull__(1)
53 __attribute__nonnull__(2)
56 PARROT_CANNOT_RETURN_NULL
57 static PMC
* get_integer_pmc(PARROT_INTERP
, INTVAL value
)
58 __attribute__nonnull__(1);
60 PARROT_CANNOT_RETURN_NULL
61 static PMC
* get_number_pmc(PARROT_INTERP
, FLOATVAL value
)
62 __attribute__nonnull__(1);
64 PARROT_CANNOT_RETURN_NULL
65 static PMC
* get_string_pmc(PARROT_INTERP
, ARGIN(STRING
*value
))
66 __attribute__nonnull__(1)
67 __attribute__nonnull__(2);
69 PARROT_WARN_UNUSED_RESULT
72 static int hash_compare(PARROT_INTERP
,
73 ARGIN(const Hash
*hash
),
74 ARGIN_NULLOK(void *a
),
75 ARGIN_NULLOK(void *b
))
76 __attribute__nonnull__(1)
77 __attribute__nonnull__(2);
79 PARROT_WARN_UNUSED_RESULT
82 static int hash_compare_cstring(SHIM_INTERP
,
85 __attribute__nonnull__(2)
86 __attribute__nonnull__(3);
88 PARROT_WARN_UNUSED_RESULT
91 static int hash_compare_int(SHIM_INTERP
,
92 ARGIN_NULLOK(const void *a
),
93 ARGIN_NULLOK(const void *b
));
95 PARROT_WARN_UNUSED_RESULT
98 static int hash_compare_pmc(PARROT_INTERP
, ARGIN(PMC
*a
), ARGIN(PMC
*b
))
99 __attribute__nonnull__(1)
100 __attribute__nonnull__(2)
101 __attribute__nonnull__(3);
103 PARROT_WARN_UNUSED_RESULT
106 static int hash_compare_pointer(SHIM_INTERP
,
107 ARGIN_NULLOK(const void *a
),
108 ARGIN_NULLOK(const void *b
));
110 PARROT_WARN_UNUSED_RESULT
113 static int hash_compare_string(PARROT_INTERP
,
114 ARGIN(const void *search_key
),
115 ARGIN_NULLOK(const void *bucket_key
))
116 __attribute__nonnull__(1)
117 __attribute__nonnull__(2);
119 PARROT_WARN_UNUSED_RESULT
120 static int hash_compare_string_enc(PARROT_INTERP
,
121 ARGIN(const void *search_key
),
122 ARGIN(const void *bucket_key
))
123 __attribute__nonnull__(1)
124 __attribute__nonnull__(2)
125 __attribute__nonnull__(3);
127 PARROT_WARN_UNUSED_RESULT
130 static size_t key_hash(PARROT_INTERP
,
131 ARGIN(const Hash
*hash
),
132 ARGIN_NULLOK(void *key
))
133 __attribute__nonnull__(1)
134 __attribute__nonnull__(2);
136 PARROT_WARN_UNUSED_RESULT
139 static size_t key_hash_cstring(SHIM_INTERP
,
140 ARGIN(const void *value
),
142 __attribute__nonnull__(2);
144 PARROT_WARN_UNUSED_RESULT
147 static size_t key_hash_int(SHIM_INTERP
,
148 ARGIN_NULLOK(const void *value
),
151 PARROT_WARN_UNUSED_RESULT
154 static size_t key_hash_PMC(PARROT_INTERP
,
157 __attribute__nonnull__(1)
158 __attribute__nonnull__(2);
160 PARROT_WARN_UNUSED_RESULT
163 static size_t key_hash_pointer(SHIM_INTERP
,
164 ARGIN(const void *value
),
166 __attribute__nonnull__(2);
168 PARROT_WARN_UNUSED_RESULT
171 static size_t key_hash_STRING(PARROT_INTERP
, ARGMOD(STRING
*s
), size_t seed
)
172 __attribute__nonnull__(1)
173 __attribute__nonnull__(2)
176 static void parrot_mark_hash_both(PARROT_INTERP
, ARGIN(Hash
*hash
))
177 __attribute__nonnull__(1)
178 __attribute__nonnull__(2);
180 static void parrot_mark_hash_keys(PARROT_INTERP
, ARGIN(Hash
*hash
))
181 __attribute__nonnull__(1)
182 __attribute__nonnull__(2);
184 static void parrot_mark_hash_values(PARROT_INTERP
, ARGIN(Hash
*hash
))
185 __attribute__nonnull__(1)
186 __attribute__nonnull__(2);
188 #define ASSERT_ARGS_allocate_buckets __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
189 PARROT_ASSERT_ARG(interp) \
190 , PARROT_ASSERT_ARG(hash))
191 #define ASSERT_ARGS_expand_hash __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
192 PARROT_ASSERT_ARG(interp) \
193 , PARROT_ASSERT_ARG(hash))
194 #define ASSERT_ARGS_get_integer_pmc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
195 PARROT_ASSERT_ARG(interp))
196 #define ASSERT_ARGS_get_number_pmc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
197 PARROT_ASSERT_ARG(interp))
198 #define ASSERT_ARGS_get_string_pmc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
199 PARROT_ASSERT_ARG(interp) \
200 , PARROT_ASSERT_ARG(value))
201 #define ASSERT_ARGS_hash_compare __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
202 PARROT_ASSERT_ARG(interp) \
203 , PARROT_ASSERT_ARG(hash))
204 #define ASSERT_ARGS_hash_compare_cstring __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
205 PARROT_ASSERT_ARG(a) \
206 , PARROT_ASSERT_ARG(b))
207 #define ASSERT_ARGS_hash_compare_int __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
208 #define ASSERT_ARGS_hash_compare_pmc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
209 PARROT_ASSERT_ARG(interp) \
210 , PARROT_ASSERT_ARG(a) \
211 , PARROT_ASSERT_ARG(b))
212 #define ASSERT_ARGS_hash_compare_pointer __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
213 #define ASSERT_ARGS_hash_compare_string __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
214 PARROT_ASSERT_ARG(interp) \
215 , PARROT_ASSERT_ARG(search_key))
216 #define ASSERT_ARGS_hash_compare_string_enc __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
217 PARROT_ASSERT_ARG(interp) \
218 , PARROT_ASSERT_ARG(search_key) \
219 , PARROT_ASSERT_ARG(bucket_key))
220 #define ASSERT_ARGS_key_hash __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
221 PARROT_ASSERT_ARG(interp) \
222 , PARROT_ASSERT_ARG(hash))
223 #define ASSERT_ARGS_key_hash_cstring __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
224 PARROT_ASSERT_ARG(value))
225 #define ASSERT_ARGS_key_hash_int __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
226 #define ASSERT_ARGS_key_hash_PMC __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
227 PARROT_ASSERT_ARG(interp) \
228 , PARROT_ASSERT_ARG(value))
229 #define ASSERT_ARGS_key_hash_pointer __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
230 PARROT_ASSERT_ARG(value))
231 #define ASSERT_ARGS_key_hash_STRING __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
232 PARROT_ASSERT_ARG(interp) \
233 , PARROT_ASSERT_ARG(s))
234 #define ASSERT_ARGS_parrot_mark_hash_both __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
235 PARROT_ASSERT_ARG(interp) \
236 , PARROT_ASSERT_ARG(hash))
237 #define ASSERT_ARGS_parrot_mark_hash_keys __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
238 PARROT_ASSERT_ARG(interp) \
239 , PARROT_ASSERT_ARG(hash))
240 #define ASSERT_ARGS_parrot_mark_hash_values __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
241 PARROT_ASSERT_ARG(interp) \
242 , PARROT_ASSERT_ARG(hash))
243 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
244 /* HEADERIZER END: static */
248 =item C<static size_t key_hash_STRING(PARROT_INTERP, STRING *s, size_t seed)>
250 Returns the hashed value of the key C<value>. See also string.c.
257 PARROT_WARN_UNUSED_RESULT
261 key_hash_STRING(PARROT_INTERP
, ARGMOD(STRING
*s
), size_t seed
)
263 ASSERT_ARGS(key_hash_STRING
)
268 return Parrot_str_to_hashval(interp
, s
);
274 =item C<static int hash_compare_string(PARROT_INTERP, const void *search_key,
275 const void *bucket_key)>
277 Compares the two strings, returning 0 if they are identical.
283 PARROT_WARN_UNUSED_RESULT
287 hash_compare_string(PARROT_INTERP
, ARGIN(const void *search_key
),
288 ARGIN_NULLOK(const void *bucket_key
))
290 ASSERT_ARGS(hash_compare_string
)
291 STRING
const *s1
= (STRING
const *)search_key
;
292 STRING
const *s2
= (STRING
const *)bucket_key
;
294 return Parrot_str_equal(interp
, s1
, s2
) == 0;
300 =item C<static int hash_compare_string_enc(PARROT_INTERP, const void
301 *search_key, const void *bucket_key)>
303 Compare two strings. Returns 0 if they are identical. Considers differing
304 encodings to be distinct.
308 PARROT_WARN_UNUSED_RESULT
310 hash_compare_string_enc(PARROT_INTERP
, ARGIN(const void *search_key
),
311 ARGIN(const void *bucket_key
))
313 ASSERT_ARGS(hash_compare_string_enc
)
314 STRING
const *s1
= (STRING
const *)search_key
;
315 STRING
const *s2
= (STRING
const *)bucket_key
;
317 if (s1
->hashval
!= s2
->hashval
)
319 if (s1
&& s2
&& s1
->encoding
!= s2
->encoding
)
322 return memcmp(s1
->strstart
, s2
->strstart
, s1
->bufused
);
328 =item C<static int hash_compare_pointer(PARROT_INTERP, const void *a, const void
331 Compares the two pointers, returning 0 if they are identical
337 PARROT_WARN_UNUSED_RESULT
341 hash_compare_pointer(SHIM_INTERP
, ARGIN_NULLOK(const void *a
), ARGIN_NULLOK(const void *b
))
343 ASSERT_ARGS(hash_compare_pointer
)
350 =item C<static size_t key_hash_pointer(PARROT_INTERP, const void *value, size_t
353 Returns a hashvalue for a pointer.
359 PARROT_WARN_UNUSED_RESULT
363 key_hash_pointer(SHIM_INTERP
, ARGIN(const void *value
), size_t seed
)
365 ASSERT_ARGS(key_hash_pointer
)
366 return ((size_t) value
) ^ seed
;
372 =item C<static size_t key_hash_cstring(PARROT_INTERP, const void *value, size_t
375 Creates and returns a hash value from a string.
377 Takes an interpreter, a pointer to a string, and a seed value.
378 Returns the hash value.
380 Used by parrot_new_cstring_hash.
386 PARROT_WARN_UNUSED_RESULT
390 key_hash_cstring(SHIM_INTERP
, ARGIN(const void *value
), size_t seed
)
392 ASSERT_ARGS(key_hash_cstring
)
393 const unsigned char *p
= (const unsigned char *) value
;
405 =item C<static int hash_compare_cstring(PARROT_INTERP, const char *a, const char
408 Compares two C strings for equality, returning -1, 0, and 1 if the first string
409 is less than, equal to, or greater than the second, respectively.
415 PARROT_WARN_UNUSED_RESULT
419 hash_compare_cstring(SHIM_INTERP
, ARGIN(const char *a
), ARGIN(const char *b
))
421 ASSERT_ARGS(hash_compare_cstring
)
428 =item C<static size_t key_hash_PMC(PARROT_INTERP, PMC *value, size_t seed)>
430 Returns a hashed value for an PMC key (passed as a void pointer, sadly).
436 PARROT_WARN_UNUSED_RESULT
440 key_hash_PMC(PARROT_INTERP
, ARGIN(PMC
*value
), SHIM(size_t seed
))
442 ASSERT_ARGS(key_hash_PMC
)
443 return VTABLE_hashvalue(interp
, value
);
448 =item C<static int hash_compare_pmc(PARROT_INTERP, PMC *a, PMC *b)>
450 Compares two PMC for equality, returning 0 if the first is equal to second.
451 Uses void pointers to store the PMC, sadly.
457 PARROT_WARN_UNUSED_RESULT
461 hash_compare_pmc(PARROT_INTERP
, ARGIN(PMC
*a
), ARGIN(PMC
*b
))
463 ASSERT_ARGS(hash_compare_pmc
)
465 /* If pointers are same - PMCs are same */
469 /* PMCs of different types are different */
470 if (a
->vtable
->base_type
!= b
->vtable
->base_type
)
473 return !VTABLE_is_equal(interp
, a
, b
);
478 =item C<static size_t key_hash_int(PARROT_INTERP, const void *value, size_t
481 Returns a hashed value for an integer key (passed as a void pointer, sadly).
487 PARROT_WARN_UNUSED_RESULT
491 key_hash_int(SHIM_INTERP
, ARGIN_NULLOK(const void *value
), size_t seed
)
493 ASSERT_ARGS(key_hash_int
)
494 return (size_t)value
^ seed
;
499 =item C<static int hash_compare_int(PARROT_INTERP, const void *a, const void
502 Compares two integers for equality, returning -1, 0, and 1 if the first is less
503 than, equal to, or greater than the second, respectively. Uses void pointers
504 to store the integers, sadly.
510 PARROT_WARN_UNUSED_RESULT
514 hash_compare_int(SHIM_INTERP
, ARGIN_NULLOK(const void *a
), ARGIN_NULLOK(const void *b
))
516 ASSERT_ARGS(hash_compare_int
)
522 =item C<static size_t key_hash(PARROT_INTERP, const Hash *hash, void *key)>
524 Generic function to get the hashvalue of a given key. It may dispatches to
525 key_hash_STRING, key_hash_cstring, etc. depending on hash->key_type.
532 PARROT_WARN_UNUSED_RESULT
536 key_hash(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN_NULLOK(void *key
))
538 ASSERT_ARGS(key_hash
)
540 if (hash
->key_type
== Hash_key_type_STRING
541 || hash
->key_type
== Hash_key_type_STRING_enc
)
542 return key_hash_STRING(interp
, (STRING
*)key
, hash
->seed
);
544 if (hash
->key_type
== Hash_key_type_cstring
)
545 return key_hash_cstring(interp
, (char *)key
, hash
->seed
);
547 if (hash
->key_type
== Hash_key_type_PMC
)
548 return VTABLE_hashvalue(interp
, (PMC
*)key
);
550 return ((size_t) key
) ^ hash
->seed
;
556 =item C<static int hash_compare(PARROT_INTERP, const Hash *hash, void *a, void
559 Generic function to compare values. It may dispatches to
560 hash_compare_string, hash_compare_cstring, etc. depending on hash->key_type.
567 PARROT_WARN_UNUSED_RESULT
571 hash_compare(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN_NULLOK(void *a
),
572 ARGIN_NULLOK(void *b
))
574 ASSERT_ARGS(hash_compare
)
579 if (hash
->key_type
== Hash_key_type_STRING
)
580 return hash_compare_string(interp
, (STRING
*)a
, (STRING
*)b
);
582 if (hash
->key_type
== Hash_key_type_STRING_enc
)
583 return hash_compare_string_enc(interp
, (STRING
*)a
, (STRING
*)b
);
585 if (hash
->key_type
== Hash_key_type_cstring
)
586 return strcmp((char *)a
, (char *)b
);
588 if (hash
->key_type
== Hash_key_type_PMC
)
589 return hash_compare_pmc(interp
, (PMC
*)a
, (PMC
*) b
);
596 =item C<void parrot_dump_hash(PARROT_INTERP, const Hash *hash)>
598 Prints out the hash in human-readable form, at least once someone implements
607 parrot_dump_hash(SHIM_INTERP
, SHIM(const Hash
*hash
))
609 ASSERT_ARGS(parrot_dump_hash
)
615 =item C<void parrot_mark_hash(PARROT_INTERP, Hash *hash)>
617 Marks the hash and its contents as live. Assumes that key and value are
618 non-null in all buckets.
626 parrot_mark_hash(PARROT_INTERP
, ARGMOD(Hash
*hash
))
628 ASSERT_ARGS(parrot_mark_hash
)
635 if (hash
->entry_type
== (PARROT_DATA_TYPE
) enum_hash_string
636 || hash
->entry_type
== (PARROT_DATA_TYPE
) enum_hash_pmc
)
639 if (hash
->key_type
== Hash_key_type_STRING
640 || hash
->key_type
== Hash_key_type_STRING_enc
641 || hash
->key_type
== Hash_key_type_PMC
642 || hash
->key_type
== Hash_key_type_PMC_ptr
)
647 parrot_mark_hash_both(interp
, hash
);
649 parrot_mark_hash_keys(interp
, hash
);
653 parrot_mark_hash_values(interp
, hash
);
660 =item C<static void parrot_mark_hash_keys(PARROT_INTERP, Hash *hash)>
662 Marks the hash and only its keys as live.
669 parrot_mark_hash_keys(PARROT_INTERP
, ARGIN(Hash
*hash
))
671 ASSERT_ARGS(parrot_mark_hash_keys
)
673 if (hash
->key_type
== Hash_key_type_STRING
674 || hash
->key_type
== Hash_key_type_STRING_enc
) {
675 parrot_hash_iterate(hash
,
676 PARROT_ASSERT(_bucket
->key
);
677 Parrot_gc_mark_STRING_alive(interp
, (STRING
*)_bucket
->key
););
680 parrot_hash_iterate(hash
,
681 PARROT_ASSERT(_bucket
->key
);
682 Parrot_gc_mark_PMC_alive(interp
, (PMC
*)_bucket
->key
););
689 =item C<static void parrot_mark_hash_values(PARROT_INTERP, Hash *hash)>
691 Marks the hash and only its values as live.
698 parrot_mark_hash_values(PARROT_INTERP
, ARGIN(Hash
*hash
))
700 ASSERT_ARGS(parrot_mark_hash_values
)
702 if (hash
->entry_type
== (PARROT_DATA_TYPE
) enum_hash_string
) {
703 parrot_hash_iterate(hash
,
704 PARROT_ASSERT(_bucket
->value
);
705 Parrot_gc_mark_STRING_alive(interp
, (STRING
*)_bucket
->value
););
707 else if (hash
->entry_type
== (PARROT_DATA_TYPE
) enum_hash_pmc
) {
708 parrot_hash_iterate(hash
,
709 PARROT_ASSERT(_bucket
->value
);
710 Parrot_gc_mark_PMC_alive(interp
, (PMC
*)_bucket
->value
););
717 =item C<static void parrot_mark_hash_both(PARROT_INTERP, Hash *hash)>
719 Marks the hash and both its keys and values as live.
726 parrot_mark_hash_both(PARROT_INTERP
, ARGIN(Hash
*hash
))
728 ASSERT_ARGS(parrot_mark_hash_both
)
730 if ((hash
->key_type
== Hash_key_type_STRING
731 || hash
->key_type
== Hash_key_type_STRING_enc
)
732 && hash
->entry_type
== (PARROT_DATA_TYPE
) enum_hash_pmc
) {
733 parrot_hash_iterate(hash
,
734 PARROT_ASSERT(_bucket
->key
);
735 Parrot_gc_mark_STRING_alive(interp
, (STRING
*)_bucket
->key
);
736 PARROT_ASSERT(_bucket
->value
);
737 Parrot_gc_mark_PMC_alive(interp
, (PMC
*)_bucket
->value
););
740 parrot_hash_iterate(hash
,
741 PARROT_ASSERT(_bucket
->key
);
742 Parrot_gc_mark_PObj_alive(interp
, (PObj
*)_bucket
->key
);
743 PARROT_ASSERT(_bucket
->value
);
744 Parrot_gc_mark_PObj_alive(interp
, (PObj
*)_bucket
->value
););
750 =item C<Hash * Parrot_hash_thaw(PARROT_INTERP, PMC *info)>
752 Visits the contents of a hash during freeze/thaw.
754 C<pinfo> is the visit info, (see include/parrot/pmc_freeze.h>).
760 PARROT_CANNOT_RETURN_NULL
761 PARROT_WARN_UNUSED_RESULT
763 Parrot_hash_thaw(PARROT_INTERP
, ARGMOD(PMC
*info
))
765 ASSERT_ARGS(Parrot_hash_thaw
)
767 const size_t num_entries
= VTABLE_shift_integer(interp
, info
);
768 const Hash_key_type key_type
= (Hash_key_type
)VTABLE_shift_integer(interp
, info
);
769 const PARROT_DATA_TYPE entry_type
= (PARROT_DATA_TYPE
)VTABLE_shift_integer(interp
, info
);
771 Hash
*hash
= parrot_create_hash_sized(interp
, entry_type
, key_type
, num_entries
);
773 /* special case for great speed */
774 if (key_type
== Hash_key_type_STRING
775 && entry_type
== enum_hash_int
) {
776 for (entry_index
= 0; entry_index
< num_entries
; ++entry_index
) {
777 STRING
* const key
= VTABLE_shift_string(interp
, info
);
778 const INTVAL i
= VTABLE_shift_integer(interp
, info
);
779 parrot_hash_put(interp
, hash
, (void *)key
, (void *)i
);
785 for (entry_index
= 0; entry_index
< num_entries
; ++entry_index
) {
789 case Hash_key_type_int
:
791 const INTVAL i_key
= VTABLE_shift_integer(interp
, info
);
795 case Hash_key_type_STRING
:
796 case Hash_key_type_STRING_enc
:
798 STRING
* const s_key
= VTABLE_shift_string(interp
, info
);
802 case Hash_key_type_PMC
:
803 case Hash_key_type_PMC_ptr
:
805 PMC
* const p_key
= VTABLE_shift_pmc(interp
, info
);
810 Parrot_ex_throw_from_c_args(interp
, NULL
, 1,
811 "unimplemented key type");
815 switch (entry_type
) {
818 const INTVAL i
= VTABLE_shift_integer(interp
, info
);
819 parrot_hash_put(interp
, hash
, key
, (void *)i
);
822 case enum_hash_string
:
824 STRING
* const s
= VTABLE_shift_string(interp
, info
);
825 parrot_hash_put(interp
, hash
, key
, (void *)s
);
830 PMC
* const p
= VTABLE_shift_pmc(interp
, info
);
831 parrot_hash_put(interp
, hash
, key
, (void *)p
);
835 Parrot_ex_throw_from_c_args(interp
, NULL
, 1,
836 "unimplemented value type");
847 =item C<void Parrot_hash_freeze(PARROT_INTERP, const Hash *hash, PMC *info)>
849 Freezes hash into a string.
851 Takes an interpreter, a pointer to the hash, and a pointer to the structure
852 containing the string start location.
859 Parrot_hash_freeze(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGMOD(PMC
*info
))
861 ASSERT_ARGS(Parrot_hash_freeze
)
862 const Hash_key_type key_type
= hash
->key_type
;
863 const PARROT_DATA_TYPE entry_type
= hash
->entry_type
;
864 const size_t entries
= hash
->entries
;
867 VTABLE_push_integer(interp
, info
, entries
);
868 VTABLE_push_integer(interp
, info
, key_type
);
869 VTABLE_push_integer(interp
, info
, entry_type
);
871 parrot_hash_iterate(hash
,
873 case Hash_key_type_int
:
874 VTABLE_push_integer(interp
, info
, (INTVAL
)_bucket
->key
);
876 case Hash_key_type_STRING
:
877 case Hash_key_type_STRING_enc
:
878 VTABLE_push_string(interp
, info
, (STRING
*)_bucket
->key
);
880 case Hash_key_type_PMC
:
881 case Hash_key_type_PMC_ptr
:
882 VTABLE_push_pmc(interp
, info
, (PMC
*)_bucket
->key
);
885 Parrot_ex_throw_from_c_args(interp
, NULL
, 1,
886 "unimplemented key type");
889 switch (entry_type
) {
891 VTABLE_push_integer(interp
, info
, (INTVAL
)_bucket
->value
);
893 case enum_hash_string
:
894 VTABLE_push_string(interp
, info
, (STRING
*)_bucket
->value
);
897 VTABLE_push_pmc(interp
, info
, (PMC
*)_bucket
->value
);
900 Parrot_ex_throw_from_c_args(interp
, NULL
, 1,
901 "unimplemented value type");
908 =item C<static void allocate_buckets(PARROT_INTERP, Hash *hash, const UINTVAL
911 Allocate sized buckets and index storage for a hash
918 allocate_buckets(PARROT_INTERP
, ARGMOD(Hash
*hash
), ARGIN_NULLOK(const UINTVAL size
))
920 ASSERT_ARGS(allocate_buckets
)
922 UINTVAL new_size
= INITIAL_SIZE
;
923 HashBucket
*new_buckets
, *bucket
;
926 while (size
> new_size
)
929 if (new_size
> SPLIT_POINT
)
930 new_buckets
= (HashBucket
*) Parrot_gc_allocate_memory_chunk(
931 interp
, HASH_ALLOC_SIZE(new_size
));
933 new_buckets
= (HashBucket
*) Parrot_gc_allocate_fixed_size_storage(
934 interp
, HASH_ALLOC_SIZE(new_size
));
936 memset(new_buckets
, 0, HASH_ALLOC_SIZE(new_size
));
938 hash
->mask
= new_size
- 1;
939 hash
->buckets
= new_buckets
;
940 hash
->index
= (HashBucket
**)(new_buckets
+ N_BUCKETS(new_size
));
942 /* add new buckets to free_list
943 * lowest bucket is top on free list and will be used first */
945 bucket
= hash
->buckets
+ N_BUCKETS(new_size
) - 1;
946 for (i
= 0; i
< N_BUCKETS(new_size
); ++i
, --bucket
) {
947 bucket
->next
= hash
->free_list
;
948 hash
->free_list
= bucket
;
954 =item C<static void expand_hash(PARROT_INTERP, Hash *hash)>
956 Expands a hash when necessary.
958 For a hashtable of size N, we use C<MAXFULL_PERCENT> % of N as the
959 number of buckets. This way, as soon as we run out of buckets on the
960 free list, we know that it's time to resize the hashtable.
962 Algorithm for expansion: We exactly double the size of the hashtable.
963 Keys are assigned to buckets with the formula
965 bucket_index = hash(key) % parrot_hash_size
967 When doubling the size of the hashtable, we know that every key is either
968 already in the correct bucket, or belongs in the current bucket plus
969 C<parrot_hash_size> (the old C<parrot_hash_size>). In fact, because the
970 hashtable is always a power of two in size, it depends only on the next bit
971 in the hash value, after the ones previously used.
973 We scan through all the buckets in order, moving the buckets that need to be
974 moved. No bucket will be scanned twice, and the cache should be reasonably
975 happy because the hashtable accesses will be two parallel sequential scans.
976 (Of course, this also mucks with the C<< ->next >> pointers, and they'll be
984 expand_hash(PARROT_INTERP
, ARGMOD(Hash
*hash
))
986 ASSERT_ARGS(expand_hash
)
987 HashBucket
**new_index
, **index
;
988 HashBucket
*new_buckets
, *bucket
;
991 void * const old_mem
= hash
->buckets
;
992 const UINTVAL old_size
= hash
->mask
+ 1;
993 const UINTVAL new_size
= old_size
<< 1; /* Double. Right-shift is 2x */
994 const UINTVAL new_mask
= new_size
- 1;
998 allocate some less buckets
999 e.g. 3 buckets, 4 pointers:
1001 +---+---+---+-+-+-+-+
1003 +---+---+---+-+-+-+-+
1005 | old_mem | hash->index
1009 if (new_size
> SPLIT_POINT
)
1010 new_mem
= Parrot_gc_allocate_memory_chunk(
1011 interp
, HASH_ALLOC_SIZE(new_size
));
1013 new_mem
= Parrot_gc_allocate_fixed_size_storage(
1014 interp
, HASH_ALLOC_SIZE(new_size
));
1016 offset
= (char *)new_mem
- (char *)old_mem
;
1018 new_buckets
= (HashBucket
*) new_mem
;
1019 new_index
= (HashBucket
**)(new_buckets
+ N_BUCKETS(new_size
));
1021 /* copy buckets and index */
1022 mem_sys_memcopy(new_buckets
, hash
->buckets
,
1023 N_BUCKETS(old_size
) * sizeof (HashBucket
));
1024 mem_sys_memcopy(new_index
, hash
->index
, old_size
* sizeof (HashBucket
**));
1027 if (old_size
> SPLIT_POINT
)
1028 Parrot_gc_free_memory_chunk(interp
, old_mem
);
1030 Parrot_gc_free_fixed_size_storage(interp
, HASH_ALLOC_SIZE(old_size
), old_mem
);
1033 /* clear second half of the buckets, freed by old the index */
1034 memset(new_buckets
+ N_BUCKETS(old_size
), 0,
1035 sizeof (HashBucket
*) * old_size
);
1037 /* clear second half of the index */
1038 memset(new_index
+ (old_size
), 0, sizeof (HashBucket
**) * old_size
);
1043 +---+---+---+---+---+---+-+-+-+-+-+-+-+-+
1044 | buckets | old_index | new_index |
1045 +---+---+---+---+---+---+-+-+-+-+-+-+-+-+
1047 | new_mem | hash->index
1050 /* update hash data */
1051 hash
->index
= new_index
;
1052 hash
->buckets
= new_buckets
;
1053 hash
->mask
= new_mask
;
1055 /* reloc pointers and recalc bucket indices */
1056 for (i
= 0; i
< old_size
; ++i
) {
1057 index
= new_index
+ i
;
1059 while (*index
!= NULL
) {
1063 bucket
= (HashBucket
*)((char *)*index
+ offset
);
1065 /* rehash the bucket */
1066 if (hash
->key_type
== Hash_key_type_STRING
1067 || hash
->key_type
== Hash_key_type_STRING_enc
) {
1068 STRING
*s
= (STRING
*)bucket
->key
;
1069 hashval
= s
->hashval
;
1072 hashval
= key_hash(interp
, hash
, bucket
->key
);
1075 new_loc
= hashval
& new_mask
;
1078 *index
= bucket
->next
;
1079 bucket
->next
= new_index
[new_loc
];
1080 new_index
[new_loc
] = bucket
;
1084 index
= &bucket
->next
;
1089 /* add new buckets to free_list
1090 * lowest bucket is top on free list and will be used first */
1091 bucket
= new_buckets
+ N_BUCKETS(old_size
);
1092 for (i
= N_BUCKETS(old_size
)-1 ; i
> 0; --i
, ++bucket
) {
1093 bucket
->next
= bucket
+ 1;
1096 bucket
->next
= NULL
;
1097 hash
->free_list
= new_buckets
+ N_BUCKETS(old_size
);
1103 =item C<Hash* parrot_new_hash(PARROT_INTERP)>
1105 Creates a new Parrot STRING hash.
1112 PARROT_CANNOT_RETURN_NULL
1114 parrot_new_hash(PARROT_INTERP
)
1116 ASSERT_ARGS(parrot_new_hash
)
1117 return parrot_create_hash(interp
,
1119 Hash_key_type_STRING
);
1125 =item C<Hash* parrot_new_cstring_hash(PARROT_INTERP)>
1127 Creates a new C string hash in C<hptr>.
1134 PARROT_CANNOT_RETURN_NULL
1136 parrot_new_cstring_hash(PARROT_INTERP
)
1138 ASSERT_ARGS(parrot_new_cstring_hash
)
1139 return parrot_create_hash(interp
,
1141 Hash_key_type_cstring
);
1147 =item C<Hash * parrot_new_pointer_hash(PARROT_INTERP)>
1149 Create and return a new hash with void * keys and values.
1156 PARROT_CANNOT_RETURN_NULL
1158 parrot_new_pointer_hash(PARROT_INTERP
)
1160 ASSERT_ARGS(parrot_new_pointer_hash
)
1161 return parrot_create_hash(interp
,
1169 =item C<Hash* parrot_new_intval_hash(PARROT_INTERP)>
1171 Creates and returns new Hash PMC with INTVAL keys and values. C<flags> can be
1172 C<PObj_constant_FLAG> or 0.
1180 PARROT_WARN_UNUSED_RESULT
1181 PARROT_CANNOT_RETURN_NULL
1183 parrot_new_intval_hash(PARROT_INTERP
)
1185 ASSERT_ARGS(parrot_new_intval_hash
)
1186 return parrot_create_hash(interp
,
1193 =item C<Hash * parrot_create_hash(PARROT_INTERP, PARROT_DATA_TYPE val_type,
1194 Hash_key_type hkey_type)>
1196 Creates and initializes a hash. Function pointers determine its behaviors.
1198 Memory from this function must be freed.
1204 PARROT_CANNOT_RETURN_NULL
1205 PARROT_WARN_UNUSED_RESULT
1207 parrot_create_hash(PARROT_INTERP
, PARROT_DATA_TYPE val_type
, Hash_key_type hkey_type
)
1209 ASSERT_ARGS(parrot_create_hash
)
1210 Hash
* const hash
= (Hash
*) Parrot_gc_allocate_fixed_size_storage(interp
, sizeof (Hash
));
1212 hash
->entry_type
= val_type
;
1213 hash
->key_type
= hkey_type
;
1214 hash
->seed
= interp
->hash_seed
;
1218 hash
->buckets
= NULL
;
1219 hash
->free_list
= NULL
;
1227 =item C<Hash * parrot_create_hash_sized(PARROT_INTERP, PARROT_DATA_TYPE
1228 val_type, Hash_key_type hkey_type, UINTVAL size)>
1230 Creates and initializes a hash, similar to C<parrot_create_hash>.
1232 Preallocates at least C<size> buckets.
1238 PARROT_CANNOT_RETURN_NULL
1239 PARROT_WARN_UNUSED_RESULT
1241 parrot_create_hash_sized(PARROT_INTERP
, PARROT_DATA_TYPE val_type
, Hash_key_type hkey_type
,
1244 ASSERT_ARGS(parrot_create_hash_sized
)
1246 Hash
*hash
= parrot_create_hash(interp
, val_type
, hkey_type
);
1247 allocate_buckets(interp
, hash
, size
);
1253 =item C<void parrot_hash_destroy(PARROT_INTERP, Hash *hash)>
1255 Frees the memory allocated to the specified hash and its bucket store. Used by
1256 parrot_chash_destroy.
1258 Unlike the C library function free(), the hash function must not be NULL.
1266 parrot_hash_destroy(PARROT_INTERP
, ARGFREE_NOTNULL(Hash
*hash
))
1268 ASSERT_ARGS(parrot_hash_destroy
)
1270 if (hash
->mask
> SPLIT_POINT
)
1271 Parrot_gc_free_memory_chunk(interp
, hash
->buckets
);
1273 Parrot_gc_free_fixed_size_storage(interp
,
1274 HASH_ALLOC_SIZE(hash
->mask
+1), hash
->buckets
);
1276 Parrot_gc_free_fixed_size_storage(interp
, sizeof (Hash
), hash
);
1282 =item C<void parrot_chash_destroy(PARROT_INTERP, Hash *hash)>
1284 Deletes the specified hash by freeing the memory allocated to all the key-value
1285 pairs, and finally the hash itself.
1292 parrot_chash_destroy(PARROT_INTERP
, ARGMOD(Hash
*hash
))
1294 ASSERT_ARGS(parrot_chash_destroy
)
1295 parrot_hash_iterate(hash
,
1296 mem_gc_free(interp
, _bucket
->key
);
1297 mem_gc_free(interp
, _bucket
->value
););
1298 parrot_hash_destroy(interp
, hash
);
1304 =item C<void parrot_chash_destroy_values(PARROT_INTERP, Hash *hash, value_free
1307 Deletes the specified hash by freeing the memory allocated to all the key-value
1308 pairs, calling the provided callback to free the values, and finally the hash
1311 The callback returns C<void> and takes a C<void *>.
1318 parrot_chash_destroy_values(PARROT_INTERP
, ARGMOD(Hash
*hash
), NOTNULL(value_free func
))
1320 ASSERT_ARGS(parrot_chash_destroy_values
)
1323 parrot_hash_iterate(hash
,
1324 mem_gc_free(interp
, _bucket
->key
);
1325 func(_bucket
->value
););
1327 parrot_hash_destroy(interp
, hash
);
1333 =item C<INTVAL parrot_hash_size(PARROT_INTERP, const Hash *hash)>
1335 Returns the number of used entries in the hash.
1342 PARROT_WARN_UNUSED_RESULT
1343 PARROT_PURE_FUNCTION
1345 parrot_hash_size(SHIM_INTERP
, ARGIN(const Hash
*hash
))
1347 ASSERT_ARGS(parrot_hash_size
)
1349 return hash
->entries
;
1355 =item C<HashBucket * parrot_hash_get_bucket(PARROT_INTERP, const Hash *hash,
1358 Returns the bucket for C<key>, if found, and NULL otherwise.
1365 PARROT_WARN_UNUSED_RESULT
1366 PARROT_CAN_RETURN_NULL
1368 parrot_hash_get_bucket(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN_NULLOK(const void *key
))
1370 ASSERT_ARGS(parrot_hash_get_bucket
)
1374 if (hash
->entries
<= 0)
1377 if (hash
->key_type
== Hash_key_type_STRING
) {
1378 STRING
* const s
= (STRING
*)PARROT_const_cast(void *, key
);
1379 const size_t hashval
= key_hash_STRING(interp
, s
, hash
->seed
);
1381 bucket
= hash
->index
[hashval
& hash
->mask
];
1384 const STRING
*s2
= (const STRING
*)bucket
->key
;
1388 /* manually inline part of string_equal */
1389 if (hashval
== s2
->hashval
) {
1390 if (s
->encoding
== s2
->encoding
){
1391 if ((STRING_byte_length(s
) == STRING_byte_length(s2
))
1392 && (memcmp(s
->strstart
, s2
->strstart
, STRING_byte_length(s
)) == 0))
1394 } else if (Parrot_str_equal(interp
, s
, s2
))
1398 bucket
= bucket
->next
;
1402 const size_t hashval
= key_hash(interp
, hash
,
1403 PARROT_const_cast(void *, key
));
1404 bucket
= hash
->index
[hashval
& hash
->mask
];
1407 if (hash_compare(interp
, hash
,
1408 PARROT_const_cast(void *, key
),
1411 bucket
= bucket
->next
;
1420 =item C<void * parrot_hash_get(PARROT_INTERP, const Hash *hash, const void
1423 Returns the value keyed by C<key>, or C<NULL> if no bucket is found.
1430 PARROT_WARN_UNUSED_RESULT
1431 PARROT_CAN_RETURN_NULL
1433 parrot_hash_get(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN(const void *key
))
1435 ASSERT_ARGS(parrot_hash_get
)
1436 const HashBucket
* const bucket
= parrot_hash_get_bucket(interp
, hash
, key
);
1437 return bucket
? bucket
->value
: NULL
;
1443 =item C<INTVAL parrot_hash_exists(PARROT_INTERP, const Hash *hash, void *key)>
1445 Returns whether the key exists in the hash.
1452 PARROT_WARN_UNUSED_RESULT
1454 parrot_hash_exists(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN(void *key
))
1456 ASSERT_ARGS(parrot_hash_exists
)
1457 const HashBucket
* const bucket
= parrot_hash_get_bucket(interp
, hash
, key
);
1458 return bucket
? 1 : 0;
1464 =item C<HashBucket* parrot_hash_put(PARROT_INTERP, Hash *hash, void *key, void
1467 Puts the key and value into the hash. Note that C<key> is B<not> copied.
1474 PARROT_IGNORABLE_RESULT
1475 PARROT_CANNOT_RETURN_NULL
1477 parrot_hash_put(PARROT_INTERP
, ARGMOD(Hash
*hash
),
1478 ARGIN_NULLOK(void *key
), ARGIN_NULLOK(void *value
))
1480 ASSERT_ARGS(parrot_hash_put
)
1481 HashBucket
*bucket
= NULL
;
1484 if (!hash
->buckets
){
1485 allocate_buckets(interp
, hash
, INITIAL_SIZE
);
1486 hashval
= key_hash(interp
, hash
, key
);
1489 if (hash
->key_type
== Hash_key_type_STRING
) {
1490 const STRING
* const s
= (STRING
*)key
;
1491 hashval
= key_hash_STRING(interp
, (STRING
*)key
, hash
->seed
);
1492 bucket
= hash
->index
[hashval
& hash
->mask
];
1495 const STRING
*s2
= (const STRING
*)bucket
->key
;
1498 /* manually inline part of string_equal */
1499 if (hashval
== s2
->hashval
) {
1500 if (s
->encoding
== s2
->encoding
) {
1501 if ((STRING_byte_length(s
) == STRING_byte_length(s2
))
1502 && (memcmp(s
->strstart
, s2
->strstart
, STRING_byte_length(s
)) == 0))
1504 } else if (Parrot_str_equal(interp
, s
, s2
))
1507 bucket
= bucket
->next
;
1511 hashval
= key_hash(interp
, hash
, key
);
1512 bucket
= hash
->index
[hashval
& hash
->mask
];
1515 if (hash_compare(interp
, hash
, key
, bucket
->key
) == 0)
1517 bucket
= bucket
->next
;
1522 /* If we have a bucket already, put the value in it. Otherwise, we need
1523 to get a new bucket */
1525 bucket
->value
= value
;
1527 /* Get a new bucket off the free list. If the free list is empty, we
1528 expand the hash so we get more items on the free list */
1529 if (!hash
->free_list
)
1530 expand_hash(interp
, hash
);
1532 bucket
= hash
->free_list
;
1534 /* Add the value to the new bucket, increasing the count of elements */
1536 hash
->free_list
= bucket
->next
;
1538 bucket
->value
= value
;
1539 bucket
->next
= hash
->index
[hashval
& hash
->mask
];
1540 hash
->index
[hashval
& hash
->mask
] = bucket
;
1549 =item C<void parrot_hash_delete(PARROT_INTERP, Hash *hash, void *key)>
1551 Deletes the key from the hash.
1559 parrot_hash_delete(PARROT_INTERP
, ARGMOD(Hash
*hash
), ARGIN(void *key
))
1561 ASSERT_ARGS(parrot_hash_delete
)
1562 const UINTVAL hashval
= key_hash(interp
, hash
, key
) & hash
->mask
;
1564 HashBucket
**prev
= &hash
->index
[hashval
];
1566 for (; *prev
; prev
= &(*prev
)->next
) {
1567 HashBucket
*current
= *prev
;
1568 if (hash_compare(interp
, hash
, key
, current
->key
) == 0) {
1569 *prev
= current
->next
;
1571 current
->next
= hash
->free_list
;
1572 current
->key
= NULL
;
1573 hash
->free_list
= current
;
1584 =item C<void parrot_hash_clone(PARROT_INTERP, const Hash *hash, Hash *dest)>
1586 Clones C<hash> to C<dest>.
1594 parrot_hash_clone(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGOUT(Hash
*dest
))
1596 ASSERT_ARGS(parrot_hash_clone
)
1597 parrot_hash_clone_prunable(interp
, hash
, dest
, 1);
1602 =item C<void parrot_hash_clone_prunable(PARROT_INTERP, const Hash *hash, Hash
1605 helper function to Clone C<hash> to C<dest>
1607 allows deep cloning of PMC types if deep set
1614 parrot_hash_clone_prunable(PARROT_INTERP
, ARGIN(const Hash
*hash
),
1615 ARGOUT(Hash
*dest
), int deep
)
1617 ASSERT_ARGS(parrot_hash_clone_prunable
)
1619 parrot_hash_iterate(hash
,
1621 void * const key
= _bucket
->key
;
1623 switch (hash
->entry_type
) {
1624 case enum_type_STRING
:
1625 valtmp
= _bucket
->value
;
1629 if (PMC_IS_NULL((PMC
*)_bucket
->value
))
1630 valtmp
= (void *)PMCNULL
;
1633 valtmp
= (void *)VTABLE_clone(interp
, (PMC
*)_bucket
->value
);
1635 valtmp
= _bucket
->value
;
1638 case enum_type_undef
:
1640 case enum_type_INTVAL
:
1641 valtmp
= (void *)_bucket
->value
;
1645 valtmp
= NULL
; /* avoid warning */
1646 Parrot_ex_throw_from_c_args(interp
, NULL
, -1,
1647 "hash corruption: type = %d\n", hash
->entry_type
);
1650 parrot_hash_put(interp
, dest
, key
, valtmp
););
1655 =item C<static PMC* get_integer_pmc(PARROT_INTERP, INTVAL value)>
1657 Lookup the PMC type which is used for storing native integers.
1663 PARROT_CANNOT_RETURN_NULL
1665 get_integer_pmc(PARROT_INTERP
, INTVAL value
)
1667 ASSERT_ARGS(get_integer_pmc
)
1668 PMC
* const ret
= Parrot_pmc_new(interp
, Parrot_get_ctx_HLL_type(interp
, enum_class_Integer
));
1669 VTABLE_set_integer_native(interp
, ret
, value
);
1676 =item C<static PMC* get_number_pmc(PARROT_INTERP, FLOATVAL value)>
1678 Lookup the PMC type which is used for floating point numbers.
1684 PARROT_CANNOT_RETURN_NULL
1686 get_number_pmc(PARROT_INTERP
, FLOATVAL value
)
1688 ASSERT_ARGS(get_number_pmc
)
1689 PMC
* const ret
= Parrot_pmc_new(interp
, Parrot_get_ctx_HLL_type(interp
, enum_class_Float
));
1690 VTABLE_set_number_native(interp
, ret
, value
);
1696 =item C<static PMC * get_string_pmc(PARROT_INTERP, STRING *value)>
1698 Lookup the PMC type which is used for storing strings.
1704 PARROT_CANNOT_RETURN_NULL
1706 get_string_pmc(PARROT_INTERP
, ARGIN(STRING
*value
))
1708 ASSERT_ARGS(get_string_pmc
)
1709 PMC
* const ret
= Parrot_pmc_new(interp
, Parrot_get_ctx_HLL_type(interp
, enum_class_String
));
1710 VTABLE_set_string_native(interp
, ret
, value
);
1717 Poor-man polymorphic functions to convert something to something.
1719 There is bunch of functions to convert from passed value to stored keys type and to/from
1722 void *hash_key_from_TYPE convert to keys type.
1723 TYPE hash_key_to_TYPE convert from keys type.
1724 void *hash_value_from_TYPE convert to values type.
1725 TYPE hash_value_to_TYPE convert from values type.
1731 =item C<void* hash_key_from_int(PARROT_INTERP, const Hash *hash, INTVAL key)>
1733 Cast INTVAL to hash key.
1739 PARROT_CAN_RETURN_NULL
1741 hash_key_from_int(PARROT_INTERP
, ARGIN(const Hash
*hash
), INTVAL key
)
1743 ASSERT_ARGS(hash_key_from_int
)
1745 switch (hash
->key_type
) {
1746 case Hash_key_type_int
:
1749 /* Currently PMCs are stringified */
1750 case Hash_key_type_PMC
:
1751 case Hash_key_type_PMC_ptr
:
1752 ret
= (void *)get_integer_pmc(interp
, key
);
1754 case Hash_key_type_STRING
:
1755 case Hash_key_type_STRING_enc
:
1756 ret
= (void *)Parrot_str_from_int(interp
, key
);
1759 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
1760 "Hash: unsupported key_type");
1767 =item C<void* hash_key_from_string(PARROT_INTERP, const Hash *hash, STRING
1770 Cast STRING to hash key.
1776 PARROT_CAN_RETURN_NULL
1778 hash_key_from_string(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN(STRING
*key
))
1780 ASSERT_ARGS(hash_key_from_string
)
1782 switch (hash
->key_type
) {
1783 case Hash_key_type_int
:
1785 /* Pacify compiler about casting INVTAL to void */
1786 const INTVAL int_key
= Parrot_str_to_int(interp
, key
);
1787 ret
= INTVAL2PTR(void *, int_key
);
1791 case Hash_key_type_PMC
:
1792 case Hash_key_type_PMC_ptr
:
1793 ret
= get_string_pmc(interp
, key
);
1796 case Hash_key_type_STRING
:
1797 case Hash_key_type_STRING_enc
:
1802 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
1803 "Hash: unsupported key_type");
1810 =item C<void* hash_key_from_pmc(PARROT_INTERP, const Hash *hash, PMC *key)>
1812 Cast PMC* to hash key.
1818 PARROT_CAN_RETURN_NULL
1820 hash_key_from_pmc(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN(PMC
*key
))
1822 ASSERT_ARGS(hash_key_from_pmc
)
1824 switch (hash
->key_type
) {
1825 case Hash_key_type_int
:
1827 const INTVAL int_key
= VTABLE_get_integer(interp
, key
);
1828 ret
= INTVAL2PTR(void *, int_key
);
1831 case Hash_key_type_PMC
:
1832 case Hash_key_type_PMC_ptr
:
1834 /* Extract real value from Key (and box it if nessary) */
1835 if (key
->vtable
->base_type
== enum_class_Key
)
1836 switch (key_type(interp
, key
)) {
1837 case KEY_integer_FLAG
:
1838 key
= get_integer_pmc(interp
, key_integer(interp
, key
));
1840 case KEY_string_FLAG
:
1841 key
= get_string_pmc(interp
, key_string(interp
, key
));
1843 case KEY_number_FLAG
:
1844 key
= get_number_pmc(interp
, key_number(interp
, key
));
1847 key
= key_pmc(interp
, key
);
1850 /* It's impossible if Keys are same (and they are not) */
1851 /* So throw exception */
1852 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_INVALID_OPERATION
,
1853 "hash: unexpected type of Key");
1860 case Hash_key_type_STRING
:
1861 case Hash_key_type_STRING_enc
:
1863 STRING
* const tmp
= VTABLE_get_string(interp
, key
);
1864 if (STRING_IS_NULL(tmp
))
1865 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNEXPECTED_NULL
,
1866 "hash: can't use null as key");
1871 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
1872 "Hash: unsupported key_type");
1879 =item C<INTVAL hash_key_to_int(PARROT_INTERP, const Hash *hash, void *key)>
1881 Cast hash key to INTVAL.
1888 hash_key_to_int(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN_NULLOK(void *key
))
1890 ASSERT_ARGS(hash_key_to_int
)
1892 switch (hash
->key_type
) {
1893 case Hash_key_type_int
:
1896 case Hash_key_type_PMC
:
1897 case Hash_key_type_PMC_ptr
:
1898 ret
= VTABLE_get_integer(interp
, (PMC
*)key
);
1900 case Hash_key_type_STRING
:
1901 case Hash_key_type_STRING_enc
:
1902 ret
= Parrot_str_to_int(interp
, (STRING
*)key
);
1905 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
1906 "Hash: unsupported key_type");
1913 =item C<STRING* hash_key_to_string(PARROT_INTERP, const Hash *hash, void *key)>
1915 Cast hash key to STRING.
1921 PARROT_CANNOT_RETURN_NULL
1923 hash_key_to_string(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN_NULLOK(void *key
))
1925 ASSERT_ARGS(hash_key_to_string
)
1927 switch (hash
->key_type
) {
1928 case Hash_key_type_int
:
1929 ret
= Parrot_str_from_int(interp
, (INTVAL
)key
);
1932 case Hash_key_type_PMC
:
1933 case Hash_key_type_PMC_ptr
:
1934 ret
= VTABLE_get_string(interp
, (PMC
*)key
);
1937 case Hash_key_type_STRING
:
1938 case Hash_key_type_STRING_enc
:
1939 ret
= (STRING
*)key
;
1943 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
1944 "Hash: unsupported key_type");
1951 =item C<PMC* hash_key_to_pmc(PARROT_INTERP, const Hash * const hash, void *key)>
1953 Cast hash key to PMC*.
1959 PARROT_CANNOT_RETURN_NULL
1961 hash_key_to_pmc(PARROT_INTERP
, ARGIN(const Hash
* const hash
), ARGIN(void *key
))
1963 ASSERT_ARGS(hash_key_to_pmc
)
1965 switch (hash
->key_type
) {
1966 case Hash_key_type_int
:
1967 ret
= get_integer_pmc(interp
, (INTVAL
)key
);
1969 case Hash_key_type_PMC
:
1970 case Hash_key_type_PMC_ptr
:
1973 case Hash_key_type_STRING
:
1974 case Hash_key_type_STRING_enc
:
1975 ret
= get_string_pmc(interp
, (STRING
*)key
);
1978 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
1979 "Hash: unsupported key_type");
1984 /* Second part - convert from stored void* to real type */
1985 /* TODO: FLOATVALs converted into Float PMC for now */
1989 =item C<void* hash_value_from_int(PARROT_INTERP, const Hash *hash, INTVAL
1992 Cast INTVAL to hash value.
1998 PARROT_CAN_RETURN_NULL
2000 hash_value_from_int(PARROT_INTERP
, ARGIN(const Hash
*hash
), INTVAL value
)
2002 ASSERT_ARGS(hash_value_from_int
)
2004 switch (hash
->entry_type
) {
2005 case enum_type_INTVAL
:
2006 ret
= INTVAL2PTR(void *, value
);
2010 PMC
* const tmp
= get_integer_pmc(interp
, value
);
2014 case enum_type_STRING
:
2015 ret
= (void *)Parrot_str_from_int(interp
, value
);
2018 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
2019 "Hash: unsupported entry_type");
2026 =item C<void* hash_value_from_string(PARROT_INTERP, const Hash *hash, STRING
2029 Cast STRING to hash value.
2035 PARROT_CAN_RETURN_NULL
2037 hash_value_from_string(PARROT_INTERP
, ARGIN(const Hash
*hash
),
2038 ARGIN_NULLOK(STRING
*value
))
2040 ASSERT_ARGS(hash_value_from_string
)
2042 switch (hash
->entry_type
) {
2043 case enum_type_INTVAL
:
2045 const INTVAL int_val
= STRING_IS_NULL(value
) ?
2046 (INTVAL
) 0 : Parrot_str_to_int(interp
, value
);
2047 ret
= INTVAL2PTR(void *, int_val
);
2050 case enum_type_STRING
:
2051 ret
= (void *)value
;
2055 PMC
* const s
= STRING_IS_NULL(value
) ?
2056 PMCNULL
: get_string_pmc(interp
, value
);
2061 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
2062 "Hash: unsupported entry_type");
2069 =item C<void* hash_value_from_pmc(PARROT_INTERP, const Hash *hash, PMC *value)>
2071 Cast PMC to hash value.
2077 PARROT_CAN_RETURN_NULL
2079 hash_value_from_pmc(PARROT_INTERP
, ARGIN(const Hash
*hash
),
2080 ARGIN_NULLOK(PMC
*value
))
2082 ASSERT_ARGS(hash_value_from_pmc
)
2084 switch (hash
->entry_type
) {
2085 case enum_type_INTVAL
:
2087 const INTVAL int_val
= PMC_IS_NULL(value
) ?
2088 (INTVAL
) 0 : VTABLE_get_integer(interp
, value
);
2089 ret
= INTVAL2PTR(void *, int_val
);
2092 case enum_type_STRING
:
2093 ret
= PMC_IS_NULL(value
) ?
2094 PMCNULL
: (void *)VTABLE_get_string(interp
, value
);
2097 ret
= (void *)value
;
2100 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
2101 "Hash: unsupported entry_type");
2108 =item C<void* hash_value_from_number(PARROT_INTERP, const Hash *hash, FLOATVAL
2111 Cast FLOATVAL to hash value.
2117 PARROT_CAN_RETURN_NULL
2119 hash_value_from_number(PARROT_INTERP
, ARGIN(const Hash
*hash
), FLOATVAL value
)
2121 ASSERT_ARGS(hash_value_from_number
)
2123 switch (hash
->entry_type
) {
2124 case enum_type_INTVAL
:
2126 const INTVAL tmp
= value
;
2130 case enum_type_STRING
:
2131 ret
= (void *)Parrot_str_from_num(interp
, value
);
2135 PMC
* const tmp
= get_number_pmc(interp
, value
);
2140 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
2141 "Hash: unsupported entry_type");
2148 =item C<INTVAL hash_value_to_int(PARROT_INTERP, const Hash *hash, void *value)>
2150 Cast hash value to INTVAL.
2157 hash_value_to_int(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN_NULLOK(void *value
))
2159 ASSERT_ARGS(hash_value_to_int
)
2161 switch (hash
->entry_type
) {
2163 case enum_type_INTVAL
:
2164 ret
= (INTVAL
)value
;
2166 case enum_type_STRING
:
2167 ret
= Parrot_str_to_int(interp
, (STRING
*)value
);
2170 ret
= VTABLE_get_integer(interp
, (PMC
*)value
);
2173 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
2174 "Hash: unsupported entry_type");
2181 =item C<STRING* hash_value_to_string(PARROT_INTERP, const Hash *hash, void
2184 Cast hash value to STRING.
2190 PARROT_CANNOT_RETURN_NULL
2192 hash_value_to_string(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN_NULLOK(void *value
))
2194 ASSERT_ARGS(hash_value_to_string
)
2196 switch (hash
->entry_type
) {
2197 case enum_type_INTVAL
:
2198 ret
= Parrot_str_from_int(interp
, (INTVAL
)value
);
2200 case enum_type_STRING
:
2201 ret
= (STRING
*)value
;
2204 ret
= VTABLE_get_string(interp
, (PMC
*)value
);
2207 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
2208 "Hash: unsupported entry_type");
2215 =item C<PMC* hash_value_to_pmc(PARROT_INTERP, const Hash *hash, void *value)>
2217 Cast hash value to PMC.
2223 PARROT_CANNOT_RETURN_NULL
2225 hash_value_to_pmc(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN_NULLOK(void *value
))
2227 ASSERT_ARGS(hash_value_to_pmc
)
2229 switch (hash
->entry_type
) {
2230 case enum_type_INTVAL
:
2231 ret
= get_integer_pmc(interp
, (INTVAL
)value
);
2233 case enum_type_STRING
:
2234 ret
= get_string_pmc(interp
, (STRING
*)value
);
2240 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
2241 "Hash: unsupported entry_type");
2248 =item C<FLOATVAL hash_value_to_number(PARROT_INTERP, const Hash *hash, void
2251 Cast hash value to FLOATVAL.
2258 hash_value_to_number(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN_NULLOK(void *value
))
2260 ASSERT_ARGS(hash_value_to_number
)
2262 switch (hash
->entry_type
) {
2263 case enum_type_INTVAL
:
2265 /* Pacify compiler about casting */
2266 const INTVAL tmp
= (INTVAL
)value
;
2270 case enum_type_STRING
:
2271 ret
= Parrot_str_to_num(interp
, (STRING
*)value
);
2274 ret
= VTABLE_get_number(interp
, (PMC
*)value
);
2277 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
2278 "Hash: unsupported entry_type");
2289 F<docs/pdds/pdd08_keys.pod>.
2293 Future optimizations:
2297 =item * Stop reallocating the bucket pool, and instead add chunks on.
2298 (Saves pointer fixups and copying during C<realloc>.)
2300 =item * Hash contraction (don't if it's worth it)
2311 * c-file-style: "parrot"
2313 * vim: expandtab shiftwidth=4: