-
Notifications
You must be signed in to change notification settings - Fork 184
/
matchertags.hpp
238 lines (184 loc) · 7.42 KB
/
matchertags.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
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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
// Copyright 2016 Carnegie Mellon University. See LICENSE file for terms.
// Author: Michael Duggan
#ifndef _MATCHERTAGS_HPP_
#define _MATCHERTAGS_HPP_
// This file contains base tag and tag/type manipulation definitions for use by matcher.hpp.
// The intent is for types in the detail namespace not to be available to the user, but are
// used in the
#include <type_traits>
namespace pharos {
namespace matcher {
namespace detail {
// A holder for types of any type
template <typename... T>
struct Types {
Types() = delete;
using types = Types<T...>;
};
// Base class for Tags, so std::is_base_of() can be used.
struct TagBase {
TagBase() = delete;
};
// Boolean template: is T a Tag?
template <typename T>
using IsTag = std::is_base_of<detail::TagBase, T>;
// AreTags<T...> Are the list of types T... all tags?
// Base case: true (will be used when T is empty)
template <typename... T>
struct AreTags : std::true_type {};
// Inductive step: false if S is not a tag, otherwise test T...
template <typename S, typename... T>
struct AreTags<S, T...> :
std::conditional<IsTag<S>::value, AreTags<T...>, std::false_type>::type {};
// Allow AreTags to be called with a Types<> argument. In this case, test if all the types in
// Types<> are tags.
template <typename... T>
struct AreTags<Types<T...>> : AreTags<T...> {};
// A type holder for capture (reference) types
template <typename... T>
struct Captures {
Captures() = delete;
using types = Types<T...>;
};
// A type holder for a Tag's sub-tags
template <typename... T>
struct SubTags {
SubTags() = delete;
using types = Types<T...>;
};
// Base of match tag types. This type holds the following information:
//
// A) subtags, which is a list of tags that this tag has as arguments. This is used by
// detail::CountRef.
// B) captures, which is a list of valid capture types for this node. This is used by the
// Matcher<Ref<T>> implementation.
//
// A Tag can have an optional Captures<> argument, and an optional Subtags<> argument.
template <typename... T>
struct Tag;
// The base case: store the Captures and SubTags
template <typename... RefTypes, typename... SubT>
struct Tag<Captures<RefTypes...>, SubTags<SubT...>> : detail::TagBase {
static_assert(detail::AreTags<SubT...>::value,
"There is a SubTag that does not inherit from TypedTag");
using subtags = Types<SubT...>;
using captures = Captures<RefTypes...>;
};
// Allow Captures and SubTags to appear in a different order
template <typename... RefTypes, typename... SubT>
struct Tag<SubTags<SubT...>, Captures<RefTypes...>> :
Tag<Captures<RefTypes...>, SubTags<SubT...>> {};
// Allow only a Captures<> argument
template <typename... RefTypes>
struct Tag<Captures<RefTypes...>> : Tag<Captures<RefTypes...>, SubTags<>> {};
// Allow only a SubTags<> argument
template <typename... SubT>
struct Tag<SubTags<SubT...>> : Tag<Captures<>, SubTags<SubT...>> {};
// Allow a tag with no captures or subtags
template <>
struct Tag<> : Tag<Captures<>, SubTags<>> {};
// Returns the captures of a tag
template <typename T>
using CapturesOf = typename T::captures;
// Returns the captures of a tag, wrapped in Types<> instead of Captures<>
template <typename T>
using CapturedTypes = typename CapturesOf<T>::types;
// Determine if type S is one of the types in Rest. If Rest is Types<...>, then it will
// determine if S is one of the types in Types<...>. This will be either std::true_type or
// std::false_type.
template <typename S, typename... Rest>
struct HasType;
// Base case: false
template <typename S>
struct HasType<S> : std::false_type {};
// Inductive step: true if S is same as T, recurse on Rest otherwise
template <typename S, typename T, typename... Rest>
struct HasType<S, T, Rest...> :
std::conditional<std::is_same<S, T>::value,
std::true_type,
HasType<S, Rest...>>::type {};
// Allow a Types<> argument instead of template parameter pack
template <typename S, typename... Rest>
struct HasType<S, Types<Rest...>> : HasType<S, Rest...> {};
// _TypesInCommon determines what types are in common between A and B (with accumulator Acc)
template <typename A, typename B, typename Acc = Types<>>
struct _TypesInCommon;
// Base case: If A has no types, there are no types left in common. Return the accumulator.
template <typename B, typename Acc>
struct _TypesInCommon<Types<>, B, Acc> {
using type = Acc;
};
// Inductive step: If A has types, see if the first type in A is in B. If so, add it to the
// accumulator and recurse. Otherwise, just recurse.
template <typename T, typename... A, typename B, typename... Acc>
struct _TypesInCommon<Types<T, A...>, B, Types<Acc...>> {
using type = typename _TypesInCommon<
Types<A...>, B, typename std::conditional<HasType<T, B>::value,
Types<Acc..., T>,
Types<Acc...>>::type>::type;
};
// _TypesInCommonN determines what types are in common between the Types<> argments to
// _TypesInCommonN.
template <typename... T>
struct _TypesInCommonN;
// The user-friendly version of _TypesInCommonN (doesn't require ::type)
template <typename... T>
using TypesInCommon = typename _TypesInCommonN<T...>::type;
// Base case: if only one set of types is left, return it
template <typename... T>
struct _TypesInCommonN<Types<T...>> {
using type = Types<T...>;
};
// Inductive case: Using the types in common between A and B, recurse on T.
template <typename A, typename B, typename... T>
struct _TypesInCommonN<A, B, T...> {
using type = TypesInCommon<typename _TypesInCommon<A, B>::type, T...>;
};
// Accumulate the Capture arguments of the tags T, storing them as Types<> arguments in the
// accumulator Acc
template <typename Acc, typename... T>
struct _CommonCaptures;
// Base case: No more tags. Calculate the types in common between the Types<> arguments in the
// accumulator, wrap them up in a Captures<> and store that in type
template <typename... Acc>
struct _CommonCaptures<Types<Acc...>> {
// Get the types in common
using common = TypesInCommon<Acc...>;
// Convert a Types<T...> to a Captures<T...>
template <typename T> struct ToCaptures;
template <typename... T> struct ToCaptures<Types<T...>> {
using type = Captures<T...>;
};
// Store the Captures in common
using type = typename ToCaptures<common>::type;
};
// Inductive step: Accumulate the captures types of S, and recurse
template <typename... Acc, typename S, typename... T>
struct _CommonCaptures<Types<Acc...>, S, T...> :
_CommonCaptures<Types<Acc..., CapturedTypes<S>>, T...> {};
} // namespace detail
template <typename T>
using IsTag = detail::IsTag<T>;
template <typename... T>
using Captures = detail::Captures<T...>;
template <typename... T>
using SubTags = detail::SubTags<T...>;
template <typename... T>
using Tag = detail::Tag<T...>;
template <typename T>
using CapturesOf = detail::CapturesOf<T>;
// Returns true if the type T is a valid capture type for the tag Tg
template <typename T, typename Tg>
using CaptureValidFor = detail::HasType<T, typename CapturesOf<Tg>::types>;
// Returns the capture types in common between the given set of tags
template <typename... T>
using CommonCaptures = typename detail::_CommonCaptures<detail::Types<>, T...>::type;
} // namespace matcher
} // namespace pharos
#endif // _MATCHERTAGS_HPP_
/* Local Variables: */
/* mode: c++ */
/* fill-column: 95 */
/* comment-column: 0 */
/* c-basic-offset: 2 */
/* End: */