Skip to content

Latest commit

 

History

History
1215 lines (777 loc) · 28.6 KB

File metadata and controls

1215 lines (777 loc) · 28.6 KB

sfl::static_unordered_set

Table of Contents

Summary

Defined in header sfl/static_unordered_set.hpp:

namespace sfl
{
    template < typename Key,
               std::size_t StaticCapacity,
               std::size_t StaticBucketCount = /* see description below */,
               typename Hash = sfl::hash<Key>,
               typename KeyEqual = std::equal_to<Key> >
    class static_unordered_set;
}

sfl::static_unordered_set is an associative container similar to std::unordered_set, but with a fixed maximum capacity defined at compile time and backed entirely by statically alocated storage. This container does not perform any dynamic memory allocation. The number of elements cannot be greater than StaticCapacity. Attempting to insert more elements results in undefined behavior. This design provides a compact and cache-friendly representation optimized for use cases where the maximum size is known in advance. It is also well-suited for bare-metal embedded development where predictable memory usage and no dynamic allocation are critical.

The underlying storage is implemented as a hash table with separate chaining.

The complexity of search, insert, and erase operations is O(1) on average.

References and pointers to elements are stable: insert and erase operations do not invalidate them unless the referenced element is erased.

Iterators to elements are forward iterators, and they meet the requirements of LegacyForwardIterator.

sfl::static_unordered_set meets the requirements of Container and UnorderedAssociativeContainer.

sfl::static_unordered_set can be used in C++20 constant expressions.

Note: Support for C++20 constant expressions is not fully mature in the major compilers (GCC, Clang, MSVC), so the following limitations apply:

  • On GCC, it is not possible to declare constexpr objects of static_unordered_set. Clang and MSVC allow this, so this is a compiler-specific limitation (possibly a bug).
  • On MSVC, when using in constant expressions:
    • Both the key hash (Hash) and key equality (KeyEqual) functors must be empty types:
      std::is_empty<KeyHash>::value == true
      std::is_empty<KeyEqual>::value == true
    • The default functors (sfl::hash and std::equal_to) are already empty, so this restriction does not apply when using them.
    • This limitation only applies in constant expressions; it does not affect usage in non-constant expressions. This is a compiler bug.



Template Parameters

  1. typename Key
    

    Key type.

  2. std::size_t StaticCapacity
    

    Size of the internal statically allocated array used for elements, i.e. the maximal number of elements that this container can contain.

  3. std::size_t StaticBucketCount
    

    Size of the internal statically allocated array used for buckets.

    Default value of this parameter is StaticCapacity rounded up to the nearest power of two.

  4. typename Hash
    

    Hash function for keys.

  5. typename KeyEqual
    

    Comparison function for keys.



Public Member Types

Member Type Definition
key_type Key
value_type Key
size_type Unsigned integer type
difference_type Signed integer type
hasher Hash
key_equal KeyEqual
reference value_type&
const_reference const value_type&
pointer Pointer to value_type
const_pointer Pointer to const value_type
iterator LegacyForwardIterator to const value_type
const_iterator LegacyForwardIterator to const value_type
local_iterator LegacyForwardIterator to const value_type. This iterator can be used to iterate through a single bucket but not across buckets.
const_local_iterator LegacyForwardIterator to const value_type. This iterator can be used to iterate through a single bucket but not across buckets



Public Data Members

static_capacity

  1. static constexpr size_type static_capacity = StaticCapacity;
    



static_bucket_count

  1. static constexpr size_type static_bucket_count = StaticBucketCount;
    



Public Member Functions

