This file contains the hash_set, hash_map, and array_map data structures. It also defines the default_hash function, which provides a default hash algorithm (currently implemented using xxhash).
For hash_set and hash_map, capacity
is the size of the underlying array (i.e. the number of buckets), whereas size
is the number of elements (i.e. number of non-empty buckets). The functions hash_set::check_size and hash_map::check_size compute the load factor size / capacity
and compare it to RESIZE_THRESHOLD. If the load factor is too large, the hashtable is resized and the capacity is increased.
The multiplicative inverse of RESIZE_THRESHOLD.
The multiplicative factor by which hash_set, hash_map, and array_map capacity is changed.
A function pointer type describing a function that returns a pointer to allocated memory. The first argument is the number of elements to allocate, and the second argument is the number of bytes for each element. calloc is an example of a function with this type.
Evaluates the hash function of the given value key
with the given Seed
using the default implementation.
const K * | keys, | |
unsigned int | length | ) |
Evaluates the hash function of the given native array of values keys
with the given Seed
using the default implementation.
An iterator implementation, similar to those in the Standard Template Library, to enable iteration of elements in a hash_set. This iterator is typically initialized using hash_set::begin.
This definition enables the use of range-based for loops.
Public members | |
---|---|
bool | operator != (const hash_set_iterator< T, IsConst > & other) const |
value_type | operator * () |
const hash_set_iterator< T, IsConst > & | operator ++ () |
typedef | std::conditional< IsConst, constT &, T & >::type value_type |
const hash_set_iterator< T, IsConst > & | other | ) const |
Returns whether this iterator is in the same position as other
. This function assumes the two iterators were created from the same hash_set, and that it was not modified.
Advances the position of the iterator to the next element in the hash_set.
The type of the entries returned by this iterator. If this is a const iterator, value_type
is const T&
. Otherwise, value_type
is T&
.
An iterator implementation, similar to those in the Standard Template Library, to enable iteration of elements in a hash_map. This iterator is typically initialized using hash_map::begin.
This definition enables the use of range-based for loops.
Public members | |
---|---|
bool | operator != (const hash_map_iterator< K, V, IsConst > & other) const |
value_type | operator * () |
const hash_map_iterator< K, V, IsConst > & | operator ++ () |
typedef | std::conditional< IsConst, pair< constK &, constV & >, pair< K &, V & > >::type value_type |
const hash_map_iterator< K, V, IsConst > & | other | ) const |
Returns whether this iterator is in the same position as other
. This function assumes the two iterators were created from the same hash_map, and that it was not modified.
Advances the position of the iterator to the next entry in the hash_map.
The type of the entries returned by this iterator. If this is a const iterator, value_type
is core::pair<const K&, constV&>
. Otherwise, value_type
is core::pair<K&, V&>
.
An iterator implementation, similar to those in the Standard Template Library, to enable iteration of elements in an array_map. This iterator is typically initialized using array_map::begin.
This definition enables the use of range-based for loops.
Public members | |
---|---|
bool | operator != (const array_map_iterator< K, V, IsConst > & other) const |
value_type | operator * () |
const array_map_iterator< K, V, IsConst > & | operator ++ () |
typedef | std::conditional< IsConst, pair< constK &, constV & >, pair< K &, V & > >::type value_type |
const array_map_iterator< K, V, IsConst > & | other | ) const |
Returns whether this iterator is in the same position as other
. This function assumes the two iterators were created from the same array_map, and that it was not modified.
Advances the position of the iterator to the next entry in the array_map.
The type of the entries returned by this iterator. If this is a const iterator, value_type
is core::pair<const K&, constV&>
. Otherwise, value_type
is core::pair<K&, V&>
.
Returns true
only if probe > start
and probe <= end
where probe
, start
, and end
are in the additive group of integers modulo the capacity of this set.
T
. The elements are stored in the native array hash_set::keys, which has capacity hash_set::capacity. To compute the index of an element in hash_set::keys, we first compute its hash. To do so:If T
is_pointer, is_fundamental, or is_enum, core::default_hash() provides the hash.
For all other types, the T::hash
function provides the hash. Once the hash is computed, the index into hash_set::keys is computed using hash % hash_set::capacity
(modular division by the capacity).
The above approach could produce the same index for distinct elements. This event is known as a collision. We use linear probing to resolve collisions: When adding an element to the hash_set, we compute its index
using the above procedure, then we inspect hash_set::keys[index]
and use core::is_empty() to determine if another element already occupies that position. If so, we try the next position (index + 1) % hash_set::capacity
. We continue until we find an empty index, and the element is inserted there.
Thus, the function core::is_empty() is used to determine if a position in hash_set::keys is occupied or empty. The total number of occupied positions is given by hash_set::size. WARNING: If hash_set::keys becomes full, the above linear probing mechanism could lead to an infinite loop. The function hash_set::check_size should be used whenever adding new elements to avoid this scenario.
Performance: This data structure provides constant-time access and modification, given that the load factor (size / capacity
) is not too large.
Below is an example of a simple use-case of hash_set, where the expected output is a.contains(2): false, a.contains(3): true, -4 9 3
.
#include <core/map.h> #include <stdio.h> using namespace core; int main() { hash_set<int> a = hash_set<int>(8); a.add(-1); a.add(-4); a.add(3); a.add(9); a.remove(-1); printf("a.contains(2): %s, ", a.contains(2) ? "true" : "false"); printf("a.contains(3): %s, ", a.contains(3) ? "true" : "false"); for (int element : a) printf("%d ", element); }
However, if a
is not allocated on the stack, the destructor will not be automatically called, and so it must be freed manually using core::free
or hash_set::free
. In the example below, the expected output is the same as that of the program above: a.contains(2): false, a.contains(3): true, -4 9 3
.
#include <core/map.h> #include <stdio.h> using namespace core; int main() { hash_set<int>& a = *((hash_set<int>*) alloca(sizeof(hash_set<int>))); hash_set_init(a, 8); a.add(-1); a.add(-4); a.add(3); a.add(9); a.remove(-1); printf("a.contains(2): %s, ", a.contains(2) ? "true" : "false"); printf("a.contains(3): %s, ", a.contains(3) ? "true" : "false"); for (int element : a) printf("%d ", element); free(a); }
A number of member functions require T
to be CopyAssignable. If this is not the case, those operations can be performed directly on the public fields, as in the following example. In addition, when using a custom struct/class with hash_set, it must implement public static functions, like hash
, is_empty
, and move
, as well as the operator ==
. The expected output of the following example is first second
.
#include <core/map.h> #include <stdio.h> #include <string.h> using namespace core; struct custom_string { char* buffer; static unsigned int hash(const custom_string& s) { return default_hash(s.buffer, strlen(s.buffer)); } static bool is_empty(const custom_string& s) { return s.buffer == NULL; } static void move(const custom_string& src, custom_string& dst) { dst.buffer = src.buffer; } static void free(custom_string& s) { core::free(s.buffer); } }; inline bool operator == (const custom_string& first, const custom_string& second) { if (first.buffer == NULL) return second.buffer == NULL; return strcmp(first.buffer, second.buffer) == 0; } bool init(custom_string& s, const char* src) { s.buffer = (char*) malloc(sizeof(char) * (strlen(src) + 1)); if (s.buffer == NULL) return false; memcpy(s.buffer, src, sizeof(char) * (strlen(src) + 1)); return true; } int main() { custom_string first, second; init(first, "first"); init(second, "second"); hash_set<custom_string> a = hash_set<custom_string>(8); a.check_size(a.size + 2); bool contains; unsigned int index; index = a.index_of(first, contains); if (!contains) { core::move(first, a.keys[index]); a.size++; } index = a.index_of(second, contains); if (!contains) { core::move(second, a.keys[index]); a.size++; } for (const custom_string& s : a) printf("%s ", s.buffer); for (custom_string& s : a) free(s); }
T | the generic type of the elements in the set. T must satisfy either:
|
The native array of keys underlying the hashtable.
The capacity of hash_set::keys.
The number of elements in the hashtable (i.e. the number of non-empty buckets).
unsigned int | initial_capacity, | |
alloc_keys_func | alloc_keys | ) |
initial_capacity
.alloc_keys | a memory allocation function with prototype |
const T * | set, | |
unsigned int | length, | |
alloc_keys_func | alloc_keys | ) |
set
with given length
.alloc_keys | a memory allocation function with prototype |
const std::initializer_list< T > & | list, | |
alloc_keys_func | alloc_keys | ) |
list
.alloc_keys | a memory allocation function with prototype |
Forces the underlying hash_set::keys to be resized to the requested capacity
.
WARNING: If new_capacity <= hash_set::size
, the hashtable could become full during the resize process, leading to an infinite loop due to the linear probing collision resolution mechanism.
alloc_keys | a memory allocation function with prototype |
hash_set::size < hash_set::capacity * RESIZE_THRESHOLD
. If not, the capacity of the underlying hash_set::keys is increased by RESIZE_FACTOR until the condition is satisfied. This is useful to ensure the hashtable is sufficiently large when preparing to add new elements.alloc_keys | a memory allocation function with prototype |
true
if the resize was successful, and false
if there is insufficient memory.
new_size
, this function first determines whether new_size < hash_set::capacity * RESIZE_THRESHOLD
. If not, the capacity of the underlying hashtable is increased by RESIZE_FACTOR until the condition is satisfied. This is useful to ensure the hashtable is sufficiently large when preparing to add new elements.alloc_keys | a memory allocation function with prototype |
true
if the resize was successful, and false
if there is insufficient memory.
element
to this set. The assignment operator is used to insert each element, and so this function should not be used if T
is not CopyAssignable. In such a case, insertion should be performed manually using hash_set::index_of to find the appropriate index and directly modifying hash_set::keys and hash_set::size. See the example in the hash_set description.alloc_keys | a memory allocation function with prototype |
T | is CopyAssignable. |
elements
to this set. The assignment operator is used to insert each element, and so this function should not be used if T
is not CopyAssignable. In such a case, insertion should be performed manually using hash_set::index_of or hash_set::index_to_insert to find the appropriate index and directly modifying hash_set::keys and hash_set::size. See the example in the hash_set description.alloc_keys | a memory allocation function with prototype |
T | is CopyAssignable. |
elements
with length count
to this set. The assignment operator is used to insert each element, and so this function should not be used if T
is not CopyAssignable. In such a case, insertion should be performed manually using hash_set::index_of or hash_set::index_to_insert and direct modification of the public fields.alloc_keys | a memory allocation function with prototype |
T | is CopyAssignable. |
element
from the set. This function does not free the removed element.true
if the element is removed, and false
if the set does not contain element
.
This function removes the element at the bucket given by index
. This function assumes that an element is located at the given bucket with the correct provided hash value. This function does not free the removed element.
Returns true
if element
exists in the set, and false
otherwise.
If the given element
exists in this set, this function returns the index of the bucket that contains it. If not, this function returns the index where the key would be located, if it had existed in the set.
If the given element
exists in this set, this function returns the index of the bucket that contains it, and sets contains
to true
. If element
is not in the set, contains
is set to false, and this function returns the index where the key would be located, if it had existed in the set.
If the given element
exists in this set, this function returns the index of the bucket that contains it, and sets contains
to true
. If element
is not in the set, contains
is set to false, and this function returns the index where the key would be located, if it had existed in the set. In any case, the evaluated hash function of element
is stored in hash_value
.
For a given element
, this function computes and returns the index of the bucket where the element would be inserted, for example by a call to hash_set::add. contains
is set to true
if and only if the given element
already exists in the set.
For a given element
, this function computes and returns the index of the bucket where the element would be inserted, for example by a call to hash_set::add, assuming the given element is not in the set.
Removes all elements from this hash_set. Note that this function does not free each element beforehand.
Returns true
if this hash_set is a subset of other
.
Returns a hash_set_iterator pointing to the first element in this container.
NOTE: Unlike the libstdc++ unordered_set and unordered_map iterators, we do not keep a linked list among the elements, so if rapid iteration over elements is more critical than rapid queries, consider using an array_map.
Returns a hash_set_iterator pointing to the end of this container.
NOTE: Unlike the libstdc++ unordered_set and unordered_map iterators, we do not keep a linked list among the elements, so if rapid iteration over elements is more critical than rapid queries, consider using an array_map.
Returns a const hash_set_iterator pointing to the first element in this container.
NOTE: Unlike the libstdc++ unordered_set and unordered_map iterators, we do not keep a linked list among the elements, so if rapid iteration over elements is more critical than rapid queries, consider using an array_map.
Returns a const hash_set_iterator pointing to the end of this container.
NOTE: Unlike the libstdc++ unordered_set and unordered_map iterators, we do not keep a linked list among the elements, so if rapid iteration over elements is more critical than rapid queries, consider using an array_map.
Swaps the contents of the hash_set first
with that of second
.
Moves the contents of the hash_set src
into dst
. Note this function does not copy the contents of the underlying hash_set::keys, it merely copies the pointer.
src
into dst
.alloc_keys | a memory allocation function with prototype |
Frees hash_set::keys. This should not be used if set
was constructed on the stack, as the destructor will automatically free hash_set::data. The elements of set
are not freed.
hash_set< T > & | set, | |
unsigned int | capacity, | |
alloc_keys_func | alloc_keys | ) |
set
with the given initial capacity
.alloc_keys | a memory allocation function with prototype |
Swaps the underlying buffers of the given hash_sets first
and second
.
An unordered associative container that contains a set of key-value pairs, where the keys are unique and have type K
and the values have type V
. The keys are stored in a hash_set structure, and the values are stored in hash_map::values, which is a native array parallel to the key array in hash_set::keys. To compute the index of a key-value pair, we compute the index of the key using the algorithm described in hash_set. The value has the same index in hash_map::values. This structure uses the same linear probing approach to resolve collisions (i.e. when two distinct keys are computed to have the same index).
WARNING: As with hash_set, if the map becomes full, the linear probing mechanism could lead to an infinite loop in many hash_map operations. The function hash_map::check_size should be used whenever adding new elements to avoid this scenario.
Performance: This data structure provides constant-time access and modification, given that the load factor (size / capacity
) is not too large.
Below is a simple example using a hash_map, where the expected output is a.get(3): c, a.get(4): d, 1:a 4:d 3:c
.
#include <core/map.h> #include <stdio.h> using namespace core; int main() { hash_map<int, char> a = hash_map<int, char>(8); a.put(1, 'a'); a.put(2, 'b'); a.put(3, 'c'); a.put(4, 'd'); a.remove(2); printf("a.get(3): %c, ", a.get(3)); printf("a.get(4): %c, ", a.get(4)); for (const auto& entry : a) printf("%d:%c ", entry.key, entry.value); }
However, if a
is not allocated on the stack, the destructor will not be automatically called, and so it must be freed manually using core::free
or hash_map::free
. In the example below, the expected output is the same as that of the program above: a.get(3): c, a.get(4): d, 1:a 4:d 3:c
.
#include <core/map.h> #include <stdio.h> using namespace core; int main() { hash_map<int, char>& a = *((hash_map<int, char>*) malloc(sizeof(hash_map<int, char>))); hash_map_init(a, 8); a.put(1, 'a'); a.put(2, 'b'); a.put(3, 'c'); a.put(4, 'd'); a.remove(2); printf("a.get(3): %c, ", a.get(3)); printf("a.get(4): %c, ", a.get(4)); for (const auto& entry : a) printf("%d:%c ", entry.key, entry.value); free(a); }
A number of member functions require K
and V
to be CopyAssignable. If this is not the case, those operations can be performed directly on the public fields, as in the following example. In addition, when using a custom struct/class as the key type in hash_map, it must implement public static functions, like hash
, is_empty
, and move
, as well as the operator ==
. The expected output of the following example is first:1 second:2
.
#include <core/map.h> #include <stdio.h> #include <string.h> using namespace core; struct custom_string { char* buffer; static unsigned int hash(const custom_string& s) { return default_hash(s.buffer, strlen(s.buffer)); } static bool is_empty(const custom_string& s) { return s.buffer == NULL; } static void move(const custom_string& src, custom_string& dst) { dst.buffer = src.buffer; } static void free(custom_string& s) { core::free(s.buffer); } }; inline bool operator == (const custom_string& first, const custom_string& second) { if (first.buffer == NULL) return second.buffer == NULL; return strcmp(first.buffer, second.buffer) == 0; } bool init(custom_string& s, const char* src) { s.buffer = (char*) malloc(sizeof(char) * (strlen(src) + 1)); if (s.buffer == NULL) return false; memcpy(s.buffer, src, sizeof(char) * (strlen(src) + 1)); return true; } int main() { custom_string key_one, key_two; int value_one = 1, value_two = 2; init(key_one, "first"); init(key_two, "second"); hash_map<custom_string, int> a = hash_map<custom_string, int>(8); a.check_size(a.table.size + 2); bool contains; unsigned int index; a.get(key_one, contains, index); if (!contains) { core::move(key_one, a.table.keys[index]); a.values[index] = value_one; a.table.size++; } a.get(key_two, contains, index); if (!contains) { core::move(key_two, a.table.keys[index]); a.values[index] = value_two; a.table.size++; } for (const auto& entry : a) printf("%s:%d ", entry.key.buffer, entry.value); for (auto entry : a) free(entry.key); }
K | the generic type of the keys in the map. K must satisfy either:
|
V | the generic type of the values in the map. |
Public members | |
---|---|
hash_set< K > | table |
V * | values |
hash_map (unsigned int capacity, alloc_keys_func alloc_keys) | |
hash_map (const K * map, unsigned int length, alloc_keys_func alloc_keys) | |
hash_map (const K * keys, const V * values, unsigned int length, alloc_keys_func alloc_keys) | |
hash_map (const std::initializer_list< pair< K, V > > & list, alloc_keys_func alloc_keys) | |
bool | resize (unsigned int new_capacity, alloc_keys_func alloc_keys) |
bool | check_size (alloc_keys_func alloc_keys) |
bool | check_size (unsigned int new_size, alloc_keys_func alloc_keys) |
bool | put (const K & key, const V & value, alloc_keys_func alloc_keys) |
bool | put_all (const hash_map< K, V > & elements, alloc_keys_func alloc_keys) |
bool | remove (const K & key) |
void | remove_at (unsigned int index) |
V & | get (const K & key) const |
V & | get (const K & key, bool & contains) const |
V & | get (const K & key, bool & contains, unsigned int & index) const |
V & | get (const K & key, bool & contains, unsigned int & index, unsigned int & hash_value) const |
void | clear () |
hash_map_iterator< K, V, false > | begin () |
hash_map_iterator< K, V, false > | end () |
hash_map_iterator< K, V, true > | begin () const |
hash_map_iterator< K, V, true > | end () const |
static void | swap (hash_map< K, V > & first, hash_map< K, V > & second) |
static void | move (const hash_map< K, V > & src, hash_map< K, V > & dst) |
static bool | copy (const hash_map< K, V > & src, hash_map< K, V > & dst, alloc_keys_func alloc_keys) |
static void | free (hash_map< K, V > & map) |
typedef | K key_type |
typedef | V value_type |
The underlying hashtable containing the keys.
An array parallel to hash_set::keys in hash_map::table, containing a value at every non-empty bucket index.
unsigned int | capacity, | |
alloc_keys_func | alloc_keys | ) |
capacity
.alloc_keys | a memory allocation function with prototype |
const K * | map, | |
unsigned int | length, | |
alloc_keys_func | alloc_keys | ) |
map
, where each element in map
is interpreted as a key, and its corresponding value is the index of the element.alloc_keys | a memory allocation function with prototype |
V | satisfies is_integral. |
keys
and values
.alloc_keys | a memory allocation function with prototype |
const std::initializer_list< pair< K, V > > & | list, | |
alloc_keys_func | alloc_keys | ) |
alloc_keys | a memory allocation function with prototype |
Forces the underlying hash_map::table.keys and hash_map::values to be resized to the requested capacity
.
WARNING: If new_capacity <= hash_map::table.size
, the hashtable could become full during the resize process, leading to an infinite loop due to the linear probing collision resolution mechanism.
alloc_keys | a memory allocation function with prototype |
hash_map::table.size < hash_map::table.capacity * RESIZE_THRESHOLD
. If not, the capacities of the underlying hash_map::table and hash_map::values is increased by RESIZE_FACTOR until the condition is satisfied. This is useful to ensure the hashtable is sufficiently large when preparing to add new elements.alloc_keys | a memory allocation function with prototype |
true
if the resize was successful, and false
if there is insufficient memory.
new_size
, this function first determines whether new_size < hash_map::table.capacity * RESIZE_THRESHOLD
. If not, the capacities of the underlying hash_map::table and hash_map::values is increased by RESIZE_FACTOR until the condition is satisfied. This is useful to ensure the hashtable is sufficiently large when preparing to add new elements.alloc_keys | a memory allocation function with prototype |
true
if the resize was successful, and false
if there is insufficient memory.
K
and V
are not CopyAssignable. In such a case, insertion should be performed manually by using hash_map::get or hash_set::index_to_insert to find the appropriate index and directly modifying hash_map::table.keys, hash_map::table.size, and hash_map::values. See the example in the hash_map description.alloc_keys | a memory allocation function with prototype |
K | is CopyAssignable. |
V | is CopyAssignable. |
elements
to this map. The assignment operator is used insert each entry, and so this function should not be used if K
and V
are not CopyAssignable. In such a case, insertion should be performed manually by using hash_map::get or hash_map::index_to_insert to find the appropriate index and directly modifying hash_map::table.keys, hash_map::table.size, and hash_map::values. See the example in the hash_map description.alloc_keys | a memory allocation function with prototype |
K | is CopyAssignable. |
V | is CopyAssignable. |
key
and associated value from the map. This function does not free the removed element.true
if the element is removed, and false
if the set does not contain element
.
This function removes the entry at the bucket given by index
. This function assumes that an entry is located at the given bucket with the correct provided hash value. This function does not free the removed key or value.
Retrieves the value associated with the given key
. This function assumes the given key exists in the map.
If the given key
exists in this map, this function returns the value associated with the key, and sets contains
to true
. If key
is not in the map, contains
is set to false
.
If the given key
exists in this map, this function returns the value associated with the key, sets contains
to true
, and sets index
to the bucket containing the key. If key
is not in the map, contains
is set to false
, and index
is set to the index where the key would be located, if it had existed in the map.
If the given key
exists in this map, this function returns the value associated with the key, sets contains
to true
, and sets index
to the bucket containing the key. If key
is not in the map, contains
is set to false
, and index
is set to the index where the key would be located, if it had existed in the map. In any case, the evaluated hash function of key
is stored in hash_value
.
Removes all entries from this hash_map. Note that this function does not free each entry beforehand.
Returns a hash_map_iterator pointing to the first entry in this container.
NOTE: Unlike the libstdc++ unordered_set and unordered_map iterators, we do not keep a linked list among the elements, so if rapid iteration over elements is more critical than rapid queries, consider using an array_map.
Returns a hash_map_iterator pointing to the end of this container.
NOTE: Unlike the libstdc++ unordered_set and unordered_map iterators, we do not keep a linked list among the elements, so if rapid iteration over elements is more critical than rapid queries, consider using an array_map.
Returns a const hash_map_iterator pointing to the first entry in this container.
NOTE: Unlike the libstdc++ unordered_set and unordered_map iterators, we do not keep a linked list among the elements, so if rapid iteration over elements is more critical than rapid queries, consider using an array_map.
Returns a const hash_map_iterator pointing to the end of this container.
NOTE: Unlike the libstdc++ unordered_set and unordered_map iterators, we do not keep a linked list among the elements, so if rapid iteration over elements is more critical than rapid queries, consider using an array_map.
Swaps the contents of the hash_map first
with that of second
.
Moves the contents of the hash_map src
into dst
. Note this function does not copy the contents of the underlying hash_map::table or hash_map::values, it merely copies the pointers.
const hash_map< K, V > & | src, | |
hash_map< K, V > & | dst, | |
alloc_keys_func | alloc_keys | ) |
src
into dst
.alloc_keys | a memory allocation function with prototype |
Frees hash_map::table and hash_map::values. This should not be used if map
was constructed on the stack, as the destructor will automatically free hash_map::table and hash_map::values. The existing entries of map
are not freed.
The type of the values in this hash_map.
hash_map< K, V > & | map, | |
unsigned int | capacity, | |
alloc_keys_func | alloc_keys | ) |
map
with the given initial capacity
.alloc_keys | a memory allocation function with prototype |
Swaps the underlying buffers of the given hash_maps first
and second
.
A sequentially-ordered associative container that contains a set of key-value pairs, where the keys are unique and have type K
and the values have type V
. The keys are stored sequentially in a native array array_map::keys, and the values are stored sequentially in a parallel native array array_map::values.
When inserting a key-value pair into an array_map, a linear search is performed to determine if the key already exists in the map. If so, its corresponding value is replaced by the new value. If not, the new key and value are inserted at the ends of their respective arrays, and array_map::size is incremented.
Performance: This data structure provides linear-time access and modification. However, due to locality of reference, this data structure may perform operations more quickly than hash_map if the size of the map is small.
A simple example of the use of array_map is given below, where the expected output is a.get(3): c, a.get(4): d, 1:a 4:d 3:c
.
#include <core/map.h> #include <stdio.h> using namespace core; int main() { array_map<int, char> a = array_map<int, char>(8); a.put(1, 'a'); a.put(2, 'b'); a.put(3, 'c'); a.put(4, 'd'); a.remove(2); printf("a.get(3): %c, ", a.get(3)); printf("a.get(4): %c, ", a.get(4)); for (const auto& entry : a) printf("%d:%c ", entry.key, entry.value); }
However, if a
is not allocated on the stack, the destructor will not be automatically called, and so it must be freed using core::free
or hash_map::free
. In the example below, the expected output is the same as that of the program above: a.get(3): c, a.get(4): d, 1:a 4:d 3:c
.
#include <core/map.h> #include <stdio.h> using namespace core; int main() { array_map<int, char>& a = *((array_map<int, char>*) alloca(sizeof(array_map<int, char>))); array_map_init(a, 8); a.put(1, 'a'); a.put(2, 'b'); a.put(3, 'c'); a.put(4, 'd'); a.remove(2); printf("a.get(3): %c, ", a.get(3)); printf("a.get(4): %c, ", a.get(4)); for (const auto& entry : a) printf("%d:%c ", entry.key, entry.value); free(a); }
A number of member functions require K
and V
to be CopyAssignable. If this is not the case, those operations can be performed directly on the public fields, as in the following example. The expected output is first:1 second:2
.
#include <core/map.h> #include <stdio.h> #include <string.h> using namespace core; struct custom_string { char* buffer; static void move(const custom_string& src, custom_string& dst) { dst.buffer = src.buffer; } static void free(custom_string& s) { core::free(s.buffer); } }; inline bool operator == (const custom_string& first, const custom_string& second) { if (first.buffer == NULL) return second.buffer == NULL; return strcmp(first.buffer, second.buffer) == 0; } bool init(custom_string& s, const char* src) { s.buffer = (char*) malloc(sizeof(char) * (strlen(src) + 1)); if (s.buffer == NULL) return false; memcpy(s.buffer, src, sizeof(char) * (strlen(src) + 1)); return true; } int main() { custom_string key_one, key_two; int value_one = 1, value_two = 2; init(key_one, "first"); init(key_two, "second"); array_map<custom_string, int> a = array_map<custom_string, int>(8); a.ensure_capacity(2); unsigned int index; a.get(key_one, index); if (index == a.size) { core::move(key_one, a.keys[index]); a.values[index] = value_one; a.size++; } a.get(key_two, index); if (index == a.size) { core::move(key_two, a.keys[index]); a.values[index] = value_two; a.size++; } for (const auto& entry : a) printf("%s:%d ", entry.key.buffer, entry.value); for (auto entry : a) free(entry.key); }
The native array of keys.
The native array of values parallel to array_map::keys.
The capacity of array_map::keys and array_map::values.
size_t | initial_capacity | ) |
Constructs the hash_map with the given initial_capacity
.
new_length
, this function determines whether array_map::capacity is sufficient. If not, it attempts to increase its capacity by factors of RESIZE_FACTOR.true
if the resize was successful, and false
if there is insufficient memory.
K
and V
are not CopyAssignable. In such a case, insertion should be performed manually by using array_map::get to compute the appropriate index and directly modifying the the public fields. See the example in the description of array_map.K | is CopyAssignable. |
V | is CopyAssignable. |
Performs a linear search to find the index of the given key
. If the key
is not in this map, array_map::size is returned.
Performs a linear search to find the index of the given key
, with the search beginning at the index start
. If the key
is not in this map, array_map::size is returned.
Performs a reverse linear search to find the index of the given key
. If the key
is not in this map, static_cast<unsigned int>(-1)
is returned.
Returns true
if the given key
exists in the map, and false
otherwise.
Retrieves the value associated with the given key
. This function assumes the given key exists in the map.
Retrieves the const value associated with the given key
. This function assumes the given key exists in the map.
If the given key
exists in the map, this function returns the value associated with the key, and sets index
to the index of array_map::keys where the key is located. If key
does not exist in the map, index
is set to array_map::size.
If the given key
exists in the map, this function returns the value associated with the key, and sets contains
to true
. If key
does not exist in the map, contains
is set to false
.
If the given key
exists in the map, this function returns the const value associated with the key, and sets contains
to true
. If key
does not exist in the map, contains
is set to false
.
key
and associated value from the map. This function does not free the removed element.true
if the element is removed, and false
if the set does not contain element
.
index
in the map. This function does not free the removed element. This function assumes 0 <= index < array_map::size
.K | satisfies is_moveable. |
V | satisfies is_moveable. |
Removes all entries from this array_map. Note that this function does not free each entry beforehand.
Returns an array_map_iterator pointing to the first entry in this container.
Returns an array_map_iterator pointing to the end of this container.
Returns a const array_map_iterator pointing to the first entry in this container.
Returns a const array_map_iterator pointing to the end of this container.
Swaps the contents of the array_map first
with that of second
.
Moves the contents of the array_map src
into dst
. Note this function does not copy the contents of the underlying array_map::keys or array_map::values, it merely copies the pointers.
Frees array_map::keys and array_map::values. This should not be used if map
was constructed on the stack, as the destructor will automatically free array_map::keys and array_map::values. The existing entries of map
are not freed.
The type of the values in this array_map.
Initializes the array_map map
with the given initial_capacity
.
Returns the number of elements in the given hash_set set
.
Returns the number of elements in the given hash_map map
.
Returns the number of elements in the given array_map map
.
map
has value type that satisfies is_integral, and the values in the map are unique and no larger than size(map)
, this function returns an array of pointers to the keys in map
, where the pointer at index i
references the key in map
that corresponds to the value i
. The caller of this function is responsible for the memory of the returned native array, and must call free to release it.MapType | a map type that allows range-based for iteration, and for which the function |