• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 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 constexpr size_t Align(size_t n, size_t m) { return (n + m - 1) & ~(m - 1); }
277 
278 constexpr size_t Min(size_t a, size_t b) { return b < a ? b : a; }
279 
280 constexpr size_t Max(size_t a) { return a; }
281 
282 template <class... Ts>
283 constexpr size_t Max(size_t a, size_t b, Ts... rest) {
284   return adl_barrier::Max(b < a ? a : b, rest...);
285 }
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   static constexpr size_t Alignment() {
372     return adl_barrier::Max(AlignOf<Elements>::value...);
373   }
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   constexpr size_t Offset() const {
385     return 0;
386   }
387 
388   template <size_t N, EnableIf<N != 0> = 0>
389   constexpr size_t Offset() const {
390     static_assert(N < NumOffsets, "Index out of bounds");
391     return adl_barrier::Align(
392         Offset<N - 1>() + SizeOf<ElementType<N - 1>>::value * size_[N - 1],
393         ElementAlignment<N>::value);
394   }
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   CopyConst<Char, ElementType<N>>* Pointer(Char* p) const {
461     using C = typename std::remove_const<Char>::type;
462     static_assert(
463         std::is_same<C, char>() || std::is_same<C, unsigned char>() ||
464             std::is_same<C, signed char>(),
465         "The argument must be a pointer to [const] [signed|unsigned] char");
466     constexpr size_t alignment = Alignment();
467     (void)alignment;
468     assert(reinterpret_cast<uintptr_t>(p) % alignment == 0);
469     return reinterpret_cast<CopyConst<Char, ElementType<N>>*>(p + Offset<N>());
470   }
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   constexpr size_t AllocSize() const {
583     static_assert(NumTypes == NumSizes, "You must specify sizes of all fields");
584     return Offset<NumTypes - 1>() +
585         SizeOf<ElementType<NumTypes - 1>>::value * size_[NumTypes - 1];
586   }
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_
729