(constructor)

  1. static_unordered_set();
    
  2. static_unordered_set(const Hash& hash);
    
  3. static_unordered_set(const Hash& hash, const KeyEqual& equal);
    

    Effects: Constructs an empty container.

    Complexity: Constant.



  4. template <typename InputIt>
    static_unordered_set(InputIt first, InputIt last);
    
  5. template <typename InputIt>
    static_unordered_set(InputIt first, InputIt last, const Hash& hash);
    
  6. template <typename InputIt>
    static_unordered_set(InputIt first, InputIt last, const Hash& hash, const KeyEqual& equal);
    

    Preconditions: std::distance(first, last) <= capacity()

    Effects: Constructs the container with the contents of the range [first, last).

    If multiple elements in the range have keys that compare equivalent, then the first element is inserted.

    Note: These overloads participate in overload resolution only if InputIt satisfies requirements of LegacyInputIterator.



  7. static_unordered_set(std::initializer_list<value_type> ilist);
    
  8. static_unordered_set(std::initializer_list<value_type> ilist, const Hash& hash);
    
  9. static_unordered_set(std::initializer_list<value_type> ilist, const Hash& hash, const KeyEqual& equal);
    

    Preconditions: ilist.size() <= capacity()

    Effects: Constructs the container with the contents of the initializer list ilist.

    If multiple elements in the range have keys that compare equivalent, then the first element is inserted.



  10. static_unordered_set(const static_unordered_set& other);
    

    Effects: Copy constructor. Constructs the container with the copy of the contents of other.



  11. static_unordered_set(static_unordered_set&& other);
    

    Effects: Move constructor. Constructs the container with the contents of other using move semantics.

    other is not guaranteed to be empty after the move.

    other is in a valid but unspecified state after the move.



  12. template <typename Range>
    static_unordered_set(sfl::from_range_t, Range&& range);
    
  13. template <typename Range>
    static_unordered_set(sfl::from_range_t, Range&& range, const Hash& hash);
    
  14. template <typename Range>
    static_unordered_set(sfl::from_range_t, Range&& range, const Hash& hash, const KeyEqual& equal);
    

    Effects: Constructs the container with the contents of range.

    If multiple elements in the range have keys that compare equivalent, then the first element is inserted.

    Note: These overloads are available in C++11. If compiled with C++20 or later, proper C++20 range concepts are used.



(destructor)

  1. ~static_unordered_set();
    

    Effects: Destructs the container. The destructors of the elements are called and the used storage is deallocated.

    Complexity: Linear in size().



operator=

  1. static_unordered_set& operator=(const static_unordered_set& other);
    

    Effects: Copy assignment operator. Replaces the contents with a copy of the contents of other.

    Returns: *this().



  2. static_unordered_set& operator=(static_unordered_set&& other);
    

    Effects: Move assignment operator. Replaces the contents with those of other using move semantics.

    other is not guaranteed to be empty after the move.

    other is in a valid but unspecified state after the move.

    Returns: *this().



  3. static_unordered_set& operator=(std::initializer_list<value_type> ilist);
    

    Preconditions: ilist.size() <= capacity()

    Effects: Replaces the contents with those identified by initializer list ilist.

    Returns: *this().



hash_function

  1. hasher hash_function() const;
    

    Effects: Returns the function object that hashes the keys.

    Complexity: Constant.



key_eq

  1. key_equal key_eq() const;
    

    Effects: Returns a function object that compares keys for equality.

    Complexity: Constant.



begin, cbegin

  1. iterator begin() noexcept;
    
  2. const_iterator begin() const noexcept;
    
  3. const_iterator cbegin() const noexcept;
    

    Effects: Returns an iterator to the first element of the container. If the container is empty, the returned iterator will be equal to end().

    Complexity: Constant.



end, cend

  1. iterator end() noexcept;
    
  2. const_iterator end() const noexcept;
    
  3. const_iterator cend() const noexcept;
    

    Effects: Returns an iterator to the element following the last element of the container. This element acts as a placeholder; attempting to access it results in undefined behavior.

    Complexity: Constant.



empty

  1. bool empty() const noexcept;
    

    Effects: Returns true if the container has no elements, i.e. whether begin() == end().

    Complexity: Constant.



full

  1. bool full() const noexcept;
    

    Effects: Returns true if the container is full, i.e. whether size() == capacity().

    Complexity: Constant.



size

  1. size_type size() const noexcept;
    

    Effects: Returns the number of elements in the container, i.e. std::distance(begin(), end()).

    Complexity: Constant.



max_size

  1. static constexpr size_type max_size() const noexcept;
    

    Effects: Returns the maximum number of elements the container is able to hold, i.e. StaticCapacity.

    Complexity: Constant.



capacity

  1. static constexpr size_type capacity() const noexcept;
    

    Effects: Returns the maximum number of elements the container is able to hold, i.e. StaticCapacity.

    Complexity: Constant.



available

  1. size_type available() const noexcept;
    

    Effects: Returns the number of elements that can be inserted into the container, i.e. capacity() - size().

    Complexity: Constant.



clear

  1. void clear() noexcept;
    

    Effects: Erases all elements from the container. After this call, size() returns zero.

    Complexity: Linear in size().



emplace

  1. template <typename... Args>
    std::pair<iterator, bool> emplace(Args&&... args);
    

    Preconditions: !full()

    Effects: Inserts new element into the container if the container doesn't already contain an element with an equivalent key.

    New element is constructed as value_type(std::forward<Args>(args)...).

    The element may be constructed even if there already is an element with the key in the container, in which case the newly constructed element will be destroyed immediately.

    Returns: The iterator component points to the inserted element or to the already existing element. The bool component is true if insertion happened and false if it did not.



emplace_hint

  1. template <typename... Args>
    iterator emplace_hint(const_iterator hint, Args&&... args);
    

    Preconditions: !full()

    Effects: Inserts new element into the container if the container doesn't already contain an element with an equivalent key.

    New element is constructed as value_type(std::forward<Args>(args)...).

    The element may be constructed even if there already is an element with the key in the container, in which case the newly constructed element will be destroyed immediately.

    Iterator hint is used as a suggestion where to start to search insert position.

    Returns: Iterator to the inserted element or to the already existing element.



insert

  1. std::pair<iterator, bool> insert(const value_type& value);
    

    Preconditions: !full()

    Effects: Inserts copy of value if the container doesn't already contain an element with an equivalent key.

    Returns: The iterator component points to the inserted element or to the already existing element. The bool component is true if insertion happened and false if it did not.



  2. std::pair<iterator, bool> insert(value_type&& value);
    

    Preconditions: !full()

    Effects: Inserts value using move semantics if the container doesn't already contain an element with an equivalent key.

    Returns: The iterator component points to the inserted element or to the already existing element. The bool component is true if insertion happened and false if it did not.



  3. template <typename K>
    std::pair<iterator, bool> insert(K&& x);
    

    Preconditions: !full()

    Effects: Inserts new element if the container doesn't already contain an element with a key equivalent to x.

    New element is constructed as value_type(std::forward<K>(x)).

    Note: This overload participates in overload resolution only if both Hash::is_transparent and KeyEqual::is_transparent exist and are valid types. This allows the function to be called without constructing an instance of Key.

    Returns: The iterator component points to the inserted element or to the already existing element. The bool component is true if insertion happened and false if it did not.



  4. iterator insert(const_iterator hint, const value_type& value);
    

    Preconditions: !full()

    Effects: Inserts copy of value if the container doesn't already contain an element with an equivalent key.

    Iterator hint is used as a suggestion where to start to search insert position.

    Returns: Iterator to the inserted element or to the already existing element.



  5. iterator insert(const_iterator hint, value_type&& value);
    

    Preconditions: !full()

    Effects: Inserts value using move semantics if the container doesn't already contain an element with an equivalent key.

    Iterator hint is used as a suggestion where to start to search insert position.

    Returns: Iterator to the inserted element or to the already existing element.



  6. template <typename K>
    iterator insert(const_iterator hint, K&& x);
    

    Preconditions: !full()

    Effects: Inserts new element if the container doesn't already contain an element with a key equivalent to x.

    New element is constructed as value_type(std::forward<K>(x)).

    Iterator hint is used as a suggestion where to start to search insert position.

    Note: This overload participates in overload resolution only if all following conditions are satisfied:

    1. Both Hash::is_transparent and KeyEqual::is_transparent exist and are valid types. This allows the function to be called without constructing an instance of Key.
    2. std::is_convertible_v<K&&, iterator> is false.
    3. std::is_convertible_v<K&&, const_iterator> is false.

    Returns: Iterator to the inserted element or to the already existing element.



  7. template <typename InputIt>
    void insert(InputIt first, InputIt last);
    

    Preconditions: std::distance(first, last) <= available()

    Effects: Inserts elements from range [first, last) if the container doesn't already contain an element with an equivalent key.

    If multiple elements in the range have keys that compare equivalent, then the first element is inserted.

    The call to this function is equivalent to:

    while (first != last)
    {
        insert(*first);
        ++first;
    }
    

    Note: This overload participates in overload resolution only if InputIt satisfies requirements of LegacyInputIterator.



  8. void insert(std::initializer_list<value_type> ilist);
    

    Preconditions: ilist.size() <= available()

    Effects: Inserts elements from initializer list ilist if the container doesn't already contain an element with an equivalent key.

    If multiple elements in the range have keys that compare equivalent, then the first element is inserted.

    The call to this function is equivalent to insert(ilist.begin(), ilist.end()).



