clox/value.c

149 lines
3.1 KiB
C
Raw Normal View History

2019-06-02 14:58:15 -05:00
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include "object.h"
#include "memory.h"
#include "value.h"
void initValueArray(ValueArray* array) {
array->values = NULL;
array->capacity = 0;
array->count = 0;
}
void writeValueArray(ValueArray* array, Value value) {
if (array->capacity < array->count + 1) {
int oldCapacity = array->capacity;
array->capacity = GROW_CAPACITY(oldCapacity);
array->values = GROW_ARRAY(array->values, Value, oldCapacity, array->capacity);
}
array->values[array->count] = value;
array->count++;
}
void freeValueArray(ValueArray* array) {
FREE_ARRAY(Value, array->values, array->capacity);
initValueArray(array);
}
void printValue(Value value) {
switch (value.type) {
case VAL_BOOL:
printf(AS_BOOL(value) ? "true" : "false");
break;
case VAL_NIL:
printf("nil");
break;
case VAL_NUMBER:
printf("%g", AS_NUMBER(value));
break;
case VAL_OBJ:
printObject(value);
break;
case VAL_EMPTY:
printf("<empty>");
break;
}
}
bool valuesEqual(Value a, Value b) {
if (a.type != b.type) return false;
switch (a.type) {
case VAL_BOOL:
return AS_BOOL(a) == AS_BOOL(b);
case VAL_NIL:
return true;
case VAL_NUMBER:
return AS_NUMBER(a) == AS_NUMBER(b);
case VAL_OBJ: {
return AS_OBJ(a) == AS_OBJ(b);
}
case VAL_EMPTY:
return true;
}
return false;
}
static uint32_t hashDouble(double value) {
union BitCast {
double value;
uint32_t ints[2];
};
union BitCast cast;
cast.value = (value) + 1.0;
return cast.ints[0] + cast.ints[1];
}
static uint32_t hashUint(unsigned int value) {
uint8_t bytes[4];
bytes[0] = value & 0xFF;
bytes[1] = (value & 0xFF00) >> 8;
bytes[2] = (value & 0xFF0000) >> 16;
bytes[3] = (value & 0xFF000000) > 24;
uint32_t hash = 2166136261u;
for (int i = 0; i < 4; i++) {
hash ^= bytes[i];
hash *= 16777619;
}
return hash;
}
uint32_t hashValue(Value value) {
switch (value.type) {
case VAL_BOOL:
return AS_BOOL(value) ? 3 : 5;
case VAL_NIL:
return 7;
case VAL_NUMBER:
return hashDouble(AS_NUMBER(value));
case VAL_OBJ: {
Obj* object = AS_OBJ(value);
switch (object->type) {
case OBJ_STRING:
return AS_STRING(value)->hash;
break;
case OBJ_ARRAY: {
2019-06-02 14:58:15 -05:00
ValueArray* valArray = AS_VARRAY(value);
unsigned int sum = 0;
for (int i = 0; i < valArray->count; i++) {
2019-06-03 16:22:10 -05:00
uint32_t valHash = hashValue(valArray->values[i])*i;
2019-06-02 14:58:15 -05:00
if ((UINT_MAX - sum) < valHash) {
sum = hashUint(sum);
}
sum += valHash;
}
2019-06-03 16:22:10 -05:00
return hashUint(sum);
2019-06-02 14:58:15 -05:00
break;
}
2019-06-03 16:22:10 -05:00
case OBJ_HASH: {
Table* hash = AS_HASH(value);
Entry** entries = getEntries(hash);
unsigned int sum = 0;
for (int i = 0; entries[i] != NULL; i++) {
Entry* entry = entries[i];
2019-06-03 16:22:10 -05:00
uint32_t valHash = hashUint((hashValue(entry->key)*i)+(hashValue(entry->value)*i));
if ((UINT_MAX - sum) < valHash) {
sum = hashUint(sum);
}
sum += valHash;
}
2019-06-03 16:22:10 -05:00
return hashUint(sum);
2019-06-02 14:58:15 -05:00
break;
2019-06-03 16:22:10 -05:00
}
2019-06-02 14:58:15 -05:00
default:
return 0;
}
break;
}
case VAL_EMPTY:
return 0;
}
return 0;
}