Mercurial > hg > sv-dependency-builds
comparison osx/include/kj/tuple.h @ 49:3ab5a40c4e3b
Add Capnp and KJ builds for OSX
author | Chris Cannam <cannam@all-day-breakfast.com> |
---|---|
date | Tue, 25 Oct 2016 14:48:23 +0100 |
parents | |
children | 0994c39f1e94 |
comparison
equal
deleted
inserted
replaced
48:9530b331f8c1 | 49:3ab5a40c4e3b |
---|---|
1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors | |
2 // Licensed under the MIT License: | |
3 // | |
4 // Permission is hereby granted, free of charge, to any person obtaining a copy | |
5 // of this software and associated documentation files (the "Software"), to deal | |
6 // in the Software without restriction, including without limitation the rights | |
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
8 // copies of the Software, and to permit persons to whom the Software is | |
9 // furnished to do so, subject to the following conditions: | |
10 // | |
11 // The above copyright notice and this permission notice shall be included in | |
12 // all copies or substantial portions of the Software. | |
13 // | |
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
20 // THE SOFTWARE. | |
21 | |
22 // This file defines a notion of tuples that is simpler that `std::tuple`. It works as follows: | |
23 // - `kj::Tuple<A, B, C> is the type of a tuple of an A, a B, and a C. | |
24 // - `kj::tuple(a, b, c)` returns a tuple containing a, b, and c. If any of these are themselves | |
25 // tuples, they are flattened, so `tuple(a, tuple(b, c), d)` is equivalent to `tuple(a, b, c, d)`. | |
26 // - `kj::get<n>(myTuple)` returns the element of `myTuple` at index n. | |
27 // - `kj::apply(func, ...)` calls func on the following arguments after first expanding any tuples | |
28 // in the argument list. So `kj::apply(foo, a, tuple(b, c), d)` would call `foo(a, b, c, d)`. | |
29 // | |
30 // Note that: | |
31 // - The type `Tuple<T>` is a synonym for T. This is why `get` and `apply` are not members of the | |
32 // type. | |
33 // - It is illegal for an element of `Tuple` to itself be a tuple, as tuples are meant to be | |
34 // flattened. | |
35 // - It is illegal for an element of `Tuple` to be a reference, due to problems this would cause | |
36 // with type inference and `tuple()`. | |
37 | |
38 #ifndef KJ_TUPLE_H_ | |
39 #define KJ_TUPLE_H_ | |
40 | |
41 #if defined(__GNUC__) && !KJ_HEADER_WARNINGS | |
42 #pragma GCC system_header | |
43 #endif | |
44 | |
45 #include "common.h" | |
46 | |
47 namespace kj { | |
48 namespace _ { // private | |
49 | |
50 template <size_t index, typename... T> | |
51 struct TypeByIndex_; | |
52 template <typename First, typename... Rest> | |
53 struct TypeByIndex_<0, First, Rest...> { | |
54 typedef First Type; | |
55 }; | |
56 template <size_t index, typename First, typename... Rest> | |
57 struct TypeByIndex_<index, First, Rest...> | |
58 : public TypeByIndex_<index - 1, Rest...> {}; | |
59 template <size_t index> | |
60 struct TypeByIndex_<index> { | |
61 static_assert(index != index, "Index out-of-range."); | |
62 }; | |
63 template <size_t index, typename... T> | |
64 using TypeByIndex = typename TypeByIndex_<index, T...>::Type; | |
65 // Chose a particular type out of a list of types, by index. | |
66 | |
67 template <size_t... s> | |
68 struct Indexes {}; | |
69 // Dummy helper type that just encapsulates a sequential list of indexes, so that we can match | |
70 // templates against them and unpack them with '...'. | |
71 | |
72 template <size_t end, size_t... prefix> | |
73 struct MakeIndexes_: public MakeIndexes_<end - 1, end - 1, prefix...> {}; | |
74 template <size_t... prefix> | |
75 struct MakeIndexes_<0, prefix...> { | |
76 typedef Indexes<prefix...> Type; | |
77 }; | |
78 template <size_t end> | |
79 using MakeIndexes = typename MakeIndexes_<end>::Type; | |
80 // Equivalent to Indexes<0, 1, 2, ..., end>. | |
81 | |
82 template <typename... T> | |
83 class Tuple; | |
84 template <size_t index, typename... U> | |
85 inline TypeByIndex<index, U...>& getImpl(Tuple<U...>& tuple); | |
86 template <size_t index, typename... U> | |
87 inline TypeByIndex<index, U...>&& getImpl(Tuple<U...>&& tuple); | |
88 template <size_t index, typename... U> | |
89 inline const TypeByIndex<index, U...>& getImpl(const Tuple<U...>& tuple); | |
90 | |
91 template <uint index, typename T> | |
92 struct TupleElement { | |
93 // Encapsulates one element of a tuple. The actual tuple implementation multiply-inherits | |
94 // from a TupleElement for each element, which is more efficient than a recursive definition. | |
95 | |
96 T value; | |
97 TupleElement() = default; | |
98 constexpr inline TupleElement(const T& value): value(value) {} | |
99 constexpr inline TupleElement(T&& value): value(kj::mv(value)) {} | |
100 }; | |
101 | |
102 template <uint index, typename T> | |
103 struct TupleElement<index, T&> { | |
104 // If tuples contained references, one of the following would have to be true: | |
105 // - `auto x = tuple(y, z)` would cause x to be a tuple of references to y and z, which is | |
106 // probably not what you expected. | |
107 // - `Tuple<Foo&, Bar&> x = tuple(a, b)` would not work, because `tuple()` returned | |
108 // Tuple<Foo, Bar>. | |
109 static_assert(sizeof(T*) == 0, "Sorry, tuples cannot contain references."); | |
110 }; | |
111 | |
112 template <uint index, typename... T> | |
113 struct TupleElement<index, Tuple<T...>> { | |
114 static_assert(sizeof(Tuple<T...>*) == 0, | |
115 "Tuples cannot contain other tuples -- they should be flattened."); | |
116 }; | |
117 | |
118 template <typename Indexes, typename... Types> | |
119 struct TupleImpl; | |
120 | |
121 template <size_t... indexes, typename... Types> | |
122 struct TupleImpl<Indexes<indexes...>, Types...> | |
123 : public TupleElement<indexes, Types>... { | |
124 // Implementation of Tuple. The only reason we need this rather than rolling this into class | |
125 // Tuple (below) is so that we can get "indexes" as an unpackable list. | |
126 | |
127 static_assert(sizeof...(indexes) == sizeof...(Types), "Incorrect use of TupleImpl."); | |
128 | |
129 template <typename... Params> | |
130 inline TupleImpl(Params&&... params) | |
131 : TupleElement<indexes, Types>(kj::fwd<Params>(params))... { | |
132 // Work around Clang 3.2 bug 16303 where this is not detected. (Unfortunately, Clang sometimes | |
133 // segfaults instead.) | |
134 static_assert(sizeof...(params) == sizeof...(indexes), | |
135 "Wrong number of parameters to Tuple constructor."); | |
136 } | |
137 | |
138 template <typename... U> | |
139 constexpr inline TupleImpl(Tuple<U...>&& other) | |
140 : TupleElement<indexes, Types>(kj::mv(getImpl<indexes>(other)))... {} | |
141 template <typename... U> | |
142 constexpr inline TupleImpl(Tuple<U...>& other) | |
143 : TupleElement<indexes, Types>(getImpl<indexes>(other))... {} | |
144 template <typename... U> | |
145 constexpr inline TupleImpl(const Tuple<U...>& other) | |
146 : TupleElement<indexes, Types>(getImpl<indexes>(other))... {} | |
147 }; | |
148 | |
149 struct MakeTupleFunc; | |
150 | |
151 template <typename... T> | |
152 class Tuple { | |
153 // The actual Tuple class (used for tuples of size other than 1). | |
154 | |
155 public: | |
156 template <typename... U> | |
157 constexpr inline Tuple(Tuple<U...>&& other): impl(kj::mv(other)) {} | |
158 template <typename... U> | |
159 constexpr inline Tuple(Tuple<U...>& other): impl(other) {} | |
160 template <typename... U> | |
161 constexpr inline Tuple(const Tuple<U...>& other): impl(other) {} | |
162 | |
163 private: | |
164 template <typename... Params> | |
165 constexpr Tuple(Params&&... params): impl(kj::fwd<Params>(params)...) {} | |
166 | |
167 TupleImpl<MakeIndexes<sizeof...(T)>, T...> impl; | |
168 | |
169 template <size_t index, typename... U> | |
170 friend inline TypeByIndex<index, U...>& getImpl(Tuple<U...>& tuple); | |
171 template <size_t index, typename... U> | |
172 friend inline TypeByIndex<index, U...>&& getImpl(Tuple<U...>&& tuple); | |
173 template <size_t index, typename... U> | |
174 friend inline const TypeByIndex<index, U...>& getImpl(const Tuple<U...>& tuple); | |
175 friend struct MakeTupleFunc; | |
176 }; | |
177 | |
178 template <> | |
179 class Tuple<> { | |
180 // Simplified zero-member version of Tuple. In particular this is important to make sure that | |
181 // Tuple<>() is constexpr. | |
182 }; | |
183 | |
184 template <typename T> | |
185 class Tuple<T>; | |
186 // Single-element tuple should never be used. The public API should ensure this. | |
187 | |
188 template <size_t index, typename... T> | |
189 inline TypeByIndex<index, T...>& getImpl(Tuple<T...>& tuple) { | |
190 // Get member of a Tuple by index, e.g. `get<2>(myTuple)`. | |
191 static_assert(index < sizeof...(T), "Tuple element index out-of-bounds."); | |
192 return implicitCast<TupleElement<index, TypeByIndex<index, T...>>&>(tuple.impl).value; | |
193 } | |
194 template <size_t index, typename... T> | |
195 inline TypeByIndex<index, T...>&& getImpl(Tuple<T...>&& tuple) { | |
196 // Get member of a Tuple by index, e.g. `get<2>(myTuple)`. | |
197 static_assert(index < sizeof...(T), "Tuple element index out-of-bounds."); | |
198 return kj::mv(implicitCast<TupleElement<index, TypeByIndex<index, T...>>&>(tuple.impl).value); | |
199 } | |
200 template <size_t index, typename... T> | |
201 inline const TypeByIndex<index, T...>& getImpl(const Tuple<T...>& tuple) { | |
202 // Get member of a Tuple by index, e.g. `get<2>(myTuple)`. | |
203 static_assert(index < sizeof...(T), "Tuple element index out-of-bounds."); | |
204 return implicitCast<const TupleElement<index, TypeByIndex<index, T...>>&>(tuple.impl).value; | |
205 } | |
206 template <size_t index, typename T> | |
207 inline T&& getImpl(T&& value) { | |
208 // Get member of a Tuple by index, e.g. `getImpl<2>(myTuple)`. | |
209 | |
210 // Non-tuples are equivalent to one-element tuples. | |
211 static_assert(index == 0, "Tuple element index out-of-bounds."); | |
212 return kj::fwd<T>(value); | |
213 } | |
214 | |
215 | |
216 template <typename Func, typename SoFar, typename... T> | |
217 struct ExpandAndApplyResult_; | |
218 // Template which computes the return type of applying Func to T... after flattening tuples. | |
219 // SoFar starts as Tuple<> and accumulates the flattened parameter types -- so after this template | |
220 // is recursively expanded, T... is empty and SoFar is a Tuple containing all the parameters. | |
221 | |
222 template <typename Func, typename First, typename... Rest, typename... T> | |
223 struct ExpandAndApplyResult_<Func, Tuple<T...>, First, Rest...> | |
224 : public ExpandAndApplyResult_<Func, Tuple<T..., First>, Rest...> {}; | |
225 template <typename Func, typename... FirstTypes, typename... Rest, typename... T> | |
226 struct ExpandAndApplyResult_<Func, Tuple<T...>, Tuple<FirstTypes...>, Rest...> | |
227 : public ExpandAndApplyResult_<Func, Tuple<T...>, FirstTypes&&..., Rest...> {}; | |
228 template <typename Func, typename... FirstTypes, typename... Rest, typename... T> | |
229 struct ExpandAndApplyResult_<Func, Tuple<T...>, Tuple<FirstTypes...>&, Rest...> | |
230 : public ExpandAndApplyResult_<Func, Tuple<T...>, FirstTypes&..., Rest...> {}; | |
231 template <typename Func, typename... FirstTypes, typename... Rest, typename... T> | |
232 struct ExpandAndApplyResult_<Func, Tuple<T...>, const Tuple<FirstTypes...>&, Rest...> | |
233 : public ExpandAndApplyResult_<Func, Tuple<T...>, const FirstTypes&..., Rest...> {}; | |
234 template <typename Func, typename... T> | |
235 struct ExpandAndApplyResult_<Func, Tuple<T...>> { | |
236 typedef decltype(instance<Func>()(instance<T&&>()...)) Type; | |
237 }; | |
238 template <typename Func, typename... T> | |
239 using ExpandAndApplyResult = typename ExpandAndApplyResult_<Func, Tuple<>, T...>::Type; | |
240 // Computes the expected return type of `expandAndApply()`. | |
241 | |
242 template <typename Func> | |
243 inline auto expandAndApply(Func&& func) -> ExpandAndApplyResult<Func> { | |
244 return func(); | |
245 } | |
246 | |
247 template <typename Func, typename First, typename... Rest> | |
248 struct ExpandAndApplyFunc { | |
249 Func&& func; | |
250 First&& first; | |
251 ExpandAndApplyFunc(Func&& func, First&& first) | |
252 : func(kj::fwd<Func>(func)), first(kj::fwd<First>(first)) {} | |
253 template <typename... T> | |
254 auto operator()(T&&... params) | |
255 -> decltype(this->func(kj::fwd<First>(first), kj::fwd<T>(params)...)) { | |
256 return this->func(kj::fwd<First>(first), kj::fwd<T>(params)...); | |
257 } | |
258 }; | |
259 | |
260 template <typename Func, typename First, typename... Rest> | |
261 inline auto expandAndApply(Func&& func, First&& first, Rest&&... rest) | |
262 -> ExpandAndApplyResult<Func, First, Rest...> { | |
263 | |
264 return expandAndApply( | |
265 ExpandAndApplyFunc<Func, First, Rest...>(kj::fwd<Func>(func), kj::fwd<First>(first)), | |
266 kj::fwd<Rest>(rest)...); | |
267 } | |
268 | |
269 template <typename Func, typename... FirstTypes, typename... Rest> | |
270 inline auto expandAndApply(Func&& func, Tuple<FirstTypes...>&& first, Rest&&... rest) | |
271 -> ExpandAndApplyResult<Func, FirstTypes&&..., Rest...> { | |
272 return expandAndApplyWithIndexes(MakeIndexes<sizeof...(FirstTypes)>(), | |
273 kj::fwd<Func>(func), kj::mv(first), kj::fwd<Rest>(rest)...); | |
274 } | |
275 | |
276 template <typename Func, typename... FirstTypes, typename... Rest> | |
277 inline auto expandAndApply(Func&& func, Tuple<FirstTypes...>& first, Rest&&... rest) | |
278 -> ExpandAndApplyResult<Func, FirstTypes..., Rest...> { | |
279 return expandAndApplyWithIndexes(MakeIndexes<sizeof...(FirstTypes)>(), | |
280 kj::fwd<Func>(func), first, kj::fwd<Rest>(rest)...); | |
281 } | |
282 | |
283 template <typename Func, typename... FirstTypes, typename... Rest> | |
284 inline auto expandAndApply(Func&& func, const Tuple<FirstTypes...>& first, Rest&&... rest) | |
285 -> ExpandAndApplyResult<Func, FirstTypes..., Rest...> { | |
286 return expandAndApplyWithIndexes(MakeIndexes<sizeof...(FirstTypes)>(), | |
287 kj::fwd<Func>(func), first, kj::fwd<Rest>(rest)...); | |
288 } | |
289 | |
290 template <typename Func, typename... FirstTypes, typename... Rest, size_t... indexes> | |
291 inline auto expandAndApplyWithIndexes( | |
292 Indexes<indexes...>, Func&& func, Tuple<FirstTypes...>&& first, Rest&&... rest) | |
293 -> ExpandAndApplyResult<Func, FirstTypes&&..., Rest...> { | |
294 return expandAndApply(kj::fwd<Func>(func), kj::mv(getImpl<indexes>(first))..., | |
295 kj::fwd<Rest>(rest)...); | |
296 } | |
297 | |
298 template <typename Func, typename... FirstTypes, typename... Rest, size_t... indexes> | |
299 inline auto expandAndApplyWithIndexes( | |
300 Indexes<indexes...>, Func&& func, const Tuple<FirstTypes...>& first, Rest&&... rest) | |
301 -> ExpandAndApplyResult<Func, FirstTypes..., Rest...> { | |
302 return expandAndApply(kj::fwd<Func>(func), getImpl<indexes>(first)..., | |
303 kj::fwd<Rest>(rest)...); | |
304 } | |
305 | |
306 struct MakeTupleFunc { | |
307 template <typename... Params> | |
308 Tuple<Decay<Params>...> operator()(Params&&... params) { | |
309 return Tuple<Decay<Params>...>(kj::fwd<Params>(params)...); | |
310 } | |
311 template <typename Param> | |
312 Decay<Param> operator()(Param&& param) { | |
313 return kj::fwd<Param>(param); | |
314 } | |
315 }; | |
316 | |
317 } // namespace _ (private) | |
318 | |
319 template <typename... T> struct Tuple_ { typedef _::Tuple<T...> Type; }; | |
320 template <typename T> struct Tuple_<T> { typedef T Type; }; | |
321 | |
322 template <typename... T> using Tuple = typename Tuple_<T...>::Type; | |
323 // Tuple type. `Tuple<T>` (i.e. a single-element tuple) is a synonym for `T`. Tuples of size | |
324 // other than 1 expand to an internal type. Either way, you can construct a Tuple using | |
325 // `kj::tuple(...)`, get an element by index `i` using `kj::get<i>(myTuple)`, and expand the tuple | |
326 // as arguments to a function using `kj::apply(func, myTuple)`. | |
327 // | |
328 // Tuples are always flat -- that is, no element of a Tuple is ever itself a Tuple. If you | |
329 // construct a tuple from other tuples, the elements are flattened and concatenated. | |
330 | |
331 template <typename... Params> | |
332 inline auto tuple(Params&&... params) | |
333 -> decltype(_::expandAndApply(_::MakeTupleFunc(), kj::fwd<Params>(params)...)) { | |
334 // Construct a new tuple from the given values. Any tuples in the argument list will be | |
335 // flattened into the result. | |
336 return _::expandAndApply(_::MakeTupleFunc(), kj::fwd<Params>(params)...); | |
337 } | |
338 | |
339 template <size_t index, typename Tuple> | |
340 inline auto get(Tuple&& tuple) -> decltype(_::getImpl<index>(kj::fwd<Tuple>(tuple))) { | |
341 // Unpack and return the tuple element at the given index. The index is specified as a template | |
342 // parameter, e.g. `kj::get<3>(myTuple)`. | |
343 return _::getImpl<index>(kj::fwd<Tuple>(tuple)); | |
344 } | |
345 | |
346 template <typename Func, typename... Params> | |
347 inline auto apply(Func&& func, Params&&... params) | |
348 -> decltype(_::expandAndApply(kj::fwd<Func>(func), kj::fwd<Params>(params)...)) { | |
349 // Apply a function to some arguments, expanding tuples into separate arguments. | |
350 return _::expandAndApply(kj::fwd<Func>(func), kj::fwd<Params>(params)...); | |
351 } | |
352 | |
353 template <typename T> struct TupleSize_ { static constexpr size_t size = 1; }; | |
354 template <typename... T> struct TupleSize_<_::Tuple<T...>> { | |
355 static constexpr size_t size = sizeof...(T); | |
356 }; | |
357 | |
358 template <typename T> | |
359 constexpr size_t tupleSize() { return TupleSize_<T>::size; } | |
360 // Returns size of the tuple T. | |
361 | |
362 } // namespace kj | |
363 | |
364 #endif // KJ_TUPLE_H_ |