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 */ 449