Made entries recursive

This commit is contained in:
Chadtech 2021-01-01 21:08:13 -05:00
parent bd5259363c
commit 58d33e643d

View file

@ -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);
}