148 lines
3.1 KiB
C
148 lines
3.1 KiB
C
#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: {
|
|
ValueArray* valArray = AS_VARRAY(value);
|
|
unsigned int sum = 0;
|
|
for (int i = 0; i < valArray->count; i++) {
|
|
uint32_t valHash = hashValue(valArray->values[i] * i);
|
|
if ((UINT_MAX - sum) < valHash) {
|
|
sum = hashUint(sum);
|
|
}
|
|
sum += valHash;
|
|
}
|
|
return hashUInt(sum);
|
|
break;
|
|
}
|
|
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];
|
|
uint32_t valHash = hashValue((hashValue(entry->key)*i)+(hashValue(entry->value)*i));
|
|
if ((UINT_MAX - sum) < valHash) {
|
|
sum = hashUint(sum);
|
|
}
|
|
sum += valHash;
|
|
}
|
|
return hashUInt(sum);
|
|
break;
|
|
default:
|
|
return 0;
|
|
}
|
|
break;
|
|
}
|
|
case VAL_EMPTY:
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|