/src/LPM/external.protobuf/include/absl/container/internal/layout.h
Line  | Count  | Source (jump to first uncovered line)  | 
1  |  | // Copyright 2018 The Abseil Authors.  | 
2  |  | //  | 
3  |  | // Licensed under the Apache License, Version 2.0 (the "License");  | 
4  |  | // you may not use this file except in compliance with the License.  | 
5  |  | // You may obtain a copy of the License at  | 
6  |  | //  | 
7  |  | //      https://www.apache.org/licenses/LICENSE-2.0  | 
8  |  | //  | 
9  |  | // Unless required by applicable law or agreed to in writing, software  | 
10  |  | // distributed under the License is distributed on an "AS IS" BASIS,  | 
11  |  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  | 
12  |  | // See the License for the specific language governing permissions and  | 
13  |  | // limitations under the License.  | 
14  |  | //  | 
15  |  | //                           MOTIVATION AND TUTORIAL  | 
16  |  | //  | 
17  |  | // If you want to put in a single heap allocation N doubles followed by M ints,  | 
18  |  | // it's easy if N and M are known at compile time.  | 
19  |  | //  | 
20  |  | //   struct S { | 
21  |  | //     double a[N];  | 
22  |  | //     int b[M];  | 
23  |  | //   };  | 
24  |  | //  | 
25  |  | //   S* p = new S;  | 
26  |  | //  | 
27  |  | // But what if N and M are known only in run time? Class template Layout to the  | 
28  |  | // rescue! It's a portable generalization of the technique known as struct hack.  | 
29  |  | //  | 
30  |  | //   // This object will tell us everything we need to know about the memory  | 
31  |  | //   // layout of double[N] followed by int[M]. It's structurally identical to  | 
32  |  | //   // size_t[2] that stores N and M. It's very cheap to create.  | 
33  |  | //   const Layout<double, int> layout(N, M);  | 
34  |  | //  | 
35  |  | //   // Allocate enough memory for both arrays. `AllocSize()` tells us how much  | 
36  |  | //   // memory is needed. We are free to use any allocation function we want as  | 
37  |  | //   // long as it returns aligned memory.  | 
38  |  | //   std::unique_ptr<unsigned char[]> p(new unsigned char[layout.AllocSize()]);  | 
39  |  | //  | 
40  |  | //   // Obtain the pointer to the array of doubles.  | 
41  |  | //   // Equivalent to `reinterpret_cast<double*>(p.get())`.  | 
42  |  | //   //  | 
43  |  | //   // We could have written layout.Pointer<0>(p) instead. If all the types are  | 
44  |  | //   // unique you can use either form, but if some types are repeated you must  | 
45  |  | //   // use the index form.  | 
46  |  | //   double* a = layout.Pointer<double>(p.get());  | 
47  |  | //  | 
48  |  | //   // Obtain the pointer to the array of ints.  | 
49  |  | //   // Equivalent to `reinterpret_cast<int*>(p.get() + N * 8)`.  | 
50  |  | //   int* b = layout.Pointer<int>(p);  | 
51  |  | //  | 
52  |  | // If we are unable to specify sizes of all fields, we can pass as many sizes as  | 
53  |  | // we can to `Partial()`. In return, it'll allow us to access the fields whose  | 
54  |  | // locations and sizes can be computed from the provided information.  | 
55  |  | // `Partial()` comes in handy when the array sizes are embedded into the  | 
56  |  | // allocation.  | 
57  |  | //  | 
58  |  | //   // size_t[0] containing N, size_t[1] containing M, double[N], int[M].  | 
59  |  | //   using L = Layout<size_t, size_t, double, int>;  | 
60  |  | //  | 
61  |  | //   unsigned char* Allocate(size_t n, size_t m) { | 
62  |  | //     const L layout(1, 1, n, m);  | 
63  |  | //     unsigned char* p = new unsigned char[layout.AllocSize()];  | 
64  |  | //     *layout.Pointer<0>(p) = n;  | 
65  |  | //     *layout.Pointer<1>(p) = m;  | 
66  |  | //     return p;  | 
67  |  | //   }  | 
68  |  | //  | 
69  |  | //   void Use(unsigned char* p) { | 
70  |  | //     // First, extract N and M.  | 
71  |  | //     // Specify that the first array has only one element. Using `prefix` we  | 
72  |  | //     // can access the first two arrays but not more.  | 
73  |  | //     constexpr auto prefix = L::Partial(1);  | 
74  |  | //     size_t n = *prefix.Pointer<0>(p);  | 
75  |  | //     size_t m = *prefix.Pointer<1>(p);  | 
76  |  | //  | 
77  |  | //     // Now we can get pointers to the payload.  | 
78  |  | //     const L layout(1, 1, n, m);  | 
79  |  | //     double* a = layout.Pointer<double>(p);  | 
80  |  | //     int* b = layout.Pointer<int>(p);  | 
81  |  | //   }  | 
82  |  | //  | 
83  |  | // The layout we used above combines fixed-size with dynamically-sized fields.  | 
84  |  | // This is quite common. Layout is optimized for this use case and generates  | 
85  |  | // optimal code. All computations that can be performed at compile time are  | 
86  |  | // indeed performed at compile time.  | 
87  |  | //  | 
88  |  | // Efficiency tip: The order of fields matters. In `Layout<T1, ..., TN>` try to  | 
89  |  | // ensure that `alignof(T1) >= ... >= alignof(TN)`. This way you'll have no  | 
90  |  | // padding in between arrays.  | 
91  |  | //  | 
92  |  | // You can manually override the alignment of an array by wrapping the type in  | 
93  |  | // `Aligned<T, N>`. `Layout<..., Aligned<T, N>, ...>` has exactly the same API  | 
94  |  | // and behavior as `Layout<..., T, ...>` except that the first element of the  | 
95  |  | // array of `T` is aligned to `N` (the rest of the elements follow without  | 
96  |  | // padding). `N` cannot be less than `alignof(T)`.  | 
97  |  | //  | 
98  |  | // `AllocSize()` and `Pointer()` are the most basic methods for dealing with  | 
99  |  | // memory layouts. Check out the reference or code below to discover more.  | 
100  |  | //  | 
101  |  | //                            EXAMPLE  | 
102  |  | //  | 
103  |  | //   // Immutable move-only string with sizeof equal to sizeof(void*). The  | 
104  |  | //   // string size and the characters are kept in the same heap allocation.  | 
105  |  | //   class CompactString { | 
106  |  | //    public:  | 
107  |  | //     CompactString(const char* s = "") { | 
108  |  | //       const size_t size = strlen(s);  | 
109  |  | //       // size_t[1] followed by char[size + 1].  | 
110  |  | //       const L layout(1, size + 1);  | 
111  |  | //       p_.reset(new unsigned char[layout.AllocSize()]);  | 
112  |  | //       // If running under ASAN, mark the padding bytes, if any, to catch  | 
113  |  | //       // memory errors.  | 
114  |  | //       layout.PoisonPadding(p_.get());  | 
115  |  | //       // Store the size in the allocation.  | 
116  |  | //       *layout.Pointer<size_t>(p_.get()) = size;  | 
117  |  | //       // Store the characters in the allocation.  | 
118  |  | //       memcpy(layout.Pointer<char>(p_.get()), s, size + 1);  | 
119  |  | //     }  | 
120  |  | //  | 
121  |  | //     size_t size() const { | 
122  |  | //       // Equivalent to reinterpret_cast<size_t&>(*p).  | 
123  |  | //       return *L::Partial().Pointer<size_t>(p_.get());  | 
124  |  | //     }  | 
125  |  | //  | 
126  |  | //     const char* c_str() const { | 
127  |  | //       // Equivalent to reinterpret_cast<char*>(p.get() + sizeof(size_t)).  | 
128  |  | //       // The argument in Partial(1) specifies that we have size_t[1] in front  | 
129  |  | //       // of the characters.  | 
130  |  | //       return L::Partial(1).Pointer<char>(p_.get());  | 
131  |  | //     }  | 
132  |  | //  | 
133  |  | //    private:  | 
134  |  | //     // Our heap allocation contains a size_t followed by an array of chars.  | 
135  |  | //     using L = Layout<size_t, char>;  | 
136  |  | //     std::unique_ptr<unsigned char[]> p_;  | 
137  |  | //   };  | 
138  |  | //  | 
139  |  | //   int main() { | 
140  |  | //     CompactString s = "hello";  | 
141  |  | //     assert(s.size() == 5);  | 
142  |  | //     assert(strcmp(s.c_str(), "hello") == 0);  | 
143  |  | //   }  | 
144  |  | //  | 
145  |  | //                               DOCUMENTATION  | 
146  |  | //  | 
147  |  | // The interface exported by this file consists of:  | 
148  |  | // - class `Layout<>` and its public members.  | 
149  |  | // - The public members of class `internal_layout::LayoutImpl<>`. That class  | 
150  |  | //   isn't intended to be used directly, and its name and template parameter  | 
151  |  | //   list are internal implementation details, but the class itself provides  | 
152  |  | //   most of the functionality in this file. See comments on its members for  | 
153  |  | //   detailed documentation.  | 
154  |  | //  | 
155  |  | // `Layout<T1,... Tn>::Partial(count1,..., countm)` (where `m` <= `n`) returns a  | 
156  |  | // `LayoutImpl<>` object. `Layout<T1,..., Tn> layout(count1,..., countn)`  | 
157  |  | // creates a `Layout` object, which exposes the same functionality by inheriting  | 
158  |  | // from `LayoutImpl<>`.  | 
159  |  |  | 
160  |  | #ifndef ABSL_CONTAINER_INTERNAL_LAYOUT_H_  | 
161  |  | #define ABSL_CONTAINER_INTERNAL_LAYOUT_H_  | 
162  |  |  | 
163  |  | #include <assert.h>  | 
164  |  | #include <stddef.h>  | 
165  |  | #include <stdint.h>  | 
166  |  |  | 
167  |  | #include <ostream>  | 
168  |  | #include <string>  | 
169  |  | #include <tuple>  | 
170  |  | #include <type_traits>  | 
171  |  | #include <typeinfo>  | 
172  |  | #include <utility>  | 
173  |  |  | 
174  |  | #include "absl/base/config.h"  | 
175  |  | #include "absl/debugging/internal/demangle.h"  | 
176  |  | #include "absl/meta/type_traits.h"  | 
177  |  | #include "absl/strings/str_cat.h"  | 
178  |  | #include "absl/types/span.h"  | 
179  |  | #include "absl/utility/utility.h"  | 
180  |  |  | 
181  |  | #ifdef ABSL_HAVE_ADDRESS_SANITIZER  | 
182  |  | #include <sanitizer/asan_interface.h>  | 
183  |  | #endif  | 
184  |  |  | 
185  |  | namespace absl { | 
186  |  | ABSL_NAMESPACE_BEGIN  | 
187  |  | namespace container_internal { | 
188  |  |  | 
189  |  | // A type wrapper that instructs `Layout` to use the specific alignment for the  | 
190  |  | // array. `Layout<..., Aligned<T, N>, ...>` has exactly the same API  | 
191  |  | // and behavior as `Layout<..., T, ...>` except that the first element of the  | 
192  |  | // array of `T` is aligned to `N` (the rest of the elements follow without  | 
193  |  | // padding).  | 
194  |  | //  | 
195  |  | // Requires: `N >= alignof(T)` and `N` is a power of 2.  | 
196  |  | template <class T, size_t N>  | 
197  |  | struct Aligned;  | 
198  |  |  | 
199  |  | namespace internal_layout { | 
200  |  |  | 
201  |  | template <class T>  | 
202  |  | struct NotAligned {}; | 
203  |  |  | 
204  |  | template <class T, size_t N>  | 
205  |  | struct NotAligned<const Aligned<T, N>> { | 
206  |  |   static_assert(sizeof(T) == 0, "Aligned<T, N> cannot be const-qualified");  | 
207  |  | };  | 
208  |  |  | 
209  |  | template <size_t>  | 
210  |  | using IntToSize = size_t;  | 
211  |  |  | 
212  |  | template <class>  | 
213  |  | using TypeToSize = size_t;  | 
214  |  |  | 
215  |  | template <class T>  | 
216  |  | struct Type : NotAligned<T> { | 
217  |  |   using type = T;  | 
218  |  | };  | 
219  |  |  | 
220  |  | template <class T, size_t N>  | 
221  |  | struct Type<Aligned<T, N>> { | 
222  |  |   using type = T;  | 
223  |  | };  | 
224  |  |  | 
225  |  | template <class T>  | 
226  |  | struct SizeOf : NotAligned<T>, std::integral_constant<size_t, sizeof(T)> {}; | 
227  |  |  | 
228  |  | template <class T, size_t N>  | 
229  |  | struct SizeOf<Aligned<T, N>> : std::integral_constant<size_t, sizeof(T)> {}; | 
230  |  |  | 
231  |  | // Note: workaround for https://gcc.gnu.org/PR88115  | 
232  |  | template <class T>  | 
233  |  | struct AlignOf : NotAligned<T> { | 
234  |  |   static constexpr size_t value = alignof(T);  | 
235  |  | };  | 
236  |  |  | 
237  |  | template <class T, size_t N>  | 
238  |  | struct AlignOf<Aligned<T, N>> { | 
239  |  |   static_assert(N % alignof(T) == 0,  | 
240  |  |                 "Custom alignment can't be lower than the type's alignment");  | 
241  |  |   static constexpr size_t value = N;  | 
242  |  | };  | 
243  |  |  | 
244  |  | // Does `Ts...` contain `T`?  | 
245  |  | template <class T, class... Ts>  | 
246  |  | using Contains = absl::disjunction<std::is_same<T, Ts>...>;  | 
247  |  |  | 
248  |  | template <class From, class To>  | 
249  |  | using CopyConst =  | 
250  |  |     typename std::conditional<std::is_const<From>::value, const To, To>::type;  | 
251  |  |  | 
252  |  | // Note: We're not qualifying this with absl:: because it doesn't compile under  | 
253  |  | // MSVC.  | 
254  |  | template <class T>  | 
255  |  | using SliceType = Span<T>;  | 
256  |  |  | 
257  |  | // This namespace contains no types. It prevents functions defined in it from  | 
258  |  | // being found by ADL.  | 
259  |  | namespace adl_barrier { | 
260  |  |  | 
261  |  | template <class Needle, class... Ts>  | 
262  |  | constexpr size_t Find(Needle, Needle, Ts...) { | 
263  |  |   static_assert(!Contains<Needle, Ts...>(), "Duplicate element type");  | 
264  |  |   return 0;  | 
265  |  | }  | 
266  |  |  | 
267  |  | template <class Needle, class T, class... Ts>  | 
268  |  | constexpr size_t Find(Needle, T, Ts...) { | 
269  |  |   return adl_barrier::Find(Needle(), Ts()...) + 1;  | 
270  |  | }  | 
271  |  |  | 
272  | 0  | constexpr bool IsPow2(size_t n) { return !(n & (n - 1)); } | 
273  |  |  | 
274  |  | // Returns `q * m` for the smallest `q` such that `q * m >= n`.  | 
275  |  | // Requires: `m` is a power of two. It's enforced by IsLegalElementType below.  | 
276  | 0  | constexpr size_t Align(size_t n, size_t m) { return (n + m - 1) & ~(m - 1); } | 
277  |  |  | 
278  | 0  | constexpr size_t Min(size_t a, size_t b) { return b < a ? b : a; } | 
279  |  |  | 
280  | 0  | constexpr size_t Max(size_t a) { return a; } | 
281  |  |  | 
282  |  | template <class... Ts>  | 
283  | 0  | constexpr size_t Max(size_t a, size_t b, Ts... rest) { | 
284  | 0  |   return adl_barrier::Max(b < a ? a : b, rest...);  | 
285  | 0  | } Unexecuted instantiation: unsigned long absl::lts_20240116::container_internal::internal_layout::adl_barrier::Max<>(unsigned long, unsigned long) Unexecuted instantiation: unsigned long absl::lts_20240116::container_internal::internal_layout::adl_barrier::Max<unsigned long>(unsigned long, unsigned long, unsigned long) Unexecuted instantiation: unsigned long absl::lts_20240116::container_internal::internal_layout::adl_barrier::Max<unsigned long, unsigned long>(unsigned long, unsigned long, unsigned long, unsigned long) Unexecuted instantiation: unsigned long absl::lts_20240116::container_internal::internal_layout::adl_barrier::Max<unsigned long, unsigned long, unsigned long>(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long)  | 
286  |  |  | 
287  |  | template <class T>  | 
288  |  | std::string TypeName() { | 
289  |  |   std::string out;  | 
290  |  | #if ABSL_INTERNAL_HAS_RTTI  | 
291  |  |   absl::StrAppend(&out, "<",  | 
292  |  |                   absl::debugging_internal::DemangleString(typeid(T).name()),  | 
293  |  |                   ">");  | 
294  |  | #endif  | 
295  |  |   return out;  | 
296  |  | }  | 
297  |  |  | 
298  |  | }  // namespace adl_barrier  | 
299  |  |  | 
300  |  | template <bool C>  | 
301  |  | using EnableIf = typename std::enable_if<C, int>::type;  | 
302  |  |  | 
303  |  | // Can `T` be a template argument of `Layout`?  | 
304  |  | template <class T>  | 
305  |  | using IsLegalElementType = std::integral_constant<  | 
306  |  |     bool, !std::is_reference<T>::value && !std::is_volatile<T>::value &&  | 
307  |  |               !std::is_reference<typename Type<T>::type>::value &&  | 
308  |  |               !std::is_volatile<typename Type<T>::type>::value &&  | 
309  |  |               adl_barrier::IsPow2(AlignOf<T>::value)>;  | 
310  |  |  | 
311  |  | template <class Elements, class SizeSeq, class OffsetSeq>  | 
312  |  | class LayoutImpl;  | 
313  |  |  | 
314  |  | // Public base class of `Layout` and the result type of `Layout::Partial()`.  | 
315  |  | //  | 
316  |  | // `Elements...` contains all template arguments of `Layout` that created this  | 
317  |  | // instance.  | 
318  |  | //  | 
319  |  | // `SizeSeq...` is `[0, NumSizes)` where `NumSizes` is the number of arguments  | 
320  |  | // passed to `Layout::Partial()` or `Layout::Layout()`.  | 
321  |  | //  | 
322  |  | // `OffsetSeq...` is `[0, NumOffsets)` where `NumOffsets` is  | 
323  |  | // `Min(sizeof...(Elements), NumSizes + 1)` (the number of arrays for which we  | 
324  |  | // can compute offsets).  | 
325  |  | template <class... Elements, size_t... SizeSeq, size_t... OffsetSeq>  | 
326  |  | class LayoutImpl<std::tuple<Elements...>, absl::index_sequence<SizeSeq...>,  | 
327  |  |                  absl::index_sequence<OffsetSeq...>> { | 
328  |  |  private:  | 
329  |  |   static_assert(sizeof...(Elements) > 0, "At least one field is required");  | 
330  |  |   static_assert(absl::conjunction<IsLegalElementType<Elements>...>::value,  | 
331  |  |                 "Invalid element type (see IsLegalElementType)");  | 
332  |  |  | 
333  |  |   enum { | 
334  |  |     NumTypes = sizeof...(Elements),  | 
335  |  |     NumSizes = sizeof...(SizeSeq),  | 
336  |  |     NumOffsets = sizeof...(OffsetSeq),  | 
337  |  |   };  | 
338  |  |  | 
339  |  |   // These are guaranteed by `Layout`.  | 
340  |  |   static_assert(NumOffsets == adl_barrier::Min(NumTypes, NumSizes + 1),  | 
341  |  |                 "Internal error");  | 
342  |  |   static_assert(NumTypes > 0, "Internal error");  | 
343  |  |  | 
344  |  |   // Returns the index of `T` in `Elements...`. Results in a compilation error  | 
345  |  |   // if `Elements...` doesn't contain exactly one instance of `T`.  | 
346  |  |   template <class T>  | 
347  |  |   static constexpr size_t ElementIndex() { | 
348  |  |     static_assert(Contains<Type<T>, Type<typename Type<Elements>::type>...>(),  | 
349  |  |                   "Type not found");  | 
350  |  |     return adl_barrier::Find(Type<T>(),  | 
351  |  |                              Type<typename Type<Elements>::type>()...);  | 
352  |  |   }  | 
353  |  |  | 
354  |  |   template <size_t N>  | 
355  |  |   using ElementAlignment =  | 
356  |  |       AlignOf<typename std::tuple_element<N, std::tuple<Elements...>>::type>;  | 
357  |  |  | 
358  |  |  public:  | 
359  |  |   // Element types of all arrays packed in a tuple.  | 
360  |  |   using ElementTypes = std::tuple<typename Type<Elements>::type...>;  | 
361  |  |  | 
362  |  |   // Element type of the Nth array.  | 
363  |  |   template <size_t N>  | 
364  |  |   using ElementType = typename std::tuple_element<N, ElementTypes>::type;  | 
365  |  |  | 
366  |  |   constexpr explicit LayoutImpl(IntToSize<SizeSeq>... sizes)  | 
367  |  |       : size_{sizes...} {} | 
368  |  |  | 
369  |  |   // Alignment of the layout, equal to the strictest alignment of all elements.  | 
370  |  |   // All pointers passed to the methods of layout must be aligned to this value.  | 
371  | 0  |   static constexpr size_t Alignment() { | 
372  | 0  |     return adl_barrier::Max(AlignOf<Elements>::value...);  | 
373  | 0  |   }  | 
374  |  |  | 
375  |  |   // Offset in bytes of the Nth array.  | 
376  |  |   //  | 
377  |  |   //   // int[3], 4 bytes of padding, double[4].  | 
378  |  |   //   Layout<int, double> x(3, 4);  | 
379  |  |   //   assert(x.Offset<0>() == 0);   // The ints starts from 0.  | 
380  |  |   //   assert(x.Offset<1>() == 16);  // The doubles starts from 16.  | 
381  |  |   //  | 
382  |  |   // Requires: `N <= NumSizes && N < sizeof...(Ts)`.  | 
383  |  |   template <size_t N, EnableIf<N == 0> = 0>  | 
384  | 0  |   constexpr size_t Offset() const { | 
385  | 0  |     return 0;  | 
386  | 0  |   } Unexecuted instantiation: _ZNK4absl12lts_2024011618container_internal15internal_layout10LayoutImplINSt3__15tupleIJPNS1_10btree_nodeINS1_10map_paramsIiN6google8protobuf8internal12ExtensionSet9ExtensionENS4_4lessIiEENS4_9allocatorINS4_4pairIKiSC_EEEELi256ELb0EEEEEjhNS1_13map_slot_typeIiSC_EESM_EEENS4_16integer_sequenceImJLm0ELm1ELm2ELm3ELm4EEEESR_E6OffsetILm0ETnNS4_9enable_ifIXeqT_Li0EEiE4typeELi0EEEmv Unexecuted instantiation: _ZNK4absl12lts_2024011618container_internal15internal_layout10LayoutImplINSt3__15tupleIJPNS1_10btree_nodeINS1_10map_paramsIN6google8protobuf8internal10VariantKeyEPNSA_8NodeBaseENS4_4lessISB_EENSA_12MapAllocatorINS4_4pairIKSB_SD_EEEELi256ELb0EEEEEjhNS1_13map_slot_typeISB_SD_EESN_EEENS4_16integer_sequenceImJLm0ELm1ELm2ELm3ELm4EEEESS_E6OffsetILm0ETnNS4_9enable_ifIXeqT_Li0EEiE4typeELi0EEEmv  | 
387  |  |  | 
388  |  |   template <size_t N, EnableIf<N != 0> = 0>  | 
389  | 0  |   constexpr size_t Offset() const { | 
390  | 0  |     static_assert(N < NumOffsets, "Index out of bounds");  | 
391  | 0  |     return adl_barrier::Align(  | 
392  | 0  |         Offset<N - 1>() + SizeOf<ElementType<N - 1>>::value * size_[N - 1],  | 
393  | 0  |         ElementAlignment<N>::value);  | 
394  | 0  |   } Unexecuted instantiation: _ZNK4absl12lts_2024011618container_internal15internal_layout10LayoutImplINSt3__15tupleIJPNS1_10btree_nodeINS1_10map_paramsIiN6google8protobuf8internal12ExtensionSet9ExtensionENS4_4lessIiEENS4_9allocatorINS4_4pairIKiSC_EEEELi256ELb0EEEEEjhNS1_13map_slot_typeIiSC_EESM_EEENS4_16integer_sequenceImJLm0ELm1ELm2ELm3ELm4EEEESR_E6OffsetILm1ETnNS4_9enable_ifIXneT_Li0EEiE4typeELi0EEEmv Unexecuted instantiation: _ZNK4absl12lts_2024011618container_internal15internal_layout10LayoutImplINSt3__15tupleIJPNS1_10btree_nodeINS1_10map_paramsIiN6google8protobuf8internal12ExtensionSet9ExtensionENS4_4lessIiEENS4_9allocatorINS4_4pairIKiSC_EEEELi256ELb0EEEEEjhNS1_13map_slot_typeIiSC_EESM_EEENS4_16integer_sequenceImJLm0ELm1ELm2ELm3ELm4EEEESR_E6OffsetILm2ETnNS4_9enable_ifIXneT_Li0EEiE4typeELi0EEEmv Unexecuted instantiation: _ZNK4absl12lts_2024011618container_internal15internal_layout10LayoutImplINSt3__15tupleIJPNS1_10btree_nodeINS1_10map_paramsIiN6google8protobuf8internal12ExtensionSet9ExtensionENS4_4lessIiEENS4_9allocatorINS4_4pairIKiSC_EEEELi256ELb0EEEEEjhNS1_13map_slot_typeIiSC_EESM_EEENS4_16integer_sequenceImJLm0ELm1ELm2ELm3ELm4EEEESR_E6OffsetILm3ETnNS4_9enable_ifIXneT_Li0EEiE4typeELi0EEEmv Unexecuted instantiation: _ZNK4absl12lts_2024011618container_internal15internal_layout10LayoutImplINSt3__15tupleIJPNS1_10btree_nodeINS1_10map_paramsIiN6google8protobuf8internal12ExtensionSet9ExtensionENS4_4lessIiEENS4_9allocatorINS4_4pairIKiSC_EEEELi256ELb0EEEEEjhNS1_13map_slot_typeIiSC_EESM_EEENS4_16integer_sequenceImJLm0ELm1ELm2ELm3ELm4EEEESR_E6OffsetILm4ETnNS4_9enable_ifIXneT_Li0EEiE4typeELi0EEEmv Unexecuted instantiation: _ZNK4absl12lts_2024011618container_internal15internal_layout10LayoutImplINSt3__15tupleIJPNS1_10btree_nodeINS1_10map_paramsIN6google8protobuf8internal10VariantKeyEPNSA_8NodeBaseENS4_4lessISB_EENSA_12MapAllocatorINS4_4pairIKSB_SD_EEEELi256ELb0EEEEEjhNS1_13map_slot_typeISB_SD_EESN_EEENS4_16integer_sequenceImJLm0ELm1ELm2ELm3ELm4EEEESS_E6OffsetILm1ETnNS4_9enable_ifIXneT_Li0EEiE4typeELi0EEEmv Unexecuted instantiation: _ZNK4absl12lts_2024011618container_internal15internal_layout10LayoutImplINSt3__15tupleIJPNS1_10btree_nodeINS1_10map_paramsIN6google8protobuf8internal10VariantKeyEPNSA_8NodeBaseENS4_4lessISB_EENSA_12MapAllocatorINS4_4pairIKSB_SD_EEEELi256ELb0EEEEEjhNS1_13map_slot_typeISB_SD_EESN_EEENS4_16integer_sequenceImJLm0ELm1ELm2ELm3ELm4EEEESS_E6OffsetILm2ETnNS4_9enable_ifIXneT_Li0EEiE4typeELi0EEEmv Unexecuted instantiation: _ZNK4absl12lts_2024011618container_internal15internal_layout10LayoutImplINSt3__15tupleIJPNS1_10btree_nodeINS1_10map_paramsIN6google8protobuf8internal10VariantKeyEPNSA_8NodeBaseENS4_4lessISB_EENSA_12MapAllocatorINS4_4pairIKSB_SD_EEEELi256ELb0EEEEEjhNS1_13map_slot_typeISB_SD_EESN_EEENS4_16integer_sequenceImJLm0ELm1ELm2ELm3ELm4EEEESS_E6OffsetILm3ETnNS4_9enable_ifIXneT_Li0EEiE4typeELi0EEEmv Unexecuted instantiation: _ZNK4absl12lts_2024011618container_internal15internal_layout10LayoutImplINSt3__15tupleIJPNS1_10btree_nodeINS1_10map_paramsIN6google8protobuf8internal10VariantKeyEPNSA_8NodeBaseENS4_4lessISB_EENSA_12MapAllocatorINS4_4pairIKSB_SD_EEEELi256ELb0EEEEEjhNS1_13map_slot_typeISB_SD_EESN_EEENS4_16integer_sequenceImJLm0ELm1ELm2ELm3ELm4EEEESS_E6OffsetILm4ETnNS4_9enable_ifIXneT_Li0EEiE4typeELi0EEEmv  | 
395  |  |  | 
396  |  |   // Offset in bytes of the array with the specified element type. There must  | 
397  |  |   // be exactly one such array and its zero-based index must be at most  | 
398  |  |   // `NumSizes`.  | 
399  |  |   //  | 
400  |  |   //   // int[3], 4 bytes of padding, double[4].  | 
401  |  |   //   Layout<int, double> x(3, 4);  | 
402  |  |   //   assert(x.Offset<int>() == 0);      // The ints starts from 0.  | 
403  |  |   //   assert(x.Offset<double>() == 16);  // The doubles starts from 16.  | 
404  |  |   template <class T>  | 
405  |  |   constexpr size_t Offset() const { | 
406  |  |     return Offset<ElementIndex<T>()>();  | 
407  |  |   }  | 
408  |  |  | 
409  |  |   // Offsets in bytes of all arrays for which the offsets are known.  | 
410  |  |   constexpr std::array<size_t, NumOffsets> Offsets() const { | 
411  |  |     return {{Offset<OffsetSeq>()...}}; | 
412  |  |   }  | 
413  |  |  | 
414  |  |   // The number of elements in the Nth array. This is the Nth argument of  | 
415  |  |   // `Layout::Partial()` or `Layout::Layout()` (zero-based).  | 
416  |  |   //  | 
417  |  |   //   // int[3], 4 bytes of padding, double[4].  | 
418  |  |   //   Layout<int, double> x(3, 4);  | 
419  |  |   //   assert(x.Size<0>() == 3);  | 
420  |  |   //   assert(x.Size<1>() == 4);  | 
421  |  |   //  | 
422  |  |   // Requires: `N < NumSizes`.  | 
423  |  |   template <size_t N>  | 
424  |  |   constexpr size_t Size() const { | 
425  |  |     static_assert(N < NumSizes, "Index out of bounds");  | 
426  |  |     return size_[N];  | 
427  |  |   }  | 
428  |  |  | 
429  |  |   // The number of elements in the array with the specified element type.  | 
430  |  |   // There must be exactly one such array and its zero-based index must be  | 
431  |  |   // at most `NumSizes`.  | 
432  |  |   //  | 
433  |  |   //   // int[3], 4 bytes of padding, double[4].  | 
434  |  |   //   Layout<int, double> x(3, 4);  | 
435  |  |   //   assert(x.Size<int>() == 3);  | 
436  |  |   //   assert(x.Size<double>() == 4);  | 
437  |  |   template <class T>  | 
438  |  |   constexpr size_t Size() const { | 
439  |  |     return Size<ElementIndex<T>()>();  | 
440  |  |   }  | 
441  |  |  | 
442  |  |   // The number of elements of all arrays for which they are known.  | 
443  |  |   constexpr std::array<size_t, NumSizes> Sizes() const { | 
444  |  |     return {{Size<SizeSeq>()...}}; | 
445  |  |   }  | 
446  |  |  | 
447  |  |   // Pointer to the beginning of the Nth array.  | 
448  |  |   //  | 
449  |  |   // `Char` must be `[const] [signed|unsigned] char`.  | 
450  |  |   //  | 
451  |  |   //   // int[3], 4 bytes of padding, double[4].  | 
452  |  |   //   Layout<int, double> x(3, 4);  | 
453  |  |   //   unsigned char* p = new unsigned char[x.AllocSize()];  | 
454  |  |   //   int* ints = x.Pointer<0>(p);  | 
455  |  |   //   double* doubles = x.Pointer<1>(p);  | 
456  |  |   //  | 
457  |  |   // Requires: `N <= NumSizes && N < sizeof...(Ts)`.  | 
458  |  |   // Requires: `p` is aligned to `Alignment()`.  | 
459  |  |   template <size_t N, class Char>  | 
460  | 0  |   CopyConst<Char, ElementType<N>>* Pointer(Char* p) const { | 
461  | 0  |     using C = typename std::remove_const<Char>::type;  | 
462  | 0  |     static_assert(  | 
463  | 0  |         std::is_same<C, char>() || std::is_same<C, unsigned char>() ||  | 
464  | 0  |             std::is_same<C, signed char>(),  | 
465  | 0  |         "The argument must be a pointer to [const] [signed|unsigned] char");  | 
466  | 0  |     constexpr size_t alignment = Alignment();  | 
467  | 0  |     (void)alignment;  | 
468  | 0  |     assert(reinterpret_cast<uintptr_t>(p) % alignment == 0);  | 
469  | 0  |     return reinterpret_cast<CopyConst<Char, ElementType<N>>*>(p + Offset<N>());  | 
470  | 0  |   } Unexecuted instantiation: _ZNK4absl12lts_2024011618container_internal15internal_layout10LayoutImplINSt3__15tupleIJPNS1_10btree_nodeINS1_10map_paramsIN6google8protobuf8internal10VariantKeyEPNSA_8NodeBaseENS4_4lessISB_EENSA_12MapAllocatorINS4_4pairIKSB_SD_EEEELi256ELb0EEEEEjhNS1_13map_slot_typeISB_SD_EESN_EEENS4_16integer_sequenceImJLm0ELm1ELm2ELm3ELm4EEEESS_E7PointerILm0EKcEEPNS4_11conditionalIXsr3std8is_constIT0_EE5valueEKNS4_13tuple_elementIXT_ESQ_E4typeES10_E4typeEPSX_ Unexecuted instantiation: _ZNK4absl12lts_2024011618container_internal15internal_layout10LayoutImplINSt3__15tupleIJPNS1_10btree_nodeINS1_10map_paramsIN6google8protobuf8internal10VariantKeyEPNSA_8NodeBaseENS4_4lessISB_EENSA_12MapAllocatorINS4_4pairIKSB_SD_EEEELi256ELb0EEEEEjhNS1_13map_slot_typeISB_SD_EESN_EEENS4_16integer_sequenceImJLm0ELm1ELm2ELm3ELm4EEEESS_E7PointerILm2EKcEEPNS4_11conditionalIXsr3std8is_constIT0_EE5valueEKNS4_13tuple_elementIXT_ESQ_E4typeES10_E4typeEPSX_ Unexecuted instantiation: _ZNK4absl12lts_2024011618container_internal15internal_layout10LayoutImplINSt3__15tupleIJPNS1_10btree_nodeINS1_10map_paramsIN6google8protobuf8internal10VariantKeyEPNSA_8NodeBaseENS4_4lessISB_EENSA_12MapAllocatorINS4_4pairIKSB_SD_EEEELi256ELb0EEEEEjhNS1_13map_slot_typeISB_SD_EESN_EEENS4_16integer_sequenceImJLm0ELm1ELm2ELm3ELm4EEEESS_E7PointerILm1EKcEEPNS4_11conditionalIXsr3std8is_constIT0_EE5valueEKNS4_13tuple_elementIXT_ESQ_E4typeES10_E4typeEPSX_ Unexecuted instantiation: _ZNK4absl12lts_2024011618container_internal15internal_layout10LayoutImplINSt3__15tupleIJPNS1_10btree_nodeINS1_10map_paramsIN6google8protobuf8internal10VariantKeyEPNSA_8NodeBaseENS4_4lessISB_EENSA_12MapAllocatorINS4_4pairIKSB_SD_EEEELi256ELb0EEEEEjhNS1_13map_slot_typeISB_SD_EESN_EEENS4_16integer_sequenceImJLm0ELm1ELm2ELm3ELm4EEEESS_E7PointerILm3EcEEPNS4_11conditionalIXsr3std8is_constIT0_EE5valueEKNS4_13tuple_elementIXT_ESQ_E4typeESZ_E4typeEPSW_  | 
471  |  |  | 
472  |  |   // Pointer to the beginning of the array with the specified element type.  | 
473  |  |   // There must be exactly one such array and its zero-based index must be at  | 
474  |  |   // most `NumSizes`.  | 
475  |  |   //  | 
476  |  |   // `Char` must be `[const] [signed|unsigned] char`.  | 
477  |  |   //  | 
478  |  |   //   // int[3], 4 bytes of padding, double[4].  | 
479  |  |   //   Layout<int, double> x(3, 4);  | 
480  |  |   //   unsigned char* p = new unsigned char[x.AllocSize()];  | 
481  |  |   //   int* ints = x.Pointer<int>(p);  | 
482  |  |   //   double* doubles = x.Pointer<double>(p);  | 
483  |  |   //  | 
484  |  |   // Requires: `p` is aligned to `Alignment()`.  | 
485  |  |   template <class T, class Char>  | 
486  |  |   CopyConst<Char, T>* Pointer(Char* p) const { | 
487  |  |     return Pointer<ElementIndex<T>()>(p);  | 
488  |  |   }  | 
489  |  |  | 
490  |  |   // Pointers to all arrays for which pointers are known.  | 
491  |  |   //  | 
492  |  |   // `Char` must be `[const] [signed|unsigned] char`.  | 
493  |  |   //  | 
494  |  |   //   // int[3], 4 bytes of padding, double[4].  | 
495  |  |   //   Layout<int, double> x(3, 4);  | 
496  |  |   //   unsigned char* p = new unsigned char[x.AllocSize()];  | 
497  |  |   //  | 
498  |  |   //   int* ints;  | 
499  |  |   //   double* doubles;  | 
500  |  |   //   std::tie(ints, doubles) = x.Pointers(p);  | 
501  |  |   //  | 
502  |  |   // Requires: `p` is aligned to `Alignment()`.  | 
503  |  |   //  | 
504  |  |   // Note: We're not using ElementType alias here because it does not compile  | 
505  |  |   // under MSVC.  | 
506  |  |   template <class Char>  | 
507  |  |   std::tuple<CopyConst<  | 
508  |  |       Char, typename std::tuple_element<OffsetSeq, ElementTypes>::type>*...>  | 
509  |  |   Pointers(Char* p) const { | 
510  |  |     return std::tuple<CopyConst<Char, ElementType<OffsetSeq>>*...>(  | 
511  |  |         Pointer<OffsetSeq>(p)...);  | 
512  |  |   }  | 
513  |  |  | 
514  |  |   // The Nth array.  | 
515  |  |   //  | 
516  |  |   // `Char` must be `[const] [signed|unsigned] char`.  | 
517  |  |   //  | 
518  |  |   //   // int[3], 4 bytes of padding, double[4].  | 
519  |  |   //   Layout<int, double> x(3, 4);  | 
520  |  |   //   unsigned char* p = new unsigned char[x.AllocSize()];  | 
521  |  |   //   Span<int> ints = x.Slice<0>(p);  | 
522  |  |   //   Span<double> doubles = x.Slice<1>(p);  | 
523  |  |   //  | 
524  |  |   // Requires: `N < NumSizes`.  | 
525  |  |   // Requires: `p` is aligned to `Alignment()`.  | 
526  |  |   template <size_t N, class Char>  | 
527  |  |   SliceType<CopyConst<Char, ElementType<N>>> Slice(Char* p) const { | 
528  |  |     return SliceType<CopyConst<Char, ElementType<N>>>(Pointer<N>(p), Size<N>());  | 
529  |  |   }  | 
530  |  |  | 
531  |  |   // The array with the specified element type. There must be exactly one  | 
532  |  |   // such array and its zero-based index must be less than `NumSizes`.  | 
533  |  |   //  | 
534  |  |   // `Char` must be `[const] [signed|unsigned] char`.  | 
535  |  |   //  | 
536  |  |   //   // int[3], 4 bytes of padding, double[4].  | 
537  |  |   //   Layout<int, double> x(3, 4);  | 
538  |  |   //   unsigned char* p = new unsigned char[x.AllocSize()];  | 
539  |  |   //   Span<int> ints = x.Slice<int>(p);  | 
540  |  |   //   Span<double> doubles = x.Slice<double>(p);  | 
541  |  |   //  | 
542  |  |   // Requires: `p` is aligned to `Alignment()`.  | 
543  |  |   template <class T, class Char>  | 
544  |  |   SliceType<CopyConst<Char, T>> Slice(Char* p) const { | 
545  |  |     return Slice<ElementIndex<T>()>(p);  | 
546  |  |   }  | 
547  |  |  | 
548  |  |   // All arrays with known sizes.  | 
549  |  |   //  | 
550  |  |   // `Char` must be `[const] [signed|unsigned] char`.  | 
551  |  |   //  | 
552  |  |   //   // int[3], 4 bytes of padding, double[4].  | 
553  |  |   //   Layout<int, double> x(3, 4);  | 
554  |  |   //   unsigned char* p = new unsigned char[x.AllocSize()];  | 
555  |  |   //  | 
556  |  |   //   Span<int> ints;  | 
557  |  |   //   Span<double> doubles;  | 
558  |  |   //   std::tie(ints, doubles) = x.Slices(p);  | 
559  |  |   //  | 
560  |  |   // Requires: `p` is aligned to `Alignment()`.  | 
561  |  |   //  | 
562  |  |   // Note: We're not using ElementType alias here because it does not compile  | 
563  |  |   // under MSVC.  | 
564  |  |   template <class Char>  | 
565  |  |   std::tuple<SliceType<CopyConst<  | 
566  |  |       Char, typename std::tuple_element<SizeSeq, ElementTypes>::type>>...>  | 
567  |  |   Slices(Char* p) const { | 
568  |  |     // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63875 (fixed  | 
569  |  |     // in 6.1).  | 
570  |  |     (void)p;  | 
571  |  |     return std::tuple<SliceType<CopyConst<Char, ElementType<SizeSeq>>>...>(  | 
572  |  |         Slice<SizeSeq>(p)...);  | 
573  |  |   }  | 
574  |  |  | 
575  |  |   // The size of the allocation that fits all arrays.  | 
576  |  |   //  | 
577  |  |   //   // int[3], 4 bytes of padding, double[4].  | 
578  |  |   //   Layout<int, double> x(3, 4);  | 
579  |  |   //   unsigned char* p = new unsigned char[x.AllocSize()];  // 48 bytes  | 
580  |  |   //  | 
581  |  |   // Requires: `NumSizes == sizeof...(Ts)`.  | 
582  | 0  |   constexpr size_t AllocSize() const { | 
583  | 0  |     static_assert(NumTypes == NumSizes, "You must specify sizes of all fields");  | 
584  | 0  |     return Offset<NumTypes - 1>() +  | 
585  | 0  |         SizeOf<ElementType<NumTypes - 1>>::value * size_[NumTypes - 1];  | 
586  | 0  |   } Unexecuted instantiation: absl::lts_20240116::container_internal::internal_layout::LayoutImpl<std::__1::tuple<absl::lts_20240116::container_internal::btree_node<absl::lts_20240116::container_internal::map_params<int, google::protobuf::internal::ExtensionSet::Extension, std::__1::less<int>, std::__1::allocator<std::__1::pair<int const, google::protobuf::internal::ExtensionSet::Extension> >, 256, false> >*, unsigned int, unsigned char, absl::lts_20240116::container_internal::map_slot_type<int, google::protobuf::internal::ExtensionSet::Extension>, absl::lts_20240116::container_internal::btree_node<absl::lts_20240116::container_internal::map_params<int, google::protobuf::internal::ExtensionSet::Extension, std::__1::less<int>, std::__1::allocator<std::__1::pair<int const, google::protobuf::internal::ExtensionSet::Extension> >, 256, false> >*>, std::__1::integer_sequence<unsigned long, 0ul, 1ul, 2ul, 3ul, 4ul>, std::__1::integer_sequence<unsigned long, 0ul, 1ul, 2ul, 3ul, 4ul> >::AllocSize() const Unexecuted instantiation: absl::lts_20240116::container_internal::internal_layout::LayoutImpl<std::__1::tuple<absl::lts_20240116::container_internal::btree_node<absl::lts_20240116::container_internal::map_params<google::protobuf::internal::VariantKey, google::protobuf::internal::NodeBase*, std::__1::less<google::protobuf::internal::VariantKey>, google::protobuf::internal::MapAllocator<std::__1::pair<google::protobuf::internal::VariantKey const, google::protobuf::internal::NodeBase*> >, 256, false> >*, unsigned int, unsigned char, absl::lts_20240116::container_internal::map_slot_type<google::protobuf::internal::VariantKey, google::protobuf::internal::NodeBase*>, absl::lts_20240116::container_internal::btree_node<absl::lts_20240116::container_internal::map_params<google::protobuf::internal::VariantKey, google::protobuf::internal::NodeBase*, std::__1::less<google::protobuf::internal::VariantKey>, google::protobuf::internal::MapAllocator<std::__1::pair<google::protobuf::internal::VariantKey const, google::protobuf::internal::NodeBase*> >, 256, false> >*>, std::__1::integer_sequence<unsigned long, 0ul, 1ul, 2ul, 3ul, 4ul>, std::__1::integer_sequence<unsigned long, 0ul, 1ul, 2ul, 3ul, 4ul> >::AllocSize() const  | 
587  |  |  | 
588  |  |   // If built with --config=asan, poisons padding bytes (if any) in the  | 
589  |  |   // allocation. The pointer must point to a memory block at least  | 
590  |  |   // `AllocSize()` bytes in length.  | 
591  |  |   //  | 
592  |  |   // `Char` must be `[const] [signed|unsigned] char`.  | 
593  |  |   //  | 
594  |  |   // Requires: `p` is aligned to `Alignment()`.  | 
595  |  |   template <class Char, size_t N = NumOffsets - 1, EnableIf<N == 0> = 0>  | 
596  |  |   void PoisonPadding(const Char* p) const { | 
597  |  |     Pointer<0>(p);  // verify the requirements on `Char` and `p`  | 
598  |  |   }  | 
599  |  |  | 
600  |  |   template <class Char, size_t N = NumOffsets - 1, EnableIf<N != 0> = 0>  | 
601  |  |   void PoisonPadding(const Char* p) const { | 
602  |  |     static_assert(N < NumOffsets, "Index out of bounds");  | 
603  |  |     (void)p;  | 
604  |  | #ifdef ABSL_HAVE_ADDRESS_SANITIZER  | 
605  |  |     PoisonPadding<Char, N - 1>(p);  | 
606  |  |     // The `if` is an optimization. It doesn't affect the observable behaviour.  | 
607  |  |     if (ElementAlignment<N - 1>::value % ElementAlignment<N>::value) { | 
608  |  |       size_t start =  | 
609  |  |           Offset<N - 1>() + SizeOf<ElementType<N - 1>>::value * size_[N - 1];  | 
610  |  |       ASAN_POISON_MEMORY_REGION(p + start, Offset<N>() - start);  | 
611  |  |     }  | 
612  |  | #endif  | 
613  |  |   }  | 
614  |  |  | 
615  |  |   // Human-readable description of the memory layout. Useful for debugging.  | 
616  |  |   // Slow.  | 
617  |  |   //  | 
618  |  |   //   // char[5], 3 bytes of padding, int[3], 4 bytes of padding, followed  | 
619  |  |   //   // by an unknown number of doubles.  | 
620  |  |   //   auto x = Layout<char, int, double>::Partial(5, 3);  | 
621  |  |   //   assert(x.DebugString() ==  | 
622  |  |   //          "@0<char>(1)[5]; @8<int>(4)[3]; @24<double>(8)");  | 
623  |  |   //  | 
624  |  |   // Each field is in the following format: @offset<type>(sizeof)[size] (<type>  | 
625  |  |   // may be missing depending on the target platform). For example,  | 
626  |  |   // @8<int>(4)[3] means that at offset 8 we have an array of ints, where each  | 
627  |  |   // int is 4 bytes, and we have 3 of those ints. The size of the last field may  | 
628  |  |   // be missing (as in the example above). Only fields with known offsets are  | 
629  |  |   // described. Type names may differ across platforms: one compiler might  | 
630  |  |   // produce "unsigned*" where another produces "unsigned int *".  | 
631  |  |   std::string DebugString() const { | 
632  |  |     const auto offsets = Offsets();  | 
633  |  |     const size_t sizes[] = {SizeOf<ElementType<OffsetSeq>>::value...}; | 
634  |  |     const std::string types[] = { | 
635  |  |         adl_barrier::TypeName<ElementType<OffsetSeq>>()...};  | 
636  |  |     std::string res = absl::StrCat("@0", types[0], "(", sizes[0], ")"); | 
637  |  |     for (size_t i = 0; i != NumOffsets - 1; ++i) { | 
638  |  |       absl::StrAppend(&res, "[", size_[i], "]; @", offsets[i + 1], types[i + 1],  | 
639  |  |                       "(", sizes[i + 1], ")"); | 
640  |  |     }  | 
641  |  |     // NumSizes is a constant that may be zero. Some compilers cannot see that  | 
642  |  |     // inside the if statement "size_[NumSizes - 1]" must be valid.  | 
643  |  |     int last = static_cast<int>(NumSizes) - 1;  | 
644  |  |     if (NumTypes == NumSizes && last >= 0) { | 
645  |  |       absl::StrAppend(&res, "[", size_[last], "]");  | 
646  |  |     }  | 
647  |  |     return res;  | 
648  |  |   }  | 
649  |  |  | 
650  |  |  private:  | 
651  |  |   // Arguments of `Layout::Partial()` or `Layout::Layout()`.  | 
652  |  |   size_t size_[NumSizes > 0 ? NumSizes : 1];  | 
653  |  | };  | 
654  |  |  | 
655  |  | template <size_t NumSizes, class... Ts>  | 
656  |  | using LayoutType = LayoutImpl<  | 
657  |  |     std::tuple<Ts...>, absl::make_index_sequence<NumSizes>,  | 
658  |  |     absl::make_index_sequence<adl_barrier::Min(sizeof...(Ts), NumSizes + 1)>>;  | 
659  |  |  | 
660  |  | }  // namespace internal_layout  | 
661  |  |  | 
662  |  | // Descriptor of arrays of various types and sizes laid out in memory one after  | 
663  |  | // another. See the top of the file for documentation.  | 
664  |  | //  | 
665  |  | // Check out the public API of internal_layout::LayoutImpl above. The type is  | 
666  |  | // internal to the library but its methods are public, and they are inherited  | 
667  |  | // by `Layout`.  | 
668  |  | template <class... Ts>  | 
669  |  | class Layout : public internal_layout::LayoutType<sizeof...(Ts), Ts...> { | 
670  |  |  public:  | 
671  |  |   static_assert(sizeof...(Ts) > 0, "At least one field is required");  | 
672  |  |   static_assert(  | 
673  |  |       absl::conjunction<internal_layout::IsLegalElementType<Ts>...>::value,  | 
674  |  |       "Invalid element type (see IsLegalElementType)");  | 
675  |  |  | 
676  |  |   // The result type of `Partial()` with `NumSizes` arguments.  | 
677  |  |   template <size_t NumSizes>  | 
678  |  |   using PartialType = internal_layout::LayoutType<NumSizes, Ts...>;  | 
679  |  |  | 
680  |  |   // `Layout` knows the element types of the arrays we want to lay out in  | 
681  |  |   // memory but not the number of elements in each array.  | 
682  |  |   // `Partial(size1, ..., sizeN)` allows us to specify the latter. The  | 
683  |  |   // resulting immutable object can be used to obtain pointers to the  | 
684  |  |   // individual arrays.  | 
685  |  |   //  | 
686  |  |   // It's allowed to pass fewer array sizes than the number of arrays. E.g.,  | 
687  |  |   // if all you need is to the offset of the second array, you only need to  | 
688  |  |   // pass one argument -- the number of elements in the first array.  | 
689  |  |   //  | 
690  |  |   //   // int[3] followed by 4 bytes of padding and an unknown number of  | 
691  |  |   //   // doubles.  | 
692  |  |   //   auto x = Layout<int, double>::Partial(3);  | 
693  |  |   //   // doubles start at byte 16.  | 
694  |  |   //   assert(x.Offset<1>() == 16);  | 
695  |  |   //  | 
696  |  |   // If you know the number of elements in all arrays, you can still call  | 
697  |  |   // `Partial()` but it's more convenient to use the constructor of `Layout`.  | 
698  |  |   //  | 
699  |  |   //   Layout<int, double> x(3, 5);  | 
700  |  |   //  | 
701  |  |   // Note: The sizes of the arrays must be specified in number of elements,  | 
702  |  |   // not in bytes.  | 
703  |  |   //  | 
704  |  |   // Requires: `sizeof...(Sizes) <= sizeof...(Ts)`.  | 
705  |  |   // Requires: all arguments are convertible to `size_t`.  | 
706  |  |   template <class... Sizes>  | 
707  |  |   static constexpr PartialType<sizeof...(Sizes)> Partial(Sizes&&... sizes) { | 
708  |  |     static_assert(sizeof...(Sizes) <= sizeof...(Ts), "");  | 
709  |  |     return PartialType<sizeof...(Sizes)>(absl::forward<Sizes>(sizes)...);  | 
710  |  |   }  | 
711  |  |  | 
712  |  |   // Creates a layout with the sizes of all arrays specified. If you know  | 
713  |  |   // only the sizes of the first N arrays (where N can be zero), you can use  | 
714  |  |   // `Partial()` defined above. The constructor is essentially equivalent to  | 
715  |  |   // calling `Partial()` and passing in all array sizes; the constructor is  | 
716  |  |   // provided as a convenient abbreviation.  | 
717  |  |   //  | 
718  |  |   // Note: The sizes of the arrays must be specified in number of elements,  | 
719  |  |   // not in bytes.  | 
720  |  |   constexpr explicit Layout(internal_layout::TypeToSize<Ts>... sizes)  | 
721  |  |       : internal_layout::LayoutType<sizeof...(Ts), Ts...>(sizes...) {} | 
722  |  | };  | 
723  |  |  | 
724  |  | }  // namespace container_internal  | 
725  |  | ABSL_NAMESPACE_END  | 
726  |  | }  // namespace absl  | 
727  |  |  | 
728  |  | #endif  // ABSL_CONTAINER_INTERNAL_LAYOUT_H_  |