Skip to content

Commit

Permalink
Update README
Browse files Browse the repository at this point in the history
Add constness to various methods in unordered_probe_map
  • Loading branch information
KredeGC committed Dec 2, 2022
1 parent f9aa86c commit f3d8743
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 21 deletions.
47 changes: 34 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
![MacOS untested](https://img.shields.io/badge/MacOS-Untested-red?style=flat-square)

A library containing various composite memory allocators and containers.<br/>
Mostly based on a [CppCon talk by Andrei Alexandrescu](https://www.youtube.com/watch?v=LIb3L4vKZ7U).
Mostly based on a [Talk by Andrei Alexandrescu](https://www.youtube.com/watch?v=LIb3L4vKZ7U).

[![Release](https://img.shields.io/github/v/release/KredeGC/KTL?display_name=tag&style=flat-square)](https://github.com/KredeGC/KTL/releases)
[![License](https://img.shields.io/github/license/KredeGC/KTL?style=flat-square)](https://github.com/KredeGC/KTL/blob/master/LICENSE)
Expand Down Expand Up @@ -52,27 +52,28 @@ Exceptions are not used with any of the allocators above. This means that upon f

## Allocator interface
The allocators roughly follow the standard for STL allocators, except that they are not typed, so use void* instead.
`type_allocator` is the only allocator that uses T* for allocations.
Some additional methods have also been added.

| Method | Description |
| --- | --- |
| void* allocate(size_type size) | Attempts to allocate a chunk of memory defined by `size`. For non-typed allocators the size is in bytes, but for typed allocators it's the amount of objects of the given type. |
| void deallocate(void* ptr, size_type size) | Attempts to deallocate the memory at location `ptr` with the given size, `size`. |
| void construct(T* ptr, Args&& args) | Calls the constructor of a specific type at the location `ptr` with `args`.<br/>Not all allocators define this method. |
| void destroy(T* ptr) | Calls the destructor of a specific type at the location `ptr`.<br/>Not all allocators define this method. |
| size_type max_size() | Returns the maximum size this allocator could possibly allocate.<br/>Not all allocators define this method. |
| bool owns(void* ptr) | Returns whether or not the given memory at location `ptr` is owned by this allocator.<br/>Not all allocators define this method, such as `mallocator`. |
| Alloc get_allocator() | Returns the allocator that this allocator wraps around.<br/>Most composite allocators define this method. |
| `void* allocate(size_type size)` | Attempts to allocate a chunk of memory defined by `size`. For non-typed allocators the size is in bytes, but for typed allocators it's the amount of objects of the given type. |
| `void deallocate(void* ptr, size_type size)` | Attempts to deallocate the memory at location `ptr` with the given size, `size`. |
| `void construct(T* ptr, Args&& args)` | Calls the constructor of a specific type at the location `ptr` with `args`.<br/>Not all allocators define this method. |
| `void destroy(T* ptr)` | Calls the destructor of a specific type at the location `ptr`.<br/>Not all allocators define this method. |
| `size_type max_size()` | Returns the maximum size this allocator could possibly allocate.<br/>Not all allocators define this method. |
| `bool owns(void* ptr)` | Returns whether or not the given memory at location `ptr` is owned by this allocator.<br/>Not all allocators define this method, such as `mallocator`. |
| `Alloc get_allocator()` | Returns the allocator that this allocator wraps around.<br/>Most composite allocators define this method. |

# Containers
This library also contains various containers that are STL compliant.

| Signature | Description | Notes |
| --- | --- | --- |
| binary_heap<br/>\<T, Comp, Alloc\> | A binary heap, sorted using the `Comp` and allocated using the given `Alloc` allocator. | `Comp` can be either `std::greater<T>` or `std::less<T>` or some other custom implementation.<br/>A shorthand version of both a min and a max heap can be used, via the `binary_min_heap<T, Alloc>` and `binary_max_heap<T, Alloc>` types. |
| trivial_array<br/>\<T, Alloc\> | An array wrapper class, similar to `std::array`, but uses dynamic allocation and is optimized for trivial types. Takes a type `T` and an allocator `Alloc`. | The container uses a straight `memcpy` for most of its operations.<br/>It's not recommended to use this with non-trivial types, eg. types that have custom default, copy or move constructors or custom destructors. |
| trivial_vector<br/>\<T, Alloc\> | A vector class, similar to `std::vector`, but optimized for trivial types. Takes a type `T` and an allocator `Alloc`. | The container uses a straight `memcpy` for most of its operations.<br/>It's not recommended to use this with non-trivial types, eg. types that have custom default, copy or move constructors or custom destructors. |
| unordered_probe_map<br/><K, V, Hash, EqualTo, Alloc> | An unordered map class similar to `std::unordered_map`, but optimized for cache locality. | Uses open addressing with linear probing for maximum cache locality.<br/>The container uses a `Hash` struct, `EqualTo` struct and `Alloc` class passed in as template parameters. |
| [binary_heap<br/>\<T, Comp, Alloc\>](#binary_heap-interface) | A binary heap, sorted using the `Comp` and allocated using the given `Alloc` allocator. | `Comp` can be either `std::greater<T>` or `std::less<T>` or some other custom implementation.<br/>A shorthand version of both a min and a max heap can be used, via the `binary_min_heap<T, Alloc>` and `binary_max_heap<T, Alloc>` types. |
| [trivial_array<br/>\<T, Alloc\>](#trivial_array-interface) | An array wrapper class, similar to `std::array`, but uses dynamic allocation and is optimized for trivial types. Takes a type `T` and an allocator `Alloc`. | The container uses a straight `memcpy` for most of its operations.<br/>It's not recommended to use this with non-trivial types, eg. types that have custom default, copy or move constructors or custom destructors.<br/>Just like with the standard array, the container may invalidate iterators and references on insertion, but not on erasure. |
| [trivial_vector<br/>\<T, Alloc\>](#trivial_vector-interface) | A vector class, similar to `std::vector`, but optimized for trivial types. Takes a type `T` and an allocator `Alloc`. | The container uses a straight `memcpy` for most of its operations.<br/>It's not recommended to use this with non-trivial types, eg. types that have custom default, copy or move constructors or custom destructors.<br/>Just like with the standard vector, the container may invalidate iterators and references on insertion, but not on erasure. |
| [unordered_probe_map<br/><K, V, Hash, EqualTo, Alloc>](#unordered_probe_map-interface) | An unordered map class similar to `std::unordered_map`, but optimized for cache locality using open addressing with linear probing. | The container uses a `Hash` struct, `EqualTo` struct and `Alloc` class passed in as template parameters, just like the standard unordered map.<br/>Unlike `std::unordered_map` iterator and reference invalidation may happen on insertion. However, only iterators and references to the erased object are invalidated on erasure. |

## binary_heap interface
| Method | Description |
Expand All @@ -85,22 +86,42 @@ This library also contains various containers that are STL compliant.
## trivial_array interface
| Method | Description |
| --- | --- |
| `T& operator[size_t index]` | Returns a reference to the element at `index`. |
| `void assign(const T* first, const T* last)` | Assigns the given values from `first` to `last`. It also resizes if the size doesn't match. |
| `bool empty()` | Returns true if the array has been initialized with no size. |
| `void resize(size_t size)` | Resizes the array to the given size. |
| `size_t size()` | Returns the current size of the array. |

## trivial_vector interface
| Method | Description |
| --- | --- |
| `T& operator[size_t index]` | Returns a reference to the element at `index`. |
| `size_t capacity()` | Returns the curren capacity of the vector. |
| `void clear()` | Clear all elements in the vector. |
| `void emplace_back(Args&& args)` | Creates a new element and pushes it to the vector. |
| `bool empty()` | Returns whether or not the vector is empty. |
| `void pop_back()` | Removes the last element from the vector. |
| `void push_back(const T& value)` | Pushes a new value by copying it. |
| `void push_back(T&& value)` | Pushes a new value by moving it. |
| `void push_back(const T* first, const T* last)` | Pushes a range of values from `first` to `last`. |
| `void reserve(size_t size)` | Reserves the size of the array to `size`, without initializing any elements. |
| `void resize(size_t size)` | Resizes the vector to the given size. |
| `size_t size()` | Returns the current amount of elements in the vector. |

# Examples
## unordered_probe_map interface
| Method | Description |
| --- | --- |
| `V& operator[const K& index]` | Returns a reference to the element with the given key `index` and inserts one if it doesn't exist. |
| `size_t capacity()` | Returns the curren capacity of the map. Always a power of two. |
| `void clear()` | Clear all elements in the map. |
| `bool empty()` | Returns whether or not the map is empty. |
| `void erase(const K& index)` | Erase an element by its key. |
| `void erase(iterator iter)` | Erase an element by an iterator pointing to it. |
| `iterator insert(K&& index, V&& value)` | Inserts an element into the map with the key `index` and value `value`. Returns an iterator to the element. |
| `iterator find(const K& index)` | Attempts to find the value with the given key `index`. Returns `end()` if not found. |
| `size_t size()` | Returns the current amount of elements in the map. |

# Allocator Examples
Create an allocator which will attempt to use a pre allocator for allocation, but fall back on malloc when full.
```cpp
// Create the allocator from some 16kb buffer and straight malloc
Expand Down
2 changes: 1 addition & 1 deletion include/ktl/containers/trivial_array.h
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ namespace ktl

size_t size() const noexcept { return m_End - m_Begin; }

bool empty() const noexcept { return m_Begin == nullptr; }
bool empty() const noexcept { return m_Begin == m_End; }


T* data() noexcept { return m_Begin; }
Expand Down
16 changes: 9 additions & 7 deletions include/ktl/containers/unordered_probe_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,8 @@ namespace ktl

bool empty() const noexcept { return m_Count == 0; }

float load_factor() const noexcept { return static_cast<float>(m_Count) / static_cast<float>(capacity()); }


template<typename Key, typename Value>
iterator insert(Key&& index, Value&& value) noexcept
Expand Down Expand Up @@ -312,7 +314,7 @@ namespace ktl
iter.m_End = nullptr;
}

iterator find(const K& index)
iterator find(const K& index) const noexcept
{
if (m_Begin == nullptr)
return iterator(nullptr, nullptr);
Expand Down Expand Up @@ -344,7 +346,7 @@ namespace ktl
}

private:
void release()
void release() noexcept
{
if (m_Begin)
{
Expand All @@ -359,7 +361,7 @@ namespace ktl
}
}

void expand()
void expand() noexcept
{
if (m_Count >= capacity() / 2)
{
Expand All @@ -370,7 +372,7 @@ namespace ktl
}
}

void set_size(size_t n)
void set_size(size_t n) noexcept
{
m_Mask = n - 1;

Expand Down Expand Up @@ -402,7 +404,7 @@ namespace ktl
m_End = m_Begin + n;
}

pair* find_empty(const K& index, pair* begin, size_t mask)
pair* find_empty(const K& index, pair* begin, size_t mask) const noexcept
{
size_t h = Hash()(index);

Expand All @@ -421,7 +423,7 @@ namespace ktl
return block;
}

pair* get_pair(const K& index, pair* begin, size_t mask)
pair* get_pair(const K& index, pair* begin, size_t mask) const noexcept
{
size_t h = Hash()(index);

Expand All @@ -441,7 +443,7 @@ namespace ktl
return block;
}

static constexpr size_t hash_collision_offet(size_t key, size_t counter, size_t size)
static constexpr size_t hash_collision_offet(size_t key, size_t counter, size_t size) noexcept
{
// Linear probing for best cache locality
return (key + counter) & size;
Expand Down

0 comments on commit f3d8743

Please sign in to comment.