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 "impl/mpl_helpers.hpp"
7
8USERVER_NAMESPACE_BEGIN
9
10namespace multi_index_lru {
11
12template <typename Value, typename IndexSpecifierList, typename Allocator = std::allocator<Value>>
13class ExpirableContainer;
14
15/// @ingroup userver_containers
16///
17/// @brief MultiIndex LRU container
18template <typename Value, typename IndexSpecifierList, typename Allocator = std::allocator<Value>>
19class Container {
20public:
21 explicit Container(size_t max_size)
22 : max_size_(max_size)
23 {}
24
25 template <typename... Args>
26 auto emplace(Args&&... args) {
27 auto& seq_index = get_sequenced();
28 auto result = seq_index.emplace_front(std::forward<Args>(args)...);
29
30 if (!result.second) {
31 seq_index.relocate(seq_index.begin(), result.first);
32 } else if (seq_index.size() > max_size_) {
33 seq_index.pop_back();
34 }
35 return result;
36 }
37
38 bool insert(const Value& value) { return emplace(value).second; }
39
40 bool insert(Value&& value) { return emplace(std::move(value)).second; }
41
42 template <typename Tag, typename Key>
43 auto find(const Key& key) {
44 auto& primary_index = get_index<Tag>();
45 auto it = primary_index.find(key);
46
47 if (it != primary_index.end()) {
48 auto& seq_index = get_sequenced();
49 auto seq_it = container_.template project<0>(it);
50 seq_index.relocate(seq_index.begin(), seq_it);
51 }
52
53 return it;
54 }
55
56 template <typename Tag, typename Key>
57 auto find_no_update(const Key& key) const {
58 return get_index<Tag>().find(key);
59 }
60
61 template <typename Tag, typename Key>
62 auto equal_range(const Key& key) {
63 auto& primary_index = get_index<Tag>();
64
65 auto [begin, end] = primary_index.equal_range(key);
66 auto it = begin;
67
68 auto& seq_index = get_sequenced();
69 while (it != end) {
70 seq_index.relocate(seq_index.begin(), project_to_sequenced(it));
71 ++it;
72 }
73
74 return std::pair{begin, end};
75 }
76
77 template <typename Tag, typename Key>
78 auto equal_range_no_update(const Key& key) const {
79 return get_index<Tag>().equal_range(key);
80 }
81
82 template <typename Tag, typename Key>
83 bool contains(const Key& key) {
84 return this->template find<Tag, Key>(key) != end<Tag>();
85 }
86
87 template <typename Tag, typename Key>
88 bool contains_no_update(const Key& key) const {
89 return this->template find_no_update<Tag, Key>(key) != end<Tag>();
90 }
91
92 template <typename Tag, typename Key>
93 bool erase(const Key& key) {
94 return get_index<Tag>().erase(key) > 0;
95 }
96
97 std::size_t size() const noexcept { return container_.size(); }
98 bool empty() const noexcept { return container_.empty(); }
99 std::size_t capacity() const noexcept { return max_size_; }
100
101 void set_capacity(std::size_t new_capacity) {
102 max_size_ = new_capacity;
103 auto& seq_index = get_sequenced();
104 while (container_.size() > max_size_) {
105 seq_index.pop_back();
106 }
107 }
108
109 void clear() { container_.clear(); }
110
111 template <typename Tag>
112 auto end() const {
113 return get_index<Tag>().end();
114 }
115
116private:
117 template <typename V, typename I, typename A>
118 friend class ExpirableContainer;
119
120 using ExtendedIndexSpecifierList = impl::add_index_t<boost::multi_index::sequenced<>, IndexSpecifierList>;
121 using BoostContainer = boost::multi_index::multi_index_container<Value, ExtendedIndexSpecifierList, Allocator>;
122
123 BoostContainer container_;
124 std::size_t max_size_;
125
126 auto& get_sequenced() noexcept { return container_.template get<0>(); }
127
128 const auto& get_sequenced() const noexcept { return container_.template get<0>(); }
129
130 template <typename Tag>
131 auto& get_index() {
132 return container_.template get<Tag>();
133 }
134
135 template <typename Tag>
136 const auto& get_index() const noexcept {
137 return container_.template get<Tag>();
138 }
139
140 template <typename IterT>
141 auto project_to_sequenced(IterT it) {
142 return container_.template project<0>(it);
143 }
144};
145
146} // namespace multi_index_lru
147
148USERVER_NAMESPACE_END