xref: /aosp_15_r20/external/abseil-cpp/absl/container/internal/compressed_tuple.h (revision 9356374a3709195abf420251b3e825997ff56c0f)
1*9356374aSAndroid Build Coastguard Worker // Copyright 2018 The Abseil Authors.
2*9356374aSAndroid Build Coastguard Worker //
3*9356374aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*9356374aSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*9356374aSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*9356374aSAndroid Build Coastguard Worker //
7*9356374aSAndroid Build Coastguard Worker //      https://www.apache.org/licenses/LICENSE-2.0
8*9356374aSAndroid Build Coastguard Worker //
9*9356374aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*9356374aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*9356374aSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9356374aSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*9356374aSAndroid Build Coastguard Worker // limitations under the License.
14*9356374aSAndroid Build Coastguard Worker //
15*9356374aSAndroid Build Coastguard Worker // Helper class to perform the Empty Base Optimization.
16*9356374aSAndroid Build Coastguard Worker // Ts can contain classes and non-classes, empty or not. For the ones that
17*9356374aSAndroid Build Coastguard Worker // are empty classes, we perform the optimization. If all types in Ts are empty
18*9356374aSAndroid Build Coastguard Worker // classes, then CompressedTuple<Ts...> is itself an empty class.
19*9356374aSAndroid Build Coastguard Worker //
20*9356374aSAndroid Build Coastguard Worker // To access the members, use member get<N>() function.
21*9356374aSAndroid Build Coastguard Worker //
22*9356374aSAndroid Build Coastguard Worker // Eg:
23*9356374aSAndroid Build Coastguard Worker //   absl::container_internal::CompressedTuple<int, T1, T2, T3> value(7, t1, t2,
24*9356374aSAndroid Build Coastguard Worker //                                                                    t3);
25*9356374aSAndroid Build Coastguard Worker //   assert(value.get<0>() == 7);
26*9356374aSAndroid Build Coastguard Worker //   T1& t1 = value.get<1>();
27*9356374aSAndroid Build Coastguard Worker //   const T2& t2 = value.get<2>();
28*9356374aSAndroid Build Coastguard Worker //   ...
29*9356374aSAndroid Build Coastguard Worker //
30*9356374aSAndroid Build Coastguard Worker // https://en.cppreference.com/w/cpp/language/ebo
31*9356374aSAndroid Build Coastguard Worker 
32*9356374aSAndroid Build Coastguard Worker #ifndef ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_
33*9356374aSAndroid Build Coastguard Worker #define ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_
34*9356374aSAndroid Build Coastguard Worker 
35*9356374aSAndroid Build Coastguard Worker #include <initializer_list>
36*9356374aSAndroid Build Coastguard Worker #include <tuple>
37*9356374aSAndroid Build Coastguard Worker #include <type_traits>
38*9356374aSAndroid Build Coastguard Worker #include <utility>
39*9356374aSAndroid Build Coastguard Worker 
40*9356374aSAndroid Build Coastguard Worker #include "absl/utility/utility.h"
41*9356374aSAndroid Build Coastguard Worker 
42*9356374aSAndroid Build Coastguard Worker #if defined(_MSC_VER) && !defined(__NVCC__)
43*9356374aSAndroid Build Coastguard Worker // We need to mark these classes with this declspec to ensure that
44*9356374aSAndroid Build Coastguard Worker // CompressedTuple happens.
45*9356374aSAndroid Build Coastguard Worker #define ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC __declspec(empty_bases)
46*9356374aSAndroid Build Coastguard Worker #else
47*9356374aSAndroid Build Coastguard Worker #define ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC
48*9356374aSAndroid Build Coastguard Worker #endif
49*9356374aSAndroid Build Coastguard Worker 
50*9356374aSAndroid Build Coastguard Worker namespace absl {
51*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_BEGIN
52*9356374aSAndroid Build Coastguard Worker namespace container_internal {
53*9356374aSAndroid Build Coastguard Worker 
54*9356374aSAndroid Build Coastguard Worker template <typename... Ts>
55*9356374aSAndroid Build Coastguard Worker class CompressedTuple;
56*9356374aSAndroid Build Coastguard Worker 
57*9356374aSAndroid Build Coastguard Worker namespace internal_compressed_tuple {
58*9356374aSAndroid Build Coastguard Worker 
59*9356374aSAndroid Build Coastguard Worker template <typename D, size_t I>
60*9356374aSAndroid Build Coastguard Worker struct Elem;
61*9356374aSAndroid Build Coastguard Worker template <typename... B, size_t I>
62*9356374aSAndroid Build Coastguard Worker struct Elem<CompressedTuple<B...>, I>
63*9356374aSAndroid Build Coastguard Worker     : std::tuple_element<I, std::tuple<B...>> {};
64*9356374aSAndroid Build Coastguard Worker template <typename D, size_t I>
65*9356374aSAndroid Build Coastguard Worker using ElemT = typename Elem<D, I>::type;
66*9356374aSAndroid Build Coastguard Worker 
67*9356374aSAndroid Build Coastguard Worker // We can't use EBCO on other CompressedTuples because that would mean that we
68*9356374aSAndroid Build Coastguard Worker // derive from multiple Storage<> instantiations with the same I parameter,
69*9356374aSAndroid Build Coastguard Worker // and potentially from multiple identical Storage<> instantiations.  So anytime
70*9356374aSAndroid Build Coastguard Worker // we use type inheritance rather than encapsulation, we mark
71*9356374aSAndroid Build Coastguard Worker // CompressedTupleImpl, to make this easy to detect.
72*9356374aSAndroid Build Coastguard Worker struct uses_inheritance {};
73*9356374aSAndroid Build Coastguard Worker 
74*9356374aSAndroid Build Coastguard Worker template <typename T>
75*9356374aSAndroid Build Coastguard Worker constexpr bool ShouldUseBase() {
76*9356374aSAndroid Build Coastguard Worker   return std::is_class<T>::value && std::is_empty<T>::value &&
77*9356374aSAndroid Build Coastguard Worker          !std::is_final<T>::value &&
78*9356374aSAndroid Build Coastguard Worker          !std::is_base_of<uses_inheritance, T>::value;
79*9356374aSAndroid Build Coastguard Worker }
80*9356374aSAndroid Build Coastguard Worker 
81*9356374aSAndroid Build Coastguard Worker // The storage class provides two specializations:
82*9356374aSAndroid Build Coastguard Worker //  - For empty classes, it stores T as a base class.
83*9356374aSAndroid Build Coastguard Worker //  - For everything else, it stores T as a member.
84*9356374aSAndroid Build Coastguard Worker template <typename T, size_t I, bool UseBase = ShouldUseBase<T>()>
85*9356374aSAndroid Build Coastguard Worker struct Storage {
86*9356374aSAndroid Build Coastguard Worker   T value;
87*9356374aSAndroid Build Coastguard Worker   constexpr Storage() = default;
88*9356374aSAndroid Build Coastguard Worker   template <typename V>
89*9356374aSAndroid Build Coastguard Worker   explicit constexpr Storage(absl::in_place_t, V&& v)
90*9356374aSAndroid Build Coastguard Worker       : value(std::forward<V>(v)) {}
91*9356374aSAndroid Build Coastguard Worker   constexpr const T& get() const& { return value; }
92*9356374aSAndroid Build Coastguard Worker   constexpr T& get() & { return value; }
93*9356374aSAndroid Build Coastguard Worker   constexpr const T&& get() const&& { return std::move(*this).value; }
94*9356374aSAndroid Build Coastguard Worker   constexpr T&& get() && { return std::move(*this).value; }
95*9356374aSAndroid Build Coastguard Worker };
96*9356374aSAndroid Build Coastguard Worker 
97*9356374aSAndroid Build Coastguard Worker template <typename T, size_t I>
98*9356374aSAndroid Build Coastguard Worker struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC Storage<T, I, true> : T {
99*9356374aSAndroid Build Coastguard Worker   constexpr Storage() = default;
100*9356374aSAndroid Build Coastguard Worker 
101*9356374aSAndroid Build Coastguard Worker   template <typename V>
102*9356374aSAndroid Build Coastguard Worker   explicit constexpr Storage(absl::in_place_t, V&& v) : T(std::forward<V>(v)) {}
103*9356374aSAndroid Build Coastguard Worker 
104*9356374aSAndroid Build Coastguard Worker   constexpr const T& get() const& { return *this; }
105*9356374aSAndroid Build Coastguard Worker   constexpr T& get() & { return *this; }
106*9356374aSAndroid Build Coastguard Worker   constexpr const T&& get() const&& { return std::move(*this); }
107*9356374aSAndroid Build Coastguard Worker   constexpr T&& get() && { return std::move(*this); }
108*9356374aSAndroid Build Coastguard Worker };
109*9356374aSAndroid Build Coastguard Worker 
110*9356374aSAndroid Build Coastguard Worker template <typename D, typename I, bool ShouldAnyUseBase>
111*9356374aSAndroid Build Coastguard Worker struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTupleImpl;
112*9356374aSAndroid Build Coastguard Worker 
113*9356374aSAndroid Build Coastguard Worker template <typename... Ts, size_t... I, bool ShouldAnyUseBase>
114*9356374aSAndroid Build Coastguard Worker struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTupleImpl<
115*9356374aSAndroid Build Coastguard Worker     CompressedTuple<Ts...>, absl::index_sequence<I...>, ShouldAnyUseBase>
116*9356374aSAndroid Build Coastguard Worker     // We use the dummy identity function through std::integral_constant to
117*9356374aSAndroid Build Coastguard Worker     // convince MSVC of accepting and expanding I in that context. Without it
118*9356374aSAndroid Build Coastguard Worker     // you would get:
119*9356374aSAndroid Build Coastguard Worker     //   error C3548: 'I': parameter pack cannot be used in this context
120*9356374aSAndroid Build Coastguard Worker     : uses_inheritance,
121*9356374aSAndroid Build Coastguard Worker       Storage<Ts, std::integral_constant<size_t, I>::value>... {
122*9356374aSAndroid Build Coastguard Worker   constexpr CompressedTupleImpl() = default;
123*9356374aSAndroid Build Coastguard Worker   template <typename... Vs>
124*9356374aSAndroid Build Coastguard Worker   explicit constexpr CompressedTupleImpl(absl::in_place_t, Vs&&... args)
125*9356374aSAndroid Build Coastguard Worker       : Storage<Ts, I>(absl::in_place, std::forward<Vs>(args))... {}
126*9356374aSAndroid Build Coastguard Worker   friend CompressedTuple<Ts...>;
127*9356374aSAndroid Build Coastguard Worker };
128*9356374aSAndroid Build Coastguard Worker 
129*9356374aSAndroid Build Coastguard Worker template <typename... Ts, size_t... I>
130*9356374aSAndroid Build Coastguard Worker struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTupleImpl<
131*9356374aSAndroid Build Coastguard Worker     CompressedTuple<Ts...>, absl::index_sequence<I...>, false>
132*9356374aSAndroid Build Coastguard Worker     // We use the dummy identity function as above...
133*9356374aSAndroid Build Coastguard Worker     : Storage<Ts, std::integral_constant<size_t, I>::value, false>... {
134*9356374aSAndroid Build Coastguard Worker   constexpr CompressedTupleImpl() = default;
135*9356374aSAndroid Build Coastguard Worker   template <typename... Vs>
136*9356374aSAndroid Build Coastguard Worker   explicit constexpr CompressedTupleImpl(absl::in_place_t, Vs&&... args)
137*9356374aSAndroid Build Coastguard Worker       : Storage<Ts, I, false>(absl::in_place, std::forward<Vs>(args))... {}
138*9356374aSAndroid Build Coastguard Worker   friend CompressedTuple<Ts...>;
139*9356374aSAndroid Build Coastguard Worker };
140*9356374aSAndroid Build Coastguard Worker 
141*9356374aSAndroid Build Coastguard Worker std::false_type Or(std::initializer_list<std::false_type>);
142*9356374aSAndroid Build Coastguard Worker std::true_type Or(std::initializer_list<bool>);
143*9356374aSAndroid Build Coastguard Worker 
144*9356374aSAndroid Build Coastguard Worker // MSVC requires this to be done separately rather than within the declaration
145*9356374aSAndroid Build Coastguard Worker // of CompressedTuple below.
146*9356374aSAndroid Build Coastguard Worker template <typename... Ts>
147*9356374aSAndroid Build Coastguard Worker constexpr bool ShouldAnyUseBase() {
148*9356374aSAndroid Build Coastguard Worker   return decltype(
149*9356374aSAndroid Build Coastguard Worker       Or({std::integral_constant<bool, ShouldUseBase<Ts>()>()...})){};
150*9356374aSAndroid Build Coastguard Worker }
151*9356374aSAndroid Build Coastguard Worker 
152*9356374aSAndroid Build Coastguard Worker template <typename T, typename V>
153*9356374aSAndroid Build Coastguard Worker using TupleElementMoveConstructible =
154*9356374aSAndroid Build Coastguard Worker     typename std::conditional<std::is_reference<T>::value,
155*9356374aSAndroid Build Coastguard Worker                               std::is_convertible<V, T>,
156*9356374aSAndroid Build Coastguard Worker                               std::is_constructible<T, V&&>>::type;
157*9356374aSAndroid Build Coastguard Worker 
158*9356374aSAndroid Build Coastguard Worker template <bool SizeMatches, class T, class... Vs>
159*9356374aSAndroid Build Coastguard Worker struct TupleMoveConstructible : std::false_type {};
160*9356374aSAndroid Build Coastguard Worker 
161*9356374aSAndroid Build Coastguard Worker template <class... Ts, class... Vs>
162*9356374aSAndroid Build Coastguard Worker struct TupleMoveConstructible<true, CompressedTuple<Ts...>, Vs...>
163*9356374aSAndroid Build Coastguard Worker     : std::integral_constant<
164*9356374aSAndroid Build Coastguard Worker           bool, absl::conjunction<
165*9356374aSAndroid Build Coastguard Worker                     TupleElementMoveConstructible<Ts, Vs&&>...>::value> {};
166*9356374aSAndroid Build Coastguard Worker 
167*9356374aSAndroid Build Coastguard Worker template <typename T>
168*9356374aSAndroid Build Coastguard Worker struct compressed_tuple_size;
169*9356374aSAndroid Build Coastguard Worker 
170*9356374aSAndroid Build Coastguard Worker template <typename... Es>
171*9356374aSAndroid Build Coastguard Worker struct compressed_tuple_size<CompressedTuple<Es...>>
172*9356374aSAndroid Build Coastguard Worker     : public std::integral_constant<std::size_t, sizeof...(Es)> {};
173*9356374aSAndroid Build Coastguard Worker 
174*9356374aSAndroid Build Coastguard Worker template <class T, class... Vs>
175*9356374aSAndroid Build Coastguard Worker struct TupleItemsMoveConstructible
176*9356374aSAndroid Build Coastguard Worker     : std::integral_constant<
177*9356374aSAndroid Build Coastguard Worker           bool, TupleMoveConstructible<compressed_tuple_size<T>::value ==
178*9356374aSAndroid Build Coastguard Worker                                            sizeof...(Vs),
179*9356374aSAndroid Build Coastguard Worker                                        T, Vs...>::value> {};
180*9356374aSAndroid Build Coastguard Worker 
181*9356374aSAndroid Build Coastguard Worker }  // namespace internal_compressed_tuple
182*9356374aSAndroid Build Coastguard Worker 
183*9356374aSAndroid Build Coastguard Worker // Helper class to perform the Empty Base Class Optimization.
184*9356374aSAndroid Build Coastguard Worker // Ts can contain classes and non-classes, empty or not. For the ones that
185*9356374aSAndroid Build Coastguard Worker // are empty classes, we perform the CompressedTuple. If all types in Ts are
186*9356374aSAndroid Build Coastguard Worker // empty classes, then CompressedTuple<Ts...> is itself an empty class.  (This
187*9356374aSAndroid Build Coastguard Worker // does not apply when one or more of those empty classes is itself an empty
188*9356374aSAndroid Build Coastguard Worker // CompressedTuple.)
189*9356374aSAndroid Build Coastguard Worker //
190*9356374aSAndroid Build Coastguard Worker // To access the members, use member .get<N>() function.
191*9356374aSAndroid Build Coastguard Worker //
192*9356374aSAndroid Build Coastguard Worker // Eg:
193*9356374aSAndroid Build Coastguard Worker //   absl::container_internal::CompressedTuple<int, T1, T2, T3> value(7, t1, t2,
194*9356374aSAndroid Build Coastguard Worker //                                                                    t3);
195*9356374aSAndroid Build Coastguard Worker //   assert(value.get<0>() == 7);
196*9356374aSAndroid Build Coastguard Worker //   T1& t1 = value.get<1>();
197*9356374aSAndroid Build Coastguard Worker //   const T2& t2 = value.get<2>();
198*9356374aSAndroid Build Coastguard Worker //   ...
199*9356374aSAndroid Build Coastguard Worker //
200*9356374aSAndroid Build Coastguard Worker // https://en.cppreference.com/w/cpp/language/ebo
201*9356374aSAndroid Build Coastguard Worker template <typename... Ts>
202*9356374aSAndroid Build Coastguard Worker class ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTuple
203*9356374aSAndroid Build Coastguard Worker     : private internal_compressed_tuple::CompressedTupleImpl<
204*9356374aSAndroid Build Coastguard Worker           CompressedTuple<Ts...>, absl::index_sequence_for<Ts...>,
205*9356374aSAndroid Build Coastguard Worker           internal_compressed_tuple::ShouldAnyUseBase<Ts...>()> {
206*9356374aSAndroid Build Coastguard Worker  private:
207*9356374aSAndroid Build Coastguard Worker   template <int I>
208*9356374aSAndroid Build Coastguard Worker   using ElemT = internal_compressed_tuple::ElemT<CompressedTuple, I>;
209*9356374aSAndroid Build Coastguard Worker 
210*9356374aSAndroid Build Coastguard Worker   template <int I>
211*9356374aSAndroid Build Coastguard Worker   using StorageT = internal_compressed_tuple::Storage<ElemT<I>, I>;
212*9356374aSAndroid Build Coastguard Worker 
213*9356374aSAndroid Build Coastguard Worker  public:
214*9356374aSAndroid Build Coastguard Worker   // There seems to be a bug in MSVC dealing in which using '=default' here will
215*9356374aSAndroid Build Coastguard Worker   // cause the compiler to ignore the body of other constructors. The work-
216*9356374aSAndroid Build Coastguard Worker   // around is to explicitly implement the default constructor.
217*9356374aSAndroid Build Coastguard Worker #if defined(_MSC_VER)
218*9356374aSAndroid Build Coastguard Worker   constexpr CompressedTuple() : CompressedTuple::CompressedTupleImpl() {}
219*9356374aSAndroid Build Coastguard Worker #else
220*9356374aSAndroid Build Coastguard Worker   constexpr CompressedTuple() = default;
221*9356374aSAndroid Build Coastguard Worker #endif
222*9356374aSAndroid Build Coastguard Worker   explicit constexpr CompressedTuple(const Ts&... base)
223*9356374aSAndroid Build Coastguard Worker       : CompressedTuple::CompressedTupleImpl(absl::in_place, base...) {}
224*9356374aSAndroid Build Coastguard Worker 
225*9356374aSAndroid Build Coastguard Worker   template <typename First, typename... Vs,
226*9356374aSAndroid Build Coastguard Worker             absl::enable_if_t<
227*9356374aSAndroid Build Coastguard Worker                 absl::conjunction<
228*9356374aSAndroid Build Coastguard Worker                     // Ensure we are not hiding default copy/move constructors.
229*9356374aSAndroid Build Coastguard Worker                     absl::negation<std::is_same<void(CompressedTuple),
230*9356374aSAndroid Build Coastguard Worker                                                 void(absl::decay_t<First>)>>,
231*9356374aSAndroid Build Coastguard Worker                     internal_compressed_tuple::TupleItemsMoveConstructible<
232*9356374aSAndroid Build Coastguard Worker                         CompressedTuple<Ts...>, First, Vs...>>::value,
233*9356374aSAndroid Build Coastguard Worker                 bool> = true>
234*9356374aSAndroid Build Coastguard Worker   explicit constexpr CompressedTuple(First&& first, Vs&&... base)
235*9356374aSAndroid Build Coastguard Worker       : CompressedTuple::CompressedTupleImpl(absl::in_place,
236*9356374aSAndroid Build Coastguard Worker                                              std::forward<First>(first),
237*9356374aSAndroid Build Coastguard Worker                                              std::forward<Vs>(base)...) {}
238*9356374aSAndroid Build Coastguard Worker 
239*9356374aSAndroid Build Coastguard Worker   template <int I>
240*9356374aSAndroid Build Coastguard Worker   constexpr ElemT<I>& get() & {
241*9356374aSAndroid Build Coastguard Worker     return StorageT<I>::get();
242*9356374aSAndroid Build Coastguard Worker   }
243*9356374aSAndroid Build Coastguard Worker 
244*9356374aSAndroid Build Coastguard Worker   template <int I>
245*9356374aSAndroid Build Coastguard Worker   constexpr const ElemT<I>& get() const& {
246*9356374aSAndroid Build Coastguard Worker     return StorageT<I>::get();
247*9356374aSAndroid Build Coastguard Worker   }
248*9356374aSAndroid Build Coastguard Worker 
249*9356374aSAndroid Build Coastguard Worker   template <int I>
250*9356374aSAndroid Build Coastguard Worker   constexpr ElemT<I>&& get() && {
251*9356374aSAndroid Build Coastguard Worker     return std::move(*this).StorageT<I>::get();
252*9356374aSAndroid Build Coastguard Worker   }
253*9356374aSAndroid Build Coastguard Worker 
254*9356374aSAndroid Build Coastguard Worker   template <int I>
255*9356374aSAndroid Build Coastguard Worker   constexpr const ElemT<I>&& get() const&& {
256*9356374aSAndroid Build Coastguard Worker     return std::move(*this).StorageT<I>::get();
257*9356374aSAndroid Build Coastguard Worker   }
258*9356374aSAndroid Build Coastguard Worker };
259*9356374aSAndroid Build Coastguard Worker 
260*9356374aSAndroid Build Coastguard Worker // Explicit specialization for a zero-element tuple
261*9356374aSAndroid Build Coastguard Worker // (needed to avoid ambiguous overloads for the default constructor).
262*9356374aSAndroid Build Coastguard Worker template <>
263*9356374aSAndroid Build Coastguard Worker class ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTuple<> {};
264*9356374aSAndroid Build Coastguard Worker 
265*9356374aSAndroid Build Coastguard Worker }  // namespace container_internal
266*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_END
267*9356374aSAndroid Build Coastguard Worker }  // namespace absl
268*9356374aSAndroid Build Coastguard Worker 
269*9356374aSAndroid Build Coastguard Worker #undef ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC
270*9356374aSAndroid Build Coastguard Worker 
271*9356374aSAndroid Build Coastguard Worker #endif  // ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_
272