/* * Hash a term. */ extern hash_t hash_term(term_t t) { switch (type(t)) { case VAR: return hash_var(var(t)); case NIL: return hash_nil(); case BOOL: return hash_bool(boolean(t)); case NUM: return hash_num(num(t)); case ATOM: return hash_atom(atom(t)); case STR: return hash_string(string(t)); case FOREIGN: return hash_foreign(foreign(t)); case FUNC: return hash_func(func(t)); default: { hash_t dummy = HASH(0, 0); return dummy; } } }
static void hash_object(object_t* object, uint32_t* hash) { switch (object->type) { case type_nil: *hash = hash_nil(*hash); return; case type_bool: *hash = hash_bool(*hash, object->b); return; case type_double: *hash = hash_double(*hash, object->d); return; case type_int: *hash = hash_i64(*hash, object->i); return; case type_uint: *hash = hash_u64(*hash, object->u); return; case type_str: *hash = hash_str(*hash, object->str, object->l); return; // unused types in this benchmark #if 0 case type_float: write_float(hash, node_float(node)); return; case type_bin: *hash = hash_str(*hash, node_data(node), node_data_len(node)); return; case type_ext: *hash = hash_u8(*hash, node_exttype(node)); *hash = hash_str(*hash, node_data(node), node_data_len(node)); return; #endif case type_array: { uint32_t count = object->l; for (uint32_t i = 0; i < count; ++i) hash_object(object->children + i, hash); *hash = hash_u32(*hash, count); return; } case type_map: { uint32_t count = object->l; for (uint32_t i = 0; i < count; ++i) { // we expect keys to be short strings object_t* key = object->children + (i * 2); *hash = hash_str(*hash, key->str, key->l); hash_object(object->children + (i * 2) + 1, hash); } *hash = hash_u32(*hash, count); return; } default: break; } abort(); }
static bool hash_json(json_value* value, uint32_t* hash) { switch (value->type) { case json_null: *hash = hash_nil(*hash); return true; case json_boolean: *hash = hash_bool(*hash, value->u.boolean ? true : false); return true; case json_double: *hash = hash_double(*hash, value->u.dbl); return true; case json_string: *hash = hash_str(*hash, value->u.string.ptr, value->u.string.length); return true; case json_integer: // json-parser does not support JSON big integers at all. // Judging from the code, it looks like it just overflows and // gives garbage with no error if an integer is outside the // range of int64_t. *hash = hash_i64(*hash, value->u.integer); return true; case json_array: { for (unsigned int i = 0; i < value->u.array.length; ++i) if (!hash_json(value->u.array.values[i], hash)) return false; *hash = hash_u32(*hash, value->u.array.length); return true; } case json_object: { for (unsigned int i = 0; i < value->u.object.length; ++i) { json_object_entry* entry = &value->u.object.values[i]; *hash = hash_str(*hash, entry->name, entry->name_length); if (!hash_json(entry->value, hash)) return false; } *hash = hash_u32(*hash, value->u.object.length); return true; } default: break; } return false; }
static bool hash_element(cmp_ctx_t* cmp, uint32_t* hash) { buffer_t* buffer = (buffer_t*)cmp->buf; cmp_object_t object; if (!cmp_read_object(cmp, &object)) return false; // note: we fetch values out of the cmp_object_t directly rather // than going through the cmp_object_is/as* functions. it's much // faster this way. switch (object.type) { case CMP_TYPE_NIL: *hash = hash_nil(*hash); return true; case CMP_TYPE_BOOLEAN: *hash = hash_bool(*hash, object.as.boolean); return true; case CMP_TYPE_DOUBLE: *hash = hash_double(*hash, object.as.dbl); return true; // note: all ints are hashed as 64-bit (not all libraries read different sized types) case CMP_TYPE_POSITIVE_FIXNUM: *hash = hash_u64(*hash, object.as.u8); return true; case CMP_TYPE_UINT8: *hash = hash_u64(*hash, object.as.u8); return true; case CMP_TYPE_UINT16: *hash = hash_u64(*hash, object.as.u16); return true; case CMP_TYPE_UINT32: *hash = hash_u64(*hash, object.as.u32); return true; case CMP_TYPE_UINT64: *hash = hash_u64(*hash, object.as.u64); return true; case CMP_TYPE_NEGATIVE_FIXNUM: *hash = hash_i64(*hash, object.as.s8); return true; case CMP_TYPE_SINT8: *hash = hash_i64(*hash, object.as.s8); return true; case CMP_TYPE_SINT16: *hash = hash_i64(*hash, object.as.s16); return true; case CMP_TYPE_SINT32: *hash = hash_i64(*hash, object.as.s32); return true; case CMP_TYPE_SINT64: *hash = hash_i64(*hash, object.as.s64); return true; case CMP_TYPE_FIXSTR: case CMP_TYPE_STR8: case CMP_TYPE_STR16: case CMP_TYPE_STR32: { uint32_t len = object.as.str_size; if (buffer->left < len) return false; *hash = hash_str(*hash, buffer->data, len); buffer->data += len; buffer->left -= len; return true; } case CMP_TYPE_FIXARRAY: case CMP_TYPE_ARRAY16: case CMP_TYPE_ARRAY32: for (size_t i = 0; i < object.as.array_size; ++i){ if (!hash_element(cmp, hash)) return false; } *hash = hash_u32(*hash, object.as.array_size); return true; case CMP_TYPE_FIXMAP: case CMP_TYPE_MAP16: case CMP_TYPE_MAP32: { for (size_t i = 0; i < object.as.map_size; ++i) { // we expect keys to be short strings char buf[16]; uint32_t size = sizeof(buf); if (!cmp_read_str(cmp, buf, &size)) return false; *hash = hash_str(*hash, buf, size); if (!hash_element(cmp, hash)) return false; } *hash = hash_u32(*hash, object.as.map_size); return true; } default: break; } return false; }
/* * hash_value - hash a value * * given: * type - hash type (see hash.h) * v - the value * state - the state to hash or NULL * * returns: * the new state */ HASH * hash_value(int type, void *v, HASH *state) { LISTELEM *ep; /* list element pointer */ ASSOCELEM **assochead; /* association chain head */ ASSOCELEM *aep; /* current association value */ ASSOCELEM *nextaep; /* next association value */ VALUE *value = (VALUE *)v; /* v cast to a VALUE */ VALUE *vp; /* pointer to next OBJ table value */ ZVALUE fileval; /* size, position, dev, inode of a file */ int i; /* * initialize if state is NULL */ if (state == NULL) { state = hash_init(type, NULL); } /* * process the value type */ switch (value->v_type) { case V_NULL: (state->chkpt)(state); state->bytes = TRUE; break; case V_INT: /* setup for the this value type */ (state->chkpt)(state); (state->type)(value->v_type, state); /* hash as if we have a 64 bit value */ state = hash_int(type, value->v_int, state); break; case V_NUM: /* hash this type */ state = hash_number(type, value->v_num, state); break; case V_COM: /* setup for the this value type */ (state->chkpt)(state); (state->type)(value->v_type, state); /* hash this type */ state = hash_complex(type, value->v_com, state); break; case V_ADDR: /* there is nothing to setup, simply hash what we point at */ state = hash_value(type, value->v_addr, state); break; case V_STR: /* strings have no setup */ /* hash this type */ state = hash_STR(type, value->v_str, state); break; case V_MAT: /* setup for the this value type */ (state->chkpt)(state); (state->type)(value->v_type, state); state->bytes = TRUE; /* hash all the elements of the matrix */ for (i=0; i < value->v_mat->m_size; ++i) { /* hash the next matrix value */ state = hash_value(type, value->v_mat->m_table+i, state); state->bytes = FALSE; /* as if reading words */ } break; case V_LIST: /* setup for the this value type */ (state->chkpt)(state); (state->type)(value->v_type, state); /* hash all the elements of the list */ for (i=0, ep = value->v_list->l_first; ep != NULL && i < value->v_list->l_count; ++i, ep = ep->e_next) { /* hash the next list value */ state = hash_value(type, &ep->e_value, state); state->bytes = FALSE; /* as if reading words */ } break; case V_ASSOC: /* setup for the this value type */ (state->chkpt)(state); (state->type)(value->v_type, state); state->bytes = TRUE; /* hash the association */ assochead = value->v_assoc->a_table; for (i = 0; i < value->v_assoc->a_size; i++) { nextaep = *assochead; while (nextaep) { aep = nextaep; nextaep = aep->e_next; /* hash the next association value */ state = hash_value(type, &aep->e_value, state); state->bytes = FALSE; /* as if reading words */ } assochead++; } break; case V_OBJ: /* setup for the this value type */ (state->chkpt)(state); (state->type)(value->v_type, state); state->bytes = TRUE; /* reading bytes */ /* hash the object name and then the element values */ state = hash_str(type, objtypename( value->v_obj->o_actions->oa_index), state); (state->chkpt)(state); for (i=value->v_obj->o_actions->oa_count, vp=value->v_obj->o_table; i-- > 0; vp++) { /* hash the next object value */ state = hash_value(type, vp, state); state->bytes = FALSE; /* as if reading words */ } break; case V_FILE: /* setup for the this value type */ (state->chkpt)(state); (state->type)(value->v_type, state); /* hash file length if possible */ if (getsize(value->v_file, &fileval) == 0) { state = hash_zvalue(type, fileval, state); zfree(fileval); } else { /* hash -1 for invalid length */ state = hash_long(type, (long)-1, state); } /* hash the file position if possible */ if (getloc(value->v_file, &fileval) == 0) { state = hash_zvalue(type, fileval, state); zfree(fileval); } else { /* hash -1 for invalid location */ state = hash_long(type, (long)-1, state); } /* hash the file device if possible */ if (get_device(value->v_file, &fileval) == 0) { state = hash_zvalue(type, fileval, state); zfree(fileval); } else { /* hash -1 for invalid device */ state = hash_long(type, (long)-1, state); } /* hash the file inode if possible */ if (get_inode(value->v_file, &fileval) == 0) { state = hash_zvalue(type, fileval, state); zfree(fileval); } else { /* hash -1 for invalid inode */ state = hash_long(type, (long)-1, state); } break; case V_RAND: /* setup for the this value type */ (state->chkpt)(state); (state->type)(value->v_type, state); /* hash the RAND state */ state = hash_int(type, value->v_rand->seeded, state); state = hash_int(type, value->v_rand->bits, state); (state->update)(state, (USB8 *)value->v_rand->buffer, SLEN*FULL_BITS/8); state = hash_int(type, value->v_rand->j, state); state = hash_int(type, value->v_rand->k, state); state = hash_int(type, value->v_rand->need_to_skip, state); (state->update)(state, (USB8 *)value->v_rand->slot, SCNT*FULL_BITS/8); (state->update)(state, (USB8*)value->v_rand->shuf, SHUFLEN*FULL_BITS/8); state->bytes = FALSE; /* as if reading words */ break; case V_RANDOM: /* setup for the this value type */ (state->chkpt)(state); (state->type)(value->v_type, state); /* hash the RANDOM state */ state = hash_int(type, value->v_random->seeded, state); state = hash_int(type, value->v_random->bits, state); (state->update)(state, (USB8 *)&(value->v_random->buffer), BASEB/8); state = hash_zvalue(type, value->v_random->r, state); state = hash_zvalue(type, value->v_random->n, state); state->bytes = FALSE; /* as if reading words */ break; case V_CONFIG: /* setup for the this value type */ (state->chkpt)(state); (state->type)(value->v_type, state); /* hash the CONFIG state */ state = hash_int(type, value->v_config->outmode, state); state = hash_int(type, value->v_config->outmode2, state); state = hash_long(type,(long)value->v_config->outdigits, state); state = hash_number(type, value->v_config->epsilon, state); state = hash_long(type, (long)value->v_config->epsilonprec, state); state = hash_flag(type, value->v_config->traceflags, state); state = hash_long(type, (long)value->v_config->maxprint, state); state = hash_len(type, value->v_config->mul2, state); state = hash_len(type, value->v_config->sq2, state); state = hash_len(type, value->v_config->pow2, state); state = hash_len(type, value->v_config->redc2, state); state = hash_bool(type, value->v_config->tilde_ok, state); state = hash_bool(type, value->v_config->tab_ok, state); state = hash_long(type, (long)value->v_config->quomod, state); state = hash_long(type, (long)value->v_config->quo, state); state = hash_long(type, (long)value->v_config->mod, state); state = hash_long(type, (long)value->v_config->sqrt, state); state = hash_long(type, (long)value->v_config->appr, state); state = hash_long(type, (long)value->v_config->cfappr, state); state = hash_long(type, (long)value->v_config->cfsim, state); state = hash_long(type, (long)value->v_config->outround, state); state = hash_long(type, (long)value->v_config->round, state); state = hash_bool(type, value->v_config->leadzero, state); state = hash_bool(type, value->v_config->fullzero, state); state = hash_long(type, (long)value->v_config->maxscancount, state); state = hash_str(type, value->v_config->prompt1, state); state->bytes = FALSE; /* as if just read words */ state = hash_str(type, value->v_config->prompt2, state); state->bytes = FALSE; /* as if just read words */ state = hash_int(type, value->v_config->blkmaxprint, state); state = hash_bool(type, value->v_config->blkverbose, state); state = hash_int(type, value->v_config->blkbase, state); state = hash_int(type, value->v_config->blkfmt, state); state = hash_long(type, (long)value->v_config->resource_debug, state); state = hash_long(type, (long)value->v_config->calc_debug, state); state = hash_long(type, (long)value->v_config->user_debug, state); state = hash_bool(type, value->v_config->verbose_quit, state); state = hash_int(type, value->v_config->ctrl_d, state); state = hash_str(type, value->v_config->program, state); state = hash_str(type, value->v_config->base_name, state); state = hash_bool(type, value->v_config->windows, state); state = hash_bool(type, value->v_config->cygwin, state); state = hash_bool(type, value->v_config->compile_custom, state); if (value->v_config->allow_custom != NULL && *(value->v_config->allow_custom)) { state = hash_bool(type, TRUE, state); } else { state = hash_bool(type, FALSE, state); } state = hash_str(type, value->v_config->version, state); state = hash_int(type, value->v_config->baseb, state); state = hash_bool(type, value->v_config->redecl_warn, state); state = hash_bool(type, value->v_config->dupvar_warn, state); break; case V_HASH: /* setup for the this value type */ (state->chkpt)(state); (state->type)(value->v_type, state); /* hash the HASH state */ state = hash_int(type, value->v_hash->type, state); state = hash_bool(type, value->v_hash->bytes,state); state = hash_int(type, value->v_hash->base, state); state = hash_int(type, value->v_hash->chunksize, state); state = hash_int(type, value->v_hash->unionsize, state); (state->update)(state, value->v_hash->h_union.data, state->unionsize); state->bytes = FALSE; /* as if reading words */ break; case V_BLOCK: /* there is no setup for a BLOCK */ /* hash the octets in the BLOCK */ if (value->v_block->datalen > 0) { state = hash_usb8(type, value->v_block->data, value->v_block->datalen, state); } break; case V_OCTET: /* there is no setup for an OCTET */ /* hash the OCTET */ state = hash_usb8(type, value->v_octet, 1, state); break; case V_NBLOCK: /* there is no setup for a NBLOCK */ /* hash the octets in the NBLOCK */ if (value->v_nblock->blk->datalen > 0) { state = hash_usb8(type, value->v_nblock->blk->data, value->v_nblock->blk->datalen, state); } break; default: math_error("hashing an unknown value"); /*NOTREACHED*/ } return state; }
static void hash_value(void* data, UBJ_TYPE type, size_t index, uint32_t* hash) { switch (type) { case UBJ_MIXED: { ubjr_dynamic_t* dynamic = &((ubjr_dynamic_t*)data)[index]; switch (dynamic->type) { case UBJ_INT8: case UBJ_UINT8: case UBJ_INT16: case UBJ_INT32: case UBJ_INT64: // the union in a dynamic doesn't actually contain these types, so // we can't just cast it and recurse like the others here. if an // integer is read in a dynamic, the int64_t integer is set to the // value read in priv_ubjr_pointer_to_dynamic(), but integers can // be smaller sizes in fixed-type arrays and objects. *hash = hash_i64(*hash, dynamic->integer); return; case UBJ_FLOAT64: hash_value(&dynamic->real, dynamic->type, 0, hash); return; case UBJ_STRING: hash_value(&dynamic->string, dynamic->type, 0, hash); return; case UBJ_ARRAY: hash_value(&dynamic->container_array, dynamic->type, 0, hash); return; case UBJ_OBJECT: hash_value(&dynamic->container_object, dynamic->type, 0, hash); return; default: break; } hash_value(NULL, dynamic->type, 0, hash); return; } case UBJ_NULLTYPE: *hash = hash_nil(*hash); return; case UBJ_BOOL_TRUE: *hash = hash_bool(*hash, true); return; case UBJ_BOOL_FALSE: *hash = hash_bool(*hash, false); return; case UBJ_FLOAT64: *hash = hash_double(*hash, ((double*)data)[index]); return; // we assume that the type here comes from a fixed-size array, not from // a dynamic (which should have been handled above.) case UBJ_INT8: *hash = hash_i64(*hash, (( int8_t*)data)[index]); return; case UBJ_UINT8: *hash = hash_i64(*hash, ((uint8_t*)data)[index]); return; case UBJ_INT16: *hash = hash_i64(*hash, ((int16_t*)data)[index]); return; case UBJ_INT32: *hash = hash_i64(*hash, ((int32_t*)data)[index]); return; case UBJ_INT64: *hash = hash_i64(*hash, ((int64_t*)data)[index]); return; case UBJ_STRING: case UBJ_CHAR: { ubjr_string_t str = ((ubjr_string_t*)data)[index]; *hash = hash_str(*hash, str, strlen(str)); return; } case UBJ_ARRAY: { ubjr_array_t* array = &((ubjr_array_t*)data)[index]; for (size_t i = 0; i < array->size; ++i) hash_value(array->values, array->type, i, hash); *hash = hash_u32(*hash, array->size); return; } case UBJ_OBJECT: { ubjr_object_t* object = &((ubjr_object_t*)data)[index]; for (size_t i = 0; i < object->size; ++i) { *hash = hash_str(*hash, object->keys[i], strlen(object->keys[i])); hash_value(object->values, object->type, i, hash); } *hash = hash_u32(*hash, object->size); return; } default: break; } }
static int parse_boolean(void* ctx, int boolean) { parser_t* parser = (parser_t*)ctx; ++parser->children[parser->depth]; parser->hash = hash_bool(parser->hash, boolean); return 1; }