Read / writes are much faster than `unordered_map`. Its actual size is always a power of 2. The documentation is rather confusing, so I'll just summarize the most useful functions here.
```cpp
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
```
## Unordered Set
`gp_hash_table<K,null_type>` functions similarly to `unordered_set<K>`.
## Hacking
`gp_hash_table` is also vulnerable to hacking.
(example of hash function that fails)
To avoid this, we can use one of the custom hash functions mentioned in the Bronze module.
```cpp
template<class K,class V> using ht = gp_hash_table<K,V,chash>;
```
## Resizing
Unordered map has [`reserve`](http://www.cplusplus.com/reference/unordered_map/unordered_map/reserve/). Calling this function before inserting any elements can result in a constant factor speedup.
We can modify the declaration of `gp_hash_table` so that it supports the `resize` function, which operates similarly.
```cpp
template<class K,class V> using ht = gp_hash_table<
K,
null_type,
hash<K>,
equal_to<K>,
direct_mask_range_hashing<>,
linear_probe_fn<>,
hash_standard_resize_policy<
hash_exponential_size_policy<>,
hash_load_check_resize_trigger<>,
true
>
>;
```
These are the same template arguments as the default `gp_hash_table`, except `false` has been changed to `true`. This modification allows us to change the actual size of the hash table.
```cpp
int main() {
ht<int,null_type> g; g.resize(5);
cout << g.get_actual_size() << "\n"; // 8
cout << g.size() << "\n"; // 0
}
```
When calling `g.resize(x)`, `x` is rounded up to the nearest power of 2. Then the actual size of `g` is changed to be equal to `x` (unless `x < g.size()`, in which case an error is thrown).
Furthermore, if we construct `g` with the following arguments:
```cpp
ht<int,null_type> g({},{},{},{},{1<<16});
```
then the actual size of `g` is always at least `1<<16` (regardless of calls to `resize`). The last argument **must** be a power of 2 (or else errors will be thrown).