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