diff --git a/src/common.cpp b/src/common.cpp index f71318a..8b8f52e 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -187,11 +187,71 @@ short cmp_tag(Tag lhs, Tag rhs) { } Result Dict::get(Arena& arena, Value& key) { - return ErrorCode::TypeMismatch; + auto pos = TRY(find(arena, key)); + if (pos > size()) return ErrorCode::KeyError; + auto k = TRY(Value::create(arena, _value->data[pos * 2].get(_value.get()))); + + if (TRY(k != key)) { + return ErrorCode::KeyError; + } + + return TRY(Value::create(arena, _value->data[pos * 2 + 1].get(_value.get()))); } Result Dict::insert(Arena& arena, Value& key, Value& value) { - return ErrorCode::TypeMismatch; + auto pos = TRY(find(arena, key)); + auto s = size(); + if (pos >= s) { + s += 1; + } else { + auto k = TRY(Value::create(arena, _value->data[pos * 2].get(_value.get()))); + if (TRY(k != key)) s += 1; + } + + auto pod = TRY(arena.alloc(2 * s * sizeof(OffPtr))); + pod->size = s; + + auto vpod = _value.get(); + for (uint64_t i = 0, j = 0; i < s; i++, j++) { + if (i == pos) { + pod->data[i * 2] = OffPtr(pod, key.pod()); + pod->data[i * 2 + 1] = OffPtr(pod, value.pod()); + if (s > size() && i < s - 1) { + i++; + pod->data[i * 2] = + OffPtr(pod, _value->data[j * 2].get(vpod)); + pod->data[i * 2 + 1] = + OffPtr(pod, _value->data[j * 2 + 1].get(vpod)); + } + } else { + pod->data[i * 2] = OffPtr(pod, _value->data[j * 2].get(vpod)); + pod->data[i * 2 + 1] = + OffPtr(pod, _value->data[j * 2 + 1].get(vpod)); + } + } + + return Dict(TRY(MkGcRoot(pod, arena))); +} + +Result Dict::find(Arena& arena, Value& key) { + uint64_t left = 0; + uint64_t right = size(); + uint64_t pos = (left + right) / 2; + while (left < right) { + auto v = TRY(Value::create(arena, _value->data[pos * 2].get(_value.get()))); + auto c = TRY(v.cmp(key)); + if (c == 0) { + return pos; + } + if (c < 0) { + left = pos + 1; + } + if (c > 0) { + right = pos; + } + pos = (left + right) / 2; + } + return left; } Result Int64::cmp(Float& rhs) { diff --git a/src/common.hpp b/src/common.hpp index 7151e3e..4b49e99 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -23,6 +23,7 @@ class Syntax; class Pair; class Array; class ByteArray; +class Writer; short cmp_tag(Tag lhs, Tag rhs); @@ -256,6 +257,7 @@ class ByteArray : public Object { class Dict : public Object { public: + friend class Writer; Dict() {} Dict(Dict&& rhs) : _value(std::move(rhs._value)) {} Dict(GcRoot&& val) : _value(std::move(val)) {} @@ -291,6 +293,9 @@ class Dict : public Object { Result insert(Arena& arena, Value& key, Value& value); + template + Result insert(Arena& arena, const K& key, const V& value); + Result concat(Arena& arena, Dict& rhs) { uint64_t rhs_size = rhs.size(); uint64_t lhs_size = size(); @@ -305,6 +310,8 @@ class Dict : public Object { } private: + Result find(Arena& arena, Value& key); + uint64_t size() { return _value->size; } GcRoot _value; }; @@ -643,6 +650,10 @@ class Value { static Result create(Arena& arena, PodObject* obj); + static Result create(Arena& arena, const int64_t& value) { + return Value(TRY(Int64::create(arena, value))); + } + template bool is() { return dynamic_cast((Object*)buf) != nullptr; @@ -664,6 +675,7 @@ class Value { } Result operator==(Value& rhs) { return TRY(cmp(rhs)) == 0; } + Result operator!=(Value& rhs) { return TRY(cmp(rhs)) != 0; } Result copy(Arena& arena) { return ((Object*)buf)->copy(arena); } @@ -676,3 +688,11 @@ Result syntax_unwrap(Value& val); Result reverse(Arena& arena, Value& val); Result debug_print(Arena& arena, String& val); + +template +Result Dict::insert(Arena& arena, const K& key, const V& value) { + Value k = TRY(Value::create(arena, key)); + Value v = TRY(Value::create(arena, value)); + + return insert(arena, k, v); +} diff --git a/src/error.hpp b/src/error.hpp index 88e7d2c..ca1a07a 100644 --- a/src/error.hpp +++ b/src/error.hpp @@ -11,4 +11,5 @@ enum class ErrorCode { NotImplemented, InvalidSymbol, MalformedList, + KeyError, }; diff --git a/src/writer.cpp b/src/writer.cpp index f595a74..35026c8 100644 --- a/src/writer.cpp +++ b/src/writer.cpp @@ -190,5 +190,29 @@ Result Writer::write_array(Array& val) { } Result Writer::write_dict(Dict& val) { - return ErrorCode::NotImplemented; + String res = TRY(String::create(_arena, "{")); + + bool is_first = true; + for (uint64_t i = 0; i < val.size(); i++) { + Value k = TRY( + Value::create(_arena, val._value->data[i * 2].get(val._value.get()))); + + Value v = TRY(Value::create( + _arena, val._value->data[i * 2 + 1].get(val._value.get()))); + + if (!is_first) res = TRY(res.concat(_arena, " ")); + + String first_str = TRY(write_one(k)); + res = TRY(res.concat(_arena, first_str)); + + res = TRY(res.concat(_arena, " ")); + + String second_str = TRY(write_one(v)); + res = TRY(res.concat(_arena, second_str)); + + is_first = false; + } + + res = TRY(res.concat(_arena, "}")); + return res; } diff --git a/test/dict.cpp b/test/dict.cpp index d92f128..38a410f 100644 --- a/test/dict.cpp +++ b/test/dict.cpp @@ -1,4 +1,24 @@ +#include "common.hpp" #include "die.hpp" #include "test.hpp" +#include "writer.hpp" -TEST_CASE(dict_insert) { die("test"); } +StaticArena<64 * 1024 * 1024> arena; + +TEST_CASE(dict_insert) { + auto d = DIEX(Dict::create(arena)); + + d = DIEX(d.insert(arena, 1, 2)); + d = DIEX(d.insert(arena, 1, 3)); + d = DIEX(d.insert(arena, 3, 3)); + d = DIEX(d.insert(arena, 0, 4)); + d = DIEX(d.insert(arena, 0, 5)); + d = DIEX(d.insert(arena, 2, 6)); + + auto w = Writer(arena); + + auto dd = DIEX(d.copy(arena)); + auto s = DIEX(w.write_one(dd)); + + DIEX(debug_print(arena, s)); +}