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/sequenced_index.hpp>
7+ #include < boost/multi_index/identity.hpp>
8+ #include < boost/multi_index_container.hpp>
129#include < boost/multi_index/ordered_index.hpp>
13- #include < boost/multi_index/tag.hpp>
14- #include < boost/multi_index_container.hpp>
1510
16- #include < cstddef>
11+ #include < boost/mpl/list.hpp>
12+ #include < boost/mpl/joint_view.hpp>
13+
1714#include < utility>
15+ #include < cstddef>
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
7021
7122// / @ingroup userver_containers
7223// /
7324// / @brief MultiIndex LRU container
74- template <typename Value, typename IndexSpecifierList, typename Allocator = std::allocator<impl::ValueWithHook<Value>>>
25+ template <
26+ typename Value,
27+ typename IndexSpecifierList,
28+ typename Allocator = std::allocator<Value>
29+ >
7530class Container {
7631public:
77- explicit Container (size_t max_size)
78- : max_size(max_size)
79- {}
80-
81- template <typename ... Args>
32+ explicit Container (size_t max_size) : max_size(max_size) {}
33+
34+ template <typename ... Args>
8235 bool emplace (Args&&... args) {
83- if (container.size () >= max_size) {
84- EvictLru ();
85- }
86-
87- auto result = container.emplace (std::forward<Args>(args)...);
36+ auto result = container.emplace_front (std::forward<Args>(args)...);
8837
89- auto & value = *result.first ;
90- if (result.second ) {
91- impl::PushBackToList (usage_list, value);
92- } else {
93- impl::SpliceInList (usage_list, value);
38+ if (result.second == false ) {
39+ container.relocate (container.begin (),result.first );
40+ } else if (container.size () >= max_size) {
41+ container.pop_back ();
9442 }
9543 return result.second ;
9644 }
97-
45+
9846 bool insert (const Value& value) { return emplace (value); }
9947
10048 bool insert (Value&& value) { return emplace (std::move (value)); }
101-
102- template <typename Tag, typename Key>
49+
50+ template <typename Tag, typename Key>
10351 auto find (const Key& key) {
10452 auto & primary_index = container.template get <Tag>();
10553 auto it = primary_index.find (key);
106-
54+
10755 if (it != primary_index.end ()) {
108- impl::SpliceInList (usage_list, * it);
56+ container. relocate (container. begin (), it);
10957 }
110-
58+
11159 return it;
11260 }
113-
114- template <typename Tag>
115- auto end () {
116- return container.template get <Tag>().end ();
117- }
118-
119- template <typename Tag, typename Key>
61+
62+ template <typename Tag, typename Key>
12063 bool contains (const Key& key) {
12164 return this ->template find <Tag, Key>(key) != container.template get <Tag>().end ();
12265 }
123-
124- template <typename Tag, typename Key>
66+
67+ 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- }
13169 return container.template get <Tag>().erase (key) > 0 ;
13270 }
133-
134- std:: size_t size () const { return container.size (); }
71+
72+ size_t size () const { return container.size (); }
13573 bool empty () const { return container.empty (); }
136- std:: size_t capacity () const { return max_size; }
137-
74+ size_t capacity () const { return max_size; }
75+
13876 void set_capacity (size_t new_capacity) {
13977 max_size = new_capacity;
14078 while (container.size () > max_size) {
141- EvictLru ();
79+ container. pop_back ();
14280 }
14381 }
144-
145- void clear () { container.clear (); }
82+
83+ void clear () {
84+ container.clear ();
85+ }
14686
14787private:
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;
88+ using AdditionalIndices = boost::mpl::list<
89+ boost::multi_index::sequenced<>
90+ >;
15891
159- using BoostContainer = boost::multi_index::multi_index_container<CacheItem, ExtendedIndexSpecifierList, Allocator>;
92+ using ExtendedIndexSpecifierList =
93+ boost::mpl::joint_view<IndexSpecifierList, AdditionalIndices>;
16094
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- }
167- }
95+ using BoostContainer = boost::multi_index::multi_index_container<
96+ Value,
97+ ExtendedIndexSpecifierList,
98+ Allocator
99+ >;
168100
169101 BoostContainer container;
170- std::size_t max_size;
171- List usage_list;
102+ size_t max_size;
172103};
173- } // namespace multi_index_lru
104+ } // namespace multi_index_lru
174105
175- USERVER_NAMESPACE_END
106+ USERVER_NAMESPACE_END
0 commit comments