Hash Maps
Hash maps are collections of items that support fast key lookup. Plywood provides two class templates for hash maps:
Set<Item>uses a key type that's automatically determined from the item type. The items are kept in insertion order and the key type must be hashable.Map<Key, Value>uses a key type that's determined by a separate template argument. The items are kept in insertion order and the key type must be hashable.
These collections aren't thread-safe. Functions that read from the same collection can be called concurrently from separate threads, but functions that modify the same collection must not be called concurrently.
Hashable Types
In the Set and Map class templates, hashing is used to speed up key lookups. Any hashable type can be used as a lookup key. In Plywood, the following types are hashable by default:
s8 |
s16 |
s32 |
s64 |
u8 |
u16 |
u32 |
u64 |
float |
double |
T* |
StringView |
- When hashing a pointer, only the address is used, not the contents of the pointed-to object. [TBD: Change this.]
- You can hash a
Stringby implicitly converting it to aStringView.
Making Custom Types Hashable
To make additional types hashable, overload the addToHash function for the desired type, as demonstrated below.
struct CustomType {
u32 x;
String str;
};
// User-defined addToHash overload.
void addToHash(HashBuilder& builder, const CustomType& item) {
addToHash(builder, item.x);
addToHash(builder, item.str);
}
addToHash is called internally by Set and Map. It's called using argument-dependent lookup, so you can define it in the same namespace as the type itself.
Set
A Set is a collection of items that supports fast lookup using a key type that's automatically determined from the item type. The key type must be hashable.
template <typename Item> class Set;
Set objects are movable, copyable and construct to an empty collection by default. They provide the following member functions:
| Additional Constructors | |
| Set(std::initializer_list<Item> items) |
| Accessing Items | |
const Item* | find(const Key& key) const |
ArrayView<Item> | items() |
ArrayView<const Item> | items() const |
| Modifying Set Contents | |
void | clear() |
InsertResult | insert(const Key& key) |
InsertResult | insertItem(Item&& item) |
bool | erase(const Key& key) |
bool | eraseQuick(const Key& key) |
Hashable item types can be used directly as the key type.
Set<u32> set = {4, 5, 6};
PLY_ASSERT(set.find(4)); // OK
Otherwise, the item type must implement a getLookupKey member function. The return type of getLookupKey determines the key type.
struct CustomItem {
String key;
u32 value;
StringView getLookupKey() const {
return this->key;
}
};
Set<CustomItem> set = {
{"apple", 1},
{"banana", 2},
{"cherry", 3},
};
PLY_ASSERT(set.find("banana")); // OK
The items in a Set are maintained in insertion order unless eraseQuick is called.
Set<u32> set = {4, 5, 6, 7};
ArrayView<u32> items = set.items(); // Returns {4, 5, 6, 7}
// erase maintains insertion order.
set.erase(5);
items = set.items(); // Returns {4, 6, 7}
// eraseQuick can change the order of remaining items.
set.eraseQuick(4);
items = set.items(); // Returns {7, 6}
Additional Constructors
Set(std::initializer_list<Item> items)Constructs a set from a braced initializer list. The items are inserted in the order they appear in the list.
Accessing Items
const Item* find(const Key& key) constLooks for an item in the collection that matches the given key. Returns a pointer to the item if found, or
nullptrif not found.The returned pointer is temporary. Any subsequent change to the
Setcan invalidate this pointer, so don't store it beyond the next call tofindorerase, even if those calls involve different keys.ArrayView<Item> items()
ArrayView<const Item> items() constReturns a view of all items in the set. The items are in insertion order unless
eraseQuickwas called.
Modifying Set Contents
void clear()Calls the destructor of all existing items and resets to an empty set.
InsertResult insert(const Key& key)Inserts a new item in the set using the given key if it doesn't already exist. The
Itemtype must be constructible fromKey. Returns anInsertResultwith the following members:[TBD]
This function is actually a function template that uses SFINAE to delete itself if the
Keytype is not constructible from theItemtype. In particular, this means you can't call this function on aSet<Owned<T>>; you can only callinsertItemon such sets.InsertResult insertItem(Item&& item)Inserts a fully constructed item into the set using move semantics. Any existing item with the same key is replaced.
bool erase(const Key& key)Removes the item with the given key. The remaining items are kept in insertion order. If an existing item was found in the set, its destructor is called and
trueis returned. Otherwise, returnsfalse. This function is slower thaneraseQuick.bool eraseQuick(const Key& key)Removes the item with the given key without keeping the remaining items in insertion order. If an existing item was found in the set, its destructor is called and
trueis returned. Otherwise, returnsfalse.
Map
A Map is a collection of key-value pairs whose types are determined by template arguments.
template <typename Key, typename Value> class Map;
Map objects are movable, copyable and construct to an empty collection by default. They provide the following member functions:
| Additional Constructors | |
| Map(std::initializer_list<Item> items) |
| Accessing Items | |
const Value* | find(const KeyView& key) const |
ArrayView<Item> | items() |
ArrayView<const Item> | items() const |
| Modifying Map Contents | |
void | clear() |
InsertResult | insert(const KeyView& key) |
bool | erase(const KeyView& key) |
bool | eraseQuick(const KeyView& key) |
Key can either be a hashable type or a type that maps to a hashable type using getLookupKey, such as String. KeyView is a type alias for the return type of getLookupKey.
Item is a member type that represents a key-value pair. It has the following members:
Key | key |
Value | value |
The items in a Map are kept in insertion order unless eraseQuick is called.
Map<u32, String> map = {
{4, "apple"},
{5, "banana"},
{6, "cherry"},
{7, "date"},
};
// erase maintains insertion order.
map.erase(5);
auto items = map.items(); // Returns {{4, "apple"}, {6, "cherry"}, {7, "date"}}
// eraseQuick can change the order of remaining items.
map.eraseQuick(4);
items = map.items(); // Returns {{7, "date"}, {6, "cherry"}}
Additional Constructors
Map(std::initializer_list<Item> items)Constructs a map from a braced initializer list. The key-value pairs are inserted in the order they appear in the list.
Accessing Items
const Value* find(const KeyView& key) constLooks up a value by key. Returns a pointer to the value if found, or
nullptrif not present.ArrayView<Item> items()
ArrayView<const Item> items() constReturns a view of all key-value pairs in the map. The pairs are in insertion order unless
eraseQuickwas called.
Modifying Map Contents
void clear()Calls the destructor of all existing items and resets to an empty map.
InsertResult insert(const KeyView& key)Inserts a new key-value pair with the given key if it doesn't already exist. The value is default-constructed. Returns an
InsertResultwith the following members:[TBD]
bool erase(const KeyView& key)Removes the key-value pair with the given key. The remaining pairs are kept in insertion order. If an existing pair was found in the map, its destructor is called and
trueis returned. Otherwise, returnsfalse. This function is slower thaneraseQuick.bool eraseQuick(const KeyView& key)Removes the key-value pair with the given key without keeping the remaining pairs in insertion order. If an existing pair was found in the map, its destructor is called and
trueis returned. Otherwise, returnsfalse.