2 Copyright (C) 2001-2010, Parrot Foundation.
7 src/pmc/hash.pmc - Hash PMC
11 Hash PMC wraps Parrot's _hash to provide a high-level API:
17 Convert between various types to use as hash keys.
21 Convert between various types to use as hash values.
25 Handle compound Keys for nested Hash/Array lookups.
29 Provide C<HashIterator> to iterate over C<Hash>.
33 By default Hash uses string keys and PMC values. Methods C<set_key_type> and
34 C<set_value_type> may be used to switch key and values type. For C<PMC> keys
35 hash value is calculated using VTABLE C<get_hashvalue> function.
37 These are the vtable functions for the Hash PMC.
47 #include "pmc/pmc_iterator.h"
48 #include "pmc/pmc_key.h"
49 #include "pmc/pmc_hashiteratorkey.h"
51 /* HEADERIZER HFILE: none */
52 /* HEADERIZER BEGIN: static */
53 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
55 PARROT_CANNOT_RETURN_NULL
56 PARROT_WARN_UNUSED_RESULT
57 static PMC* get_next_hash(PARROT_INTERP,
60 __attribute__nonnull__(1)
61 __attribute__nonnull__(2)
62 __attribute__nonnull__(3)
65 #define ASSERT_ARGS_get_next_hash __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
66 PARROT_ASSERT_ARG(interp) \
67 , PARROT_ASSERT_ARG(hash) \
68 , PARROT_ASSERT_ARG(key))
69 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
70 /* HEADERIZER END: static */
74 =item C<static PMC* get_next_hash(PARROT_INTERP, Hash *hash, void *key)>
76 Get the next hash for multipart keys. Autovivify a hash if it doesn't exist.
82 PARROT_CANNOT_RETURN_NULL
83 PARROT_WARN_UNUSED_RESULT
85 get_next_hash(PARROT_INTERP, ARGMOD(Hash *hash), ARGIN(void *key))
87 ASSERT_ARGS(get_next_hash)
91 if (hash->entry_type != enum_type_PMC)
92 Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
93 "Hash entry type must be PMC for multipart keys.");
95 bucket = parrot_hash_get_bucket(interp, hash, key);
98 next_hash = (PMC *)bucket->value;
101 /* autovivify a Hash */
102 next_hash = Parrot_pmc_new(interp, enum_class_Hash);
103 parrot_hash_put(interp, hash, key, next_hash);
109 pmclass Hash provides hash auto_attrs {
116 Initializes the instance.
118 =item C<void init_int(INTVAL value_type)>
120 Initializes the instance with the value_type provided.
122 =item C<void destroy()>
131 Parrot_Hash_attributes * const attr =
132 (Parrot_Hash_attributes *) PMC_data(SELF);
134 attr->hash = parrot_new_hash(INTERP);
135 PObj_custom_mark_destroy_SETALL(SELF);
138 VTABLE void init_int(INTVAL value_type) {
139 Parrot_Hash_attributes * const attr =
140 (Parrot_Hash_attributes *) PMC_data(SELF);
142 attr->hash = parrot_create_hash(INTERP,
143 (PARROT_DATA_TYPE)value_type,
144 Hash_key_type_STRING);
145 PObj_custom_mark_destroy_SETALL(SELF);
148 VTABLE void destroy() {
149 Hash * const hash = (Hash *)SELF.get_pointer();
151 parrot_hash_destroy(INTERP, hash);
158 Marks the hash as live.
165 Hash * const hash = (Hash *)SELF.get_pointer();
166 if (hash && hash->entries)
167 parrot_mark_hash(INTERP, hash);
172 =item C<PMC *clone()>
174 Creates and returns a clone of the hash.
180 VTABLE PMC *clone() {
181 PMC * const dest = Parrot_pmc_new(INTERP, SELF->vtable->base_type);
183 parrot_hash_clone(INTERP, (Hash *)SELF.get_pointer(),
184 (Hash *)VTABLE_get_pointer(INTERP, dest));
191 =item C<void set_pointer(void *ptr)>
193 Use C<ptr> as this PMC's Hash*.
199 VTABLE void set_pointer(void *ptr) {
200 Hash * const old_hash = (Hash *)SELF.get_pointer();
201 Hash * const new_hash = (Hash *)ptr;
203 PARROT_HASH(SELF)->hash = new_hash;
206 parrot_hash_destroy(INTERP, old_hash);
212 =item C<void set_integer(INTVAL type)>
214 =item C<void set_key_type(INTVAL type)>
216 Reset Hash to use different keys. See enum C<Hash_key_type> for possible
219 NB: this method will destroy all old data!
224 VTABLE void set_integer_native(INTVAL type) {
226 Hash * const old_hash = PARROT_HASH(SELF)->hash;
227 PARROT_DATA_TYPE entry_type = old_hash
228 ? old_hash->entry_type
231 if (type == Hash_key_type_STRING)
232 new_hash = parrot_create_hash(INTERP,
234 Hash_key_type_STRING);
235 else if (type == Hash_key_type_int)
236 /* new_int_hash set BOTH keys and values to INTVAL */
237 new_hash = parrot_create_hash(INTERP,
240 else if (type == Hash_key_type_PMC)
241 /* new_int_hash set BOTH keys and values to INTVAL */
242 new_hash = parrot_create_hash(INTERP,
246 /* We probably will not implement other types of keys. They are way
247 * too dangerous to use from PIR */
248 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_UNIMPLEMENTED,
249 "Hash: Unknown key type");
252 PARROT_HASH(SELF)->hash = new_hash;
255 parrot_hash_destroy(INTERP, old_hash);
258 METHOD set_key_type(INTVAL type) {
259 SELF.set_integer_native(type);
264 =item C<METHOD get_key_type()>
266 Return type of keys in Hash.
271 METHOD get_key_type() {
272 const INTVAL ret = ((Hash *)SELF.get_pointer())->key_type;
278 =item C<METHOD set_value_type(INTVAL type)>
280 Reset Hash to use different value-type for stored items. If there is no
281 previous _hash was set defaults to STRING* keys.
283 NB: this method will destroy all old data!
287 METHOD set_value_type(INTVAL type) {
288 Hash *old_hash = (Hash *)SELF.get_pointer();
292 If someone called Hash.set_pointer with NULL pointer...
293 It will create STRING* keys hash.
296 if (old_hash && old_hash->entry_type == type)
300 case enum_type_INTVAL:
301 case enum_type_STRING:
303 new_hash = parrot_create_hash(INTERP,
304 (PARROT_DATA_TYPE)type,
305 old_hash ? old_hash->key_type : Hash_key_type_STRING);
308 Parrot_ex_throw_from_c_args(INTERP, NULL, EXCEPTION_UNIMPLEMENTED,
309 "Hash: unsupported entry_type %d", type);
312 PARROT_HASH(SELF)->hash = new_hash;
315 parrot_hash_destroy(INTERP, old_hash);
318 METHOD get_value_type() {
319 INTVAL ret = ((Hash *)SELF.get_pointer())->entry_type;
325 =item C<void *get_pointer()>
327 Get a pointer to this PMC's Hash*.
332 VTABLE void *get_pointer() {
333 return PARROT_HASH(SELF)->hash;
338 =item C<INTVAL get_integer()>
340 =item C<FLOATVAL get_number()>
342 Returns the size of the hash.
348 VTABLE INTVAL get_integer() {
349 return parrot_hash_size(INTERP, (Hash *)SELF.get_pointer());
352 VTABLE FLOATVAL get_number() {
353 return SELF.get_integer();
358 =item C<STRING *get_string()>
360 Returns a string representation of the hash, showing its class name and
363 =item C<STRING *get_repr()>
365 Return a representation of the hash contents.
371 VTABLE STRING *get_string() {
372 return Parrot_sprintf_c(INTERP, "Hash[0x%x]", SELF);
375 VTABLE STRING *get_repr() {
376 /* TT #1231: Use freeze in get_repr() (for hashes) */
377 PMC * const iter = VTABLE_get_iter(INTERP, SELF);
378 STRING *res = CONST_STRING(INTERP, "{");
379 const INTVAL n = VTABLE_elements(INTERP, SELF);
382 for (j = 0; j < n; ++j) {
383 STRING * const key = VTABLE_shift_string(INTERP, iter);
384 char * const key_str = Parrot_str_to_cstring(INTERP, key);
385 const size_t str_len = strlen(key_str);
390 for (i = 0; i < str_len; ++i) {
391 if (!isdigit((unsigned char)key_str[i])) {
397 Parrot_str_free_cstring(key_str);
400 res = Parrot_str_concat(INTERP, res, key);
403 res = Parrot_str_concat(INTERP, res, CONST_STRING(INTERP, "'"));
404 res = Parrot_str_concat(INTERP, res, key);
405 res = Parrot_str_concat(INTERP, res, CONST_STRING(INTERP, "'"));
408 res = Parrot_str_concat(INTERP, res, CONST_STRING(INTERP, ": "));
409 val = SELF.get_pmc_keyed_str(key);
410 res = Parrot_str_concat(INTERP, res, VTABLE_get_string(INTERP, val));
413 res = Parrot_str_concat(INTERP, res, CONST_STRING(INTERP, ", "));
416 res = Parrot_str_concat(INTERP, res, CONST_STRING(INTERP, "}"));
423 =item C<INTVAL get_integer_keyed_str(STRING *key)>
425 =item C<INTVAL get_integer_keyed_int(INTVAL key)>
431 VTABLE INTVAL get_integer_keyed_str(STRING *key) {
432 const Hash * const hash = (Hash*)SELF.get_pointer();
433 HashBucket * const b = parrot_hash_get_bucket(INTERP, hash,
434 hash_key_from_string(INTERP, hash, key));
439 return hash_value_to_int(INTERP, hash, b->value);
442 VTABLE INTVAL get_integer_keyed_int(INTVAL key) {
443 const Hash * const hash = (Hash*)SELF.get_pointer();
444 HashBucket * const b = parrot_hash_get_bucket(INTERP, hash,
445 hash_key_from_int(INTERP, hash, key));
450 return hash_value_to_int(INTERP, hash, b->value);
454 =item C<INTVAL get_integer_keyed(PMC *key)>
456 Returns the integer value for the element at C<*key>.
463 VTABLE INTVAL get_integer_keyed(PMC *key) {
464 const Hash * const hash = (Hash *)SELF.get_pointer();
465 const void * const hash_key = hash_key_from_pmc(INTERP, hash, key);
466 HashBucket * const b = parrot_hash_get_bucket(INTERP, hash, hash_key);
471 key = key_next(INTERP, key);
473 /* Stop recursion. This is last step */
475 return hash_value_to_int(INTERP, hash, b->value);
477 if (hash->entry_type != enum_type_PMC)
478 Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
479 "Hash entry type must be PMC for multipart keys.");
481 /* Recursively call to enclosed aggregate */
482 return VTABLE_get_integer_keyed(INTERP, (PMC *)b->value, key);
487 =item C<void set_integer_keyed(PMC *key, INTVAL value)>
493 VTABLE void set_integer_keyed(PMC *key, INTVAL value) {
494 Hash * const hash = (Hash *)SELF.get_pointer();
495 void * const hash_key = hash_key_from_pmc(INTERP, hash, key);
497 if (PObj_constant_TEST(SELF)
498 && !PObj_constant_TEST((PObj *)key))
499 Parrot_ex_throw_from_c_args(INTERP, NULL,
500 EXCEPTION_INVALID_OPERATION,
501 "Used non-constant PMC key in constant hash.");
503 key = key_next(INTERP, key);
506 parrot_hash_put(INTERP, hash, hash_key,
507 hash_value_from_int(INTERP, hash, value));
510 PMC * const next_hash = get_next_hash(INTERP, hash, hash_key);
511 VTABLE_set_integer_keyed(INTERP, next_hash, key, value);
515 VTABLE void set_integer_keyed_int(INTVAL key, INTVAL value) {
516 Hash * const hash = (Hash *)SELF.get_pointer();
517 parrot_hash_put(INTERP, hash, hash_key_from_int(INTERP, hash, key),
518 hash_value_from_int(INTERP, hash, value));
523 =item C<void set_integer_keyed_str(STRING *key, INTVAL value)>
529 VTABLE void set_integer_keyed_str(STRING *key, INTVAL value) {
530 Hash * const hash = (Hash *)SELF.get_pointer();
532 if (PObj_constant_TEST(SELF)
533 && !PObj_constant_TEST((PObj *)key))
534 Parrot_ex_throw_from_c_args(INTERP, NULL,
535 EXCEPTION_INVALID_OPERATION,
536 "Used non-constant key in constant hash.");
538 parrot_hash_put(INTERP, hash, hash_key_from_string(INTERP, hash, key),
539 hash_value_from_int(INTERP, hash, value));
545 =item C<FLOATVAL get_number_keyed_str(STRING *key)>
547 =item C<FLOATVAL get_number_keyed_int(INTVAL key)>
553 VTABLE FLOATVAL get_number_keyed_str(STRING *key) {
554 const Hash * const hash = (Hash *)SELF.get_pointer();
555 HashBucket * const b = parrot_hash_get_bucket(INTERP, hash,
556 hash_key_from_string(INTERP, hash, key));
561 return hash_value_to_number(INTERP, hash, b->value);
564 VTABLE FLOATVAL get_number_keyed_int(INTVAL key) {
565 const Hash * const hash = (Hash *)SELF.get_pointer();
566 HashBucket * const b = parrot_hash_get_bucket(INTERP, hash,
567 hash_key_from_int(INTERP, hash, key));
572 return hash_value_to_number(INTERP, hash, b->value);
576 =item C<FLOATVAL get_number_keyed(PMC *key)>
578 Returns the floating-point value for the element at C<*key>.
584 /* I can't migrate this function right now. Some problem with JITting */
585 VTABLE FLOATVAL get_number_keyed(PMC *key) {
586 const Hash * const hash = (Hash *)SELF.get_pointer();
587 void * const hash_key = hash_key_from_pmc(INTERP, hash, key);
588 HashBucket * const b = parrot_hash_get_bucket(INTERP, hash, hash_key);
593 key = key_next(INTERP, key);
596 return hash_value_to_number(INTERP, hash, b->value);
598 if (hash->entry_type != enum_type_PMC)
599 Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
600 "Hash entry type must be PMC for multipart keys.");
602 return VTABLE_get_number_keyed(INTERP, (PMC *)b->value, key);
608 =item C<STRING *get_string_keyed_str(STRING *key)>
610 =item C<STRING *get_string_keyed_int(INTVAL key)>
616 VTABLE STRING *get_string_keyed_str(STRING *key) {
617 const Hash * const hash = (Hash*)SELF.get_pointer();
618 HashBucket * const b =
619 parrot_hash_get_bucket(INTERP, hash, hash_key_from_string(INTERP, hash, key));
621 /* XXX: shouldn't we return STRINGNULL? */
623 return CONST_STRING(INTERP, "");
625 return hash_value_to_string(INTERP, hash, b->value);
628 VTABLE STRING *get_string_keyed_int(INTVAL key) {
629 const Hash * const hash = (Hash*)SELF.get_pointer();
630 HashBucket * const b =
631 parrot_hash_get_bucket(INTERP, hash, hash_key_from_int(INTERP, hash, key));
634 return CONST_STRING(INTERP, "");
636 return hash_value_to_string(INTERP, hash, b->value);
641 =item C<STRING *get_string_keyed(PMC *key)>
643 Returns the string value for the element at C<*key>.
649 VTABLE STRING *get_string_keyed(PMC *key) {
650 const Hash * const hash = (Hash *)SELF.get_pointer();
651 const void * const hash_key = hash_key_from_pmc(INTERP, hash, key);
652 HashBucket * const b = parrot_hash_get_bucket(INTERP, hash, hash_key);
655 return CONST_STRING(INTERP, "");
657 key = key_next(INTERP, key);
659 /* Stop recursion. This is last step */
661 return hash_value_to_string(INTERP, hash, b->value);
663 if (hash->entry_type != enum_type_PMC)
664 Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
665 "Hash entry type must be PMC for multipart keys.");
667 /* Recursively call to enclosed aggregate */
668 return VTABLE_get_string_keyed(INTERP, (PMC *)b->value, key);
673 =item C<void set_string_keyed(PMC *key, STRING *value)>
679 VTABLE void set_string_keyed(PMC *key, STRING *value) {
680 Hash * const hash = (Hash *)SELF.get_pointer();
681 void * const hash_key = hash_key_from_pmc(INTERP, hash, key);
683 if (PObj_constant_TEST(SELF)){
684 if (!PObj_constant_TEST((PObj *)key))
685 Parrot_ex_throw_from_c_args(INTERP, NULL,
686 EXCEPTION_INVALID_OPERATION,
687 "Used non-constant PMC key in constant hash.");
688 if (!PObj_constant_TEST((PObj *)value))
689 Parrot_ex_throw_from_c_args(INTERP, NULL,
690 EXCEPTION_INVALID_OPERATION,
691 "Used non-constant STRING value in constant hash.");
694 key = key_next(INTERP, key);
697 parrot_hash_put(INTERP, hash, hash_key,
698 hash_value_from_string(INTERP, hash, value));
701 PMC * const next_hash = get_next_hash(INTERP, hash, hash_key);
702 VTABLE_set_string_keyed(INTERP, next_hash, key, value);
708 =item C<void set_string_keyed_str(STRING *key, STRING *value)>
714 VTABLE void set_string_keyed_str(STRING *key, STRING *value) {
715 Hash * const hash = (Hash *)SELF.get_pointer();
717 if (PObj_constant_TEST(SELF)){
718 if (!PObj_constant_TEST((PObj *)key))
719 Parrot_ex_throw_from_c_args(INTERP, NULL,
720 EXCEPTION_INVALID_OPERATION,
721 "Used non-constant STRING key in constant hash.");
722 if (!PObj_constant_TEST((PObj *)value))
723 Parrot_ex_throw_from_c_args(INTERP, NULL,
724 EXCEPTION_INVALID_OPERATION,
725 "Used non-constant STRING value in constant hash.");
728 parrot_hash_put(INTERP, hash, hash_key_from_string(INTERP, hash, key),
729 hash_value_from_string(INTERP, hash, value));
732 VTABLE void set_string_keyed_int(INTVAL key, STRING *value) {
733 Hash * const hash = (Hash *)SELF.get_pointer();
735 if ((PObj_constant_TEST(SELF))
736 && (!PObj_constant_TEST((PObj *)value)))
737 Parrot_ex_throw_from_c_args(INTERP, NULL,
738 EXCEPTION_INVALID_OPERATION,
739 "Used non-constant STRING value in constant hash.");
741 parrot_hash_put(INTERP, hash,
742 hash_key_from_int(INTERP, hash, key),
743 hash_value_from_string(INTERP, hash, value));
748 =item C<PMC *get_pmc_keyed(PMC *key)>
750 =item C<PMC *get_pmc_keyed_str(STRING *key)>
752 =item C<PMC *get_pmc_keyed_int(INTVAL key)>
754 Returns the PMC value for the element at C<*key>.
760 VTABLE PMC *get_pmc_keyed_str(STRING *key) {
764 GET_ATTR_hash(INTERP, SELF, hash);
766 /* special case the most likely key type, for speed */
767 if (hash->key_type != Hash_key_type_STRING)
768 key = (STRING *)hash_key_from_string(INTERP, hash, key);
770 b = parrot_hash_get_bucket(INTERP, hash, key);
775 /* special case the most likely value type, for speed */
776 if (hash->entry_type == enum_type_PMC)
777 return (PMC *)b->value;
779 return hash_value_to_pmc(INTERP, hash, b->value);
782 VTABLE PMC *get_pmc_keyed_int(INTVAL key) {
783 const Hash * const hash = (Hash *)SELF.get_pointer();
784 HashBucket * const b = parrot_hash_get_bucket(INTERP, hash,
785 hash_key_from_int(INTERP, hash, key));
790 return hash_value_to_pmc(INTERP, hash, b->value);
794 VTABLE PMC *get_pmc_keyed(PMC *key) {
795 const Hash * const hash = (Hash *)SELF.get_pointer();
796 const void * const hash_key = hash_key_from_pmc(INTERP, hash, key);
797 HashBucket * const b = parrot_hash_get_bucket(INTERP, hash, hash_key);
802 key = key_next(INTERP, key);
804 /* Stop recursion. This is last step */
806 return hash_value_to_pmc(INTERP, hash, b->value);
808 if (hash->entry_type != enum_type_PMC)
809 Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
810 "Hash entry type must be PMC for multipart keys.");
812 /* Recursively call to enclosed aggregate */
813 return VTABLE_get_pmc_keyed(INTERP, (PMC *)b->value, key);
818 =item C<void set_number_keyed(PMC *key, FLOATVAL value)>
824 VTABLE void set_number_keyed(PMC *key, FLOATVAL value) {
825 Hash * const hash = (Hash *)SELF.get_pointer();
826 void * const hash_key = hash_key_from_pmc(INTERP, hash, key);
828 if (PObj_constant_TEST(SELF)
829 && !PObj_constant_TEST((PObj *)key))
830 Parrot_ex_throw_from_c_args(INTERP, NULL,
831 EXCEPTION_INVALID_OPERATION,
832 "Used non-constant PMC key in constant hash.");
834 key = key_next(INTERP, key);
837 parrot_hash_put(INTERP, hash, hash_key,
838 hash_value_from_number(INTERP, hash, value));
841 PMC * const next_hash = get_next_hash(INTERP, hash, hash_key);
842 VTABLE_set_number_keyed(INTERP, next_hash, key, value);
848 =item C<void set_number_keyed_str(STRING *key, FLOATVAL value)>
850 Sets C<value> as the value for C<*key>.
856 VTABLE void set_number_keyed_str(STRING *key, FLOATVAL value) {
857 Hash * const hash = (Hash *)SELF.get_pointer();
859 if (PObj_constant_TEST(SELF)
860 && !PObj_constant_TEST((PObj *)key))
861 Parrot_ex_throw_from_c_args(INTERP, NULL,
862 EXCEPTION_INVALID_OPERATION,
863 "Used non-constant STRING key in constant hash.");
865 parrot_hash_put(INTERP, hash, hash_key_from_string(INTERP, hash, key),
866 hash_value_from_number(INTERP, hash, value));
871 =item C<void set_pmc_keyed(PMC *dest_key, PMC *value)>
877 VTABLE void set_pmc_keyed(PMC *key, PMC *value) {
878 Hash * const hash = (Hash *)SELF.get_pointer();
879 void * const hash_key = hash_key_from_pmc(INTERP, hash, key);
881 if (PObj_constant_TEST(SELF)) {
882 if (!PObj_constant_TEST((PObj *)key))
883 Parrot_ex_throw_from_c_args(INTERP, NULL,
884 EXCEPTION_INVALID_OPERATION,
885 "Used non-constant PMC key in constant hash.");
887 if (!PObj_constant_TEST((PObj *)value))
888 Parrot_ex_throw_from_c_args(INTERP, NULL,
889 EXCEPTION_INVALID_OPERATION,
890 "Used non-constant PMC value in constant hash.");
893 key = key_next(INTERP, key);
896 parrot_hash_put(INTERP, hash, hash_key, value);
899 PMC * const next_hash = get_next_hash(INTERP, hash, hash_key);
900 VTABLE_set_pmc_keyed(INTERP, next_hash, key, value);
906 =item C<void set_pmc_keyed_str(STRING *key, PMC *value)>
908 Sets C<*value> as the value for C<*key>.
914 VTABLE void set_pmc_keyed_str(STRING *key, PMC *value) {
915 Hash * const hash = (Hash *)SELF.get_pointer();
917 if (PObj_constant_TEST(SELF)) {
918 if (!PObj_constant_TEST((PObj *)key))
919 Parrot_ex_throw_from_c_args(INTERP, NULL,
920 EXCEPTION_INVALID_OPERATION,
921 "Used non-constant STRING key in constant hash.");
923 if (!PObj_constant_TEST((PObj *)value))
924 Parrot_ex_throw_from_c_args(INTERP, NULL,
925 EXCEPTION_INVALID_OPERATION,
926 "Used non-constant STRING value in constant hash.");
929 parrot_hash_put(INTERP, hash, hash_key_from_string(INTERP, hash, key),
930 hash_value_from_pmc(INTERP, hash, value));
935 =item C<INTVAL exists_keyed_str(STRING *key)>
941 VTABLE INTVAL exists_keyed_str(STRING *key) {
942 Hash * const hash = (Hash *)SELF.get_pointer();
943 HashBucket * const b = parrot_hash_get_bucket(INTERP, hash,
944 hash_key_from_string(INTERP, hash, key));
950 =item C<INTVAL exists_keyed(PMC *key)>
952 Returns whether a key C<*key> exists in the hash.
958 VTABLE INTVAL exists_keyed(PMC *key) {
959 Hash * const h = (Hash *)SELF.get_pointer();
960 void * const sx = hash_key_from_pmc(INTERP, h, key);
961 HashBucket * const b = parrot_hash_get_bucket(INTERP, h, sx);
967 key = key_next(INTERP, key);
969 /* lookup stops here */
973 if (h->entry_type != enum_type_PMC)
974 Parrot_ex_throw_from_c_args(INTERP, NULL,
975 EXCEPTION_INVALID_OPERATION,
976 "Hash entry type must be PMC for multipart keys.");
978 return VTABLE_exists_keyed(INTERP, (PMC *)b->value, key);
983 =item C<INTVAL defined_keyed_str(STRING *key)>
989 VTABLE INTVAL defined_keyed_str(STRING *key) {
990 const Hash * const hash = (Hash *)SELF.get_pointer();
991 HashBucket * const b = parrot_hash_get_bucket(INTERP, hash,
992 hash_key_from_string(INTERP, hash, key));
998 return VTABLE_defined(INTERP, hash_value_to_pmc(INTERP, hash, b->value));
1003 =item C<INTVAL defined_keyed(PMC *key)>
1005 Returns whether the value for C<*key> is defined.
1011 VTABLE INTVAL defined_keyed(PMC *key) {
1012 Hash * const h = (Hash *)SELF.get_pointer();
1013 void * const sx = hash_key_from_pmc(INTERP, h, key);
1014 HashBucket * const b = parrot_hash_get_bucket(INTERP, h, sx);
1020 key = key_next(INTERP, key);
1023 return VTABLE_defined(INTERP, hash_value_to_pmc(INTERP, h, b->value));
1025 if (h->entry_type != enum_type_PMC)
1026 Parrot_ex_throw_from_c_args(INTERP, NULL,
1027 EXCEPTION_INVALID_OPERATION,
1028 "Hash entry type must be PMC for multipart keys.");
1030 return VTABLE_defined_keyed(INTERP, (PMC *)b->value, key);
1035 =item C<void delete_keyed_str(STRING *key)>
1041 VTABLE void delete_keyed_str(STRING *key) {
1042 Hash * const hash = (Hash *)SELF.get_pointer();
1043 parrot_hash_delete(INTERP, hash, hash_key_from_string(INTERP, hash, key));
1048 =item C<void delete_keyed(PMC *key)>
1050 Deletes the element associated with C<*key>.
1056 VTABLE void delete_keyed(PMC *key) {
1057 Hash * const h = (Hash *)SELF.get_pointer();
1058 void * const sx = hash_key_from_pmc(INTERP, h, key);
1059 HashBucket * const b = parrot_hash_get_bucket(INTERP, h, sx);
1065 key = key_next(INTERP, key);
1068 parrot_hash_delete(INTERP, h, sx);
1072 if (h->entry_type != enum_type_PMC)
1073 Parrot_ex_throw_from_c_args(INTERP, NULL,
1074 EXCEPTION_INVALID_OPERATION,
1075 "Hash entry type must be PMC for multipart keys.");
1077 VTABLE_delete_keyed(INTERP, (PMC *)b->value, key);
1082 =item C<INTVAL get_bool()>
1084 Returns true if the hash size is not zero.
1090 VTABLE INTVAL get_bool() {
1091 return parrot_hash_size(INTERP, (Hash *)SELF.get_pointer()) != 0;
1096 =item C<INTVAL elements()>
1098 Returns the number of elements in the hash.
1104 VTABLE INTVAL elements() {
1105 return parrot_hash_size(INTERP, (Hash *)SELF.get_pointer());
1110 =item C<PMC *get_iter()>
1112 Return a new iterator.
1118 VTABLE PMC *get_iter() {
1119 return Parrot_pmc_new_init(INTERP, enum_class_HashIterator, SELF);
1124 =item C<INTVAL is_same(const PMC *other)>
1126 Returns whether the hash is the same as C<*other>.
1132 VTABLE INTVAL is_same(PMC *other) {
1133 return (INTVAL)(other->vtable == SELF->vtable &&
1134 VTABLE_get_pointer(INTERP, other) == SELF.get_pointer());
1139 =item C<INTVAL is_equal(PMC *value)>
1141 The C<==> operation.
1143 Check if two hashes hold the same keys and values.
1149 VTABLE INTVAL is_equal(PMC *value) {
1150 PMC * const iter = VTABLE_get_iter(INTERP, SELF);
1153 if (value->vtable->base_type != SELF->vtable->base_type)
1156 n = SELF.elements();
1158 if (VTABLE_elements(INTERP, value) != n)
1161 for (j = 0; j < n; ++j) {
1162 STRING * const key = VTABLE_shift_string(INTERP, iter);
1165 if (!VTABLE_exists_keyed_str(INTERP, value, key))
1168 item1 = SELF.get_pmc_keyed_str(key);
1169 item2 = VTABLE_get_pmc_keyed_str(INTERP, value, key);
1174 if (!VTABLE_is_equal(INTERP, item1, item2))
1183 =item C<void freeze(PMC *info)>
1185 Used to archive the hash.
1191 VTABLE void freeze(PMC *info) {
1193 Parrot_hash_freeze(INTERP, (Hash *)SELF.get_pointer(), info);
1198 =item C<void thaw(PMC *info)>
1200 Used to unarchive the hash.
1206 VTABLE void thaw(PMC *info) {
1208 SELF.set_pointer((void *)Parrot_hash_thaw(INTERP, info));
1218 F<docs/pdds/pdd08_keys.pod>.
1226 * c-file-style: "parrot"
1228 * vim: expandtab shiftwidth=4: