Skip to content

Commit

Permalink
feat: added support for defining custom hash functions for Argon objects
Browse files Browse the repository at this point in the history
  • Loading branch information
jacopodl committed May 17, 2024
1 parent 0c5db38 commit 456a889
Show file tree
Hide file tree
Showing 9 changed files with 203 additions and 95 deletions.
4 changes: 2 additions & 2 deletions argon/vm/datatype/arobject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -323,9 +323,9 @@ ArObject *argon::vm::datatype::AttributeLoadMethod(const ArObject *object, const
if (AR_TYPEOF(meth, type_function_) && meth->IsMethod())
return (ArObject *) meth;

Release(meth);
ErrorFormat(kTypeError[0], kTypeError[11], ARGON_RAW_STRING(meth->qname));

ErrorFormat(kTypeError[0], "expected method '%s', got function", key);
Release(meth);
}

return nullptr;
Expand Down
46 changes: 32 additions & 14 deletions argon/vm/datatype/dict.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,12 @@ ARGON_METHOD(dict_pop, pop,
"- Returns: Option<?>.\n",
": key", false, false) {
auto *self = (Dict *) _self;
DictEntry *item;

std::shared_lock _(self->rwlock);

auto *item = self->hmap.Remove(args[0]);
if (!self->hmap.Remove(args[0], &item))
return nullptr;

if (item == nullptr)
return (ArObject *) OptionNew();
Expand Down Expand Up @@ -205,9 +207,13 @@ const ObjectSlots dict_objslot = {
};

ArObject *dict_get_item(Dict *self, ArObject *key) {
DictEntry *entry;

std::shared_lock _(self->rwlock);

auto *entry = self->hmap.Lookup(key);
if (!self->hmap.Lookup(key, &entry))
return nullptr;

if (entry == nullptr) {
_.unlock();

Expand All @@ -220,9 +226,12 @@ ArObject *dict_get_item(Dict *self, ArObject *key) {
}

ArObject *dict_item_in(Dict *self, ArObject *key) {
DictEntry *entry;

std::shared_lock _(self->rwlock);

const auto *entry = self->hmap.Lookup(key);
if (!self->hmap.Lookup(key, &entry))
return nullptr;

_.unlock();

Expand Down Expand Up @@ -263,7 +272,9 @@ ArObject *dict_compare(Dict *self, ArObject *other, CompareMode mode) {
return BoolToArBool(false);

for (auto *cursor = self->hmap.iter_begin; cursor != nullptr; cursor = cursor->iter_next) {
const auto *other_entry = o->hmap.Lookup(cursor->key);
DictEntry *other_entry;

o->hmap.Lookup(cursor->key, &other_entry);

if (other_entry == nullptr)
return BoolToArBool(false);
Expand Down Expand Up @@ -409,11 +420,13 @@ TypeInfo DictType = {
const TypeInfo *argon::vm::datatype::type_dict_ = &DictType;

ArObject *argon::vm::datatype::DictLookup(Dict *dict, ArObject *key) {
CHECK_HASHABLE(key, nullptr);
DictEntry *entry;

std::shared_lock _(dict->rwlock);

auto entry = dict->hmap.Lookup(key);
if (!dict->hmap.Lookup(key, &entry))
return nullptr;

if (entry == nullptr)
return nullptr;

Expand All @@ -432,13 +445,14 @@ ArObject *argon::vm::datatype::DictLookup(Dict *dict, const char *key, ArSize le
}

bool argon::vm::datatype::DictInsert(Dict *dict, ArObject *key, ArObject *value) {
HEntry<ArObject, ArObject *> *entry;

CHECK_HASHABLE(key, false);
DictEntry *entry;

std::unique_lock _(dict->rwlock);

if ((entry = dict->hmap.Lookup(key)) != nullptr) {
if (!dict->hmap.Lookup(key, &entry))
return false;

if (entry != nullptr) {
Release(entry->value);
entry->value = IncRef(value);

Expand Down Expand Up @@ -505,11 +519,13 @@ bool argon::vm::datatype::DictLookupIsTrue(argon::vm::datatype::Dict *dict, cons
}

bool argon::vm::datatype::DictRemove(Dict *dict, ArObject *key) {
CHECK_HASHABLE(key, false);
DictEntry *entry;

std::unique_lock _(dict->rwlock);

auto *entry = dict->hmap.Remove(key);
if (!dict->hmap.Remove(key, &entry))
return false;

if (entry == nullptr)
return false;

Expand Down Expand Up @@ -557,7 +573,7 @@ Dict *argon::vm::datatype::DictMerge(Dict *dict1, Dict *dict2, bool clone) {
if ((merge = DictNew(merge_sz)) == nullptr)
return nullptr;

HEntry<ArObject, ArObject *> *entry;
DictEntry *entry;

for (auto *cursor = dict1->hmap.iter_begin; cursor != nullptr; cursor = cursor->iter_next) {
if ((entry = merge->hmap.AllocHEntry()) == nullptr) {
Expand All @@ -584,7 +600,9 @@ Dict *argon::vm::datatype::DictMerge(Dict *dict1, Dict *dict2, bool clone) {
d1.unlock();

for (auto *cursor = dict2->hmap.iter_begin; cursor != nullptr; cursor = cursor->iter_next) {
if (merge->hmap.Lookup(cursor->key) != nullptr) {
merge->hmap.Lookup(cursor->key, &entry);

if (entry != nullptr) {
ErrorFormat(kValueError[0], "got multiple values for key '%s'", cursor->key);

Release(merge);
Expand Down
2 changes: 2 additions & 0 deletions argon/vm/datatype/dict.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
#include <argon/vm/datatype/hashmap.h>

namespace argon::vm::datatype {
using DictEntry = HEntry<ArObject, ArObject*>;

struct Dict {
AROBJ_HEAD;

Expand Down
17 changes: 14 additions & 3 deletions argon/vm/datatype/error.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,11 @@ const ObjectSlots error_objslot = {
};

ArObject *error_get_item(const Error *self, ArObject *key) {
auto *entry = self->detail.Lookup(key);
ErrorEntry *entry;

if (!self->detail.Lookup(key, &entry))
return nullptr;

if (entry == nullptr) {
ErrorFormat(kKeyError[0], kKeyError[1], key);

Expand All @@ -72,7 +76,12 @@ ArObject *error_get_item(const Error *self, ArObject *key) {
}

ArObject *error_item_in(const Error *self, ArObject *key) {
return BoolToArBool(self->detail.Lookup(key) != nullptr);
ErrorEntry *entry;

if (!self->detail.Lookup(key, &entry))
return nullptr;

return BoolToArBool(entry != nullptr);
}

ArSize error_length(const Error *self) {
Expand Down Expand Up @@ -101,7 +110,9 @@ ArObject *error_compare(Error *self, ArObject *other, CompareMode mode) {
return BoolToArBool(false);

for (auto *cursor = self->detail.iter_begin; cursor != nullptr; cursor = cursor->iter_next) {
const auto *other_entry = o->detail.Lookup(cursor->key);
ErrorEntry *other_entry;

o->detail.Lookup(cursor->key, &other_entry);

if (other_entry == nullptr)
return BoolToArBool(false);
Expand Down
5 changes: 4 additions & 1 deletion argon/vm/datatype/error.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@ namespace argon::vm::datatype {
(const char *) "%s does not support %s (generator function)",
(const char *) "no viable conversion from '%s' to %s",
(const char *) "'%s' is not callable",
(const char *) "'%s' is not iterable"
(const char *) "'%s' is not iterable",
(const char *) "expected '%s' as method, got function"
};

constexpr const char *kUnassignableError[] = {
Expand Down Expand Up @@ -152,6 +153,8 @@ namespace argon::vm::datatype {
(const char *) "ValueError"
};

using ErrorEntry = HEntry<ArObject, ArObject *>;

struct Error {
AROBJ_HEAD;

Expand Down
99 changes: 62 additions & 37 deletions argon/vm/datatype/hashmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ namespace argon::vm::datatype {
std::atomic_int ref;

HEntry *next;
HEntry **prev;

HEntry *iter_next;
HEntry *iter_prev;
Expand Down Expand Up @@ -72,11 +73,19 @@ namespace argon::vm::datatype {
if (!this->Resize())
return false;

Hash((ArObject *) entry->key, &index);
if (!Hash((ArObject *) entry->key, &index))
return false;

index %= this->capacity;

entry->next = this->map[index];
auto *slot = this->map[index];

entry->next = slot;
entry->prev = this->map + index;

if (slot != nullptr)
slot->prev = &entry->next;

this->map[index] = entry;
this->length++;

Expand All @@ -85,6 +94,57 @@ namespace argon::vm::datatype {
return true;
}

bool Lookup(K *key, HEntry<K, V> **entry) const {
ArSize index;

*entry = nullptr;

if (!Hash((ArObject *) key, &index))
return false;

index %= this->capacity;

for (HEntry<K, V> *cur = this->map[index]; cur != nullptr; cur = cur->next) {
if (EqualStrict((const ArObject *) key, (const ArObject *) cur->key)) {
*entry = cur;

break;
}
}

return true;
}

bool Remove(K *key, HEntry<K, V> **entry) {
ArSize index;

*entry = nullptr;

if (!Hash((ArObject *) key, &index))
return false;

index %= this->capacity;

for (HEntry<K, V> *cur = this->map[index]; cur != nullptr; cur = cur->next) {
if (EqualStrict((ArObject *) key, (ArObject *) cur->key)) {
(*cur->prev) = cur->next;

if (cur->next != nullptr)
cur->next->prev = cur->prev;

this->length--;

this->RemoveIterItem(cur);

*entry = cur;

break;
}
}

return true;
}

bool Resize() {
HEntry<K, V> **new_map;
ArSize new_cap;
Expand Down Expand Up @@ -146,41 +206,6 @@ namespace argon::vm::datatype {
return ret;
}

HEntry<K, V> *Lookup(K *key) const {
ArSize index;

Hash((ArObject *) key, &index);

index %= this->capacity;

for (HEntry<K, V> *cur = this->map[index]; cur != nullptr; cur = cur->next)
if (EqualStrict((const ArObject *) key, (const ArObject *) cur->key))
return cur;

return nullptr;
}

HEntry<K, V> *Remove(K *key) {
ArSize index;

Hash((ArObject *) key, &index);

index %= this->capacity;

for (HEntry<K, V> *cur = this->map[index]; cur != nullptr; cur = cur->next) {
if (EqualStrict((ArObject *) key, (ArObject *) cur->key)) {
this->map[index] = cur->next;
this->length--;

this->RemoveIterItem(cur);

return cur;
}
}

return nullptr;
}

void AppendIterItem(HEntry<K, V> *entry) {
if (this->iter_begin == nullptr) {
this->iter_begin = entry;
Expand Down
Loading

0 comments on commit 456a889

Please sign in to comment.