33// / @file userver/multi-index-lru/container.hpp
44// / @brief @copybrief multi_index_lru::Container
55
6- #include < boost/intrusive/link_mode.hpp>
7- #include < boost/intrusive/list.hpp>
8- #include < boost/intrusive/list_hook.hpp>
9- #include < boost/multi_index/hashed_index.hpp>
10- #include < boost/multi_index/mem_fun.hpp>
11- #include < boost/multi_index/member.hpp>
6+ #include < boost/multi_index/identity.hpp>
127#include < boost/multi_index/ordered_index.hpp>
13- #include < boost/multi_index/tag .hpp>
8+ #include < boost/multi_index/sequenced_index .hpp>
149#include < boost/multi_index_container.hpp>
1510
11+ #include < boost/mpl/joint_view.hpp>
12+ #include < boost/mpl/list.hpp>
13+
1614#include < cstddef>
1715#include < utility>
1816
1917USERVER_NAMESPACE_BEGIN
2018
2119namespace multi_index_lru {
2220
23- namespace impl {
24-
25- template <typename Value>
26- struct ValueWithHook {
27- Value value;
28- mutable boost::intrusive::list_member_hook<> list_hook;
29-
30- const ValueWithHook* GetPointerToSelf () const { return this ; };
31-
32- explicit ValueWithHook (const Value& val)
33- : value(val)
34- {}
35-
36- explicit ValueWithHook (Value&& val)
37- : value(std::move(val))
38- {}
39-
40- ValueWithHook () = delete ;
41- ValueWithHook (const ValueWithHook&) = delete ;
42- ValueWithHook (ValueWithHook&&) = delete ;
43-
44- ValueWithHook& operator =(const ValueWithHook&) = delete ;
45- ValueWithHook& operator =(ValueWithHook&&) = delete ;
46-
47- operator Value&() { return value; }
48- operator const Value&() const { return value; }
49-
50- Value* operator ->() { return &value; }
51- const Value* operator ->() const { return &value; }
52-
53- Value& get () { return value; }
54- const Value& get () const { return value; }
55- };
56-
57- template <class List , class Node >
58- void PushBackToList (List& lst, const Node& node) {
59- lst.push_back (const_cast <Node&>(node)); // TODO:
60- }
61-
62- template <class List , class Node >
63- void SpliceInList (List& lst, Node& node) {
64- lst.splice (lst.end (), lst, lst.iterator_to (node));
65- }
66-
67- struct InternalPtrTag {};
68-
69- } // namespace impl
70-
7121// / @ingroup userver_containers
7222// /
7323// / @brief MultiIndex LRU container
74- template <typename Value, typename IndexSpecifierList, typename Allocator = std::allocator<impl::ValueWithHook< Value>> >
24+ template <typename Value, typename IndexSpecifierList, typename Allocator = std::allocator<Value> >
7525class Container {
7626public:
7727 explicit Container (size_t max_size)
78- : max_size (max_size)
28+ : max_size_ (max_size)
7929 {}
8030
8131 template <typename ... Args>
8232 bool emplace (Args&&... args) {
83- if (container.size () >= max_size) {
84- EvictLru ();
85- }
86-
87- auto result = container.emplace (std::forward<Args>(args)...);
33+ auto & seq_index = container_.template get <0 >();
34+ auto result = seq_index.emplace_front (std::forward<Args>(args)...);
8835
89- auto & value = *result.first ;
90- if (result.second ) {
91- impl::PushBackToList (usage_list, value);
92- } else {
93- impl::SpliceInList (usage_list, value);
36+ if (!result.second ) {
37+ seq_index.relocate (seq_index.begin (), result.first );
38+ } else if (seq_index.size () > max_size_) {
39+ seq_index.pop_back ();
9440 }
9541 return result.second ;
9642 }
@@ -101,74 +47,56 @@ class Container {
10147
10248 template <typename Tag, typename Key>
10349 auto find (const Key& key) {
104- auto & primary_index = container .template get <Tag>();
50+ auto & primary_index = container_ .template get <Tag>();
10551 auto it = primary_index.find (key);
10652
10753 if (it != primary_index.end ()) {
108- impl::SpliceInList (usage_list, *it);
54+ auto & seq_index = container_.template get <0 >();
55+ auto seq_it = container_.template project <0 >(it);
56+ seq_index.relocate (seq_index.begin (), seq_it);
10957 }
11058
11159 return it;
11260 }
11361
114- template <typename Tag>
115- auto end () {
116- return container.template get <Tag>().end ();
117- }
118-
11962 template <typename Tag, typename Key>
12063 bool contains (const Key& key) {
121- return this ->template find <Tag, Key>(key) != container .template get <Tag>().end ();
64+ return this ->template find <Tag, Key>(key) != container_ .template get <Tag>().end ();
12265 }
12366
12467 template <typename Tag, typename Key>
12568 bool erase (const Key& key) {
126- auto & primary_index = container.template get <Tag>();
127- auto it = primary_index.find (key);
128- if (it != primary_index.end ()) {
129- usage_list.erase (usage_list.iterator_to (*it));
130- }
131- return container.template get <Tag>().erase (key) > 0 ;
69+ return container_.template get <Tag>().erase (key) > 0 ;
13270 }
13371
134- std:: size_t size () const { return container .size (); }
135- bool empty () const { return container .empty (); }
136- std:: size_t capacity () const { return max_size ; }
72+ size_t size () const { return container_ .size (); }
73+ bool empty () const { return container_ .empty (); }
74+ size_t capacity () const { return max_size_ ; }
13775
13876 void set_capacity (size_t new_capacity) {
139- max_size = new_capacity;
140- while (container.size () > max_size) {
141- EvictLru ();
77+ max_size_ = new_capacity;
78+ auto & seq_index = container_.template get <0 >();
79+ while (container_.size () > max_size_) {
80+ seq_index.pop_back ();
14281 }
14382 }
14483
145- void clear () { container .clear (); }
84+ void clear () { container_ .clear (); }
14685
147- private:
148- using CacheItem = impl::ValueWithHook<Value>;
149- using List = boost::intrusive::list<
150- CacheItem,
151- boost::intrusive::member_hook<CacheItem, boost::intrusive::list_member_hook<>, &CacheItem::list_hook>>;
152-
153- using ExtendedIndexSpecifierList = typename boost::mpl::push_back<
154- IndexSpecifierList,
155- boost::multi_index::hashed_unique<
156- boost::multi_index::tag<impl::InternalPtrTag>,
157- boost::multi_index::const_mem_fun<CacheItem, const CacheItem*, &CacheItem::GetPointerToSelf>>>::type;
158-
159- using BoostContainer = boost::multi_index::multi_index_container<CacheItem, ExtendedIndexSpecifierList, Allocator>;
160-
161- void EvictLru () {
162- if (!usage_list.empty ()) {
163- CacheItem* ptr_to_erase = &*usage_list.begin ();
164- usage_list.erase (usage_list.begin ());
165- container.template get <impl::InternalPtrTag>().erase (ptr_to_erase);
166- }
86+ template <typename Tag>
87+ auto end () {
88+ return container_.template get <Tag>().end ();
16789 }
16890
169- BoostContainer container;
170- std::size_t max_size;
171- List usage_list;
91+ private:
92+ using AdditionalIndices = boost::mpl::list<boost::multi_index::sequenced<> >;
93+
94+ using ExtendedIndexSpecifierList = boost::mpl::joint_view<AdditionalIndices, IndexSpecifierList>;
95+
96+ using BoostContainer = boost::multi_index::multi_index_container<Value, ExtendedIndexSpecifierList, Allocator>;
97+
98+ BoostContainer container_;
99+ size_t max_size_;
172100};
173101} // namespace multi_index_lru
174102
0 commit comments