Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:27:12

0001 // Copyright 2018 The Abseil Authors.
0002 //
0003 // Licensed under the Apache License, Version 2.0 (the "License");
0004 // you may not use this file except in compliance with the License.
0005 // You may obtain a copy of the License at
0006 //
0007 //      https://www.apache.org/licenses/LICENSE-2.0
0008 //
0009 // Unless required by applicable law or agreed to in writing, software
0010 // distributed under the License is distributed on an "AS IS" BASIS,
0011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0012 // See the License for the specific language governing permissions and
0013 // limitations under the License.
0014 //
0015 //                           MOTIVATION AND TUTORIAL
0016 //
0017 // If you want to put in a single heap allocation N doubles followed by M ints,
0018 // it's easy if N and M are known at compile time.
0019 //
0020 //   struct S {
0021 //     double a[N];
0022 //     int b[M];
0023 //   };
0024 //
0025 //   S* p = new S;
0026 //
0027 // But what if N and M are known only in run time? Class template Layout to the
0028 // rescue! It's a portable generalization of the technique known as struct hack.
0029 //
0030 //   // This object will tell us everything we need to know about the memory
0031 //   // layout of double[N] followed by int[M]. It's structurally identical to
0032 //   // size_t[2] that stores N and M. It's very cheap to create.
0033 //   const Layout<double, int> layout(N, M);
0034 //
0035 //   // Allocate enough memory for both arrays. `AllocSize()` tells us how much
0036 //   // memory is needed. We are free to use any allocation function we want as
0037 //   // long as it returns aligned memory.
0038 //   std::unique_ptr<unsigned char[]> p(new unsigned char[layout.AllocSize()]);
0039 //
0040 //   // Obtain the pointer to the array of doubles.
0041 //   // Equivalent to `reinterpret_cast<double*>(p.get())`.
0042 //   //
0043 //   // We could have written layout.Pointer<0>(p) instead. If all the types are
0044 //   // unique you can use either form, but if some types are repeated you must
0045 //   // use the index form.
0046 //   double* a = layout.Pointer<double>(p.get());
0047 //
0048 //   // Obtain the pointer to the array of ints.
0049 //   // Equivalent to `reinterpret_cast<int*>(p.get() + N * 8)`.
0050 //   int* b = layout.Pointer<int>(p);
0051 //
0052 // If we are unable to specify sizes of all fields, we can pass as many sizes as
0053 // we can to `Partial()`. In return, it'll allow us to access the fields whose
0054 // locations and sizes can be computed from the provided information.
0055 // `Partial()` comes in handy when the array sizes are embedded into the
0056 // allocation.
0057 //
0058 //   // size_t[0] containing N, size_t[1] containing M, double[N], int[M].
0059 //   using L = Layout<size_t, size_t, double, int>;
0060 //
0061 //   unsigned char* Allocate(size_t n, size_t m) {
0062 //     const L layout(1, 1, n, m);
0063 //     unsigned char* p = new unsigned char[layout.AllocSize()];
0064 //     *layout.Pointer<0>(p) = n;
0065 //     *layout.Pointer<1>(p) = m;
0066 //     return p;
0067 //   }
0068 //
0069 //   void Use(unsigned char* p) {
0070 //     // First, extract N and M.
0071 //     // Specify that the first array has only one element. Using `prefix` we
0072 //     // can access the first two arrays but not more.
0073 //     constexpr auto prefix = L::Partial(1);
0074 //     size_t n = *prefix.Pointer<0>(p);
0075 //     size_t m = *prefix.Pointer<1>(p);
0076 //
0077 //     // Now we can get pointers to the payload.
0078 //     const L layout(1, 1, n, m);
0079 //     double* a = layout.Pointer<double>(p);
0080 //     int* b = layout.Pointer<int>(p);
0081 //   }
0082 //
0083 // The layout we used above combines fixed-size with dynamically-sized fields.
0084 // This is quite common. Layout is optimized for this use case and attempts to
0085 // generate optimal code. To help the compiler do that in more cases, you can
0086 // specify the fixed sizes using `WithStaticSizes`. This ensures that all
0087 // computations that can be performed at compile time are indeed performed at
0088 // compile time. Note that sometimes the `template` keyword is needed. E.g.:
0089 //
0090 //   using SL = L::template WithStaticSizes<1, 1>;
0091 //
0092 //   void Use(unsigned char* p) {
0093 //     // First, extract N and M.
0094 //     // Using `prefix` we can access the first three arrays but not more.
0095 //     //
0096 //     // More details: The first element always has offset 0. `SL`
0097 //     // has offsets for the second and third array based on sizes of
0098 //     // the first and second array, specified via `WithStaticSizes`.
0099 //     constexpr auto prefix = SL::Partial();
0100 //     size_t n = *prefix.Pointer<0>(p);
0101 //     size_t m = *prefix.Pointer<1>(p);
0102 //
0103 //     // Now we can get a pointer to the final payload.
0104 //     const SL layout(n, m);
0105 //     double* a = layout.Pointer<double>(p);
0106 //     int* b = layout.Pointer<int>(p);
0107 //   }
0108 //
0109 // Efficiency tip: The order of fields matters. In `Layout<T1, ..., TN>` try to
0110 // ensure that `alignof(T1) >= ... >= alignof(TN)`. This way you'll have no
0111 // padding in between arrays.
0112 //
0113 // You can manually override the alignment of an array by wrapping the type in
0114 // `Aligned<T, N>`. `Layout<..., Aligned<T, N>, ...>` has exactly the same API
0115 // and behavior as `Layout<..., T, ...>` except that the first element of the
0116 // array of `T` is aligned to `N` (the rest of the elements follow without
0117 // padding). `N` cannot be less than `alignof(T)`.
0118 //
0119 // `AllocSize()` and `Pointer()` are the most basic methods for dealing with
0120 // memory layouts. Check out the reference or code below to discover more.
0121 //
0122 //                            EXAMPLE
0123 //
0124 //   // Immutable move-only string with sizeof equal to sizeof(void*). The
0125 //   // string size and the characters are kept in the same heap allocation.
0126 //   class CompactString {
0127 //    public:
0128 //     CompactString(const char* s = "") {
0129 //       const size_t size = strlen(s);
0130 //       // size_t[1] followed by char[size + 1].
0131 //       const L layout(size + 1);
0132 //       p_.reset(new unsigned char[layout.AllocSize()]);
0133 //       // If running under ASAN, mark the padding bytes, if any, to catch
0134 //       // memory errors.
0135 //       layout.PoisonPadding(p_.get());
0136 //       // Store the size in the allocation.
0137 //       *layout.Pointer<size_t>(p_.get()) = size;
0138 //       // Store the characters in the allocation.
0139 //       memcpy(layout.Pointer<char>(p_.get()), s, size + 1);
0140 //     }
0141 //
0142 //     size_t size() const {
0143 //       // Equivalent to reinterpret_cast<size_t&>(*p).
0144 //       return *L::Partial().Pointer<size_t>(p_.get());
0145 //     }
0146 //
0147 //     const char* c_str() const {
0148 //       // Equivalent to reinterpret_cast<char*>(p.get() + sizeof(size_t)).
0149 //       return L::Partial().Pointer<char>(p_.get());
0150 //     }
0151 //
0152 //    private:
0153 //     // Our heap allocation contains a single size_t followed by an array of
0154 //     // chars.
0155 //     using L = Layout<size_t, char>::WithStaticSizes<1>;
0156 //     std::unique_ptr<unsigned char[]> p_;
0157 //   };
0158 //
0159 //   int main() {
0160 //     CompactString s = "hello";
0161 //     assert(s.size() == 5);
0162 //     assert(strcmp(s.c_str(), "hello") == 0);
0163 //   }
0164 //
0165 //                               DOCUMENTATION
0166 //
0167 // The interface exported by this file consists of:
0168 // - class `Layout<>` and its public members.
0169 // - The public members of classes `internal_layout::LayoutWithStaticSizes<>`
0170 //   and `internal_layout::LayoutImpl<>`. Those classes aren't intended to be
0171 //   used directly, and their name and template parameter list are internal
0172 //   implementation details, but the classes themselves provide most of the
0173 //   functionality in this file. See comments on their members for detailed
0174 //   documentation.
0175 //
0176 // `Layout<T1,... Tn>::Partial(count1,..., countm)` (where `m` <= `n`) returns a
0177 // `LayoutImpl<>` object. `Layout<T1,..., Tn> layout(count1,..., countn)`
0178 // creates a `Layout` object, which exposes the same functionality by inheriting
0179 // from `LayoutImpl<>`.
0180 
0181 #ifndef ABSL_CONTAINER_INTERNAL_LAYOUT_H_
0182 #define ABSL_CONTAINER_INTERNAL_LAYOUT_H_
0183 
0184 #include <assert.h>
0185 #include <stddef.h>
0186 #include <stdint.h>
0187 
0188 #include <array>
0189 #include <string>
0190 #include <tuple>
0191 #include <type_traits>
0192 #include <typeinfo>
0193 #include <utility>
0194 
0195 #include "absl/base/attributes.h"
0196 #include "absl/base/config.h"
0197 #include "absl/debugging/internal/demangle.h"
0198 #include "absl/meta/type_traits.h"
0199 #include "absl/strings/str_cat.h"
0200 #include "absl/types/span.h"
0201 #include "absl/utility/utility.h"
0202 
0203 #ifdef ABSL_HAVE_ADDRESS_SANITIZER
0204 #include <sanitizer/asan_interface.h>
0205 #endif
0206 
0207 namespace absl {
0208 ABSL_NAMESPACE_BEGIN
0209 namespace container_internal {
0210 
0211 // A type wrapper that instructs `Layout` to use the specific alignment for the
0212 // array. `Layout<..., Aligned<T, N>, ...>` has exactly the same API
0213 // and behavior as `Layout<..., T, ...>` except that the first element of the
0214 // array of `T` is aligned to `N` (the rest of the elements follow without
0215 // padding).
0216 //
0217 // Requires: `N >= alignof(T)` and `N` is a power of 2.
0218 template <class T, size_t N>
0219 struct Aligned;
0220 
0221 namespace internal_layout {
0222 
0223 template <class T>
0224 struct NotAligned {};
0225 
0226 template <class T, size_t N>
0227 struct NotAligned<const Aligned<T, N>> {
0228   static_assert(sizeof(T) == 0, "Aligned<T, N> cannot be const-qualified");
0229 };
0230 
0231 template <size_t>
0232 using IntToSize = size_t;
0233 
0234 template <class T>
0235 struct Type : NotAligned<T> {
0236   using type = T;
0237 };
0238 
0239 template <class T, size_t N>
0240 struct Type<Aligned<T, N>> {
0241   using type = T;
0242 };
0243 
0244 template <class T>
0245 struct SizeOf : NotAligned<T>, std::integral_constant<size_t, sizeof(T)> {};
0246 
0247 template <class T, size_t N>
0248 struct SizeOf<Aligned<T, N>> : std::integral_constant<size_t, sizeof(T)> {};
0249 
0250 // Note: workaround for https://gcc.gnu.org/PR88115
0251 template <class T>
0252 struct AlignOf : NotAligned<T> {
0253   static constexpr size_t value = alignof(T);
0254 };
0255 
0256 template <class T, size_t N>
0257 struct AlignOf<Aligned<T, N>> {
0258   static_assert(N % alignof(T) == 0,
0259                 "Custom alignment can't be lower than the type's alignment");
0260   static constexpr size_t value = N;
0261 };
0262 
0263 // Does `Ts...` contain `T`?
0264 template <class T, class... Ts>
0265 using Contains = absl::disjunction<std::is_same<T, Ts>...>;
0266 
0267 template <class From, class To>
0268 using CopyConst =
0269     typename std::conditional<std::is_const<From>::value, const To, To>::type;
0270 
0271 // Note: We're not qualifying this with absl:: because it doesn't compile under
0272 // MSVC.
0273 template <class T>
0274 using SliceType = Span<T>;
0275 
0276 // This namespace contains no types. It prevents functions defined in it from
0277 // being found by ADL.
0278 namespace adl_barrier {
0279 
0280 template <class Needle, class... Ts>
0281 constexpr size_t Find(Needle, Needle, Ts...) {
0282   static_assert(!Contains<Needle, Ts...>(), "Duplicate element type");
0283   return 0;
0284 }
0285 
0286 template <class Needle, class T, class... Ts>
0287 constexpr size_t Find(Needle, T, Ts...) {
0288   return adl_barrier::Find(Needle(), Ts()...) + 1;
0289 }
0290 
0291 constexpr bool IsPow2(size_t n) { return !(n & (n - 1)); }
0292 
0293 // Returns `q * m` for the smallest `q` such that `q * m >= n`.
0294 // Requires: `m` is a power of two. It's enforced by IsLegalElementType below.
0295 constexpr size_t Align(size_t n, size_t m) { return (n + m - 1) & ~(m - 1); }
0296 
0297 constexpr size_t Min(size_t a, size_t b) { return b < a ? b : a; }
0298 
0299 constexpr size_t Max(size_t a) { return a; }
0300 
0301 template <class... Ts>
0302 constexpr size_t Max(size_t a, size_t b, Ts... rest) {
0303   return adl_barrier::Max(b < a ? a : b, rest...);
0304 }
0305 
0306 template <class T>
0307 std::string TypeName() {
0308   std::string out;
0309 #if ABSL_INTERNAL_HAS_RTTI
0310   absl::StrAppend(&out, "<",
0311                   absl::debugging_internal::DemangleString(typeid(T).name()),
0312                   ">");
0313 #endif
0314   return out;
0315 }
0316 
0317 }  // namespace adl_barrier
0318 
0319 template <bool C>
0320 using EnableIf = typename std::enable_if<C, int>::type;
0321 
0322 // Can `T` be a template argument of `Layout`?
0323 template <class T>
0324 using IsLegalElementType = std::integral_constant<
0325     bool, !std::is_reference<T>::value && !std::is_volatile<T>::value &&
0326               !std::is_reference<typename Type<T>::type>::value &&
0327               !std::is_volatile<typename Type<T>::type>::value &&
0328               adl_barrier::IsPow2(AlignOf<T>::value)>;
0329 
0330 template <class Elements, class StaticSizeSeq, class RuntimeSizeSeq,
0331           class SizeSeq, class OffsetSeq>
0332 class LayoutImpl;
0333 
0334 // Public base class of `Layout` and the result type of `Layout::Partial()`.
0335 //
0336 // `Elements...` contains all template arguments of `Layout` that created this
0337 // instance.
0338 //
0339 // `StaticSizeSeq...` is an index_sequence containing the sizes specified at
0340 // compile-time.
0341 //
0342 // `RuntimeSizeSeq...` is `[0, NumRuntimeSizes)`, where `NumRuntimeSizes` is the
0343 // number of arguments passed to `Layout::Partial()` or `Layout::Layout()`.
0344 //
0345 // `SizeSeq...` is `[0, NumSizes)` where `NumSizes` is `NumRuntimeSizes` plus
0346 // the number of sizes in `StaticSizeSeq`.
0347 //
0348 // `OffsetSeq...` is `[0, NumOffsets)` where `NumOffsets` is
0349 // `Min(sizeof...(Elements), NumSizes + 1)` (the number of arrays for which we
0350 // can compute offsets).
0351 template <class... Elements, size_t... StaticSizeSeq, size_t... RuntimeSizeSeq,
0352           size_t... SizeSeq, size_t... OffsetSeq>
0353 class LayoutImpl<
0354     std::tuple<Elements...>, absl::index_sequence<StaticSizeSeq...>,
0355     absl::index_sequence<RuntimeSizeSeq...>, absl::index_sequence<SizeSeq...>,
0356     absl::index_sequence<OffsetSeq...>> {
0357  private:
0358   static_assert(sizeof...(Elements) > 0, "At least one field is required");
0359   static_assert(absl::conjunction<IsLegalElementType<Elements>...>::value,
0360                 "Invalid element type (see IsLegalElementType)");
0361   static_assert(sizeof...(StaticSizeSeq) <= sizeof...(Elements),
0362                 "Too many static sizes specified");
0363 
0364   enum {
0365     NumTypes = sizeof...(Elements),
0366     NumStaticSizes = sizeof...(StaticSizeSeq),
0367     NumRuntimeSizes = sizeof...(RuntimeSizeSeq),
0368     NumSizes = sizeof...(SizeSeq),
0369     NumOffsets = sizeof...(OffsetSeq),
0370   };
0371 
0372   // These are guaranteed by `Layout`.
0373   static_assert(NumStaticSizes + NumRuntimeSizes == NumSizes, "Internal error");
0374   static_assert(NumSizes <= NumTypes, "Internal error");
0375   static_assert(NumOffsets == adl_barrier::Min(NumTypes, NumSizes + 1),
0376                 "Internal error");
0377   static_assert(NumTypes > 0, "Internal error");
0378 
0379   static constexpr std::array<size_t, sizeof...(StaticSizeSeq)> kStaticSizes = {
0380       StaticSizeSeq...};
0381 
0382   // Returns the index of `T` in `Elements...`. Results in a compilation error
0383   // if `Elements...` doesn't contain exactly one instance of `T`.
0384   template <class T>
0385   static constexpr size_t ElementIndex() {
0386     static_assert(Contains<Type<T>, Type<typename Type<Elements>::type>...>(),
0387                   "Type not found");
0388     return adl_barrier::Find(Type<T>(),
0389                              Type<typename Type<Elements>::type>()...);
0390   }
0391 
0392   template <size_t N>
0393   using ElementAlignment =
0394       AlignOf<typename std::tuple_element<N, std::tuple<Elements...>>::type>;
0395 
0396  public:
0397   // Element types of all arrays packed in a tuple.
0398   using ElementTypes = std::tuple<typename Type<Elements>::type...>;
0399 
0400   // Element type of the Nth array.
0401   template <size_t N>
0402   using ElementType = typename std::tuple_element<N, ElementTypes>::type;
0403 
0404   constexpr explicit LayoutImpl(IntToSize<RuntimeSizeSeq>... sizes)
0405       : size_{sizes...} {}
0406 
0407   // Alignment of the layout, equal to the strictest alignment of all elements.
0408   // All pointers passed to the methods of layout must be aligned to this value.
0409   static constexpr size_t Alignment() {
0410     return adl_barrier::Max(AlignOf<Elements>::value...);
0411   }
0412 
0413   // Offset in bytes of the Nth array.
0414   //
0415   //   // int[3], 4 bytes of padding, double[4].
0416   //   Layout<int, double> x(3, 4);
0417   //   assert(x.Offset<0>() == 0);   // The ints starts from 0.
0418   //   assert(x.Offset<1>() == 16);  // The doubles starts from 16.
0419   //
0420   // Requires: `N <= NumSizes && N < sizeof...(Ts)`.
0421   template <size_t N, EnableIf<N == 0> = 0>
0422   constexpr size_t Offset() const {
0423     return 0;
0424   }
0425 
0426   template <size_t N, EnableIf<N != 0> = 0>
0427   constexpr size_t Offset() const {
0428     static_assert(N < NumOffsets, "Index out of bounds");
0429     return adl_barrier::Align(
0430         Offset<N - 1>() + SizeOf<ElementType<N - 1>>::value * Size<N - 1>(),
0431         ElementAlignment<N>::value);
0432   }
0433 
0434   // Offset in bytes of the array with the specified element type. There must
0435   // be exactly one such array and its zero-based index must be at most
0436   // `NumSizes`.
0437   //
0438   //   // int[3], 4 bytes of padding, double[4].
0439   //   Layout<int, double> x(3, 4);
0440   //   assert(x.Offset<int>() == 0);      // The ints starts from 0.
0441   //   assert(x.Offset<double>() == 16);  // The doubles starts from 16.
0442   template <class T>
0443   constexpr size_t Offset() const {
0444     return Offset<ElementIndex<T>()>();
0445   }
0446 
0447   // Offsets in bytes of all arrays for which the offsets are known.
0448   constexpr std::array<size_t, NumOffsets> Offsets() const {
0449     return {{Offset<OffsetSeq>()...}};
0450   }
0451 
0452   // The number of elements in the Nth array (zero-based).
0453   //
0454   //   // int[3], 4 bytes of padding, double[4].
0455   //   Layout<int, double> x(3, 4);
0456   //   assert(x.Size<0>() == 3);
0457   //   assert(x.Size<1>() == 4);
0458   //
0459   // Requires: `N < NumSizes`.
0460   template <size_t N, EnableIf<(N < NumStaticSizes)> = 0>
0461   constexpr size_t Size() const {
0462     return kStaticSizes[N];
0463   }
0464 
0465   template <size_t N, EnableIf<(N >= NumStaticSizes)> = 0>
0466   constexpr size_t Size() const {
0467     static_assert(N < NumSizes, "Index out of bounds");
0468     return size_[N - NumStaticSizes];
0469   }
0470 
0471   // The number of elements in the array with the specified element type.
0472   // There must be exactly one such array and its zero-based index must be
0473   // at most `NumSizes`.
0474   //
0475   //   // int[3], 4 bytes of padding, double[4].
0476   //   Layout<int, double> x(3, 4);
0477   //   assert(x.Size<int>() == 3);
0478   //   assert(x.Size<double>() == 4);
0479   template <class T>
0480   constexpr size_t Size() const {
0481     return Size<ElementIndex<T>()>();
0482   }
0483 
0484   // The number of elements of all arrays for which they are known.
0485   constexpr std::array<size_t, NumSizes> Sizes() const {
0486     return {{Size<SizeSeq>()...}};
0487   }
0488 
0489   // Pointer to the beginning of the Nth array.
0490   //
0491   // `Char` must be `[const] [signed|unsigned] char`.
0492   //
0493   //   // int[3], 4 bytes of padding, double[4].
0494   //   Layout<int, double> x(3, 4);
0495   //   unsigned char* p = new unsigned char[x.AllocSize()];
0496   //   int* ints = x.Pointer<0>(p);
0497   //   double* doubles = x.Pointer<1>(p);
0498   //
0499   // Requires: `N <= NumSizes && N < sizeof...(Ts)`.
0500   // Requires: `p` is aligned to `Alignment()`.
0501   template <size_t N, class Char>
0502   CopyConst<Char, ElementType<N>>* Pointer(Char* p) const {
0503     using C = typename std::remove_const<Char>::type;
0504     static_assert(
0505         std::is_same<C, char>() || std::is_same<C, unsigned char>() ||
0506             std::is_same<C, signed char>(),
0507         "The argument must be a pointer to [const] [signed|unsigned] char");
0508     constexpr size_t alignment = Alignment();
0509     (void)alignment;
0510     assert(reinterpret_cast<uintptr_t>(p) % alignment == 0);
0511     return reinterpret_cast<CopyConst<Char, ElementType<N>>*>(p + Offset<N>());
0512   }
0513 
0514   // Pointer to the beginning of the array with the specified element type.
0515   // There must be exactly one such array and its zero-based index must be at
0516   // most `NumSizes`.
0517   //
0518   // `Char` must be `[const] [signed|unsigned] char`.
0519   //
0520   //   // int[3], 4 bytes of padding, double[4].
0521   //   Layout<int, double> x(3, 4);
0522   //   unsigned char* p = new unsigned char[x.AllocSize()];
0523   //   int* ints = x.Pointer<int>(p);
0524   //   double* doubles = x.Pointer<double>(p);
0525   //
0526   // Requires: `p` is aligned to `Alignment()`.
0527   template <class T, class Char>
0528   CopyConst<Char, T>* Pointer(Char* p) const {
0529     return Pointer<ElementIndex<T>()>(p);
0530   }
0531 
0532   // Pointers to all arrays for which pointers are known.
0533   //
0534   // `Char` must be `[const] [signed|unsigned] char`.
0535   //
0536   //   // int[3], 4 bytes of padding, double[4].
0537   //   Layout<int, double> x(3, 4);
0538   //   unsigned char* p = new unsigned char[x.AllocSize()];
0539   //
0540   //   int* ints;
0541   //   double* doubles;
0542   //   std::tie(ints, doubles) = x.Pointers(p);
0543   //
0544   // Requires: `p` is aligned to `Alignment()`.
0545   template <class Char>
0546   auto Pointers(Char* p) const {
0547     return std::tuple<CopyConst<Char, ElementType<OffsetSeq>>*...>(
0548         Pointer<OffsetSeq>(p)...);
0549   }
0550 
0551   // The Nth array.
0552   //
0553   // `Char` must be `[const] [signed|unsigned] char`.
0554   //
0555   //   // int[3], 4 bytes of padding, double[4].
0556   //   Layout<int, double> x(3, 4);
0557   //   unsigned char* p = new unsigned char[x.AllocSize()];
0558   //   Span<int> ints = x.Slice<0>(p);
0559   //   Span<double> doubles = x.Slice<1>(p);
0560   //
0561   // Requires: `N < NumSizes`.
0562   // Requires: `p` is aligned to `Alignment()`.
0563   template <size_t N, class Char>
0564   SliceType<CopyConst<Char, ElementType<N>>> Slice(Char* p) const {
0565     return SliceType<CopyConst<Char, ElementType<N>>>(Pointer<N>(p), Size<N>());
0566   }
0567 
0568   // The array with the specified element type. There must be exactly one
0569   // such array and its zero-based index must be less than `NumSizes`.
0570   //
0571   // `Char` must be `[const] [signed|unsigned] char`.
0572   //
0573   //   // int[3], 4 bytes of padding, double[4].
0574   //   Layout<int, double> x(3, 4);
0575   //   unsigned char* p = new unsigned char[x.AllocSize()];
0576   //   Span<int> ints = x.Slice<int>(p);
0577   //   Span<double> doubles = x.Slice<double>(p);
0578   //
0579   // Requires: `p` is aligned to `Alignment()`.
0580   template <class T, class Char>
0581   SliceType<CopyConst<Char, T>> Slice(Char* p) const {
0582     return Slice<ElementIndex<T>()>(p);
0583   }
0584 
0585   // All arrays with known sizes.
0586   //
0587   // `Char` must be `[const] [signed|unsigned] char`.
0588   //
0589   //   // int[3], 4 bytes of padding, double[4].
0590   //   Layout<int, double> x(3, 4);
0591   //   unsigned char* p = new unsigned char[x.AllocSize()];
0592   //
0593   //   Span<int> ints;
0594   //   Span<double> doubles;
0595   //   std::tie(ints, doubles) = x.Slices(p);
0596   //
0597   // Requires: `p` is aligned to `Alignment()`.
0598   //
0599   // Note: We mark the parameter as unused because GCC detects it is not used
0600   // when `SizeSeq` is empty [-Werror=unused-but-set-parameter].
0601   template <class Char>
0602   auto Slices(ABSL_ATTRIBUTE_UNUSED Char* p) const {
0603     return std::tuple<SliceType<CopyConst<Char, ElementType<SizeSeq>>>...>(
0604         Slice<SizeSeq>(p)...);
0605   }
0606 
0607   // The size of the allocation that fits all arrays.
0608   //
0609   //   // int[3], 4 bytes of padding, double[4].
0610   //   Layout<int, double> x(3, 4);
0611   //   unsigned char* p = new unsigned char[x.AllocSize()];  // 48 bytes
0612   //
0613   // Requires: `NumSizes == sizeof...(Ts)`.
0614   constexpr size_t AllocSize() const {
0615     static_assert(NumTypes == NumSizes, "You must specify sizes of all fields");
0616     return Offset<NumTypes - 1>() +
0617            SizeOf<ElementType<NumTypes - 1>>::value * Size<NumTypes - 1>();
0618   }
0619 
0620   // If built with --config=asan, poisons padding bytes (if any) in the
0621   // allocation. The pointer must point to a memory block at least
0622   // `AllocSize()` bytes in length.
0623   //
0624   // `Char` must be `[const] [signed|unsigned] char`.
0625   //
0626   // Requires: `p` is aligned to `Alignment()`.
0627   template <class Char, size_t N = NumOffsets - 1, EnableIf<N == 0> = 0>
0628   void PoisonPadding(const Char* p) const {
0629     Pointer<0>(p);  // verify the requirements on `Char` and `p`
0630   }
0631 
0632   template <class Char, size_t N = NumOffsets - 1, EnableIf<N != 0> = 0>
0633   void PoisonPadding(const Char* p) const {
0634     static_assert(N < NumOffsets, "Index out of bounds");
0635     (void)p;
0636 #ifdef ABSL_HAVE_ADDRESS_SANITIZER
0637     PoisonPadding<Char, N - 1>(p);
0638     // The `if` is an optimization. It doesn't affect the observable behaviour.
0639     if (ElementAlignment<N - 1>::value % ElementAlignment<N>::value) {
0640       size_t start =
0641           Offset<N - 1>() + SizeOf<ElementType<N - 1>>::value * Size<N - 1>();
0642       ASAN_POISON_MEMORY_REGION(p + start, Offset<N>() - start);
0643     }
0644 #endif
0645   }
0646 
0647   // Human-readable description of the memory layout. Useful for debugging.
0648   // Slow.
0649   //
0650   //   // char[5], 3 bytes of padding, int[3], 4 bytes of padding, followed
0651   //   // by an unknown number of doubles.
0652   //   auto x = Layout<char, int, double>::Partial(5, 3);
0653   //   assert(x.DebugString() ==
0654   //          "@0<char>(1)[5]; @8<int>(4)[3]; @24<double>(8)");
0655   //
0656   // Each field is in the following format: @offset<type>(sizeof)[size] (<type>
0657   // may be missing depending on the target platform). For example,
0658   // @8<int>(4)[3] means that at offset 8 we have an array of ints, where each
0659   // int is 4 bytes, and we have 3 of those ints. The size of the last field may
0660   // be missing (as in the example above). Only fields with known offsets are
0661   // described. Type names may differ across platforms: one compiler might
0662   // produce "unsigned*" where another produces "unsigned int *".
0663   std::string DebugString() const {
0664     const auto offsets = Offsets();
0665     const size_t sizes[] = {SizeOf<ElementType<OffsetSeq>>::value...};
0666     const std::string types[] = {
0667         adl_barrier::TypeName<ElementType<OffsetSeq>>()...};
0668     std::string res = absl::StrCat("@0", types[0], "(", sizes[0], ")");
0669     for (size_t i = 0; i != NumOffsets - 1; ++i) {
0670       absl::StrAppend(&res, "[", DebugSize(i), "]; @", offsets[i + 1],
0671                       types[i + 1], "(", sizes[i + 1], ")");
0672     }
0673     // NumSizes is a constant that may be zero. Some compilers cannot see that
0674     // inside the if statement "size_[NumSizes - 1]" must be valid.
0675     int last = static_cast<int>(NumSizes) - 1;
0676     if (NumTypes == NumSizes && last >= 0) {
0677       absl::StrAppend(&res, "[", DebugSize(static_cast<size_t>(last)), "]");
0678     }
0679     return res;
0680   }
0681 
0682  private:
0683   size_t DebugSize(size_t n) const {
0684     if (n < NumStaticSizes) {
0685       return kStaticSizes[n];
0686     } else {
0687       return size_[n - NumStaticSizes];
0688     }
0689   }
0690 
0691   // Arguments of `Layout::Partial()` or `Layout::Layout()`.
0692   size_t size_[NumRuntimeSizes > 0 ? NumRuntimeSizes : 1];
0693 };
0694 
0695 // Defining a constexpr static class member variable is redundant and deprecated
0696 // in C++17, but required in C++14.
0697 template <class... Elements, size_t... StaticSizeSeq, size_t... RuntimeSizeSeq,
0698           size_t... SizeSeq, size_t... OffsetSeq>
0699 constexpr std::array<size_t, sizeof...(StaticSizeSeq)> LayoutImpl<
0700     std::tuple<Elements...>, absl::index_sequence<StaticSizeSeq...>,
0701     absl::index_sequence<RuntimeSizeSeq...>, absl::index_sequence<SizeSeq...>,
0702     absl::index_sequence<OffsetSeq...>>::kStaticSizes;
0703 
0704 template <class StaticSizeSeq, size_t NumRuntimeSizes, class... Ts>
0705 using LayoutType = LayoutImpl<
0706     std::tuple<Ts...>, StaticSizeSeq,
0707     absl::make_index_sequence<NumRuntimeSizes>,
0708     absl::make_index_sequence<NumRuntimeSizes + StaticSizeSeq::size()>,
0709     absl::make_index_sequence<adl_barrier::Min(
0710         sizeof...(Ts), NumRuntimeSizes + StaticSizeSeq::size() + 1)>>;
0711 
0712 template <class StaticSizeSeq, class... Ts>
0713 class LayoutWithStaticSizes
0714     : public LayoutType<StaticSizeSeq,
0715                         sizeof...(Ts) - adl_barrier::Min(sizeof...(Ts),
0716                                                          StaticSizeSeq::size()),
0717                         Ts...> {
0718  private:
0719   using Super =
0720       LayoutType<StaticSizeSeq,
0721                  sizeof...(Ts) -
0722                      adl_barrier::Min(sizeof...(Ts), StaticSizeSeq::size()),
0723                  Ts...>;
0724 
0725  public:
0726   // The result type of `Partial()` with `NumSizes` arguments.
0727   template <size_t NumSizes>
0728   using PartialType =
0729       internal_layout::LayoutType<StaticSizeSeq, NumSizes, Ts...>;
0730 
0731   // `Layout` knows the element types of the arrays we want to lay out in
0732   // memory but not the number of elements in each array.
0733   // `Partial(size1, ..., sizeN)` allows us to specify the latter. The
0734   // resulting immutable object can be used to obtain pointers to the
0735   // individual arrays.
0736   //
0737   // It's allowed to pass fewer array sizes than the number of arrays. E.g.,
0738   // if all you need is to the offset of the second array, you only need to
0739   // pass one argument -- the number of elements in the first array.
0740   //
0741   //   // int[3] followed by 4 bytes of padding and an unknown number of
0742   //   // doubles.
0743   //   auto x = Layout<int, double>::Partial(3);
0744   //   // doubles start at byte 16.
0745   //   assert(x.Offset<1>() == 16);
0746   //
0747   // If you know the number of elements in all arrays, you can still call
0748   // `Partial()` but it's more convenient to use the constructor of `Layout`.
0749   //
0750   //   Layout<int, double> x(3, 5);
0751   //
0752   // Note: The sizes of the arrays must be specified in number of elements,
0753   // not in bytes.
0754   //
0755   // Requires: `sizeof...(Sizes) + NumStaticSizes <= sizeof...(Ts)`.
0756   // Requires: all arguments are convertible to `size_t`.
0757   template <class... Sizes>
0758   static constexpr PartialType<sizeof...(Sizes)> Partial(Sizes&&... sizes) {
0759     static_assert(sizeof...(Sizes) + StaticSizeSeq::size() <= sizeof...(Ts),
0760                   "");
0761     return PartialType<sizeof...(Sizes)>(
0762         static_cast<size_t>(std::forward<Sizes>(sizes))...);
0763   }
0764 
0765   // Inherit LayoutType's constructor.
0766   //
0767   // Creates a layout with the sizes of all arrays specified. If you know
0768   // only the sizes of the first N arrays (where N can be zero), you can use
0769   // `Partial()` defined above. The constructor is essentially equivalent to
0770   // calling `Partial()` and passing in all array sizes; the constructor is
0771   // provided as a convenient abbreviation.
0772   //
0773   // Note: The sizes of the arrays must be specified in number of elements,
0774   // not in bytes.
0775   //
0776   // Implementation note: we do this via a `using` declaration instead of
0777   // defining our own explicit constructor because the signature of LayoutType's
0778   // constructor depends on RuntimeSizeSeq, which we don't have access to here.
0779   // If we defined our own constructor here, it would have to use a parameter
0780   // pack and then cast the arguments to size_t when calling the superclass
0781   // constructor, similar to what Partial() does. But that would suffer from the
0782   // same problem that Partial() has, which is that the parameter types are
0783   // inferred from the arguments, which may be signed types, which must then be
0784   // cast to size_t. This can lead to negative values being silently (i.e. with
0785   // no compiler warnings) cast to an unsigned type. Having a constructor with
0786   // size_t parameters helps the compiler generate better warnings about
0787   // potential bad casts, while avoiding false warnings when positive literal
0788   // arguments are used. If an argument is a positive literal integer (e.g.
0789   // `1`), the compiler will understand that it can be safely converted to
0790   // size_t, and hence not generate a warning. But if a negative literal (e.g.
0791   // `-1`) or a variable with signed type is used, then it can generate a
0792   // warning about a potentially unsafe implicit cast. It would be great if we
0793   // could do this for Partial() too, but unfortunately as of C++23 there seems
0794   // to be no way to define a function with a variable number of parameters of a
0795   // certain type, a.k.a. homogeneous function parameter packs. So we're forced
0796   // to choose between explicitly casting the arguments to size_t, which
0797   // suppresses all warnings, even potentially valid ones, or implicitly casting
0798   // them to size_t, which generates bogus warnings whenever literal arguments
0799   // are used, even if they're positive.
0800   using Super::Super;
0801 };
0802 
0803 }  // namespace internal_layout
0804 
0805 // Descriptor of arrays of various types and sizes laid out in memory one after
0806 // another. See the top of the file for documentation.
0807 //
0808 // Check out the public API of internal_layout::LayoutWithStaticSizes and
0809 // internal_layout::LayoutImpl above. Those types are internal to the library
0810 // but their methods are public, and they are inherited by `Layout`.
0811 template <class... Ts>
0812 class Layout : public internal_layout::LayoutWithStaticSizes<
0813                    absl::make_index_sequence<0>, Ts...> {
0814  private:
0815   using Super =
0816       internal_layout::LayoutWithStaticSizes<absl::make_index_sequence<0>,
0817                                              Ts...>;
0818 
0819  public:
0820   // If you know the sizes of some or all of the arrays at compile time, you can
0821   // use `WithStaticSizes` or `WithStaticSizeSequence` to create a `Layout` type
0822   // with those sizes baked in. This can help the compiler generate optimal code
0823   // for calculating array offsets and AllocSize().
0824   //
0825   // Like `Partial()`, the N sizes you specify are for the first N arrays, and
0826   // they specify the number of elements in each array, not the number of bytes.
0827   template <class StaticSizeSeq>
0828   using WithStaticSizeSequence =
0829       internal_layout::LayoutWithStaticSizes<StaticSizeSeq, Ts...>;
0830 
0831   template <size_t... StaticSizes>
0832   using WithStaticSizes =
0833       WithStaticSizeSequence<std::index_sequence<StaticSizes...>>;
0834 
0835   // Inherit LayoutWithStaticSizes's constructor, which requires you to specify
0836   // all the array sizes.
0837   using Super::Super;
0838 };
0839 
0840 }  // namespace container_internal
0841 ABSL_NAMESPACE_END
0842 }  // namespace absl
0843 
0844 #endif  // ABSL_CONTAINER_INTERNAL_LAYOUT_H_