Modules

Hash_Table

moduleSource
macOSLinuxWindowswasm

#import "Hash_Table";

Table(Key, Value) maps keys to values.

ExampleOpen in playground ↗
table: Table(string, int);
table_add(*table, "one", 1);
found, value := table_find(*table, "one");
assert(found && value == 1);

Procedures#

(table: *Table, slots_to_allocate: s64 = 0)

Deprecated and not needed: a zero-initialized Table is ready to use. With slots_to_allocate greater than zero it reserves that many slots (rounded up) through expand.

(table: *Table, new_allocated := -1)

Rehashes every entry into a new array of new_allocated slots, and frees the old one.

(table: *Table, items: s64)

Makes sure items more entries can be added without the table growing again.

(table: *Table, expected_count: s64)

Rehashes the table so that expected_count entries (or the current count, if larger) fit within the load factor.

table: Table(int, int);
table_resize(*table, 1000);
slots := table.allocated;
for 0..999 table_add(*table, it, it);
assert(table.allocated == slots && table.count == 1000); // no growth in between
deinit(*table);
↗
(table: *Table, key: table.Key_Type, value: table.Value_Type) -> *table.Value_Type

Adds an entry, even when key is already present, and returns a pointer to the stored value.

table: Table(int, string);
slot := table_add(*table, 1, "one");
slot.* = "uno";
found, value := table_find(*table, 1);
assert(found && value == "uno");
deinit(*table);
↗
(table: *Table, key: table.Key_Type, value: table.Value_Type) -> *table.Value_Type

Sets the value of key, replacing the first entry with an equal key, or adding one if there is none. Returns a pointer to the stored value.

(table: *Table, key: table.Key_Type) -> (success: bool, table.Value_Type)

Looks up key; returns whether it was found and a copy of the value (the default value of the type when it was not).

table: Table(int, float);
table_add(*table, 3, 1.5);
found, value := table_find(*table, 3);
assert(found && value == 1.5);
found, value = table_find(*table, 4);
assert(!found && value == 0);
deinit(*table);
↗
(table: *Table, key: table.Key_Type) -> (success: bool, value: table.Value_Type)

Removes one entry with this key; returns whether there was one and its value.

table: Table(int, string);
table_add(*table, 5, "five");
removed, value := table_remove(*table, 5);
assert(removed && value == "five" && table.count == 0);
removed, value = table_remove(*table, 5);
assert(!removed);
deinit(*table);
↗
(table: *Table, key: table.Key_Type) -> (entry: *table.Value_Type, newly_added: bool)

Finds the value for key, adding a zero-initialized one if there is none. Returns a pointer to it and whether it was just added.

counts: Table(string, int);
for word: string.["a", "b", "a"] {
    count, added := find_or_add(*counts, word);
    count.* += 1;
}
assert(table_find_pointer(*counts, "a").* == 2 && counts.count == 2);
deinit(*counts);
↗
(table: *Table)

Removes every entry but keeps the allocated slots, so refilling the table up to its old size allocates nothing.

(table: *Table)

Removes every entry and frees the slot array through the table's allocator. The table is usable again afterwards and allocates from scratch.

(table: *Table)

Frees the table's memory, as table_reset does. Call it when the table is no longer needed.

(table: *$T/Table, body: Code, flags: For_Flags)

Lets a table be used in a for loop: it is the value and it_index the key.

table: Table(int, int);
for 0..9 table_add(*table, it, it * it);

for *square, key: table square.* += key; // in place

for square, key: table {
    if key % 2 == 0 remove square;
}
assert(table.count == 5);
deinit(*table);
↗
(code: Code)

Low-level macro that visits the slots a lookup of key would probe, in order, up to the first never-used slot.

table: Table(int, string);
table_add(*table, 7, "seven");

key := 7;
matches := 0;
Walk_Table(#code {
    if table_while_loop == hash && table.entries[index].key == key matches += 1;
});
assert(matches == 1);
deinit(*table);
↗

Types#

Tablestruct
:: struct

A hash table from Key_Type to Value_Type: open addressing with linear probing, in one array of entries.

table: Table(string, int);
table_add(*table, "one", 1);
table_set(*table, "two", 2);
table_set(*table, "two", 22); // replaces

found, value := table_find(*table, "two");
assert(found && value == 22 && table.count == 2);

total := 0;
for number, name: table total += number; // `it` is the value, `it_index` the key
assert(total == 23);

deinit(*table);
↗

Constants#