abseil-cpp/absl/container/internal/layout.h
Go to the documentation of this file.
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 {
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>
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>
254 
255 template <class From, class To>
256 using CopyConst =
258 
259 // Note: We're not qualifying this with absl:: because it doesn't compile under
260 // MSVC.
261 template <class 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 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 constexpr size_t Align(size_t n, size_t m) { return (n + m - 1) & ~(m - 1); }
284 
285 constexpr size_t Min(size_t a, size_t b) { return b < a ? b : a; }
286 
287 constexpr size_t Max(size_t a) { return a; }
288 
289 template <class... Ts>
290 constexpr size_t Max(size_t a, size_t b, Ts... rest) {
291  return adl_barrier::Max(b < a ? a : b, rest...);
292 }
293 
294 template <class T>
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>
317 
318 // Can `T` be a template argument of `Layout`?
319 template <class T>
320 using IsLegalElementType = std::integral_constant<
325 
326 template <class Elements, class SizeSeq, class OffsetSeq>
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");
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.
376 
377  // Element type of the Nth array.
378  template <size_t N>
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  static constexpr size_t Alignment() {
388  }
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  constexpr size_t Offset() const {
400  return 0;
401  }
402 
403  template <size_t N, EnableIf<N != 0> = 0>
404  constexpr size_t Offset() const {
405  static_assert(N < NumOffsets, "Index out of bounds");
406  return adl_barrier::Align(
407  Offset<N - 1>() + SizeOf<ElementType<N - 1>>::value * size_[N - 1],
409  }
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>
476  using C = typename std::remove_const<Char>::type;
477  static_assert(
478  std::is_same<C, char>() || std::is_same<C, unsigned char>() ||
479  std::is_same<C, signed char>(),
480  "The argument must be a pointer to [const] [signed|unsigned] char");
481  constexpr size_t alignment = Alignment();
482  (void)alignment;
483  assert(reinterpret_cast<uintptr_t>(p) % alignment == 0);
484  return reinterpret_cast<CopyConst<Char, ElementType<N>>*>(p + Offset<N>());
485  }
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>
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<
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>
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>
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<
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  constexpr size_t AllocSize() const {
598  static_assert(NumTypes == NumSizes, "You must specify sizes of all fields");
599  return Offset<NumTypes - 1>() +
600  SizeOf<ElementType<NumTypes - 1>>::value * size_[NumTypes - 1];
601  }
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.
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 *".
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(
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  static constexpr PartialType<sizeof...(Sizes)> Partial(Sizes&&... sizes) {
723  static_assert(sizeof...(Sizes) <= sizeof...(Ts), "");
724  return PartialType<sizeof...(Sizes)>(absl::forward<Sizes>(sizes)...);
725  }
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
741 } // namespace absl
742 
743 #endif // ABSL_CONTAINER_INTERNAL_LAYOUT_H_
absl::container_internal::Aligned
Definition: abseil-cpp/absl/container/internal/layout.h:204
absl::container_internal::internal_layout::LayoutImpl< std::tuple< Elements... >, absl::index_sequence< SizeSeq... >, absl::index_sequence< OffsetSeq... > >::Offset
constexpr size_t Offset() const
Definition: abseil-cpp/absl/container/internal/layout.h:420
absl::container_internal::internal_layout::LayoutImpl< std::tuple< Elements... >, absl::index_sequence< SizeSeq... >, absl::index_sequence< OffsetSeq... > >::ElementTypes
std::tuple< typename Type< Elements >::type... > ElementTypes
Definition: abseil-cpp/absl/container/internal/layout.h:375
absl::StrAppend
void StrAppend(std::string *dest, const AlphaNum &a)
Definition: abseil-cpp/absl/strings/str_cat.cc:193
const
#define const
Definition: bloaty/third_party/zlib/zconf.h:230
bool
bool
Definition: setup_once.h:312
absl::StrCat
std::string StrCat(const AlphaNum &a, const AlphaNum &b)
Definition: abseil-cpp/absl/strings/str_cat.cc:98
absl::conjunction
Definition: abseil-cpp/absl/meta/type_traits.h:230
absl::container_internal::internal_layout::adl_barrier::Max
constexpr size_t Max(size_t a)
Definition: abseil-cpp/absl/container/internal/layout.h:287
C
#define C(x)
Definition: abseil-cpp/absl/hash/internal/city_test.cc:49
absl::Span
Definition: abseil-cpp/absl/types/span.h:152
absl::container_internal::Layout::Layout
constexpr Layout(internal_layout::TypeToSize< Ts >... sizes)
Definition: abseil-cpp/absl/container/internal/layout.h:735
__cxa_demangle
char * __cxa_demangle(const char *mangled_name, char *buf, size_t *n, int *status)
Definition: cxa_demangle.cpp:4927
absl::container_internal::internal_layout::LayoutImpl< std::tuple< Elements... >, absl::index_sequence< SizeSeq... >, absl::index_sequence< OffsetSeq... > >::Pointer
CopyConst< Char, T > * Pointer(Char *p) const
Definition: abseil-cpp/absl/container/internal/layout.h:501
absl::container_internal::internal_layout::LayoutImpl< std::tuple< Elements... >, absl::index_sequence< SizeSeq... >, absl::index_sequence< OffsetSeq... > >::DebugString
std::string DebugString() const
Definition: abseil-cpp/absl/container/internal/layout.h:646
testing::internal::string
::std::string string
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:881
absl::container_internal::internal_layout::Type
Definition: abseil-cpp/absl/container/internal/layout.h:223
status
absl::Status status
Definition: rls.cc:251
setup.name
name
Definition: setup.py:542
absl::container_internal::internal_layout::LayoutImpl
Definition: abseil-cpp/absl/container/internal/layout.h:327
absl::container_internal::internal_layout::LayoutImpl< std::tuple< Elements... >, absl::index_sequence< SizeSeq... >, absl::index_sequence< OffsetSeq... > >::Offset
constexpr size_t Offset() const
Definition: abseil-cpp/absl/container/internal/layout.h:399
a
int a
Definition: abseil-cpp/absl/container/internal/hash_policy_traits_test.cc:88
ABSL_NAMESPACE_END
#define ABSL_NAMESPACE_END
Definition: third_party/abseil-cpp/absl/base/config.h:171
T
#define T(upbtypeconst, upbtype, ctype, default_value)
absl::container_internal::internal_layout::LayoutImpl< std::tuple< Elements... >, absl::index_sequence< SizeSeq... >, absl::index_sequence< OffsetSeq... > >::PoisonPadding
void PoisonPadding(const Char *p) const
Definition: abseil-cpp/absl/container/internal/layout.h:611
testing::gmock_generated_actions_test::Char
char Char(char ch)
Definition: bloaty/third_party/googletest/googlemock/test/gmock-generated-actions_test.cc:63
absl::container_internal::internal_layout::LayoutImpl< std::tuple< Elements... >, absl::index_sequence< SizeSeq... >, absl::index_sequence< OffsetSeq... > >::Sizes
constexpr std::array< size_t, NumSizes > Sizes() const
Definition: abseil-cpp/absl/container/internal/layout.h:458
absl::container_internal::internal_layout::adl_barrier::Min
constexpr size_t Min(size_t a, size_t b)
Definition: abseil-cpp/absl/container/internal/layout.h:285
absl::container_internal::internal_layout::IsLegalElementType
std::integral_constant< bool, !std::is_reference< T >::value &&!std::is_volatile< T >::value &&!std::is_reference< typename Type< T >::type >::value &&!std::is_volatile< typename Type< T >::type >::value &&adl_barrier::IsPow2(AlignOf< T >::value)> IsLegalElementType
Definition: abseil-cpp/absl/container/internal/layout.h:324
start
static uint64_t start
Definition: benchmark-pound.c:74
absl::container_internal::internal_layout::LayoutImpl< std::tuple< Elements... >, absl::index_sequence< SizeSeq... >, absl::index_sequence< OffsetSeq... > >::Slice
SliceType< CopyConst< Char, T > > Slice(Char *p) const
Definition: abseil-cpp/absl/container/internal/layout.h:559
ABSL_NAMESPACE_BEGIN
#define ABSL_NAMESPACE_BEGIN
Definition: third_party/abseil-cpp/absl/base/config.h:170
absl::container_internal::internal_layout::Type< Aligned< T, N > >::type
T type
Definition: abseil-cpp/absl/container/internal/layout.h:229
absl::container_internal::Layout
Definition: abseil-cpp/absl/container/internal/layout.h:684
absl::container_internal::internal_layout::LayoutType
LayoutImpl< std::tuple< Ts... >, absl::make_index_sequence< NumSizes >, absl::make_index_sequence< adl_barrier::Min(sizeof...(Ts), NumSizes+1)> > LayoutType
Definition: abseil-cpp/absl/container/internal/layout.h:673
absl::container_internal::internal_layout::LayoutImpl< std::tuple< Elements... >, absl::index_sequence< SizeSeq... >, absl::index_sequence< OffsetSeq... > >::Offsets
constexpr std::array< size_t, NumOffsets > Offsets() const
Definition: abseil-cpp/absl/container/internal/layout.h:425
absl::make_index_sequence
make_integer_sequence< size_t, N > make_index_sequence
Definition: abseil-cpp/absl/utility/utility.h:150
absl::integer_sequence
Definition: abseil-cpp/absl/utility/utility.h:76
absl::container_internal::internal_layout::AlignOf
Definition: abseil-cpp/absl/container/internal/layout.h:240
absl::container_internal::internal_layout::LayoutImpl< std::tuple< Elements... >, absl::index_sequence< SizeSeq... >, absl::index_sequence< OffsetSeq... > >::Pointer
CopyConst< Char, ElementType< N > > * Pointer(Char *p) const
Definition: abseil-cpp/absl/container/internal/layout.h:475
absl::container_internal::internal_layout::LayoutImpl< std::tuple< Elements... >, absl::index_sequence< SizeSeq... >, absl::index_sequence< OffsetSeq... > >::ElementType
typename std::tuple_element< N, ElementTypes >::type ElementType
Definition: abseil-cpp/absl/container/internal/layout.h:379
absl::container_internal::internal_layout::IntToSize
size_t IntToSize
Definition: abseil-cpp/absl/container/internal/layout.h:217
uintptr_t
_W64 unsigned int uintptr_t
Definition: stdint-msvc2008.h:119
b
uint64_t b
Definition: abseil-cpp/absl/container/internal/layout_test.cc:53
n
int n
Definition: abseil-cpp/absl/container/btree_test.cc:1080
stdint.h
absl::container_internal::internal_layout::adl_barrier::TypeName
std::string TypeName()
Definition: abseil-cpp/absl/container/internal/layout.h:295
absl::container_internal::internal_layout::LayoutImpl< std::tuple< Elements... >, absl::index_sequence< SizeSeq... >, absl::index_sequence< OffsetSeq... > >::AllocSize
constexpr size_t AllocSize() const
Definition: abseil-cpp/absl/container/internal/layout.h:597
value
const char * value
Definition: hpack_parser_table.cc:165
absl::container_internal::Layout::Partial
static constexpr PartialType< sizeof...(Sizes)> Partial(Sizes &&... sizes)
Definition: abseil-cpp/absl/container/internal/layout.h:722
absl::container_internal::internal_layout::EnableIf
typename std::enable_if< C, int >::type EnableIf
Definition: abseil-cpp/absl/container/internal/layout.h:316
alignment
static const std::size_t alignment
Definition: cxa_demangle.cpp:4721
absl::container_internal::internal_layout::LayoutImpl< std::tuple< Elements... >, absl::index_sequence< SizeSeq... >, absl::index_sequence< OffsetSeq... > >::Size
constexpr size_t Size() const
Definition: abseil-cpp/absl/container/internal/layout.h:439
N
#define N
Definition: sync_test.cc:37
size_
size_t size_
Definition: memory_allocator.cc:56
absl::container_internal::internal_layout::LayoutImpl< std::tuple< Elements... >, absl::index_sequence< SizeSeq... >, absl::index_sequence< OffsetSeq... > >::Slice
SliceType< CopyConst< Char, ElementType< N > > > Slice(Char *p) const
Definition: abseil-cpp/absl/container/internal/layout.h:542
absl::container_internal::internal_layout::adl_barrier::IsPow2
constexpr bool IsPow2(size_t n)
Definition: abseil-cpp/absl/container/internal/layout.h:279
absl::container_internal::internal_layout::adl_barrier::Find
constexpr size_t Find(Needle, Needle, Ts...)
Definition: abseil-cpp/absl/container/internal/layout.h:269
std
Definition: grpcpp/impl/codegen/async_unary_call.h:407
types
static const struct nv types[]
Definition: adig.c:83
absl::disjunction
Definition: abseil-cpp/absl/meta/type_traits.h:249
absl::container_internal::internal_layout::LayoutImpl< std::tuple< Elements... >, absl::index_sequence< SizeSeq... >, absl::index_sequence< OffsetSeq... > >::Slices
std::tuple< SliceType< CopyConst< Char, typename std::tuple_element< SizeSeq, ElementTypes >::type > >... > Slices(Char *p) const
Definition: abseil-cpp/absl/container/internal/layout.h:582
absl::container_internal::internal_layout::TypeToSize
size_t TypeToSize
Definition: abseil-cpp/absl/container/internal/layout.h:220
absl
Definition: abseil-cpp/absl/algorithm/algorithm.h:31
absl::container_internal::internal_layout::NotAligned
Definition: abseil-cpp/absl/container/internal/layout.h:209
absl::container_internal::internal_layout::AlignOf::value
static constexpr size_t value
Definition: abseil-cpp/absl/container/internal/layout.h:241
asyncio_get_stats.type
type
Definition: asyncio_get_stats.py:37
absl::out
char * out
Definition: abseil-cpp/absl/synchronization/mutex.h:1048
absl::container_internal::internal_layout::adl_barrier::Align
constexpr size_t Align(size_t n, size_t m)
Definition: abseil-cpp/absl/container/internal/layout.h:283
absl::container_internal::internal_layout::CopyConst
typename std::conditional< std::is_const< From >::value, const To, To >::type CopyConst
Definition: abseil-cpp/absl/container/internal/layout.h:257
absl::container_internal::internal_layout::LayoutImpl< std::tuple< Elements... >, absl::index_sequence< SizeSeq... >, absl::index_sequence< OffsetSeq... > >::ElementIndex
static constexpr size_t ElementIndex()
Definition: abseil-cpp/absl/container/internal/layout.h:362
regress.m
m
Definition: regress/regress.py:25
absl::container_internal::internal_layout::SizeOf
Definition: abseil-cpp/absl/container/internal/layout.h:233
absl::container_internal::internal_layout::LayoutImpl< std::tuple< Elements... >, absl::index_sequence< SizeSeq... >, absl::index_sequence< OffsetSeq... > >::Alignment
static constexpr size_t Alignment()
Definition: abseil-cpp/absl/container/internal/layout.h:386
absl::container_internal::internal_layout::Type::type
T type
Definition: abseil-cpp/absl/container/internal/layout.h:224
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
absl::container_internal::internal_layout::LayoutImpl< std::tuple< Elements... >, absl::index_sequence< SizeSeq... >, absl::index_sequence< OffsetSeq... > >::Pointers
std::tuple< CopyConst< Char, typename std::tuple_element< OffsetSeq, ElementTypes >::type > *... > Pointers(Char *p) const
Definition: abseil-cpp/absl/container/internal/layout.h:524
absl::container_internal::internal_layout::LayoutImpl< std::tuple< Elements... >, absl::index_sequence< SizeSeq... >, absl::index_sequence< OffsetSeq... > >::LayoutImpl
constexpr LayoutImpl(IntToSize< SizeSeq >... sizes)
Definition: abseil-cpp/absl/container/internal/layout.h:381


grpc
Author(s):
autogenerated on Fri May 16 2025 02:59:14