6#include <boost/multi_index/identity.hpp>
7#include <boost/multi_index/ordered_index.hpp>
8#include <boost/multi_index/sequenced_index.hpp>
9#include <boost/multi_index_container.hpp>
15USERVER_NAMESPACE_BEGIN
17namespace multi_index_lru {
20template <
typename T,
typename = std::void_t<>>
21inline constexpr bool is_mpl_na =
false;
24inline constexpr bool is_mpl_na<T, std::void_t<
decltype(std::declval<T>().~na())>> =
true;
26template <
typename... Indices>
28 using type = boost::multi_index::indexed_by<boost::multi_index::sequenced<>, Indices...>;
31template <
typename... Indices>
32struct lazy_add_seq_no_last {
34 template <std::size_t... I>
35 static auto makeWithoutLast(std::index_sequence<I...>) {
36 using Tuple = std::tuple<Indices...>;
37 return boost::multi_index::indexed_by<boost::multi_index::sequenced<>, std::tuple_element_t<I, Tuple>...>{};
41 using type =
decltype(makeWithoutLast(std::make_index_sequence<
sizeof...(Indices) - 1>{}));
44template <
typename IndexList>
45struct add_seq_index {};
47template <
typename... Indices>
48struct add_seq_index<boost::multi_index::indexed_by<Indices...>> {
49 using LastType =
decltype((Indices{}, ...));
51 using type =
typename std::conditional_t<
53 lazy_add_seq_no_last<Indices...>,
54 lazy_add_seq<Indices...>>::type;
57template <
typename IndexList>
58using add_seq_index_t =
typename add_seq_index<IndexList>::type;
64template <
typename Value,
typename IndexSpecifierList,
typename Allocator = std::allocator<Value>>
67 explicit Container(size_t max_size)
71 template <
typename... Args>
72 bool emplace(Args&&... args) {
73 auto& seq_index = container_.
template get<0>();
74 auto result = seq_index.emplace_front(std::forward<Args>(args)...);
77 seq_index.relocate(seq_index.begin(), result.first);
78 }
else if (seq_index.size() > max_size_) {
84 bool insert(
const Value& value) {
return emplace(value); }
86 bool insert(Value&& value) {
return emplace(std::move(value)); }
88 template <
typename Tag,
typename Key>
89 auto find(
const Key& key) {
90 auto& primary_index = container_.
template get<Tag>();
91 auto it = primary_index.find(key);
93 if (it != primary_index.end()) {
94 auto& seq_index = container_.
template get<0>();
95 auto seq_it = container_.
template project<0>(it);
96 seq_index.relocate(seq_index.begin(), seq_it);
102 template <
typename Tag,
typename Key>
103 bool contains(
const Key& key) {
104 return this->
template find<Tag, Key>(key) != container_.
template get<Tag>().end();
107 template <
typename Tag,
typename Key>
108 bool erase(
const Key& key) {
109 return container_.
template get<Tag>().erase(key) > 0;
112 std::size_t size()
const {
return container_.size(); }
113 bool empty()
const {
return container_.empty(); }
114 std::size_t capacity()
const {
return max_size_; }
116 void set_capacity(std::size_t new_capacity) {
117 max_size_ = new_capacity;
118 auto& seq_index = container_.
template get<0>();
119 while (container_.size() > max_size_) {
120 seq_index.pop_back();
124 void clear() { container_.clear(); }
126 template <
typename Tag>
128 return container_.
template get<Tag>().end();
132 using ExtendedIndexSpecifierList = impl::add_seq_index_t<IndexSpecifierList>;
134 using BoostContainer = boost::multi_index::multi_index_container<Value, ExtendedIndexSpecifierList, Allocator>;
136 BoostContainer container_;
137 std::size_t max_size_;