Andrew Top | 2ea2238 | 2016-12-08 09:47:36 -0800 | [diff] [blame] | 1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
| 2 | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
| 3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
| 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
| 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| 6 | |
| 7 | /* A variadic tuple class. */ |
| 8 | |
| 9 | #ifndef mozilla_Tuple_h |
| 10 | #define mozilla_Tuple_h |
| 11 | |
| 12 | #include "mozilla/Move.h" |
| 13 | #include "mozilla/Pair.h" |
| 14 | #include "mozilla/TemplateLib.h" |
| 15 | #include "mozilla/TypeTraits.h" |
| 16 | |
| 17 | #include <stddef.h> |
| 18 | #include <utility> |
| 19 | |
| 20 | namespace mozilla { |
| 21 | |
| 22 | namespace detail { |
| 23 | |
| 24 | /* |
| 25 | * A helper class that allows passing around multiple variadic argument lists |
| 26 | * by grouping them. |
| 27 | */ |
| 28 | template<typename... Ts> |
| 29 | struct Group; |
| 30 | |
| 31 | /* |
| 32 | * CheckConvertibility checks whether each type in a source pack of types |
| 33 | * is convertible to the corresponding type in a target pack of types. |
| 34 | * |
| 35 | * It is intended to be invoked like this: |
| 36 | * CheckConvertibility<Group<SourceTypes...>, Group<TargetTypes...>> |
| 37 | * 'Group' is used to separate types in the two packs (otherwise if we just |
| 38 | * wrote 'CheckConvertibility<SourceTypes..., TargetTypes...', it couldn't |
| 39 | * know where the first pack ends and the second begins). |
| 40 | * |
| 41 | * Note that we need to check explicitly that the two packs are of the same |
| 42 | * size, because attempting to simultaneously expand two parameter packs |
| 43 | * is an error (and it would be a hard error, because it wouldn't be in the |
| 44 | * immediate context of the caller). |
| 45 | */ |
| 46 | |
| 47 | template<typename Source, typename Target, bool SameSize> |
| 48 | struct CheckConvertibilityImpl; |
| 49 | |
| 50 | template<typename Source, typename Target> |
| 51 | struct CheckConvertibilityImpl<Source, Target, false> |
| 52 | : FalseType {}; |
| 53 | |
| 54 | template<typename... SourceTypes, typename... TargetTypes> |
| 55 | struct CheckConvertibilityImpl<Group<SourceTypes...>, Group<TargetTypes...>, true> |
| 56 | : IntegralConstant<bool, tl::And<IsConvertible<SourceTypes, TargetTypes>::value...>::value> { }; |
| 57 | |
| 58 | template<typename Source, typename Target> |
| 59 | struct CheckConvertibility; |
| 60 | |
| 61 | template<typename... SourceTypes, typename... TargetTypes> |
| 62 | struct CheckConvertibility<Group<SourceTypes...>, Group<TargetTypes...>> |
| 63 | : CheckConvertibilityImpl<Group<SourceTypes...>, Group<TargetTypes...>, |
| 64 | sizeof...(SourceTypes) == sizeof...(TargetTypes)> { }; |
| 65 | |
| 66 | /* |
| 67 | * TupleImpl is a helper class used to implement mozilla::Tuple. |
| 68 | * It represents one node in a recursive inheritance hierarchy. |
| 69 | * 'Index' is the 0-based index of the tuple element stored in this node; |
| 70 | * 'Elements...' are the types of the elements stored in this node and its |
| 71 | * base classes. |
| 72 | * |
| 73 | * Example: |
| 74 | * Tuple<int, float, char> inherits from |
| 75 | * TupleImpl<0, int, float, char>, which stores the 'int' and inherits from |
| 76 | * TupleImpl<1, float, char>, which stores the 'float' and inherits from |
| 77 | * TupleImpl<2, char>, which stores the 'char' and inherits from |
| 78 | * TupleImpl<3>, which stores nothing and terminates the recursion. |
| 79 | * |
| 80 | * The purpose of the 'Index' parameter is to allow efficient index-based |
| 81 | * access to a tuple element: given a tuple, and an index 'I' that we wish to |
| 82 | * access, we can cast the tuple to the base which stores the I'th element |
| 83 | * by performing template argument deduction against 'TupleImpl<I, E...>', |
| 84 | * where 'I' is specified explicitly and 'E...' is deduced (this is what the |
| 85 | * non-member 'Get<N>(t)' function does). |
| 86 | * |
| 87 | * This implementation strategy is borrowed from libstdc++'s std::tuple |
| 88 | * implementation. |
| 89 | */ |
| 90 | template<std::size_t Index, typename... Elements> |
| 91 | struct TupleImpl; |
| 92 | |
| 93 | /* |
| 94 | * The base case of the inheritance recursion (and also the implementation |
| 95 | * of an empty tuple). |
| 96 | */ |
| 97 | template<std::size_t Index> |
| 98 | struct TupleImpl<Index> {}; |
| 99 | |
| 100 | /* |
| 101 | * One node of the recursive inheritance hierarchy. It stores the element at |
| 102 | * index 'Index' of a tuple, of type 'HeadT', and inherits from the nodes |
| 103 | * that store the remaining elements, of types 'TailT...'. |
| 104 | */ |
| 105 | template<std::size_t Index, typename HeadT, typename... TailT> |
| 106 | struct TupleImpl<Index, HeadT, TailT...> |
| 107 | : public TupleImpl<Index + 1, TailT...> |
| 108 | { |
| 109 | typedef TupleImpl<Index + 1, TailT...> Base; |
| 110 | |
| 111 | // Accessors for the head and the tail. |
| 112 | // These are static, because the intended usage is for the caller to, |
| 113 | // given a tuple, obtain the type B of the base class which stores the |
| 114 | // element of interest, and then call B::Head(tuple) to access it. |
| 115 | // (Tail() is mostly for internal use, but is exposed for consistency.) |
| 116 | static HeadT& Head(TupleImpl& aTuple) { return aTuple.mHead; } |
| 117 | static const HeadT& Head(const TupleImpl& aTuple) { return aTuple.mHead; } |
| 118 | static Base& Tail(TupleImpl& aTuple) { return aTuple; } |
| 119 | static const Base& Tail(const TupleImpl& aTuple) { return aTuple; } |
| 120 | |
| 121 | TupleImpl() : Base(), mHead() { } |
| 122 | |
| 123 | // Construct from const references to the elements. |
| 124 | explicit TupleImpl(const HeadT& aHead, const TailT&... aTail) |
| 125 | : Base(aTail...), mHead(aHead) { } |
| 126 | |
| 127 | // Construct from objects that are convertible to the elements. |
| 128 | // This constructor is enabled only when the argument types are actually |
| 129 | // convertible to the element types, otherwise it could become a better |
| 130 | // match for certain invocations than the copy constructor. |
| 131 | template <typename OtherHeadT, typename... OtherTailT, |
| 132 | typename = typename EnableIf< |
| 133 | CheckConvertibility< |
| 134 | Group<OtherHeadT, OtherTailT...>, |
| 135 | Group<HeadT, TailT...>>::value>::Type> |
| 136 | explicit TupleImpl(OtherHeadT&& aHead, OtherTailT&&... aTail) |
| 137 | : Base(Forward<OtherTailT>(aTail)...), mHead(Forward<OtherHeadT>(aHead)) { } |
| 138 | |
| 139 | // Copy and move constructors. |
| 140 | // We'd like to use '= default' to implement these, but MSVC 2013's support |
| 141 | // for '= default' is incomplete and this doesn't work. |
| 142 | TupleImpl(const TupleImpl& aOther) |
| 143 | : Base(Tail(aOther)) |
| 144 | , mHead(Head(aOther)) {} |
| 145 | TupleImpl(TupleImpl&& aOther) |
| 146 | : Base(Move(Tail(aOther))) |
| 147 | , mHead(Forward<HeadT>(Head(aOther))) {} |
| 148 | |
| 149 | // Assign from a tuple whose elements are convertible to the elements |
| 150 | // of this tuple. |
| 151 | template <typename... OtherElements, |
| 152 | typename = typename EnableIf< |
| 153 | sizeof...(OtherElements) == sizeof...(TailT) + 1>::Type> |
| 154 | TupleImpl& operator=(const TupleImpl<Index, OtherElements...>& aOther) |
| 155 | { |
| 156 | typedef TupleImpl<Index, OtherElements...> OtherT; |
| 157 | Head(*this) = OtherT::Head(aOther); |
| 158 | Tail(*this) = OtherT::Tail(aOther); |
| 159 | return *this; |
| 160 | } |
| 161 | template <typename... OtherElements, |
| 162 | typename = typename EnableIf< |
| 163 | sizeof...(OtherElements) == sizeof...(TailT) + 1>::Type> |
| 164 | TupleImpl& operator=(TupleImpl<Index, OtherElements...>&& aOther) |
| 165 | { |
| 166 | typedef TupleImpl<Index, OtherElements...> OtherT; |
| 167 | Head(*this) = Move(OtherT::Head(aOther)); |
| 168 | Tail(*this) = Move(OtherT::Tail(aOther)); |
| 169 | return *this; |
| 170 | } |
| 171 | |
| 172 | // Copy and move assignment operators. |
| 173 | TupleImpl& operator=(const TupleImpl& aOther) |
| 174 | { |
| 175 | Head(*this) = Head(aOther); |
| 176 | Tail(*this) = Tail(aOther); |
| 177 | return *this; |
| 178 | } |
| 179 | TupleImpl& operator=(TupleImpl&& aOther) |
| 180 | { |
| 181 | Head(*this) = Move(Head(aOther)); |
| 182 | Tail(*this) = Move(Tail(aOther)); |
| 183 | return *this; |
| 184 | } |
| 185 | private: |
| 186 | HeadT mHead; // The element stored at this index in the tuple. |
| 187 | }; |
| 188 | |
| 189 | } // namespace detail |
| 190 | |
| 191 | /** |
| 192 | * Tuple is a class that stores zero or more objects, whose types are specified |
| 193 | * as template parameters. It can be thought of as a generalization of Pair, |
| 194 | * (which can be thought of as a 2-tuple). |
| 195 | * |
| 196 | * Tuple allows index-based access to its elements (with the index having to be |
| 197 | * known at compile time) via the non-member function 'Get<N>(tuple)'. |
| 198 | */ |
| 199 | template<typename... Elements> |
| 200 | class Tuple : public detail::TupleImpl<0, Elements...> |
| 201 | { |
| 202 | typedef detail::TupleImpl<0, Elements...> Impl; |
| 203 | public: |
| 204 | // The constructors and assignment operators here are simple wrappers |
| 205 | // around those in TupleImpl. |
| 206 | |
| 207 | Tuple() : Impl() { } |
| 208 | explicit Tuple(const Elements&... aElements) : Impl(aElements...) { } |
| 209 | // Here, we can't just use 'typename... OtherElements' because MSVC will give |
| 210 | // a warning "C4520: multiple default constructors specified" (even if no one |
| 211 | // actually instantiates the constructor with an empty parameter pack - |
| 212 | // that's probably a bug) and we compile with warnings-as-errors. |
| 213 | template <typename OtherHead, typename... OtherTail, |
| 214 | typename = typename EnableIf< |
| 215 | detail::CheckConvertibility< |
| 216 | detail::Group<OtherHead, OtherTail...>, |
| 217 | detail::Group<Elements...>>::value>::Type> |
| 218 | explicit Tuple(OtherHead&& aHead, OtherTail&&... aTail) |
| 219 | : Impl(Forward<OtherHead>(aHead), Forward<OtherTail>(aTail)...) { } |
| 220 | Tuple(const Tuple& aOther) : Impl(aOther) { } |
| 221 | Tuple(Tuple&& aOther) : Impl(Move(aOther)) { } |
| 222 | |
| 223 | template <typename... OtherElements, |
| 224 | typename = typename EnableIf< |
| 225 | sizeof...(OtherElements) == sizeof...(Elements)>::Type> |
| 226 | Tuple& operator=(const Tuple<OtherElements...>& aOther) |
| 227 | { |
| 228 | static_cast<Impl&>(*this) = aOther; |
| 229 | return *this; |
| 230 | } |
| 231 | template <typename... OtherElements, |
| 232 | typename = typename EnableIf< |
| 233 | sizeof...(OtherElements) == sizeof...(Elements)>::Type> |
| 234 | Tuple& operator=(Tuple<OtherElements...>&& aOther) |
| 235 | { |
| 236 | static_cast<Impl&>(*this) = Move(aOther); |
| 237 | return *this; |
| 238 | } |
| 239 | Tuple& operator=(const Tuple& aOther) |
| 240 | { |
| 241 | static_cast<Impl&>(*this) = aOther; |
| 242 | return *this; |
| 243 | } |
| 244 | Tuple& operator=(Tuple&& aOther) |
| 245 | { |
| 246 | static_cast<Impl&>(*this) = Move(aOther); |
| 247 | return *this; |
| 248 | } |
| 249 | }; |
| 250 | |
| 251 | /** |
| 252 | * Specialization of Tuple for two elements. |
| 253 | * This is created to support construction and assignment from a Pair or std::pair. |
| 254 | */ |
| 255 | template <typename A, typename B> |
| 256 | class Tuple<A, B> : public detail::TupleImpl<0, A, B> |
| 257 | { |
| 258 | typedef detail::TupleImpl<0, A, B> Impl; |
| 259 | |
| 260 | public: |
| 261 | // The constructors and assignment operators here are simple wrappers |
| 262 | // around those in TupleImpl. |
| 263 | |
| 264 | Tuple() : Impl() { } |
| 265 | explicit Tuple(const A& aA, const B& aB) : Impl(aA, aB) { } |
| 266 | template <typename AArg, typename BArg, |
| 267 | typename = typename EnableIf< |
| 268 | detail::CheckConvertibility< |
| 269 | detail::Group<AArg, BArg>, |
| 270 | detail::Group<A, B>>::value>::Type> |
| 271 | explicit Tuple(AArg&& aA, BArg&& aB) |
| 272 | : Impl(Forward<AArg>(aA), Forward<BArg>(aB)) { } |
| 273 | Tuple(const Tuple& aOther) : Impl(aOther) { } |
| 274 | Tuple(Tuple&& aOther) : Impl(Move(aOther)) { } |
| 275 | explicit Tuple(const Pair<A, B>& aOther) |
| 276 | : Impl(aOther.first(), aOther.second()) { } |
| 277 | explicit Tuple(Pair<A, B>&& aOther) : Impl(Forward<A>(aOther.first()), |
| 278 | Forward<B>(aOther.second())) { } |
| 279 | explicit Tuple(const std::pair<A, B>& aOther) |
| 280 | : Impl(aOther.first, aOther.second) { } |
| 281 | explicit Tuple(std::pair<A, B>&& aOther) : Impl(Forward<A>(aOther.first), |
| 282 | Forward<B>(aOther.second)) { } |
| 283 | |
| 284 | template <typename AArg, typename BArg> |
| 285 | Tuple& operator=(const Tuple<AArg, BArg>& aOther) |
| 286 | { |
| 287 | static_cast<Impl&>(*this) = aOther; |
| 288 | return *this; |
| 289 | } |
| 290 | template <typename AArg, typename BArg> |
| 291 | Tuple& operator=(Tuple<AArg, BArg>&& aOther) |
| 292 | { |
| 293 | static_cast<Impl&>(*this) = Move(aOther); |
| 294 | return *this; |
| 295 | } |
| 296 | Tuple& operator=(const Tuple& aOther) |
| 297 | { |
| 298 | static_cast<Impl&>(*this) = aOther; |
| 299 | return *this; |
| 300 | } |
| 301 | Tuple& operator=(Tuple&& aOther) |
| 302 | { |
| 303 | static_cast<Impl&>(*this) = Move(aOther); |
| 304 | return *this; |
| 305 | } |
| 306 | template <typename AArg, typename BArg> |
| 307 | Tuple& operator=(const Pair<AArg, BArg>& aOther) |
| 308 | { |
| 309 | Impl::Head(*this) = aOther.first(); |
| 310 | Impl::Tail(*this).Head(*this) = aOther.second(); |
| 311 | return *this; |
| 312 | } |
| 313 | template <typename AArg, typename BArg> |
| 314 | Tuple& operator=(Pair<AArg, BArg>&& aOther) |
| 315 | { |
| 316 | Impl::Head(*this) = Forward<AArg>(aOther.first()); |
| 317 | Impl::Tail(*this).Head(*this) = Forward<BArg>(aOther.second()); |
| 318 | return *this; |
| 319 | } |
| 320 | template <typename AArg, typename BArg> |
| 321 | Tuple& operator=(const std::pair<AArg, BArg>& aOther) |
| 322 | { |
| 323 | Impl::Head(*this) = aOther.first; |
| 324 | Impl::Tail(*this).Head(*this) = aOther.second; |
| 325 | return *this; |
| 326 | } |
| 327 | template <typename AArg, typename BArg> |
| 328 | Tuple& operator=(std::pair<AArg, BArg>&& aOther) |
| 329 | { |
| 330 | Impl::Head(*this) = Forward<AArg>(aOther.first); |
| 331 | Impl::Tail(*this).Head(*this) = Forward<BArg>(aOther.second); |
| 332 | return *this; |
| 333 | } |
| 334 | }; |
| 335 | |
| 336 | /** |
| 337 | * Specialization of Tuple for zero arguments. |
| 338 | * This is necessary because if the primary template were instantiated with |
| 339 | * an empty parameter pack, the 'Tuple(Elements...)' constructors would |
| 340 | * become illegal overloads of the default constructor. |
| 341 | */ |
| 342 | template <> |
| 343 | class Tuple<> {}; |
| 344 | |
| 345 | namespace detail { |
| 346 | |
| 347 | /* |
| 348 | * Helper functions for implementing Get<N>(tuple). |
| 349 | * These functions take a TupleImpl<Index, Elements...>, with Index being |
| 350 | * explicitly specified, and Elements being deduced. By passing a Tuple |
| 351 | * object as argument, template argument deduction will do its magic and |
| 352 | * cast the tuple to the base class which stores the element at Index. |
| 353 | */ |
| 354 | |
| 355 | // Const reference version. |
| 356 | template<std::size_t Index, typename... Elements> |
| 357 | auto TupleGetHelper(TupleImpl<Index, Elements...>& aTuple) |
| 358 | -> decltype(TupleImpl<Index, Elements...>::Head(aTuple)) |
| 359 | { |
| 360 | return TupleImpl<Index, Elements...>::Head(aTuple); |
| 361 | } |
| 362 | |
| 363 | // Non-const reference version. |
| 364 | template<std::size_t Index, typename... Elements> |
| 365 | auto TupleGetHelper(const TupleImpl<Index, Elements...>& aTuple) |
| 366 | -> decltype(TupleImpl<Index, Elements...>::Head(aTuple)) |
| 367 | { |
| 368 | return TupleImpl<Index, Elements...>::Head(aTuple); |
| 369 | } |
| 370 | |
| 371 | } // namespace detail |
| 372 | |
| 373 | /** |
| 374 | * Index-based access to an element of a tuple. |
| 375 | * The syntax is Get<Index>(tuple). The index is zero-based. |
| 376 | * |
| 377 | * Example: |
| 378 | * |
| 379 | * Tuple<int, float, char> t; |
| 380 | * ... |
| 381 | * float f = Get<1>(t); |
| 382 | */ |
| 383 | |
| 384 | // Non-const reference version. |
| 385 | template<std::size_t Index, typename... Elements> |
| 386 | auto Get(Tuple<Elements...>& aTuple) |
| 387 | -> decltype(detail::TupleGetHelper<Index>(aTuple)) |
| 388 | { |
| 389 | return detail::TupleGetHelper<Index>(aTuple); |
| 390 | } |
| 391 | |
| 392 | // Const reference version. |
| 393 | template<std::size_t Index, typename... Elements> |
| 394 | auto Get(const Tuple<Elements...>& aTuple) |
| 395 | -> decltype(detail::TupleGetHelper<Index>(aTuple)) |
| 396 | { |
| 397 | return detail::TupleGetHelper<Index>(aTuple); |
| 398 | } |
| 399 | |
| 400 | // Rvalue reference version. |
| 401 | template<std::size_t Index, typename... Elements> |
| 402 | auto Get(Tuple<Elements...>&& aTuple) |
| 403 | -> decltype(Move(mozilla::Get<Index>(aTuple))) |
| 404 | { |
| 405 | // We need a 'mozilla::' qualification here to avoid |
| 406 | // name lookup only finding the current function. |
| 407 | return Move(mozilla::Get<Index>(aTuple)); |
| 408 | } |
| 409 | |
| 410 | /** |
| 411 | * A convenience function for constructing a tuple out of a sequence of |
| 412 | * values without specifying the type of the tuple. |
| 413 | * The type of the tuple is deduced from the types of its elements. |
| 414 | * |
| 415 | * Example: |
| 416 | * |
| 417 | * auto tuple = MakeTuple(42, 0.5f, 'c'); // has type Tuple<int, float, char> |
| 418 | */ |
| 419 | template<typename... Elements> |
| 420 | inline Tuple<typename Decay<Elements>::Type...> |
| 421 | MakeTuple(Elements&&... aElements) |
| 422 | { |
| 423 | return Tuple<typename Decay<Elements>::Type...>(Forward<Elements>(aElements)...); |
| 424 | } |
| 425 | |
| 426 | /** |
| 427 | * A convenience function for constructing a tuple of references to a |
| 428 | * sequence of variables. Since assignments to the elements of the tuple |
| 429 | * "go through" to the referenced variables, this can be used to "unpack" |
| 430 | * a tuple into individual variables. |
| 431 | * |
| 432 | * Example: |
| 433 | * |
| 434 | * int i; |
| 435 | * float f; |
| 436 | * char c; |
| 437 | * Tie(i, f, c) = FunctionThatReturnsATuple(); |
| 438 | */ |
| 439 | template<typename... Elements> |
| 440 | inline Tuple<Elements&...> |
| 441 | Tie(Elements&... aVariables) |
| 442 | { |
| 443 | return Tuple<Elements&...>(aVariables...); |
| 444 | } |
| 445 | |
| 446 | } // namespace mozilla |
| 447 | |
| 448 | #endif /* mozilla_Tuple_h */ |