/* since strings are immutable, it's enough to generate the hash on-demand, * then store it for later use. */ static unsigned long hash_string(void *obj) { SpnString *str = obj; if (!str->ishashed) { str->hash = spn_hash_bytes(str->cstr, str->len); str->ishashed = 1; } return str->hash; }
unsigned long spn_hash_value(const SpnValue *key) { switch (valtype(key)) { case SPN_TTAG_NIL: { return 0; } case SPN_TTAG_BOOL: { return boolvalue(key); /* 0 or 1 */ } case SPN_TTAG_NUMBER: { if (isfloat(key)) { double f = floatvalue(key); /* only test for integer if it fits into one (anti-UB) */ if (LONG_MIN <= f && f <= LONG_MAX) { long i = f; /* truncate */ if (f == i) { /* it's really an integer. * This takes care of the +/- 0 problem too * (since 0 itself is an integer) */ return i; } } else { return spn_hash_bytes(&f, sizeof f); } } /* the hash value of an integer is itself */ return intvalue(key); } case SPN_TTAG_STRING: case SPN_TTAG_ARRAY: case SPN_TTAG_HASHMAP: case SPN_TTAG_FUNC: { SpnObject *obj = objvalue(key); unsigned long (*hashfn)(void *) = obj->isa->hashfn; return hashfn ? hashfn(obj) : (unsigned long)(obj); } case SPN_TTAG_USERINFO: { if (isobject(key)) { SpnObject *obj = objvalue(key); unsigned long (*hashfn)(void *) = obj->isa->hashfn; return hashfn ? hashfn(obj) : (unsigned long)(obj); } return (unsigned long)(ptrvalue(key)); } default: SHANT_BE_REACHED(); } return 0; }
unsigned long spn_hash_value(const SpnValue *key) { switch (valtype(key)) { case SPN_TTAG_NIL: { return 0; } case SPN_TTAG_BOOL: { return boolvalue(key); /* 0 or 1 */ } case SPN_TTAG_NUMBER: { if (isfloat(key)) { double f = floatvalue(key); long i = f; /* truncate */ if (f == i) { return i; /* it's really an integer */ } else { return spn_hash_bytes(&f, sizeof f); } } /* the hash value of an integer is itself */ return intvalue(key); } case SPN_TTAG_STRING: case SPN_TTAG_ARRAY: case SPN_TTAG_HASHMAP: case SPN_TTAG_FUNC: { SpnObject *obj = objvalue(key); unsigned long (*hashfn)(void *) = obj->isa->hashfn; return hashfn ? hashfn(obj) : (unsigned long)(obj); } case SPN_TTAG_USERINFO: { if (isobject(key)) { SpnObject *obj = objvalue(key); unsigned long (*hashfn)(void *) = obj->isa->hashfn; return hashfn ? hashfn(obj) : (unsigned long)(obj); } return (unsigned long)(ptrvalue(key)); } default: SHANT_BE_REACHED(); } return 0; }