Skip to content

Commit b4e6710

Browse files
committed
self pointer as key, member_hook instead of base_hook
1 parent f404549 commit b4e6710

File tree

4 files changed

+54
-50
lines changed

4 files changed

+54
-50
lines changed

lru_container/main.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
#include "src/benchmarks/lru_google_benchmarks.h"
44

55
// #define LRU_CONTAINER_DEBUG__
6-
#include "src/implements/lru_time_index_container.h"
7-
#include "src/implements/lru_list_container.h"
8-
#include "src/implements/lru_boost_list_container.h"
6+
#include "src/implements/examples/lru_time_index_container.h"
7+
#include "src/implements/examples/lru_list_container.h"
8+
#include "src/implements/actual/lru_boost_list_container.h"
99

1010

1111
int main() {

lru_container/src/implements/lru_boost_list_container.h renamed to lru_container/src/implements/actual/lru_boost_list_container.h

Lines changed: 51 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -14,33 +14,26 @@ namespace lru_boost_list {
1414
using namespace boost::multi_index;
1515

1616
template<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

5767
template<
5868
typename Value,
@@ -62,13 +72,20 @@ template<
6272
class LRUCacheContainer_BoostList {
6373
private:
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 {
172186
private:
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

Comments
 (0)