Pair.h 5.7 KB

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