Bug 1637291 [wpt PR 23538] - Update some scriptlevel tests to match the new syntax...
[gecko.git] / mfbt / CompactPair.h
blob28b2dd001b49c6f5a4bd30ee6e885e4a3aec0529
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/. */
7 /* A class holding a pair of objects that tries to conserve storage space. */
9 #ifndef mozilla_CompactPair_h
10 #define mozilla_CompactPair_h
12 #include <type_traits>
13 #include <utility>
15 #include "mozilla/Attributes.h"
17 namespace mozilla {
19 namespace detail {
21 enum StorageType { AsBase, AsMember };
23 // Optimize storage using the Empty Base Optimization -- that empty base classes
24 // don't take up space -- to optimize size when one or the other class is
25 // stateless and can be used as a base class.
27 // The extra conditions on storage for B are necessary so that CompactPairHelper
28 // won't ambiguously inherit from either A or B, such that one or the other base
29 // class would be inaccessible.
30 template <typename A, typename B,
31 detail::StorageType =
32 std::is_empty_v<A> ? detail::AsBase : detail::AsMember,
33 detail::StorageType = std::is_empty_v<B> &&
34 !std::is_base_of<A, B>::value &&
35 !std::is_base_of<B, A>::value
36 ? detail::AsBase
37 : detail::AsMember>
38 struct CompactPairHelper;
40 template <typename A, typename B>
41 struct CompactPairHelper<A, B, AsMember, AsMember> {
42 protected:
43 template <typename AArg, typename BArg>
44 CompactPairHelper(AArg&& aA, BArg&& aB)
45 : mFirstA(std::forward<AArg>(aA)), mSecondB(std::forward<BArg>(aB)) {}
47 A& first() { return mFirstA; }
48 const A& first() const { return mFirstA; }
49 B& second() { return mSecondB; }
50 const B& second() const { return mSecondB; }
52 void swap(CompactPairHelper& aOther) {
53 std::swap(mFirstA, aOther.mFirstA);
54 std::swap(mSecondB, aOther.mSecondB);
57 private:
58 A mFirstA;
59 B mSecondB;
62 template <typename A, typename B>
63 struct CompactPairHelper<A, B, AsMember, AsBase> : private B {
64 protected:
65 template <typename AArg, typename BArg>
66 CompactPairHelper(AArg&& aA, BArg&& aB)
67 : B(std::forward<BArg>(aB)), mFirstA(std::forward<AArg>(aA)) {}
69 A& first() { return mFirstA; }
70 const A& first() const { return mFirstA; }
71 B& second() { return *this; }
72 const B& second() const { return *this; }
74 void swap(CompactPairHelper& aOther) {
75 std::swap(mFirstA, aOther.mFirstA);
76 std::swap(static_cast<B&>(*this), static_cast<B&>(aOther));
79 private:
80 A mFirstA;
83 template <typename A, typename B>
84 struct CompactPairHelper<A, B, AsBase, AsMember> : private A {
85 protected:
86 template <typename AArg, typename BArg>
87 CompactPairHelper(AArg&& aA, BArg&& aB)
88 : A(std::forward<AArg>(aA)), mSecondB(std::forward<BArg>(aB)) {}
90 A& first() { return *this; }
91 const A& first() const { return *this; }
92 B& second() { return mSecondB; }
93 const B& second() const { return mSecondB; }
95 void swap(CompactPairHelper& aOther) {
96 std::swap(static_cast<A&>(*this), static_cast<A&>(aOther));
97 std::swap(mSecondB, aOther.mSecondB);
100 private:
101 B mSecondB;
104 template <typename A, typename B>
105 struct CompactPairHelper<A, B, AsBase, AsBase> : private A, private B {
106 protected:
107 template <typename AArg, typename BArg>
108 CompactPairHelper(AArg&& aA, BArg&& aB)
109 : A(std::forward<AArg>(aA)), B(std::forward<BArg>(aB)) {}
111 A& first() { return static_cast<A&>(*this); }
112 const A& first() const { return static_cast<A&>(*this); }
113 B& second() { return static_cast<B&>(*this); }
114 const B& second() const { return static_cast<B&>(*this); }
116 void swap(CompactPairHelper& aOther) {
117 std::swap(static_cast<A&>(*this), static_cast<A&>(aOther));
118 std::swap(static_cast<B&>(*this), static_cast<B&>(aOther));
122 } // namespace detail
125 * CompactPair is the logical concatenation of an instance of A with an instance
126 * B. Space is conserved when possible. Neither A nor B may be a final class.
128 * In general if space conservation is not critical is preferred to use
129 * std::pair.
131 * It's typically clearer to have individual A and B member fields. Except if
132 * you want the space-conserving qualities of CompactPair, you're probably
133 * better off not using this!
135 * No guarantees are provided about the memory layout of A and B, the order of
136 * initialization or destruction of A and B, and so on. (This is approximately
137 * required to optimize space usage.) The first/second names are merely
138 * conceptual!
140 template <typename A, typename B>
141 struct CompactPair : private detail::CompactPairHelper<A, B> {
142 typedef typename detail::CompactPairHelper<A, B> Base;
144 public:
145 template <typename AArg, typename BArg>
146 CompactPair(AArg&& aA, BArg&& aB)
147 : Base(std::forward<AArg>(aA), std::forward<BArg>(aB)) {}
149 CompactPair(CompactPair&& aOther) = default;
150 CompactPair(const CompactPair& aOther) = default;
152 CompactPair& operator=(CompactPair&& aOther) = default;
153 CompactPair& operator=(const CompactPair& aOther) = default;
155 /** The A instance. */
156 using Base::first;
157 /** The B instance. */
158 using Base::second;
160 /** Swap this pair with another pair. */
161 void swap(CompactPair& aOther) { Base::swap(aOther); }
165 * MakeCompactPair allows you to construct a CompactPair instance using type
166 * inference. A call like this:
168 * MakeCompactPair(Foo(), Bar())
170 * will return a CompactPair<Foo, Bar>.
172 template <typename A, typename B>
173 CompactPair<std::remove_cv_t<std::remove_reference_t<A>>,
174 std::remove_cv_t<std::remove_reference_t<B>>>
175 MakeCompactPair(A&& aA, B&& aB) {
176 return CompactPair<std::remove_cv_t<std::remove_reference_t<A>>,
177 std::remove_cv_t<std::remove_reference_t<B>>>(
178 std::forward<A>(aA), std::forward<B>(aB));
181 } // namespace mozilla
183 namespace std {
185 template <typename A, class B>
186 void swap(mozilla::CompactPair<A, B>& aX, mozilla::CompactPair<A, B>& aY) {
187 aX.swap(aY);
190 } // namespace std
192 #endif /* mozilla_CompactPair_h */