mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-19 18:45:52 +00:00
* Header-only! * No external dependencies or other beast modules * Compilation options allow for: - Stand-alone application to run a single test suite - Stand-alone application to run a set of test suites - Global suite of tests inline with the host application - Disable test suite generation completely * Existing tests reworked to use the new classes
2484 lines
74 KiB
C++
2484 lines
74 KiB
C++
//------------------------------------------------------------------------------
|
|
/*
|
|
This file is part of Beast: https://github.com/vinniefalco/Beast
|
|
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
|
|
|
Permission to use, copy, modify, and/or distribute this software for any
|
|
purpose with or without fee is hereby granted, provided that the above
|
|
copyright notice and this permission notice appear in all copies.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
//==============================================================================
|
|
|
|
#ifndef BEAST_CONTAINER_AGED_UNORDERED_CONTAINER_H_INCLUDED
|
|
#define BEAST_CONTAINER_AGED_UNORDERED_CONTAINER_H_INCLUDED
|
|
|
|
#include "aged_container_iterator.h"
|
|
#include "aged_associative_container.h"
|
|
|
|
#include "../aged_container.h"
|
|
|
|
#include "../../chrono/abstract_clock.h"
|
|
#include "../../utility/empty_base_optimization.h"
|
|
|
|
#include <boost/intrusive/list.hpp>
|
|
#include <boost/intrusive/unordered_set.hpp>
|
|
|
|
#include "../../cxx14/algorithm.h" // <algorithm>
|
|
#include <functional>
|
|
#include <initializer_list>
|
|
#include <iterator>
|
|
#include <memory>
|
|
#include "../../cxx14/type_traits.h" // <type_traits>
|
|
#include <utility>
|
|
|
|
/*
|
|
|
|
TODO
|
|
|
|
- Add constructor variations that take a bucket count
|
|
|
|
- Review for noexcept and exception guarantees
|
|
|
|
- Call the safe version of is_permutation that takes 4 iterators
|
|
|
|
*/
|
|
|
|
#ifndef BEAST_NO_CXX14_IS_PERMUTATION
|
|
#define BEAST_NO_CXX14_IS_PERMUTATION 1
|
|
#endif
|
|
|
|
namespace beast {
|
|
namespace detail {
|
|
|
|
/** Associative container where each element is also indexed by time.
|
|
|
|
This container mirrors the interface of the standard library unordered
|
|
associative containers, with the addition that each element is associated
|
|
with a `when` `time_point` which is obtained from the value of the clock's
|
|
`now`. The function `touch` updates the time for an element to the current
|
|
time as reported by the clock.
|
|
|
|
An extra set of iterator types and member functions are provided in the
|
|
`chronological` memberspace that allow traversal in temporal or reverse
|
|
temporal order. This container is useful as a building block for caches
|
|
whose items expire after a certain amount of time. The chronological
|
|
iterators allow for fully customizable expiration strategies.
|
|
|
|
@see aged_unordered_set, aged_unordered_multiset
|
|
@see aged_unordered_map, aged_unordered_multimap
|
|
*/
|
|
template <
|
|
bool IsMulti,
|
|
bool IsMap,
|
|
class Key,
|
|
class T,
|
|
class Duration = std::chrono::seconds,
|
|
class Hash = std::hash <Key>,
|
|
class KeyEqual = std::equal_to <Key>,
|
|
class Allocator = std::allocator <
|
|
typename std::conditional <IsMap,
|
|
std::pair <Key const, T>,
|
|
Key>::type>
|
|
>
|
|
class aged_unordered_container
|
|
{
|
|
public:
|
|
typedef abstract_clock <Duration> clock_type;
|
|
typedef typename clock_type::time_point time_point;
|
|
typedef typename clock_type::duration duration;
|
|
typedef Key key_type;
|
|
typedef T mapped_type;
|
|
typedef typename std::conditional <IsMap,
|
|
std::pair <Key const, T>,
|
|
Key>::type value_type;
|
|
typedef std::size_t size_type;
|
|
typedef std::ptrdiff_t difference_type;
|
|
|
|
// Introspection (for unit tests)
|
|
typedef std::true_type is_unordered;
|
|
typedef std::integral_constant <bool, IsMulti> is_multi;
|
|
typedef std::integral_constant <bool, IsMap> is_map;
|
|
|
|
// VFALCO TODO How can we reorder the declarations to keep
|
|
// all the public things together contiguously?
|
|
|
|
private:
|
|
static Key const& extract (value_type const& value)
|
|
{
|
|
return aged_associative_container_extract_t <IsMap> () (value);
|
|
}
|
|
|
|
// VFALCO TODO hoist to remove template argument dependencies
|
|
struct element
|
|
: boost::intrusive::unordered_set_base_hook <
|
|
boost::intrusive::link_mode <
|
|
boost::intrusive::normal_link>
|
|
>
|
|
, boost::intrusive::list_base_hook <
|
|
boost::intrusive::link_mode <
|
|
boost::intrusive::normal_link>
|
|
>
|
|
{
|
|
// Stash types here so the iterator doesn't
|
|
// need to see the container declaration.
|
|
struct stashed
|
|
{
|
|
typedef typename aged_unordered_container::value_type value_type;
|
|
typedef typename aged_unordered_container::time_point time_point;
|
|
};
|
|
|
|
element (
|
|
time_point const& when_,
|
|
value_type const& value_)
|
|
: value (value_)
|
|
, when (when_)
|
|
{
|
|
}
|
|
|
|
element (
|
|
time_point const& when_,
|
|
value_type&& value_)
|
|
: value (std::move (value_))
|
|
, when (when_)
|
|
{
|
|
}
|
|
|
|
template <
|
|
class... Args,
|
|
class = typename std::enable_if <
|
|
std::is_constructible <value_type,
|
|
Args...>::value>::type
|
|
>
|
|
element (time_point const& when_, Args&&... args)
|
|
: value (std::forward <Args> (args)...)
|
|
, when (when_)
|
|
{
|
|
}
|
|
|
|
value_type value;
|
|
time_point when;
|
|
};
|
|
|
|
// VFALCO TODO hoist to remove template argument dependencies
|
|
class ValueHash
|
|
: private empty_base_optimization <Hash>
|
|
, public std::unary_function <element, std::size_t>
|
|
{
|
|
public:
|
|
ValueHash ()
|
|
{
|
|
}
|
|
|
|
ValueHash (Hash const& hash)
|
|
: empty_base_optimization <Hash> (hash)
|
|
{
|
|
}
|
|
|
|
std::size_t operator() (element const& e) const
|
|
{
|
|
return this->member() (extract (e.value));
|
|
}
|
|
|
|
Hash& hash_function()
|
|
{
|
|
return this->member();
|
|
}
|
|
|
|
Hash const& hash_function() const
|
|
{
|
|
return this->member();
|
|
}
|
|
};
|
|
|
|
// Compares value_type against element, used in find/insert_check
|
|
// VFALCO TODO hoist to remove template argument dependencies
|
|
class KeyValueEqual
|
|
: private empty_base_optimization <KeyEqual>
|
|
, public std::binary_function <Key, element, bool>
|
|
{
|
|
public:
|
|
KeyValueEqual ()
|
|
{
|
|
}
|
|
|
|
KeyValueEqual (KeyEqual const& keyEqual)
|
|
: empty_base_optimization <KeyEqual> (keyEqual)
|
|
{
|
|
}
|
|
|
|
// VFALCO NOTE WE might want only to enable these overloads
|
|
// if KeyEqual has is_transparent
|
|
#if 0
|
|
template <class K>
|
|
bool operator() (K const& k, element const& e) const
|
|
{
|
|
return this->member() (k, extract (e.value));
|
|
}
|
|
|
|
template <class K>
|
|
bool operator() (element const& e, K const& k) const
|
|
{
|
|
return this->member() (extract (e.value), k);
|
|
}
|
|
#endif
|
|
|
|
bool operator() (Key const& k, element const& e) const
|
|
{
|
|
return this->member() (k, extract (e.value));
|
|
}
|
|
|
|
bool operator() (element const& e, Key const& k) const
|
|
{
|
|
return this->member() (extract (e.value), k);
|
|
}
|
|
|
|
bool operator() (element const& lhs, element const& rhs) const
|
|
{
|
|
return this->member() (extract (lhs.value), extract (rhs.value));
|
|
}
|
|
|
|
KeyEqual& key_eq()
|
|
{
|
|
return this->member();
|
|
}
|
|
|
|
KeyEqual const& key_eq() const
|
|
{
|
|
return this->member();
|
|
}
|
|
};
|
|
|
|
typedef typename boost::intrusive::make_list <element,
|
|
boost::intrusive::constant_time_size <false>
|
|
>::type list_type;
|
|
|
|
typedef typename std::conditional <
|
|
IsMulti,
|
|
typename boost::intrusive::make_unordered_multiset <element,
|
|
boost::intrusive::constant_time_size <true>,
|
|
boost::intrusive::hash <ValueHash>,
|
|
boost::intrusive::equal <KeyValueEqual>,
|
|
boost::intrusive::cache_begin <true>
|
|
>::type,
|
|
typename boost::intrusive::make_unordered_set <element,
|
|
boost::intrusive::constant_time_size <true>,
|
|
boost::intrusive::hash <ValueHash>,
|
|
boost::intrusive::equal <KeyValueEqual>,
|
|
boost::intrusive::cache_begin <true>
|
|
>::type
|
|
>::type cont_type;
|
|
|
|
typedef typename cont_type::bucket_type bucket_type;
|
|
typedef typename cont_type::bucket_traits bucket_traits;
|
|
|
|
typedef typename std::allocator_traits <
|
|
Allocator>::template rebind_alloc <element> ElementAllocator;
|
|
|
|
using ElementAllocatorTraits = std::allocator_traits <ElementAllocator>;
|
|
|
|
typedef typename std::allocator_traits <
|
|
Allocator>::template rebind_alloc <element> BucketAllocator;
|
|
|
|
using BucketAllocatorTraits = std::allocator_traits <BucketAllocator>;
|
|
|
|
class config_t
|
|
: private ValueHash
|
|
, private KeyValueEqual
|
|
, private empty_base_optimization <ElementAllocator>
|
|
{
|
|
public:
|
|
explicit config_t (
|
|
clock_type& clock_)
|
|
: clock (clock_)
|
|
{
|
|
}
|
|
|
|
config_t (
|
|
clock_type& clock_,
|
|
Hash const& hash)
|
|
: ValueHash (hash)
|
|
, clock (clock_)
|
|
{
|
|
}
|
|
|
|
config_t (
|
|
clock_type& clock_,
|
|
KeyEqual const& keyEqual)
|
|
: KeyValueEqual (keyEqual)
|
|
, clock (clock_)
|
|
{
|
|
}
|
|
|
|
config_t (
|
|
clock_type& clock_,
|
|
Allocator const& alloc_)
|
|
: empty_base_optimization <ElementAllocator> (alloc_)
|
|
, clock (clock_)
|
|
{
|
|
}
|
|
|
|
config_t (
|
|
clock_type& clock_,
|
|
Hash const& hash,
|
|
KeyEqual const& keyEqual)
|
|
: ValueHash (hash)
|
|
, KeyValueEqual (keyEqual)
|
|
, clock (clock_)
|
|
{
|
|
}
|
|
|
|
config_t (
|
|
clock_type& clock_,
|
|
Hash const& hash,
|
|
Allocator const& alloc_)
|
|
: ValueHash (hash)
|
|
, empty_base_optimization <ElementAllocator> (alloc_)
|
|
, clock (clock_)
|
|
{
|
|
}
|
|
|
|
config_t (
|
|
clock_type& clock_,
|
|
KeyEqual const& keyEqual,
|
|
Allocator const& alloc_)
|
|
: KeyValueEqual (keyEqual)
|
|
, empty_base_optimization <ElementAllocator> (alloc_)
|
|
, clock (clock_)
|
|
{
|
|
}
|
|
|
|
config_t (
|
|
clock_type& clock_,
|
|
Hash const& hash,
|
|
KeyEqual const& keyEqual,
|
|
Allocator const& alloc_)
|
|
: ValueHash (hash)
|
|
, KeyValueEqual (keyEqual)
|
|
, empty_base_optimization <ElementAllocator> (alloc_)
|
|
, clock (clock_)
|
|
{
|
|
}
|
|
|
|
config_t (config_t const& other)
|
|
: ValueHash (other.hash_function())
|
|
, KeyValueEqual (other.key_eq())
|
|
, empty_base_optimization <ElementAllocator> (
|
|
ElementAllocatorTraits::
|
|
select_on_container_copy_construction (
|
|
other.alloc()))
|
|
, clock (other.clock)
|
|
{
|
|
}
|
|
|
|
config_t (config_t const& other, Allocator const& alloc)
|
|
: ValueHash (other.hash_function())
|
|
, KeyValueEqual (other.key_eq())
|
|
, empty_base_optimization <ElementAllocator> (alloc)
|
|
, clock (other.clock)
|
|
{
|
|
}
|
|
|
|
config_t (config_t&& other)
|
|
: ValueHash (std::move (other.hash_function()))
|
|
, KeyValueEqual (std::move (other.key_eq()))
|
|
, empty_base_optimization <ElementAllocator> (
|
|
std::move (other.alloc()))
|
|
, clock (other.clock)
|
|
{
|
|
}
|
|
|
|
config_t (config_t&& other, Allocator const& alloc)
|
|
: ValueHash (std::move (other.hash_function()))
|
|
, KeyValueEqual (std::move (other.key_eq()))
|
|
, empty_base_optimization <ElementAllocator> (alloc)
|
|
, clock (other.clock)
|
|
{
|
|
}
|
|
|
|
config_t& operator= (config_t const& other)
|
|
{
|
|
hash_function() = other.hash_function();
|
|
key_eq() = other.key_eq();
|
|
alloc() = other.alloc();
|
|
clock = other.clock;
|
|
return *this;
|
|
}
|
|
|
|
config_t& operator= (config_t&& other)
|
|
{
|
|
hash_function() = std::move (other.hash_function());
|
|
key_eq() = std::move (other.key_eq());
|
|
alloc() = std::move (other.alloc());
|
|
clock = other.clock;
|
|
return *this;
|
|
}
|
|
|
|
ValueHash& value_hash()
|
|
{
|
|
return *this;
|
|
}
|
|
|
|
ValueHash const& value_hash() const
|
|
{
|
|
return *this;
|
|
}
|
|
|
|
Hash& hash_function()
|
|
{
|
|
return ValueHash::hash_function();
|
|
}
|
|
|
|
Hash const& hash_function() const
|
|
{
|
|
return ValueHash::hash_function();
|
|
}
|
|
|
|
KeyValueEqual& key_value_equal()
|
|
{
|
|
return *this;
|
|
}
|
|
|
|
KeyValueEqual const& key_value_equal() const
|
|
{
|
|
return *this;
|
|
}
|
|
|
|
KeyEqual& key_eq()
|
|
{
|
|
return key_value_equal().key_eq();
|
|
}
|
|
|
|
KeyEqual const& key_eq() const
|
|
{
|
|
return key_value_equal().key_eq();
|
|
}
|
|
|
|
ElementAllocator& alloc()
|
|
{
|
|
return empty_base_optimization <
|
|
ElementAllocator>::member();
|
|
}
|
|
|
|
ElementAllocator const& alloc() const
|
|
{
|
|
return empty_base_optimization <
|
|
ElementAllocator>::member();
|
|
}
|
|
|
|
std::reference_wrapper <clock_type> clock;
|
|
};
|
|
|
|
class Buckets
|
|
{
|
|
public:
|
|
typedef std::vector <
|
|
bucket_type,
|
|
typename std::allocator_traits <Allocator>::
|
|
template rebind_alloc <bucket_type>> vec_type;
|
|
|
|
Buckets ()
|
|
: m_max_load_factor (1.f)
|
|
, m_vec ()
|
|
{
|
|
m_vec.resize (
|
|
cont_type::suggested_upper_bucket_count (0));
|
|
}
|
|
|
|
Buckets (Allocator const& alloc)
|
|
: m_max_load_factor (1.f)
|
|
, m_vec (alloc)
|
|
{
|
|
m_vec.resize (
|
|
cont_type::suggested_upper_bucket_count (0));
|
|
}
|
|
|
|
operator bucket_traits()
|
|
{
|
|
return bucket_traits (&m_vec[0], m_vec.size());
|
|
}
|
|
|
|
void clear()
|
|
{
|
|
m_vec.clear();
|
|
}
|
|
|
|
size_type max_bucket_count() const
|
|
{
|
|
return m_vec.max_size();
|
|
}
|
|
|
|
float& max_load_factor()
|
|
{
|
|
return m_max_load_factor;
|
|
}
|
|
|
|
float const& max_load_factor() const
|
|
{
|
|
return m_max_load_factor;
|
|
}
|
|
|
|
// count is the number of buckets
|
|
template <class Container>
|
|
void rehash (size_type count, Container& c)
|
|
{
|
|
size_type const size (m_vec.size());
|
|
if (count == size)
|
|
return;
|
|
if (count > m_vec.capacity())
|
|
{
|
|
// Need two vectors otherwise we
|
|
// will destroy non-empty buckets.
|
|
vec_type vec (m_vec.get_allocator());
|
|
std::swap (m_vec, vec);
|
|
m_vec.resize (count);
|
|
c.rehash (bucket_traits (
|
|
&m_vec[0], m_vec.size()));
|
|
return;
|
|
}
|
|
// Rehash in place.
|
|
if (count > size)
|
|
{
|
|
// This should not reallocate since
|
|
// we checked capacity earlier.
|
|
m_vec.resize (count);
|
|
c.rehash (bucket_traits (
|
|
&m_vec[0], count));
|
|
return;
|
|
}
|
|
// Resize must happen after rehash otherwise
|
|
// we might destroy non-empty buckets.
|
|
c.rehash (bucket_traits (
|
|
&m_vec[0], count));
|
|
m_vec.resize (count);
|
|
}
|
|
|
|
// Resize the buckets to accomodate at least n items.
|
|
template <class Container>
|
|
void resize (size_type n, Container& c)
|
|
{
|
|
size_type const suggested (
|
|
cont_type::suggested_upper_bucket_count (n));
|
|
rehash (suggested, c);
|
|
}
|
|
|
|
private:
|
|
float m_max_load_factor;
|
|
vec_type m_vec;
|
|
};
|
|
|
|
template <class... Args>
|
|
element* new_element (Args&&... args)
|
|
{
|
|
element* const p (
|
|
ElementAllocatorTraits::allocate (m_config.alloc(), 1));
|
|
ElementAllocatorTraits::construct (m_config.alloc(),
|
|
p, clock().now(), std::forward <Args> (args)...);
|
|
return p;
|
|
}
|
|
|
|
void delete_element (element* p)
|
|
{
|
|
ElementAllocatorTraits::destroy (m_config.alloc(), p);
|
|
ElementAllocatorTraits::deallocate (m_config.alloc(), p, 1);
|
|
}
|
|
|
|
void unlink_and_delete_element (element* p)
|
|
{
|
|
chronological.list.erase (
|
|
chronological.list.iterator_to (*p));
|
|
m_cont.erase (m_cont.iterator_to (*p));
|
|
delete_element (p);
|
|
}
|
|
|
|
public:
|
|
typedef Hash hasher;
|
|
typedef KeyEqual key_equal;
|
|
typedef Allocator allocator_type;
|
|
typedef value_type& reference;
|
|
typedef value_type const& const_reference;
|
|
typedef typename std::allocator_traits <
|
|
Allocator>::pointer pointer;
|
|
typedef typename std::allocator_traits <
|
|
Allocator>::const_pointer const_pointer;
|
|
|
|
typedef detail::aged_container_iterator <false,
|
|
typename cont_type::iterator> iterator;
|
|
typedef detail::aged_container_iterator <true,
|
|
typename cont_type::iterator> const_iterator;
|
|
|
|
typedef detail::aged_container_iterator <false,
|
|
typename cont_type::local_iterator> local_iterator;
|
|
typedef detail::aged_container_iterator <true,
|
|
typename cont_type::local_iterator> const_local_iterator;
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// Chronological ordered iterators
|
|
//
|
|
// "Memberspace"
|
|
// http://accu.org/index.php/journals/1527
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
class chronological_t
|
|
{
|
|
public:
|
|
typedef detail::aged_container_iterator <false,
|
|
typename list_type::iterator> iterator;
|
|
typedef detail::aged_container_iterator <true,
|
|
typename list_type::iterator> const_iterator;
|
|
typedef detail::aged_container_iterator <false,
|
|
typename list_type::reverse_iterator> reverse_iterator;
|
|
typedef detail::aged_container_iterator <true,
|
|
typename list_type::reverse_iterator> const_reverse_iterator;
|
|
|
|
iterator begin ()
|
|
{
|
|
return iterator (list.begin());
|
|
}
|
|
|
|
const_iterator begin () const
|
|
{
|
|
return const_iterator (list.begin ());
|
|
}
|
|
|
|
const_iterator cbegin() const
|
|
{
|
|
return const_iterator (list.begin ());
|
|
}
|
|
|
|
iterator end ()
|
|
{
|
|
return iterator (list.end ());
|
|
}
|
|
|
|
const_iterator end () const
|
|
{
|
|
return const_iterator (list.end ());
|
|
}
|
|
|
|
const_iterator cend () const
|
|
{
|
|
return const_iterator (list.end ());
|
|
}
|
|
|
|
reverse_iterator rbegin ()
|
|
{
|
|
return reverse_iterator (list.rbegin());
|
|
}
|
|
|
|
const_reverse_iterator rbegin () const
|
|
{
|
|
return const_reverse_iterator (list.rbegin ());
|
|
}
|
|
|
|
const_reverse_iterator crbegin() const
|
|
{
|
|
return const_reverse_iterator (list.rbegin ());
|
|
}
|
|
|
|
reverse_iterator rend ()
|
|
{
|
|
return reverse_iterator (list.rend ());
|
|
}
|
|
|
|
const_reverse_iterator rend () const
|
|
{
|
|
return const_reverse_iterator (list.rend ());
|
|
}
|
|
|
|
const_reverse_iterator crend () const
|
|
{
|
|
return const_reverse_iterator (list.rend ());
|
|
}
|
|
|
|
iterator iterator_to (value_type& value)
|
|
{
|
|
static_assert (std::is_standard_layout <element>::value,
|
|
"must be standard layout");
|
|
return list.iterator_to (*reinterpret_cast <element*>(
|
|
reinterpret_cast<uint8_t*>(&value)-((std::size_t)
|
|
std::addressof(((element*)0)->member))));
|
|
}
|
|
|
|
const_iterator iterator_to (value_type const& value) const
|
|
{
|
|
static_assert (std::is_standard_layout <element>::value,
|
|
"must be standard layout");
|
|
return list.iterator_to (*reinterpret_cast <element const*>(
|
|
reinterpret_cast<uint8_t const*>(&value)-((std::size_t)
|
|
std::addressof(((element*)0)->member))));
|
|
}
|
|
|
|
private:
|
|
chronological_t ()
|
|
{
|
|
}
|
|
|
|
chronological_t (chronological_t const&) = delete;
|
|
chronological_t (chronological_t&&) = delete;
|
|
|
|
friend class aged_unordered_container;
|
|
list_type mutable list;
|
|
} chronological;
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// Construction
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
explicit aged_unordered_container (clock_type& clock);
|
|
|
|
aged_unordered_container (clock_type& clock, Hash const& hash);
|
|
|
|
aged_unordered_container (clock_type& clock,
|
|
KeyEqual const& key_eq);
|
|
|
|
aged_unordered_container (clock_type& clock,
|
|
Allocator const& alloc);
|
|
|
|
aged_unordered_container (clock_type& clock,
|
|
Hash const& hash, KeyEqual const& key_eq);
|
|
|
|
aged_unordered_container (clock_type& clock,
|
|
Hash const& hash, Allocator const& alloc);
|
|
|
|
aged_unordered_container (clock_type& clock,
|
|
KeyEqual const& key_eq, Allocator const& alloc);
|
|
|
|
aged_unordered_container (
|
|
clock_type& clock, Hash const& hash, KeyEqual const& key_eq,
|
|
Allocator const& alloc);
|
|
|
|
template <class InputIt>
|
|
aged_unordered_container (InputIt first, InputIt last,
|
|
clock_type& clock);
|
|
|
|
template <class InputIt>
|
|
aged_unordered_container (InputIt first, InputIt last,
|
|
clock_type& clock, Hash const& hash);
|
|
|
|
template <class InputIt>
|
|
aged_unordered_container (InputIt first, InputIt last,
|
|
clock_type& clock, KeyEqual const& key_eq);
|
|
|
|
template <class InputIt>
|
|
aged_unordered_container (InputIt first, InputIt last,
|
|
clock_type& clock, Allocator const& alloc);
|
|
|
|
template <class InputIt>
|
|
aged_unordered_container (InputIt first, InputIt last,
|
|
clock_type& clock, Hash const& hash, KeyEqual const& key_eq);
|
|
|
|
template <class InputIt>
|
|
aged_unordered_container (InputIt first, InputIt last,
|
|
clock_type& clock, Hash const& hash, Allocator const& alloc);
|
|
|
|
template <class InputIt>
|
|
aged_unordered_container (InputIt first, InputIt last,
|
|
clock_type& clock, KeyEqual const& key_eq,
|
|
Allocator const& alloc);
|
|
|
|
template <class InputIt>
|
|
aged_unordered_container (InputIt first, InputIt last,
|
|
clock_type& clock, Hash const& hash, KeyEqual const& key_eq,
|
|
Allocator const& alloc);
|
|
|
|
aged_unordered_container (aged_unordered_container const& other);
|
|
|
|
aged_unordered_container (aged_unordered_container const& other,
|
|
Allocator const& alloc);
|
|
|
|
aged_unordered_container (aged_unordered_container&& other);
|
|
|
|
aged_unordered_container (aged_unordered_container&& other,
|
|
Allocator const& alloc);
|
|
|
|
aged_unordered_container (std::initializer_list <value_type> init,
|
|
clock_type& clock);
|
|
|
|
aged_unordered_container (std::initializer_list <value_type> init,
|
|
clock_type& clock, Hash const& hash);
|
|
|
|
aged_unordered_container (std::initializer_list <value_type> init,
|
|
clock_type& clock, KeyEqual const& key_eq);
|
|
|
|
aged_unordered_container (std::initializer_list <value_type> init,
|
|
clock_type& clock, Allocator const& alloc);
|
|
|
|
aged_unordered_container (std::initializer_list <value_type> init,
|
|
clock_type& clock, Hash const& hash, KeyEqual const& key_eq);
|
|
|
|
aged_unordered_container (std::initializer_list <value_type> init,
|
|
clock_type& clock, Hash const& hash, Allocator const& alloc);
|
|
|
|
aged_unordered_container (std::initializer_list <value_type> init,
|
|
clock_type& clock, KeyEqual const& key_eq, Allocator const& alloc);
|
|
|
|
aged_unordered_container (std::initializer_list <value_type> init,
|
|
clock_type& clock, Hash const& hash, KeyEqual const& key_eq,
|
|
Allocator const& alloc);
|
|
|
|
~aged_unordered_container();
|
|
|
|
aged_unordered_container& operator= (aged_unordered_container const& other);
|
|
|
|
aged_unordered_container& operator= (aged_unordered_container&& other);
|
|
|
|
aged_unordered_container& operator= (std::initializer_list <value_type> init);
|
|
|
|
allocator_type get_allocator() const
|
|
{
|
|
return m_config.alloc();
|
|
}
|
|
|
|
clock_type& clock()
|
|
{
|
|
return m_config.clock;
|
|
}
|
|
|
|
clock_type const& clock() const
|
|
{
|
|
return m_config.clock;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// Element access (maps)
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
template <
|
|
class K,
|
|
bool maybe_multi = IsMulti,
|
|
bool maybe_map = IsMap,
|
|
class = typename std::enable_if <maybe_map && ! maybe_multi>::type>
|
|
typename std::conditional <IsMap, T, void*>::type&
|
|
at (K const& k);
|
|
|
|
template <
|
|
class K,
|
|
bool maybe_multi = IsMulti,
|
|
bool maybe_map = IsMap,
|
|
class = typename std::enable_if <maybe_map && ! maybe_multi>::type>
|
|
typename std::conditional <IsMap, T, void*>::type const&
|
|
at (K const& k) const;
|
|
|
|
template <
|
|
bool maybe_multi = IsMulti,
|
|
bool maybe_map = IsMap,
|
|
class = typename std::enable_if <maybe_map && ! maybe_multi>::type>
|
|
typename std::conditional <IsMap, T, void*>::type&
|
|
operator[] (Key const& key);
|
|
|
|
template <
|
|
bool maybe_multi = IsMulti,
|
|
bool maybe_map = IsMap,
|
|
class = typename std::enable_if <maybe_map && ! maybe_multi>::type>
|
|
typename std::conditional <IsMap, T, void*>::type&
|
|
operator[] (Key&& key);
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// Iterators
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
iterator
|
|
begin ()
|
|
{
|
|
return iterator (m_cont.begin());
|
|
}
|
|
|
|
const_iterator
|
|
begin () const
|
|
{
|
|
return const_iterator (m_cont.begin ());
|
|
}
|
|
|
|
const_iterator
|
|
cbegin() const
|
|
{
|
|
return const_iterator (m_cont.begin ());
|
|
}
|
|
|
|
iterator
|
|
end ()
|
|
{
|
|
return iterator (m_cont.end ());
|
|
}
|
|
|
|
const_iterator
|
|
end () const
|
|
{
|
|
return const_iterator (m_cont.end ());
|
|
}
|
|
|
|
const_iterator
|
|
cend () const
|
|
{
|
|
return const_iterator (m_cont.end ());
|
|
}
|
|
|
|
iterator
|
|
iterator_to (value_type& value)
|
|
{
|
|
static_assert (std::is_standard_layout <element>::value,
|
|
"must be standard layout");
|
|
return m_cont.iterator_to (*reinterpret_cast <element*>(
|
|
reinterpret_cast<uint8_t*>(&value)-((std::size_t)
|
|
std::addressof(((element*)0)->member))));
|
|
}
|
|
|
|
const_iterator
|
|
iterator_to (value_type const& value) const
|
|
{
|
|
static_assert (std::is_standard_layout <element>::value,
|
|
"must be standard layout");
|
|
return m_cont.iterator_to (*reinterpret_cast <element const*>(
|
|
reinterpret_cast<uint8_t const*>(&value)-((std::size_t)
|
|
std::addressof(((element*)0)->member))));
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// Capacity
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
bool empty() const noexcept
|
|
{
|
|
return m_cont.empty();
|
|
}
|
|
|
|
size_type size() const noexcept
|
|
{
|
|
return m_cont.size();
|
|
}
|
|
|
|
size_type max_size() const noexcept
|
|
{
|
|
return m_config.max_size();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// Modifiers
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
void clear();
|
|
|
|
// map, set
|
|
template <bool maybe_multi = IsMulti>
|
|
auto
|
|
insert (value_type const& value) ->
|
|
typename std::enable_if <! maybe_multi,
|
|
std::pair <iterator, bool>>::type;
|
|
|
|
// multimap, multiset
|
|
template <bool maybe_multi = IsMulti>
|
|
auto
|
|
insert (value_type const& value) ->
|
|
typename std::enable_if <maybe_multi,
|
|
iterator>::type;
|
|
|
|
// map, set
|
|
template <bool maybe_multi = IsMulti, bool maybe_map = IsMap>
|
|
auto
|
|
insert (value_type&& value) ->
|
|
typename std::enable_if <! maybe_multi && ! maybe_map,
|
|
std::pair <iterator, bool>>::type;
|
|
|
|
// multimap, multiset
|
|
template <bool maybe_multi = IsMulti, bool maybe_map = IsMap>
|
|
auto
|
|
insert (value_type&& value) ->
|
|
typename std::enable_if <maybe_multi && ! maybe_map,
|
|
iterator>::type;
|
|
|
|
// map, set
|
|
template <bool maybe_multi = IsMulti>
|
|
typename std::enable_if <! maybe_multi,
|
|
iterator>::type
|
|
insert (const_iterator /*hint*/, value_type const& value)
|
|
{
|
|
// Hint is ignored but we provide the interface so
|
|
// callers may use ordered and unordered interchangeably.
|
|
return insert (value).first;
|
|
}
|
|
|
|
// multimap, multiset
|
|
template <bool maybe_multi = IsMulti>
|
|
typename std::enable_if <maybe_multi,
|
|
iterator>::type
|
|
insert (const_iterator const& /*hint*/, value_type const& value)
|
|
{
|
|
// VFALCO TODO The hint could be used to let
|
|
// the client order equal ranges
|
|
return insert (value);
|
|
}
|
|
|
|
// map, set
|
|
template <bool maybe_multi = IsMulti>
|
|
typename std::enable_if <! maybe_multi,
|
|
iterator>::type
|
|
insert (const_iterator /*hint*/, value_type&& value)
|
|
{
|
|
// Hint is ignored but we provide the interface so
|
|
// callers may use ordered and unordered interchangeably.
|
|
return insert (std::move (value)).first;
|
|
}
|
|
|
|
// multimap, multiset
|
|
template <bool maybe_multi = IsMulti>
|
|
typename std::enable_if <maybe_multi,
|
|
iterator>::type
|
|
insert (const_iterator const& /*hint*/, value_type&& value)
|
|
{
|
|
// VFALCO TODO The hint could be used to let
|
|
// the client order equal ranges
|
|
return insert (std::move (value));
|
|
}
|
|
|
|
// map, multimap
|
|
template <
|
|
class P,
|
|
bool maybe_map = IsMap
|
|
>
|
|
typename std::enable_if <maybe_map &&
|
|
std::is_constructible <value_type, P&&>::value,
|
|
typename std::conditional <IsMulti,
|
|
iterator, std::pair <iterator, bool>
|
|
>::type
|
|
>::type
|
|
insert (P&& value)
|
|
{
|
|
return emplace (std::forward <P> (value));
|
|
}
|
|
|
|
// map, multimap
|
|
template <
|
|
class P,
|
|
bool maybe_map = IsMap
|
|
>
|
|
typename std::enable_if <maybe_map &&
|
|
std::is_constructible <value_type, P&&>::value,
|
|
typename std::conditional <IsMulti,
|
|
iterator, std::pair <iterator, bool>
|
|
>::type
|
|
>::type
|
|
insert (const_iterator hint, P&& value)
|
|
{
|
|
return emplace_hint (hint, std::forward <P> (value));
|
|
}
|
|
|
|
template <class InputIt>
|
|
void insert (InputIt first, InputIt const& last)
|
|
{
|
|
insert (first, last,
|
|
typename std::iterator_traits <
|
|
InputIt>::iterator_category());
|
|
}
|
|
|
|
void
|
|
insert (std::initializer_list <value_type> init)
|
|
{
|
|
insert (init.begin(), init.end());
|
|
}
|
|
|
|
// set, map
|
|
template <bool maybe_multi = IsMulti, class... Args>
|
|
auto
|
|
emplace (Args&&... args) ->
|
|
typename std::enable_if <! maybe_multi,
|
|
std::pair <iterator, bool>>::type;
|
|
|
|
// multiset, multimap
|
|
template <bool maybe_multi = IsMulti, class... Args>
|
|
auto
|
|
emplace (Args&&... args) ->
|
|
typename std::enable_if <maybe_multi,
|
|
iterator>::type;
|
|
|
|
// set, map
|
|
template <bool maybe_multi = IsMulti, class... Args>
|
|
auto
|
|
emplace_hint (const_iterator const& /*hint*/, Args&&... args) ->
|
|
typename std::enable_if <! maybe_multi,
|
|
std::pair <iterator, bool>>::type;
|
|
|
|
// multiset, multimap
|
|
template <bool maybe_multi = IsMulti, class... Args>
|
|
typename std::enable_if <maybe_multi,
|
|
iterator>::type
|
|
emplace_hint (const_iterator const& /*hint*/, Args&&... args)
|
|
{
|
|
// VFALCO TODO The hint could be used for multi, to let
|
|
// the client order equal ranges
|
|
return emplace <maybe_multi> (
|
|
std::forward <Args> (args)...);
|
|
}
|
|
|
|
template <bool is_const, class Iterator, class Base>
|
|
detail::aged_container_iterator <false, Iterator, Base>
|
|
erase (detail::aged_container_iterator <
|
|
is_const, Iterator, Base> const& pos);
|
|
|
|
template <bool is_const, class Iterator, class Base>
|
|
detail::aged_container_iterator <false, Iterator, Base>
|
|
erase (detail::aged_container_iterator <
|
|
is_const, Iterator, Base> first,
|
|
detail::aged_container_iterator <
|
|
is_const, Iterator, Base> const& last);
|
|
|
|
template <class K>
|
|
auto
|
|
erase (K const& k) ->
|
|
size_type;
|
|
|
|
void
|
|
swap (aged_unordered_container& other) noexcept;
|
|
|
|
template <bool is_const, class Iterator, class Base>
|
|
void
|
|
touch (detail::aged_container_iterator <
|
|
is_const, Iterator, Base> const& pos)
|
|
{
|
|
touch (pos, clock().now());
|
|
}
|
|
|
|
template <class K>
|
|
auto
|
|
touch (K const& k) ->
|
|
size_type;
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// Lookup
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
// VFALCO TODO Respect is_transparent (c++14)
|
|
template <class K>
|
|
size_type
|
|
count (K const& k) const
|
|
{
|
|
return m_cont.count (k, std::cref (m_config.hash_function()),
|
|
std::cref (m_config.key_value_equal()));
|
|
}
|
|
|
|
// VFALCO TODO Respect is_transparent (c++14)
|
|
template <class K>
|
|
iterator
|
|
find (K const& k)
|
|
{
|
|
return iterator (m_cont.find (k,
|
|
std::cref (m_config.hash_function()),
|
|
std::cref (m_config.key_value_equal())));
|
|
}
|
|
|
|
// VFALCO TODO Respect is_transparent (c++14)
|
|
template <class K>
|
|
const_iterator
|
|
find (K const& k) const
|
|
{
|
|
return const_iterator (m_cont.find (k,
|
|
std::cref (m_config.hash_function()),
|
|
std::cref (m_config.key_value_equal())));
|
|
}
|
|
|
|
// VFALCO TODO Respect is_transparent (c++14)
|
|
template <class K>
|
|
std::pair <iterator, iterator>
|
|
equal_range (K const& k)
|
|
{
|
|
auto const r (m_cont.equal_range (k,
|
|
std::cref (m_config.hash_function()),
|
|
std::cref (m_config.key_value_equal())));
|
|
return std::make_pair (iterator (r.first),
|
|
iterator (r.second));
|
|
}
|
|
|
|
// VFALCO TODO Respect is_transparent (c++14)
|
|
template <class K>
|
|
std::pair <const_iterator, const_iterator>
|
|
equal_range (K const& k) const
|
|
{
|
|
auto const r (m_cont.equal_range (k,
|
|
std::cref (m_config.hash_function()),
|
|
std::cref (m_config.key_value_equal())));
|
|
return std::make_pair (const_iterator (r.first),
|
|
const_iterator (r.second));
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// Bucket interface
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
local_iterator begin (size_type n)
|
|
{
|
|
return local_iterator (m_cont.begin (n));
|
|
}
|
|
|
|
const_local_iterator begin (size_type n) const
|
|
{
|
|
return const_local_iterator (m_cont.begin (n));
|
|
}
|
|
|
|
const_local_iterator cbegin (size_type n) const
|
|
{
|
|
return const_local_iterator (m_cont.begin (n));
|
|
}
|
|
|
|
local_iterator end (size_type n)
|
|
{
|
|
return local_iterator (m_cont.end (n));
|
|
}
|
|
|
|
const_local_iterator end (size_type n) const
|
|
{
|
|
return const_local_iterator (m_cont.end (n));
|
|
}
|
|
|
|
const_local_iterator cend (size_type n) const
|
|
{
|
|
return const_local_iterator (m_cont.end (n));
|
|
}
|
|
|
|
size_type bucket_count() const
|
|
{
|
|
return m_cont.bucket_count();
|
|
}
|
|
|
|
size_type max_bucket_count() const
|
|
{
|
|
return m_buck.max_bucket_count();
|
|
}
|
|
|
|
size_type bucket_size (size_type n) const
|
|
{
|
|
return m_cont.bucket_size (n);
|
|
}
|
|
|
|
size_type bucket (Key const& k) const
|
|
{
|
|
assert (bucket_count() != 0);
|
|
return m_cont.bucket (k,
|
|
std::cref (m_config.hash_function()));
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// Hash policy
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
float load_factor() const
|
|
{
|
|
return size() /
|
|
static_cast <float> (m_cont.bucket_count());
|
|
}
|
|
|
|
float max_load_factor() const
|
|
{
|
|
return m_buck.max_load_factor();
|
|
}
|
|
|
|
void max_load_factor (float ml)
|
|
{
|
|
m_buck.max_load_factor () =
|
|
std::max (ml, m_buck.max_load_factor());
|
|
}
|
|
|
|
void rehash (size_type count)
|
|
{
|
|
count = std::max (count,
|
|
size_type (size() / max_load_factor()));
|
|
m_buck.rehash (count, m_cont);
|
|
}
|
|
|
|
void reserve (size_type count)
|
|
{
|
|
rehash (std::ceil (count / max_load_factor()));
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// Observers
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
hasher const& hash_function() const
|
|
{
|
|
return m_config.hash_function();
|
|
}
|
|
|
|
key_equal const& key_eq () const
|
|
{
|
|
return m_config.key_eq();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// Comparison
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
// This differs from the standard in that the comparison
|
|
// is only done on the key portion of the value type, ignoring
|
|
// the mapped type.
|
|
//
|
|
template <
|
|
bool OtherIsMap,
|
|
class OtherKey,
|
|
class OtherT,
|
|
class OtherDuration,
|
|
class OtherHash,
|
|
class OtherAllocator,
|
|
bool maybe_multi = IsMulti
|
|
>
|
|
typename std::enable_if <! maybe_multi,
|
|
bool>::type
|
|
operator== (
|
|
aged_unordered_container <false, OtherIsMap,
|
|
OtherKey, OtherT, OtherDuration, OtherHash, KeyEqual,
|
|
OtherAllocator> const& other) const
|
|
{
|
|
if (size() != other.size())
|
|
return false;
|
|
for (auto iter (cbegin()), last (cend()), olast (other.cend());
|
|
iter != last; ++iter)
|
|
{
|
|
auto oiter (other.find (extract (*iter)));
|
|
if (oiter == olast)
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
template <
|
|
bool OtherIsMap,
|
|
class OtherKey,
|
|
class OtherT,
|
|
class OtherDuration,
|
|
class OtherHash,
|
|
class OtherAllocator,
|
|
bool maybe_multi = IsMulti
|
|
>
|
|
typename std::enable_if <maybe_multi,
|
|
bool>::type
|
|
operator== (
|
|
aged_unordered_container <true, OtherIsMap,
|
|
OtherKey, OtherT, OtherDuration, OtherHash, KeyEqual,
|
|
OtherAllocator> const& other) const
|
|
{
|
|
if (size() != other.size())
|
|
return false;
|
|
typedef std::pair <const_iterator, const_iterator> EqRng;
|
|
for (auto iter (cbegin()), last (cend()); iter != last;)
|
|
{
|
|
auto const& k (extract (*iter));
|
|
auto const eq (equal_range (k));
|
|
auto const oeq (other.equal_range (k));
|
|
#if BEAST_NO_CXX14_IS_PERMUTATION
|
|
if (std::distance (eq.first, eq.second) !=
|
|
std::distance (oeq.first, oeq.second) ||
|
|
! std::is_permutation (eq.first, eq.second, oeq.first))
|
|
return false;
|
|
#else
|
|
if (! std::is_permutation (eq.first,
|
|
eq.second, oeq.first, oeq.second))
|
|
return false;
|
|
#endif
|
|
iter = eq.second;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
template <
|
|
bool OtherIsMulti,
|
|
bool OtherIsMap,
|
|
class OtherKey,
|
|
class OtherT,
|
|
class OtherDuration,
|
|
class OtherHash,
|
|
class OtherAllocator
|
|
>
|
|
bool operator!= (
|
|
aged_unordered_container <OtherIsMulti, OtherIsMap,
|
|
OtherKey, OtherT, OtherDuration, OtherHash, KeyEqual,
|
|
OtherAllocator> const& other) const
|
|
{
|
|
return ! (this->operator== (other));
|
|
}
|
|
|
|
private:
|
|
bool
|
|
would_exceed (size_type additional) const
|
|
{
|
|
return size() + additional >
|
|
bucket_count() * max_load_factor();
|
|
}
|
|
|
|
void
|
|
maybe_rehash (size_type additional)
|
|
{
|
|
if (would_exceed (additional))
|
|
m_buck.resize (size() + additional, m_cont);
|
|
assert (load_factor() <= max_load_factor());
|
|
}
|
|
|
|
// map, set
|
|
template <bool maybe_multi = IsMulti>
|
|
auto
|
|
insert_unchecked (value_type const& value) ->
|
|
typename std::enable_if <! maybe_multi,
|
|
std::pair <iterator, bool>>::type;
|
|
|
|
// multimap, multiset
|
|
template <bool maybe_multi = IsMulti>
|
|
auto
|
|
insert_unchecked (value_type const& value) ->
|
|
typename std::enable_if <maybe_multi,
|
|
iterator>::type;
|
|
|
|
template <class InputIt>
|
|
void
|
|
insert_unchecked (InputIt first, InputIt const& last)
|
|
{
|
|
for (; first != last; ++first)
|
|
insert_unchecked (*first);
|
|
}
|
|
|
|
template <class InputIt>
|
|
void
|
|
insert (InputIt first, InputIt const& last,
|
|
std::input_iterator_tag)
|
|
{
|
|
for (; first != last; ++first)
|
|
insert (*first);
|
|
}
|
|
|
|
template <class InputIt>
|
|
void
|
|
insert (InputIt first, InputIt const& last,
|
|
std::random_access_iterator_tag)
|
|
{
|
|
auto const n (std::distance (first, last));
|
|
maybe_rehash (n);
|
|
insert_unchecked (first, last);
|
|
}
|
|
|
|
template <bool is_const, class Iterator, class Base>
|
|
void
|
|
touch (detail::aged_container_iterator <
|
|
is_const, Iterator, Base> const& pos,
|
|
typename clock_type::time_point const& now)
|
|
{
|
|
auto& e (*pos.iterator());
|
|
e.when = now;
|
|
chronological.list.erase (chronological.list.iterator_to (e));
|
|
chronological.list.push_back (e);
|
|
}
|
|
|
|
template <bool maybe_propagate = std::allocator_traits <
|
|
Allocator>::propagate_on_container_swap::value>
|
|
typename std::enable_if <maybe_propagate>::type
|
|
swap_data (aged_unordered_container& other) noexcept
|
|
{
|
|
std::swap (m_config.key_compare(), other.m_config.key_compare());
|
|
std::swap (m_config.alloc(), other.m_config.alloc());
|
|
std::swap (m_config.clock, other.m_config.clock);
|
|
}
|
|
|
|
template <bool maybe_propagate = std::allocator_traits <
|
|
Allocator>::propagate_on_container_swap::value>
|
|
typename std::enable_if <! maybe_propagate>::type
|
|
swap_data (aged_unordered_container& other) noexcept
|
|
{
|
|
std::swap (m_config.key_compare(), other.m_config.key_compare());
|
|
std::swap (m_config.clock, other.m_config.clock);
|
|
}
|
|
|
|
private:
|
|
config_t m_config;
|
|
Buckets m_buck;
|
|
cont_type mutable m_cont;
|
|
};
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
aged_unordered_container (
|
|
clock_type& clock)
|
|
: m_config (clock)
|
|
, m_cont (m_buck,
|
|
std::cref (m_config.value_hash()),
|
|
std::cref (m_config.key_value_equal()))
|
|
{
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
aged_unordered_container (
|
|
clock_type& clock,
|
|
Hash const& hash)
|
|
: m_config (clock, hash)
|
|
, m_cont (m_buck,
|
|
std::cref (m_config.value_hash()),
|
|
std::cref (m_config.key_value_equal()))
|
|
{
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
aged_unordered_container (
|
|
clock_type& clock,
|
|
KeyEqual const& key_eq)
|
|
: m_config (clock, key_eq)
|
|
, m_cont (m_buck,
|
|
std::cref (m_config.value_hash()),
|
|
std::cref (m_config.key_value_equal()))
|
|
{
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
aged_unordered_container (
|
|
clock_type& clock,
|
|
Allocator const& alloc)
|
|
: m_config (clock, alloc)
|
|
, m_buck (alloc)
|
|
, m_cont (m_buck,
|
|
std::cref (m_config.value_hash()),
|
|
std::cref (m_config.key_value_equal()))
|
|
{
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
aged_unordered_container (
|
|
clock_type& clock,
|
|
Hash const& hash,
|
|
KeyEqual const& key_eq)
|
|
: m_config (clock, hash, key_eq)
|
|
, m_cont (m_buck,
|
|
std::cref (m_config.value_hash()),
|
|
std::cref (m_config.key_value_equal()))
|
|
{
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
aged_unordered_container (
|
|
clock_type& clock,
|
|
Hash const& hash,
|
|
Allocator const& alloc)
|
|
: m_config (clock, hash, alloc)
|
|
, m_buck (alloc)
|
|
, m_cont (m_buck,
|
|
std::cref (m_config.value_hash()),
|
|
std::cref (m_config.key_value_equal()))
|
|
{
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
aged_unordered_container (
|
|
clock_type& clock,
|
|
KeyEqual const& key_eq,
|
|
Allocator const& alloc)
|
|
: m_config (clock, key_eq, alloc)
|
|
, m_buck (alloc)
|
|
, m_cont (m_buck,
|
|
std::cref (m_config.value_hash()),
|
|
std::cref (m_config.key_value_equal()))
|
|
{
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
aged_unordered_container (
|
|
clock_type& clock,
|
|
Hash const& hash,
|
|
KeyEqual const& key_eq,
|
|
Allocator const& alloc)
|
|
: m_config (clock, hash, key_eq, alloc)
|
|
, m_buck (alloc)
|
|
, m_cont (m_buck,
|
|
std::cref (m_config.value_hash()),
|
|
std::cref (m_config.key_value_equal()))
|
|
{
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
template <class InputIt>
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
aged_unordered_container (InputIt first, InputIt last,
|
|
clock_type& clock)
|
|
: m_config (clock)
|
|
, m_cont (m_buck,
|
|
std::cref (m_config.value_hash()),
|
|
std::cref (m_config.key_value_equal()))
|
|
{
|
|
insert (first, last);
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
template <class InputIt>
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
aged_unordered_container (InputIt first, InputIt last,
|
|
clock_type& clock,
|
|
Hash const& hash)
|
|
: m_config (clock, hash)
|
|
, m_cont (m_buck,
|
|
std::cref (m_config.value_hash()),
|
|
std::cref (m_config.key_value_equal()))
|
|
{
|
|
insert (first, last);
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
template <class InputIt>
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
aged_unordered_container (InputIt first, InputIt last,
|
|
clock_type& clock,
|
|
KeyEqual const& key_eq)
|
|
: m_config (clock, key_eq)
|
|
, m_cont (m_buck,
|
|
std::cref (m_config.value_hash()),
|
|
std::cref (m_config.key_value_equal()))
|
|
{
|
|
insert (first, last);
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
template <class InputIt>
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
aged_unordered_container (InputIt first, InputIt last,
|
|
clock_type& clock,
|
|
Allocator const& alloc)
|
|
: m_config (clock, alloc)
|
|
, m_buck (alloc)
|
|
, m_cont (m_buck,
|
|
std::cref (m_config.value_hash()),
|
|
std::cref (m_config.key_value_equal()))
|
|
{
|
|
insert (first, last);
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
template <class InputIt>
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
aged_unordered_container (InputIt first, InputIt last,
|
|
clock_type& clock,
|
|
Hash const& hash,
|
|
KeyEqual const& key_eq)
|
|
: m_config (clock, hash, key_eq)
|
|
, m_cont (m_buck,
|
|
std::cref (m_config.value_hash()),
|
|
std::cref (m_config.key_value_equal()))
|
|
{
|
|
insert (first, last);
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
template <class InputIt>
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
aged_unordered_container (InputIt first, InputIt last,
|
|
clock_type& clock,
|
|
Hash const& hash,
|
|
Allocator const& alloc)
|
|
: m_config (clock, hash, alloc)
|
|
, m_buck (alloc)
|
|
, m_cont (m_buck,
|
|
std::cref (m_config.value_hash()),
|
|
std::cref (m_config.key_value_equal()))
|
|
{
|
|
insert (first, last);
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
template <class InputIt>
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
aged_unordered_container (InputIt first, InputIt last,
|
|
clock_type& clock,
|
|
KeyEqual const& key_eq,
|
|
Allocator const& alloc)
|
|
: m_config (clock, key_eq, alloc)
|
|
, m_buck (alloc)
|
|
, m_cont (m_buck,
|
|
std::cref (m_config.value_hash()),
|
|
std::cref (m_config.key_value_equal()))
|
|
{
|
|
insert (first, last);
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
template <class InputIt>
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
aged_unordered_container (InputIt first, InputIt last,
|
|
clock_type& clock,
|
|
Hash const& hash,
|
|
KeyEqual const& key_eq,
|
|
Allocator const& alloc)
|
|
: m_config (clock, hash, key_eq, alloc)
|
|
, m_buck (alloc)
|
|
, m_cont (m_buck,
|
|
std::cref (m_config.value_hash()),
|
|
std::cref (m_config.key_value_equal()))
|
|
{
|
|
insert (first, last);
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
aged_unordered_container (aged_unordered_container const& other)
|
|
: m_config (other.m_config)
|
|
, m_buck (m_config.alloc())
|
|
, m_cont (m_buck,
|
|
std::cref (m_config.value_hash()),
|
|
std::cref (m_config.key_value_equal()))
|
|
{
|
|
insert (other.cbegin(), other.cend());
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
aged_unordered_container (aged_unordered_container const& other,
|
|
Allocator const& alloc)
|
|
: m_config (other.m_config, alloc)
|
|
, m_buck (alloc)
|
|
, m_cont (m_buck,
|
|
std::cref (m_config.value_hash()),
|
|
std::cref (m_config.key_value_equal()))
|
|
{
|
|
insert (other.cbegin(), other.cend());
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
aged_unordered_container (aged_unordered_container&& other)
|
|
: m_config (std::move (other.m_config))
|
|
, m_buck (m_config.alloc())
|
|
, m_cont (std::move (other.m_cont))
|
|
{
|
|
chronological.list = std::move (other.chronological.list);
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
aged_unordered_container (aged_unordered_container&& other,
|
|
Allocator const& alloc)
|
|
: m_config (std::move (other.m_config), alloc)
|
|
, m_buck (alloc)
|
|
, m_cont (m_buck,
|
|
std::cref (m_config.value_hash()),
|
|
std::cref (m_config.key_value_equal()))
|
|
{
|
|
insert (other.cbegin(), other.cend());
|
|
other.clear ();
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
aged_unordered_container (std::initializer_list <value_type> init,
|
|
clock_type& clock)
|
|
: m_config (clock)
|
|
, m_cont (m_buck,
|
|
std::cref (m_config.value_hash()),
|
|
std::cref (m_config.key_value_equal()))
|
|
{
|
|
insert (init.begin(), init.end());
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
aged_unordered_container (std::initializer_list <value_type> init,
|
|
clock_type& clock,
|
|
Hash const& hash)
|
|
: m_config (clock, hash)
|
|
, m_cont (m_buck,
|
|
std::cref (m_config.value_hash()),
|
|
std::cref (m_config.key_value_equal()))
|
|
{
|
|
insert (init.begin(), init.end());
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
aged_unordered_container (std::initializer_list <value_type> init,
|
|
clock_type& clock,
|
|
KeyEqual const& key_eq)
|
|
: m_config (clock, key_eq)
|
|
, m_cont (m_buck,
|
|
std::cref (m_config.value_hash()),
|
|
std::cref (m_config.key_value_equal()))
|
|
{
|
|
insert (init.begin(), init.end());
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
aged_unordered_container (std::initializer_list <value_type> init,
|
|
clock_type& clock,
|
|
Allocator const& alloc)
|
|
: m_config (clock, alloc)
|
|
, m_buck (alloc)
|
|
, m_cont (m_buck,
|
|
std::cref (m_config.value_hash()),
|
|
std::cref (m_config.key_value_equal()))
|
|
{
|
|
insert (init.begin(), init.end());
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
aged_unordered_container (std::initializer_list <value_type> init,
|
|
clock_type& clock,
|
|
Hash const& hash,
|
|
KeyEqual const& key_eq)
|
|
: m_config (clock, hash, key_eq)
|
|
, m_cont (m_buck,
|
|
std::cref (m_config.value_hash()),
|
|
std::cref (m_config.key_value_equal()))
|
|
{
|
|
insert (init.begin(), init.end());
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
aged_unordered_container (std::initializer_list <value_type> init,
|
|
clock_type& clock,
|
|
Hash const& hash,
|
|
Allocator const& alloc)
|
|
: m_config (clock, hash, alloc)
|
|
, m_buck (alloc)
|
|
, m_cont (m_buck,
|
|
std::cref (m_config.value_hash()),
|
|
std::cref (m_config.key_value_equal()))
|
|
{
|
|
insert (init.begin(), init.end());
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
aged_unordered_container (std::initializer_list <value_type> init,
|
|
clock_type& clock,
|
|
KeyEqual const& key_eq,
|
|
Allocator const& alloc)
|
|
: m_config (clock, key_eq, alloc)
|
|
, m_buck (alloc)
|
|
, m_cont (m_buck,
|
|
std::cref (m_config.value_hash()),
|
|
std::cref (m_config.key_value_equal()))
|
|
{
|
|
insert (init.begin(), init.end());
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
aged_unordered_container (std::initializer_list <value_type> init,
|
|
clock_type& clock,
|
|
Hash const& hash,
|
|
KeyEqual const& key_eq,
|
|
Allocator const& alloc)
|
|
: m_config (clock, hash, key_eq, alloc)
|
|
, m_buck (alloc)
|
|
, m_cont (m_buck,
|
|
std::cref (m_config.value_hash()),
|
|
std::cref (m_config.key_value_equal()))
|
|
{
|
|
insert (init.begin(), init.end());
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
~aged_unordered_container()
|
|
{
|
|
clear();
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
auto
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
operator= (aged_unordered_container const& other)
|
|
-> aged_unordered_container&
|
|
{
|
|
if (this != &other)
|
|
{
|
|
size_type const n (other.size());
|
|
clear();
|
|
m_config = other.m_config;
|
|
m_buck = Buckets (m_config.alloc());
|
|
maybe_rehash (n);
|
|
insert_unchecked (other.begin(), other.end());
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
auto
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
operator= (aged_unordered_container&& other) ->
|
|
aged_unordered_container&
|
|
{
|
|
size_type const n (other.size());
|
|
clear();
|
|
m_config = std::move (other.m_config);
|
|
m_buck = Buckets (m_config.alloc());
|
|
maybe_rehash (n);
|
|
insert_unchecked (other.begin(), other.end());
|
|
other.clear();
|
|
return *this;
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
auto
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
operator= (std::initializer_list <value_type> init) ->
|
|
aged_unordered_container&
|
|
{
|
|
clear ();
|
|
insert (init);
|
|
return *this;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
template <class K, bool maybe_multi, bool maybe_map, class>
|
|
typename std::conditional <IsMap, T, void*>::type&
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
at (K const& k)
|
|
{
|
|
auto const iter (m_cont.find (k,
|
|
std::cref (m_config.hash_function()),
|
|
std::cref (m_config.key_value_equal())));
|
|
if (iter == m_cont.end())
|
|
throw std::out_of_range ("key not found");
|
|
return iter->value.second;
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
template <class K, bool maybe_multi, bool maybe_map, class>
|
|
typename std::conditional <IsMap, T, void*>::type const&
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
at (K const& k) const
|
|
{
|
|
auto const iter (m_cont.find (k,
|
|
std::cref (m_config.hash_function()),
|
|
std::cref (m_config.key_value_equal())));
|
|
if (iter == m_cont.end())
|
|
throw std::out_of_range ("key not found");
|
|
return iter->value.second;
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
template <bool maybe_multi, bool maybe_map, class>
|
|
typename std::conditional <IsMap, T, void*>::type&
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
operator[] (Key const& key)
|
|
{
|
|
maybe_rehash (1);
|
|
typename cont_type::insert_commit_data d;
|
|
auto const result (m_cont.insert_check (key,
|
|
std::cref (m_config.hash_function()),
|
|
std::cref (m_config.key_value_equal()), d));
|
|
if (result.second)
|
|
{
|
|
element* const p (new_element (
|
|
std::piecewise_construct,
|
|
std::forward_as_tuple (key),
|
|
std::forward_as_tuple ()));
|
|
chronological.list.push_back (*p);
|
|
m_cont.insert_commit (*p, d);
|
|
return p->value.second;
|
|
}
|
|
return result.first->value.second;
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
template <bool maybe_multi, bool maybe_map, class>
|
|
typename std::conditional <IsMap, T, void*>::type&
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
operator[] (Key&& key)
|
|
{
|
|
maybe_rehash (1);
|
|
typename cont_type::insert_commit_data d;
|
|
auto const result (m_cont.insert_check (key,
|
|
std::cref (m_config.hash_function()),
|
|
std::cref (m_config.key_value_equal()), d));
|
|
if (result.second)
|
|
{
|
|
element* const p (new_element (
|
|
std::piecewise_construct,
|
|
std::forward_as_tuple (std::move (key)),
|
|
std::forward_as_tuple ()));
|
|
chronological.list.push_back (*p);
|
|
m_cont.insert_commit (*p, d);
|
|
return p->value.second;
|
|
}
|
|
return result.first->value.second;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
void
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
clear()
|
|
{
|
|
for (auto iter (chronological.list.begin());
|
|
iter != chronological.list.end();)
|
|
unlink_and_delete_element (&*iter++);
|
|
chronological.list.clear();
|
|
m_cont.clear();
|
|
m_buck.clear();
|
|
}
|
|
|
|
// map, set
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
template <bool maybe_multi>
|
|
auto
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
insert (value_type const& value) ->
|
|
typename std::enable_if <! maybe_multi,
|
|
std::pair <iterator, bool>>::type
|
|
{
|
|
maybe_rehash (1);
|
|
typename cont_type::insert_commit_data d;
|
|
auto const result (m_cont.insert_check (extract (value),
|
|
std::cref (m_config.hash_function()),
|
|
std::cref (m_config.key_value_equal()), d));
|
|
if (result.second)
|
|
{
|
|
element* const p (new_element (value));
|
|
chronological.list.push_back (*p);
|
|
auto const iter (m_cont.insert_commit (*p, d));
|
|
return std::make_pair (iterator (iter), true);
|
|
}
|
|
return std::make_pair (iterator (result.first), false);
|
|
}
|
|
|
|
// multimap, multiset
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
template <bool maybe_multi>
|
|
auto
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
insert (value_type const& value) ->
|
|
typename std::enable_if <maybe_multi,
|
|
iterator>::type
|
|
{
|
|
maybe_rehash (1);
|
|
element* const p (new_element (value));
|
|
chronological.list.push_back (*p);
|
|
auto const iter (m_cont.insert (*p));
|
|
return iterator (iter);
|
|
}
|
|
|
|
// map, set
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
template <bool maybe_multi, bool maybe_map>
|
|
auto
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
insert (value_type&& value) ->
|
|
typename std::enable_if <! maybe_multi && ! maybe_map,
|
|
std::pair <iterator, bool>>::type
|
|
{
|
|
maybe_rehash (1);
|
|
typename cont_type::insert_commit_data d;
|
|
auto const result (m_cont.insert_check (extract (value),
|
|
std::cref (m_config.hash_function()),
|
|
std::cref (m_config.key_value_equal()), d));
|
|
if (result.second)
|
|
{
|
|
element* const p (new_element (std::move (value)));
|
|
chronological.list.push_back (*p);
|
|
auto const iter (m_cont.insert_commit (*p, d));
|
|
return std::make_pair (iterator (iter), true);
|
|
}
|
|
return std::make_pair (iterator (result.first), false);
|
|
}
|
|
|
|
// multimap, multiset
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
template <bool maybe_multi, bool maybe_map>
|
|
auto
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
insert (value_type&& value) ->
|
|
typename std::enable_if <maybe_multi && ! maybe_map,
|
|
iterator>::type
|
|
{
|
|
maybe_rehash (1);
|
|
element* const p (new_element (std::move (value)));
|
|
chronological.list.push_back (*p);
|
|
auto const iter (m_cont.insert (*p));
|
|
return iterator (iter);
|
|
}
|
|
|
|
// set, map
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
template <bool maybe_multi, class... Args>
|
|
auto
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
emplace (Args&&... args) ->
|
|
typename std::enable_if <! maybe_multi,
|
|
std::pair <iterator, bool>>::type
|
|
{
|
|
maybe_rehash (1);
|
|
// VFALCO NOTE Its unfortunate that we need to
|
|
// construct element here
|
|
element* const p (new_element (
|
|
std::forward <Args> (args)...));
|
|
typename cont_type::insert_commit_data d;
|
|
auto const result (m_cont.insert_check (extract (p->value),
|
|
std::cref (m_config.hash_function()),
|
|
std::cref (m_config.key_value_equal()), d));
|
|
if (result.second)
|
|
{
|
|
chronological.list.push_back (*p);
|
|
auto const iter (m_cont.insert_commit (*p, d));
|
|
return std::make_pair (iterator (iter), true);
|
|
}
|
|
delete_element (p);
|
|
return std::make_pair (iterator (result.first), false);
|
|
}
|
|
|
|
// multiset, multimap
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
template <bool maybe_multi, class... Args>
|
|
auto
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
emplace (Args&&... args) ->
|
|
typename std::enable_if <maybe_multi,
|
|
iterator>::type
|
|
{
|
|
maybe_rehash (1);
|
|
element* const p (new_element (
|
|
std::forward <Args> (args)...));
|
|
chronological.list.push_back (*p);
|
|
auto const iter (m_cont.insert (*p));
|
|
return iterator (iter);
|
|
}
|
|
|
|
// set, map
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
template <bool maybe_multi, class... Args>
|
|
auto
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
emplace_hint (const_iterator const& /*hint*/, Args&&... args) ->
|
|
typename std::enable_if <! maybe_multi,
|
|
std::pair <iterator, bool>>::type
|
|
{
|
|
maybe_rehash (1);
|
|
// VFALCO NOTE Its unfortunate that we need to
|
|
// construct element here
|
|
element* const p (new_element (
|
|
std::forward <Args> (args)...));
|
|
typename cont_type::insert_commit_data d;
|
|
auto const result (m_cont.insert_check (extract (p->value),
|
|
std::cref (m_config.hash_function()),
|
|
std::cref (m_config.key_value_equal()), d));
|
|
if (result.second)
|
|
{
|
|
chronological.list.push_back (*p);
|
|
auto const iter (m_cont.insert_commit (*p, d));
|
|
return std::make_pair (iterator (iter), true);
|
|
}
|
|
delete_element (p);
|
|
return std::make_pair (iterator (result.first), false);
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
template <bool is_const, class Iterator, class Base>
|
|
detail::aged_container_iterator <false, Iterator, Base>
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
erase (detail::aged_container_iterator <
|
|
is_const, Iterator, Base> const& pos)
|
|
{
|
|
auto iter (pos.iterator());
|
|
auto p (&*iter++);
|
|
unlink_and_delete_element (p);
|
|
return detail::aged_container_iterator <
|
|
false, Iterator, Base> (iter);
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
template <bool is_const, class Iterator, class Base>
|
|
detail::aged_container_iterator <false, Iterator, Base>
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
erase (detail::aged_container_iterator <
|
|
is_const, Iterator, Base> first,
|
|
detail::aged_container_iterator <
|
|
is_const, Iterator, Base> const& last)
|
|
{
|
|
size_type n (0);
|
|
for (; first != last; ++n)
|
|
{
|
|
auto p (&*first++);
|
|
unlink_and_delete_element (p);
|
|
}
|
|
return detail::aged_container_iterator <
|
|
false, Iterator, Base> (first.iterator());
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
template <class K>
|
|
auto
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
erase (K const& k) ->
|
|
size_type
|
|
{
|
|
auto iter (m_cont.find (k, std::cref (m_config.hash_function()),
|
|
std::cref (m_config.key_value_equal())));
|
|
if (iter == m_cont.end())
|
|
return 0;
|
|
size_type n (0);
|
|
for (;;)
|
|
{
|
|
auto p (&*iter++);
|
|
bool const done (
|
|
m_config (*p, extract (iter->value)));
|
|
unlink_and_delete_element (p);
|
|
++n;
|
|
if (done)
|
|
break;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
void
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
swap (aged_unordered_container& other) noexcept
|
|
{
|
|
swap_data (other);
|
|
std::swap (chronological, other.chronological);
|
|
std::swap (m_cont, other.m_cont);
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
template <class K>
|
|
auto
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
touch (K const& k) ->
|
|
size_type
|
|
{
|
|
auto const now (clock().now());
|
|
size_type n (0);
|
|
auto const range (equal_range (k));
|
|
for (auto iter : range)
|
|
{
|
|
touch (iter, now);
|
|
++n;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// map, set
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
template <bool maybe_multi>
|
|
auto
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
insert_unchecked (value_type const& value) ->
|
|
typename std::enable_if <! maybe_multi,
|
|
std::pair <iterator, bool>>::type
|
|
{
|
|
typename cont_type::insert_commit_data d;
|
|
auto const result (m_cont.insert_check (extract (value),
|
|
std::cref (m_config.hash_function()),
|
|
std::cref (m_config.key_value_equal()), d));
|
|
if (result.second)
|
|
{
|
|
element* const p (new_element (value));
|
|
chronological.list.push_back (*p);
|
|
auto const iter (m_cont.insert_commit (*p, d));
|
|
return std::make_pair (iterator (iter), true);
|
|
}
|
|
return std::make_pair (iterator (result.first), false);
|
|
}
|
|
|
|
// multimap, multiset
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
template <bool maybe_multi>
|
|
auto
|
|
aged_unordered_container <IsMulti, IsMap, Key, T, Duration,
|
|
Hash, KeyEqual, Allocator>::
|
|
insert_unchecked (value_type const& value) ->
|
|
typename std::enable_if <maybe_multi,
|
|
iterator>::type
|
|
{
|
|
element* const p (new_element (value));
|
|
chronological.list.push_back (*p);
|
|
auto const iter (m_cont.insert (*p));
|
|
return iterator (iter);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator>
|
|
struct is_aged_container <detail::aged_unordered_container <
|
|
IsMulti, IsMap, Key, T, Duration, Hash, KeyEqual, Allocator>>
|
|
: std::true_type
|
|
{
|
|
};
|
|
|
|
// Free functions
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T, class Duration,
|
|
class Hash, class KeyEqual, class Allocator>
|
|
void swap (
|
|
detail::aged_unordered_container <IsMulti, IsMap,
|
|
Key, T, Duration, Hash, KeyEqual, Allocator>& lhs,
|
|
detail::aged_unordered_container <IsMulti, IsMap,
|
|
Key, T, Duration, Hash, KeyEqual, Allocator>& rhs) noexcept
|
|
{
|
|
lhs.swap (rhs);
|
|
}
|
|
|
|
/** Expire aged container items past the specified age. */
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Duration, class Hash, class KeyEqual, class Allocator,
|
|
class Rep, class Period>
|
|
std::size_t expire (detail::aged_unordered_container <
|
|
IsMulti, IsMap, Key, T, Duration, Hash, KeyEqual, Allocator>& c,
|
|
std::chrono::duration <Rep, Period> const& age) noexcept
|
|
{
|
|
std::size_t n (0);
|
|
auto const expired (c.clock().now() - age);
|
|
for (auto iter (c.chronological.cbegin());
|
|
iter != c.chronological.cend() &&
|
|
iter.when() <= expired;)
|
|
{
|
|
iter = c.erase (iter);
|
|
++n;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|