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.
#import "Hash_Table";
Table(Key, Value) maps keys to values.
table: Table(string, int);
table_add(*table, "one", 1);
found, value := table_find(*table, "one");
assert(found && value == 1);Procedures#
The smallest power of two that is at least x, and 1 for anything below that. Fails an assert when the result would not fit an int.
assert(next_power_of_two(33) == 64);
assert(next_power_of_two(64) == 64);
assert(next_power_of_two(0) == 1);↗Rehashes every entry into a new array of new_allocated slots, and frees the old one.
Makes sure items more entries can be added without the table growing again.
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);↗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);↗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.
A pointer to the value stored for key, or null when there is none, so the value can be changed in place.
counts: Table(string, int);
table_add(*counts, "a", 1);
pointer := table_find_pointer(*counts, "a");
pointer.* += 1;
assert(table_find_pointer(*counts, "a").* == 2);
assert(table_find_pointer(*counts, "b") == null);
deinit(*counts);↗table: Table(int, string);
table_add(*table, 7, "seven");
assert(table_contains(*table, 7) && !table_contains(*table, 8));↗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);↗Every value stored under key, as a view into temporary storage (talloc), or an empty view when there are none.
table: Table(int, string);
table_add(*table, 1, "a");
table_add(*table, 1, "b");
table_add(*table, 2, "c");
assert(table_find_multiple(*table, 1).count == 2);
assert(table_find_multiple(*table, 9).count == 0);
deinit(*table);↗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);↗Removes every entry with this key and returns how many there were.
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);↗Removes every entry but keeps the allocated slots, so refilling the table up to its old size allocates nothing.
Removes every entry and frees the slot array through the table's allocator. The table is usable again afterwards and allocates from scratch.
Frees the table's memory, as table_reset does. Call it when the table is no longer needed.
Lets a table be used in a for loop: it is the value and it_index the key.
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#
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);↗