-
Notifications
You must be signed in to change notification settings - Fork 0
/
out_of_line.hpp
124 lines (98 loc) · 3.31 KB
/
out_of_line.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/*
* A a class out_of_line, which is a memory pattern for high performance C++,
* preserving RAII and keeping only often used class members in cache,
* with zero memory overhead.
*
* The class helps to avoid cache misses.
*/
#ifndef OutOfLine
#define OutOfLine
#include "fundamental_wrapper.hpp"
#include <map>
#include <tuple>
/*
* Class out_of_line inherits from HotType
* and has the same size as HotType.
*
* ColdType is moved to another memory segment.
* Cold data is returned by member function "cold".
*/
template<typename HotType, typename ColdType>
class out_of_line : public std::conditional<
std::is_fundamental<HotType>::value, fundamental_wrapper<HotType>, HotType>::type {
using hot_t = std::conditional<
std::is_fundamental<HotType>::value, fundamental_wrapper<HotType>, HotType>::type;
using map_t = std::map<hot_t const *, ColdType>;
static map_t cold_storage;
public:
out_of_line() = default;
out_of_line(HotType const &hot_data, ColdType const &cold_data) : hot_t(hot_data) {
cold_storage[this] = cold_data;
}
out_of_line(out_of_line const &r) : out_of_line(r, r.cold()){
}
out_of_line(out_of_line &&r) : hot_t(static_cast<hot_t &&>(r)) {
cold() = std::move(r.cold());
}
~out_of_line() {
cold_storage.erase(this);
}
out_of_line &operator=(out_of_line const &r) {
static_cast<hot_t &>(*this) = r;
cold() = r.cold();
return *this;
}
out_of_line &operator=(out_of_line &&r) {
static_cast<hot_t &>(*this) = static_cast<hot_t &&>(r);
cold() = std::move(r.cold());
return *this;
}
/*
* Implementation of functions get.
* Allows structured binding declaration.
*/
template<size_t Idx>
auto &get() & {
if constexpr(Idx == 0) { return static_cast<hot_t &>(*this); }
if constexpr(Idx == 1) { return cold(); }
}
template<size_t Idx>
auto &get() const& {
if constexpr(Idx == 0) { return static_cast<hot_t const &>(*this); }
if constexpr(Idx == 1) { return cold(); }
}
template<size_t Idx>
auto &&get() && {
if constexpr(Idx == 0) { return static_cast<hot_t &&>(*this); }
if constexpr(Idx == 1) { return std::move(cold()); }
}
/*
* Functions returning hot and cold data.
*/
HotType &hot() {
return static_cast<hot_t &>(*this);
}
HotType const &hot() const {
return static_cast<hot_t const &>(*this);
}
ColdType &cold() {
return cold_storage[this];
}
ColdType const &cold() const {
return cold_storage[this];
}
};
template<typename HotType, typename ColdType>
out_of_line<HotType, ColdType>::map_t out_of_line<HotType, ColdType>::cold_storage;
namespace std {
template <typename HotType, typename ColdType>
struct tuple_size<out_of_line<HotType, ColdType>> : std::integral_constant<size_t, 2> { };
template <typename HotType, typename ColdType>
struct tuple_element<0, out_of_line<HotType, ColdType>> {
using type =std::conditional<
std::is_fundamental<HotType>::value, fundamental_wrapper<HotType>, HotType>::type;
};
template <typename HotType, typename ColdType>
struct tuple_element<1, out_of_line<HotType, ColdType>> { using type = ColdType; };
}
#endif // OutOfLine