/* hash.c -- type-general hashing */ /* Copyright (c) 2009 Alex Shinn. All rights reserved. */ /* BSD-style license: http://synthcode.com/license.txt */ #include #define HASH_DEPTH 5 #define HASH_BOUND sexp_make_fixnum(SEXP_MAX_FIXNUM) #define FNV_PRIME 16777619 #define FNV_OFFSET_BASIS 2166136261uL #define sexp_hash_table_buckets(x) sexp_slot_ref(x, 0) #define sexp_hash_table_size(x) sexp_slot_ref(x, 1) #define sexp_hash_table_hash_fn(x) sexp_slot_ref(x, 2) #define sexp_hash_table_eq_fn(x) sexp_slot_ref(x, 3) #define sexp_hash_resize_check(n, len) (((n)*3) > ((len)>>2)) static sexp_uint_t string_hash (char *str, sexp_uint_t bound) { sexp_uint_t acc = FNV_OFFSET_BASIS; while (*str) {acc *= FNV_PRIME; acc ^= *str++;} return acc % bound; } static sexp sexp_string_hash (sexp ctx sexp_api_params(self, n), sexp str, sexp bound) { if (! sexp_stringp(str)) return sexp_type_exception(ctx, "string-hash: not a string", str); else if (! sexp_integerp(bound)) return sexp_type_exception(ctx, "string-hash: not an integer", bound); return sexp_make_fixnum(string_hash(sexp_string_data(str), sexp_unbox_fixnum(bound))); } static sexp_uint_t string_ci_hash (char *str, sexp_uint_t bound) { sexp_uint_t acc = FNV_OFFSET_BASIS; while (*str) {acc *= FNV_PRIME; acc ^= tolower(*str++);} return acc % bound; } static sexp sexp_string_ci_hash (sexp ctx sexp_api_params(self, n), sexp str, sexp bound) { if (! sexp_stringp(str)) return sexp_type_exception(ctx, "string-ci-hash: not a string", str); else if (! sexp_integerp(bound)) return sexp_type_exception(ctx, "string-ci-hash: not an integer", bound); return sexp_make_fixnum(string_ci_hash(sexp_string_data(str), sexp_unbox_fixnum(bound))); } static sexp_uint_t hash_one (sexp ctx, sexp obj, sexp_uint_t bound, sexp_sint_t depth) { sexp_uint_t acc = FNV_OFFSET_BASIS, size; sexp_sint_t i, len; sexp t, *p; char *p0; loop: #if SEXP_USE_FLONUMS if (sexp_flonump(obj)) acc ^= (sexp_sint_t) sexp_flonum_value(obj); else #endif if (sexp_pointerp(obj)) { if (depth) { t = sexp_object_type(ctx, obj); p = (sexp*) (((char*)obj) + sexp_type_field_base(t)); p0 = ((char*)obj) + offsetof(struct sexp_struct, value); if ((sexp)p == obj) p=(sexp*)p0; /* hash trailing non-object data */ size = sexp_type_size_of_object(t, obj)-offsetof(struct sexp_struct, value); p0 = ((char*)p + sexp_type_num_slots_of_object(t,obj)*sizeof(sexp)); if (((char*)obj + size) > p0) for (i=0; i 0) { depth--; for (i=0; i