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->bs >> bucket store points to this region.
19 This hash doesn't move during GC, therefore a lot of the old caveats
30 #include "parrot/parrot.h"
31 #include "pmc/pmc_key.h"
33 /* the number of entries above which it's faster to hash the hashval instead of
34 * looping over the used HashBuckets directly */
35 #define SMALL_HASH_SIZE 4
36 #define INITIAL_BUCKETS 4
38 /* HEADERIZER HFILE: include/parrot/hash.h */
40 /* HEADERIZER BEGIN: static */
41 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
43 PARROT_WARN_UNUSED_RESULT
45 static int cstring_compare(SHIM_INTERP
,
48 __attribute__nonnull__(2)
49 __attribute__nonnull__(3);
51 static void expand_hash(PARROT_INTERP
, ARGMOD(Hash
*hash
))
52 __attribute__nonnull__(1)
53 __attribute__nonnull__(2)
56 static void hash_freeze(PARROT_INTERP
,
57 ARGIN(const Hash
*hash
),
59 __attribute__nonnull__(1)
60 __attribute__nonnull__(2)
61 __attribute__nonnull__(3)
64 static void hash_thaw(PARROT_INTERP
, ARGMOD(Hash
*hash
), ARGMOD(PMC
*info
))
65 __attribute__nonnull__(1)
66 __attribute__nonnull__(2)
67 __attribute__nonnull__(3)
71 PARROT_WARN_UNUSED_RESULT
73 static size_t key_hash_cstring(SHIM_INTERP
,
74 ARGIN(const void *value
),
76 __attribute__nonnull__(2);
78 PARROT_WARN_UNUSED_RESULT
80 static size_t key_hash_pointer(SHIM_INTERP
,
81 ARGIN(const void *value
),
83 __attribute__nonnull__(2);
85 static void parrot_mark_hash_both(PARROT_INTERP
, ARGIN(Hash
*hash
))
86 __attribute__nonnull__(1)
87 __attribute__nonnull__(2);
89 static void parrot_mark_hash_keys(PARROT_INTERP
, ARGIN(Hash
*hash
))
90 __attribute__nonnull__(1)
91 __attribute__nonnull__(2);
93 static void parrot_mark_hash_values(PARROT_INTERP
, ARGIN(Hash
*hash
))
94 __attribute__nonnull__(1)
95 __attribute__nonnull__(2);
97 PARROT_WARN_UNUSED_RESULT
99 static int pointer_compare(SHIM_INTERP
,
100 ARGIN_NULLOK(const void *a
),
101 ARGIN_NULLOK(const void *b
));
103 #define ASSERT_ARGS_cstring_compare __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
104 PARROT_ASSERT_ARG(a) \
105 , PARROT_ASSERT_ARG(b))
106 #define ASSERT_ARGS_expand_hash __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
107 PARROT_ASSERT_ARG(interp) \
108 , PARROT_ASSERT_ARG(hash))
109 #define ASSERT_ARGS_hash_freeze __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
110 PARROT_ASSERT_ARG(interp) \
111 , PARROT_ASSERT_ARG(hash) \
112 , PARROT_ASSERT_ARG(info))
113 #define ASSERT_ARGS_hash_thaw __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
114 PARROT_ASSERT_ARG(interp) \
115 , PARROT_ASSERT_ARG(hash) \
116 , PARROT_ASSERT_ARG(info))
117 #define ASSERT_ARGS_key_hash_cstring __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
118 PARROT_ASSERT_ARG(value))
119 #define ASSERT_ARGS_key_hash_pointer __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
120 PARROT_ASSERT_ARG(value))
121 #define ASSERT_ARGS_parrot_mark_hash_both __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
122 PARROT_ASSERT_ARG(interp) \
123 , PARROT_ASSERT_ARG(hash))
124 #define ASSERT_ARGS_parrot_mark_hash_keys __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
125 PARROT_ASSERT_ARG(interp) \
126 , PARROT_ASSERT_ARG(hash))
127 #define ASSERT_ARGS_parrot_mark_hash_values __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
128 PARROT_ASSERT_ARG(interp) \
129 , PARROT_ASSERT_ARG(hash))
130 #define ASSERT_ARGS_pointer_compare __attribute__unused__ int _ASSERT_ARGS_CHECK = (0)
131 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
132 /* HEADERIZER END: static */
138 =item C<size_t key_hash_STRING(PARROT_INTERP, STRING *s, size_t seed)>
140 Returns the hashed value of the key C<value>. See also string.c.
147 PARROT_WARN_UNUSED_RESULT
149 key_hash_STRING(PARROT_INTERP
, ARGMOD(STRING
*s
), SHIM(size_t seed
))
151 ASSERT_ARGS(key_hash_STRING
)
156 return Parrot_str_to_hashval(interp
, s
);
162 =item C<int STRING_compare(PARROT_INTERP, const void *search_key, const void
165 Compares the two strings, returning 0 if they are identical.
171 PARROT_WARN_UNUSED_RESULT
173 STRING_compare(PARROT_INTERP
, ARGIN(const void *search_key
), ARGIN_NULLOK(const void *bucket_key
))
175 ASSERT_ARGS(STRING_compare
)
176 STRING
const *s1
= (STRING
const *)search_key
;
177 STRING
const *s2
= (STRING
const *)bucket_key
;
182 if (s1
->hashval
!= s2
->hashval
)
186 if (Buffer_bufstart(s1
) == Buffer_bufstart(s2
)
187 && s1
->bufused
== s2
->bufused
)
190 return CHARSET_COMPARE(interp
, s1
, s2
);
196 =item C<int STRING_compare_distinct_cs_enc(PARROT_INTERP, const void
197 *search_key, const void *bucket_key)>
199 Compare two strings. Returns 0 if they are identical. Considers differing
200 charset or encoding to be distinct.
204 PARROT_WARN_UNUSED_RESULT
206 STRING_compare_distinct_cs_enc(PARROT_INTERP
, ARGIN(const void *search_key
),
207 ARGIN(const void *bucket_key
))
209 ASSERT_ARGS(STRING_compare_distinct_cs_enc
)
210 STRING
const *s1
= (STRING
const *)search_key
;
211 STRING
const *s2
= (STRING
const *)bucket_key
;
214 s1
->charset
!= s2
->charset
||
215 s1
->encoding
!= s2
->encoding
)) {
219 return STRING_compare(interp
, search_key
, bucket_key
);
225 =item C<static int pointer_compare(PARROT_INTERP, const void *a, const void *b)>
227 Compares the two pointers, returning 0 if they are identical
233 PARROT_WARN_UNUSED_RESULT
234 PARROT_CONST_FUNCTION
236 pointer_compare(SHIM_INTERP
, ARGIN_NULLOK(const void *a
), ARGIN_NULLOK(const void *b
))
238 ASSERT_ARGS(pointer_compare
)
245 =item C<static size_t key_hash_pointer(PARROT_INTERP, const void *value, size_t
248 Returns a hashvalue for a pointer.
254 PARROT_WARN_UNUSED_RESULT
255 PARROT_CONST_FUNCTION
257 key_hash_pointer(SHIM_INTERP
, ARGIN(const void *value
), size_t seed
)
259 ASSERT_ARGS(key_hash_pointer
)
260 return ((size_t) value
) ^ seed
;
266 =item C<static size_t key_hash_cstring(PARROT_INTERP, const void *value, size_t
269 Creates and returns a hash value from a string.
271 Takes an interpreter, a pointer to a string, and a seed value.
272 Returns the hash value.
274 Used by parrot_new_cstring_hash.
280 PARROT_WARN_UNUSED_RESULT
283 key_hash_cstring(SHIM_INTERP
, ARGIN(const void *value
), size_t seed
)
285 ASSERT_ARGS(key_hash_cstring
)
286 const unsigned char * p
= (const unsigned char *) value
;
287 register size_t h
= seed
;
300 =item C<static int cstring_compare(PARROT_INTERP, const char *a, const char *b)>
302 Compares two C strings for equality, returning -1, 0, and 1 if the first string
303 is less than, equal to, or greater than the second, respectively.
309 PARROT_WARN_UNUSED_RESULT
312 cstring_compare(SHIM_INTERP
, ARGIN(const char *a
), ARGIN(const char *b
))
314 ASSERT_ARGS(cstring_compare
)
321 =item C<size_t key_hash_PMC(PARROT_INTERP, PMC *value, size_t seed)>
323 Returns a hashed value for an PMC key (passed as a void pointer, sadly).
329 PARROT_WARN_UNUSED_RESULT
332 key_hash_PMC(PARROT_INTERP
, ARGIN(PMC
*value
), SHIM(size_t seed
))
334 ASSERT_ARGS(key_hash_PMC
)
335 return VTABLE_hashvalue(interp
, value
);
340 =item C<int PMC_compare(PARROT_INTERP, PMC *a, PMC *b)>
342 Compares two PMC for equality, returning 0 if the first is equal to second.
343 Uses void pointers to store the PMC, sadly.
349 PARROT_WARN_UNUSED_RESULT
352 PMC_compare(PARROT_INTERP
, ARGIN(PMC
*a
), ARGIN(PMC
*b
))
354 ASSERT_ARGS(PMC_compare
)
356 /* If pointers are same - PMCs are same */
360 /* PMCs of different types are differ */
361 if (a
->vtable
->base_type
!= b
->vtable
->base_type
)
364 return !VTABLE_is_equal(interp
, a
, b
);
369 =item C<size_t key_hash_int(PARROT_INTERP, const void *value, size_t seed)>
371 Returns a hashed value for an integer key (passed as a void pointer, sadly).
377 PARROT_WARN_UNUSED_RESULT
378 PARROT_CONST_FUNCTION
380 key_hash_int(SHIM_INTERP
, ARGIN_NULLOK(const void *value
), size_t seed
)
382 ASSERT_ARGS(key_hash_int
)
383 return (size_t)value
^ seed
;
388 =item C<int int_compare(PARROT_INTERP, const void *a, const void *b)>
390 Compares two integers for equality, returning -1, 0, and 1 if the first is less
391 than, equal to, or greater than the second, respectively. Uses void pointers
392 to store the integers, sadly.
398 PARROT_WARN_UNUSED_RESULT
399 PARROT_CONST_FUNCTION
401 int_compare(SHIM_INTERP
, ARGIN_NULLOK(const void *a
), ARGIN_NULLOK(const void *b
))
403 ASSERT_ARGS(int_compare
)
409 =item C<void parrot_dump_hash(PARROT_INTERP, const Hash *hash)>
411 Prints out the hash in human-readable form, at least once someone implements
420 parrot_dump_hash(SHIM_INTERP
, SHIM(const Hash
*hash
))
422 ASSERT_ARGS(parrot_dump_hash
)
428 =item C<void parrot_mark_hash(PARROT_INTERP, Hash *hash)>
430 Marks the hash and its contents as live. Assumes that key and value are non
439 parrot_mark_hash(PARROT_INTERP
, ARGMOD(Hash
*hash
))
441 ASSERT_ARGS(parrot_mark_hash
)
445 if (hash
->entry_type
== (PARROT_DATA_TYPE
) enum_hash_string
446 || hash
->entry_type
== (PARROT_DATA_TYPE
) enum_hash_pmc
)
449 if (hash
->key_type
== Hash_key_type_STRING
450 || hash
->key_type
== Hash_key_type_PMC
)
455 parrot_mark_hash_both(interp
, hash
);
457 parrot_mark_hash_keys(interp
, hash
);
461 parrot_mark_hash_values(interp
, hash
);
468 =item C<static void parrot_mark_hash_keys(PARROT_INTERP, Hash *hash)>
470 Marks the hash and only its keys as live.
477 parrot_mark_hash_keys(PARROT_INTERP
, ARGIN(Hash
*hash
))
479 ASSERT_ARGS(parrot_mark_hash_keys
)
480 UINTVAL entries
= hash
->entries
;
484 for (i
= hash
->mask
; i
>= 0; --i
) {
485 HashBucket
*bucket
= hash
->bi
[i
];
488 if (++found
> entries
)
489 Parrot_ex_throw_from_c_args(interp
, NULL
, 1,
490 "Detected hash corruption at hash %p entries %d",
493 PARROT_ASSERT(bucket
->key
);
494 Parrot_gc_mark_PObj_alive(interp
, (PObj
*)bucket
->key
);
496 bucket
= bucket
->next
;
504 =item C<static void parrot_mark_hash_values(PARROT_INTERP, Hash *hash)>
506 Marks the hash and only its values as live.
513 parrot_mark_hash_values(PARROT_INTERP
, ARGIN(Hash
*hash
))
515 ASSERT_ARGS(parrot_mark_hash_values
)
516 const UINTVAL entries
= hash
->entries
;
520 for (i
= hash
->mask
; i
>= 0; --i
) {
521 HashBucket
*bucket
= hash
->bi
[i
];
524 if (++found
> entries
)
525 Parrot_ex_throw_from_c_args(interp
, NULL
, 1,
526 "Detected hash corruption at hash %p entries %d",
529 PARROT_ASSERT(bucket
->value
);
530 Parrot_gc_mark_PObj_alive(interp
, (PObj
*)bucket
->value
);
532 bucket
= bucket
->next
;
540 =item C<static void parrot_mark_hash_both(PARROT_INTERP, Hash *hash)>
542 Marks the hash and both its keys and values as live.
549 parrot_mark_hash_both(PARROT_INTERP
, ARGIN(Hash
*hash
))
551 ASSERT_ARGS(parrot_mark_hash_both
)
552 const UINTVAL entries
= hash
->entries
;
556 for (i
= hash
->mask
; i
>= 0; --i
) {
557 HashBucket
*bucket
= hash
->bi
[i
];
560 if (++found
> entries
)
561 Parrot_ex_throw_from_c_args(interp
, NULL
, 1,
562 "Detected hash corruption at hash %p entries %d",
565 PARROT_ASSERT(bucket
->key
);
566 Parrot_gc_mark_PObj_alive(interp
, (PObj
*)bucket
->key
);
568 PARROT_ASSERT(bucket
->value
);
569 Parrot_gc_mark_PObj_alive(interp
, (PObj
*)bucket
->value
);
571 bucket
= bucket
->next
;
579 =item C<static void hash_thaw(PARROT_INTERP, Hash *hash, PMC *info)>
581 Visits the contents of a hash during freeze/thaw.
583 C<pinfo> is the visit info, (see include/parrot/pmc_freeze.h>).
590 hash_thaw(PARROT_INTERP
, ARGMOD(Hash
*hash
), ARGMOD(PMC
*info
))
592 ASSERT_ARGS(hash_thaw
)
594 /* during thaw, info->extra is the key/value count */
595 const size_t num_entries
= (size_t) hash
->entries
;
600 for (entry_index
= 0; entry_index
< num_entries
; ++entry_index
) {
603 switch (hash
->key_type
) {
604 case Hash_key_type_int
:
606 const INTVAL i_key
= VTABLE_shift_integer(interp
, info
);
607 b
= parrot_hash_put(interp
, hash
, (void*)i_key
, NULL
);
610 case Hash_key_type_STRING
:
612 STRING
* const s_key
= VTABLE_shift_string(interp
, info
);
613 b
= parrot_hash_put(interp
, hash
, s_key
, NULL
);
616 case Hash_key_type_PMC
:
618 PMC
* const p_key
= VTABLE_shift_pmc(interp
, info
);
619 b
= parrot_hash_put(interp
, hash
, p_key
, NULL
);
623 Parrot_ex_throw_from_c_args(interp
, NULL
, 1,
624 "unimplemented key type");
628 switch (hash
->entry_type
) {
631 const INTVAL i
= VTABLE_shift_integer(interp
, info
);
632 b
->value
= (void *)i
;
635 case enum_hash_string
:
637 STRING
* const s
= VTABLE_shift_string(interp
, info
);
638 b
->value
= (void *)s
;
643 PMC
* const p
= VTABLE_shift_pmc(interp
, info
);
644 b
->value
= (void *)p
;
648 Parrot_ex_throw_from_c_args(interp
, NULL
, 1,
649 "unimplemented value type");
658 =item C<static void hash_freeze(PARROT_INTERP, const Hash *hash, PMC *info)>
660 Freezes hash into a string.
662 Takes an interpreter, a pointer to the hash, and a pointer to the structure
663 containing the string start location.
665 Use by parrot_hash_visit.
672 hash_freeze(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGMOD(PMC
*info
))
674 ASSERT_ARGS(hash_freeze
)
677 for (i
= 0; i
< hash
->entries
; ++i
) {
678 HashBucket
* const b
= hash
->bs
+i
;
680 switch (hash
->key_type
) {
681 case Hash_key_type_int
:
682 VTABLE_push_integer(interp
, info
, (INTVAL
)b
->key
);
684 case Hash_key_type_STRING
:
685 VTABLE_push_string(interp
, info
, (STRING
*)b
->key
);
687 case Hash_key_type_PMC
:
688 VTABLE_push_pmc(interp
, info
, (PMC
*)b
->key
);
691 Parrot_ex_throw_from_c_args(interp
, NULL
, 1,
692 "unimplemented key type");
696 switch (hash
->entry_type
) {
698 VTABLE_push_integer(interp
, info
, (INTVAL
)b
->value
);
700 case enum_hash_string
:
701 VTABLE_push_string(interp
, info
, (STRING
*)b
->value
);
704 VTABLE_push_pmc(interp
, info
, (PMC
*)b
->value
);
707 Parrot_ex_throw_from_c_args(interp
, NULL
, 1,
708 "unimplemented value type");
717 =item C<void parrot_hash_visit(PARROT_INTERP, Hash *hash, void *pinfo)>
719 Freezes or thaws a hash as specified. Takes an interpreter, a pointer to the
720 hash, and a pointer to the structure identifying what to do and the location of
729 parrot_hash_visit(PARROT_INTERP
, ARGMOD(Hash
*hash
), ARGMOD(void *pinfo
))
731 ASSERT_ARGS(parrot_hash_visit
)
732 PMC
* const info
= (PMC
*) pinfo
;
734 switch (VTABLE_get_integer(interp
, info
)) {
735 case VISIT_THAW_NORMAL
:
736 hash_thaw(interp
, hash
, info
);
738 case VISIT_FREEZE_NORMAL
:
739 hash_freeze(interp
, hash
, info
);
742 Parrot_ex_throw_from_c_args(interp
, NULL
, 1,
743 "unimplemented visit mode");
750 =item C<static void expand_hash(PARROT_INTERP, Hash *hash)>
752 Expands a hash when necessary.
754 For a hashtable of size N, we use C<MAXFULL_PERCENT> % of N as the
755 number of buckets. This way, as soon as we run out of buckets on the
756 free list, we know that it's time to resize the hashtable.
758 Algorithm for expansion: We exactly double the size of the hashtable.
759 Keys are assigned to buckets with the formula
761 bucket_index = hash(key) % parrot_hash_size
763 When doubling the size of the hashtable, we know that every key is either
764 already in the correct bucket, or belongs in the current bucket plus
765 C<parrot_hash_size> (the old C<parrot_hash_size>). In fact, because the
766 hashtable is always a power of two in size, it depends only on the next bit
767 in the hash value, after the ones previously used.
769 We scan through all the buckets in order, moving the buckets that need to be
770 moved. No bucket will be scanned twice, and the cache should be reasonably
771 happy because the hashtable accesses will be two parallel sequential scans.
772 (Of course, this also mucks with the C<< ->next >> pointers, and they'll be
780 expand_hash(PARROT_INTERP
, ARGMOD(Hash
*hash
))
782 ASSERT_ARGS(expand_hash
)
783 HashBucket
**old_bi
, **new_bi
;
784 HashBucket
*bs
, *b
, *new_mem
;
785 HashBucket
* const old_offset
= (HashBucket
*)((char *)hash
+ sizeof (Hash
));
787 void * const old_mem
= hash
->bs
;
788 const UINTVAL old_size
= hash
->mask
+ 1;
789 const UINTVAL new_size
= old_size
<< 1;
790 const UINTVAL old_nb
= N_BUCKETS(old_size
);
794 allocate some less buckets
795 e.g. 3 buckets, 4 pointers:
797 +---+---+---+-+-+-+-+
799 +---+---+---+-+-+-+-+
805 if (old_offset
!= old_mem
) {
806 /* This buffer has been reallocated at least once before. */
807 new_mem
= (HashBucket
*)Parrot_gc_reallocate_memory_chunk_with_interior_pointers(
808 interp
, old_mem
, HASH_ALLOC_SIZE(new_size
), HASH_ALLOC_SIZE(old_size
));
811 /* Allocate a new buffer. */
812 new_mem
= (HashBucket
*)Parrot_gc_allocate_memory_chunk_with_interior_pointers(
813 interp
, HASH_ALLOC_SIZE(new_size
));
814 memcpy(new_mem
, old_mem
, HASH_ALLOC_SIZE(old_size
));
818 +---+---+---+---+---+---+-+-+-+-+-+-+-+-+
819 | bs | old_bi | new_bi |
820 +---+---+---+---+---+---+-+-+-+-+-+-+-+-+
825 old_bi
= (HashBucket
**)(bs
+ old_nb
);
826 new_bi
= (HashBucket
**)(bs
+ N_BUCKETS(new_size
));
828 /* things can have moved by this offset */
829 offset
= (char *)new_mem
- (char *)old_mem
;
831 /* relocate the bucket index */
832 mem_sys_memmove(new_bi
, old_bi
, old_size
* sizeof (HashBucket
*));
834 /* update hash data */
837 hash
->mask
= new_size
- 1;
839 /* clear freshly allocated bucket index */
840 memset(new_bi
+ old_size
, 0, sizeof (HashBucket
*) * old_size
);
843 * reloc pointers - this part would be also needed, if we
844 * allocate hash memory from GC movable memory, and then
845 * also the free_list needs updating (this is empty now,
846 * as expand_hash is only called for that case).
850 for (j
= 0; j
< old_size
; ++j
) {
851 HashBucket
**next_p
= new_bi
+ j
;
853 *next_p
= (HashBucket
*)((char *)*next_p
+ offset
);
860 /* recalc bucket index */
861 for (i
= 0; i
< old_size
; ++i
) {
862 HashBucket
**next_p
= new_bi
+ i
;
864 while ((b
= *next_p
) != NULL
) {
865 /* rehash the bucket */
866 const size_t new_loc
=
867 (hash
->hash_val
)(interp
, b
->key
, hash
->seed
) & (new_size
- 1);
871 b
->next
= new_bi
[new_loc
];
879 /* add new buckets to free_list in reverse order
880 * lowest bucket is top on free list and will be used first */
881 for (i
= 0, b
= (HashBucket
*)new_bi
- 1; i
< old_nb
; ++i
, --b
) {
882 b
->next
= hash
->free_list
;
883 b
->key
= b
->value
= NULL
;
891 =item C<Hash* parrot_new_hash(PARROT_INTERP)>
893 Creates a new Parrot STRING hash.
900 PARROT_CANNOT_RETURN_NULL
902 parrot_new_hash(PARROT_INTERP
)
904 ASSERT_ARGS(parrot_new_hash
)
905 return parrot_create_hash(interp
,
907 Hash_key_type_STRING
,
909 (hash_hash_key_fn
)key_hash_STRING
);
915 =item C<Hash* parrot_new_cstring_hash(PARROT_INTERP)>
917 Creates a new C string hash in C<hptr>.
924 PARROT_CANNOT_RETURN_NULL
926 parrot_new_cstring_hash(PARROT_INTERP
)
928 ASSERT_ARGS(parrot_new_cstring_hash
)
929 return parrot_create_hash(interp
,
931 Hash_key_type_cstring
,
932 (hash_comp_fn
)cstring_compare
,
933 (hash_hash_key_fn
)key_hash_cstring
);
939 =item C<Hash * parrot_new_pointer_hash(PARROT_INTERP)>
941 Create and return a new hash with void * keys and values.
948 PARROT_CANNOT_RETURN_NULL
950 parrot_new_pointer_hash(PARROT_INTERP
)
952 ASSERT_ARGS(parrot_new_pointer_hash
)
953 return parrot_create_hash(interp
,
963 =item C<Hash* parrot_new_intval_hash(PARROT_INTERP)>
965 Creates and returns new Hash PMC with INTVAL keys and values. C<flags> can be
966 C<PObj_constant_FLAG> or 0.
974 PARROT_WARN_UNUSED_RESULT
975 PARROT_CANNOT_RETURN_NULL
977 parrot_new_intval_hash(PARROT_INTERP
)
979 ASSERT_ARGS(parrot_new_intval_hash
)
980 return parrot_create_hash(interp
,
989 =item C<Hash * parrot_create_hash(PARROT_INTERP, PARROT_DATA_TYPE val_type,
990 Hash_key_type hkey_type, hash_comp_fn compare, hash_hash_key_fn keyhash)>
992 Creates and initializes a hash. Function pointers determine its behaviors.
993 The container passed in is the address of the hash PMC that is using it. The
994 hash and the PMC point to each other.
996 Memory from this function must be freed.
1002 PARROT_CANNOT_RETURN_NULL
1003 PARROT_WARN_UNUSED_RESULT
1006 parrot_create_hash(PARROT_INTERP
, PARROT_DATA_TYPE val_type
, Hash_key_type hkey_type
,
1007 NOTNULL(hash_comp_fn compare
), NOTNULL(hash_hash_key_fn keyhash
))
1009 ASSERT_ARGS(parrot_create_hash
)
1011 void *alloc
= Parrot_gc_allocate_memory_chunk_with_interior_pointers(
1012 interp
, sizeof (Hash
) + HASH_ALLOC_SIZE(INITIAL_BUCKETS
));
1013 Hash
* const hash
= (Hash
*)alloc
;
1016 PARROT_ASSERT(INITIAL_BUCKETS
% 4 == 0);
1018 hash
->compare
= compare
;
1019 hash
->hash_val
= keyhash
;
1020 hash
->entry_type
= val_type
;
1021 hash
->key_type
= hkey_type
;
1022 hash
->seed
= interp
->hash_seed
;
1023 hash
->mask
= INITIAL_BUCKETS
- 1;
1025 hash
->container
= PMCNULL
;
1028 * TODO if we have a significant amount of small hashes:
1029 * - allocate a bigger hash structure e.g. 128 byte
1030 * - use the bucket store and bi inside this structure
1031 * - when reallocate copy this part
1033 bp
= (HashBucket
*)((char *)alloc
+ sizeof (Hash
));
1034 hash
->free_list
= NULL
;
1036 /* fill free_list from hi addresses so that we can use
1037 * buckets[i] directly in an OrderedHash, *if* nothing
1041 bp
+= N_BUCKETS(INITIAL_BUCKETS
);
1042 hash
->bi
= (HashBucket
**)bp
;
1044 for (i
= 0, --bp
; i
< N_BUCKETS(INITIAL_BUCKETS
); ++i
, --bp
) {
1045 bp
->next
= hash
->free_list
;
1046 hash
->free_list
= bp
;
1055 =item C<void parrot_hash_destroy(PARROT_INTERP, Hash *hash)>
1057 Frees the memory allocated to the specified hash and its bucket store. Used by
1058 parrot_chash_destroy.
1060 Unlike the C library function free(), the hash function must not be NULL.
1068 parrot_hash_destroy(PARROT_INTERP
, ARGFREE_NOTNULL(Hash
*hash
))
1070 ASSERT_ARGS(parrot_hash_destroy
)
1071 HashBucket
* const bp
= (HashBucket
*)((char*)hash
+ sizeof (Hash
));
1073 mem_gc_free(interp
, hash
->bs
);
1074 mem_gc_free(interp
, hash
);
1080 =item C<void parrot_chash_destroy(PARROT_INTERP, Hash *hash)>
1082 Deletes the specified hash by freeing the memory allocated to all the key-value
1083 pairs, and finally the hash itself.
1090 parrot_chash_destroy(PARROT_INTERP
, ARGMOD(Hash
*hash
))
1092 ASSERT_ARGS(parrot_chash_destroy
)
1095 for (i
= 0; i
<= hash
->mask
; ++i
) {
1096 HashBucket
*bucket
= hash
->bi
[i
];
1098 mem_gc_free(interp
, bucket
->key
);
1099 mem_gc_free(interp
, bucket
->value
);
1100 bucket
= bucket
->next
;
1104 parrot_hash_destroy(interp
, hash
);
1110 =item C<void parrot_chash_destroy_values(PARROT_INTERP, Hash *hash, value_free
1113 Deletes the specified hash by freeing the memory allocated to all the key-value
1114 pairs, calling the provided callback to free the values, and finally the hash
1117 The callback returns C<void> and takes a C<void *>.
1124 parrot_chash_destroy_values(PARROT_INTERP
, ARGMOD(Hash
*hash
), NOTNULL(value_free func
))
1126 ASSERT_ARGS(parrot_chash_destroy_values
)
1129 for (i
= 0; i
<= hash
->mask
; ++i
) {
1130 HashBucket
*bucket
= hash
->bi
[i
];
1132 mem_gc_free(interp
, bucket
->key
);
1133 func(bucket
->value
);
1134 bucket
= bucket
->next
;
1138 parrot_hash_destroy(interp
, hash
);
1144 =item C<INTVAL parrot_hash_size(PARROT_INTERP, const Hash *hash)>
1146 Returns the number of used entries in the hash.
1153 PARROT_WARN_UNUSED_RESULT
1154 PARROT_PURE_FUNCTION
1156 parrot_hash_size(SHIM_INTERP
, ARGIN(const Hash
*hash
))
1158 ASSERT_ARGS(parrot_hash_size
)
1160 return hash
->entries
;
1166 =item C<void * parrot_hash_get_idx(PARROT_INTERP, const Hash *hash, PMC *key)>
1168 Finds the next index into the hash's internal storage for the given Key. Used
1176 PARROT_WARN_UNUSED_RESULT
1177 PARROT_CAN_RETURN_NULL
1179 parrot_hash_get_idx(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGMOD(PMC
*key
))
1181 ASSERT_ARGS(parrot_hash_get_idx
)
1184 INTVAL i
= VTABLE_get_integer(interp
, key
);
1188 /* idx directly in the bucket store, which is at negative
1189 * address from the data pointer */
1190 /* locate initial */
1191 const INTVAL size
= (INTVAL
)N_BUCKETS(hash
->mask
+ 1);
1193 GETATTR_Key_next_key(interp
, key
, fake_bi
);
1194 bi
= (BucketIndex
)fake_bi
;
1196 if (bi
== INITBucketIndex
) {
1198 SETATTR_Key_next_key(interp
, key
, NULL
);
1200 else if (i
>= size
|| i
< 0) {
1201 /* NOTE: These instances of SETATTR_Key_int_key can't be VTABLE
1202 * functions because of the "special" way hash iterators work. */
1203 SETATTR_Key_int_key(interp
, key
, -1);
1209 for (b
= hash
->bs
+ i
; i
< size
; ++i
, ++b
) {
1210 /* XXX int keys may be zero - use different iterator */
1215 /* found next key - FIXME hash iter does auto next */
1224 SETATTR_Key_int_key(interp
, key
, i
);
1232 =item C<HashBucket * parrot_hash_get_bucket(PARROT_INTERP, const Hash *hash,
1235 Returns the bucket for C<key>, if found, and NULL otherwise.
1242 PARROT_WARN_UNUSED_RESULT
1243 PARROT_CAN_RETURN_NULL
1245 parrot_hash_get_bucket(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN_NULLOK(const void *key
))
1247 ASSERT_ARGS(parrot_hash_get_bucket
)
1249 if (hash
->entries
<= 0)
1252 /* a very fast search for very small hashes */
1253 if (hash
->entries
<= SMALL_HASH_SIZE
) {
1254 const UINTVAL entries
= hash
->entries
;
1257 for (i
= 0; i
< entries
; ++i
) {
1258 HashBucket
* const bucket
= hash
->bs
+ i
;
1260 /* the hash->compare cost is too high for this fast path */
1261 if (bucket
->key
== key
)
1266 /* if the fast search didn't work, try the normal hashing search */
1268 const UINTVAL hashval
= (hash
->hash_val
)(interp
, key
, hash
->seed
);
1269 HashBucket
*bucket
= hash
->bi
[hashval
& hash
->mask
];
1272 /* key equality is always a match, so it's worth checking */
1273 if (bucket
->key
== key
1275 /* ... but the slower comparison is more accurate */
1276 || ((hash
->compare
)(interp
, key
, bucket
->key
) == 0))
1278 bucket
= bucket
->next
;
1288 =item C<void * parrot_hash_get(PARROT_INTERP, const Hash *hash, const void
1291 Returns the value keyed by C<key>, or C<NULL> if no bucket is found.
1298 PARROT_WARN_UNUSED_RESULT
1299 PARROT_CAN_RETURN_NULL
1301 parrot_hash_get(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN(const void *key
))
1303 ASSERT_ARGS(parrot_hash_get
)
1304 const HashBucket
* const bucket
= parrot_hash_get_bucket(interp
, hash
, key
);
1305 return bucket
? bucket
->value
: NULL
;
1311 =item C<INTVAL parrot_hash_exists(PARROT_INTERP, const Hash *hash, void *key)>
1313 Returns whether the key exists in the hash.
1320 PARROT_WARN_UNUSED_RESULT
1322 parrot_hash_exists(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN(void *key
))
1324 ASSERT_ARGS(parrot_hash_exists
)
1325 const HashBucket
* const bucket
= parrot_hash_get_bucket(interp
, hash
, key
);
1326 return bucket
? 1 : 0;
1332 =item C<HashBucket* parrot_hash_put(PARROT_INTERP, Hash *hash, void *key, void
1335 Puts the key and value into the hash. Note that C<key> is B<not> copied.
1342 PARROT_IGNORABLE_RESULT
1343 PARROT_CANNOT_RETURN_NULL
1345 parrot_hash_put(PARROT_INTERP
, ARGMOD(Hash
*hash
),
1346 ARGIN_NULLOK(void *key
), ARGIN_NULLOK(void *value
))
1348 ASSERT_ARGS(parrot_hash_put
)
1349 const UINTVAL hashval
= (hash
->hash_val
)(interp
, key
, hash
->seed
);
1350 HashBucket
*bucket
= hash
->bi
[hashval
& hash
->mask
];
1352 /* When the hash is constant, check that the key and value are also
1354 if (!PMC_IS_NULL(hash
->container
)
1355 && PObj_constant_TEST(hash
->container
)) {
1356 if (hash
->key_type
== Hash_key_type_STRING
1357 && !PObj_constant_TEST((PObj
*)key
))
1358 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_INVALID_OPERATION
,
1359 "Used non-constant key in constant hash.");
1360 if (((hash
->entry_type
== enum_type_PMC
)
1361 || (hash
->entry_type
== enum_type_STRING
))
1362 && !PObj_constant_TEST((PObj
*)value
))
1363 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_INVALID_OPERATION
,
1364 "Used non-constant value in constant hash.");
1368 /* store hash_val or not */
1369 if ((hash
->compare
)(interp
, key
, bucket
->key
) == 0)
1371 bucket
= bucket
->next
;
1375 bucket
->value
= value
;
1377 bucket
= hash
->free_list
;
1380 expand_hash(interp
, hash
);
1381 bucket
= hash
->free_list
;
1385 hash
->free_list
= bucket
->next
;
1387 bucket
->value
= value
;
1388 bucket
->next
= hash
->bi
[hashval
& hash
->mask
];
1389 hash
->bi
[hashval
& hash
->mask
] = bucket
;
1398 =item C<void parrot_hash_delete(PARROT_INTERP, Hash *hash, void *key)>
1400 Deletes the key from the hash.
1408 parrot_hash_delete(PARROT_INTERP
, ARGMOD(Hash
*hash
), ARGIN(void *key
))
1410 ASSERT_ARGS(parrot_hash_delete
)
1412 HashBucket
*prev
= NULL
;
1413 const UINTVAL hashval
= (hash
->hash_val
)(interp
, key
, hash
->seed
) & hash
->mask
;
1415 for (bucket
= hash
->bi
[hashval
]; bucket
; bucket
= bucket
->next
) {
1416 if ((hash
->compare
)(interp
, key
, bucket
->key
) == 0) {
1419 prev
->next
= bucket
->next
;
1421 hash
->bi
[hashval
] = bucket
->next
;
1424 bucket
->next
= hash
->free_list
;
1426 hash
->free_list
= bucket
;
1438 =item C<void parrot_hash_clone(PARROT_INTERP, const Hash *hash, Hash *dest)>
1440 Clones C<hash> to C<dest>.
1448 parrot_hash_clone(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGOUT(Hash
*dest
))
1450 ASSERT_ARGS(parrot_hash_clone
)
1451 UINTVAL entries
= hash
->entries
;
1454 for (i
= 0; i
< entries
; ++i
) {
1456 HashBucket
*b
= hash
->bs
+i
;
1457 void * const key
= b
->key
;
1459 switch (hash
->entry_type
) {
1460 case enum_type_undef
:
1462 case enum_type_INTVAL
:
1463 valtmp
= (void *)b
->value
;
1466 case enum_type_STRING
:
1471 if (PMC_IS_NULL((PMC
*)b
->value
))
1472 valtmp
= (void *)PMCNULL
;
1474 valtmp
= (void *)VTABLE_clone(interp
, (PMC
*)b
->value
);
1478 valtmp
= NULL
; /* avoid warning */
1479 Parrot_ex_throw_from_c_args(interp
, NULL
, -1,
1480 "hash corruption: type = %d\n", hash
->entry_type
);
1484 parrot_hash_put(interp
, dest
, key
, valtmp
);
1490 =item C<PMC* get_integer_pmc(PARROT_INTERP, INTVAL value)>
1492 Lookup the PMC type which is used for storing native integers.
1498 PARROT_CANNOT_RETURN_NULL
1500 get_integer_pmc(PARROT_INTERP
, INTVAL value
)
1502 ASSERT_ARGS(get_integer_pmc
)
1503 PMC
* const ret
= Parrot_pmc_new(interp
, Parrot_get_ctx_HLL_type(interp
, enum_class_Integer
));
1504 VTABLE_set_integer_native(interp
, ret
, value
);
1511 =item C<PMC* get_number_pmc(PARROT_INTERP, FLOATVAL value)>
1513 Lookup the PMC type which is used for floating point numbers.
1519 PARROT_CANNOT_RETURN_NULL
1521 get_number_pmc(PARROT_INTERP
, FLOATVAL value
)
1523 ASSERT_ARGS(get_number_pmc
)
1524 PMC
* const ret
= Parrot_pmc_new(interp
, Parrot_get_ctx_HLL_type(interp
, enum_class_Float
));
1525 VTABLE_set_number_native(interp
, ret
, value
);
1531 =item C<PMC * get_string_pmc(PARROT_INTERP, STRING *value)>
1533 Lookup the PMC type which is used for storing strings.
1539 PARROT_CANNOT_RETURN_NULL
1541 get_string_pmc(PARROT_INTERP
, ARGIN(STRING
*value
))
1543 ASSERT_ARGS(get_string_pmc
)
1544 PMC
* const ret
= Parrot_pmc_new(interp
, Parrot_get_ctx_HLL_type(interp
, enum_class_String
));
1545 VTABLE_set_string_native(interp
, ret
, value
);
1552 Poor-man polymorphic functions to convert something to something.
1554 There is bunch of functions to convert from passed value to stored keys type and to/from
1557 void *hash_key_from_TYPE convert to keys type.
1558 TYPE hash_key_to_TYPE convert from keys type.
1559 void *hash_value_from_TYPE convert to values type.
1560 TYPE hash_value_to_TYPE convert from values type.
1566 =item C<void* hash_key_from_int(PARROT_INTERP, const Hash *hash, INTVAL key)>
1568 Cast INTVAL to hash key.
1574 PARROT_CAN_RETURN_NULL
1576 hash_key_from_int(PARROT_INTERP
, ARGIN(const Hash
*hash
), INTVAL key
)
1578 ASSERT_ARGS(hash_key_from_int
)
1580 switch (hash
->key_type
) {
1581 case Hash_key_type_int
:
1584 /* Currently PMCs are stringified */
1585 case Hash_key_type_PMC
:
1586 ret
= (void *)get_integer_pmc(interp
, key
);
1588 case Hash_key_type_STRING
:
1589 ret
= (void *)Parrot_str_from_int(interp
, key
);
1592 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
1593 "Hash: unsupported key_type");
1600 =item C<void* hash_key_from_string(PARROT_INTERP, const Hash *hash, STRING
1603 Cast STRING to hash key.
1609 PARROT_CAN_RETURN_NULL
1611 hash_key_from_string(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN(STRING
*key
))
1613 ASSERT_ARGS(hash_key_from_string
)
1615 switch (hash
->key_type
) {
1616 case Hash_key_type_int
:
1618 /* Pacify compiler about casting INVTAL to void */
1619 const INTVAL int_key
= Parrot_str_to_int(interp
, key
);
1620 ret
= INTVAL2PTR(void *, int_key
);
1624 case Hash_key_type_PMC
:
1625 ret
= get_string_pmc(interp
, key
);
1628 case Hash_key_type_STRING
:
1633 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
1634 "Hash: unsupported key_type");
1641 =item C<void* hash_key_from_pmc(PARROT_INTERP, const Hash *hash, PMC *key)>
1643 Cast PMC* to hash key.
1649 PARROT_CAN_RETURN_NULL
1651 hash_key_from_pmc(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN(PMC
*key
))
1653 ASSERT_ARGS(hash_key_from_pmc
)
1655 switch (hash
->key_type
) {
1656 case Hash_key_type_int
:
1658 const INTVAL int_key
= VTABLE_get_integer(interp
, key
);
1659 ret
= INTVAL2PTR(void *, int_key
);
1662 case Hash_key_type_PMC
:
1664 /* Extract real value from Key (and box it if nessary) */
1665 if (key
->vtable
->base_type
== enum_class_Key
)
1666 switch (key_type(interp
, key
)) {
1667 case KEY_integer_FLAG
:
1668 key
= get_integer_pmc(interp
, key_integer(interp
, key
));
1670 case KEY_string_FLAG
:
1671 key
= get_string_pmc(interp
, key_string(interp
, key
));
1673 case KEY_number_FLAG
:
1674 key
= get_number_pmc(interp
, key_number(interp
, key
));
1677 key
= key_pmc(interp
, key
);
1680 /* It's impossible if Keys are same (and they are not) */
1681 /* So throw exception */
1682 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_INVALID_OPERATION
,
1683 "hash: unexpected type of Key");
1690 case Hash_key_type_STRING
:
1692 STRING
* const tmp
= VTABLE_get_string(interp
, key
);
1693 if (STRING_IS_NULL(tmp
))
1694 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNEXPECTED_NULL
,
1695 "hash: can't use null as key");
1700 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
1701 "Hash: unsupported key_type");
1708 =item C<INTVAL hash_key_to_int(PARROT_INTERP, const Hash *hash, void *key)>
1710 Cast hash key to INTVAL.
1717 hash_key_to_int(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN_NULLOK(void *key
))
1719 ASSERT_ARGS(hash_key_to_int
)
1721 switch (hash
->key_type
) {
1722 case Hash_key_type_int
:
1725 case Hash_key_type_PMC
:
1726 ret
= VTABLE_get_integer(interp
, (PMC
*)key
);
1728 case Hash_key_type_STRING
:
1729 ret
= Parrot_str_to_int(interp
, (STRING
*)key
);
1732 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
1733 "Hash: unsupported key_type");
1740 =item C<STRING* hash_key_to_string(PARROT_INTERP, const Hash *hash, void *key)>
1742 Cast hash key to STRING.
1748 PARROT_CANNOT_RETURN_NULL
1750 hash_key_to_string(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN_NULLOK(void *key
))
1752 ASSERT_ARGS(hash_key_to_string
)
1754 switch (hash
->key_type
) {
1755 case Hash_key_type_int
:
1756 ret
= Parrot_str_from_int(interp
, (INTVAL
)key
);
1759 case Hash_key_type_PMC
:
1760 ret
= VTABLE_get_string(interp
, (PMC
*)key
);
1763 case Hash_key_type_STRING
:
1764 ret
= (STRING
*)key
;
1768 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
1769 "Hash: unsupported key_type");
1776 =item C<PMC* hash_key_to_pmc(PARROT_INTERP, const Hash * const hash, void *key)>
1778 Cast hash key to PMC*.
1784 PARROT_CANNOT_RETURN_NULL
1786 hash_key_to_pmc(PARROT_INTERP
, ARGIN(const Hash
* const hash
), ARGIN(void *key
))
1788 ASSERT_ARGS(hash_key_to_pmc
)
1790 switch (hash
->key_type
) {
1791 case Hash_key_type_int
:
1792 ret
= get_integer_pmc(interp
, (INTVAL
)key
);
1794 case Hash_key_type_PMC
:
1797 case Hash_key_type_STRING
:
1798 ret
= get_string_pmc(interp
, (STRING
*)key
);
1801 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
1802 "Hash: unsupported key_type");
1807 /* Second part - convert from stored void* to real type */
1808 /* TODO: FLOATVALs converted into Float PMC for now */
1812 =item C<void* hash_value_from_int(PARROT_INTERP, const Hash *hash, INTVAL
1815 Cast INTVAL to hash value.
1821 PARROT_CAN_RETURN_NULL
1823 hash_value_from_int(PARROT_INTERP
, ARGIN(const Hash
*hash
), INTVAL value
)
1825 ASSERT_ARGS(hash_value_from_int
)
1827 switch (hash
->entry_type
) {
1828 case enum_type_INTVAL
:
1829 ret
= INTVAL2PTR(void *, value
);
1833 PMC
* const tmp
= get_integer_pmc(interp
, value
);
1837 case enum_type_STRING
:
1838 ret
= (void *)Parrot_str_from_int(interp
, value
);
1841 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
1842 "Hash: unsupported entry_type");
1849 =item C<void* hash_value_from_string(PARROT_INTERP, const Hash *hash, STRING
1852 Cast STRING to hash value.
1858 PARROT_CAN_RETURN_NULL
1860 hash_value_from_string(PARROT_INTERP
, ARGIN(const Hash
*hash
),
1861 ARGIN_NULLOK(STRING
*value
))
1863 ASSERT_ARGS(hash_value_from_string
)
1865 switch (hash
->entry_type
) {
1866 case enum_type_INTVAL
:
1868 const INTVAL int_val
= STRING_IS_NULL(value
) ?
1869 (INTVAL
) 0 : Parrot_str_to_int(interp
, value
);
1870 ret
= INTVAL2PTR(void *, int_val
);
1873 case enum_type_STRING
:
1874 ret
= (void *)value
;
1878 PMC
* const s
= STRING_IS_NULL(value
) ?
1879 PMCNULL
: get_string_pmc(interp
, value
);
1884 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
1885 "Hash: unsupported entry_type");
1892 =item C<void* hash_value_from_pmc(PARROT_INTERP, const Hash *hash, PMC *value)>
1894 Cast PMC to hash value.
1900 PARROT_CAN_RETURN_NULL
1902 hash_value_from_pmc(PARROT_INTERP
, ARGIN(const Hash
*hash
),
1903 ARGIN_NULLOK(PMC
*value
))
1905 ASSERT_ARGS(hash_value_from_pmc
)
1907 switch (hash
->entry_type
) {
1908 case enum_type_INTVAL
:
1910 const INTVAL int_val
= PMC_IS_NULL(value
) ?
1911 (INTVAL
) 0 : VTABLE_get_integer(interp
, value
);
1912 ret
= INTVAL2PTR(void *, int_val
);
1915 case enum_type_STRING
:
1916 ret
= PMC_IS_NULL(value
) ?
1917 PMCNULL
: (void *)VTABLE_get_string(interp
, value
);
1920 ret
= (void *)value
;
1923 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
1924 "Hash: unsupported entry_type");
1931 =item C<void* hash_value_from_number(PARROT_INTERP, const Hash *hash, FLOATVAL
1934 Cast FLOATVAL to hash value.
1940 PARROT_CAN_RETURN_NULL
1942 hash_value_from_number(PARROT_INTERP
, ARGIN(const Hash
*hash
), FLOATVAL value
)
1944 ASSERT_ARGS(hash_value_from_number
)
1946 switch (hash
->entry_type
) {
1947 case enum_type_INTVAL
:
1949 const INTVAL tmp
= value
;
1953 case enum_type_STRING
:
1954 ret
= (void *)Parrot_str_from_num(interp
, value
);
1958 PMC
* const tmp
= get_number_pmc(interp
, value
);
1963 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
1964 "Hash: unsupported entry_type");
1971 =item C<INTVAL hash_value_to_int(PARROT_INTERP, const Hash *hash, void *value)>
1973 Cast hash value to INTVAL.
1980 hash_value_to_int(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN_NULLOK(void *value
))
1982 ASSERT_ARGS(hash_value_to_int
)
1984 switch (hash
->entry_type
) {
1986 case enum_type_INTVAL
:
1987 ret
= (INTVAL
)value
;
1989 case enum_type_STRING
:
1990 ret
= Parrot_str_to_int(interp
, (STRING
*)value
);
1993 ret
= VTABLE_get_integer(interp
, (PMC
*)value
);
1996 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
1997 "Hash: unsupported entry_type");
2004 =item C<STRING* hash_value_to_string(PARROT_INTERP, const Hash *hash, void
2007 Cast hash value to STRING.
2013 PARROT_CANNOT_RETURN_NULL
2015 hash_value_to_string(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN_NULLOK(void *value
))
2017 ASSERT_ARGS(hash_value_to_string
)
2019 switch (hash
->entry_type
) {
2020 case enum_type_INTVAL
:
2021 ret
= Parrot_str_from_int(interp
, (INTVAL
)value
);
2023 case enum_type_STRING
:
2024 ret
= (STRING
*)value
;
2027 ret
= VTABLE_get_string(interp
, (PMC
*)value
);
2030 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
2031 "Hash: unsupported entry_type");
2038 =item C<PMC* hash_value_to_pmc(PARROT_INTERP, const Hash *hash, void *value)>
2040 Cast hash value to PMC.
2046 PARROT_CANNOT_RETURN_NULL
2048 hash_value_to_pmc(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN_NULLOK(void *value
))
2050 ASSERT_ARGS(hash_value_to_pmc
)
2052 switch (hash
->entry_type
) {
2053 case enum_type_INTVAL
:
2054 ret
= get_integer_pmc(interp
, (INTVAL
)value
);
2056 case enum_type_STRING
:
2057 ret
= get_string_pmc(interp
, (STRING
*)value
);
2063 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
2064 "Hash: unsupported entry_type");
2071 =item C<FLOATVAL hash_value_to_number(PARROT_INTERP, const Hash *hash, void
2074 Cast hash value to FLOATVAL.
2081 hash_value_to_number(PARROT_INTERP
, ARGIN(const Hash
*hash
), ARGIN_NULLOK(void *value
))
2083 ASSERT_ARGS(hash_value_to_number
)
2085 switch (hash
->entry_type
) {
2086 case enum_type_INTVAL
:
2088 /* Pacify compiler about casting */
2089 const INTVAL tmp
= (INTVAL
)value
;
2093 case enum_type_STRING
:
2094 ret
= Parrot_str_to_num(interp
, (STRING
*)value
);
2097 ret
= VTABLE_get_number(interp
, (PMC
*)value
);
2100 Parrot_ex_throw_from_c_args(interp
, NULL
, EXCEPTION_UNIMPLEMENTED
,
2101 "Hash: unsupported entry_type");
2112 F<docs/pdds/pdd08_keys.pod>.
2116 Future optimizations:
2120 =item * Stop reallocating the bucket pool, and instead add chunks on.
2121 (Saves pointer fixups and copying during C<realloc>.)
2123 =item * Hash contraction (don't if it's worth it)
2134 * c-file-style: "parrot"
2136 * vim: expandtab shiftwidth=4: