This section describes all the containers provided by the library. Check the Design section for a general discussion of these containers and how to use them.
immer::
box
¶Immutable box for a single value of type T
.
The box is always copiable and movable. The T
copy or move operations are never called. Since a box is immutable, copying or moving just copy the underlying pointers.
Public Functions
impl
() const¶box
()¶Constructs a box holding T{}
.
box
(Arg &&arg)¶Constructs a box holding T{arg}
box
(Arg1 &&arg1, Arg2 &&arg2, Args&&... args)¶Constructs a box holding T{arg1, arg2, args...}
~box
()¶get
() const¶Query the current value.
operator const T&
() const¶Conversion to the boxed type.
operator*
() const¶Access via dereference
operator->
() const¶Access via pointer member access
update
(Fn &&fn) const¶Returns a new box built by applying the fn
to the underlying value.
auto v1 = immer::box<std::string>{"hello"};
auto v2 = v1.update([&](auto l) { return l + ", world!"; });
assert((v1 == immer::box<std::string>{"hello"}));
assert((v2 == immer::box<std::string>{"hello, world!"}));
Friends
immer::box::detail::gc_atom_impl< T, MemoryPolicy >
immer::box::detail::refcount_atom_impl< T, MemoryPolicy >
swap
(box &a, box &b)¶immer::
array
¶Immutable container that stores a sequence of elements in contiguous memory.
It supports the most efficient iteration and random access,
equivalent to a std::vector
or std::array
, but all
manipulations are \(O(size)\).
Tip
Don’t be fooled by the bad complexity of this data
structure. It is a great choice for short sequence or when it
is seldom or never changed. This depends on the sizeof(T)
and the expensiveness of its T
’s copy constructor. In case
of doubt, measure. For basic types, using an array when
\(n < 100\) is a good heuristic.
T
: The type of the values to be stored in the container.Public Types
value_type
= T¶reference
= const T&¶size_type
= std::size_t¶difference_type
= std::ptrdiff_t¶const_reference
= const T&¶iterator
= const T *¶memory_policy
= MemoryPolicy¶transient_type
= array_transient<T, MemoryPolicy>¶Public Functions
array
()¶Default constructor. It creates an array of size() == 0
. It does not allocate memory and its complexity is \( O(1) \).
array
(std::initializer_list<T> values)¶Constructs an array containing the elements in values
.
array
(Iter first, Sent last)¶Constructs a array containing the elements in the range defined by the forward iterator first
and range sentinel last
.
array
(size_type n, T v = {})¶Constructs an array containing the element val
repeated n
times.
begin
() const¶Returns an iterator pointing at the first element of the collection. It does not allocate memory and its complexity is \( O(1) \).
end
() const¶Returns an iterator pointing just after the last element of the collection. It does not allocate memory and its complexity is \( O(1) \).
rbegin
() const¶Returns an iterator that traverses the collection backwards, pointing at the first element of the reversed collection. It does not allocate memory and its complexity is \( O(1) \).
rend
() const¶Returns an iterator that traverses the collection backwards, pointing after the last element of the reversed collection. It does not allocate memory and its complexity is \( O(1) \).
size
() const¶Returns the number of elements in the container. It does not allocate memory and its complexity is \( O(1) \).
empty
() const¶Returns true
if there are no elements in the container. It does not allocate memory and its complexity is \( O(1) \).
data
() const¶Access the raw data.
back
() const¶Access the last element.
front
() const¶Access the first element.
operator[]
(size_type index) const¶Returns a const
reference to the element at position index
. It is undefined when \( index \geq size() \). It does not allocate memory and its complexity is effectively \( O(1) \).
at
(size_type index) const¶Returns a const
reference to the element at position index
. It throws an std::out_of_range
exception when \( index \geq size() \). It does not allocate memory and its complexity is effectively \( O(1) \).
push_back
(value_type value) const¶Returns an array with value
inserted at the end. It may allocate memory and its complexity is \( O(size) \).
auto v1 = immer::array<int>{1};
auto v2 = v1.push_back(8);
assert((v1 == immer::array<int>{1}));
assert((v2 == immer::array<int>{1, 8}));
decltype(auto) immer::array::push_back(value_type value)
set
(std::size_t index, value_type value) const¶Returns an array containing value value
at position idx
. Undefined for index >= size()
. It may allocate memory and its complexity is \( O(size) \).
auto v1 = immer::array<int>{1, 2, 3};
auto v2 = v1.set(0, 5);
assert((v1 == immer::array<int>{1, 2, 3}));
assert((v2 == immer::array<int>{5, 2, 3}));
decltype(auto) immer::array::set(size_type index, value_type value)
update
(std::size_t index, FnT &&fn) const¶Returns an array containing the result of the expression fn((*this)[idx])
at position idx
. Undefined for index >= size()
. It may allocate memory and its complexity is \( O(size) \).
auto v1 = immer::array<int>{1, 2, 3, 4};
auto v2 = v1.update(2, [&](auto l) { return ++l; });
assert((v1 == immer::array<int>{1, 2, 3, 4}));
assert((v2 == immer::array<int>{1, 2, 4, 4}));
decltype(auto) immer::array::update(size_type index, FnT && fn)
take
(size_type elems) const¶Returns a array containing only the first min(elems, size())
elements. It may allocate memory and its complexity is effectively \( O(1) \).
auto v1 = immer::array<int>{1, 2, 3, 4, 5, 6};
auto v2 = v1.take(3);
assert((v1 == immer::array<int>{1, 2, 3, 4, 5, 6}));
assert((v2 == immer::array<int>{1, 2, 3}));
decltype(auto) immer::array::take(size_type elems)
transient
() const¶Returns an transient form of this container, an immer::array_transient
.
transient
()¶identity
() const¶Returns a value that can be used as identity for the container. If two values have the same identity, they are guaranteed to be equal and to contain the same objects. However, two equal containers are not guaranteed to have the same identity.
impl
() const¶immer::
vector
¶Immutable sequential container supporting both random access and structural sharing.
This container provides a good trade-off between cache locality,
random access, update performance and structural sharing. It does
so by storing the data in contiguous chunks of \(2^{BL}\)
elements. By default, when sizeof(T) == sizeof(void*)
then
\(B=BL=5\), such that data would be stored in contiguous
chunks of \(32\) elements.
You may learn more about the meaning and implications of B
and
BL
parameters in the Implementation overview section.
Note
In several methods we say that their complexity is effectively \(O(...)\). Do not confuse this with the word amortized, which has a very different meaning. In this context, effective means that while the mathematically rigurous complexity might be higher, for all practical matters the provided complexity is more useful to think about the actual cost of the operation.
#include <immer/vector.hpp>
int main()
{
const auto v0 = immer::vector<int>{};
const auto v1 = v0.push_back(13);
assert((v0 == immer::vector<int>{}));
assert((v1 == immer::vector<int>{13}));
const auto v2 = v1.set(0, 42);
assert(v1[0] == 13);
assert(v2[0] == 42);
}
T
: The type of the values to be stored in the container. MemoryPolicy
: Memory management policy. See memory_policy.Public Types
memory_policy
= MemoryPolicy¶value_type
= T¶reference
= const T&¶size_type
= detail::rbts::size_t¶difference_type
= std::ptrdiff_t¶const_reference
= const T&¶iterator
= detail::rbts::rbtree_iterator<T, MemoryPolicy, B, BL>¶transient_type
= vector_transient<T, MemoryPolicy, B, BL>¶Public Functions
vector
()¶Default constructor. It creates a vector of size() == 0
. It does not allocate memory and its complexity is \( O(1) \).
vector
(std::initializer_list<T> values)¶Constructs a vector containing the elements in values
.
vector
(Iter first, Sent last)¶Constructs a vector containing the elements in the range defined by the input iterator first
and range sentinel last
.
vector
(size_type n, T v = {})¶Constructs a vector containing the element val
repeated n
times.
begin
() const¶Returns an iterator pointing at the first element of the collection. It does not allocate memory and its complexity is \( O(1) \).
end
() const¶Returns an iterator pointing just after the last element of the collection. It does not allocate and its complexity is \( O(1) \).
rbegin
() const¶Returns an iterator that traverses the collection backwards, pointing at the first element of the reversed collection. It does not allocate memory and its complexity is \( O(1) \).
rend
() const¶Returns an iterator that traverses the collection backwards, pointing after the last element of the reversed collection. It does not allocate memory and its complexity is \( O(1) \).
size
() const¶Returns the number of elements in the container. It does not allocate memory and its complexity is \( O(1) \).
empty
() const¶Returns true
if there are no elements in the container. It does not allocate memory and its complexity is \( O(1) \).
back
() const¶Access the last element.
front
() const¶Access the first element.
operator[]
(size_type index) const¶Returns a const
reference to the element at position index
. It is undefined when \( 0 index \geq size() \). It does not allocate memory and its complexity is effectively \( O(1) \).
at
(size_type index) const¶Returns a const
reference to the element at position index
. It throws an std::out_of_range
exception when \( index \geq size() \). It does not allocate memory and its complexity is effectively \( O(1) \).
push_back
(value_type value) const¶Returns a vector with value
inserted at the end. It may allocate memory and its complexity is effectively \( O(1) \).
auto v1 = immer::vector<int>{1};
auto v2 = v1.push_back(8);
assert((v1 == immer::vector<int>{1}));
assert((v2 == immer::vector<int>{1, 8}));
decltype(auto) immer::vector::push_back(value_type value)
set
(size_type index, value_type value) const¶Returns a vector containing value value
at position idx
. Undefined for index >= size()
. It may allocate memory and its complexity is effectively \( O(1) \).
auto v1 = immer::vector<int>{1, 2, 3};
auto v2 = v1.set(0, 5);
assert((v1 == immer::vector<int>{1, 2, 3}));
assert((v2 == immer::vector<int>{5, 2, 3}));
decltype(auto) immer::vector::set(size_type index, value_type value)
update
(size_type index, FnT &&fn) const¶Returns a vector containing the result of the expression fn((*this)[idx])
at position idx
. Undefined for 0 >= size()
. It may allocate memory and its complexity is effectively \( O(1) \).
auto v1 = immer::vector<int>{1, 2, 3, 4};
auto v2 = v1.update(2, [&](auto l) { return ++l; });
assert((v1 == immer::vector<int>{1, 2, 3, 4}));
assert((v2 == immer::vector<int>{1, 2, 4, 4}));
decltype(auto) immer::vector::update(size_type index, FnT && fn)
take
(size_type elems) const¶Returns a vector containing only the first min(elems, size())
elements. It may allocate memory and its complexity is effectively \( O(1) \).
auto v1 = immer::vector<int>{1, 2, 3, 4, 5, 6};
auto v2 = v1.take(3);
assert((v1 == immer::vector<int>{1, 2, 3, 4, 5, 6}));
assert((v2 == immer::vector<int>{1, 2, 3}));
decltype(auto) immer::vector::take(size_type elems)
transient
() const¶Returns an transient form of this container, an immer::vector_transient
.
transient
()¶identity
() const¶Returns a value that can be used as identity for the container. If two values have the same identity, they are guaranteed to be equal and to contain the same objects. However, two equal containers are not guaranteed to have the same identity.
impl
() const¶vector
(impl_t impl)¶Public Static Functions
max_size
()¶Returns the maximum theoretical size supported by the internal structure given the current B, BL.
immer::
flex_vector
¶Immutable sequential container supporting both random access, structural sharing and efficient concatenation and slicing.
This container is very similar to vector but also supports \(O(log(size))\) concatenation, slicing and insertion at any point. Its performance characteristics are almost identical until one of these operations is performed. After that, performance is degraded by a constant factor that usually oscilates in the range \([1, 2)\) depending on the operation and the amount of flexible operations that have been performed.
Tip
A vector can be converted to a flex_vector in constant time without any allocation. This is so because the internal structure of a vector is a strict subset of the internal structure of a flexible vector. You can take advantage of this property by creating normal vectors as long as the flexible operations are not needed, and convert later in your processing pipeline once and if these are needed.
T
: The type of the values to be stored in the container. MemoryPolicy
: Memory management policy. See memory_policy.Public Types
memory_policy
= MemoryPolicy¶value_type
= T¶reference
= const T&¶size_type
= detail::rbts::size_t¶difference_type
= std::ptrdiff_t¶const_reference
= const T&¶iterator
= detail::rbts::rrbtree_iterator<T, MemoryPolicy, B, BL>¶transient_type
= flex_vector_transient<T, MemoryPolicy, B, BL>¶Public Functions
flex_vector
()¶Default constructor. It creates a flex_vector of size() == 0
. It does not allocate memory and its complexity is \( O(1) \).
flex_vector
(std::initializer_list<T> values)¶Constructs a flex_vector containing the elements in values
.
flex_vector
(Iter first, Sent last)¶Constructs a flex_vector containing the elements in the range defined by the input iterator first
and range sentinel last
.
flex_vector
(size_type n, T v = {})¶Constructs a vector containing the element val
repeated n
times.
flex_vector
(vector<T, MemoryPolicy, B, BL> v)¶Default constructor. It creates a flex_vector with the same contents as v
. It does not allocate memory and is \( O(1) \).
begin
() const¶Returns an iterator pointing at the first element of the collection. It does not allocate memory and its complexity is \( O(1) \).
end
() const¶Returns an iterator pointing just after the last element of the collection. It does not allocate and its complexity is \( O(1) \).
rbegin
() const¶Returns an iterator that traverses the collection backwards, pointing at the first element of the reversed collection. It does not allocate memory and its complexity is \( O(1) \).
rend
() const¶Returns an iterator that traverses the collection backwards, pointing after the last element of the reversed collection. It does not allocate memory and its complexity is \( O(1) \).
size
() const¶Returns the number of elements in the container. It does not allocate memory and its complexity is \( O(1) \).
empty
() const¶Returns true
if there are no elements in the container. It does not allocate memory and its complexity is \( O(1) \).
back
() const¶Access the last element.
front
() const¶Access the first element.
operator[]
(size_type index) const¶Returns a const
reference to the element at position index
. It is undefined when \( 0 index \geq size() \). It does not allocate memory and its complexity is effectively \( O(1) \).
at
(size_type index) const¶Returns a const
reference to the element at position index
. It throws an std::out_of_range
exception when \( index \geq size() \). It does not allocate memory and its complexity is effectively \( O(1) \).
operator==
(const flex_vector &other) const¶Returns whether the vectors are equal.
operator!=
(const flex_vector &other) const¶push_back
(value_type value) const¶Returns a flex_vector with value
inserted at the end. It may allocate memory and its complexity is effectively \( O(1) \).
auto v1 = immer::flex_vector<int>{1};
auto v2 = v1.push_back(8);
assert((v1 == immer::flex_vector<int>{1}));
assert((v2 == immer::flex_vector<int>{1, 8}));
decltype(auto) immer::flex_vector::push_back(value_type value)
push_front
(value_type value) const¶Returns a flex_vector with value
inserted at the front. It may allocate memory and its complexity is \( O(log(size)) \).
auto v1 = immer::flex_vector<int>{1};
auto v2 = v1.push_front(8);
assert((v1 == immer::flex_vector<int>{1}));
assert((v2 == immer::flex_vector<int>{8, 1}));
set
(size_type index, value_type value) const¶Returns a flex_vector containing value value
at position index
. Undefined for index >= size()
. It may allocate memory and its complexity is effectively \( O(1) \).
auto v1 = immer::flex_vector<int>{1, 2, 3};
auto v2 = v1.set(0, 5);
assert((v1 == immer::flex_vector<int>{1, 2, 3}));
assert((v2 == immer::flex_vector<int>{5, 2, 3}));
decltype(auto) immer::flex_vector::set(size_type index, value_type value)
update
(size_type index, FnT &&fn) const¶Returns a vector containing the result of the expression fn((*this)[idx])
at position idx
. Undefined for index >= size()
. It may allocate memory and its complexity is effectively \( O(1) \).
auto v1 = immer::flex_vector<int>{1, 2, 3, 4};
auto v2 = v1.update(2, [&](auto l) { return ++l; });
assert((v1 == immer::flex_vector<int>{1, 2, 3, 4}));
assert((v2 == immer::flex_vector<int>{1, 2, 4, 4}));
decltype(auto) immer::flex_vector::update(size_type index, FnT && fn)
take
(size_type elems) const¶Returns a vector containing only the first min(elems, size())
elements. It may allocate memory and its complexity is effectively \( O(1) \).
auto v1 = immer::flex_vector<int>{1, 2, 3, 4, 5, 6};
auto v2 = v1.take(3);
assert((v1 == immer::flex_vector<int>{1, 2, 3, 4, 5, 6}));
assert((v2 == immer::flex_vector<int>{1, 2, 3}));
decltype(auto) immer::flex_vector::take(size_type elems)
drop
(size_type elems) const¶Returns a vector without the first min(elems, size())
elements. It may allocate memory and its complexity is effectively \( O(1) \).
auto v1 = immer::flex_vector<int>{1, 2, 3, 4, 5, 6};
auto v2 = v1.drop(3);
assert((v1 == immer::flex_vector<int>{1, 2, 3, 4, 5, 6}));
assert((v2 == immer::flex_vector<int>{4, 5, 6}));
decltype(auto) immer::flex_vector::drop(size_type elems)
decltype(auto) friend immer::flex_vector::operator+(flex_vector && l, const flex_vector & r)
decltype(auto) friend immer::flex_vector::operator+(const flex_vector & l, flex_vector && r)
decltype(auto) friend immer::flex_vector::operator+(flex_vector && l, flex_vector && r)
insert
(size_type pos, T value) const¶Returns a flex_vector with the value
inserted at index pos
. It may allocate memory and its complexity is \( O(log(size)) \)
auto v1 = immer::flex_vector<int>{1, 2, 3};
auto v2 = v1.insert(0, 0);
assert((v1 == immer::flex_vector<int>{1, 2, 3}));
assert((v2 == immer::flex_vector<int>{0, 1, 2, 3}));
decltype(auto) immer::flex_vector::insert(size_type pos, T value)
insert
(size_type pos, flex_vector value) const¶decltype(auto) immer::flex_vector::insert(size_type pos, flex_vector value)
erase
(size_type pos) const¶Returns a flex_vector without the element at index pos
. It may allocate memory and its complexity is \( O(log(size)) \)
auto v1 = immer::flex_vector<int>{1, 2, 3, 4, 5};
auto v2 = v1.erase(2);
assert((v1 == immer::flex_vector<int>{1, 2, 3, 4, 5}));
assert((v2 == immer::flex_vector<int>{1, 2, 4, 5}));
decltype(auto) immer::flex_vector::erase(size_type pos)
erase
(size_type pos, size_type lpos) const¶decltype(auto) immer::flex_vector::erase(size_type pos, size_type lpos)
transient
() const¶Returns an transient form of this container, an immer::flex_vector_transient
.
transient
()¶identity
() const¶Returns a value that can be used as identity for the container. If two values have the same identity, they are guaranteed to be equal and to contain the same objects. However, two equal containers are not guaranteed to have the same identity.
impl
() const¶flex_vector
(impl_t impl)¶Public Static Functions
max_size
()¶Returns the maximum theoretical size supported by the internal structure given the current B, BL.
Friends
operator+
(const flex_vector &l, const flex_vector &r)¶Concatenation operator. Returns a flex_vector with the contents of l
followed by those of r
. It may allocate memory and its complexity is \( O(log(max(size_r, size_l))) \)
auto v1 = immer::flex_vector<int>{1, 2, 3};
auto v2 = v1 + v1;
assert((v1 == immer::flex_vector<int>{1, 2, 3}));
assert((v2 == immer::flex_vector<int>{1, 2, 3, 1, 2, 3}));
immer::
set
¶Immutable set representing an unordered bag of values.
This container provides a good trade-off between cache locality, membership checks, update performance and structural sharing. It does so by storing the data in contiguous chunks of \(2^{B}\) elements. When storing big objects, the size of these contiguous chunks can become too big, damaging performance. If this is measured to be problematic for a specific use-case, it can be solved by using a immer::box to wrap the type T.
#include <immer/set.hpp>
int main()
{
const auto v0 = immer::set<int>{};
const auto v1 = v0.insert(42);
assert(v0.count(42) == 0);
assert(v1.count(42) == 1);
const auto v2 = v1.erase(42);
assert(v1.count(42) == 1);
assert(v2.count(42) == 0);
}
T
: The type of the values to be stored in the container. Hash
: The type of a function object capable of hashing values of type T
. Equal
: The type of a function object capable of comparing values of type T
. MemoryPolicy
: Memory management policy. See memory_policy.Public Types
value_type
= T¶size_type
= detail::hamts::size_t¶difference_type
= std::ptrdiff_t¶hasher
= Hash¶key_equal
= Equal¶reference
= const T&¶const_reference
= const T&¶iterator
= detail::hamts::champ_iterator<T, Hash, Equal, MemoryPolicy, B>¶transient_type
= set_transient<T, Hash, Equal, MemoryPolicy, B>¶memory_policy_type
= MemoryPolicy¶Public Functions
set
()¶Default constructor. It creates a set of size() == 0
. It does not allocate memory and its complexity is \( O(1) \).
set
(std::initializer_list<value_type> values)¶Constructs a set containing the elements in values
.
set
(Iter first, Sent last)¶Constructs a set containing the elements in the range defined by the input iterator first
and range sentinel last
.
begin
() const¶Returns an iterator pointing at the first element of the collection. It does not allocate memory and its complexity is \( O(1) \).
end
() const¶Returns an iterator pointing just after the last element of the collection. It does not allocate and its complexity is \( O(1) \).
size
() const¶Returns the number of elements in the container. It does not allocate memory and its complexity is \( O(1) \).
empty
() const¶Returns true
if there are no elements in the container. It does not allocate memory and its complexity is \( O(1) \).
count
(const K &value) const¶Returns 1
when value
is contained in the set or 0
otherwise. It won’t allocate memory and its complexity is effectively \( O(1) \).
This overload participates in overload resolution only if Hash::is_transparent
is valid and denotes a type.
count
(const T &value) const¶Returns 1
when value
is contained in the set or 0
otherwise. It won’t allocate memory and its complexity is effectively \( O(1) \).
find
(const T &value) const¶Returns a pointer to the value if value
is contained in the set, or nullptr otherwise. It does not allocate memory and its complexity is effectively \( O(1) \).
find
(const K &value) const¶Returns a pointer to the value if value
is contained in the set, or nullptr otherwise. It does not allocate memory and its complexity is effectively \( O(1) \).
This overload participates in overload resolution only if Hash::is_transparent
is valid and denotes a type.
insert
(T value) const¶Returns a set containing value
. If the value
is already in the set, it returns the same set. It may allocate memory and its complexity is effectively \( O(1) \).
decltype(auto) immer::set::insert(T value)
erase
(const T &value) const¶Returns a set without value
. If the value
is not in the set it returns the same set. It may allocate memory and its complexity is effectively \( O(1) \).
decltype(auto) immer::set::erase(const T & value)
transient
() const¶Returns an transient form of this container, a immer::set_transient
.
transient
()¶identity
() const¶Returns a value that can be used as identity for the container. If two values have the same identity, they are guaranteed to be equal and to contain the same objects. However, two equal containers are not guaranteed to have the same identity.
impl
() const¶set
(impl_t impl)¶immer::
map
¶Immutable unordered mapping of values from type K
to type T
.
This container provides a good trade-off between cache locality, search, update performance and structural sharing. It does so by storing the data in contiguous chunks of \(2^{B}\) elements. When storing big objects, the size of these contiguous chunks can become too big, damaging performance. If this is measured to be problematic for a specific use-case, it can be solved by using a immer::box to wrap the type T.
#include <immer/map.hpp>
int main()
{
const auto v0 = immer::map<std::string, int>{};
const auto v1 = v0.set("hello", 42);
assert(v0["hello"] == 0);
assert(v1["hello"] == 42);
const auto v2 = v1.erase("hello");
assert(*v1.find("hello") == 42);
assert(!v2.find("hello"));
}
K
: The type of the keys. T
: The type of the values to be stored in the container. Hash
: The type of a function object capable of hashing values of type T
. Equal
: The type of a function object capable of comparing values of type T
. MemoryPolicy
: Memory management policy. See memory_policy.Public Types
key_type
= K¶mapped_type
= T¶value_type
= std::pair<K, T>¶size_type
= detail::hamts::size_t¶difference_type
= std::ptrdiff_t¶hasher
= Hash¶key_equal
= Equal¶reference
= const value_type&¶const_reference
= const value_type&¶iterator
= detail::hamts::champ_iterator<value_t, hash_key, equal_key, MemoryPolicy, B>¶transient_type
= map_transient<K, T, Hash, Equal, MemoryPolicy, B>¶memory_policy_type
= MemoryPolicy¶Public Functions
map
(std::initializer_list<value_type> values)¶Constructs a map containing the elements in values
.
map
(Iter first, Sent last)¶Constructs a map containing the elements in the range defined by the input iterator first
and range sentinel last
.
map
()¶Default constructor. It creates a map of size() == 0
. It does not allocate memory and its complexity is \( O(1) \).
begin
() const¶Returns an iterator pointing at the first element of the collection. It does not allocate memory and its complexity is \( O(1) \).
end
() const¶Returns an iterator pointing just after the last element of the collection. It does not allocate and its complexity is \( O(1) \).
size
() const¶Returns the number of elements in the container. It does not allocate memory and its complexity is \( O(1) \).
empty
() const¶Returns true
if there are no elements in the container. It does not allocate memory and its complexity is \( O(1) \).
count
(const Key &k) const¶Returns 1
when the key k
is contained in the map or 0
otherwise. It won’t allocate memory and its complexity is effectively \( O(1) \).
This overload participates in overload resolution only if Hash::is_transparent
is valid and denotes a type.
count
(const K &k) const¶Returns 1
when the key k
is contained in the map or 0
otherwise. It won’t allocate memory and its complexity is effectively \( O(1) \).
operator[]
(const Key &k) const¶Returns a const
reference to the values associated to the key k
. If the key is not contained in the map, it returns a default constructed value. It does not allocate memory and its complexity is effectively \( O(1) \).
This overload participates in overload resolution only if Hash::is_transparent
is valid and denotes a type.
operator[]
(const K &k) const¶Returns a const
reference to the values associated to the key k
. If the key is not contained in the map, it returns a default constructed value. It does not allocate memory and its complexity is effectively \( O(1) \).
at
(const Key &k) const¶Returns a const
reference to the values associated to the key k
. If the key is not contained in the map, throws an std::out_of_range
error. It does not allocate memory and its complexity is effectively \( O(1) \).
at
(const K &k) const¶Returns a const
reference to the values associated to the key k
. If the key is not contained in the map, throws an std::out_of_range
error. It does not allocate memory and its complexity is effectively \( O(1) \).
This overload participates in overload resolution only if Hash::is_transparent
is valid and denotes a type.
find
(const K &k) const¶Returns a pointer to the value associated with the key k
. If the key is not contained in the map, a nullptr
is returned. It does not allocate memory and its complexity is effectively \( O(1) \).
Why doesn’t this function return an iterator?
Associative containers from the C++ standard library provide a
find
method that returns an iterator pointing to the
element in the container or end()
when the key is missing.
In the case of an unordered container, the only meaningful
thing one may do with it is to compare it with the end, to
test if the find was succesfull, and dereference it. This
comparison is cumbersome compared to testing for a non-empty
optional value. Furthermore, for an immutable container,
returning an iterator would have some additional performance
cost, with no benefits otherwise.
In our opinion, this function should return a
std::optional<const T&>
but this construction is not valid
in any current standard. As a compromise we return a
pointer, which has similar syntactic properties yet it is
unfortunately unnecessarily unrestricted.
find
(const Key &k) const¶Returns a pointer to the value associated with the key k
. If the key is not contained in the map, a nullptr
is returned. It does not allocate memory and its complexity is effectively \( O(1) \).
This overload participates in overload resolution only if Hash::is_transparent
is valid and denotes a type.
insert
(value_type value) const¶Returns a map containing the association value
. If the key is already in the map, it replaces its association in the map. It may allocate memory and its complexity is effectively \( O(1) \).
decltype(auto) immer::map::insert(value_type value)
set
(key_type k, mapped_type v) const¶Returns a map containing the association (k, v)
. If the key is already in the map, it replaces its association in the map. It may allocate memory and its complexity is effectively \( O(1) \).
decltype(auto) immer::map::set(key_type k, mapped_type v)
update
(key_type k, Fn &&fn) const¶Returns a map replacing the association (k, v)
by the association new association (k, fn(v))
, where v
is the currently associated value for k
in the map or a default constructed value otherwise. It may allocate memory and its complexity is effectively \( O(1) \).
decltype(auto) immer::map::update(key_type k, Fn && fn)
update_if_exists
(key_type k, Fn &&fn) const¶Returns a map replacing the association (k, v)
by the association new association (k, fn(v))
, where v
is the currently associated value for k
in the map. It does nothing if k
is not present in the map. It may allocate memory and its complexity is effectively \( O(1) \).
decltype(auto) immer::map::update_if_exists(key_type k, Fn && fn)
erase
(const K &k) const¶Returns a map without the key k
. If the key is not associated in the map it returns the same map. It may allocate memory and its complexity is effectively \( O(1) \).
decltype(auto) immer::map::erase(const K & k)
transient
() const¶Returns a transient form of this container, an immer::map_transient
.
transient
()¶identity
() const¶Returns a value that can be used as identity for the container. If two values have the same identity, they are guaranteed to be equal and to contain the same objects. However, two equal containers are not guaranteed to have the same identity.
impl
() const¶map
(impl_t impl)¶immer::
table
¶Immutable unordered set of values of type T
. Values are indexed via operator()(const T&)
from KeyFn
template parameter. By default, key is &T::id
.
This container is based on the immer::map underlying data structure.
This container provides a good trade-off between cache locality, search, update performance and structural sharing. It does so by storing the data in contiguous chunks of \(2^{B}\) elements. When storing big objects, the size of these contiguous chunks can become too big, damaging performance. If this is measured to be problematic for a specific use-case, it can be solved by using a immer::box to wrap the type T.
#include <immer/table.hpp>
int main()
{
struct Item
{
std::string id;
int value;
};
const auto v0 = immer::table<Item>{};
const auto v1 = v0.insert({"hello", 42});
assert(v0["hello"].value == 0);
assert(v1["hello"].value == 42);
const auto v2 = v1.erase("hello");
assert(v1.find("hello")->value == 42);
assert(!v2.find("hello"));
}
T
: The type of the values to be stored in the container. KeyFn
: Type which implements operator()(const T&)
Hash
: The type of a function object capable of hashing values of type T
. Equal
: The type of a function object capable of comparing values of type T
. MemoryPolicy
: Memory management policy. See memory_policy.Public Types
key_type
= K¶mapped_type
= T¶value_type
= T¶size_type
= detail::hamts::size_t¶difference_type
= std::ptrdiff_t¶hasher
= Hash¶key_equal
= Equal¶reference
= const value_type&¶const_reference
= const value_type&¶iterator
= detail::hamts::champ_iterator<value_t, hash_key, equal_key, MemoryPolicy, B>¶transient_type
= table_transient<T, KeyFn, Hash, Equal, MemoryPolicy, B>¶memory_policy_type
= MemoryPolicy¶Public Functions
table
(std::initializer_list<value_type> values)¶Constructs a table containing the elements in values
.
table
(Iter first, Sent last)¶Constructs a table containing the elements in the range defined by the input iterator first
and range sentinel last
.
table
()¶Default constructor. It creates a table of size() == 0
. It does not allocate memory and its complexity is \( O(1) \).
begin
() const¶Returns an iterator pointing at the first element of the collection. It does not allocate memory and its complexity is \( O(1) \).
end
() const¶Returns an iterator pointing just after the last element of the collection. It does not allocate and its complexity is \( O(1) \).
size
() const¶Returns the number of elements in the container. It does not allocate memory and its complexity is \( O(1) \).
empty
() const¶Returns true
if there are no elements in the container. It does not allocate memory and its complexity is \( O(1) \).
count
(const Key &k) const¶Returns 1
when the key k
is contained in the table or 0
otherwise. It won’t allocate memory and its complexity is effectively \( O(1) \).
This overload participates in overload resolution only if Hash::is_transparent
is valid and denotes a type.
count
(const K &k) const¶Returns 1
when the key k
is contained in the table or 0
otherwise. It won’t allocate memory and its complexity is effectively \( O(1) \).
operator[]
(const Key &k) const¶Returns a const
reference to the values associated to the key k
. If there is no entry with such a key in the table, it returns a default constructed value. It does not allocate memory and its complexity is effectively \( O(1) \).
This overload participates in overload resolution only if Hash::is_transparent
is valid and denotes a type.
operator[]
(const K &k) const¶Returns a const
reference to the values associated to the key k
. If there is no entry with such a key in the table, it returns a default constructed value. It does not allocate memory and its complexity is effectively \( O(1) \).
at
(const Key &k) const¶Returns a const
reference to the values associated to the key k
. If there is no entry with such a key in the table, throws an std::out_of_range
error. It does not allocate memory and its complexity is effectively \( O(1) \).
This overload participates in overload resolution only if Hash::is_transparent
is valid and denotes a type.
at
(const K &k) const¶Returns a const
reference to the values associated to the key k
. If there is no entry with such a key in the table, throws an std::out_of_range
error. It does not allocate memory and its complexity is effectively \( O(1) \).
find
(const K &k) const¶Returns a pointer to the value associated with the key k
. If there is no entry with such a key in the table, a nullptr
is returned. It does not allocate memory and its complexity is effectively \( O(1) \).
find
(const Key &k) const¶Returns a pointer to the value associated with the key k
. If there is no entry with such a key in the table, a nullptr
is returned. It does not allocate memory and its complexity is effectively \( O(1) \).
This overload participates in overload resolution only if Hash::is_transparent
is valid and denotes a type.
insert
(value_type value) const¶Returns a table containing the value
. If there is an entry with its key is already, it replaces this entry by value
. It may allocate memory and its complexity is effectively \( O(1) \).
decltype(auto) immer::table::insert(value_type value)
Returns a table containing the value
. If there is an entry with its key is already, it replaces this entry by value
. It may allocate memory and its complexity is effectively \( O(1) \).
update
(key_type k, Fn &&fn) const¶Returns this->insert(fn((*this)[k]))
. In particular, fn
maps T
to T
. The key k
will be replaced inside the value returned by fn
. It may allocate memory and its complexity is effectively \( O(1) \).
decltype(auto) immer::table::update(key_type k, Fn && fn)
update_if_exists
(key_type k, Fn &&fn) const¶Returns this.count(k) ? this->insert(fn((*this)[k])) : *this
. In particular, fn
maps T
to T
. The key k
will be replaced inside the value returned by fn
. It may allocate memory and its complexity is effectively \( O(1) \).
decltype(auto) immer::table::update_if_exists(key_type k, Fn && fn)
erase
(const K &k) const¶Returns a table without entries with given key k
. If the key is not present it returns *this
. It may allocate memory and its complexity is effectively \( O(1) \).
decltype(auto) immer::table::erase(const K & k)
Returns a table without entries with given key k
. If the key is not present it returns *this
. It may allocate memory and its complexity is effectively \( O(1) \).
transient
() const¶Returns a transient form of this container, an immer::table_transient
.
transient
()¶Returns a transient form of this container, an immer::table_transient
.
impl
() const¶table
(impl_t impl)¶