rewrote Set to rehash
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 10 Oct 2021 23:33:27 +0000 (18:33 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 10 Oct 2021 23:33:27 +0000 (18:33 -0500)
bin/onyx
core/container/map.onyx
core/container/set.onyx

index 255ab06d05481b1533820de3fd57c869b4d0db6e..2570cf38dbeb573582a7234fa23989cf1de7dfc3 100755 (executable)
Binary files a/bin/onyx and b/bin/onyx differ
index a504b11452a5e39ee60b25d1fc1a659e2c16fa64..f9c15df66e88526b292055f98efb5a76a9aa2eeb 100644 (file)
@@ -150,16 +150,6 @@ empty :: (use map: ^Map($K, $V)) -> bool {
         return lr;
     }
 
-    add_entry :: (use map: ^Map($K, $V), key: K) -> i32 {
-        entry: Map.Entry(K, V);
-        entry.key = key;
-        entry.next = -1;
-
-        entries << entry;
-
-        return entries.count - 1;
-    }
-
     full :: (use map: ^Map($K, $V)) => entries.count >= ~~(0.75f * ~~hashes.count);
 
     grow :: (use map: ^Map($K, $V)) {
index cac405d33784e3c285ee9e0f3d97d6cfa35db9c6..51ce0cbb48de6eade5b187f83fccf09a24a703fa 100644 (file)
@@ -1,11 +1,17 @@
 package core.set
 
-#private_file array :: package core.array
-#private_file hash  :: package core.hash
+#private_file {
+    array :: package core.array
+    hash  :: package core.hash
+    memory :: package core.memory
+    math :: package core.math
+}
 use package core.intrinsics.onyx { __zero_value }
 
 Set :: struct (T: type_expr) {
-    hashes  : [..] i32;
+    allocator : Allocator;
+
+    hashes  : [] i32;
     entries : [..] Entry(T);
 
     default_value: T;
@@ -16,24 +22,24 @@ Set :: struct (T: type_expr) {
     }
 }
 
-make :: ($T: type_expr, default := __zero_value(T), hash_count: i32 = 16) -> Set(T) {
+make :: ($T: type_expr, default := __zero_value(T)) -> Set(T) {
     set : Set(T);
-    init(^set, default=default, hash_count=hash_count);
+    init(^set, default=default);
     return set;
 }
 
-init :: (use set: ^Set($T), default := __zero_value(T), hash_count: i32 = 16) {
-    array.init(^hashes, hash_count);
-    hashes.count = hash_count;
-    array.fill(hashes, -1);
+init :: (use set: ^Set($T), default := __zero_value(T)) {
+    allocator = context.allocator;
+    default_value = default;
 
-    array.init(^entries, 4); 
+    memory.alloc_slice(^hashes, 8, allocator=allocator);
+    memory.fill_slice(hashes, -1);
 
-    default_value = default;
+    array.init(^entries, 4, allocator=allocator); 
 }
 
 free :: (use set: ^Set($T)) {
-    array.free(^hashes);
+    memory.free_slice(^hashes, allocator=allocator);
     array.free(^entries);
 }
 
@@ -42,12 +48,10 @@ insert :: (use set: ^Set($T), value: T) {
 
     if lr.entry_index >= 0 do return;
 
-    array.push(^entries, .{
-        value = value,
-        hashes[lr.hash_index],
-    });
-
+    entries << .{ hashes[lr.hash_index], value };
     hashes[lr.hash_index] = entries.count - 1;
+
+    if full(set) do grow(set);
 }
 
 #operator << macro (set: Set($T), value: T) do (package core.set).insert(^set, value);
@@ -124,28 +128,52 @@ iterator :: (set: ^Set($T)) -> Iterator(T) {
 // Private symbols
 //
 
-#private_file
-SetLookupResult :: struct {
-    hash_index  : i32 = -1;
-    entry_index : i32 = -1;
-    entry_prev  : i32 = -1;
-}
+#private_file {
+    SetLookupResult :: struct {
+        hash_index  : i32 = -1;
+        entry_index : i32 = -1;
+        entry_prev  : i32 = -1;
+    }
 
-#private_file
-lookup :: (use set: ^Set($T), value: T) -> SetLookupResult {
-    lr := SetLookupResult.{};
+    lookup :: (use set: ^Set($T), value: T) -> SetLookupResult {
+        lr := SetLookupResult.{};
 
-    hash_value: u32 = hash.to_u32(value); // You cannot have a set of this type without defining a to_u32 hash.
+        hash_value: u32 = hash.to_u32(value); // You cannot have a set of this type without defining a to_u32 hash.
 
-    lr.hash_index = hash_value % hashes.count;
-    lr.entry_index = hashes[lr.hash_index];
+        lr.hash_index = hash_value % hashes.count;
+        lr.entry_index = hashes[lr.hash_index];
 
-    while lr.entry_index >= 0 {
-        if entries[lr.entry_index].value == value do return lr;
+        while lr.entry_index >= 0 {
+            if entries[lr.entry_index].value == value do return lr;
+
+            lr.entry_prev = lr.entry_index;
+            lr.entry_index = entries[lr.entry_index].next;
+        }
 
-        lr.entry_prev = lr.entry_index;
-        lr.entry_index = entries[lr.entry_index].next;
+        return lr;
     }
 
-    return lr;
-}
+    full :: (use set: ^Set($T)) => entries.count >= ~~(0.75f * ~~hashes.count);
+
+    grow :: (use set: ^Set($T)) {
+        new_size := math.max(hashes.count << 1, 8);
+        rehash(set, new_size);
+    }
+
+    rehash :: (use set: ^Set($T), new_size: i32) {
+        memory.free_slice(^hashes, allocator);
+        memory.alloc_slice(^hashes, new_size, allocator);
+        memory.fill_slice(hashes, -1);
+
+        for ^entry: entries do entry.next = -1;
+
+        index := 0;
+        for ^entry: entries {
+            defer index += 1;
+
+            lr := lookup(set, entry.value); 
+            entries[index].next = hashes[lr.hash_index];
+            hashes[lr.hash_index] = index;
+        }
+    }
+}
\ No newline at end of file