annotate win32-mingw/include/kj/tuple.h @ 83:ae30d91d2ffe

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