HEADER_DECLARE hash_t hash_rec(Term* term, hash_t hash){ term = chase(term); switch(term->type){ case INTEGER: return hash_integer(term->data.integer, hash); case FUNCTOR: hash = hash_atom(term->data.functor.atom, hash); functor_size_t size = term->data.functor.size; if(size){ hash = hash_byte(size, hash); for(functor_size_t i = 0; i < size; i++){ hash = hash_rec(term->data.functor.args[i], hash); } } return hash; case STRING: return hash_string(&term->data.string, hash); case VAR: fatal_error("Cannot hash variable '%s'", term->data.var.name); case DICT: fatal_error("unimplemented: hash dict"); case MOVED: fatal_error("Cannot hash a moved term"); } UNREACHABLE; }
static void hash_rec( value v, int *h, vlist *l ) { val_type t = val_type(v); switch( t ) { case VAL_INT: HBIG(val_int(v)); break; case VAL_INT32: HBIG(val_int32(v)); break; case VAL_NULL: HSMALL(0); break; case VAL_FLOAT: { int k = sizeof(tfloat); while( k ) HSMALL(val_string(v)[--k]); } break; case VAL_BOOL: HSMALL(val_bool(v)); break; case VAL_STRING: { int k = val_strlen(v); while( k ) HSMALL(val_string(v)[--k]); } break; case VAL_OBJECT: case VAL_ARRAY: { vlist *tmp = l; int k = 0; while( tmp != NULL ) { if( tmp->v == v ) { HSMALL(k); return; } k = k + 1; tmp = tmp->next; } } if( t == VAL_OBJECT ) { vparam p; p.h = h; p.l.v = v; p.l.next = l; val_iter_fields(v,hash_obj_rec,&p); v = (value)((vobject*)v)->proto; if( v != NULL ) hash_rec(v,h,&p.l); } else { vlist cur; int k = val_array_size(v); cur.v = v; cur.next = l; while( k ) hash_rec(val_array_ptr(v)[--k],h,&cur); } break; default: // ignore since we want hashes to be stable wrt memory break; } }
EXTERN int val_hash( value v ) { int h = 0; hash_rec(v,&h,NULL); return (((unsigned int)h) & 0x3FFFFFFF); }
static void hash_obj_rec( value v, field f, void *_p ) { vparam *p = (vparam*)_p; int *h = p->h; HBIG((int)f); hash_rec(v,h,&p->l); }
HEADER_DECLARE hash_t hash(Term* term){ uint32_t hash = HASH_INIT; return hash_rec(term, hash); }