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>>
152 #ifdef _LIBCPP_VERSION
158 #ifndef _LIBCPP_VERSION
181 return this->member();
187 return this->member();
195 #ifdef _LIBCPP_VERSION
201 #ifndef _LIBCPP_VERSION
220 bool operator() (K
const& k,
element const& e)
const
226 bool operator() (element
const& e, K
const& k)
const
228 return this->member() (
extract (e.value), k);
253 return this->member();
259 return this->member();
263 using list_type =
typename boost::intrusive::
264 make_list<element, boost::intrusive::constant_time_size<false>>::type;
268 typename boost::intrusive::make_unordered_multiset<
270 boost::intrusive::constant_time_size<true>,
271 boost::intrusive::hash<ValueHash>,
272 boost::intrusive::equal<KeyValueEqual>,
273 boost::intrusive::cache_begin<true>>::type,
274 typename boost::intrusive::make_unordered_set<
276 boost::intrusive::constant_time_size<true>,
277 boost::intrusive::hash<ValueHash>,
278 boost::intrusive::equal<KeyValueEqual>,
279 boost::intrusive::cache_begin<true>>::type>::type;
285 Allocator>::template rebind_alloc<element>;
290 Allocator>::template rebind_alloc<element>;
334 KeyEqual
const& keyEqual,
335 Allocator
const& alloc_)
345 KeyEqual
const& keyEqual,
346 Allocator
const& alloc_)
403 key_eq() = std::move(other.key_eq());
404 alloc() = std::move(other.alloc());
484 m_vec.
resize(cont_type::suggested_upper_bucket_count(0));
489 m_vec.
resize(cont_type::suggested_upper_bucket_count(0));
522 template <
class Container>
555 template <
class Container>
560 cont_type::suggested_upper_bucket_count(n));
569 template <
class... Args>
581 operator()(element* p)
594 std::forward<Args>(args)...);
627 aged_container_iterator<!IsMap, typename cont_type::iterator>;
629 aged_container_iterator<true, typename cont_type::iterator>;
632 aged_container_iterator<!IsMap, typename cont_type::local_iterator>;
634 aged_container_iterator<true, typename cont_type::local_iterator>;
651 aged_container_iterator<!IsMap, typename list_type::iterator>;
653 aged_container_iterator<true, typename list_type::iterator>;
656 typename list_type::reverse_iterator>;
658 aged_container_iterator<true, typename list_type::reverse_iterator>;
737 "must be standard layout");
738 return list.iterator_to(*
reinterpret_cast<element*
>(
739 reinterpret_cast<uint8_t*
>(&value) -
748 "must be standard layout");
749 return list.iterator_to(*
reinterpret_cast<element const*
>(
750 reinterpret_cast<uint8_t const*
>(&value) -
790 Allocator
const& alloc);
795 Allocator
const& alloc);
801 Allocator
const& alloc);
803 template <
class InputIt>
806 template <
class InputIt>
813 template <
class InputIt>
820 template <
class InputIt>
825 Allocator
const& alloc);
827 template <
class InputIt>
835 template <
class InputIt>
841 Allocator
const& alloc);
843 template <
class InputIt>
849 Allocator
const& alloc);
851 template <
class InputIt>
858 Allocator
const& alloc);
864 Allocator
const& alloc);
870 Allocator
const& alloc);
889 Allocator
const& alloc);
901 Allocator
const& alloc);
907 Allocator
const& alloc);
914 Allocator
const& alloc);
953 bool maybe_multi = IsMulti,
954 bool maybe_map = IsMap,
961 bool maybe_multi = IsMulti,
962 bool maybe_map = IsMap,
965 at(K
const& k)
const;
968 bool maybe_multi = IsMulti,
969 bool maybe_map = IsMap,
975 bool maybe_multi = IsMulti,
976 bool maybe_map = IsMap,
1028 return m_cont.iterator_to(*
reinterpret_cast<element*
>(
1029 reinterpret_cast<uint8_t*
>(&value) -
1038 return m_cont.iterator_to(*
reinterpret_cast<element const*
>(
1039 reinterpret_cast<uint8_t const*
>(&value) -
1077 template <
bool maybe_multi = IsMulti>
1083 template <
bool maybe_multi = IsMulti>
1089 template <
bool maybe_multi = IsMulti,
bool maybe_map = IsMap>
1092 enable_if<!maybe_multi && !maybe_map, std::pair<iterator, bool>>::type;
1095 template <
bool maybe_multi = IsMulti,
bool maybe_map = IsMap>
1101 template <
bool maybe_multi = IsMulti>
1107 return insert(value).first;
1111 template <
bool maybe_multi = IsMulti>
1121 template <
bool maybe_multi = IsMulti>
1127 return insert(std::move(value)).first;
1131 template <
bool maybe_multi = IsMulti>
1137 return insert(std::move(value));
1141 template <
class P,
bool maybe_map = IsMap>
1145 conditional<IsMulti, iterator, std::pair<iterator, bool>>::type>::
1149 return emplace(std::forward<P>(value));
1153 template <
class P,
bool maybe_map = IsMap>
1157 conditional<IsMulti, iterator, std::pair<iterator, bool>>::type>::
1164 template <
class InputIt>
1181 template <
bool maybe_multi = IsMulti,
class... Args>
1187 template <
bool maybe_multi = IsMulti,
class... Args>
1193 template <
bool maybe_multi = IsMulti,
class... Args>
1199 template <
bool maybe_multi = IsMulti,
class... Args>
1205 return emplace<maybe_multi>(std::forward<Args>(args)...);
1208 template <
bool is_const,
class Iterator,
class Base>
1212 template <
bool is_const,
class Iterator,
class Base>
1225 template <
bool is_const,
class Iterator,
class Base>
1280 auto const r(
m_cont.equal_range(
1292 auto const r(
m_cont.equal_range(
1345 return m_cont.bucket_count();
1357 return m_cont.bucket_size(n);
1376 return size() /
static_cast<float>(
m_cont.bucket_count());
1436 class OtherDuration,
1438 class OtherAllocator,
1439 bool maybe_multi = IsMulti>
1449 OtherAllocator>
const& other)
const;
1455 class OtherDuration,
1457 class OtherAllocator,
1458 bool maybe_multi = IsMulti>
1468 OtherAllocator>
const& other)
const;
1475 class OtherDuration,
1477 class OtherAllocator>
1487 OtherAllocator>
const& other)
const
1508 template <
bool maybe_multi = IsMulti>
1514 template <
bool maybe_multi = IsMulti>
1519 template <
class InputIt>
1523 for (; first != last; ++first)
1527 template <
class InputIt>
1531 for (; first != last; ++first)
1535 template <
class InputIt>
1544 template <
bool is_const,
class Iterator,
class Base>
1558 Allocator>::propagate_on_container_swap::value>
1569 Allocator>::propagate_on_container_swap::value>
1606 std::cref(m_config.value_hash()),
1607 std::cref(m_config.key_value_equal()))
1629 : m_config(clock, hash)
1632 std::cref(m_config.value_hash()),
1633 std::cref(m_config.key_value_equal()))
1655 aged_unordered_container(
clock_type& clock, KeyEqual
const& key_eq)
1656 : m_config(clock, key_eq)
1659 std::cref(m_config.value_hash()),
1660 std::cref(m_config.key_value_equal()))
1682 aged_unordered_container(
clock_type& clock, Allocator
const& alloc)
1683 : m_config(clock, alloc)
1687 std::cref(m_config.value_hash()),
1688 std::cref(m_config.key_value_equal()))
1710 aged_unordered_container(
1713 KeyEqual
const& key_eq)
1714 : m_config(clock, hash, key_eq)
1717 std::cref(m_config.value_hash()),
1718 std::cref(m_config.key_value_equal()))
1740 aged_unordered_container(
1743 Allocator
const& alloc)
1744 : m_config(clock, hash, alloc)
1748 std::cref(m_config.value_hash()),
1749 std::cref(m_config.key_value_equal()))
1771 aged_unordered_container(
1773 KeyEqual
const& key_eq,
1774 Allocator
const& alloc)
1775 : m_config(clock, key_eq, alloc)
1779 std::cref(m_config.value_hash()),
1780 std::cref(m_config.key_value_equal()))
1802 aged_unordered_container(
1805 KeyEqual
const& key_eq,
1806 Allocator
const& alloc)
1807 : m_config(clock, hash, key_eq, alloc)
1811 std::cref(m_config.value_hash()),
1812 std::cref(m_config.key_value_equal()))
1825 template <
class InputIt>
1835 aged_unordered_container(InputIt first, InputIt last,
clock_type& clock)
1839 std::cref(m_config.value_hash()),
1840 std::cref(m_config.key_value_equal()))
1842 insert(first, last);
1854 template <
class InputIt>
1864 aged_unordered_container(
1869 : m_config(clock, hash)
1872 std::cref(m_config.value_hash()),
1873 std::cref(m_config.key_value_equal()))
1875 insert(first, last);
1887 template <
class InputIt>
1897 aged_unordered_container(
1901 KeyEqual
const& key_eq)
1902 : m_config(clock, key_eq)
1905 std::cref(m_config.value_hash()),
1906 std::cref(m_config.key_value_equal()))
1908 insert(first, last);
1920 template <
class InputIt>
1930 aged_unordered_container(
1934 Allocator
const& alloc)
1935 : m_config(clock, alloc)
1939 std::cref(m_config.value_hash()),
1940 std::cref(m_config.key_value_equal()))
1942 insert(first, last);
1954 template <
class InputIt>
1964 aged_unordered_container(
1969 KeyEqual
const& key_eq)
1970 : m_config(clock, hash, key_eq)
1973 std::cref(m_config.value_hash()),
1974 std::cref(m_config.key_value_equal()))
1976 insert(first, last);
1988 template <
class InputIt>
1998 aged_unordered_container(
2003 Allocator
const& alloc)
2004 : m_config(clock, hash, alloc)
2008 std::cref(m_config.value_hash()),
2009 std::cref(m_config.key_value_equal()))
2011 insert(first, last);
2023 template <
class InputIt>
2033 aged_unordered_container(
2037 KeyEqual
const& key_eq,
2038 Allocator
const& alloc)
2039 : m_config(clock, key_eq, alloc)
2043 std::cref(m_config.value_hash()),
2044 std::cref(m_config.key_value_equal()))
2046 insert(first, last);
2058 template <
class InputIt>
2068 aged_unordered_container(
2073 KeyEqual
const& key_eq,
2074 Allocator
const& alloc)
2075 : m_config(clock, hash, key_eq, alloc)
2079 std::cref(m_config.value_hash()),
2080 std::cref(m_config.key_value_equal()))
2082 insert(first, last);
2103 : m_config(other.m_config)
2104 , m_buck(m_config.alloc())
2107 std::cref(m_config.value_hash()),
2108 std::cref(m_config.key_value_equal()))
2131 aged_unordered_container(
2133 Allocator
const& alloc)
2134 : m_config(other.m_config, alloc)
2138 std::cref(m_config.value_hash()),
2139 std::cref(m_config.key_value_equal()))
2162 : m_config(
std::move(other.m_config))
2163 , m_buck(
std::move(other.m_buck))
2164 , m_cont(
std::move(other.m_cont))
2166 chronological.list = std::move(other.chronological.list);
2187 aged_unordered_container(
2189 Allocator
const& alloc)
2190 : m_config(
std::move(other.m_config), alloc)
2194 std::cref(m_config.value_hash()),
2195 std::cref(m_config.key_value_equal()))
2197 insert(other.cbegin(), other.cend());
2219 aged_unordered_container(
2225 std::cref(m_config.value_hash()),
2226 std::cref(m_config.key_value_equal()))
2249 aged_unordered_container(
2253 : m_config(clock, hash)
2256 std::cref(m_config.value_hash()),
2257 std::cref(m_config.key_value_equal()))
2280 aged_unordered_container(
2283 KeyEqual
const& key_eq)
2284 : m_config(clock, key_eq)
2287 std::cref(m_config.value_hash()),
2288 std::cref(m_config.key_value_equal()))
2311 aged_unordered_container(
2314 Allocator
const& alloc)
2315 : m_config(clock, alloc)
2319 std::cref(m_config.value_hash()),
2320 std::cref(m_config.key_value_equal()))
2343 aged_unordered_container(
2347 KeyEqual
const& key_eq)
2348 : m_config(clock, hash, key_eq)
2351 std::cref(m_config.value_hash()),
2352 std::cref(m_config.key_value_equal()))
2375 aged_unordered_container(
2379 Allocator
const& alloc)
2380 : m_config(clock, hash, alloc)
2384 std::cref(m_config.value_hash()),
2385 std::cref(m_config.key_value_equal()))
2408 aged_unordered_container(
2411 KeyEqual
const& key_eq,
2412 Allocator
const& alloc)
2413 : m_config(clock, key_eq, alloc)
2417 std::cref(m_config.value_hash()),
2418 std::cref(m_config.key_value_equal()))
2441 aged_unordered_container(
2445 KeyEqual
const& key_eq,
2446 Allocator
const& alloc)
2447 : m_config(clock, hash, key_eq, alloc)
2451 std::cref(m_config.value_hash()),
2452 std::cref(m_config.key_value_equal()))
2474 Allocator>::~aged_unordered_container()
2504 m_config = other.m_config;
2505 m_buck = Buckets(m_config.alloc());
2507 insert_unchecked(other.begin(), other.end());
2535 m_config = std::move(other.m_config);
2536 m_buck = Buckets(m_config.alloc());
2538 insert_unchecked(other.begin(), other.end());
2580 template <
class K,
bool maybe_multi,
bool maybe_map,
class>
2590 Allocator>::at(K
const& k)
2592 auto const iter(m_cont.find(
2595 std::cref(m_config.key_value_equal())));
2596 if (iter == m_cont.end())
2598 return iter->value.second;
2610 template <
class K,
bool maybe_multi,
bool maybe_map,
class>
2620 Allocator>::at(K
const& k)
const
2622 auto const iter(m_cont.find(
2625 std::cref(m_config.key_value_equal())));
2626 if (iter == m_cont.end())
2628 return iter->value.second;
2640 template <
bool maybe_multi,
bool maybe_map,
class>
2650 Allocator>::operator[](Key
const& key)
2653 typename cont_type::insert_commit_data d;
2654 auto const result(m_cont.insert_check(
2661 element*
const p(new_element(
2662 std::piecewise_construct,
2665 m_cont.insert_commit(*p, d);
2666 chronological.list.push_back(*p);
2667 return p->value.second;
2669 return result.first->value.second;
2681 template <
bool maybe_multi,
bool maybe_map,
class>
2691 Allocator>::operator[](Key&& key)
2694 typename cont_type::insert_commit_data d;
2695 auto const result(m_cont.insert_check(
2702 element*
const p(new_element(
2703 std::piecewise_construct,
2706 m_cont.insert_commit(*p, d);
2707 chronological.list.push_back(*p);
2708 return p->value.second;
2710 return result.first->value.second;
2735 for (
auto iter(chronological.list.begin());
2736 iter != chronological.list.end();)
2737 unlink_and_delete_element(&*iter++);
2738 chronological.list.clear();
2753 template <
bool maybe_multi>
2767 typename cont_type::insert_commit_data d;
2768 auto const result(m_cont.insert_check(
2775 element*
const p(new_element(value));
2776 auto const iter(m_cont.insert_commit(*p, d));
2777 chronological.list.push_back(*p);
2793 template <
bool maybe_multi>
2803 Allocator>::insert(value_type
const& value) ->
2807 element*
const p(new_element(value));
2808 chronological.list.push_back(*p);
2809 auto const iter(m_cont.insert(*p));
2810 return iterator(iter);
2823 template <
bool maybe_multi,
bool maybe_map>
2825 aged_unordered_container<
2834 enable_if<!maybe_multi && !maybe_map, std::pair<iterator, bool>>::type
2837 typename cont_type::insert_commit_data d;
2838 auto const result(m_cont.insert_check(
2845 element*
const p(new_element(std::move(value)));
2846 auto const iter(m_cont.insert_commit(*p, d));
2847 chronological.list.push_back(*p);
2863 template <
bool maybe_multi,
bool maybe_map>
2873 Allocator>::insert(value_type&& value) ->
2877 element*
const p(new_element(std::move(value)));
2878 chronological.list.push_back(*p);
2879 auto const iter(m_cont.insert(*p));
2880 return iterator(iter);
2883 #if 1 // Use insert() instead of insert_check() insert_commit()
2894 template <
bool maybe_multi,
class... Args>
2896 aged_unordered_container<
2904 Allocator>::emplace(Args&&... args) ->
2910 element*
const p(new_element(std::forward<Args>(args)...));
2911 auto const result(m_cont.insert(*p));
2914 chronological.list.push_back(*p);
2920 #else // As original, use insert_check() / insert_commit () pair.
2931 template <
bool maybe_multi,
class... Args>
2941 Allocator>::emplace(Args&&... args) ->
2947 element*
const p(new_element(std::forward<Args>(args)...));
2948 typename cont_type::insert_commit_data d;
2949 auto const result(m_cont.insert_check(
2956 auto const iter(m_cont.insert_commit(*p, d));
2957 chronological.list.push_back(*p);
2975 template <
bool maybe_multi,
class... Args>
2977 aged_unordered_container<
2985 Allocator>::emplace(Args&&... args) ->
2989 element*
const p(new_element(std::forward<Args>(args)...));
2990 chronological.list.push_back(*p);
2991 auto const iter(m_cont.insert(*p));
2992 return iterator(iter);
3005 template <
bool maybe_multi,
class... Args>
3007 aged_unordered_container<
3021 element*
const p(new_element(std::forward<Args>(args)...));
3022 typename cont_type::insert_commit_data d;
3023 auto const result(m_cont.insert_check(
3030 auto const iter(m_cont.insert_commit(*p, d));
3031 chronological.list.push_back(*p);
3047 template <
bool is_const,
class Iterator,
class Base>
3060 unlink_and_delete_element(&*((pos++).
iterator()));
3074 template <
bool is_const,
class Iterator,
class Base>
3089 for (; first != last;)
3090 unlink_and_delete_element(&*((first++).
iterator()));
3117 auto iter(m_cont.find(
3120 std::cref(m_config.key_value_equal())));
3121 if (iter == m_cont.end())
3127 bool const done(m_config(*p, extract(iter->value)));
3128 unlink_and_delete_element(p);
3157 std::swap(chronological, other.chronological);
3182 auto const now(clock().now());
3184 auto const range(equal_range(k));
3185 for (
auto iter : range)
3206 class OtherDuration,
3208 class OtherAllocator,
3228 OtherAllocator>
const& other)
const
3230 if (size() != other.size())
3232 for (
auto iter(cbegin()), last(cend()), olast(other.cend()); iter != last;
3235 auto oiter(other.find(extract(*iter)));
3255 class OtherDuration,
3257 class OtherAllocator,
3277 OtherAllocator>
const& other)
const
3279 if (size() != other.size())
3282 for (
auto iter(cbegin()), last(cend()); iter != last;)
3284 auto const& k(extract(*iter));
3285 auto const eq(equal_range(k));
3286 auto const oeq(other.equal_range(k));
3287 #if BEAST_NO_CXX14_IS_PERMUTATION
3313 template <
bool maybe_multi>
3326 typename cont_type::insert_commit_data d;
3327 auto const result(m_cont.insert_check(
3334 element*
const p(new_element(value));
3335 auto const iter(m_cont.insert_commit(*p, d));
3336 chronological.list.push_back(*p);
3352 template <
bool maybe_multi>
3362 Allocator>::insert_unchecked(value_type
const& value) ->
3365 element*
const p(new_element(value));
3366 chronological.list.push_back(*p);
3367 auto const iter(m_cont.insert(*p));
3368 return iterator(iter);
3429 Allocator>& rhs) noexcept
3460 auto const expired(c.clock().now() - age);
3461 for (
auto iter(c.chronological.cbegin());
3462 iter != c.chronological.cend() && iter.when() <= expired;)
3464 iter = c.erase(iter);