| ... | ... | @@ -9,22 +9,12 @@ const debug_u32 = if (want_modification_safety) u32 else void; |
| 9 | 9 | |
| 10 | 10 | pub fn HashMap(inline K: type, inline V: type, inline hash: fn(key: K)->u32, |
| 11 | 11 | inline eql: fn(a: K, b: K)->bool) -> type |
| 12 | | { |
| 13 | | SmallHashMap(K, V, hash, eql, @sizeOf(usize)) |
| 14 | | } |
| 15 | | |
| 16 | | pub fn SmallHashMap(inline K: type, inline V: type, |
| 17 | | inline hash: fn(key: K)->u32, inline eql: fn(a: K, b: K)->bool, |
| 18 | | inline static_size: usize) -> type |
| 19 | 12 | { |
| 20 | 13 | struct { |
| 21 | 14 | entries: []Entry, |
| 22 | 15 | size: usize, |
| 23 | 16 | max_distance_from_start_index: usize, |
| 24 | 17 | allocator: &Allocator, |
| 25 | | // if the hash map is small enough, we use linear search through these |
| 26 | | // entries instead of allocating memory |
| 27 | | prealloc_entries: [static_size]Entry, |
| 28 | 18 | // this is used to detect bugs where a hashtable is edited while an iterator is running. |
| 29 | 19 | modification_count: debug_u32, |
| 30 | 20 | |
| ... | ... | @@ -64,18 +54,16 @@ pub fn SmallHashMap(inline K: type, inline V: type, |
| 64 | 54 | }; |
| 65 | 55 | |
| 66 | 56 | pub fn init(hm: &Self, allocator: &Allocator) { |
| 67 | | hm.entries = hm.prealloc_entries[0...]; |
| 57 | hm.entries = []Entry{}; |
| 68 | 58 | hm.allocator = allocator; |
| 69 | 59 | hm.size = 0; |
| 70 | 60 | hm.max_distance_from_start_index = 0; |
| 71 | | hm.prealloc_entries = zeroes; // sets used to false for all entries |
| 72 | | hm.modification_count = zeroes; |
| 61 | // it doesn't actually matter what we set this to since we use wrapping integer arithmetic |
| 62 | hm.modification_count = undefined; |
| 73 | 63 | } |
| 74 | 64 | |
| 75 | 65 | pub fn deinit(hm: &Self) { |
| 76 | | if (hm.entries.ptr != &hm.prealloc_entries[0]) { |
| 77 | | hm.allocator.free(Entry, hm.entries); |
| 78 | | } |
| 66 | hm.allocator.free(Entry, hm.entries); |
| 79 | 67 | } |
| 80 | 68 | |
| 81 | 69 | pub fn clear(hm: &Self) { |
| ... | ... | @@ -90,14 +78,8 @@ pub fn SmallHashMap(inline K: type, inline V: type, |
| 90 | 78 | pub fn put(hm: &Self, key: K, value: V) -> %void { |
| 91 | 79 | hm.incrementModificationCount(); |
| 92 | 80 | |
| 93 | | const resize = if (hm.entries.ptr == &hm.prealloc_entries[0]) { |
| 94 | | // preallocated entries table is full |
| 95 | | hm.size == hm.entries.len |
| 96 | | } else { |
| 97 | | // if we get too full (60%), double the capacity |
| 98 | | hm.size * 5 >= hm.entries.len * 3 |
| 99 | | }; |
| 100 | | if (resize) { |
| 81 | // if we get too full (60%), double the capacity |
| 82 | if (hm.size * 5 >= hm.entries.len * 3) { |
| 101 | 83 | const old_entries = hm.entries; |
| 102 | 84 | %return hm.initCapacity(hm.entries.len * 2); |
| 103 | 85 | // dump all of the old elements into the new table |
| ... | ... | @@ -106,9 +88,7 @@ pub fn SmallHashMap(inline K: type, inline V: type, |
| 106 | 88 | hm.internalPut(old_entry.key, old_entry.value); |
| 107 | 89 | } |
| 108 | 90 | } |
| 109 | | if (old_entries.ptr != &hm.prealloc_entries[0]) { |
| 110 | | hm.allocator.free(Entry, old_entries); |
| 111 | | } |
| 91 | hm.allocator.free(Entry, old_entries); |
| 112 | 92 | } |
| 113 | 93 | |
| 114 | 94 | hm.internalPut(key, value); |