Repository navigation
Expand file tree
/
Copy pathbuilder.hpp
More file actions
173 lines (151 loc) · 6.26 KB
/
Copy pathbuilder.hpp
File metadata and controls
173 lines (151 loc) · 6.26 KB
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#ifndef _H_TMP_BUILDER_PATTERN__
#define _H_TMP_BUILDER_PATTERN__
#include <type_traits>
#include <experimental/type_traits>
#include <utility>
namespace tmp_builder {
namespace detail {
template<auto p>
struct ReadMemPtr {
static_assert(p!=p,"not a member pointer");
};
template<typename Class, typename Result, Result Class::* ptr>
struct ReadMemPtr<ptr> {
static constexpr auto value = ptr;
using type = Result;
using containing_type = Class;
};
template<auto p>
using memPtrType = typename ReadMemPtr<p>::type;
template<auto,auto>
struct isEqualMemPtr {
static constexpr auto value = false;
};
template<typename Class, typename Result, Result Class::* ptr, Result Class::* ptr2>
struct isEqualMemPtr<ptr,ptr2> {
static constexpr auto value = (ptr == ptr2);
};
template<auto ptr, auto ptr2>
constexpr bool isEqualMemPtr_v = isEqualMemPtr<ptr,ptr2>::value;
template<auto ptr>
struct canApplyMemPtr {
template<typename T>
using check = decltype(std::declval<T>().*ptr);
};
}
template<typename T,auto...>
class Builder;
template<typename T>
class Builder<T> {
T value;
template<typename,auto...>
friend class Builder;
template<auto... newptrs>
using addInFront = Builder<T,newptrs...>;
constexpr T& getValue() {return value;}
public:
constexpr Builder() = default;
constexpr Builder(const Builder&) = default;
constexpr Builder(Builder&&) = default;
constexpr explicit Builder(const T& t) : value(t) {};
constexpr explicit Builder(T&& t) : value(std::move(t)) {};
constexpr T& get() & {
return value;
}
constexpr T&& get() && {
return std::move(value);
}
template<auto p>
constexpr Builder<T>& set(const detail::memPtrType<p>& v) & {
value.*p = v;
return *this;
}
template<auto p>
constexpr Builder<T>& set(detail::memPtrType<p>&& v) & {
value.*p = std::move(v);
return *this;
}
template<auto p>
constexpr Builder<T>&& set(const detail::memPtrType<p>& v) && {
value.*p = v;
return std::move(*this);
}
template<auto p>
constexpr Builder<T>&& set(detail::memPtrType<p>&& v) && {
value.*p = std::move(v);
return std::move(*this);
}
};
template<typename T, auto ptr, auto... ptrs>
class Builder<T,ptr,ptrs...> : private Builder<T,ptrs...> {
using parent = Builder<T,ptrs...>;
using info = detail::ReadMemPtr<ptr>;
using infoT = std::remove_reference_t<typename info::type>;
static_assert(std::experimental::is_detected_v<detail::canApplyMemPtr<ptr>::template check,T>, "mismatching member pointer types");
template<typename,auto...>
friend class Builder;
template<auto... newptrs>
using addInFront = Builder<T,newptrs...,ptr,ptrs...>;
constexpr Builder(const parent& t) : parent(t) {};
constexpr Builder(parent&& t) : parent(std::move(t)) {};
template<auto p, typename Val>
[[nodiscard]] constexpr auto set_nested(Val&& v) & {
using returnType = std::remove_reference_t<decltype(std::declval<parent>().template set<p>(std::forward<Val>(v)))>;
return typename returnType::template addInFront<ptr>(static_cast<parent>(*this).template set<p>(std::forward<Val>(v)));
}
template<auto p, typename Val>
[[nodiscard]] constexpr auto set_nested(Val&& v) && {
using returnType = std::remove_reference_t<decltype(std::declval<parent&&>().template set<p>(std::forward<Val>(v)))>;
return typename returnType::template addInFront<ptr>{static_cast<parent&&>(std::move(*this)).template set<p>(std::forward<Val>(v))};
}
public:
constexpr Builder() = default;
constexpr Builder(const Builder&) = default;
constexpr Builder(Builder&&) = default;
constexpr explicit Builder(const T& t) : parent(t) {};
constexpr explicit Builder(T&& t) : parent(std::move(t)) {};
template<int check = 1>
constexpr T& get() {
static_assert(check != 1, "Can't get from incompleted build");
}
//Simple case: the member set is the same as this Builder's, return parent with changed value.
template<auto p, typename = std::enable_if_t<detail::isEqualMemPtr_v<p,ptr>>>
[[nodiscard]] constexpr parent& set(const infoT& val) & {
this->getValue().*ptr = val;
return *this;
}
template<auto p, typename = std::enable_if_t<detail::isEqualMemPtr_v<p,ptr>>>
[[nodiscard]] constexpr parent& set(infoT&& val) & {
this->getValue().*ptr = std::move(val);
return *this;
}
template<auto p, typename = std::enable_if_t<detail::isEqualMemPtr_v<p,ptr>>>
[[nodiscard]] constexpr parent&& set(const infoT& val) && {
this->getValue().*ptr = val;
return std::move(*this);
}
template<auto p, typename = std::enable_if_t<detail::isEqualMemPtr_v<p,ptr>>>
[[nodiscard]] constexpr parent&& set(infoT&& val) && {
this->getValue().*ptr = std::move(val);
return std::move(*this);
}
//More difficult case: the member set is not ours, push set through in case it is a required parameter
template<auto p, typename = std::enable_if_t<!detail::isEqualMemPtr_v<p,ptr>>>
[[nodiscard]] constexpr auto set(const detail::memPtrType<p>& v) & {
return set_nested<p>(v);
}
template<auto p, typename = std::enable_if_t<!detail::isEqualMemPtr_v<p,ptr>>>
[[nodiscard]] constexpr auto set(detail::memPtrType<p>&& v) & {
return set_nested<p>(std::move(v));
}
template<auto p, typename = std::enable_if_t<!detail::isEqualMemPtr_v<p,ptr>>>
[[nodiscard]] constexpr auto set(const detail::memPtrType<p>& v) && {
return std::move(*this).template set_nested<p>(v);
}
template<auto p, typename = std::enable_if_t<!detail::isEqualMemPtr_v<p,ptr>>>
[[nodiscard]] constexpr auto set(detail::memPtrType<p>&& v) && {
return std::move(*this).template set_nested<p>(std::move(v));
}
};
}
#endif