insert_range

  1. template <typename Range>
    void insert_range(Range&& range);
    

    Effects: Inserts elements from range if the container doesn't already contain an element with an equivalent key.

    If multiple elements in the range have keys that compare equivalent, then the first element is inserted.

    Note: This function is available in C++11. If compiled with C++20 or later, proper C++20 range concepts are used.



erase

  1. iterator erase(iterator pos);
    
  2. iterator erase(const_iterator pos);
    

    Effects: Removes the element at pos.

    Returns: Iterator following the last removed element.



  3. iterator erase(const_iterator first, const_iterator last);
    

    Effects: Removes the elements in the range [first, last).

    Returns: Iterator following the last removed element.



  4. size_type erase(const Key& key);
    
  5. template <typename K>
    size_type erase(K&& x);
    

    Effects: Removes the element (if one exists) with the key equivalent to key or x.

    Note: Overload (5) participates in overload resolution only if both Hash::is_transparent and KeyEqual::is_transparent exist and are valid types. This allows the function to be called without constructing an instance of Key.

    Returns: Number of elements removed (0 or 1).



swap

  1. void swap(static_unordered_set& other);
    

    Effects: Exchanges the contents of the container with those of other.



equal_range

  1. std::pair<iterator, iterator> equal_range(const Key& key);
    
  2. std::pair<const_iterator, const_iterator> equal_range(const Key& key) const;
    
  3. template <typename K>
    std::pair<iterator, iterator> equal_range(const K& x);
    
  4. template <typename K>
    std::pair<const_iterator, const_iterator> equal_range(const K& x) const;
    

    Effects: Returns a range containing all elements with key that compares equivalent to key or x.

    • The first iterator in pair points to the first element of range. It is equal to end() if no such element is found.
    • The second iterator in pair points to the one-past-last element of range. It is equal to end() is no such element is found.

    Note: Overloads (3) and (4) participate in overload resolution only if both Hash::is_transparent and KeyEqual::is_transparent exist and are valid types. This allows these functions to be called without constructing an instance of Key.

    Complexity: Average case linear in number of elements with key that compares equivalent to key or x. Worst case linear in size().



find

  1. iterator find(const Key& key);
    
  2. const_iterator find(const Key& key) const;
    
  3. template <typename K>
    iterator find(const K& x);
    
  4. template <typename K>
    const_iterator find(const K& x) const;
    

    Effects: Returns an iterator pointing to the element with key equivalent to key or x. Returns end() if no such element is found.

    Note: Overloads (3) and (4) participate in overload resolution only if both Hash::is_transparent and KeyEqual::is_transparent exist and are valid types. This allows these functions to be called without constructing an instance of Key.

    Complexity: Constant on average. Worst case linear in size().



count

  1. size_type count(const Key& key) const;
    
  2. template <typename K>
    size_type count(const K& x) const;
    

    Effects: Returns the number of elements with key equivalent to key or x, which is either 1 or 0 since this container does not allow duplicates.

    Note: Overload (2) participates in overload resolution only if both Hash::is_transparent and KeyEqual::is_transparent exist and are valid types. This allows the function to be called without constructing an instance of Key.

    Complexity: Constant on average. Worst case linear in size().



contains

  1. bool contains(const Key& key) const;
    
  2. template <typename K>
    bool contains(const K& x) const;
    

    Effects: Returns true if the container contains an element with key equivalent to key or x, otherwise returns false.

    Note: Overload (2) participates in overload resolution only if both Hash::is_transparent and KeyEqual::is_transparent exist and are valid types. This allows the function to be called without constructing an instance of Key.

    Complexity: Constant on average. Worst case linear in size().



begin, cbegin (bucket interface)

  1. local_iterator begin(size_type n) noexcept;
    
  2. const_local_iterator begin(size_type n) const noexcept;
    
  3. const_local_iterator cbegin(size_type n) const noexcept;
    

    Effects: Returns an iterator to the first element of the bucket with index n.

    Complexity: Constant.



end, cend (bucket interface)

  1. local_iterator end(size_type n) noexcept;
    
  2. const_local_iterator end(size_type n) const noexcept;
    
  3. const_local_iterator cend(size_type n) const noexcept;
    

    Effects: Returns an iterator to the element following the last element of the bucket with index n. This element acts as a placeholder; attempting to access it results in undefined behavior.

    Complexity: Constant.



bucket_count

  1. size_type bucket_count() const;
    

    Effects: Returns the number of buckets in the container, i.e. returns StaticBucketCount.

    Complexity: Constant.



max_bucket_count

  1. size_type max_bucket_count() const;
    

    Effects: Returns the maximum number of buckets the container is able to hold due to system or library implementation limitations, i.e. returns StaticBucketCount.

    Complexity: Constant.



bucket_size

  1. size_type bucket_size(size_type n) const;
    

    Effects: Returns the number of elements in the bucket with index n.

    Complexity: Linear in the size of the bucket n.



bucket

  1. size_type bucket(const Key& key) const;
    
  2. template <typename K>
    size_type bucket(const K& x) const;
    

    Effects: Returns the index of the bucket for key equivalent to key or x.

    Note: Overload (2) participates in overload resolution only if both Hash::is_transparent and KeyEqual::is_transparent exist and are valid types. This allows the function to be called without constructing an instance of Key.

    Complexity: Constant.



load_factor

  1. float load_factor() const;
    

    Effects: Returns the average number of elements per bucket, that is, size() divided by bucket_count().

    Complexity: Constant.



max_load_factor

  1. float max_load_factor() const;
    

    Effects: Returns current maximum load factor, i.e. StaticCapacity divided by StaticBucketCount.

    Complexity: Constant.



Non-member Functions

operator==

  1. template <typename K, std::size_t N, std::size_t M, typename H, typename E>
    bool operator==
    (
        const static_unordered_set<K, N, M, H, E>& x,
        const static_unordered_set<K, N, M, H, E>& y
    );
    

    Effects: Compares the contents of two containers.

    Returns: Returns true if the contents of the x and y are equal, false otherwise.



operator!=

  1. template <typename K, std::size_t N, std::size_t M, typename H, typename E>
    bool operator!=
    (
        const static_unordered_set<K, N, M, H, E>& x,
        const static_unordered_set<K, N, M, H, E>& y
    );
    

    Effects: Compares the contents of two containers.

    Returns: Returns true if the contents of the x and y are not equal, false otherwise.



swap

  1. template <typename K, std::size_t N, std::size_t M, typename H, typename E>
    void swap
    (
        static_unordered_set<K, N, M, H, E>& x,
        static_unordered_set<K, N, M, H, E>& y
    );
    

    Effects: Swaps the contents of x and y. Calls x.swap(y).



erase_if

  1. template <typename K, std::size_t N, std::size_t M, typename H, typename E, typename Predicate>
    typename static_unordered_set<K, N, M, H, E>::size_type
        erase_if(static_unordered_set<K, N, M, H, E>& c, Predicate pred);
    

    Effects: Erases all elements that satisfy the predicate pred from the container.

    pred is unary predicate which returns true if the element should be removed.

    Returns: The number of erased elements.



End of document.