Use tuples to store range data for faster lookup

This commit is contained in:
K. Lange 2021-01-05 11:39:20 +09:00
parent c8758c9ffb
commit 7a91678701
4 changed files with 61 additions and 33 deletions

View File

@ -102,7 +102,7 @@ typedef struct {
KrkObj obj;
KrkClass * _class;
KrkTable fields;
KrkObj * _internal;
void * _internal;
} KrkInstance;
typedef struct {

10
table.c
View File

@ -29,7 +29,7 @@ static uint32_t hashValue(KrkValue value) {
return (((uint32_t)(intptr_t)AS_OBJECT(value)) >> 4)| (((uint32_t)(intptr_t)AS_OBJECT(value)) << 28);
}
static KrkTableEntry * findEntry(KrkTableEntry * entries, size_t capacity, KrkValue key) {
KrkTableEntry * krk_findEntry(KrkTableEntry * entries, size_t capacity, KrkValue key) {
uint32_t index = hashValue(key) % capacity;
KrkTableEntry * tombstone = NULL;
for (;;) {
@ -58,7 +58,7 @@ static void adjustCapacity(KrkTable * table, size_t capacity) {
for (size_t i = 0; i < table->capacity; ++i) {
KrkTableEntry * entry = &table->entries[i];
if (entry->key.type == VAL_NONE) continue;
KrkTableEntry * dest = findEntry(entries, capacity, entry->key);
KrkTableEntry * dest = krk_findEntry(entries, capacity, entry->key);
dest->key = entry->key;
dest->value = entry->value;
table->count++;
@ -74,7 +74,7 @@ int krk_tableSet(KrkTable * table, KrkValue key, KrkValue value) {
size_t capacity = GROW_CAPACITY(table->capacity);
adjustCapacity(table, capacity);
}
KrkTableEntry * entry = findEntry(table->entries, table->capacity, key);
KrkTableEntry * entry = krk_findEntry(table->entries, table->capacity, key);
int isNewKey = entry->key.type == VAL_NONE;
if (isNewKey && IS_NONE(entry->value)) table->count++;
entry->key = key;
@ -93,7 +93,7 @@ void krk_tableAddAll(KrkTable * from, KrkTable * to) {
int krk_tableGet(KrkTable * table, KrkValue key, KrkValue * value) {
if (table->count == 0) return 0;
KrkTableEntry * entry = findEntry(table->entries, table->capacity, key);
KrkTableEntry * entry = krk_findEntry(table->entries, table->capacity, key);
if (entry->key.type == VAL_NONE) return 0;
*value = entry->value;
return 1;
@ -101,7 +101,7 @@ int krk_tableGet(KrkTable * table, KrkValue key, KrkValue * value) {
int krk_tableDelete(KrkTable * table, KrkValue key) {
if (table->count == 0) return 0;
KrkTableEntry * entry = findEntry(table->entries, table->capacity, key);
KrkTableEntry * entry = krk_findEntry(table->entries, table->capacity, key);
if (entry->key.type == VAL_NONE) return 0;
entry->key = NONE_VAL();
entry->value = BOOLEAN_VAL(1);

View File

@ -29,3 +29,4 @@ extern KrkString * krk_tableFindString(KrkTable * table, const char * chars, siz
extern int krk_tableSet(KrkTable * table, KrkValue key, KrkValue value);
extern int krk_tableGet(KrkTable * table, KrkValue key, KrkValue * value);
extern int krk_tableDelete(KrkTable * table, KrkValue key);
extern KrkTableEntry * krk_findEntry(KrkTableEntry * entries, size_t capacity, KrkValue key);

81
vm.c
View File

@ -887,7 +887,7 @@ _finishArg:
KrkValue value = startOfExtras[i*2+1];
if (IS_KWARGS(name)) {
if (AS_INTEGER(name) == LONG_MAX-1) {
if (!IS_INSTANCE(value) || !AS_INSTANCE(value)->_internal || !AS_INSTANCE(value)->_internal->type == OBJ_FUNCTION) {
if (!IS_INSTANCE(value) || !AS_INSTANCE(value)->_internal || !((KrkObj*)(AS_INSTANCE(value)->_internal))->type == OBJ_FUNCTION) {
krk_runtimeError(vm.exceptions.typeError, "*expresssion value is not a list.");
return 0;
}
@ -1085,7 +1085,9 @@ int krk_callValue(KrkValue callee, int argCount, int extra) {
case OBJ_INSTANCE: {
KrkClass * _class = AS_INSTANCE(callee)->_class;
KrkValue callFunction;
if (krk_tableGet(&_class->methods, vm.specialMethodNames[METHOD_CALL], &callFunction)) {
if (_class->_call) {
return krk_callValue(OBJECT_VAL(_class->_call), argCount + 1, 0);
} else if (krk_tableGet(&_class->methods, vm.specialMethodNames[METHOD_CALL], &callFunction)) {
return krk_callValue(callFunction, argCount + 1, 0);
} else {
krk_runtimeError(vm.exceptions.typeError, "Attempted to call non-callable type: %s", krk_typeName(callee));
@ -1096,7 +1098,9 @@ int krk_callValue(KrkValue callee, int argCount, int extra) {
KrkClass * _class = AS_CLASS(callee);
vm.stackTop[-argCount - 1] = OBJECT_VAL(krk_newInstance(_class));
KrkValue initializer;
if (krk_tableGet(&_class->methods, vm.specialMethodNames[METHOD_INIT], &initializer)) {
if (_class->_init) {
return krk_callValue(OBJECT_VAL(_class->_init), argCount + 1, 0);
} else if (krk_tableGet(&_class->methods, vm.specialMethodNames[METHOD_INIT], &initializer)) {
return krk_callValue(initializer, argCount + 1, 0);
} else if (argCount != 0) {
krk_runtimeError(vm.exceptions.attributeError, "Class does not have an __init__ but arguments were passed to initializer: %d", argCount);
@ -1539,12 +1543,16 @@ static KrkValue _string_format(int argc, KrkValue argv[], int hasKw) {
asString = value;
} else {
krk_push(value);
if (!krk_bindMethod(AS_CLASS(krk_typeOf(1,(KrkValue[]){value})),
AS_STRING(vm.specialMethodNames[METHOD_STR]))) {
errorStr = "Failed to convert field to string.";
goto _formatError;
KrkClass * type = AS_CLASS(krk_typeOf(1, (KrkValue[]){value}));
if (type->_tostr) {
asString = krk_callSimple(OBJECT_VAL(type->_tostr), 1, 0);
} else {
if (!krk_bindMethod(type, AS_STRING(vm.specialMethodNames[METHOD_STR]))) {
errorStr = "Failed to convert field to string.";
goto _formatError;
}
asString = krk_callSimple(krk_peek(0), 0, 1);
}
asString = krk_callSimple(krk_peek(0), 0, 1);
if (!IS_STRING(asString)) goto _freeAndDone;
}
krk_push(asString);
@ -1610,7 +1618,7 @@ static KrkValue _string_join(int argc, KrkValue argv[], int hasKw) {
}
/* TODO: Support any object with an __iter__ - kinda need an internal method to do that well. */
if (!IS_INSTANCE(argv[1]) || !AS_INSTANCE(argv[1])->_internal || !AS_INSTANCE(argv[1])->_internal->type == OBJ_FUNCTION) {
if (!IS_INSTANCE(argv[1]) || !AS_INSTANCE(argv[1])->_internal || !((KrkObj*)AS_INSTANCE(argv[1])->_internal)->type == OBJ_FUNCTION) {
krk_runtimeError(vm.exceptions.typeError, "*expresssion value is not a list.");
return NONE_VAL();
}
@ -2213,21 +2221,31 @@ static KrkValue _range_init(int argc, KrkValue argv[]) {
return NONE_VAL();
}
krk_push(OBJECT_VAL(self));
/* Add them to ourselves */
krk_push(argv[0]);
krk_attachNamedValue(&self->fields, "min", min);
krk_attachNamedValue(&self->fields, "max", max);
krk_pop();
KrkTuple * myTuple = krk_newTuple(2);
krk_push(OBJECT_VAL(myTuple));
myTuple->values.values[0] = min;
myTuple->values.values[1] = max;
myTuple->values.count = 2;
krk_attachNamedObject(&self->fields, "_tuple", (KrkObj*)myTuple);
self->_internal = myTuple;
krk_pop(); /* myTuple */
krk_pop(); /* self */
return argv[0];
}
static KrkValue _range_repr(int argc, KrkValue argv[]) {
KrkInstance * self = AS_INSTANCE(argv[0]);
KrkTuple * myTuple = self->_internal;
KrkValue min, max;
krk_tableGet(&self->fields, OBJECT_VAL(S("min")), &min);
krk_tableGet(&self->fields, OBJECT_VAL(S("max")), &max);
KrkValue min = myTuple->values.values[0];
KrkValue max = myTuple->values.values[1];
krk_push(OBJECT_VAL(S("range({},{})")));
KrkValue output = _string_format(3, (KrkValue[]){krk_peek(0), min, max}, 0);
@ -2238,30 +2256,39 @@ static KrkValue _range_repr(int argc, KrkValue argv[]) {
static KrkValue _rangeiterator_init(int argc, KrkValue argv[]) {
KrkInstance * self = AS_INSTANCE(argv[0]);
krk_push(argv[0]);
krk_attachNamedValue(&self->fields, "i", argv[1]);
krk_attachNamedValue(&self->fields, "m", argv[2]);
krk_pop();
KrkTuple * myTuple = krk_newTuple(2);
krk_push(OBJECT_VAL(myTuple));
myTuple->values.values[0] = argv[1];
myTuple->values.values[1] = argv[2];
myTuple->values.count = 2;
krk_attachNamedObject(&self->fields, "_tuple", (KrkObj*)myTuple);
self->_internal = myTuple;
krk_pop(); /* myTuple */
krk_pop(); /* self */
return argv[0];
}
static KrkValue _rangeiterator_call(int argc, KrkValue argv[]) {
KrkInstance * self = AS_INSTANCE(argv[0]);
KrkValue i, m;
krk_tableGet(&self->fields, OBJECT_VAL(S("i")), &i);
krk_tableGet(&self->fields, OBJECT_VAL(S("m")), &m);
if (AS_INTEGER(i) >= AS_INTEGER(m)) {
KrkTuple * myTuple = self->_internal;
KrkValue i = myTuple->values.values[0];
if (AS_INTEGER(i) >= AS_INTEGER(myTuple->values.values[1])) {
return argv[0];
} else {
krk_attachNamedValue(&self->fields, "i", INTEGER_VAL(AS_INTEGER(i)+1));
myTuple->values.values[0] = INTEGER_VAL(AS_INTEGER(i)+1);
return i;
}
}
static KrkValue _range_iter(int argc, KrkValue argv[]) {
KrkInstance * self = AS_INSTANCE(argv[0]);
KrkValue min, max;
krk_tableGet(&self->fields, OBJECT_VAL(S("min")), &min);
krk_tableGet(&self->fields, OBJECT_VAL(S("max")), &max);
KrkTuple * myTuple = self->_internal;
KrkValue min = myTuple->values.values[0];
KrkValue max = myTuple->values.values[1];
KrkInstance * output = krk_newInstance(vm.baseClasses.rangeiteratorClass);