20 #ifndef BEAST_CONTAINER_DETAIL_AGED_UNORDERED_CONTAINER_H_INCLUDED
21 #define BEAST_CONTAINER_DETAIL_AGED_UNORDERED_CONTAINER_H_INCLUDED
23 #include <ripple/beast/clock/abstract_clock.h>
24 #include <ripple/beast/container/aged_container.h>
25 #include <ripple/beast/container/detail/aged_associative_container.h>
26 #include <ripple/beast/container/detail/aged_container_iterator.h>
27 #include <ripple/beast/container/detail/empty_base_optimization.h>
28 #include <boost/intrusive/list.hpp>
29 #include <boost/intrusive/unordered_set.hpp>
51 #ifndef BEAST_NO_CXX14_IS_PERMUTATION
52 #define BEAST_NO_CXX14_IS_PERMUTATION 1
112 : boost::intrusive::unordered_set_base_hook<
113 boost::intrusive::link_mode<boost::intrusive::normal_link>>,
114 boost::intrusive::list_base_hook<
115 boost::intrusive::link_mode<boost::intrusive::normal_link>>
232 using list_type =
typename boost::intrusive::
233 make_list<element, boost::intrusive::constant_time_size<false>>::type;
237 typename boost::intrusive::make_unordered_multiset<
239 boost::intrusive::constant_time_size<true>,
240 boost::intrusive::hash<ValueHash>,
241 boost::intrusive::equal<KeyValueEqual>,
242 boost::intrusive::cache_begin<true>>::type,
243 typename boost::intrusive::make_unordered_set<
245 boost::intrusive::constant_time_size<true>,
246 boost::intrusive::hash<ValueHash>,
247 boost::intrusive::equal<KeyValueEqual>,
248 boost::intrusive::cache_begin<true>>::type>::type;
254 Allocator>::template rebind_alloc<element>;
259 Allocator>::template rebind_alloc<element>;
303 KeyEqual
const& keyEqual,
304 Allocator
const& alloc_)
314 KeyEqual
const& keyEqual,
315 Allocator
const& alloc_)
372 key_eq() = std::move(other.key_eq());
373 alloc() = std::move(other.alloc());
453 m_vec.
resize(cont_type::suggested_upper_bucket_count(0));
458 m_vec.
resize(cont_type::suggested_upper_bucket_count(0));
491 template <
class Container>
524 template <
class Container>
529 cont_type::suggested_upper_bucket_count(n));
538 template <
class... Args>
550 operator()(element* p)
563 std::forward<Args>(args)...);
596 aged_container_iterator<!IsMap, typename cont_type::iterator>;
598 aged_container_iterator<true, typename cont_type::iterator>;
601 aged_container_iterator<!IsMap, typename cont_type::local_iterator>;
603 aged_container_iterator<true, typename cont_type::local_iterator>;
620 aged_container_iterator<!IsMap, typename list_type::iterator>;
622 aged_container_iterator<true, typename list_type::iterator>;
625 typename list_type::reverse_iterator>;
627 aged_container_iterator<true, typename list_type::reverse_iterator>;
706 "must be standard layout");
707 return list.iterator_to(*
reinterpret_cast<element*
>(
708 reinterpret_cast<uint8_t*
>(&value) -
717 "must be standard layout");
718 return list.iterator_to(*
reinterpret_cast<element const*
>(
719 reinterpret_cast<uint8_t const*
>(&value) -
759 Allocator
const& alloc);
764 Allocator
const& alloc);
770 Allocator
const& alloc);
772 template <
class InputIt>
775 template <
class InputIt>
782 template <
class InputIt>
789 template <
class InputIt>
794 Allocator
const& alloc);
796 template <
class InputIt>
804 template <
class InputIt>
810 Allocator
const& alloc);
812 template <
class InputIt>
818 Allocator
const& alloc);
820 template <
class InputIt>
827 Allocator
const& alloc);
833 Allocator
const& alloc);
839 Allocator
const& alloc);
858 Allocator
const& alloc);
870 Allocator
const& alloc);
876 Allocator
const& alloc);
883 Allocator
const& alloc);
922 bool maybe_multi = IsMulti,
923 bool maybe_map = IsMap,
930 bool maybe_multi = IsMulti,
931 bool maybe_map = IsMap,
934 at(K
const& k)
const;
937 bool maybe_multi = IsMulti,
938 bool maybe_map = IsMap,
944 bool maybe_multi = IsMulti,
945 bool maybe_map = IsMap,
997 return m_cont.iterator_to(*
reinterpret_cast<element*
>(
998 reinterpret_cast<uint8_t*
>(&value) -
1007 return m_cont.iterator_to(*
reinterpret_cast<element const*
>(
1008 reinterpret_cast<uint8_t const*
>(&value) -
1046 template <
bool maybe_multi = IsMulti>
1052 template <
bool maybe_multi = IsMulti>
1058 template <
bool maybe_multi = IsMulti,
bool maybe_map = IsMap>
1061 enable_if<!maybe_multi && !maybe_map, std::pair<iterator, bool>>::type;
1064 template <
bool maybe_multi = IsMulti,
bool maybe_map = IsMap>
1070 template <
bool maybe_multi = IsMulti>
1076 return insert(value).first;
1080 template <
bool maybe_multi = IsMulti>
1090 template <
bool maybe_multi = IsMulti>
1096 return insert(std::move(value)).first;
1100 template <
bool maybe_multi = IsMulti>
1106 return insert(std::move(value));
1110 template <
class P,
bool maybe_map = IsMap>
1114 conditional<IsMulti, iterator, std::pair<iterator, bool>>::type>::
1118 return emplace(std::forward<P>(value));
1122 template <
class P,
bool maybe_map = IsMap>
1126 conditional<IsMulti, iterator, std::pair<iterator, bool>>::type>::
1133 template <
class InputIt>
1150 template <
bool maybe_multi = IsMulti,
class... Args>
1156 template <
bool maybe_multi = IsMulti,
class... Args>
1162 template <
bool maybe_multi = IsMulti,
class... Args>
1168 template <
bool maybe_multi = IsMulti,
class... Args>
1174 return emplace<maybe_multi>(std::forward<Args>(args)...);
1177 template <
bool is_const,
class Iterator>
1181 template <
bool is_const,
class Iterator>
1194 template <
bool is_const,
class Iterator>
1249 auto const r(
m_cont.equal_range(
1261 auto const r(
m_cont.equal_range(
1314 return m_cont.bucket_count();
1326 return m_cont.bucket_size(n);
1345 return size() /
static_cast<float>(
m_cont.bucket_count());
1405 class OtherDuration,
1407 class OtherAllocator,
1408 bool maybe_multi = IsMulti>
1418 OtherAllocator>
const& other)
const;
1424 class OtherDuration,
1426 class OtherAllocator,
1427 bool maybe_multi = IsMulti>
1437 OtherAllocator>
const& other)
const;
1444 class OtherDuration,
1446 class OtherAllocator>
1456 OtherAllocator>
const& other)
const
1477 template <
bool maybe_multi = IsMulti>
1483 template <
bool maybe_multi = IsMulti>
1488 template <
class InputIt>
1492 for (; first != last; ++first)
1496 template <
class InputIt>
1500 for (; first != last; ++first)
1504 template <
class InputIt>
1513 template <
bool is_const,
class Iterator>
1527 Allocator>::propagate_on_container_swap::value>
1538 Allocator>::propagate_on_container_swap::value>
1575 std::cref(m_config.value_hash()),
1576 std::cref(m_config.key_value_equal()))
1598 : m_config(clock, hash)
1601 std::cref(m_config.value_hash()),
1602 std::cref(m_config.key_value_equal()))
1624 aged_unordered_container(
clock_type& clock, KeyEqual
const& key_eq)
1625 : m_config(clock, key_eq)
1628 std::cref(m_config.value_hash()),
1629 std::cref(m_config.key_value_equal()))
1651 aged_unordered_container(
clock_type& clock, Allocator
const& alloc)
1652 : m_config(clock, alloc)
1656 std::cref(m_config.value_hash()),
1657 std::cref(m_config.key_value_equal()))
1679 aged_unordered_container(
1682 KeyEqual
const& key_eq)
1683 : m_config(clock, hash, key_eq)
1686 std::cref(m_config.value_hash()),
1687 std::cref(m_config.key_value_equal()))
1709 aged_unordered_container(
1712 Allocator
const& alloc)
1713 : m_config(clock, hash, alloc)
1717 std::cref(m_config.value_hash()),
1718 std::cref(m_config.key_value_equal()))
1740 aged_unordered_container(
1742 KeyEqual
const& key_eq,
1743 Allocator
const& alloc)
1744 : m_config(clock, key_eq, alloc)
1748 std::cref(m_config.value_hash()),
1749 std::cref(m_config.key_value_equal()))
1771 aged_unordered_container(
1774 KeyEqual
const& key_eq,
1775 Allocator
const& alloc)
1776 : m_config(clock, hash, key_eq, alloc)
1780 std::cref(m_config.value_hash()),
1781 std::cref(m_config.key_value_equal()))
1794 template <
class InputIt>
1804 aged_unordered_container(InputIt first, InputIt last,
clock_type& clock)
1808 std::cref(m_config.value_hash()),
1809 std::cref(m_config.key_value_equal()))
1811 insert(first, last);
1823 template <
class InputIt>
1833 aged_unordered_container(
1838 : m_config(clock, hash)
1841 std::cref(m_config.value_hash()),
1842 std::cref(m_config.key_value_equal()))
1844 insert(first, last);
1856 template <
class InputIt>
1866 aged_unordered_container(
1870 KeyEqual
const& key_eq)
1871 : m_config(clock, key_eq)
1874 std::cref(m_config.value_hash()),
1875 std::cref(m_config.key_value_equal()))
1877 insert(first, last);
1889 template <
class InputIt>
1899 aged_unordered_container(
1903 Allocator
const& alloc)
1904 : m_config(clock, alloc)
1908 std::cref(m_config.value_hash()),
1909 std::cref(m_config.key_value_equal()))
1911 insert(first, last);
1923 template <
class InputIt>
1933 aged_unordered_container(
1938 KeyEqual
const& key_eq)
1939 : m_config(clock, hash, key_eq)
1942 std::cref(m_config.value_hash()),
1943 std::cref(m_config.key_value_equal()))
1945 insert(first, last);
1957 template <
class InputIt>
1967 aged_unordered_container(
1972 Allocator
const& alloc)
1973 : m_config(clock, hash, alloc)
1977 std::cref(m_config.value_hash()),
1978 std::cref(m_config.key_value_equal()))
1980 insert(first, last);
1992 template <
class InputIt>
2002 aged_unordered_container(
2006 KeyEqual
const& key_eq,
2007 Allocator
const& alloc)
2008 : m_config(clock, key_eq, alloc)
2012 std::cref(m_config.value_hash()),
2013 std::cref(m_config.key_value_equal()))
2015 insert(first, last);
2027 template <
class InputIt>
2037 aged_unordered_container(
2042 KeyEqual
const& key_eq,
2043 Allocator
const& alloc)
2044 : m_config(clock, hash, key_eq, alloc)
2048 std::cref(m_config.value_hash()),
2049 std::cref(m_config.key_value_equal()))
2051 insert(first, last);
2072 : m_config(other.m_config)
2073 , m_buck(m_config.alloc())
2076 std::cref(m_config.value_hash()),
2077 std::cref(m_config.key_value_equal()))
2100 aged_unordered_container(
2102 Allocator
const& alloc)
2103 : m_config(other.m_config, alloc)
2107 std::cref(m_config.value_hash()),
2108 std::cref(m_config.key_value_equal()))
2131 : m_config(
std::move(other.m_config))
2132 , m_buck(
std::move(other.m_buck))
2133 , m_cont(
std::move(other.m_cont))
2135 chronological.list = std::move(other.chronological.list);
2156 aged_unordered_container(
2158 Allocator
const& alloc)
2159 : m_config(
std::move(other.m_config), alloc)
2163 std::cref(m_config.value_hash()),
2164 std::cref(m_config.key_value_equal()))
2166 insert(other.cbegin(), other.cend());
2188 aged_unordered_container(
2194 std::cref(m_config.value_hash()),
2195 std::cref(m_config.key_value_equal()))
2218 aged_unordered_container(
2222 : m_config(clock, hash)
2225 std::cref(m_config.value_hash()),
2226 std::cref(m_config.key_value_equal()))
2249 aged_unordered_container(
2252 KeyEqual
const& key_eq)
2253 : m_config(clock, key_eq)
2256 std::cref(m_config.value_hash()),
2257 std::cref(m_config.key_value_equal()))
2280 aged_unordered_container(
2283 Allocator
const& alloc)
2284 : m_config(clock, alloc)
2288 std::cref(m_config.value_hash()),
2289 std::cref(m_config.key_value_equal()))
2312 aged_unordered_container(
2316 KeyEqual
const& key_eq)
2317 : m_config(clock, hash, key_eq)
2320 std::cref(m_config.value_hash()),
2321 std::cref(m_config.key_value_equal()))
2344 aged_unordered_container(
2348 Allocator
const& alloc)
2349 : m_config(clock, hash, alloc)
2353 std::cref(m_config.value_hash()),
2354 std::cref(m_config.key_value_equal()))
2377 aged_unordered_container(
2380 KeyEqual
const& key_eq,
2381 Allocator
const& alloc)
2382 : m_config(clock, key_eq, alloc)
2386 std::cref(m_config.value_hash()),
2387 std::cref(m_config.key_value_equal()))
2410 aged_unordered_container(
2414 KeyEqual
const& key_eq,
2415 Allocator
const& alloc)
2416 : m_config(clock, hash, key_eq, alloc)
2420 std::cref(m_config.value_hash()),
2421 std::cref(m_config.key_value_equal()))
2443 Allocator>::~aged_unordered_container()
2473 m_config = other.m_config;
2474 m_buck = Buckets(m_config.alloc());
2476 insert_unchecked(other.begin(), other.end());
2504 m_config = std::move(other.m_config);
2505 m_buck = Buckets(m_config.alloc());
2507 insert_unchecked(other.begin(), other.end());
2549 template <
class K,
bool maybe_multi,
bool maybe_map,
class>
2559 Allocator>::at(K
const& k)
2561 auto const iter(m_cont.find(
2564 std::cref(m_config.key_value_equal())));
2565 if (iter == m_cont.end())
2567 return iter->value.second;
2579 template <
class K,
bool maybe_multi,
bool maybe_map,
class>
2589 Allocator>::at(K
const& k)
const
2591 auto const iter(m_cont.find(
2594 std::cref(m_config.key_value_equal())));
2595 if (iter == m_cont.end())
2597 return iter->value.second;
2609 template <
bool maybe_multi,
bool maybe_map,
class>
2619 Allocator>::operator[](Key
const& key)
2622 typename cont_type::insert_commit_data d;
2623 auto const result(m_cont.insert_check(
2630 element*
const p(new_element(
2631 std::piecewise_construct,
2634 m_cont.insert_commit(*p, d);
2635 chronological.list.push_back(*p);
2636 return p->value.second;
2638 return result.first->value.second;
2650 template <
bool maybe_multi,
bool maybe_map,
class>
2660 Allocator>::operator[](Key&& key)
2663 typename cont_type::insert_commit_data d;
2664 auto const result(m_cont.insert_check(
2671 element*
const p(new_element(
2672 std::piecewise_construct,
2675 m_cont.insert_commit(*p, d);
2676 chronological.list.push_back(*p);
2677 return p->value.second;
2679 return result.first->value.second;
2704 for (
auto iter(chronological.list.begin());
2705 iter != chronological.list.end();)
2706 unlink_and_delete_element(&*iter++);
2707 chronological.list.clear();
2722 template <
bool maybe_multi>
2736 typename cont_type::insert_commit_data d;
2737 auto const result(m_cont.insert_check(
2744 element*
const p(new_element(value));
2745 auto const iter(m_cont.insert_commit(*p, d));
2746 chronological.list.push_back(*p);
2762 template <
bool maybe_multi>
2772 Allocator>::insert(value_type
const& value) ->
2776 element*
const p(new_element(value));
2777 chronological.list.push_back(*p);
2778 auto const iter(m_cont.insert(*p));
2779 return iterator(iter);
2792 template <
bool maybe_multi,
bool maybe_map>
2794 aged_unordered_container<
2803 enable_if<!maybe_multi && !maybe_map, std::pair<iterator, bool>>::type
2806 typename cont_type::insert_commit_data d;
2807 auto const result(m_cont.insert_check(
2814 element*
const p(new_element(std::move(value)));
2815 auto const iter(m_cont.insert_commit(*p, d));
2816 chronological.list.push_back(*p);
2832 template <
bool maybe_multi,
bool maybe_map>
2842 Allocator>::insert(value_type&& value) ->
2846 element*
const p(new_element(std::move(value)));
2847 chronological.list.push_back(*p);
2848 auto const iter(m_cont.insert(*p));
2849 return iterator(iter);
2852 #if 1 // Use insert() instead of insert_check() insert_commit()
2863 template <
bool maybe_multi,
class... Args>
2865 aged_unordered_container<
2873 Allocator>::emplace(Args&&... args) ->
2879 element*
const p(new_element(std::forward<Args>(args)...));
2880 auto const result(m_cont.insert(*p));
2883 chronological.list.push_back(*p);
2889 #else // As original, use insert_check() / insert_commit () pair.
2900 template <
bool maybe_multi,
class... Args>
2910 Allocator>::emplace(Args&&... args) ->
2916 element*
const p(new_element(std::forward<Args>(args)...));
2917 typename cont_type::insert_commit_data d;
2918 auto const result(m_cont.insert_check(
2925 auto const iter(m_cont.insert_commit(*p, d));
2926 chronological.list.push_back(*p);
2944 template <
bool maybe_multi,
class... Args>
2946 aged_unordered_container<
2954 Allocator>::emplace(Args&&... args) ->
2958 element*
const p(new_element(std::forward<Args>(args)...));
2959 chronological.list.push_back(*p);
2960 auto const iter(m_cont.insert(*p));
2961 return iterator(iter);
2974 template <
bool maybe_multi,
class... Args>
2976 aged_unordered_container<
2990 element*
const p(new_element(std::forward<Args>(args)...));
2991 typename cont_type::insert_commit_data d;
2992 auto const result(m_cont.insert_check(
2999 auto const iter(m_cont.insert_commit(*p, d));
3000 chronological.list.push_back(*p);
3016 template <
bool is_const,
class Iterator>
3029 unlink_and_delete_element(&*((pos++).
iterator()));
3043 template <
bool is_const,
class Iterator>
3058 for (; first != last;)
3059 unlink_and_delete_element(&*((first++).
iterator()));
3086 auto iter(m_cont.find(
3089 std::cref(m_config.key_value_equal())));
3090 if (iter == m_cont.end())
3096 bool const done(m_config(*p, extract(iter->value)));
3097 unlink_and_delete_element(p);
3126 std::swap(chronological, other.chronological);
3151 auto const now(clock().now());
3153 auto const range(equal_range(k));
3154 for (
auto iter : range)
3175 class OtherDuration,
3177 class OtherAllocator,
3197 OtherAllocator>
const& other)
const
3199 if (size() != other.size())
3201 for (
auto iter(cbegin()), last(cend()), olast(other.cend()); iter != last;
3204 auto oiter(other.find(extract(*iter)));
3224 class OtherDuration,
3226 class OtherAllocator,
3246 OtherAllocator>
const& other)
const
3248 if (size() != other.size())
3251 for (
auto iter(cbegin()), last(cend()); iter != last;)
3253 auto const& k(extract(*iter));
3254 auto const eq(equal_range(k));
3255 auto const oeq(other.equal_range(k));
3256 #if BEAST_NO_CXX14_IS_PERMUTATION
3282 template <
bool maybe_multi>
3295 typename cont_type::insert_commit_data d;
3296 auto const result(m_cont.insert_check(
3303 element*
const p(new_element(value));
3304 auto const iter(m_cont.insert_commit(*p, d));
3305 chronological.list.push_back(*p);
3321 template <
bool maybe_multi>
3331 Allocator>::insert_unchecked(value_type
const& value) ->
3334 element*
const p(new_element(value));
3335 chronological.list.push_back(*p);
3336 auto const iter(m_cont.insert(*p));
3337 return iterator(iter);
3398 Allocator>& rhs) noexcept
3429 auto const expired(c.clock().now() - age);
3430 for (
auto iter(c.chronological.cbegin());
3431 iter != c.chronological.cend() && iter.when() <= expired;)
3433 iter = c.erase(iter);