/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[1] 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/meta/type_traits.h" |
176 | | #include "absl/strings/str_cat.h" |
177 | | #include "absl/types/span.h" |
178 | | #include "absl/utility/utility.h" |
179 | | |
180 | | #ifdef ABSL_HAVE_ADDRESS_SANITIZER |
181 | | #include <sanitizer/asan_interface.h> |
182 | | #endif |
183 | | |
184 | | #if defined(__GXX_RTTI) |
185 | | #define ABSL_INTERNAL_HAS_CXA_DEMANGLE |
186 | | #endif |
187 | | |
188 | | #ifdef ABSL_INTERNAL_HAS_CXA_DEMANGLE |
189 | | #include <cxxabi.h> |
190 | | #endif |
191 | | |
192 | | namespace absl { |
193 | | ABSL_NAMESPACE_BEGIN |
194 | | namespace container_internal { |
195 | | |
196 | | // A type wrapper that instructs `Layout` to use the specific alignment for the |
197 | | // array. `Layout<..., Aligned<T, N>, ...>` has exactly the same API |
198 | | // and behavior as `Layout<..., T, ...>` except that the first element of the |
199 | | // array of `T` is aligned to `N` (the rest of the elements follow without |
200 | | // padding). |
201 | | // |
202 | | // Requires: `N >= alignof(T)` and `N` is a power of 2. |
203 | | template <class T, size_t N> |
204 | | struct Aligned; |
205 | | |
206 | | namespace internal_layout { |
207 | | |
208 | | template <class T> |
209 | | struct NotAligned {}; |
210 | | |
211 | | template <class T, size_t N> |
212 | | struct NotAligned<const Aligned<T, N>> { |
213 | | static_assert(sizeof(T) == 0, "Aligned<T, N> cannot be const-qualified"); |
214 | | }; |
215 | | |
216 | | template <size_t> |
217 | | using IntToSize = size_t; |
218 | | |
219 | | template <class> |
220 | | using TypeToSize = size_t; |
221 | | |
222 | | template <class T> |
223 | | struct Type : NotAligned<T> { |
224 | | using type = T; |
225 | | }; |
226 | | |
227 | | template <class T, size_t N> |
228 | | struct Type<Aligned<T, N>> { |
229 | | using type = T; |
230 | | }; |
231 | | |
232 | | template <class T> |
233 | | struct SizeOf : NotAligned<T>, std::integral_constant<size_t, sizeof(T)> {}; |
234 | | |
235 | | template <class T, size_t N> |
236 | | struct SizeOf<Aligned<T, N>> : std::integral_constant<size_t, sizeof(T)> {}; |
237 | | |
238 | | // Note: workaround for https://gcc.gnu.org/PR88115 |
239 | | template <class T> |
240 | | struct AlignOf : NotAligned<T> { |
241 | | static constexpr size_t value = alignof(T); |
242 | | }; |
243 | | |
244 | | template <class T, size_t N> |
245 | | struct AlignOf<Aligned<T, N>> { |
246 | | static_assert(N % alignof(T) == 0, |
247 | | "Custom alignment can't be lower than the type's alignment"); |
248 | | static constexpr size_t value = N; |
249 | | }; |
250 | | |
251 | | // Does `Ts...` contain `T`? |
252 | | template <class T, class... Ts> |
253 | | using Contains = absl::disjunction<std::is_same<T, Ts>...>; |
254 | | |
255 | | template <class From, class To> |
256 | | using CopyConst = |
257 | | typename std::conditional<std::is_const<From>::value, const To, To>::type; |
258 | | |
259 | | // Note: We're not qualifying this with absl:: because it doesn't compile under |
260 | | // MSVC. |
261 | | template <class T> |
262 | | using SliceType = Span<T>; |
263 | | |
264 | | // This namespace contains no types. It prevents functions defined in it from |
265 | | // being found by ADL. |
266 | | namespace adl_barrier { |
267 | | |
268 | | template <class Needle, class... Ts> |
269 | | constexpr size_t Find(Needle, Needle, Ts...) { |
270 | | static_assert(!Contains<Needle, Ts...>(), "Duplicate element type"); |
271 | | return 0; |
272 | | } |
273 | | |
274 | | template <class Needle, class T, class... Ts> |
275 | | constexpr size_t Find(Needle, T, Ts...) { |
276 | | return adl_barrier::Find(Needle(), Ts()...) + 1; |
277 | | } |
278 | | |
279 | 0 | constexpr bool IsPow2(size_t n) { return !(n & (n - 1)); } |
280 | | |
281 | | // Returns `q * m` for the smallest `q` such that `q * m >= n`. |
282 | | // Requires: `m` is a power of two. It's enforced by IsLegalElementType below. |
283 | 0 | constexpr size_t Align(size_t n, size_t m) { return (n + m - 1) & ~(m - 1); } |
284 | | |
285 | 0 | constexpr size_t Min(size_t a, size_t b) { return b < a ? b : a; } |
286 | | |
287 | 0 | constexpr size_t Max(size_t a) { return a; } |
288 | | |
289 | | template <class... Ts> |
290 | 0 | constexpr size_t Max(size_t a, size_t b, Ts... rest) { |
291 | 0 | return adl_barrier::Max(b < a ? a : b, rest...); |
292 | 0 | } Unexecuted instantiation: unsigned long absl::lts_20230125::container_internal::internal_layout::adl_barrier::Max<>(unsigned long, unsigned long) Unexecuted instantiation: unsigned long absl::lts_20230125::container_internal::internal_layout::adl_barrier::Max<unsigned long>(unsigned long, unsigned long, unsigned long) |
293 | | |
294 | | template <class T> |
295 | | std::string TypeName() { |
296 | | std::string out; |
297 | | int status = 0; |
298 | | char* demangled = nullptr; |
299 | | #ifdef ABSL_INTERNAL_HAS_CXA_DEMANGLE |
300 | | demangled = abi::__cxa_demangle(typeid(T).name(), nullptr, nullptr, &status); |
301 | | #endif |
302 | | if (status == 0 && demangled != nullptr) { // Demangling succeeded. |
303 | | absl::StrAppend(&out, "<", demangled, ">"); |
304 | | free(demangled); |
305 | | } else { |
306 | | #if defined(__GXX_RTTI) || defined(_CPPRTTI) |
307 | | absl::StrAppend(&out, "<", typeid(T).name(), ">"); |
308 | | #endif |
309 | | } |
310 | | return out; |
311 | | } |
312 | | |
313 | | } // namespace adl_barrier |
314 | | |
315 | | template <bool C> |
316 | | using EnableIf = typename std::enable_if<C, int>::type; |
317 | | |
318 | | // Can `T` be a template argument of `Layout`? |
319 | | template <class T> |
320 | | using IsLegalElementType = std::integral_constant< |
321 | | bool, !std::is_reference<T>::value && !std::is_volatile<T>::value && |
322 | | !std::is_reference<typename Type<T>::type>::value && |
323 | | !std::is_volatile<typename Type<T>::type>::value && |
324 | | adl_barrier::IsPow2(AlignOf<T>::value)>; |
325 | | |
326 | | template <class Elements, class SizeSeq, class OffsetSeq> |
327 | | class LayoutImpl; |
328 | | |
329 | | // Public base class of `Layout` and the result type of `Layout::Partial()`. |
330 | | // |
331 | | // `Elements...` contains all template arguments of `Layout` that created this |
332 | | // instance. |
333 | | // |
334 | | // `SizeSeq...` is `[0, NumSizes)` where `NumSizes` is the number of arguments |
335 | | // passed to `Layout::Partial()` or `Layout::Layout()`. |
336 | | // |
337 | | // `OffsetSeq...` is `[0, NumOffsets)` where `NumOffsets` is |
338 | | // `Min(sizeof...(Elements), NumSizes + 1)` (the number of arrays for which we |
339 | | // can compute offsets). |
340 | | template <class... Elements, size_t... SizeSeq, size_t... OffsetSeq> |
341 | | class LayoutImpl<std::tuple<Elements...>, absl::index_sequence<SizeSeq...>, |
342 | | absl::index_sequence<OffsetSeq...>> { |
343 | | private: |
344 | | static_assert(sizeof...(Elements) > 0, "At least one field is required"); |
345 | | static_assert(absl::conjunction<IsLegalElementType<Elements>...>::value, |
346 | | "Invalid element type (see IsLegalElementType)"); |
347 | | |
348 | | enum { |
349 | | NumTypes = sizeof...(Elements), |
350 | | NumSizes = sizeof...(SizeSeq), |
351 | | NumOffsets = sizeof...(OffsetSeq), |
352 | | }; |
353 | | |
354 | | // These are guaranteed by `Layout`. |
355 | | static_assert(NumOffsets == adl_barrier::Min(NumTypes, NumSizes + 1), |
356 | | "Internal error"); |
357 | | static_assert(NumTypes > 0, "Internal error"); |
358 | | |
359 | | // Returns the index of `T` in `Elements...`. Results in a compilation error |
360 | | // if `Elements...` doesn't contain exactly one instance of `T`. |
361 | | template <class T> |
362 | | static constexpr size_t ElementIndex() { |
363 | | static_assert(Contains<Type<T>, Type<typename Type<Elements>::type>...>(), |
364 | | "Type not found"); |
365 | | return adl_barrier::Find(Type<T>(), |
366 | | Type<typename Type<Elements>::type>()...); |
367 | | } |
368 | | |
369 | | template <size_t N> |
370 | | using ElementAlignment = |
371 | | AlignOf<typename std::tuple_element<N, std::tuple<Elements...>>::type>; |
372 | | |
373 | | public: |
374 | | // Element types of all arrays packed in a tuple. |
375 | | using ElementTypes = std::tuple<typename Type<Elements>::type...>; |
376 | | |
377 | | // Element type of the Nth array. |
378 | | template <size_t N> |
379 | | using ElementType = typename std::tuple_element<N, ElementTypes>::type; |
380 | | |
381 | | constexpr explicit LayoutImpl(IntToSize<SizeSeq>... sizes) |
382 | | : size_{sizes...} {} |
383 | | |
384 | | // Alignment of the layout, equal to the strictest alignment of all elements. |
385 | | // All pointers passed to the methods of layout must be aligned to this value. |
386 | 0 | static constexpr size_t Alignment() { |
387 | 0 | return adl_barrier::Max(AlignOf<Elements>::value...); |
388 | 0 | } Unexecuted instantiation: absl::lts_20230125::container_internal::internal_layout::LayoutImpl<std::__1::tuple<unsigned long, absl::lts_20230125::cord_internal::CordRep*, unsigned int>, absl::lts_20230125::integer_sequence<unsigned long>, absl::lts_20230125::integer_sequence<unsigned long, 0ul> >::Alignment() Unexecuted instantiation: absl::lts_20230125::container_internal::internal_layout::LayoutImpl<std::__1::tuple<unsigned long, absl::lts_20230125::cord_internal::CordRep*, unsigned int>, absl::lts_20230125::integer_sequence<unsigned long, 0ul>, absl::lts_20230125::integer_sequence<unsigned long, 0ul, 1ul> >::Alignment() Unexecuted instantiation: absl::lts_20230125::container_internal::internal_layout::LayoutImpl<std::__1::tuple<unsigned long, absl::lts_20230125::cord_internal::CordRep*, unsigned int>, absl::lts_20230125::integer_sequence<unsigned long, 0ul, 1ul>, absl::lts_20230125::integer_sequence<unsigned long, 0ul, 1ul, 2ul> >::Alignment() |
389 | | |
390 | | // Offset in bytes of the Nth array. |
391 | | // |
392 | | // // int[3], 4 bytes of padding, double[4]. |
393 | | // Layout<int, double> x(3, 4); |
394 | | // assert(x.Offset<0>() == 0); // The ints starts from 0. |
395 | | // assert(x.Offset<1>() == 16); // The doubles starts from 16. |
396 | | // |
397 | | // Requires: `N <= NumSizes && N < sizeof...(Ts)`. |
398 | | template <size_t N, EnableIf<N == 0> = 0> |
399 | 0 | constexpr size_t Offset() const { |
400 | 0 | return 0; |
401 | 0 | } Unexecuted instantiation: unsigned long absl::lts_20230125::container_internal::internal_layout::LayoutImpl<std::__1::tuple<unsigned long, absl::lts_20230125::cord_internal::CordRep*, unsigned int>, absl::lts_20230125::integer_sequence<unsigned long, 0ul, 1ul, 2ul>, absl::lts_20230125::integer_sequence<unsigned long, 0ul, 1ul, 2ul> >::Offset<0ul, 0>() const Unexecuted instantiation: unsigned long absl::lts_20230125::container_internal::internal_layout::LayoutImpl<std::__1::tuple<absl::lts_20230125::container_internal::btree_node<absl::lts_20230125::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_20230125::container_internal::map_slot_type<int, google::protobuf::internal::ExtensionSet::Extension>, absl::lts_20230125::container_internal::btree_node<absl::lts_20230125::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> >*>, absl::lts_20230125::integer_sequence<unsigned long, 0ul, 1ul, 2ul, 3ul, 4ul>, absl::lts_20230125::integer_sequence<unsigned long, 0ul, 1ul, 2ul, 3ul, 4ul> >::Offset<0ul, 0>() const Unexecuted instantiation: unsigned long absl::lts_20230125::container_internal::internal_layout::LayoutImpl<std::__1::tuple<unsigned long, absl::lts_20230125::cord_internal::CordRep*, unsigned int>, absl::lts_20230125::integer_sequence<unsigned long>, absl::lts_20230125::integer_sequence<unsigned long, 0ul> >::Offset<0ul, 0>() const Unexecuted instantiation: unsigned long absl::lts_20230125::container_internal::internal_layout::LayoutImpl<std::__1::tuple<unsigned long, absl::lts_20230125::cord_internal::CordRep*, unsigned int>, absl::lts_20230125::integer_sequence<unsigned long, 0ul>, absl::lts_20230125::integer_sequence<unsigned long, 0ul, 1ul> >::Offset<0ul, 0>() const Unexecuted instantiation: unsigned long absl::lts_20230125::container_internal::internal_layout::LayoutImpl<std::__1::tuple<unsigned long, absl::lts_20230125::cord_internal::CordRep*, unsigned int>, absl::lts_20230125::integer_sequence<unsigned long, 0ul, 1ul>, absl::lts_20230125::integer_sequence<unsigned long, 0ul, 1ul, 2ul> >::Offset<0ul, 0>() const |
402 | | |
403 | | template <size_t N, EnableIf<N != 0> = 0> |
404 | 0 | constexpr size_t Offset() const { |
405 | 0 | static_assert(N < NumOffsets, "Index out of bounds"); |
406 | 0 | return adl_barrier::Align( |
407 | 0 | Offset<N - 1>() + SizeOf<ElementType<N - 1>>::value * size_[N - 1], |
408 | 0 | ElementAlignment<N>::value); |
409 | 0 | } Unexecuted instantiation: unsigned long absl::lts_20230125::container_internal::internal_layout::LayoutImpl<std::__1::tuple<unsigned long, absl::lts_20230125::cord_internal::CordRep*, unsigned int>, absl::lts_20230125::integer_sequence<unsigned long, 0ul, 1ul, 2ul>, absl::lts_20230125::integer_sequence<unsigned long, 0ul, 1ul, 2ul> >::Offset<1ul, 0>() const Unexecuted instantiation: unsigned long absl::lts_20230125::container_internal::internal_layout::LayoutImpl<std::__1::tuple<unsigned long, absl::lts_20230125::cord_internal::CordRep*, unsigned int>, absl::lts_20230125::integer_sequence<unsigned long, 0ul, 1ul, 2ul>, absl::lts_20230125::integer_sequence<unsigned long, 0ul, 1ul, 2ul> >::Offset<2ul, 0>() const Unexecuted instantiation: unsigned long absl::lts_20230125::container_internal::internal_layout::LayoutImpl<std::__1::tuple<absl::lts_20230125::container_internal::btree_node<absl::lts_20230125::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_20230125::container_internal::map_slot_type<int, google::protobuf::internal::ExtensionSet::Extension>, absl::lts_20230125::container_internal::btree_node<absl::lts_20230125::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> >*>, absl::lts_20230125::integer_sequence<unsigned long, 0ul, 1ul, 2ul, 3ul, 4ul>, absl::lts_20230125::integer_sequence<unsigned long, 0ul, 1ul, 2ul, 3ul, 4ul> >::Offset<1ul, 0>() const Unexecuted instantiation: unsigned long absl::lts_20230125::container_internal::internal_layout::LayoutImpl<std::__1::tuple<absl::lts_20230125::container_internal::btree_node<absl::lts_20230125::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_20230125::container_internal::map_slot_type<int, google::protobuf::internal::ExtensionSet::Extension>, absl::lts_20230125::container_internal::btree_node<absl::lts_20230125::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> >*>, absl::lts_20230125::integer_sequence<unsigned long, 0ul, 1ul, 2ul, 3ul, 4ul>, absl::lts_20230125::integer_sequence<unsigned long, 0ul, 1ul, 2ul, 3ul, 4ul> >::Offset<2ul, 0>() const Unexecuted instantiation: unsigned long absl::lts_20230125::container_internal::internal_layout::LayoutImpl<std::__1::tuple<absl::lts_20230125::container_internal::btree_node<absl::lts_20230125::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_20230125::container_internal::map_slot_type<int, google::protobuf::internal::ExtensionSet::Extension>, absl::lts_20230125::container_internal::btree_node<absl::lts_20230125::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> >*>, absl::lts_20230125::integer_sequence<unsigned long, 0ul, 1ul, 2ul, 3ul, 4ul>, absl::lts_20230125::integer_sequence<unsigned long, 0ul, 1ul, 2ul, 3ul, 4ul> >::Offset<3ul, 0>() const Unexecuted instantiation: unsigned long absl::lts_20230125::container_internal::internal_layout::LayoutImpl<std::__1::tuple<absl::lts_20230125::container_internal::btree_node<absl::lts_20230125::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_20230125::container_internal::map_slot_type<int, google::protobuf::internal::ExtensionSet::Extension>, absl::lts_20230125::container_internal::btree_node<absl::lts_20230125::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> >*>, absl::lts_20230125::integer_sequence<unsigned long, 0ul, 1ul, 2ul, 3ul, 4ul>, absl::lts_20230125::integer_sequence<unsigned long, 0ul, 1ul, 2ul, 3ul, 4ul> >::Offset<4ul, 0>() const Unexecuted instantiation: unsigned long absl::lts_20230125::container_internal::internal_layout::LayoutImpl<std::__1::tuple<unsigned long, absl::lts_20230125::cord_internal::CordRep*, unsigned int>, absl::lts_20230125::integer_sequence<unsigned long, 0ul>, absl::lts_20230125::integer_sequence<unsigned long, 0ul, 1ul> >::Offset<1ul, 0>() const Unexecuted instantiation: unsigned long absl::lts_20230125::container_internal::internal_layout::LayoutImpl<std::__1::tuple<unsigned long, absl::lts_20230125::cord_internal::CordRep*, unsigned int>, absl::lts_20230125::integer_sequence<unsigned long, 0ul, 1ul>, absl::lts_20230125::integer_sequence<unsigned long, 0ul, 1ul, 2ul> >::Offset<1ul, 0>() const Unexecuted instantiation: unsigned long absl::lts_20230125::container_internal::internal_layout::LayoutImpl<std::__1::tuple<unsigned long, absl::lts_20230125::cord_internal::CordRep*, unsigned int>, absl::lts_20230125::integer_sequence<unsigned long, 0ul, 1ul>, absl::lts_20230125::integer_sequence<unsigned long, 0ul, 1ul, 2ul> >::Offset<2ul, 0>() const |
410 | | |
411 | | // Offset in bytes of the array with the specified element type. There must |
412 | | // be exactly one such array and its zero-based index must be at most |
413 | | // `NumSizes`. |
414 | | // |
415 | | // // int[3], 4 bytes of padding, double[4]. |
416 | | // Layout<int, double> x(3, 4); |
417 | | // assert(x.Offset<int>() == 0); // The ints starts from 0. |
418 | | // assert(x.Offset<double>() == 16); // The doubles starts from 16. |
419 | | template <class T> |
420 | | constexpr size_t Offset() const { |
421 | | return Offset<ElementIndex<T>()>(); |
422 | | } |
423 | | |
424 | | // Offsets in bytes of all arrays for which the offsets are known. |
425 | | constexpr std::array<size_t, NumOffsets> Offsets() const { |
426 | | return {{Offset<OffsetSeq>()...}}; |
427 | | } |
428 | | |
429 | | // The number of elements in the Nth array. This is the Nth argument of |
430 | | // `Layout::Partial()` or `Layout::Layout()` (zero-based). |
431 | | // |
432 | | // // int[3], 4 bytes of padding, double[4]. |
433 | | // Layout<int, double> x(3, 4); |
434 | | // assert(x.Size<0>() == 3); |
435 | | // assert(x.Size<1>() == 4); |
436 | | // |
437 | | // Requires: `N < NumSizes`. |
438 | | template <size_t N> |
439 | | constexpr size_t Size() const { |
440 | | static_assert(N < NumSizes, "Index out of bounds"); |
441 | | return size_[N]; |
442 | | } |
443 | | |
444 | | // The number of elements in the array with the specified element type. |
445 | | // There must be exactly one such array and its zero-based index must be |
446 | | // at most `NumSizes`. |
447 | | // |
448 | | // // int[3], 4 bytes of padding, double[4]. |
449 | | // Layout<int, double> x(3, 4); |
450 | | // assert(x.Size<int>() == 3); |
451 | | // assert(x.Size<double>() == 4); |
452 | | template <class T> |
453 | | constexpr size_t Size() const { |
454 | | return Size<ElementIndex<T>()>(); |
455 | | } |
456 | | |
457 | | // The number of elements of all arrays for which they are known. |
458 | | constexpr std::array<size_t, NumSizes> Sizes() const { |
459 | | return {{Size<SizeSeq>()...}}; |
460 | | } |
461 | | |
462 | | // Pointer to the beginning of the Nth array. |
463 | | // |
464 | | // `Char` must be `[const] [signed|unsigned] char`. |
465 | | // |
466 | | // // int[3], 4 bytes of padding, double[4]. |
467 | | // Layout<int, double> x(3, 4); |
468 | | // unsigned char* p = new unsigned char[x.AllocSize()]; |
469 | | // int* ints = x.Pointer<0>(p); |
470 | | // double* doubles = x.Pointer<1>(p); |
471 | | // |
472 | | // Requires: `N <= NumSizes && N < sizeof...(Ts)`. |
473 | | // Requires: `p` is aligned to `Alignment()`. |
474 | | template <size_t N, class Char> |
475 | 0 | CopyConst<Char, ElementType<N>>* Pointer(Char* p) const { |
476 | 0 | using C = typename std::remove_const<Char>::type; |
477 | 0 | static_assert( |
478 | 0 | std::is_same<C, char>() || std::is_same<C, unsigned char>() || |
479 | 0 | std::is_same<C, signed char>(), |
480 | 0 | "The argument must be a pointer to [const] [signed|unsigned] char"); |
481 | 0 | constexpr size_t alignment = Alignment(); |
482 | 0 | (void)alignment; |
483 | 0 | assert(reinterpret_cast<uintptr_t>(p) % alignment == 0); |
484 | 0 | return reinterpret_cast<CopyConst<Char, ElementType<N>>*>(p + Offset<N>()); |
485 | 0 | } Unexecuted instantiation: _ZNK4absl12lts_2023012518container_internal15internal_layout10LayoutImplINSt3__15tupleIJmPNS0_13cord_internal7CordRepEjEEENS0_16integer_sequenceImJEEENSA_ImJLm0EEEEE7PointerILm0EKcEEPNS4_11conditionalIXsr3std8is_constIT0_EE5valueEKNS4_13tuple_elementIXT_ES9_E4typeESK_E4typeEPSH_ Unexecuted instantiation: _ZNK4absl12lts_2023012518container_internal15internal_layout10LayoutImplINSt3__15tupleIJmPNS0_13cord_internal7CordRepEjEEENS0_16integer_sequenceImJLm0EEEENSA_ImJLm0ELm1EEEEE7PointerILm1EKcEEPNS4_11conditionalIXsr3std8is_constIT0_EE5valueEKNS4_13tuple_elementIXT_ES9_E4typeESK_E4typeEPSH_ Unexecuted instantiation: _ZNK4absl12lts_2023012518container_internal15internal_layout10LayoutImplINSt3__15tupleIJmPNS0_13cord_internal7CordRepEjEEENS0_16integer_sequenceImJLm0ELm1EEEENSA_ImJLm0ELm1ELm2EEEEE7PointerILm2EKcEEPNS4_11conditionalIXsr3std8is_constIT0_EE5valueEKNS4_13tuple_elementIXT_ES9_E4typeESK_E4typeEPSH_ Unexecuted instantiation: _ZNK4absl12lts_2023012518container_internal15internal_layout10LayoutImplINSt3__15tupleIJmPNS0_13cord_internal7CordRepEjEEENS0_16integer_sequenceImJEEENSA_ImJLm0EEEEE7PointerILm0EcEEPNS4_11conditionalIXsr3std8is_constIT0_EE5valueEKNS4_13tuple_elementIXT_ES9_E4typeESJ_E4typeEPSG_ Unexecuted instantiation: _ZNK4absl12lts_2023012518container_internal15internal_layout10LayoutImplINSt3__15tupleIJmPNS0_13cord_internal7CordRepEjEEENS0_16integer_sequenceImJLm0EEEENSA_ImJLm0ELm1EEEEE7PointerILm1EcEEPNS4_11conditionalIXsr3std8is_constIT0_EE5valueEKNS4_13tuple_elementIXT_ES9_E4typeESJ_E4typeEPSG_ Unexecuted instantiation: _ZNK4absl12lts_2023012518container_internal15internal_layout10LayoutImplINSt3__15tupleIJmPNS0_13cord_internal7CordRepEjEEENS0_16integer_sequenceImJLm0ELm1EEEENSA_ImJLm0ELm1ELm2EEEEE7PointerILm2EcEEPNS4_11conditionalIXsr3std8is_constIT0_EE5valueEKNS4_13tuple_elementIXT_ES9_E4typeESJ_E4typeEPSG_ |
486 | | |
487 | | // Pointer to the beginning of the array with the specified element type. |
488 | | // There must be exactly one such array and its zero-based index must be at |
489 | | // most `NumSizes`. |
490 | | // |
491 | | // `Char` must be `[const] [signed|unsigned] char`. |
492 | | // |
493 | | // // int[3], 4 bytes of padding, double[4]. |
494 | | // Layout<int, double> x(3, 4); |
495 | | // unsigned char* p = new unsigned char[x.AllocSize()]; |
496 | | // int* ints = x.Pointer<int>(p); |
497 | | // double* doubles = x.Pointer<double>(p); |
498 | | // |
499 | | // Requires: `p` is aligned to `Alignment()`. |
500 | | template <class T, class Char> |
501 | | CopyConst<Char, T>* Pointer(Char* p) const { |
502 | | return Pointer<ElementIndex<T>()>(p); |
503 | | } |
504 | | |
505 | | // Pointers to all arrays for which pointers are known. |
506 | | // |
507 | | // `Char` must be `[const] [signed|unsigned] char`. |
508 | | // |
509 | | // // int[3], 4 bytes of padding, double[4]. |
510 | | // Layout<int, double> x(3, 4); |
511 | | // unsigned char* p = new unsigned char[x.AllocSize()]; |
512 | | // |
513 | | // int* ints; |
514 | | // double* doubles; |
515 | | // std::tie(ints, doubles) = x.Pointers(p); |
516 | | // |
517 | | // Requires: `p` is aligned to `Alignment()`. |
518 | | // |
519 | | // Note: We're not using ElementType alias here because it does not compile |
520 | | // under MSVC. |
521 | | template <class Char> |
522 | | std::tuple<CopyConst< |
523 | | Char, typename std::tuple_element<OffsetSeq, ElementTypes>::type>*...> |
524 | | Pointers(Char* p) const { |
525 | | return std::tuple<CopyConst<Char, ElementType<OffsetSeq>>*...>( |
526 | | Pointer<OffsetSeq>(p)...); |
527 | | } |
528 | | |
529 | | // The Nth array. |
530 | | // |
531 | | // `Char` must be `[const] [signed|unsigned] char`. |
532 | | // |
533 | | // // int[3], 4 bytes of padding, double[4]. |
534 | | // Layout<int, double> x(3, 4); |
535 | | // unsigned char* p = new unsigned char[x.AllocSize()]; |
536 | | // Span<int> ints = x.Slice<0>(p); |
537 | | // Span<double> doubles = x.Slice<1>(p); |
538 | | // |
539 | | // Requires: `N < NumSizes`. |
540 | | // Requires: `p` is aligned to `Alignment()`. |
541 | | template <size_t N, class Char> |
542 | | SliceType<CopyConst<Char, ElementType<N>>> Slice(Char* p) const { |
543 | | return SliceType<CopyConst<Char, ElementType<N>>>(Pointer<N>(p), Size<N>()); |
544 | | } |
545 | | |
546 | | // The array with the specified element type. There must be exactly one |
547 | | // such array and its zero-based index must be less than `NumSizes`. |
548 | | // |
549 | | // `Char` must be `[const] [signed|unsigned] char`. |
550 | | // |
551 | | // // int[3], 4 bytes of padding, double[4]. |
552 | | // Layout<int, double> x(3, 4); |
553 | | // unsigned char* p = new unsigned char[x.AllocSize()]; |
554 | | // Span<int> ints = x.Slice<int>(p); |
555 | | // Span<double> doubles = x.Slice<double>(p); |
556 | | // |
557 | | // Requires: `p` is aligned to `Alignment()`. |
558 | | template <class T, class Char> |
559 | | SliceType<CopyConst<Char, T>> Slice(Char* p) const { |
560 | | return Slice<ElementIndex<T>()>(p); |
561 | | } |
562 | | |
563 | | // All arrays with known sizes. |
564 | | // |
565 | | // `Char` must be `[const] [signed|unsigned] char`. |
566 | | // |
567 | | // // int[3], 4 bytes of padding, double[4]. |
568 | | // Layout<int, double> x(3, 4); |
569 | | // unsigned char* p = new unsigned char[x.AllocSize()]; |
570 | | // |
571 | | // Span<int> ints; |
572 | | // Span<double> doubles; |
573 | | // std::tie(ints, doubles) = x.Slices(p); |
574 | | // |
575 | | // Requires: `p` is aligned to `Alignment()`. |
576 | | // |
577 | | // Note: We're not using ElementType alias here because it does not compile |
578 | | // under MSVC. |
579 | | template <class Char> |
580 | | std::tuple<SliceType<CopyConst< |
581 | | Char, typename std::tuple_element<SizeSeq, ElementTypes>::type>>...> |
582 | | Slices(Char* p) const { |
583 | | // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63875 (fixed |
584 | | // in 6.1). |
585 | | (void)p; |
586 | | return std::tuple<SliceType<CopyConst<Char, ElementType<SizeSeq>>>...>( |
587 | | Slice<SizeSeq>(p)...); |
588 | | } |
589 | | |
590 | | // The size of the allocation that fits all arrays. |
591 | | // |
592 | | // // int[3], 4 bytes of padding, double[4]. |
593 | | // Layout<int, double> x(3, 4); |
594 | | // unsigned char* p = new unsigned char[x.AllocSize()]; // 48 bytes |
595 | | // |
596 | | // Requires: `NumSizes == sizeof...(Ts)`. |
597 | 0 | constexpr size_t AllocSize() const { |
598 | 0 | static_assert(NumTypes == NumSizes, "You must specify sizes of all fields"); |
599 | 0 | return Offset<NumTypes - 1>() + |
600 | 0 | SizeOf<ElementType<NumTypes - 1>>::value * size_[NumTypes - 1]; |
601 | 0 | } Unexecuted instantiation: absl::lts_20230125::container_internal::internal_layout::LayoutImpl<std::__1::tuple<unsigned long, absl::lts_20230125::cord_internal::CordRep*, unsigned int>, absl::lts_20230125::integer_sequence<unsigned long, 0ul, 1ul, 2ul>, absl::lts_20230125::integer_sequence<unsigned long, 0ul, 1ul, 2ul> >::AllocSize() const Unexecuted instantiation: absl::lts_20230125::container_internal::internal_layout::LayoutImpl<std::__1::tuple<absl::lts_20230125::container_internal::btree_node<absl::lts_20230125::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_20230125::container_internal::map_slot_type<int, google::protobuf::internal::ExtensionSet::Extension>, absl::lts_20230125::container_internal::btree_node<absl::lts_20230125::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> >*>, absl::lts_20230125::integer_sequence<unsigned long, 0ul, 1ul, 2ul, 3ul, 4ul>, absl::lts_20230125::integer_sequence<unsigned long, 0ul, 1ul, 2ul, 3ul, 4ul> >::AllocSize() const |
602 | | |
603 | | // If built with --config=asan, poisons padding bytes (if any) in the |
604 | | // allocation. The pointer must point to a memory block at least |
605 | | // `AllocSize()` bytes in length. |
606 | | // |
607 | | // `Char` must be `[const] [signed|unsigned] char`. |
608 | | // |
609 | | // Requires: `p` is aligned to `Alignment()`. |
610 | | template <class Char, size_t N = NumOffsets - 1, EnableIf<N == 0> = 0> |
611 | | void PoisonPadding(const Char* p) const { |
612 | | Pointer<0>(p); // verify the requirements on `Char` and `p` |
613 | | } |
614 | | |
615 | | template <class Char, size_t N = NumOffsets - 1, EnableIf<N != 0> = 0> |
616 | | void PoisonPadding(const Char* p) const { |
617 | | static_assert(N < NumOffsets, "Index out of bounds"); |
618 | | (void)p; |
619 | | #ifdef ABSL_HAVE_ADDRESS_SANITIZER |
620 | | PoisonPadding<Char, N - 1>(p); |
621 | | // The `if` is an optimization. It doesn't affect the observable behaviour. |
622 | | if (ElementAlignment<N - 1>::value % ElementAlignment<N>::value) { |
623 | | size_t start = |
624 | | Offset<N - 1>() + SizeOf<ElementType<N - 1>>::value * size_[N - 1]; |
625 | | ASAN_POISON_MEMORY_REGION(p + start, Offset<N>() - start); |
626 | | } |
627 | | #endif |
628 | | } |
629 | | |
630 | | // Human-readable description of the memory layout. Useful for debugging. |
631 | | // Slow. |
632 | | // |
633 | | // // char[5], 3 bytes of padding, int[3], 4 bytes of padding, followed |
634 | | // // by an unknown number of doubles. |
635 | | // auto x = Layout<char, int, double>::Partial(5, 3); |
636 | | // assert(x.DebugString() == |
637 | | // "@0<char>(1)[5]; @8<int>(4)[3]; @24<double>(8)"); |
638 | | // |
639 | | // Each field is in the following format: @offset<type>(sizeof)[size] (<type> |
640 | | // may be missing depending on the target platform). For example, |
641 | | // @8<int>(4)[3] means that at offset 8 we have an array of ints, where each |
642 | | // int is 4 bytes, and we have 3 of those ints. The size of the last field may |
643 | | // be missing (as in the example above). Only fields with known offsets are |
644 | | // described. Type names may differ across platforms: one compiler might |
645 | | // produce "unsigned*" where another produces "unsigned int *". |
646 | | std::string DebugString() const { |
647 | | const auto offsets = Offsets(); |
648 | | const size_t sizes[] = {SizeOf<ElementType<OffsetSeq>>::value...}; |
649 | | const std::string types[] = { |
650 | | adl_barrier::TypeName<ElementType<OffsetSeq>>()...}; |
651 | | std::string res = absl::StrCat("@0", types[0], "(", sizes[0], ")"); |
652 | | for (size_t i = 0; i != NumOffsets - 1; ++i) { |
653 | | absl::StrAppend(&res, "[", size_[i], "]; @", offsets[i + 1], types[i + 1], |
654 | | "(", sizes[i + 1], ")"); |
655 | | } |
656 | | // NumSizes is a constant that may be zero. Some compilers cannot see that |
657 | | // inside the if statement "size_[NumSizes - 1]" must be valid. |
658 | | int last = static_cast<int>(NumSizes) - 1; |
659 | | if (NumTypes == NumSizes && last >= 0) { |
660 | | absl::StrAppend(&res, "[", size_[last], "]"); |
661 | | } |
662 | | return res; |
663 | | } |
664 | | |
665 | | private: |
666 | | // Arguments of `Layout::Partial()` or `Layout::Layout()`. |
667 | | size_t size_[NumSizes > 0 ? NumSizes : 1]; |
668 | | }; |
669 | | |
670 | | template <size_t NumSizes, class... Ts> |
671 | | using LayoutType = LayoutImpl< |
672 | | std::tuple<Ts...>, absl::make_index_sequence<NumSizes>, |
673 | | absl::make_index_sequence<adl_barrier::Min(sizeof...(Ts), NumSizes + 1)>>; |
674 | | |
675 | | } // namespace internal_layout |
676 | | |
677 | | // Descriptor of arrays of various types and sizes laid out in memory one after |
678 | | // another. See the top of the file for documentation. |
679 | | // |
680 | | // Check out the public API of internal_layout::LayoutImpl above. The type is |
681 | | // internal to the library but its methods are public, and they are inherited |
682 | | // by `Layout`. |
683 | | template <class... Ts> |
684 | | class Layout : public internal_layout::LayoutType<sizeof...(Ts), Ts...> { |
685 | | public: |
686 | | static_assert(sizeof...(Ts) > 0, "At least one field is required"); |
687 | | static_assert( |
688 | | absl::conjunction<internal_layout::IsLegalElementType<Ts>...>::value, |
689 | | "Invalid element type (see IsLegalElementType)"); |
690 | | |
691 | | // The result type of `Partial()` with `NumSizes` arguments. |
692 | | template <size_t NumSizes> |
693 | | using PartialType = internal_layout::LayoutType<NumSizes, Ts...>; |
694 | | |
695 | | // `Layout` knows the element types of the arrays we want to lay out in |
696 | | // memory but not the number of elements in each array. |
697 | | // `Partial(size1, ..., sizeN)` allows us to specify the latter. The |
698 | | // resulting immutable object can be used to obtain pointers to the |
699 | | // individual arrays. |
700 | | // |
701 | | // It's allowed to pass fewer array sizes than the number of arrays. E.g., |
702 | | // if all you need is to the offset of the second array, you only need to |
703 | | // pass one argument -- the number of elements in the first array. |
704 | | // |
705 | | // // int[3] followed by 4 bytes of padding and an unknown number of |
706 | | // // doubles. |
707 | | // auto x = Layout<int, double>::Partial(3); |
708 | | // // doubles start at byte 16. |
709 | | // assert(x.Offset<1>() == 16); |
710 | | // |
711 | | // If you know the number of elements in all arrays, you can still call |
712 | | // `Partial()` but it's more convenient to use the constructor of `Layout`. |
713 | | // |
714 | | // Layout<int, double> x(3, 5); |
715 | | // |
716 | | // Note: The sizes of the arrays must be specified in number of elements, |
717 | | // not in bytes. |
718 | | // |
719 | | // Requires: `sizeof...(Sizes) <= sizeof...(Ts)`. |
720 | | // Requires: all arguments are convertible to `size_t`. |
721 | | template <class... Sizes> |
722 | 0 | static constexpr PartialType<sizeof...(Sizes)> Partial(Sizes&&... sizes) { |
723 | 0 | static_assert(sizeof...(Sizes) <= sizeof...(Ts), ""); |
724 | 0 | return PartialType<sizeof...(Sizes)>(absl::forward<Sizes>(sizes)...); |
725 | 0 | } Unexecuted instantiation: absl::lts_20230125::container_internal::internal_layout::LayoutImpl<std::__1::tuple<unsigned long, absl::lts_20230125::cord_internal::CordRep*, unsigned int>, absl::lts_20230125::utility_internal::Gen<unsigned long, 0>::type, absl::lts_20230125::utility_internal::Gen<unsigned long, absl::lts_20230125::container_internal::internal_layout::adl_barrier::Min(0, (0)+(1))>::type> absl::lts_20230125::container_internal::Layout<unsigned long, absl::lts_20230125::cord_internal::CordRep*, unsigned int>::Partial<>() Unexecuted instantiation: absl::lts_20230125::container_internal::internal_layout::LayoutImpl<std::__1::tuple<unsigned long, absl::lts_20230125::cord_internal::CordRep*, unsigned int>, absl::lts_20230125::utility_internal::Gen<unsigned long, 1>::type, absl::lts_20230125::utility_internal::Gen<unsigned long, absl::lts_20230125::container_internal::internal_layout::adl_barrier::Min(0, (1)+(1))>::type> absl::lts_20230125::container_internal::Layout<unsigned long, absl::lts_20230125::cord_internal::CordRep*, unsigned int>::Partial<unsigned int>(unsigned int&&) Unexecuted instantiation: absl::lts_20230125::container_internal::internal_layout::LayoutImpl<std::__1::tuple<unsigned long, absl::lts_20230125::cord_internal::CordRep*, unsigned int>, absl::lts_20230125::utility_internal::Gen<unsigned long, 2>::type, absl::lts_20230125::utility_internal::Gen<unsigned long, absl::lts_20230125::container_internal::internal_layout::adl_barrier::Min(0, (2)+(1))>::type> absl::lts_20230125::container_internal::Layout<unsigned long, absl::lts_20230125::cord_internal::CordRep*, unsigned int>::Partial<unsigned int, unsigned int>(unsigned int&&, unsigned int&&) |
726 | | |
727 | | // Creates a layout with the sizes of all arrays specified. If you know |
728 | | // only the sizes of the first N arrays (where N can be zero), you can use |
729 | | // `Partial()` defined above. The constructor is essentially equivalent to |
730 | | // calling `Partial()` and passing in all array sizes; the constructor is |
731 | | // provided as a convenient abbreviation. |
732 | | // |
733 | | // Note: The sizes of the arrays must be specified in number of elements, |
734 | | // not in bytes. |
735 | | constexpr explicit Layout(internal_layout::TypeToSize<Ts>... sizes) |
736 | | : internal_layout::LayoutType<sizeof...(Ts), Ts...>(sizes...) {} |
737 | | }; |
738 | | |
739 | | } // namespace container_internal |
740 | | ABSL_NAMESPACE_END |
741 | | } // namespace absl |
742 | | |
743 | | #endif // ABSL_CONTAINER_INTERNAL_LAYOUT_H_ |