mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 16:44:33 +00:00
Made entries recursive
This commit is contained in:
parent
bd5259363c
commit
58d33e643d
1 changed files with 238 additions and 77 deletions
|
@ -7,7 +7,6 @@ const assert = std.debug.assert;
|
|||
|
||||
const print = std.debug.print;
|
||||
|
||||
|
||||
const hash = @import("hash.zig");
|
||||
|
||||
const size = 32;
|
||||
|
@ -20,21 +19,163 @@ pub fn RocDict(
|
|||
const Self = @This();
|
||||
|
||||
pub const Entry = struct {
|
||||
key: Key,
|
||||
value: Value,
|
||||
key_ptr: *Key,
|
||||
value_ptr: *Value,
|
||||
overflow: ?Overflow,
|
||||
|
||||
pub const Overflow = struct {
|
||||
entries: *[size]?*Entry,
|
||||
|
||||
// This function takes an
|
||||
// index, key, and value,
|
||||
// because presumably overflow
|
||||
// is only created once an
|
||||
// there is a collision between
|
||||
// two entries, and there is
|
||||
// therefore an extra entry
|
||||
// that needs to be stored
|
||||
pub fn new(
|
||||
index: u64,
|
||||
key_ptr: *Key,
|
||||
value_ptr: *Value
|
||||
) Overflow {
|
||||
var init_entries : [size]?*Entry = undefined;
|
||||
|
||||
var new_overflow = Overflow {
|
||||
.entries = &init_entries
|
||||
};
|
||||
|
||||
new_overflow.set_at_index(index, key_ptr, value_ptr);
|
||||
|
||||
return new_overflow;
|
||||
}
|
||||
|
||||
pub fn set_at_index(
|
||||
self: *Overflow,
|
||||
index: u64,
|
||||
key_ptr: *Key,
|
||||
value_ptr: *Value
|
||||
) void {
|
||||
var overflow = self.*;
|
||||
var new_entry = Entry.new(key_ptr, value_ptr);
|
||||
|
||||
overflow.entries.*[index] = &new_entry;
|
||||
}
|
||||
|
||||
pub fn get_at_index(
|
||||
self: Overflow,
|
||||
index: u64,
|
||||
) ?*Entry {
|
||||
return self.entries.*[index];
|
||||
}
|
||||
};
|
||||
|
||||
pub fn new(key_ptr: *Key, value_ptr: *Value) Entry {
|
||||
return Entry {
|
||||
.value_ptr = value_ptr,
|
||||
.key_ptr = key_ptr,
|
||||
.overflow = null
|
||||
};
|
||||
}
|
||||
|
||||
pub fn eq(self: Entry, other: Entry) bool {
|
||||
const same_keys = self.key == other.key;
|
||||
const same_value = self.value == other.value;
|
||||
const same_keys = self.key_ptr.* == other.key_ptr.*;
|
||||
const same_value = self.value_ptr.* == other.value_ptr.*;
|
||||
return same_keys and same_value;
|
||||
}
|
||||
|
||||
pub fn set_value(self: *Entry, value: Value) void {
|
||||
self.*.value = value;
|
||||
pub fn set_value(self: *Entry, value_ptr: *Value) void {
|
||||
self.*.value_ptr = value_ptr;
|
||||
}
|
||||
|
||||
pub fn get(self: *Entry, key: Key, level: u64) ?*Value {
|
||||
const entry = self.*;
|
||||
const entry_key = entry.key_ptr.*;
|
||||
|
||||
if (key == entry_key) {
|
||||
return entry.value_ptr;
|
||||
} else {
|
||||
const maybe_overflow = entry.overflow;
|
||||
|
||||
if (maybe_overflow == null) {
|
||||
return null;
|
||||
} else {
|
||||
const overflow = maybe_overflow.?;
|
||||
const index = key_to_index_at_level(key, level);
|
||||
const maybe_next_entry_ptr = overflow.get_at_index(index);
|
||||
|
||||
if (maybe_next_entry_ptr == null) {
|
||||
return null;
|
||||
} else {
|
||||
var next_entry = maybe_next_entry_ptr.?.*;
|
||||
const next_level = level + 1;
|
||||
|
||||
return next_entry.get(key, next_level);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The bool this function returns
|
||||
// represents if an new entry was
|
||||
// added (true), or if an old one
|
||||
// was updated (false);
|
||||
pub fn insert_into_overflow(
|
||||
self: *Entry,
|
||||
key_ptr: *Key,
|
||||
value_ptr: *Value,
|
||||
level: u64
|
||||
) bool {
|
||||
const key = key_ptr.*;
|
||||
|
||||
const index = key_to_index_at_level(key, level);
|
||||
|
||||
var entry = self.*;
|
||||
|
||||
// If there is no overflow, make a new OverFlow
|
||||
if (entry.overflow == null) {
|
||||
var new_overflow : Overflow = Overflow.new(index, key_ptr, value_ptr);
|
||||
|
||||
entry.overflow = new_overflow;
|
||||
|
||||
return true;
|
||||
} else {
|
||||
var overflow = entry.overflow.?;
|
||||
|
||||
const maybe_overflow_entry_ptr = overflow.get_at_index(index);
|
||||
|
||||
// If there is overflow, check if this index is taken
|
||||
// and if it isnt, than insert it
|
||||
if (maybe_overflow_entry_ptr == null) {
|
||||
var new_entry = Entry.new(key_ptr, value_ptr);
|
||||
|
||||
overflow.set_at_index(index, key_ptr, value_ptr);
|
||||
return true;
|
||||
} else {
|
||||
var overflow_entry_ptr = maybe_overflow_entry_ptr.?;
|
||||
|
||||
var overflow_entry = overflow_entry_ptr.*;
|
||||
|
||||
// if this index in the overflow is taken
|
||||
// and it has the same key, update the entry
|
||||
// at that key, otherwise move down another
|
||||
// level into that entry's overflow.
|
||||
if (overflow_entry.key_ptr.* == key) {
|
||||
overflow_entry.set_value(value_ptr);
|
||||
return false;
|
||||
} else {
|
||||
return overflow_entry.insert_into_overflow(
|
||||
key_ptr,
|
||||
value_ptr,
|
||||
level + 1
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
pub const Query = struct {
|
||||
maybe_entry: ?Entry
|
||||
};
|
||||
|
@ -52,7 +193,7 @@ pub fn RocDict(
|
|||
} else {
|
||||
var entry = maybe_entry.?;
|
||||
|
||||
if (entry.key == key) {
|
||||
if (entry.key_ptr.* == key) {
|
||||
return Query { .maybe_entry = entry };
|
||||
} else {
|
||||
return self.query(key, level + 1);
|
||||
|
@ -82,44 +223,56 @@ pub fn RocDict(
|
|||
}
|
||||
|
||||
|
||||
pub fn get(self: Self, key: Key) ?Value {
|
||||
pub fn get(self: Self, key: Key) ?*Value {
|
||||
|
||||
const q = self.query(key, 0);
|
||||
|
||||
if (q.maybe_entry == null) {
|
||||
return null;
|
||||
} else {
|
||||
const entry = q.maybe_entry.?;
|
||||
var entry = q.maybe_entry.?;
|
||||
|
||||
return entry.value;
|
||||
const entry_key = entry.key_ptr.*;
|
||||
|
||||
if (entry_key == key) {
|
||||
return entry.value_ptr;
|
||||
} else {
|
||||
return entry.get(key, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert(self: *Self, key: Key, value: Value) void {
|
||||
pub fn insert(self: *Self, key_ptr: *Key, value_ptr: *Value) void {
|
||||
const level = 0;
|
||||
|
||||
const key = key_ptr.*;
|
||||
|
||||
const q = self.query(key, level);
|
||||
|
||||
const index = key_to_index_at_level(key, level);
|
||||
|
||||
if (q.maybe_entry == null) {
|
||||
|
||||
var new_entry = Entry {
|
||||
.value = value,
|
||||
.key = key
|
||||
};
|
||||
var new_entry = Entry.new(value_ptr, key_ptr);
|
||||
|
||||
self.entries[index] = new_entry;
|
||||
|
||||
self.len += 1;
|
||||
|
||||
self.*.len += 1;
|
||||
|
||||
} else {
|
||||
var entry = q.maybe_entry.?;
|
||||
|
||||
var entry_ptr = &entry;
|
||||
if (entry.key_ptr.* == key) {
|
||||
var entry_ptr = &entry;
|
||||
entry_ptr.set_value(value_ptr);
|
||||
self.entries[index] = entry;
|
||||
} else {
|
||||
const inserted_new_entry = entry.insert_into_overflow(key_ptr, value_ptr, 0);
|
||||
|
||||
entry_ptr.set_value(value);
|
||||
|
||||
self.entries[index] = entry;
|
||||
if (inserted_new_entry) {
|
||||
self.len += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,112 +320,120 @@ pub fn RocDict(
|
|||
}
|
||||
|
||||
test "RocDict.insert with hash collisions" {
|
||||
var dict = RocDict(u64,u64).init(testing.allocator);
|
||||
var dict = RocDict(u64,u64).init(testing.allocator);
|
||||
|
||||
var i : u64 = 0;
|
||||
var i : u64 = 0;
|
||||
|
||||
while (i < (size * 2)) {
|
||||
dict.insert(i, i);
|
||||
while (i < (size * 2)) {
|
||||
dict.insert(&i, &i);
|
||||
|
||||
i += 1;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (i < (size * 2)) {
|
||||
const entry = dict.get(i);
|
||||
i = 0;
|
||||
while (i < (size * 2)) {
|
||||
const entry = dict.get(i);
|
||||
|
||||
expectEqual(i, entry.?);
|
||||
expectEqual(i, entry.?.*);
|
||||
|
||||
i += 1;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
test "repeated RocDict.insert" {
|
||||
var dict = RocDict(u64,u64).init(testing.allocator);
|
||||
var dict = RocDict(u64,u64).init(testing.allocator);
|
||||
|
||||
const index = 0;
|
||||
dict.insert(index, 17);
|
||||
dict.insert(index, 49);
|
||||
var index : u64 = 0;
|
||||
var fst_val : u64 = 17;
|
||||
var snd_val : u64 = 49;
|
||||
|
||||
var value : ?u64 = dict.get(index);
|
||||
dict.insert(&index, &fst_val);
|
||||
dict.insert(&index, &snd_val);
|
||||
|
||||
if (value == null) {
|
||||
unreachable;
|
||||
} else {
|
||||
const result : ?u64 = 49;
|
||||
expectEqual(result, value);
|
||||
}
|
||||
var value_ptr : ?*u64 = dict.get(index);
|
||||
|
||||
if (value_ptr == null) {
|
||||
unreachable;
|
||||
} else {
|
||||
const value = value_ptr.?.*;
|
||||
expectEqual(snd_val, value);
|
||||
}
|
||||
}
|
||||
|
||||
test "RocDict.eq" {
|
||||
var fst = RocDict(u64,u64).init(testing.allocator);
|
||||
var snd = RocDict(u64,u64).init(testing.allocator);
|
||||
var fst = RocDict(u64,u64).init(testing.allocator);
|
||||
var snd = RocDict(u64,u64).init(testing.allocator);
|
||||
|
||||
const key = 0;
|
||||
const value = 30;
|
||||
var key : u64 = 0;
|
||||
var value : u64 = 30;
|
||||
|
||||
fst.insert(key, value);
|
||||
snd.insert(key, value);
|
||||
assert(fst.eq(snd));
|
||||
fst.insert(&key, &value);
|
||||
snd.insert(&key, &value);
|
||||
assert(fst.eq(snd));
|
||||
|
||||
var empty = RocDict(u64,u64).init(testing.allocator);
|
||||
assert(!fst.eq(empty));
|
||||
var empty = RocDict(u64,u64).init(testing.allocator);
|
||||
assert(!fst.eq(empty));
|
||||
|
||||
var trd = RocDict(u64,u64).init(testing.allocator);
|
||||
trd.insert(key, value + 1);
|
||||
var trd = RocDict(u64,u64).init(testing.allocator);
|
||||
var new_value : u64 = value + 1;
|
||||
trd.insert(&key, &new_value);
|
||||
|
||||
assert(!fst.eq(trd));
|
||||
assert(!fst.eq(trd));
|
||||
}
|
||||
|
||||
|
||||
|
||||
test "RocDict.get_len" {
|
||||
var dict = RocDict(u64,u64).init(testing.allocator);
|
||||
var dict = RocDict(u64,u64).init(testing.allocator);
|
||||
|
||||
const index = 0;
|
||||
var key : u64 = 0;
|
||||
|
||||
dict.insert(index, 16);
|
||||
var value : u64 = 16;
|
||||
dict.insert(&key, &value);
|
||||
|
||||
const expect_len : u64 = 1;
|
||||
expectEqual(expect_len, dict.get_len());
|
||||
const expect_len : u64 = 1;
|
||||
expectEqual(dict.get_len(), expect_len);
|
||||
|
||||
dict.insert(index, 16);
|
||||
dict.insert(&key, &value);
|
||||
|
||||
expectEqual(expect_len, dict.get_len());
|
||||
expectEqual(dict.get_len(), expect_len);
|
||||
|
||||
dict.insert(index + 1, 3);
|
||||
var next_key : u64 = key + 1;
|
||||
var next_value : u64 = 3 ;
|
||||
dict.insert(&next_key, &next_value);
|
||||
|
||||
expectEqual(expect_len + 1, dict.get_len());
|
||||
var next_expected_len : u64 = 2;
|
||||
expectEqual(dict.get_len(), next_expected_len);
|
||||
}
|
||||
|
||||
|
||||
test "RocDict.insert" {
|
||||
var dict = RocDict(u64,u64).init(testing.allocator);
|
||||
|
||||
const index = 0;
|
||||
const value : u64 = 30;
|
||||
var index : u64 = 0;
|
||||
var value : u64 = 30;
|
||||
|
||||
dict.insert(index, value);
|
||||
dict.insert(&index, &value);
|
||||
|
||||
var result_value : ?u64 = dict.get(index);
|
||||
expectEqual(value, result_value.?);
|
||||
var result_value : ?*u64 = dict.get(index);
|
||||
expectEqual(result_value.?.*, value);
|
||||
|
||||
var expect_len : u64 = 1;
|
||||
expectEqual(expect_len, dict.get_len());
|
||||
expectEqual(dict.get_len(), expect_len);
|
||||
}
|
||||
|
||||
|
||||
test "RocDict.get" {
|
||||
const empty = RocDict(u64, u64).init(testing.allocator);
|
||||
|
||||
const expect : ?u64 = null;
|
||||
expectEqual(expect, empty.get(29));
|
||||
const expect : ?*u64 = null;
|
||||
expectEqual(empty.get(29), expect);
|
||||
}
|
||||
|
||||
|
||||
test "RocDict.init" {
|
||||
const empty = RocDict(u64, u64).init(testing.allocator);
|
||||
expectEqual(empty.get_len(), 0);
|
||||
expectEqual(0, empty.get_len());
|
||||
|
||||
const MadeUpType = struct {
|
||||
oneField: u64
|
||||
|
@ -281,5 +442,5 @@ test "RocDict.init" {
|
|||
const empty_made_up = RocDict(u64, MadeUpType).init(testing.allocator);
|
||||
|
||||
const expect : u64 = 0;
|
||||
expectEqual(expect, empty_made_up.get_len());
|
||||
expectEqual(empty_made_up.get_len(), expect);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue