Sets¶
template<typename K, typename... Properties>
using Set = Store<set<K>, Properties...>; // written out as Store<set<K>, ...> in code
-
class Set¶
A set:
Store<set<K>, Properties...>. The nameSetstands for the resolved Store type on this page.
A set holds each key once (unique is what a set means). Its order, keys, references, memory, threads and lifecycle are
what the request says; the registry picks the container (What a request resolves to).
Request |
Representation |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Template parameters¶
Member types¶
|
the container chosen |
|
|
|
|
|
|
|
the representation’s; a set’s elements never change in place, so |
|
|
Member functions¶
Construction and assignment¶
-
Set()¶
Empty. Not offered with
nonempty.
-
Set(std::initializer_list<value_type> elements)¶
From any elements, each kept once. With
nonempty, asserts one.
-
Set(layer number, std::initializer_list<value_type> elements)¶
The same, numbered (
urd::layer): a set that hands out positions (positional,insertion_ordered) is built only so, and its views are identified by index and number.
Capacity¶
-
size_type size() const¶
-
bool empty() const¶
-
void reserve(std::size_t count)¶
Hints how many elements will be inserted. Only where the representation can reserve; growable Stores only (not
frozen).
Iterators¶
-
const_iterator begin() const¶
-
const_iterator end() const¶
-
const_iterator cbegin() const¶
-
const_iterator cend() const¶
In the set’s order: ascending with
sorted(and for adensebitset), in insertion order withinsertion_ordered, unspecified otherwise.
-
auto rbegin() const¶
-
auto rend() const¶
With an order (
sortedorinsertion_ordered).
Lookup¶
-
const_iterator find(const key_type &key) const¶
-
size_type count(const key_type &key) const¶
-
bool contains(const key_type &key) const¶
O(1) expected for hashed keys, O(log n) sorted, O(1) dense (a key that is no index finds nothing).
-
const_iterator lower_bound(const key_type &key) const¶
-
const_iterator upper_bound(const key_type &key) const¶
-
std::pair<const_iterator, const_iterator> equal_range(const key_type &key) const¶
sortedonly.
Modifiers¶
Growable Stores (not frozen):
-
std::pair<iterator, bool> insert(const value_type &element)¶
-
std::pair<iterator, bool> insert(value_type &&element)¶
-
iterator insert(const_iterator hint, const value_type &element)¶
-
void insert(std::initializer_list<value_type> elements)¶
-
template<typename ...Args>
std::pair<iterator, bool> emplace(Args&&... args)¶ Inserts the element unless an equal one is held; the iterator to it and whether it was inserted. In an interner (
positional, monotone) the element’s position is its index and never shifts.
Shrinkable Stores (neither frozen nor monotone; monotone_until_clear keeps clear only):
-
iterator erase(const_iterator pos)¶
-
iterator erase(const_iterator first, const_iterator last)¶
-
size_type erase(const key_type &key)¶
-
void clear()¶
Set algebra¶
Words (dense, a bitset)¶
Where the set is a bitset (DenseSet), its words (urd::word_t, urd::word_bits bits each, urd/config.hpp): key k at bit k % word_bits of word k / word_bits.
A pool of such sets as trees of blocks (Pools) takes and gives rows by them.
-
std::span<const urd::word_t> significant_words() const noexcept¶
The words up to the last one with a bit set: equal sets give equal words, however many each keeps.
-
void assign_words(std::span<const urd::word_t> words)¶
Makes this the set whose bits
wordsset, its storage reused: a whole assignment, asoperator=is, so afrozenset takes it too.
Positions (positional, and insertion_ordered)¶
Every insertion-ordered set is kept in one array, so it has positions whether the request names them or not (not with
reclaims).
-
const_reference operator[](std::size_t pos) const¶
-
const_reference at(std::size_t pos) const¶
-
const_reference front() const¶
-
const_reference back() const¶
-
std::size_t position(const_iterator it) const¶
The position of the element at
it;size()forend(), asfindgives for an absent one.
-
const_reference operator[](index_type at) const¶
-
const_reference at(index_type at) const¶
-
index_type index(const_iterator it) const¶
The same, through
index<K>: what an interner mints.atthrowsstd::out_of_rangefornoneor a position past the end.
-
index_view<K, Store> view(index_type at) const¶
A
index_view<K, Store>of the element, through this Store (urd/elements/view.hppincluded).
-
std::size_t layer() const¶
The number it was built with (
urd::layer): a positional set has no constructor without one.
Least and greatest (sorted, not dense)¶
front() and back(), as above, give a sorted set’s least and greatest elements (a map’s entries with the least
and greatest keys), O(1) in a tree or a sorted array; the Store must not be empty. Dense keys find their first by a
scan of the key range, so a dense set reads *begin() where that cost is meant.
Comparison¶
Complexity¶
Representation |
ordered lookup |
access |
iterate |
lookup |
insert |
erase |
clear |
memory |
holds |
|---|---|---|---|---|---|---|---|---|---|
|
— |
— |
O(capacity) |
O(1)~ |
O(1)*~ |
O(1)~ |
O(capacity) |
O(capacity), 1.3 words |
~n/0.875 slots + 1 byte each; retains |
|
— |
— |
O(n) |
O(1)~ |
O(1)*~ |
O(1)~ |
O(n) |
O(n), 4.8 words |
a node per element + buckets; stable references |
|
O(log n) |
— |
O(n) |
O(log n) |
O(log n) |
O(log n) |
O(n) |
O(n), 5 words |
a node per element; reclaims |
|
— |
O(1) |
O(n) |
O(1)~ |
O(1)*~ |
O(n) |
O(capacity) |
O(capacity), 2.5 words |
n elements in order + a table of positions |
|
O(log n) |
O(1) |
O(n) |
O(log n) |
O(n) |
O(n) |
O(n) |
O(n), 1.5 words |
n elements in one array; retains |
|
— |
— |
as its part |
as its part |
as its part |
as its part |
O(n) |
O(n), 4.5 words |
erased nodes kept for reuse |
|
as its part |
— |
as its part |
as its part |
as its part |
as its part |
O(n) |
O(n), 5.5 words |
erased nodes kept for reuse |
|
— |
— |
O(capacity) |
O(1)~ |
O(1)*~ |
O(1)~ |
O(capacity) |
O(capacity), 1.3 words |
16 shards of open addressing, a lock each |
|
— |
— |
O(capacity) |
O(1)~ |
O(1)*~ |
O(1)~ |
O(capacity) |
O(n), 3 words |
16 shards, a node per element; stable references |
|
— |
O(1) |
O(n) |
O(1)~ |
O(1)*~ |
— |
— |
O(capacity), 2.5 words |
segments that never move + a table of positions |
|
— |
O(1) |
O(n) |
O(1)~ |
O(1)*~ |
— |
— |
O(capacity), 4.3 words |
segments that never move + a table of positions; new elements under a lock |
|
O(U) |
— |
O(U) |
O(1) |
O(1)* |
O(1) |
O(U) |
O(U), 0.03 words |
U bits |
|
O(U) |
— |
O(U) |
O(1) |
O(1)* |
O(1) |
O(n) |
O(U), 0.08 words |
U bits + the indices of the words in use |
|
— |
— |
O(n) |
O(1) |
O(1)* |
O(1) |
O(1) |
O(U), 2.7 words |
n members + U positions |
|
— |
O(1) |
O(n) |
O(1) |
O(1)* |
O(n) |
O(1) |
O(U), 2.7 words |
n members in insertion order + U positions |
* amortized, ~ expected; n elements, U the key range, r a row’s length, k a delta’s changes. Memory is the heap it holds (urd::memory_usage): what it grows in, and per element (or key, or slot) at most so many words, each the size of an element and at least a machine word. The declared costs; what they measure to is in Benchmarks.
Example¶
using Seen = Store<set<User>, dense>; // a bitset: User 17 is bit 17
auto seen = Seen { start };
if (seen.insert(next).second) frontier.push(next);
using Names = Store<set<std::string>, positional, monotone>; // an interner
auto names = Names(urd::layer { 0 }); // numbered: its views are (index, 0)
const auto [it, fresh] = names.insert("block");
const urd::index<std::string> block = names.index(it); // 0
names[block]; // "block"