@@ -14,33 +14,26 @@ namespace lru_boost_list {
1414using namespace boost ::multi_index;
1515
1616template <typename Value>
17- struct ValueWithHook : public boost ::intrusive::list_base_hook
18- <boost::intrusive::link_mode
19- <boost::intrusive::safe_link>>
17+ struct ValueWithHook
2018{
21- static size_t id;
2219 Value value;
23- size_t internal_id;
24-
25- // тестовая реализация, я понимаю, что вариант с таким стаким счетчиком
26- // работает только до переполнения size_t.
27- // пока думаю, как сделать лучше, например можно
28- // обязать Value иметь поле ::key хэшируемого типа
29- ValueWithHook () : internal_id(++id) {}
30-
31- explicit ValueWithHook (const Value& val)
32- : value(val), internal_id(++id) {
33- #ifdef LRU_CONTAINER_DEBUG__
34- std::cout << " created id " << internal_id << std::endl;
35- #endif
36- }
20+ mutable boost::intrusive::list_member_hook<> list_hook;
21+ ValueWithHook *__this;
22+
23+ explicit ValueWithHook (const Value& val) : value(val) {
24+ __this = this ;
25+ }
3726
38- explicit ValueWithHook (Value&& val)
39- : value(std::move(val)), internal_id(++id) {
40- #ifdef LRU_CONTAINER_DEBUG__
41- std::cout << " created id " << internal_id << std::endl;
42- #endif
43- }
27+ explicit ValueWithHook (Value&& val) : value(std::move(val)) {
28+ __this = this ;
29+ }
30+
31+ ValueWithHook () = delete ;
32+ ValueWithHook (const ValueWithHook&) = delete ;
33+ ValueWithHook (ValueWithHook &&) = delete ;
34+
35+ ValueWithHook &operator =(const ValueWithHook&) = delete ;
36+ ValueWithHook &operator =(ValueWithHook&&) = delete ;
4437
4538 operator Value&() { return value; }
4639 operator const Value&() const { return value; }
@@ -50,9 +43,26 @@ struct ValueWithHook : public boost::intrusive::list_base_hook
5043
5144 Value& get () { return value; }
5245 const Value& get () const { return value; }
46+
47+ using boost_list = boost::intrusive::list<
48+ ValueWithHook,
49+ boost::intrusive::member_hook<
50+ ValueWithHook,
51+ boost::intrusive::list_member_hook<>,
52+ &ValueWithHook::list_hook
53+ >
54+ >;
55+
56+ void push_back_to_list (boost_list &lst) const {
57+ lst.push_back (const_cast <ValueWithHook&>(*this ));
58+ }
59+
60+ void splice_in_list (boost_list &lst) const {
61+ lst.splice (lst.end (), lst, lst.iterator_to (const_cast <ValueWithHook&>(*this )));
62+ }
5363};
5464
55- struct internal_id_tag {};
65+ struct internal_ptr_tag {};
5666
5767template <
5868 typename Value,
@@ -62,13 +72,20 @@ template<
6272class LRUCacheContainer_BoostList {
6373private:
6474 using CacheItem = ValueWithHook<Value>;
65- using List = boost::intrusive::list<ValueWithHook<Value>>;
75+ using List = boost::intrusive::list<
76+ CacheItem,
77+ boost::intrusive::member_hook<
78+ CacheItem,
79+ boost::intrusive::list_member_hook<>,
80+ &CacheItem::list_hook
81+ >
82+ >;
6683
6784 using ExtendedIndexSpecifierList = typename boost::mpl::push_back<
6885 IndexSpecifierList,
6986 hashed_unique<
70- tag<internal_id_tag >,
71- member<CacheItem, size_t , &CacheItem::internal_id >
87+ tag<internal_ptr_tag >,
88+ member<CacheItem, CacheItem* , &CacheItem::__this >
7289 >
7390 >::type;
7491
@@ -97,13 +114,11 @@ class LRUCacheContainer_BoostList {
97114
98115 auto result = container.emplace (std::forward<Args>(args)...);
99116
100- // здесь и далее - данные гарантировано не "испортятся" - const_cast
101- // нужен потому, что итератор константный, а intrusive::list должен поменять хуки
102- auto &value = const_cast <ValueWithHook<Value>&>(*result.first );
117+ auto &value = *result.first ;
103118 if (result.second ) {
104- usage_list. push_back (value );
119+ value. push_back_to_list (usage_list );
105120 } else {
106- touch ( value);
121+ value. splice_in_list (usage_list );
107122 }
108123 return result.second ;
109124 }
@@ -122,8 +137,7 @@ class LRUCacheContainer_BoostList {
122137 auto it = primary_index.find (key);
123138
124139 if (it != primary_index.end ()) {
125- auto &value = const_cast <ValueWithHook<Value>&>(*it);
126- touch (value);
140+ it->splice_in_list (usage_list);
127141 }
128142
129143 return it;
@@ -172,20 +186,10 @@ class LRUCacheContainer_BoostList {
172186private:
173187 void evict_lru () {
174188 if (!usage_list.empty ()) {
175- size_t id_to_erase = usage_list.begin ()-> internal_id ;
189+ CacheItem *ptr_to_erase = &* usage_list.begin ();
176190 usage_list.erase (usage_list.begin ());
177- container.template get <internal_id_tag>().erase (id_to_erase);
178- }
179- }
180-
181- void touch (CacheItem &item) {
182- auto it = usage_list.iterator_to (item);
183- if (it != usage_list.end ()) {
184- usage_list.splice (usage_list.end (), usage_list, it);
191+ container.template get <internal_ptr_tag>().erase (ptr_to_erase);
185192 }
186193 }
187194};
188-
189- template <typename T>
190- size_t ValueWithHook<T>::id = 0 ;
191195}
0 commit comments