Skip to content

Commit 7e4a7d1

Browse files
committed
lru with boost::intrusive::list
1 parent f62b90d commit 7e4a7d1

File tree

4 files changed

+207
-16
lines changed

4 files changed

+207
-16
lines changed

lru_container/main.cpp

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,33 @@
11
#include "src/tests/lru_basic_tests.h"
2-
#include "src/implements/lru_time_index_container.h"
32
#include "src/benchmarks/lru_basic_benchmarks.h"
43
#include "src/benchmarks/lru_google_benchmarks.h"
4+
5+
// #define LRU_CONTAINER_DEBUG__
6+
#include "src/implements/lru_time_index_container.h"
57
#include "src/implements/lru_list_container.h"
8+
#include "src/implements/lru_boost_list_container.h"
9+
610

711
int main() {
8-
test_lru_users<LRUCacheContainer_TimeIndex>();
9-
test_lru_products<LRUCacheContainer_TimeIndex>();
12+
test_lru_users<lru_time_index::LRUCacheContainer_TimeIndex>();
13+
test_lru_products<lru_time_index::LRUCacheContainer_TimeIndex>();
1014
std::cout << "all tests success" << std::endl;
1115

12-
test_lru_users<LRUCacheContainer_List>();
13-
test_lru_products<LRUCacheContainer_List>();
16+
test_lru_users<lru_list::LRUCacheContainer_List>();
17+
test_lru_products<lru_list::LRUCacheContainer_List>();
1418
std::cout << "all tests success" << std::endl;
1519

16-
benchmark::simple_benchmark<LRUCacheContainer_List>("output.txt");
17-
benchmark::simple_benchmark<LRUCacheContainer_TimeIndex>("output.txt");
20+
test_lru_users<lru_boost_list::LRUCacheContainer_BoostList>();
21+
test_lru_products<lru_boost_list::LRUCacheContainer_BoostList>();
22+
std::cout << "all tests success" << std::endl;
23+
24+
benchmark::simple_benchmark<lru_list::LRUCacheContainer_List>("list_output.txt");
25+
benchmark::simple_benchmark<lru_time_index::LRUCacheContainer_TimeIndex>("time_index_output.txt");
26+
benchmark::simple_benchmark<lru_boost_list::LRUCacheContainer_BoostList>("boost_list_output.txt");
1827

19-
benchmark::google_benchmark<LRUCacheContainer_List>();
20-
benchmark::google_benchmark<LRUCacheContainer_TimeIndex>();
28+
benchmark::google_benchmark<lru_list::LRUCacheContainer_List>();
29+
benchmark::google_benchmark<lru_time_index::LRUCacheContainer_TimeIndex>();
30+
benchmark::google_benchmark<lru_boost_list::LRUCacheContainer_BoostList>();
2131

2232
benchmark::google_benchmark_init("google_output.txt");
2333
benchmark::google_benchmark_run();
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
#pragma once
2+
3+
#include <boost/intrusive/link_mode.hpp>
4+
#include <boost/intrusive/list.hpp>
5+
#include <boost/intrusive/list_hook.hpp>
6+
#include <boost/multi_index/hashed_index.hpp>
7+
8+
#include <list>
9+
#include <functional>
10+
#include <unordered_set>
11+
#include <iostream>
12+
13+
namespace lru_boost_list {
14+
using namespace boost::multi_index;
15+
16+
template<typename Value>
17+
struct ValueWithHook : public boost::intrusive::list_base_hook
18+
<boost::intrusive::link_mode
19+
<boost::intrusive::safe_link>>
20+
{
21+
static size_t id;
22+
Value value;
23+
size_t internal_id;
24+
25+
ValueWithHook() : internal_id(++id) {}
26+
27+
explicit ValueWithHook(const Value& val)
28+
: value(val), internal_id(++id) {
29+
#ifdef LRU_CONTAINER_DEBUG__
30+
std::cout << "created id " << internal_id << std::endl;
31+
#endif
32+
}
33+
34+
explicit ValueWithHook(Value&& val)
35+
: value(std::move(val)), internal_id(++id) {
36+
#ifdef LRU_CONTAINER_DEBUG__
37+
std::cout << "created id " << internal_id << std::endl;
38+
#endif
39+
}
40+
41+
operator Value&() { return value; }
42+
operator const Value&() const { return value; }
43+
44+
Value* operator->() { return &value; }
45+
const Value* operator->() const { return &value; }
46+
47+
Value& get() { return value; }
48+
const Value& get() const { return value; }
49+
};
50+
51+
struct internal_id_tag {};
52+
53+
template<
54+
typename Value,
55+
typename IndexSpecifierList,
56+
typename Allocator = std::allocator<ValueWithHook<Value>>
57+
>
58+
class LRUCacheContainer_BoostList {
59+
private:
60+
using CacheItem = ValueWithHook<Value>;
61+
using List = boost::intrusive::list<ValueWithHook<Value>>;
62+
63+
using ExtendedIndexSpecifierList = typename boost::mpl::push_back<
64+
IndexSpecifierList,
65+
hashed_unique<
66+
tag<internal_id_tag>,
67+
member<CacheItem, size_t, &CacheItem::internal_id>
68+
>
69+
>::type;
70+
71+
using Container = multi_index_container<
72+
CacheItem,
73+
ExtendedIndexSpecifierList,
74+
Allocator
75+
>;
76+
77+
Container container;
78+
size_t max_size;
79+
80+
List usage_list;
81+
82+
public:
83+
using value_type = Value;
84+
using cache_item_type = CacheItem;
85+
86+
LRUCacheContainer_BoostList(size_t max_size) : max_size(max_size) {}
87+
88+
template<typename... Args>
89+
bool emplace(Args&&... args) {
90+
if (container.size() >= max_size) {
91+
evict_lru();
92+
}
93+
94+
auto result = container.emplace(std::forward<Args>(args)...);
95+
auto &value = const_cast<ValueWithHook<Value>&>(*result.first);
96+
if (result.second) {
97+
usage_list.push_back(value);
98+
} else {
99+
touch(value);
100+
}
101+
return result.second;
102+
}
103+
104+
bool insert(const Value& value) {
105+
return emplace(value);
106+
}
107+
108+
bool insert(Value&& value) {
109+
return emplace(std::move(value));
110+
}
111+
112+
template<typename Tag, typename Key>
113+
typename Container::template index<Tag>::type::iterator find(const Key& key) {
114+
auto& primary_index = container.template get<Tag>();
115+
auto it = primary_index.find(key);
116+
117+
if (it != primary_index.end()) {
118+
auto &value = const_cast<ValueWithHook<Value>&>(*it);
119+
touch(value);
120+
}
121+
122+
return it;
123+
}
124+
125+
template<typename Tag, typename Key>
126+
bool contains(const Key& key) {
127+
return this->template find<Tag, Key>(key) != container.template get<Tag>().end();
128+
}
129+
130+
template<typename Tag, typename Key>
131+
bool erase(const Key& key) {
132+
auto& primary_index = container.template get<Tag>();
133+
auto it = primary_index.find(key);
134+
if (it != primary_index.end()) {
135+
usage_list.erase(usage_list.iterator_to(*it));
136+
}
137+
return container.template get<Tag>().erase(key) > 0;
138+
}
139+
140+
template<typename Tag>
141+
auto& get() {
142+
return container.template get<Tag>();
143+
}
144+
145+
template<typename Tag>
146+
const auto& get() const {
147+
return container.template get<Tag>();
148+
}
149+
150+
size_t size() const { return container.size(); }
151+
bool empty() const { return container.empty(); }
152+
size_t capacity() const { return max_size; }
153+
154+
void set_capacity(size_t new_capacity) {
155+
max_size = new_capacity;
156+
while (container.size() > max_size) {
157+
evict_lru();
158+
}
159+
}
160+
161+
void clear() {
162+
container.clear();
163+
}
164+
165+
private:
166+
void evict_lru() {
167+
if (!usage_list.empty()) {
168+
size_t id_to_erase = usage_list.begin()->internal_id;
169+
usage_list.erase(usage_list.begin());
170+
container.template get<internal_id_tag>().erase(id_to_erase);
171+
}
172+
}
173+
174+
void touch(CacheItem &item) {
175+
auto it = usage_list.iterator_to(item);
176+
if (it != usage_list.end()) {
177+
usage_list.splice(usage_list.end(), usage_list, it);
178+
}
179+
}
180+
};
181+
182+
template<typename T>
183+
size_t ValueWithHook<T>::id = 0;
184+
}

lru_container/src/implements/lru_list_container.h

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
11
#pragma once
22

33
#include <boost/intrusive/link_mode.hpp>
4-
#include <boost/intrusive/list.hpp>
5-
#include <boost/intrusive/list_hook.hpp>
6-
#include <boost/intrusive/unordered_set.hpp>
7-
#include <boost/intrusive/unordered_set_hook.hpp>
4+
#include <boost/multi_index/hashed_index.hpp>
85

96
#include <list>
107
#include <functional>
118
#include <unordered_set>
129

13-
namespace {
10+
namespace lru_list {
1411
using namespace boost::multi_index;
1512

1613
template<typename Value>
@@ -51,7 +48,7 @@ class LRUCacheContainer_List {
5148

5249
using ExtendedIndexSpecifierList = typename boost::mpl::push_back<
5350
IndexSpecifierList,
54-
ordered_unique<
51+
hashed_unique<
5552
tag<internal_id_tag>,
5653
member<CacheItem, size_t, &CacheItem::internal_id>
5754
>

lru_container/src/implements/lru_time_index_container.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
#include <chrono>
44

5-
namespace {
5+
namespace lru_time_index {
66
using namespace boost::multi_index;
77

88
struct lru_time_tag {};

0 commit comments

Comments
 (0)