-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathkwargs.h
178 lines (146 loc) · 5.4 KB
/
kwargs.h
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
174
175
176
177
178
/**
* @file kwargs.h
* @author Josh Bialkowski <josh.bialkowski@gmail.com>
* @brief tooling for python-like kwargs in c++
*/
/// classes and templates used by kwargs library
namespace kw {
/// parameter storage for type T within a parameter pack
template <int tag, typename T>
struct Arg {
T v;
Arg(T v) : v(v) {}
};
/// signifies that the parameter should be passed by reference
template <typename T>
struct RefWrap {
T& v;
RefWrap(T& v) : v(v) {}
};
/// signifies the parameter should be passed by const reference
template <typename T>
struct ConstRefWrap {
const T& v;
ConstRefWrap(const T& v) : v(v) {}
};
/// forces an argument to be passed by reference
template <typename T>
RefWrap<T> Ref(T& v){ return RefWrap<T>(v); }
/// forces an argument to be passed by const reference
template <typename T>
const ConstRefWrap<T> ConstRef(const T& v) { return ConstRefWrap<T>(v); }
/// the type of a global symbol used as a key for key-values pairs in the
/// kwargs parameter pack
template <int tag>
struct Key {
template <typename T>
Arg<tag,T> operator=(T v) { return v; }
template <typename T>
Arg<tag,T&> operator=(RefWrap<T> vw) { return vw.v; }
template <typename T>
Arg<tag,const T&> operator=(ConstRefWrap<T> vw) { return vw.v; }
};
/// storage for kwargs parameter pack
template <typename... Args>
struct ParamPack{};
/// template meta-function contains a static boolean variable 'result' which
/// is true if tag is in the list of kwargs and false if not
template <int tag, typename... Args>
struct ContainsTag {};
/// template meta function provides a member typedef Result which evaluates
/// to T if Arg<tag,T> is in Args... or Default if it is not
template <int tag, typename Default, typename... Args>
struct TypeOfTagDefault {};
/// provides static member Get() with implementations depending on whether
/// or not tag is in Args...
template <int tag, bool exists, typename Default, typename... Args>
struct GetImpl{};
/// given a parameter pack, retrieves and return sthe parameter tagged with tag,
/// or else returns a default value if tag is not in Args...
template <int tag, typename Default, typename... Args>
typename TypeOfTagDefault<tag,Default,Args...>::Result
Get(ParamPack<Args...>& pack, Default d) {
return
GetImpl<tag,ContainsTag<tag,Args...>::result,Default,Args...>::Get(pack,d);
}
/// given a parameter pack, retrieves and return sthe parameter tagged with tag,
/// or else returns a default value if tag is not in Args...
template <int tag, typename Default, typename... Args>
typename TypeOfTagDefault<tag,Default,Args...>::Result
Get(ParamPack<Args...>& pack, Key<tag> key, Default d) {
return
GetImpl<tag,ContainsTag<tag,Args...>::result,Default,Args...>::Get(pack,d);
}
} //< namespace kw
// ----------------------------------------------------------------------------
// Danger!!! Horrible implementation details below!!!
// Continue at your own risk!
// ----------------------------------------------------------------------------
#ifndef DOXYGEN_IGNORE
namespace kw {
/// specialization for recursion, provides storage for the current type in the
/// type list, then recursively derives from the remaining types in the type
/// list
template <typename Head, typename... Tail>
struct ParamPack<Head,Tail...>
: Head,
ParamPack<Tail...> {
ParamPack( Head head, Tail... tail )
: Head(head),
ParamPack<Tail...>(tail...) {}
};
/// specialization for base case, provides storage for the last type in the
/// type list
template <typename Tail>
struct ParamPack<Tail> : Tail {
ParamPack( Tail tail ) : Tail(tail) {}
};
/// specialization for recursion
template <int tag, typename First, typename... Rest>
struct ContainsTag<tag,First,Rest...> {
static const bool result = ContainsTag<tag, Rest...>::result;
};
/// specialization for when the Arg<tag,T> type is found
template <int tag, typename T, typename... Rest>
struct ContainsTag<tag, Arg<tag,T>, Rest...> {
static const bool result = true;
};
/// specialization for when tag is not in the type list
template <int tag>
struct ContainsTag<tag> {
static const bool result = false;
};
/// specialization for recursion
template <int tag, typename Default, typename Head, typename... Tail>
struct TypeOfTagDefault<tag, Default, Head, Tail...> {
typedef typename TypeOfTagDefault<tag, Default, Tail...>::Result Result;
};
/// specialization for when Arg<tag,T> is found
template <int tag, typename Default, typename T, typename... Tail>
struct TypeOfTagDefault<tag, Default, Arg<tag, T>, Tail...> {
typedef T Result;
};
/// specialization for when Arg<tag,T> is not in the type list
template <int tag, typename Default>
struct TypeOfTagDefault<tag,Default> {
typedef Default Result;
};
/// specialization for when tag is not in Args..., returns the default value
template <int tag, typename Default, typename... Args>
struct GetImpl<tag,false,Default,Args...>{
static Default Get(ParamPack<Args...>& pack, Default d) {
return d;
}
};
/// specialization for when tag is in Args... returns the value corresponding
/// to tag
template <int tag, typename Default, typename... Args>
struct GetImpl<tag,true,Default,Args...>{
static typename TypeOfTagDefault<tag,Default,Args...>::Result Get(
ParamPack<Args...>& pack, Default d) {
typedef typename TypeOfTagDefault<tag,Default,Args...>::Result StorageType;
return static_cast<Arg<tag,StorageType>&>(pack).v;
}
};
} //< namespace kw
#endif // DOXYGEN_IGNORE