Pair.h 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. /* A class holding a pair of objects that tries to conserve storage space. */
  6. #ifndef mozilla_Pair_h
  7. #define mozilla_Pair_h
  8. #include "mozilla/Attributes.h"
  9. #include "mozilla/Move.h"
  10. #include "mozilla/TypeTraits.h"
  11. namespace mozilla {
  12. namespace detail {
  13. enum StorageType { AsBase, AsMember };
  14. // Optimize storage using the Empty Base Optimization -- that empty base classes
  15. // don't take up space -- to optimize size when one or the other class is
  16. // stateless and can be used as a base class.
  17. //
  18. // The extra conditions on storage for B are necessary so that PairHelper won't
  19. // ambiguously inherit from either A or B, such that one or the other base class
  20. // would be inaccessible.
  21. template<typename A, typename B,
  22. detail::StorageType =
  23. IsEmpty<A>::value ? detail::AsBase : detail::AsMember,
  24. detail::StorageType =
  25. IsEmpty<B>::value && !IsBaseOf<A, B>::value && !IsBaseOf<B, A>::value
  26. ? detail::AsBase
  27. : detail::AsMember>
  28. struct PairHelper;
  29. template<typename A, typename B>
  30. struct PairHelper<A, B, AsMember, AsMember>
  31. {
  32. protected:
  33. template<typename AArg, typename BArg>
  34. PairHelper(AArg&& aA, BArg&& aB)
  35. : mFirstA(Forward<AArg>(aA)),
  36. mSecondB(Forward<BArg>(aB))
  37. {}
  38. A& first() { return mFirstA; }
  39. const A& first() const { return mFirstA; }
  40. B& second() { return mSecondB; }
  41. const B& second() const { return mSecondB; }
  42. void swap(PairHelper& aOther)
  43. {
  44. Swap(mFirstA, aOther.mFirstA);
  45. Swap(mSecondB, aOther.mSecondB);
  46. }
  47. private:
  48. A mFirstA;
  49. B mSecondB;
  50. };
  51. template<typename A, typename B>
  52. struct PairHelper<A, B, AsMember, AsBase> : private B
  53. {
  54. protected:
  55. template<typename AArg, typename BArg>
  56. PairHelper(AArg&& aA, BArg&& aB)
  57. : B(Forward<BArg>(aB)),
  58. mFirstA(Forward<AArg>(aA))
  59. {}
  60. A& first() { return mFirstA; }
  61. const A& first() const { return mFirstA; }
  62. B& second() { return *this; }
  63. const B& second() const { return *this; }
  64. void swap(PairHelper& aOther)
  65. {
  66. Swap(mFirstA, aOther.mFirstA);
  67. Swap(static_cast<B&>(*this), static_cast<B&>(aOther));
  68. }
  69. private:
  70. A mFirstA;
  71. };
  72. template<typename A, typename B>
  73. struct PairHelper<A, B, AsBase, AsMember> : private A
  74. {
  75. protected:
  76. template<typename AArg, typename BArg>
  77. PairHelper(AArg&& aA, BArg&& aB)
  78. : A(Forward<AArg>(aA)),
  79. mSecondB(Forward<BArg>(aB))
  80. {}
  81. A& first() { return *this; }
  82. const A& first() const { return *this; }
  83. B& second() { return mSecondB; }
  84. const B& second() const { return mSecondB; }
  85. void swap(PairHelper& aOther)
  86. {
  87. Swap(static_cast<A&>(*this), static_cast<A&>(aOther));
  88. Swap(mSecondB, aOther.mSecondB);
  89. }
  90. private:
  91. B mSecondB;
  92. };
  93. template<typename A, typename B>
  94. struct PairHelper<A, B, AsBase, AsBase> : private A, private B
  95. {
  96. protected:
  97. template<typename AArg, typename BArg>
  98. PairHelper(AArg&& aA, BArg&& aB)
  99. : A(Forward<AArg>(aA)),
  100. B(Forward<BArg>(aB))
  101. {}
  102. A& first() { return static_cast<A&>(*this); }
  103. const A& first() const { return static_cast<A&>(*this); }
  104. B& second() { return static_cast<B&>(*this); }
  105. const B& second() const { return static_cast<B&>(*this); }
  106. void swap(PairHelper& aOther)
  107. {
  108. Swap(static_cast<A&>(*this), static_cast<A&>(aOther));
  109. Swap(static_cast<B&>(*this), static_cast<B&>(aOther));
  110. }
  111. };
  112. } // namespace detail
  113. /**
  114. * Pair is the logical concatenation of an instance of A with an instance B.
  115. * Space is conserved when possible. Neither A nor B may be a final class.
  116. *
  117. * It's typically clearer to have individual A and B member fields. Except if
  118. * you want the space-conserving qualities of Pair, you're probably better off
  119. * not using this!
  120. *
  121. * No guarantees are provided about the memory layout of A and B, the order of
  122. * initialization or destruction of A and B, and so on. (This is approximately
  123. * required to optimize space usage.) The first/second names are merely
  124. * conceptual!
  125. */
  126. template<typename A, typename B>
  127. struct Pair
  128. : private detail::PairHelper<A, B>
  129. {
  130. typedef typename detail::PairHelper<A, B> Base;
  131. public:
  132. template<typename AArg, typename BArg>
  133. Pair(AArg&& aA, BArg&& aB)
  134. : Base(Forward<AArg>(aA), Forward<BArg>(aB))
  135. {}
  136. Pair(Pair&& aOther)
  137. : Base(Move(aOther.first()), Move(aOther.second()))
  138. { }
  139. Pair(const Pair& aOther) = default;
  140. Pair& operator=(Pair&& aOther)
  141. {
  142. MOZ_ASSERT(this != &aOther, "Self-moves are prohibited");
  143. first() = Move(aOther.first());
  144. second() = Move(aOther.second());
  145. return *this;
  146. }
  147. Pair& operator=(const Pair& aOther) = default;
  148. /** The A instance. */
  149. using Base::first;
  150. /** The B instance. */
  151. using Base::second;
  152. /** Swap this pair with another pair. */
  153. void swap(Pair& aOther) { Base::swap(aOther); }
  154. };
  155. template<typename A, class B>
  156. void
  157. Swap(Pair<A, B>& aX, Pair<A, B>& aY)
  158. {
  159. aX.swap(aY);
  160. }
  161. /**
  162. * MakePair allows you to construct a Pair instance using type inference. A call
  163. * like this:
  164. *
  165. * MakePair(Foo(), Bar())
  166. *
  167. * will return a Pair<Foo, Bar>.
  168. */
  169. template<typename A, typename B>
  170. Pair<typename RemoveCV<typename RemoveReference<A>::Type>::Type,
  171. typename RemoveCV<typename RemoveReference<B>::Type>::Type>
  172. MakePair(A&& aA, B&& aB)
  173. {
  174. return
  175. Pair<typename RemoveCV<typename RemoveReference<A>::Type>::Type,
  176. typename RemoveCV<typename RemoveReference<B>::Type>::Type>(
  177. Forward<A>(aA),
  178. Forward<B>(aB));
  179. }
  180. } // namespace mozilla
  181. #endif /* mozilla_Pair_h */