forked from jamboree/CxxFunctionBenchmark
-
Notifications
You must be signed in to change notification settings - Fork 0
/
smallfun.hpp
129 lines (100 loc) · 2.62 KB
/
smallfun.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
125
126
127
128
129
#ifndef SMALLFUNCTION_SMALLFUNCTION_HPP
#define SMALLFUNCTION_SMALLFUNCTION_HPP
#include <type_traits>
#include <utility>
#include <cstddef>
namespace smallfun {
template<class ReturnType, class...Xs>
struct SFConcept {
virtual ReturnType operator()(Xs...)const = 0;
virtual void copy(void*)const = 0;
virtual ~SFConcept() {};
};
template<class F, class ReturnType, class...Xs>
struct SFModel final
: SFConcept<ReturnType, Xs...> {
mutable F f;
SFModel(F const& f)
: f(f)
{}
void copy(void* memory) const override final {
new (memory) SFModel(f);
}
ReturnType operator()(Xs...xs)const override final {
return f(xs...);
}
};
template<class Signature, std::size_t size=128>
struct SmallFun;
template<class ReturnType, class...Xs, std::size_t size>
class SmallFun<ReturnType(Xs...), size> {
static constexpr std::size_t alignment = alignof(std::max_align_t);
alignas(alignment) char memory[size];
bool allocated = false;
using Concept = SFConcept<ReturnType, Xs...>;
public:
SmallFun(){}
template<class F>
SmallFun(F const&f)
: allocated(true) {
using Model = SFModel<F, ReturnType, Xs...>;
static_assert(sizeof(Model) <= size, "");
new (memory) Model(f);
}
template<class F>
SmallFun& operator=(F const&f) {
using Model = SFModel<F, ReturnType, Xs...>;
static_assert(sizeof(Model) <= size, "");
clean();
allocated = true;
new (memory) Model(f);
return *this;
}
// copy constructor
template<std::size_t s>
SmallFun(SmallFun<ReturnType(Xs...), s> const& sf)
: allocated(sf.allocated) {
static_assert(s <= size, "");
sf.copy(memory);
}
// copy assign
template<std::size_t s>
SmallFun& operator=(SmallFun<ReturnType(Xs...), s> const& sf) {
static_assert(s <= size, "");
clean();
allocated = sf.allocated;
sf.copy(memory);
return *this;
}
void clean() {
if (allocated) {
Concept *cpt = reinterpret_cast<Concept*>(memory);
cpt->~Concept();
allocated = 0;
}
}
~SmallFun() {
if (allocated) {
Concept *cpt = reinterpret_cast<Concept*>(memory);
cpt->~Concept();
}
}
template<class...Ys>
ReturnType operator()(Ys&&...ys) {
Concept *cpt = reinterpret_cast<Concept*>(memory);
return (*cpt)(std::forward<Ys>(ys)...);
}
template<class...Ys>
ReturnType operator()(Ys&&...ys)const {
Concept *cpt = reinterpret_cast<Concept*>(memory);
return (*cpt)(std::forward<Ys>(ys)...);
}
void copy(void* data)const {
if (allocated) {
Concept *cpt = reinterpret_cast<Concept*>(memory);
cpt->copy(data);
}
}
};
}
#endif