mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-19 18:45:52 +00:00
The abstract_clock is now templated on a type meeting the requirements of the Clock concept. It inherits the nested types of the Clock on which it is based. This resolves a problem with the original design which broke the type-safety of time_point from different abstract clocks.
1945 lines
58 KiB
C++
1945 lines
58 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_ORDERED_CONTAINER_H_INCLUDED
|
|
#define BEAST_CONTAINER_AGED_ORDERED_CONTAINER_H_INCLUDED
|
|
|
|
#include <beast/container/detail/aged_container_iterator.h>
|
|
#include <beast/container/detail/aged_associative_container.h>
|
|
#include <beast/container/aged_container.h>
|
|
#include <beast/chrono/abstract_clock.h>
|
|
#include <beast/utility/empty_base_optimization.h>
|
|
#include <boost/intrusive/list.hpp>
|
|
#include <boost/intrusive/set.hpp>
|
|
#include <beast/cxx14/algorithm.h> // <algorithm>
|
|
#include <functional>
|
|
#include <initializer_list>
|
|
#include <iterator>
|
|
#include <memory>
|
|
#include <beast/cxx14/type_traits.h> // <type_traits>
|
|
#include <utility>
|
|
|
|
namespace beast {
|
|
namespace detail {
|
|
|
|
// Traits templates used to discern reverse_iterators, which are disallowed
|
|
// for mutating operations.
|
|
template <class It>
|
|
struct is_boost_reverse_iterator
|
|
: std::false_type
|
|
{};
|
|
|
|
template <class It>
|
|
struct is_boost_reverse_iterator<boost::intrusive::detail::reverse_iterator<It>>
|
|
: std::true_type
|
|
{};
|
|
|
|
/** Associative container where each element is also indexed by time.
|
|
|
|
This container mirrors the interface of the standard library ordered
|
|
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_set, aged_multiset, aged_map, aged_multimap
|
|
*/
|
|
template <
|
|
bool IsMulti,
|
|
bool IsMap,
|
|
class Key,
|
|
class T,
|
|
class Clock = std::chrono::steady_clock,
|
|
class Compare = std::less <Key>,
|
|
class Allocator = std::allocator <
|
|
typename std::conditional <IsMap,
|
|
std::pair <Key const, T>,
|
|
Key>::type>
|
|
>
|
|
class aged_ordered_container
|
|
{
|
|
public:
|
|
using clock_type = abstract_clock<Clock>;
|
|
using time_point = typename clock_type::time_point;
|
|
using duration = typename clock_type::duration;
|
|
using key_type = Key;
|
|
using mapped_type = T;
|
|
using value_type = typename std::conditional <
|
|
IsMap, std::pair <Key const, T>, Key>::type;
|
|
using size_type = std::size_t;
|
|
using difference_type = std::ptrdiff_t;
|
|
|
|
// Introspection (for unit tests)
|
|
using is_unordered = std::false_type;
|
|
using is_multi = std::integral_constant <bool, IsMulti>;
|
|
using is_map = std::integral_constant <bool, IsMap>;
|
|
|
|
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::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_ordered_container::value_type value_type;
|
|
typedef typename aged_ordered_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 This should only be enabled for maps.
|
|
class pair_value_compare
|
|
: private empty_base_optimization <Compare>
|
|
, public std::binary_function <value_type, value_type, bool>
|
|
{
|
|
public:
|
|
bool operator() (value_type const& lhs, value_type const& rhs) const
|
|
{
|
|
return this->member() (lhs.first, rhs.first);
|
|
}
|
|
|
|
pair_value_compare ()
|
|
{
|
|
}
|
|
|
|
pair_value_compare (pair_value_compare const& other)
|
|
: empty_base_optimization <Compare> (other)
|
|
{
|
|
}
|
|
|
|
private:
|
|
friend aged_ordered_container;
|
|
|
|
pair_value_compare (Compare const& compare)
|
|
: empty_base_optimization <Compare> (compare)
|
|
{
|
|
}
|
|
};
|
|
|
|
// Compares value_type against element, used in insert_check
|
|
// VFALCO TODO hoist to remove template argument dependencies
|
|
class KeyValueCompare
|
|
: private empty_base_optimization <Compare>
|
|
, public std::binary_function <Key, element, bool>
|
|
{
|
|
public:
|
|
KeyValueCompare ()
|
|
{
|
|
}
|
|
|
|
KeyValueCompare (Compare const& compare)
|
|
: empty_base_optimization <Compare> (compare)
|
|
{
|
|
}
|
|
|
|
// VFALCO NOTE WE might want only to enable these overloads
|
|
// if Compare 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);
|
|
}
|
|
|
|
Compare& compare()
|
|
{
|
|
return empty_base_optimization <Compare>::member();
|
|
}
|
|
|
|
Compare const& compare() const
|
|
{
|
|
return empty_base_optimization <Compare>::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_multiset <element,
|
|
boost::intrusive::constant_time_size <true>
|
|
>::type,
|
|
typename boost::intrusive::make_set <element,
|
|
boost::intrusive::constant_time_size <true>
|
|
>::type
|
|
>::type cont_type;
|
|
|
|
typedef typename std::allocator_traits <
|
|
Allocator>::template rebind_alloc <element> ElementAllocator;
|
|
|
|
using ElementAllocatorTraits = std::allocator_traits <ElementAllocator>;
|
|
|
|
class config_t
|
|
: private KeyValueCompare
|
|
, private empty_base_optimization <ElementAllocator>
|
|
{
|
|
public:
|
|
explicit config_t (
|
|
clock_type& clock_)
|
|
: clock (clock_)
|
|
{
|
|
}
|
|
|
|
config_t (
|
|
clock_type& clock_,
|
|
Compare const& comp)
|
|
: KeyValueCompare (comp)
|
|
, clock (clock_)
|
|
{
|
|
}
|
|
|
|
config_t (
|
|
clock_type& clock_,
|
|
Allocator const& alloc_)
|
|
: empty_base_optimization <ElementAllocator> (alloc_)
|
|
, clock (clock_)
|
|
{
|
|
}
|
|
|
|
config_t (
|
|
clock_type& clock_,
|
|
Compare const& comp,
|
|
Allocator const& alloc_)
|
|
: KeyValueCompare (comp)
|
|
, empty_base_optimization <ElementAllocator> (alloc_)
|
|
, clock (clock_)
|
|
{
|
|
}
|
|
|
|
config_t (config_t const& other)
|
|
: KeyValueCompare (other.key_compare())
|
|
, empty_base_optimization <ElementAllocator> (
|
|
ElementAllocatorTraits::
|
|
select_on_container_copy_construction (
|
|
other.alloc()))
|
|
, clock (other.clock)
|
|
{
|
|
}
|
|
|
|
config_t (config_t const& other, Allocator const& alloc)
|
|
: KeyValueCompare (other.key_compare())
|
|
, empty_base_optimization <ElementAllocator> (alloc)
|
|
, clock (other.clock)
|
|
{
|
|
}
|
|
|
|
config_t (config_t&& other)
|
|
: KeyValueCompare (std::move (other.key_compare()))
|
|
, empty_base_optimization <ElementAllocator> (
|
|
std::move (other))
|
|
, clock (other.clock)
|
|
{
|
|
}
|
|
|
|
config_t (config_t&& other, Allocator const& alloc)
|
|
: KeyValueCompare (std::move (other.key_compare()))
|
|
, empty_base_optimization <ElementAllocator> (alloc)
|
|
, clock (other.clock)
|
|
{
|
|
}
|
|
|
|
config_t& operator= (config_t const& other)
|
|
{
|
|
if (this != &other)
|
|
{
|
|
compare() = other.compare();
|
|
alloc() = other.alloc();
|
|
clock = other.clock;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
config_t& operator= (config_t&& other)
|
|
{
|
|
compare() = std::move (other.compare());
|
|
alloc() = std::move (other.alloc());
|
|
clock = other.clock;
|
|
return *this;
|
|
}
|
|
|
|
Compare& compare ()
|
|
{
|
|
return KeyValueCompare::compare();
|
|
}
|
|
|
|
Compare const& compare () const
|
|
{
|
|
return KeyValueCompare::compare();
|
|
}
|
|
|
|
KeyValueCompare& key_compare()
|
|
{
|
|
return *this;
|
|
}
|
|
|
|
KeyValueCompare const& key_compare() const
|
|
{
|
|
return *this;
|
|
}
|
|
|
|
ElementAllocator& alloc()
|
|
{
|
|
return empty_base_optimization <
|
|
ElementAllocator>::member();
|
|
}
|
|
|
|
ElementAllocator const& alloc() const
|
|
{
|
|
return empty_base_optimization <
|
|
ElementAllocator>::member();
|
|
}
|
|
|
|
std::reference_wrapper <clock_type> clock;
|
|
};
|
|
|
|
template <class... Args>
|
|
element* new_element (Args&&... args)
|
|
{
|
|
struct Deleter
|
|
{
|
|
std::reference_wrapper <ElementAllocator> a_;
|
|
Deleter (ElementAllocator& a)
|
|
: a_(a)
|
|
{
|
|
}
|
|
|
|
void
|
|
operator()(element* p)
|
|
{
|
|
ElementAllocatorTraits::deallocate (a_.get(), p, 1);
|
|
}
|
|
};
|
|
|
|
std::unique_ptr <element, Deleter> p (ElementAllocatorTraits::allocate (
|
|
m_config.alloc(), 1), Deleter(m_config.alloc()));
|
|
ElementAllocatorTraits::construct (m_config.alloc(),
|
|
p.get(), clock().now(), std::forward <Args> (args)...);
|
|
return p.release();
|
|
}
|
|
|
|
void delete_element (element const* p)
|
|
{
|
|
ElementAllocatorTraits::destroy (m_config.alloc(), p);
|
|
ElementAllocatorTraits::deallocate (
|
|
m_config.alloc(), const_cast<element*>(p), 1);
|
|
}
|
|
|
|
void unlink_and_delete_element (element const* p)
|
|
{
|
|
chronological.list.erase (
|
|
chronological.list.iterator_to (*p));
|
|
m_cont.erase (m_cont.iterator_to (*p));
|
|
delete_element (p);
|
|
}
|
|
|
|
public:
|
|
typedef Compare key_compare;
|
|
typedef typename std::conditional <
|
|
IsMap,
|
|
pair_value_compare,
|
|
Compare>::type value_compare;
|
|
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;
|
|
|
|
// A set (that is, !IsMap) iterator is aways const because the elements
|
|
// of a set are immutable.
|
|
typedef detail::aged_container_iterator <!IsMap,
|
|
typename cont_type::iterator> iterator;
|
|
typedef detail::aged_container_iterator <true,
|
|
typename cont_type::iterator> const_iterator;
|
|
typedef detail::aged_container_iterator <!IsMap,
|
|
typename cont_type::reverse_iterator> reverse_iterator;
|
|
typedef detail::aged_container_iterator <true,
|
|
typename cont_type::reverse_iterator> const_reverse_iterator;
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// Chronological ordered iterators
|
|
//
|
|
// "Memberspace"
|
|
// http://accu.org/index.php/journals/1527
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
class chronological_t
|
|
{
|
|
public:
|
|
// A set (that is, !IsMap) iterator is aways const because the elements
|
|
// of a set are immutable.
|
|
typedef detail::aged_container_iterator <!IsMap,
|
|
typename list_type::iterator> iterator;
|
|
typedef detail::aged_container_iterator <true,
|
|
typename list_type::iterator> const_iterator;
|
|
typedef detail::aged_container_iterator <!IsMap,
|
|
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_ordered_container;
|
|
list_type mutable list;
|
|
} chronological;
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// Construction
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
explicit aged_ordered_container (clock_type& clock);
|
|
|
|
aged_ordered_container (clock_type& clock,
|
|
Compare const& comp);
|
|
|
|
aged_ordered_container (clock_type& clock,
|
|
Allocator const& alloc);
|
|
|
|
aged_ordered_container (clock_type& clock,
|
|
Compare const& comp, Allocator const& alloc);
|
|
|
|
template <class InputIt>
|
|
aged_ordered_container (InputIt first, InputIt last, clock_type& clock);
|
|
|
|
template <class InputIt>
|
|
aged_ordered_container (InputIt first, InputIt last, clock_type& clock,
|
|
Compare const& comp);
|
|
|
|
template <class InputIt>
|
|
aged_ordered_container (InputIt first, InputIt last, clock_type& clock,
|
|
Allocator const& alloc);
|
|
|
|
template <class InputIt>
|
|
aged_ordered_container (InputIt first, InputIt last, clock_type& clock,
|
|
Compare const& comp, Allocator const& alloc);
|
|
|
|
aged_ordered_container (aged_ordered_container const& other);
|
|
|
|
aged_ordered_container (aged_ordered_container const& other,
|
|
Allocator const& alloc);
|
|
|
|
aged_ordered_container (aged_ordered_container&& other);
|
|
|
|
aged_ordered_container (aged_ordered_container&& other,
|
|
Allocator const& alloc);
|
|
|
|
aged_ordered_container (std::initializer_list <value_type> init,
|
|
clock_type& clock);
|
|
|
|
aged_ordered_container (std::initializer_list <value_type> init,
|
|
clock_type& clock, Compare const& comp);
|
|
|
|
aged_ordered_container (std::initializer_list <value_type> init,
|
|
clock_type& clock, Allocator const& alloc);
|
|
|
|
aged_ordered_container (std::initializer_list <value_type> init,
|
|
clock_type& clock, Compare const& comp, Allocator const& alloc);
|
|
|
|
~aged_ordered_container();
|
|
|
|
aged_ordered_container&
|
|
operator= (aged_ordered_container const& other);
|
|
|
|
aged_ordered_container&
|
|
operator= (aged_ordered_container&& other);
|
|
|
|
aged_ordered_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 ());
|
|
}
|
|
|
|
reverse_iterator
|
|
rbegin ()
|
|
{
|
|
return reverse_iterator (m_cont.rbegin());
|
|
}
|
|
|
|
const_reverse_iterator
|
|
rbegin () const
|
|
{
|
|
return const_reverse_iterator (m_cont.rbegin ());
|
|
}
|
|
|
|
const_reverse_iterator
|
|
crbegin() const
|
|
{
|
|
return const_reverse_iterator (m_cont.rbegin ());
|
|
}
|
|
|
|
reverse_iterator
|
|
rend ()
|
|
{
|
|
return reverse_iterator (m_cont.rend ());
|
|
}
|
|
|
|
const_reverse_iterator
|
|
rend () const
|
|
{
|
|
return const_reverse_iterator (m_cont.rend ());
|
|
}
|
|
|
|
const_reverse_iterator
|
|
crend () const
|
|
{
|
|
return const_reverse_iterator (m_cont.rend ());
|
|
}
|
|
|
|
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;
|
|
|
|
// 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;
|
|
|
|
// 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>
|
|
auto
|
|
insert (const_iterator hint, value_type const& value) ->
|
|
typename std::enable_if <! maybe_multi,
|
|
iterator>::type;
|
|
|
|
// multimap, multiset
|
|
template <bool maybe_multi = IsMulti>
|
|
typename std::enable_if <maybe_multi,
|
|
iterator>::type
|
|
insert (const_iterator /*hint*/, value_type const& value)
|
|
{
|
|
// VFALCO TODO Figure out how to utilize 'hint'
|
|
return insert (value);
|
|
}
|
|
|
|
// map, set
|
|
template <bool maybe_multi = IsMulti>
|
|
auto
|
|
insert (const_iterator hint, value_type&& value) ->
|
|
typename std::enable_if <! maybe_multi,
|
|
iterator>::type;
|
|
|
|
// multimap, multiset
|
|
template <bool maybe_multi = IsMulti>
|
|
typename std::enable_if <maybe_multi,
|
|
iterator>::type
|
|
insert (const_iterator /*hint*/, value_type&& value)
|
|
{
|
|
// VFALCO TODO Figure out how to utilize 'hint'
|
|
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 last)
|
|
{
|
|
for (; first != last; ++first)
|
|
insert (cend(), *first);
|
|
}
|
|
|
|
void
|
|
insert (std::initializer_list <value_type> init)
|
|
{
|
|
insert (init.begin(), init.end());
|
|
}
|
|
|
|
// map, set
|
|
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;
|
|
|
|
// map, set
|
|
template <bool maybe_multi = IsMulti, class... Args>
|
|
auto
|
|
emplace_hint (const_iterator 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 /*hint*/, Args&&... args)
|
|
{
|
|
// VFALCO TODO Figure out how to utilize 'hint'
|
|
return emplace <maybe_multi> (
|
|
std::forward <Args> (args)...);
|
|
}
|
|
|
|
// enable_if prevents erase (reverse_iterator pos) from compiling
|
|
template <bool is_const, class Iterator, class Base,
|
|
class = std::enable_if_t<!is_boost_reverse_iterator<Iterator>::value>>
|
|
detail::aged_container_iterator <false, Iterator, Base>
|
|
erase (detail::aged_container_iterator <is_const, Iterator, Base> pos);
|
|
|
|
// enable_if prevents erase (reverse_iterator first, reverse_iterator last)
|
|
// from compiling
|
|
template <bool is_const, class Iterator, class Base,
|
|
class = std::enable_if_t<!is_boost_reverse_iterator<Iterator>::value>>
|
|
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> last);
|
|
|
|
template <class K>
|
|
auto
|
|
erase (K const& k) ->
|
|
size_type;
|
|
|
|
void
|
|
swap (aged_ordered_container& other) noexcept;
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// enable_if prevents touch (reverse_iterator pos) from compiling
|
|
template <bool is_const, class Iterator, class Base,
|
|
class = std::enable_if_t<!is_boost_reverse_iterator<Iterator>::value>>
|
|
void
|
|
touch (detail::aged_container_iterator <is_const, Iterator, Base> pos)
|
|
{
|
|
touch (pos, clock().now());
|
|
}
|
|
|
|
template <class K>
|
|
size_type
|
|
touch (K const& k);
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// 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.key_compare()));
|
|
}
|
|
|
|
// 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.key_compare())));
|
|
}
|
|
|
|
// 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.key_compare())));
|
|
}
|
|
|
|
// 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.key_compare())));
|
|
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.key_compare())));
|
|
return std::make_pair (const_iterator (r.first),
|
|
const_iterator (r.second));
|
|
}
|
|
|
|
// VFALCO TODO Respect is_transparent (c++14)
|
|
template <class K>
|
|
iterator
|
|
lower_bound (K const& k)
|
|
{
|
|
return iterator (m_cont.lower_bound (k,
|
|
std::cref (m_config.key_compare())));
|
|
}
|
|
|
|
// VFALCO TODO Respect is_transparent (c++14)
|
|
template <class K>
|
|
const_iterator
|
|
lower_bound (K const& k) const
|
|
{
|
|
return const_iterator (m_cont.lower_bound (k,
|
|
std::cref (m_config.key_compare())));
|
|
}
|
|
|
|
// VFALCO TODO Respect is_transparent (c++14)
|
|
template <class K>
|
|
iterator
|
|
upper_bound (K const& k)
|
|
{
|
|
return iterator (m_cont.upper_bound (k,
|
|
std::cref (m_config.key_compare())));
|
|
}
|
|
|
|
// VFALCO TODO Respect is_transparent (c++14)
|
|
template <class K>
|
|
const_iterator
|
|
upper_bound (K const& k) const
|
|
{
|
|
return const_iterator (m_cont.upper_bound (k,
|
|
std::cref (m_config.key_compare())));
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// Observers
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
key_compare
|
|
key_comp() const
|
|
{
|
|
return m_config.compare();
|
|
}
|
|
|
|
// VFALCO TODO Should this return const reference for set?
|
|
value_compare
|
|
value_comp() const
|
|
{
|
|
return value_compare (m_config.compare());
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// 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 OtherIsMulti,
|
|
bool OtherIsMap,
|
|
class OtherT,
|
|
class OtherDuration,
|
|
class OtherAllocator
|
|
>
|
|
bool
|
|
operator== (
|
|
aged_ordered_container <OtherIsMulti, OtherIsMap,
|
|
Key, OtherT, OtherDuration, Compare,
|
|
OtherAllocator> const& other) const;
|
|
|
|
template <
|
|
bool OtherIsMulti,
|
|
bool OtherIsMap,
|
|
class OtherT,
|
|
class OtherDuration,
|
|
class OtherAllocator
|
|
>
|
|
bool
|
|
operator!= (
|
|
aged_ordered_container <OtherIsMulti, OtherIsMap,
|
|
Key, OtherT, OtherDuration, Compare,
|
|
OtherAllocator> const& other) const
|
|
{
|
|
return ! (this->operator== (other));
|
|
}
|
|
|
|
template <
|
|
bool OtherIsMulti,
|
|
bool OtherIsMap,
|
|
class OtherT,
|
|
class OtherDuration,
|
|
class OtherAllocator
|
|
>
|
|
bool
|
|
operator< (
|
|
aged_ordered_container <OtherIsMulti, OtherIsMap,
|
|
Key, OtherT, OtherDuration, Compare,
|
|
OtherAllocator> const& other) const
|
|
{
|
|
value_compare const comp (value_comp ());
|
|
return std::lexicographical_compare (
|
|
cbegin(), cend(), other.cbegin(), other.cend(), comp);
|
|
}
|
|
|
|
template <
|
|
bool OtherIsMulti,
|
|
bool OtherIsMap,
|
|
class OtherT,
|
|
class OtherDuration,
|
|
class OtherAllocator
|
|
>
|
|
bool
|
|
operator<= (
|
|
aged_ordered_container <OtherIsMulti, OtherIsMap,
|
|
Key, OtherT, OtherDuration, Compare,
|
|
OtherAllocator> const& other) const
|
|
{
|
|
return ! (other < *this);
|
|
}
|
|
|
|
template <
|
|
bool OtherIsMulti,
|
|
bool OtherIsMap,
|
|
class OtherT,
|
|
class OtherDuration,
|
|
class OtherAllocator
|
|
>
|
|
bool
|
|
operator> (
|
|
aged_ordered_container <OtherIsMulti, OtherIsMap,
|
|
Key, OtherT, OtherDuration, Compare,
|
|
OtherAllocator> const& other) const
|
|
{
|
|
return other < *this;
|
|
}
|
|
|
|
template <
|
|
bool OtherIsMulti,
|
|
bool OtherIsMap,
|
|
class OtherT,
|
|
class OtherDuration,
|
|
class OtherAllocator
|
|
>
|
|
bool
|
|
operator>= (
|
|
aged_ordered_container <OtherIsMulti, OtherIsMap,
|
|
Key, OtherT, OtherDuration, Compare,
|
|
OtherAllocator> const& other) const
|
|
{
|
|
return ! (*this < other);
|
|
}
|
|
|
|
private:
|
|
// enable_if prevents erase (reverse_iterator pos, now) from compiling
|
|
template <bool is_const, class Iterator, class Base,
|
|
class = std::enable_if_t<!is_boost_reverse_iterator<Iterator>::value>>
|
|
void
|
|
touch (detail::aged_container_iterator <
|
|
is_const, Iterator, Base> pos,
|
|
typename clock_type::time_point const& now);
|
|
|
|
template <bool maybe_propagate = std::allocator_traits <
|
|
Allocator>::propagate_on_container_swap::value>
|
|
typename std::enable_if <maybe_propagate>::type
|
|
swap_data (aged_ordered_container& other) noexcept;
|
|
|
|
template <bool maybe_propagate = std::allocator_traits <
|
|
Allocator>::propagate_on_container_swap::value>
|
|
typename std::enable_if <! maybe_propagate>::type
|
|
swap_data (aged_ordered_container& other) noexcept;
|
|
|
|
private:
|
|
config_t m_config;
|
|
cont_type mutable m_cont;
|
|
};
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
aged_ordered_container (
|
|
clock_type& clock)
|
|
: m_config (clock)
|
|
{
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
aged_ordered_container (
|
|
clock_type& clock,
|
|
Compare const& comp)
|
|
: m_config (clock, comp)
|
|
{
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
aged_ordered_container (
|
|
clock_type& clock,
|
|
Allocator const& alloc)
|
|
: m_config (clock, alloc)
|
|
{
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
aged_ordered_container (
|
|
clock_type& clock,
|
|
Compare const& comp,
|
|
Allocator const& alloc)
|
|
: m_config (clock, comp, alloc)
|
|
{
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
template <class InputIt>
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
aged_ordered_container (InputIt first, InputIt last,
|
|
clock_type& clock)
|
|
: m_config (clock)
|
|
{
|
|
insert (first, last);
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
template <class InputIt>
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
aged_ordered_container (InputIt first, InputIt last,
|
|
clock_type& clock,
|
|
Compare const& comp)
|
|
: m_config (clock, comp)
|
|
{
|
|
insert (first, last);
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
template <class InputIt>
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
aged_ordered_container (InputIt first, InputIt last,
|
|
clock_type& clock,
|
|
Allocator const& alloc)
|
|
: m_config (clock, alloc)
|
|
{
|
|
insert (first, last);
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
template <class InputIt>
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
aged_ordered_container (InputIt first, InputIt last,
|
|
clock_type& clock,
|
|
Compare const& comp,
|
|
Allocator const& alloc)
|
|
: m_config (clock, comp, alloc)
|
|
{
|
|
insert (first, last);
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
aged_ordered_container (aged_ordered_container const& other)
|
|
: m_config (other.m_config)
|
|
{
|
|
insert (other.cbegin(), other.cend());
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
aged_ordered_container (aged_ordered_container const& other,
|
|
Allocator const& alloc)
|
|
: m_config (other.m_config, alloc)
|
|
{
|
|
insert (other.cbegin(), other.cend());
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
aged_ordered_container (aged_ordered_container&& other)
|
|
: m_config (std::move (other.m_config))
|
|
, m_cont (std::move (other.m_cont))
|
|
{
|
|
chronological.list = std::move (other.chronological.list);
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
aged_ordered_container (aged_ordered_container&& other,
|
|
Allocator const& alloc)
|
|
: m_config (std::move (other.m_config), alloc)
|
|
{
|
|
insert (other.cbegin(), other.cend());
|
|
other.clear ();
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
aged_ordered_container (std::initializer_list <value_type> init,
|
|
clock_type& clock)
|
|
: m_config (clock)
|
|
{
|
|
insert (init.begin(), init.end());
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
aged_ordered_container (std::initializer_list <value_type> init,
|
|
clock_type& clock,
|
|
Compare const& comp)
|
|
: m_config (clock, comp)
|
|
{
|
|
insert (init.begin(), init.end());
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
aged_ordered_container (std::initializer_list <value_type> init,
|
|
clock_type& clock,
|
|
Allocator const& alloc)
|
|
: m_config (clock, alloc)
|
|
{
|
|
insert (init.begin(), init.end());
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
aged_ordered_container (std::initializer_list <value_type> init,
|
|
clock_type& clock,
|
|
Compare const& comp,
|
|
Allocator const& alloc)
|
|
: m_config (clock, comp, alloc)
|
|
{
|
|
insert (init.begin(), init.end());
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
~aged_ordered_container()
|
|
{
|
|
clear();
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
auto
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
operator= (aged_ordered_container const& other) ->
|
|
aged_ordered_container&
|
|
{
|
|
if (this != &other)
|
|
{
|
|
clear();
|
|
this->m_config = other.m_config;
|
|
insert (other.begin(), other.end());
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
auto
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
operator= (aged_ordered_container&& other) ->
|
|
aged_ordered_container&
|
|
{
|
|
clear();
|
|
this->m_config = std::move (other.m_config);
|
|
insert (other.begin(), other.end());
|
|
other.clear();
|
|
return *this;
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
auto
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
operator= (std::initializer_list <value_type> init) ->
|
|
aged_ordered_container&
|
|
{
|
|
clear ();
|
|
insert (init);
|
|
return *this;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
template <class K, bool maybe_multi, bool maybe_map, class>
|
|
typename std::conditional <IsMap, T, void*>::type&
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
at (K const& k)
|
|
{
|
|
auto const iter (m_cont.find (k,
|
|
std::cref (m_config.key_compare())));
|
|
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 Clock, class Compare, class Allocator>
|
|
template <class K, bool maybe_multi, bool maybe_map, class>
|
|
typename std::conditional <IsMap, T, void*>::type const&
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
at (K const& k) const
|
|
{
|
|
auto const iter (m_cont.find (k,
|
|
std::cref (m_config.key_compare())));
|
|
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 Clock, class Compare, class Allocator>
|
|
template <bool maybe_multi, bool maybe_map, class>
|
|
typename std::conditional <IsMap, T, void*>::type&
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
operator[] (Key const& key)
|
|
{
|
|
typename cont_type::insert_commit_data d;
|
|
auto const result (m_cont.insert_check (key,
|
|
std::cref (m_config.key_compare()), d));
|
|
if (result.second)
|
|
{
|
|
element* const p (new_element (
|
|
std::piecewise_construct, std::forward_as_tuple (key),
|
|
std::forward_as_tuple ()));
|
|
m_cont.insert_commit (*p, d);
|
|
chronological.list.push_back (*p);
|
|
return p->value.second;
|
|
}
|
|
return result.first->value.second;
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
template <bool maybe_multi, bool maybe_map, class>
|
|
typename std::conditional <IsMap, T, void*>::type&
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
operator[] (Key&& key)
|
|
{
|
|
typename cont_type::insert_commit_data d;
|
|
auto const result (m_cont.insert_check (key,
|
|
std::cref (m_config.key_compare()), d));
|
|
if (result.second)
|
|
{
|
|
element* const p (new_element (
|
|
std::piecewise_construct,
|
|
std::forward_as_tuple (std::move (key)),
|
|
std::forward_as_tuple ()));
|
|
m_cont.insert_commit (*p, d);
|
|
chronological.list.push_back (*p);
|
|
return p->value.second;
|
|
}
|
|
return result.first->value.second;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
void
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
clear()
|
|
{
|
|
for (auto iter (chronological.list.begin());
|
|
iter != chronological.list.end();)
|
|
delete_element (&*iter++);
|
|
chronological.list.clear();
|
|
m_cont.clear();
|
|
}
|
|
|
|
// map, set
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
template <bool maybe_multi>
|
|
auto
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
insert (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.key_compare()), d));
|
|
if (result.second)
|
|
{
|
|
element* const p (new_element (value));
|
|
auto const iter (m_cont.insert_commit (*p, d));
|
|
chronological.list.push_back (*p);
|
|
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 Clock, class Compare, class Allocator>
|
|
template <bool maybe_multi>
|
|
auto
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
insert (value_type const& value) ->
|
|
typename std::enable_if <maybe_multi,
|
|
iterator>::type
|
|
{
|
|
auto const before (m_cont.upper_bound (
|
|
extract (value), std::cref (m_config.key_compare())));
|
|
element* const p (new_element (value));
|
|
chronological.list.push_back (*p);
|
|
auto const iter (m_cont.insert_before (before, *p));
|
|
return iterator (iter);
|
|
}
|
|
|
|
// set
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
template <bool maybe_multi, bool maybe_map>
|
|
auto
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
insert (value_type&& value) ->
|
|
typename std::enable_if <! maybe_multi && ! maybe_map,
|
|
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.key_compare()), d));
|
|
if (result.second)
|
|
{
|
|
element* const p (new_element (std::move (value)));
|
|
auto const iter (m_cont.insert_commit (*p, d));
|
|
chronological.list.push_back (*p);
|
|
return std::make_pair (iterator (iter), true);
|
|
}
|
|
return std::make_pair (iterator (result.first), false);
|
|
}
|
|
|
|
// multiset
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
template <bool maybe_multi, bool maybe_map>
|
|
auto
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
insert (value_type&& value) ->
|
|
typename std::enable_if <maybe_multi && ! maybe_map,
|
|
iterator>::type
|
|
{
|
|
auto const before (m_cont.upper_bound (
|
|
extract (value), std::cref (m_config.key_compare())));
|
|
element* const p (new_element (std::move (value)));
|
|
chronological.list.push_back (*p);
|
|
auto const iter (m_cont.insert_before (before, *p));
|
|
return iterator (iter);
|
|
}
|
|
|
|
//---
|
|
|
|
// map, set
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
template <bool maybe_multi>
|
|
auto
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
insert (const_iterator hint, value_type const& value) ->
|
|
typename std::enable_if <! maybe_multi,
|
|
iterator>::type
|
|
{
|
|
typename cont_type::insert_commit_data d;
|
|
auto const result (m_cont.insert_check (hint.iterator(),
|
|
extract (value), std::cref (m_config.key_compare()), d));
|
|
if (result.second)
|
|
{
|
|
element* const p (new_element (value));
|
|
auto const iter (m_cont.insert_commit (*p, d));
|
|
chronological.list.push_back (*p);
|
|
return iterator (iter);
|
|
}
|
|
return iterator (result.first);
|
|
}
|
|
|
|
// map, set
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
template <bool maybe_multi>
|
|
auto
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
insert (const_iterator hint, value_type&& value) ->
|
|
typename std::enable_if <! maybe_multi,
|
|
iterator>::type
|
|
{
|
|
typename cont_type::insert_commit_data d;
|
|
auto const result (m_cont.insert_check (hint.iterator(),
|
|
extract (value), std::cref (m_config.key_compare()), d));
|
|
if (result.second)
|
|
{
|
|
element* const p (new_element (std::move (value)));
|
|
auto const iter (m_cont.insert_commit (*p, d));
|
|
chronological.list.push_back (*p);
|
|
return iterator (iter);
|
|
}
|
|
return iterator (result.first);
|
|
}
|
|
|
|
// map, set
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
template <bool maybe_multi, class... Args>
|
|
auto
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
emplace (Args&&... args) ->
|
|
typename std::enable_if <! maybe_multi,
|
|
std::pair <iterator, bool>>::type
|
|
{
|
|
// 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.key_compare()), d));
|
|
if (result.second)
|
|
{
|
|
auto const iter (m_cont.insert_commit (*p, d));
|
|
chronological.list.push_back (*p);
|
|
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 Clock, class Compare, class Allocator>
|
|
template <bool maybe_multi, class... Args>
|
|
auto
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
emplace (Args&&... args) ->
|
|
typename std::enable_if <maybe_multi,
|
|
iterator>::type
|
|
{
|
|
element* const p (new_element (
|
|
std::forward <Args> (args)...));
|
|
auto const before (m_cont.upper_bound (extract (p->value),
|
|
std::cref (m_config.key_compare())));
|
|
chronological.list.push_back (*p);
|
|
auto const iter (m_cont.insert_before (before, *p));
|
|
return iterator (iter);
|
|
}
|
|
|
|
// map, set
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
template <bool maybe_multi, class... Args>
|
|
auto
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
emplace_hint (const_iterator hint, Args&&... args) ->
|
|
typename std::enable_if <! maybe_multi,
|
|
std::pair <iterator, bool>>::type
|
|
{
|
|
// 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 (hint.iterator(),
|
|
extract (p->value), std::cref (m_config.key_compare()), d));
|
|
if (result.second)
|
|
{
|
|
auto const iter (m_cont.insert_commit (*p, d));
|
|
chronological.list.push_back (*p);
|
|
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 Clock, class Compare, class Allocator>
|
|
template <bool is_const, class Iterator, class Base, class>
|
|
detail::aged_container_iterator <false, Iterator, Base>
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
erase (detail::aged_container_iterator <is_const, Iterator, Base> pos)
|
|
{
|
|
unlink_and_delete_element(&*((pos++).iterator()));
|
|
return detail::aged_container_iterator <
|
|
false, Iterator, Base> (pos.iterator());
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
template <bool is_const, class Iterator, class Base, class>
|
|
detail::aged_container_iterator <false, Iterator, Base>
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
erase (detail::aged_container_iterator <is_const, Iterator, Base> first,
|
|
detail::aged_container_iterator <is_const, Iterator, Base> last)
|
|
{
|
|
for (; first != last;)
|
|
unlink_and_delete_element(&*((first++).iterator()));
|
|
|
|
return detail::aged_container_iterator <
|
|
false, Iterator, Base> (first.iterator());
|
|
}
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
template <class K>
|
|
auto
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
erase (K const& k) ->
|
|
size_type
|
|
{
|
|
auto iter (m_cont.find (k,
|
|
std::cref (m_config.key_compare())));
|
|
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 Clock, class Compare, class Allocator>
|
|
void
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
swap (aged_ordered_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 Clock, class Compare, class Allocator>
|
|
template <class K>
|
|
auto
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, 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;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
template <bool OtherIsMulti, bool OtherIsMap,
|
|
class OtherT, class OtherDuration, class OtherAllocator>
|
|
bool
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
operator== (
|
|
aged_ordered_container <OtherIsMulti, OtherIsMap,
|
|
Key, OtherT, OtherDuration, Compare,
|
|
OtherAllocator> const& other) const
|
|
{
|
|
typedef aged_ordered_container <OtherIsMulti, OtherIsMap,
|
|
Key, OtherT, OtherDuration, Compare,
|
|
OtherAllocator> Other;
|
|
if (size() != other.size())
|
|
return false;
|
|
std::equal_to <void> eq;
|
|
return std::equal (cbegin(), cend(), other.cbegin(), other.cend(),
|
|
[&eq, &other](value_type const& lhs,
|
|
typename Other::value_type const& rhs)
|
|
{
|
|
return eq (extract (lhs), other.extract (rhs));
|
|
});
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
template <bool is_const, class Iterator, class Base, class>
|
|
void
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
touch (detail::aged_container_iterator <
|
|
is_const, Iterator, Base> 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 IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
template <bool maybe_propagate>
|
|
typename std::enable_if <maybe_propagate>::type
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
swap_data (aged_ordered_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 IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
template <bool maybe_propagate>
|
|
typename std::enable_if <! maybe_propagate>::type
|
|
aged_ordered_container <IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::
|
|
swap_data (aged_ordered_container& other) noexcept
|
|
{
|
|
std::swap (m_config.key_compare(), other.m_config.key_compare());
|
|
std::swap (m_config.clock, other.m_config.clock);
|
|
}
|
|
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
struct is_aged_container <detail::aged_ordered_container <
|
|
IsMulti, IsMap, Key, T, Clock, Compare, Allocator>>
|
|
: std::true_type
|
|
{
|
|
};
|
|
|
|
// Free functions
|
|
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator>
|
|
void swap (
|
|
detail::aged_ordered_container <IsMulti, IsMap,
|
|
Key, T, Clock, Compare, Allocator>& lhs,
|
|
detail::aged_ordered_container <IsMulti, IsMap,
|
|
Key, T, Clock, Compare, Allocator>& rhs) noexcept
|
|
{
|
|
lhs.swap (rhs);
|
|
}
|
|
|
|
/** Expire aged container items past the specified age. */
|
|
template <bool IsMulti, bool IsMap, class Key, class T,
|
|
class Clock, class Compare, class Allocator,
|
|
class Rep, class Period>
|
|
std::size_t expire (detail::aged_ordered_container <
|
|
IsMulti, IsMap, Key, T, Clock, Compare, Allocator>& c,
|
|
std::chrono::duration <Rep, Period> const& age)
|
|
{
|
|
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
|