-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathPlusifier.hpp
112 lines (86 loc) · 3.92 KB
/
Plusifier.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
#pragma once
#include <array>
#include <memory>
#include <tuple>
namespace plusifier {
template <typename ... F>
class FunctionWrapper final {
static_assert(sizeof...(F) != 0, "FunctionWrapper should be not empty");
std::tuple<F...> var;
constexpr static inline std::size_t pack_size = sizeof...(F);
template<typename T>
struct ReturnType;
template<typename R, typename ...Args>
struct ReturnType<R(*)(Args...)> {
using type = R;
};
template <typename ... Args>
constexpr static auto NoOverloadFound() {
return VerificationResult{ pack_size, false };
}
struct VerificationResult {
std::size_t function_number = 0;
bool is_invokable = false;
constexpr operator std::size_t() const {
return function_number;
}
constexpr operator bool() const {
return is_invokable;
}
};
template <std::size_t function_number, typename ... Args>
constexpr static auto VerifyOverload() {
using function_pointer_signature = std::remove_reference_t<decltype(std::get<function_number>(var))>;
constexpr bool is_invokable = std::is_invocable_v<function_pointer_signature, Args...>;
if constexpr (is_invokable)
return VerificationResult{ function_number, true };
if constexpr (function_number + 1 < pack_size)
return VerifyOverload<function_number + 1, Args...>();
else
return NoOverloadFound<Args...>();
}
template <std::size_t function_number, typename T, typename ... Args>
constexpr static auto VerifyOverloadByReturnType() {
using function_pointer_signature = std::remove_reference_t<decltype(std::get<function_number>(var))>;
constexpr bool is_invokable = std::is_invocable_v<function_pointer_signature, Args...>;
if constexpr (is_invokable && std::is_same_v<T, typename ReturnType<function_pointer_signature>::type>)
return VerificationResult{ function_number, true };
if constexpr (function_number + 1 < pack_size)
return VerifyOverloadByReturnType<function_number + 1, T, Args...>();
else
return NoOverloadFound<Args...>();
}
public:
constexpr FunctionWrapper(F ... functions) : var(functions...) {}
template <typename ... Args>
constexpr auto operator()(Args ... args) const {
constexpr auto verification_result = VerifyOverload<0, Args...>();
if constexpr (!verification_result)
static_assert(NoOverloadFound<F...>(), "No suitable overload is found");
return std::get<verification_result>(var)(args...);
}
template <typename T, typename ... Args>
constexpr auto OverloadByReturnType(Args ... args) const {
constexpr auto verification_result = VerifyOverloadByReturnType<0, T, Args...>();
if constexpr (!verification_result)
static_assert(NoOverloadFound<F...>(), "No suitable overload is found");
return std::get<verification_result>(var)(args...);
}
};
template <typename T, auto D>
class PointerWrapper {
std::unique_ptr<T, decltype(D)> pointer;
public:
PointerWrapper(T* ptr = nullptr) : pointer(ptr, D) {}
template <typename F, typename ... Args>
PointerWrapper(F alloc_fn, Args ... args) : pointer(alloc_fn(args...), D) {}
template <typename ... F, typename ... Args>
PointerWrapper(FunctionWrapper<F...> alloc_fn, Args ... args) : pointer(alloc_fn.template OverloadByReturnType<T*>(args...), D) {}
operator T* () {
return pointer.get();
}
auto operator->() {
return pointer.operator->();
}
};
}