zig/src/list.hpp
Andrew Kelley df2c27eb48 stage1 HashMap: store hash & do robin hood hashing
This adds these two fields to a HashMap Entry:

uint32_t hash
uint32_t distance_from_start_index

Compared to master branch, standard library tests compiled 8.4% faster
and took negligible (0.001%) more memory to complete. The amount of
memory used is still down from before 8b82c4010480 which moved indexes
to be stored separately from entries.

So, it turns out, keeping robin hood hashing plus separating indexes
did result in a performance improvement. What happened previously is
that the gains from separating indexes balanced out the losses from
removing robin hood hashing, resulting in a wash.

This also serves as an inspiration for adding a benchmark to
std.AutoHashMap and improving the implementation.
2020-07-02 22:38:55 +00:00

97 lines
2.1 KiB
C++

/*
* Copyright (c) 2015 Andrew Kelley
*
* This file is part of zig, which is MIT licensed.
* See http://opensource.org/licenses/MIT
*/
#ifndef ZIG_LIST_HPP
#define ZIG_LIST_HPP
#include "util.hpp"
template<typename T>
struct ZigList {
void deinit() {
heap::c_allocator.deallocate(items, capacity);
}
void append(const T& item) {
ensure_capacity(length + 1);
items[length++] = item;
}
void append_assuming_capacity(const T& item) {
items[length++] = item;
}
// remember that the pointer to this item is invalid after you
// modify the length of the list
const T & at(size_t index) const {
assert(index != SIZE_MAX);
assert(index < length);
return items[index];
}
T & at(size_t index) {
assert(index != SIZE_MAX);
assert(index < length);
return items[index];
}
T pop() {
assert(length >= 1);
return items[--length];
}
T *add_one() {
resize(length + 1);
return &last();
}
const T & last() const {
assert(length >= 1);
return items[length - 1];
}
T & last() {
assert(length >= 1);
return items[length - 1];
}
void resize(size_t new_length) {
assert(new_length != SIZE_MAX);
ensure_capacity(new_length);
length = new_length;
}
void clear() {
length = 0;
}
void ensure_capacity(size_t new_capacity) {
if (capacity >= new_capacity)
return;
size_t better_capacity = capacity;
do {
better_capacity = better_capacity * 5 / 2 + 8;
} while (better_capacity < new_capacity);
items = heap::c_allocator.reallocate_nonzero(items, capacity, better_capacity);
capacity = better_capacity;
}
T swap_remove(size_t index) {
if (length - 1 == index) return pop();
assert(index != SIZE_MAX);
assert(index < length);
T old_item = items[index];
items[index] = pop();
return old_item;
}
T *items;
size_t length;
size_t capacity;
};
#endif