tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

layout.h (31726B)


      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 attempts to
     85 // generate optimal code. To help the compiler do that in more cases, you can
     86 // specify the fixed sizes using `WithStaticSizes`. This ensures that all
     87 // computations that can be performed at compile time are indeed performed at
     88 // compile time. Note that sometimes the `template` keyword is needed. E.g.:
     89 //
     90 //   using SL = L::template WithStaticSizes<1, 1>;
     91 //
     92 //   void Use(unsigned char* p) {
     93 //     // First, extract N and M.
     94 //     // Using `prefix` we can access the first three arrays but not more.
     95 //     //
     96 //     // More details: The first element always has offset 0. `SL`
     97 //     // has offsets for the second and third array based on sizes of
     98 //     // the first and second array, specified via `WithStaticSizes`.
     99 //     constexpr auto prefix = SL::Partial();
    100 //     size_t n = *prefix.Pointer<0>(p);
    101 //     size_t m = *prefix.Pointer<1>(p);
    102 //
    103 //     // Now we can get a pointer to the final payload.
    104 //     const SL layout(n, m);
    105 //     double* a = layout.Pointer<double>(p);
    106 //     int* b = layout.Pointer<int>(p);
    107 //   }
    108 //
    109 // Efficiency tip: The order of fields matters. In `Layout<T1, ..., TN>` try to
    110 // ensure that `alignof(T1) >= ... >= alignof(TN)`. This way you'll have no
    111 // padding in between arrays.
    112 //
    113 // You can manually override the alignment of an array by wrapping the type in
    114 // `Aligned<T, N>`. `Layout<..., Aligned<T, N>, ...>` has exactly the same API
    115 // and behavior as `Layout<..., T, ...>` except that the first element of the
    116 // array of `T` is aligned to `N` (the rest of the elements follow without
    117 // padding). `N` cannot be less than `alignof(T)`.
    118 //
    119 // `AllocSize()` and `Pointer()` are the most basic methods for dealing with
    120 // memory layouts. Check out the reference or code below to discover more.
    121 //
    122 //                            EXAMPLE
    123 //
    124 //   // Immutable move-only string with sizeof equal to sizeof(void*). The
    125 //   // string size and the characters are kept in the same heap allocation.
    126 //   class CompactString {
    127 //    public:
    128 //     CompactString(const char* s = "") {
    129 //       const size_t size = strlen(s);
    130 //       // size_t[1] followed by char[size + 1].
    131 //       const L layout(size + 1);
    132 //       p_.reset(new unsigned char[layout.AllocSize()]);
    133 //       // If running under ASAN, mark the padding bytes, if any, to catch
    134 //       // memory errors.
    135 //       layout.PoisonPadding(p_.get());
    136 //       // Store the size in the allocation.
    137 //       *layout.Pointer<size_t>(p_.get()) = size;
    138 //       // Store the characters in the allocation.
    139 //       memcpy(layout.Pointer<char>(p_.get()), s, size + 1);
    140 //     }
    141 //
    142 //     size_t size() const {
    143 //       // Equivalent to reinterpret_cast<size_t&>(*p).
    144 //       return *L::Partial().Pointer<size_t>(p_.get());
    145 //     }
    146 //
    147 //     const char* c_str() const {
    148 //       // Equivalent to reinterpret_cast<char*>(p.get() + sizeof(size_t)).
    149 //       return L::Partial().Pointer<char>(p_.get());
    150 //     }
    151 //
    152 //    private:
    153 //     // Our heap allocation contains a single size_t followed by an array of
    154 //     // chars.
    155 //     using L = Layout<size_t, char>::WithStaticSizes<1>;
    156 //     std::unique_ptr<unsigned char[]> p_;
    157 //   };
    158 //
    159 //   int main() {
    160 //     CompactString s = "hello";
    161 //     assert(s.size() == 5);
    162 //     assert(strcmp(s.c_str(), "hello") == 0);
    163 //   }
    164 //
    165 //                               DOCUMENTATION
    166 //
    167 // The interface exported by this file consists of:
    168 // - class `Layout<>` and its public members.
    169 // - The public members of classes `internal_layout::LayoutWithStaticSizes<>`
    170 //   and `internal_layout::LayoutImpl<>`. Those classes aren't intended to be
    171 //   used directly, and their name and template parameter list are internal
    172 //   implementation details, but the classes themselves provide most of the
    173 //   functionality in this file. See comments on their members for detailed
    174 //   documentation.
    175 //
    176 // `Layout<T1,... Tn>::Partial(count1,..., countm)` (where `m` <= `n`) returns a
    177 // `LayoutImpl<>` object. `Layout<T1,..., Tn> layout(count1,..., countn)`
    178 // creates a `Layout` object, which exposes the same functionality by inheriting
    179 // from `LayoutImpl<>`.
    180 
    181 #ifndef ABSL_CONTAINER_INTERNAL_LAYOUT_H_
    182 #define ABSL_CONTAINER_INTERNAL_LAYOUT_H_
    183 
    184 #include <assert.h>
    185 #include <stddef.h>
    186 #include <stdint.h>
    187 
    188 #include <array>
    189 #include <string>
    190 #include <tuple>
    191 #include <type_traits>
    192 #include <typeinfo>
    193 #include <utility>
    194 
    195 #include "absl/base/config.h"
    196 #include "absl/debugging/internal/demangle.h"
    197 #include "absl/meta/type_traits.h"
    198 #include "absl/strings/str_cat.h"
    199 #include "absl/types/span.h"
    200 #include "absl/utility/utility.h"
    201 
    202 #ifdef ABSL_HAVE_ADDRESS_SANITIZER
    203 #include <sanitizer/asan_interface.h>
    204 #endif
    205 
    206 namespace absl {
    207 ABSL_NAMESPACE_BEGIN
    208 namespace container_internal {
    209 
    210 // A type wrapper that instructs `Layout` to use the specific alignment for the
    211 // array. `Layout<..., Aligned<T, N>, ...>` has exactly the same API
    212 // and behavior as `Layout<..., T, ...>` except that the first element of the
    213 // array of `T` is aligned to `N` (the rest of the elements follow without
    214 // padding).
    215 //
    216 // Requires: `N >= alignof(T)` and `N` is a power of 2.
    217 template <class T, size_t N>
    218 struct Aligned;
    219 
    220 namespace internal_layout {
    221 
    222 template <class T>
    223 struct NotAligned {};
    224 
    225 template <class T, size_t N>
    226 struct NotAligned<const Aligned<T, N>> {
    227  static_assert(sizeof(T) == 0, "Aligned<T, N> cannot be const-qualified");
    228 };
    229 
    230 template <size_t>
    231 using IntToSize = size_t;
    232 
    233 template <class T>
    234 struct Type : NotAligned<T> {
    235  using type = T;
    236 };
    237 
    238 template <class T, size_t N>
    239 struct Type<Aligned<T, N>> {
    240  using type = T;
    241 };
    242 
    243 template <class T>
    244 struct SizeOf : NotAligned<T>, std::integral_constant<size_t, sizeof(T)> {};
    245 
    246 template <class T, size_t N>
    247 struct SizeOf<Aligned<T, N>> : std::integral_constant<size_t, sizeof(T)> {};
    248 
    249 // Note: workaround for https://gcc.gnu.org/PR88115
    250 template <class T>
    251 struct AlignOf : NotAligned<T> {
    252  static constexpr size_t value = alignof(T);
    253 };
    254 
    255 template <class T, size_t N>
    256 struct AlignOf<Aligned<T, N>> {
    257  static_assert(N % alignof(T) == 0,
    258                "Custom alignment can't be lower than the type's alignment");
    259  static constexpr size_t value = N;
    260 };
    261 
    262 // Does `Ts...` contain `T`?
    263 template <class T, class... Ts>
    264 using Contains = absl::disjunction<std::is_same<T, Ts>...>;
    265 
    266 template <class From, class To>
    267 using CopyConst =
    268    typename std::conditional<std::is_const<From>::value, const To, To>::type;
    269 
    270 // Note: We're not qualifying this with absl:: because it doesn't compile under
    271 // MSVC.
    272 template <class T>
    273 using SliceType = Span<T>;
    274 
    275 // This namespace contains no types. It prevents functions defined in it from
    276 // being found by ADL.
    277 namespace adl_barrier {
    278 
    279 template <class Needle, class... Ts>
    280 constexpr size_t Find(Needle, Needle, Ts...) {
    281  static_assert(!Contains<Needle, Ts...>(), "Duplicate element type");
    282  return 0;
    283 }
    284 
    285 template <class Needle, class T, class... Ts>
    286 constexpr size_t Find(Needle, T, Ts...) {
    287  return adl_barrier::Find(Needle(), Ts()...) + 1;
    288 }
    289 
    290 constexpr bool IsPow2(size_t n) { return !(n & (n - 1)); }
    291 
    292 // Returns `q * m` for the smallest `q` such that `q * m >= n`.
    293 // Requires: `m` is a power of two. It's enforced by IsLegalElementType below.
    294 constexpr size_t Align(size_t n, size_t m) { return (n + m - 1) & ~(m - 1); }
    295 
    296 constexpr size_t Min(size_t a, size_t b) { return b < a ? b : a; }
    297 
    298 constexpr size_t Max(size_t a) { return a; }
    299 
    300 template <class... Ts>
    301 constexpr size_t Max(size_t a, size_t b, Ts... rest) {
    302  return adl_barrier::Max(b < a ? a : b, rest...);
    303 }
    304 
    305 template <class T>
    306 std::string TypeName() {
    307  std::string out;
    308 #ifdef ABSL_INTERNAL_HAS_RTTI
    309  absl::StrAppend(&out, "<",
    310                  absl::debugging_internal::DemangleString(typeid(T).name()),
    311                  ">");
    312 #endif
    313  return out;
    314 }
    315 
    316 }  // namespace adl_barrier
    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 StaticSizeSeq, class RuntimeSizeSeq,
    327          class SizeSeq, class OffsetSeq>
    328 class LayoutImpl;
    329 
    330 // Public base class of `Layout` and the result type of `Layout::Partial()`.
    331 //
    332 // `Elements...` contains all template arguments of `Layout` that created this
    333 // instance.
    334 //
    335 // `StaticSizeSeq...` is an index_sequence containing the sizes specified at
    336 // compile-time.
    337 //
    338 // `RuntimeSizeSeq...` is `[0, NumRuntimeSizes)`, where `NumRuntimeSizes` is the
    339 // number of arguments passed to `Layout::Partial()` or `Layout::Layout()`.
    340 //
    341 // `SizeSeq...` is `[0, NumSizes)` where `NumSizes` is `NumRuntimeSizes` plus
    342 // the number of sizes in `StaticSizeSeq`.
    343 //
    344 // `OffsetSeq...` is `[0, NumOffsets)` where `NumOffsets` is
    345 // `Min(sizeof...(Elements), NumSizes + 1)` (the number of arrays for which we
    346 // can compute offsets).
    347 template <class... Elements, size_t... StaticSizeSeq, size_t... RuntimeSizeSeq,
    348          size_t... SizeSeq, size_t... OffsetSeq>
    349 class LayoutImpl<
    350    std::tuple<Elements...>, absl::index_sequence<StaticSizeSeq...>,
    351    absl::index_sequence<RuntimeSizeSeq...>, absl::index_sequence<SizeSeq...>,
    352    absl::index_sequence<OffsetSeq...>> {
    353 private:
    354  static_assert(sizeof...(Elements) > 0, "At least one field is required");
    355  static_assert(absl::conjunction<IsLegalElementType<Elements>...>::value,
    356                "Invalid element type (see IsLegalElementType)");
    357  static_assert(sizeof...(StaticSizeSeq) <= sizeof...(Elements),
    358                "Too many static sizes specified");
    359 
    360  enum {
    361    NumTypes = sizeof...(Elements),
    362    NumStaticSizes = sizeof...(StaticSizeSeq),
    363    NumRuntimeSizes = sizeof...(RuntimeSizeSeq),
    364    NumSizes = sizeof...(SizeSeq),
    365    NumOffsets = sizeof...(OffsetSeq),
    366  };
    367 
    368  // These are guaranteed by `Layout`.
    369  static_assert(NumStaticSizes + NumRuntimeSizes == NumSizes, "Internal error");
    370  static_assert(NumSizes <= NumTypes, "Internal error");
    371  static_assert(NumOffsets == adl_barrier::Min(NumTypes, NumSizes + 1),
    372                "Internal error");
    373  static_assert(NumTypes > 0, "Internal error");
    374 
    375  static constexpr std::array<size_t, sizeof...(StaticSizeSeq)> kStaticSizes = {
    376      StaticSizeSeq...};
    377 
    378  // Returns the index of `T` in `Elements...`. Results in a compilation error
    379  // if `Elements...` doesn't contain exactly one instance of `T`.
    380  template <class T>
    381  static constexpr size_t ElementIndex() {
    382    static_assert(Contains<Type<T>, Type<typename Type<Elements>::type>...>(),
    383                  "Type not found");
    384    return adl_barrier::Find(Type<T>(),
    385                             Type<typename Type<Elements>::type>()...);
    386  }
    387 
    388  template <size_t N>
    389  using ElementAlignment =
    390      AlignOf<typename std::tuple_element<N, std::tuple<Elements...>>::type>;
    391 
    392 public:
    393  // Element types of all arrays packed in a tuple.
    394  using ElementTypes = std::tuple<typename Type<Elements>::type...>;
    395 
    396  // Element type of the Nth array.
    397  template <size_t N>
    398  using ElementType = typename std::tuple_element<N, ElementTypes>::type;
    399 
    400  constexpr explicit LayoutImpl(IntToSize<RuntimeSizeSeq>... sizes)
    401      : size_{sizes...} {}
    402 
    403  // Alignment of the layout, equal to the strictest alignment of all elements.
    404  // All pointers passed to the methods of layout must be aligned to this value.
    405  static constexpr size_t Alignment() {
    406    return adl_barrier::Max(AlignOf<Elements>::value...);
    407  }
    408 
    409  // Offset in bytes of the Nth array.
    410  //
    411  //   // int[3], 4 bytes of padding, double[4].
    412  //   Layout<int, double> x(3, 4);
    413  //   assert(x.Offset<0>() == 0);   // The ints starts from 0.
    414  //   assert(x.Offset<1>() == 16);  // The doubles starts from 16.
    415  //
    416  // Requires: `N <= NumSizes && N < sizeof...(Ts)`.
    417  template <size_t N>
    418  constexpr size_t Offset() const {
    419    if constexpr (N == 0) {
    420      return 0;
    421    } else {
    422      static_assert(N < NumOffsets, "Index out of bounds");
    423      return adl_barrier::Align(
    424          Offset<N - 1>() + SizeOf<ElementType<N - 1>>::value * Size<N - 1>(),
    425          ElementAlignment<N>::value);
    426    }
    427  }
    428 
    429  // Offset in bytes of the array with the specified element type. There must
    430  // be exactly one such array and its zero-based index must be at most
    431  // `NumSizes`.
    432  //
    433  //   // int[3], 4 bytes of padding, double[4].
    434  //   Layout<int, double> x(3, 4);
    435  //   assert(x.Offset<int>() == 0);      // The ints starts from 0.
    436  //   assert(x.Offset<double>() == 16);  // The doubles starts from 16.
    437  template <class T>
    438  constexpr size_t Offset() const {
    439    return Offset<ElementIndex<T>()>();
    440  }
    441 
    442  // Offsets in bytes of all arrays for which the offsets are known.
    443  constexpr std::array<size_t, NumOffsets> Offsets() const {
    444    return {{Offset<OffsetSeq>()...}};
    445  }
    446 
    447  // The number of elements in the Nth array (zero-based).
    448  //
    449  //   // int[3], 4 bytes of padding, double[4].
    450  //   Layout<int, double> x(3, 4);
    451  //   assert(x.Size<0>() == 3);
    452  //   assert(x.Size<1>() == 4);
    453  //
    454  // Requires: `N < NumSizes`.
    455  template <size_t N>
    456  constexpr size_t Size() const {
    457    if constexpr (N < NumStaticSizes) {
    458      return kStaticSizes[N];
    459    } else {
    460      static_assert(N < NumSizes, "Index out of bounds");
    461      return size_[N - NumStaticSizes];
    462    }
    463  }
    464 
    465  // The number of elements in the array with the specified element type.
    466  // There must be exactly one such array and its zero-based index must be
    467  // at most `NumSizes`.
    468  //
    469  //   // int[3], 4 bytes of padding, double[4].
    470  //   Layout<int, double> x(3, 4);
    471  //   assert(x.Size<int>() == 3);
    472  //   assert(x.Size<double>() == 4);
    473  template <class T>
    474  constexpr size_t Size() const {
    475    return Size<ElementIndex<T>()>();
    476  }
    477 
    478  // The number of elements of all arrays for which they are known.
    479  constexpr std::array<size_t, NumSizes> Sizes() const {
    480    return {{Size<SizeSeq>()...}};
    481  }
    482 
    483  // Pointer to the beginning of the Nth array.
    484  //
    485  // `Char` must be `[const] [signed|unsigned] char`.
    486  //
    487  //   // int[3], 4 bytes of padding, double[4].
    488  //   Layout<int, double> x(3, 4);
    489  //   unsigned char* p = new unsigned char[x.AllocSize()];
    490  //   int* ints = x.Pointer<0>(p);
    491  //   double* doubles = x.Pointer<1>(p);
    492  //
    493  // Requires: `N <= NumSizes && N < sizeof...(Ts)`.
    494  // Requires: `p` is aligned to `Alignment()`.
    495  template <size_t N, class Char>
    496  CopyConst<Char, ElementType<N>>* Pointer(Char* p) const {
    497    using C = typename std::remove_const<Char>::type;
    498    static_assert(
    499        std::is_same<C, char>() || std::is_same<C, unsigned char>() ||
    500            std::is_same<C, signed char>(),
    501        "The argument must be a pointer to [const] [signed|unsigned] char");
    502    constexpr size_t alignment = Alignment();
    503    (void)alignment;
    504    assert(reinterpret_cast<uintptr_t>(p) % alignment == 0);
    505    return reinterpret_cast<CopyConst<Char, ElementType<N>>*>(p + Offset<N>());
    506  }
    507 
    508  // Pointer to the beginning of the array with the specified element type.
    509  // There must be exactly one such array and its zero-based index must be at
    510  // most `NumSizes`.
    511  //
    512  // `Char` must be `[const] [signed|unsigned] char`.
    513  //
    514  //   // int[3], 4 bytes of padding, double[4].
    515  //   Layout<int, double> x(3, 4);
    516  //   unsigned char* p = new unsigned char[x.AllocSize()];
    517  //   int* ints = x.Pointer<int>(p);
    518  //   double* doubles = x.Pointer<double>(p);
    519  //
    520  // Requires: `p` is aligned to `Alignment()`.
    521  template <class T, class Char>
    522  CopyConst<Char, T>* Pointer(Char* p) const {
    523    return Pointer<ElementIndex<T>()>(p);
    524  }
    525 
    526  // Pointers to all arrays for which pointers are known.
    527  //
    528  // `Char` must be `[const] [signed|unsigned] char`.
    529  //
    530  //   // int[3], 4 bytes of padding, double[4].
    531  //   Layout<int, double> x(3, 4);
    532  //   unsigned char* p = new unsigned char[x.AllocSize()];
    533  //
    534  //   int* ints;
    535  //   double* doubles;
    536  //   std::tie(ints, doubles) = x.Pointers(p);
    537  //
    538  // Requires: `p` is aligned to `Alignment()`.
    539  template <class Char>
    540  auto Pointers(Char* p) const {
    541    return std::tuple<CopyConst<Char, ElementType<OffsetSeq>>*...>(
    542        Pointer<OffsetSeq>(p)...);
    543  }
    544 
    545  // The Nth array.
    546  //
    547  // `Char` must be `[const] [signed|unsigned] char`.
    548  //
    549  //   // int[3], 4 bytes of padding, double[4].
    550  //   Layout<int, double> x(3, 4);
    551  //   unsigned char* p = new unsigned char[x.AllocSize()];
    552  //   Span<int> ints = x.Slice<0>(p);
    553  //   Span<double> doubles = x.Slice<1>(p);
    554  //
    555  // Requires: `N < NumSizes`.
    556  // Requires: `p` is aligned to `Alignment()`.
    557  template <size_t N, class Char>
    558  SliceType<CopyConst<Char, ElementType<N>>> Slice(Char* p) const {
    559    return SliceType<CopyConst<Char, ElementType<N>>>(Pointer<N>(p), Size<N>());
    560  }
    561 
    562  // The array with the specified element type. There must be exactly one
    563  // such array and its zero-based index must be less than `NumSizes`.
    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  //   Span<int> ints = x.Slice<int>(p);
    571  //   Span<double> doubles = x.Slice<double>(p);
    572  //
    573  // Requires: `p` is aligned to `Alignment()`.
    574  template <class T, class Char>
    575  SliceType<CopyConst<Char, T>> Slice(Char* p) const {
    576    return Slice<ElementIndex<T>()>(p);
    577  }
    578 
    579  // All arrays with known sizes.
    580  //
    581  // `Char` must be `[const] [signed|unsigned] char`.
    582  //
    583  //   // int[3], 4 bytes of padding, double[4].
    584  //   Layout<int, double> x(3, 4);
    585  //   unsigned char* p = new unsigned char[x.AllocSize()];
    586  //
    587  //   Span<int> ints;
    588  //   Span<double> doubles;
    589  //   std::tie(ints, doubles) = x.Slices(p);
    590  //
    591  // Requires: `p` is aligned to `Alignment()`.
    592  //
    593  // Note: We mark the parameter as maybe_unused because GCC detects it is not
    594  // used when `SizeSeq` is empty [-Werror=unused-but-set-parameter].
    595  template <class Char>
    596  auto Slices([[maybe_unused]] Char* p) const {
    597    return std::tuple<SliceType<CopyConst<Char, ElementType<SizeSeq>>>...>(
    598        Slice<SizeSeq>(p)...);
    599  }
    600 
    601  // The size of the allocation that fits all arrays.
    602  //
    603  //   // int[3], 4 bytes of padding, double[4].
    604  //   Layout<int, double> x(3, 4);
    605  //   unsigned char* p = new unsigned char[x.AllocSize()];  // 48 bytes
    606  //
    607  // Requires: `NumSizes == sizeof...(Ts)`.
    608  constexpr size_t AllocSize() const {
    609    static_assert(NumTypes == NumSizes, "You must specify sizes of all fields");
    610    return Offset<NumTypes - 1>() +
    611           SizeOf<ElementType<NumTypes - 1>>::value * Size<NumTypes - 1>();
    612  }
    613 
    614  // If built with --config=asan, poisons padding bytes (if any) in the
    615  // allocation. The pointer must point to a memory block at least
    616  // `AllocSize()` bytes in length.
    617  //
    618  // `Char` must be `[const] [signed|unsigned] char`.
    619  //
    620  // Requires: `p` is aligned to `Alignment()`.
    621  template <class Char, size_t N = NumOffsets - 1>
    622  void PoisonPadding(const Char* p) const {
    623    if constexpr (N == 0) {
    624      Pointer<0>(p);  // verify the requirements on `Char` and `p`
    625    } else {
    626      static_assert(N < NumOffsets, "Index out of bounds");
    627      (void)p;
    628 #ifdef ABSL_HAVE_ADDRESS_SANITIZER
    629    PoisonPadding<Char, N - 1>(p);
    630    // The `if` is an optimization. It doesn't affect the observable behaviour.
    631    if (ElementAlignment<N - 1>::value % ElementAlignment<N>::value) {
    632      size_t start =
    633          Offset<N - 1>() + SizeOf<ElementType<N - 1>>::value * Size<N - 1>();
    634      ASAN_POISON_MEMORY_REGION(p + start, Offset<N>() - start);
    635    }
    636 #endif
    637    }
    638  }
    639 
    640  // Human-readable description of the memory layout. Useful for debugging.
    641  // Slow.
    642  //
    643  //   // char[5], 3 bytes of padding, int[3], 4 bytes of padding, followed
    644  //   // by an unknown number of doubles.
    645  //   auto x = Layout<char, int, double>::Partial(5, 3);
    646  //   assert(x.DebugString() ==
    647  //          "@0<char>(1)[5]; @8<int>(4)[3]; @24<double>(8)");
    648  //
    649  // Each field is in the following format: @offset<type>(sizeof)[size] (<type>
    650  // may be missing depending on the target platform). For example,
    651  // @8<int>(4)[3] means that at offset 8 we have an array of ints, where each
    652  // int is 4 bytes, and we have 3 of those ints. The size of the last field may
    653  // be missing (as in the example above). Only fields with known offsets are
    654  // described. Type names may differ across platforms: one compiler might
    655  // produce "unsigned*" where another produces "unsigned int *".
    656  std::string DebugString() const {
    657    const auto offsets = Offsets();
    658    const size_t sizes[] = {SizeOf<ElementType<OffsetSeq>>::value...};
    659    const std::string types[] = {
    660        adl_barrier::TypeName<ElementType<OffsetSeq>>()...};
    661    std::string res = absl::StrCat("@0", types[0], "(", sizes[0], ")");
    662    for (size_t i = 0; i != NumOffsets - 1; ++i) {
    663      absl::StrAppend(&res, "[", DebugSize(i), "]; @", offsets[i + 1],
    664                      types[i + 1], "(", sizes[i + 1], ")");
    665    }
    666    // NumSizes is a constant that may be zero. Some compilers cannot see that
    667    // inside the if statement "size_[NumSizes - 1]" must be valid.
    668    int last = static_cast<int>(NumSizes) - 1;
    669    if (NumTypes == NumSizes && last >= 0) {
    670      absl::StrAppend(&res, "[", DebugSize(static_cast<size_t>(last)), "]");
    671    }
    672    return res;
    673  }
    674 
    675 private:
    676  size_t DebugSize(size_t n) const {
    677    if (n < NumStaticSizes) {
    678      return kStaticSizes[n];
    679    } else {
    680      return size_[n - NumStaticSizes];
    681    }
    682  }
    683 
    684  // Arguments of `Layout::Partial()` or `Layout::Layout()`.
    685  size_t size_[NumRuntimeSizes > 0 ? NumRuntimeSizes : 1];
    686 };
    687 
    688 template <class StaticSizeSeq, size_t NumRuntimeSizes, class... Ts>
    689 using LayoutType = LayoutImpl<
    690    std::tuple<Ts...>, StaticSizeSeq,
    691    absl::make_index_sequence<NumRuntimeSizes>,
    692    absl::make_index_sequence<NumRuntimeSizes + StaticSizeSeq::size()>,
    693    absl::make_index_sequence<adl_barrier::Min(
    694        sizeof...(Ts), NumRuntimeSizes + StaticSizeSeq::size() + 1)>>;
    695 
    696 template <class StaticSizeSeq, class... Ts>
    697 class LayoutWithStaticSizes
    698    : public LayoutType<StaticSizeSeq,
    699                        sizeof...(Ts) - adl_barrier::Min(sizeof...(Ts),
    700                                                         StaticSizeSeq::size()),
    701                        Ts...> {
    702 private:
    703  using Super =
    704      LayoutType<StaticSizeSeq,
    705                 sizeof...(Ts) -
    706                     adl_barrier::Min(sizeof...(Ts), StaticSizeSeq::size()),
    707                 Ts...>;
    708 
    709 public:
    710  // The result type of `Partial()` with `NumSizes` arguments.
    711  template <size_t NumSizes>
    712  using PartialType =
    713      internal_layout::LayoutType<StaticSizeSeq, NumSizes, Ts...>;
    714 
    715  // `Layout` knows the element types of the arrays we want to lay out in
    716  // memory but not the number of elements in each array.
    717  // `Partial(size1, ..., sizeN)` allows us to specify the latter. The
    718  // resulting immutable object can be used to obtain pointers to the
    719  // individual arrays.
    720  //
    721  // It's allowed to pass fewer array sizes than the number of arrays. E.g.,
    722  // if all you need is to the offset of the second array, you only need to
    723  // pass one argument -- the number of elements in the first array.
    724  //
    725  //   // int[3] followed by 4 bytes of padding and an unknown number of
    726  //   // doubles.
    727  //   auto x = Layout<int, double>::Partial(3);
    728  //   // doubles start at byte 16.
    729  //   assert(x.Offset<1>() == 16);
    730  //
    731  // If you know the number of elements in all arrays, you can still call
    732  // `Partial()` but it's more convenient to use the constructor of `Layout`.
    733  //
    734  //   Layout<int, double> x(3, 5);
    735  //
    736  // Note: The sizes of the arrays must be specified in number of elements,
    737  // not in bytes.
    738  //
    739  // Requires: `sizeof...(Sizes) + NumStaticSizes <= sizeof...(Ts)`.
    740  // Requires: all arguments are convertible to `size_t`.
    741  template <class... Sizes>
    742  static constexpr PartialType<sizeof...(Sizes)> Partial(Sizes&&... sizes) {
    743    static_assert(sizeof...(Sizes) + StaticSizeSeq::size() <= sizeof...(Ts),
    744                  "");
    745    return PartialType<sizeof...(Sizes)>(
    746        static_cast<size_t>(std::forward<Sizes>(sizes))...);
    747  }
    748 
    749  // Inherit LayoutType's constructor.
    750  //
    751  // Creates a layout with the sizes of all arrays specified. If you know
    752  // only the sizes of the first N arrays (where N can be zero), you can use
    753  // `Partial()` defined above. The constructor is essentially equivalent to
    754  // calling `Partial()` and passing in all array sizes; the constructor is
    755  // provided as a convenient abbreviation.
    756  //
    757  // Note: The sizes of the arrays must be specified in number of elements,
    758  // not in bytes.
    759  //
    760  // Implementation note: we do this via a `using` declaration instead of
    761  // defining our own explicit constructor because the signature of LayoutType's
    762  // constructor depends on RuntimeSizeSeq, which we don't have access to here.
    763  // If we defined our own constructor here, it would have to use a parameter
    764  // pack and then cast the arguments to size_t when calling the superclass
    765  // constructor, similar to what Partial() does. But that would suffer from the
    766  // same problem that Partial() has, which is that the parameter types are
    767  // inferred from the arguments, which may be signed types, which must then be
    768  // cast to size_t. This can lead to negative values being silently (i.e. with
    769  // no compiler warnings) cast to an unsigned type. Having a constructor with
    770  // size_t parameters helps the compiler generate better warnings about
    771  // potential bad casts, while avoiding false warnings when positive literal
    772  // arguments are used. If an argument is a positive literal integer (e.g.
    773  // `1`), the compiler will understand that it can be safely converted to
    774  // size_t, and hence not generate a warning. But if a negative literal (e.g.
    775  // `-1`) or a variable with signed type is used, then it can generate a
    776  // warning about a potentially unsafe implicit cast. It would be great if we
    777  // could do this for Partial() too, but unfortunately as of C++23 there seems
    778  // to be no way to define a function with a variable number of parameters of a
    779  // certain type, a.k.a. homogeneous function parameter packs. So we're forced
    780  // to choose between explicitly casting the arguments to size_t, which
    781  // suppresses all warnings, even potentially valid ones, or implicitly casting
    782  // them to size_t, which generates bogus warnings whenever literal arguments
    783  // are used, even if they're positive.
    784  using Super::Super;
    785 };
    786 
    787 }  // namespace internal_layout
    788 
    789 // Descriptor of arrays of various types and sizes laid out in memory one after
    790 // another. See the top of the file for documentation.
    791 //
    792 // Check out the public API of internal_layout::LayoutWithStaticSizes and
    793 // internal_layout::LayoutImpl above. Those types are internal to the library
    794 // but their methods are public, and they are inherited by `Layout`.
    795 template <class... Ts>
    796 class Layout : public internal_layout::LayoutWithStaticSizes<
    797                   absl::make_index_sequence<0>, Ts...> {
    798 private:
    799  using Super =
    800      internal_layout::LayoutWithStaticSizes<absl::make_index_sequence<0>,
    801                                             Ts...>;
    802 
    803 public:
    804  // If you know the sizes of some or all of the arrays at compile time, you can
    805  // use `WithStaticSizes` or `WithStaticSizeSequence` to create a `Layout` type
    806  // with those sizes baked in. This can help the compiler generate optimal code
    807  // for calculating array offsets and AllocSize().
    808  //
    809  // Like `Partial()`, the N sizes you specify are for the first N arrays, and
    810  // they specify the number of elements in each array, not the number of bytes.
    811  template <class StaticSizeSeq>
    812  using WithStaticSizeSequence =
    813      internal_layout::LayoutWithStaticSizes<StaticSizeSeq, Ts...>;
    814 
    815  template <size_t... StaticSizes>
    816  using WithStaticSizes =
    817      WithStaticSizeSequence<std::index_sequence<StaticSizes...>>;
    818 
    819  // Inherit LayoutWithStaticSizes's constructor, which requires you to specify
    820  // all the array sizes.
    821  using Super::Super;
    822 };
    823 
    824 }  // namespace container_internal
    825 ABSL_NAMESPACE_END
    826 }  // namespace absl
    827 
    828 #endif  // ABSL_CONTAINER_INTERNAL_LAYOUT_H_