userver: /data/code/userver/libraries/multi-index-lru/include/userver/multi-index-lru/container.hpp Source File
Loading...
Searching...
No Matches
container.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/multi-index-lru/container.hpp
4/// @brief @copybrief multi_index_lru::Container
5
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>
10
11#include <cstddef>
12#include <tuple>
13#include <utility>
14
15USERVER_NAMESPACE_BEGIN
16
17namespace multi_index_lru {
18
19namespace impl {
20template <typename T, typename = std::void_t<>>
21inline constexpr bool is_mpl_na = false;
22
23template <typename T>
24inline constexpr bool is_mpl_na<T, std::void_t<decltype(std::declval<T>().~na())>> = true;
25
26template <typename... Indices>
27struct lazy_add_seq {
28 using type = boost::multi_index::indexed_by<boost::multi_index::sequenced<>, Indices...>;
29};
30
31template <typename... Indices>
32struct lazy_add_seq_no_last {
33private:
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>...>{};
38 }
39
40public:
41 using type = decltype(makeWithoutLast(std::make_index_sequence<sizeof...(Indices) - 1>{}));
42};
43
44template <typename IndexList>
45struct add_seq_index {};
46
47template <typename... Indices>
48struct add_seq_index<boost::multi_index::indexed_by<Indices...>> {
49 using LastType = decltype((Indices{}, ...));
50
51 using type = typename std::conditional_t<
52 is_mpl_na<LastType>,
53 lazy_add_seq_no_last<Indices...>,
54 lazy_add_seq<Indices...>>::type;
55};
56
57template <typename IndexList>
58using add_seq_index_t = typename add_seq_index<IndexList>::type;
59} // namespace impl
60
61/// @ingroup userver_containers
62///
63/// @brief MultiIndex LRU container
64template <typename Value, typename IndexSpecifierList, typename Allocator = std::allocator<Value>>
65class Container {
66public:
67 explicit Container(size_t max_size)
68 : max_size_(max_size)
69 {}
70
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)...);
75
76 if (!result.second) {
77 seq_index.relocate(seq_index.begin(), result.first);
78 } else if (seq_index.size() > max_size_) {
79 seq_index.pop_back();
80 }
81 return result.second;
82 }
83
84 bool insert(const Value& value) { return emplace(value); }
85
86 bool insert(Value&& value) { return emplace(std::move(value)); }
87
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);
92
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);
97 }
98
99 return it;
100 }
101
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();
105 }
106
107 template <typename Tag, typename Key>
108 bool erase(const Key& key) {
109 return container_.template get<Tag>().erase(key) > 0;
110 }
111
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_; }
115
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();
121 }
122 }
123
124 void clear() { container_.clear(); }
125
126 template <typename Tag>
127 auto end() {
128 return container_.template get<Tag>().end();
129 }
130
131private:
132 using ExtendedIndexSpecifierList = impl::add_seq_index_t<IndexSpecifierList>;
133
134 using BoostContainer = boost::multi_index::multi_index_container<Value, ExtendedIndexSpecifierList, Allocator>;
135
136 BoostContainer container_;
137 std::size_t max_size_;
138};
139} // namespace multi_index_lru
140
141USERVER_NAMESPACE_END