Coverage Report

Created: 2025-04-27 06:20

/src/LPM/external.protobuf/include/absl/container/internal/layout.h
Line
Count
Source (jump to first uncovered line)
1
// Copyright 2018 The Abseil Authors.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//      https://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
//
15
//                           MOTIVATION AND TUTORIAL
16
//
17
// If you want to put in a single heap allocation N doubles followed by M ints,
18
// it's easy if N and M are known at compile time.
19
//
20
//   struct S {
21
//     double a[N];
22
//     int b[M];
23
//   };
24
//
25
//   S* p = new S;
26
//
27
// But what if N and M are known only in run time? Class template Layout to the
28
// rescue! It's a portable generalization of the technique known as struct hack.
29
//
30
//   // This object will tell us everything we need to know about the memory
31
//   // layout of double[N] followed by int[M]. It's structurally identical to
32
//   // size_t[2] that stores N and M. It's very cheap to create.
33
//   const Layout<double, int> layout(N, M);
34
//
35
//   // Allocate enough memory for both arrays. `AllocSize()` tells us how much
36
//   // memory is needed. We are free to use any allocation function we want as
37
//   // long as it returns aligned memory.
38
//   std::unique_ptr<unsigned char[]> p(new unsigned char[layout.AllocSize()]);
39
//
40
//   // Obtain the pointer to the array of doubles.
41
//   // Equivalent to `reinterpret_cast<double*>(p.get())`.
42
//   //
43
//   // We could have written layout.Pointer<0>(p) instead. If all the types are
44
//   // unique you can use either form, but if some types are repeated you must
45
//   // use the index form.
46
//   double* a = layout.Pointer<double>(p.get());
47
//
48
//   // Obtain the pointer to the array of ints.
49
//   // Equivalent to `reinterpret_cast<int*>(p.get() + N * 8)`.
50
//   int* b = layout.Pointer<int>(p);
51
//
52
// If we are unable to specify sizes of all fields, we can pass as many sizes as
53
// we can to `Partial()`. In return, it'll allow us to access the fields whose
54
// locations and sizes can be computed from the provided information.
55
// `Partial()` comes in handy when the array sizes are embedded into the
56
// allocation.
57
//
58
//   // size_t[0] containing N, size_t[1] containing M, double[N], int[M].
59
//   using L = Layout<size_t, size_t, double, int>;
60
//
61
//   unsigned char* Allocate(size_t n, size_t m) {
62
//     const L layout(1, 1, n, m);
63
//     unsigned char* p = new unsigned char[layout.AllocSize()];
64
//     *layout.Pointer<0>(p) = n;
65
//     *layout.Pointer<1>(p) = m;
66
//     return p;
67
//   }
68
//
69
//   void Use(unsigned char* p) {
70
//     // First, extract N and M.
71
//     // Specify that the first array has only one element. Using `prefix` we
72
//     // can access the first two arrays but not more.
73
//     constexpr auto prefix = L::Partial(1);
74
//     size_t n = *prefix.Pointer<0>(p);
75
//     size_t m = *prefix.Pointer<1>(p);
76
//
77
//     // Now we can get pointers to the payload.
78
//     const L layout(1, 1, n, m);
79
//     double* a = layout.Pointer<double>(p);
80
//     int* b = layout.Pointer<int>(p);
81
//   }
82
//
83
// The layout we used above combines fixed-size with dynamically-sized fields.
84
// This is quite common. Layout is optimized for this use case and generates
85
// optimal code. All computations that can be performed at compile time are
86
// indeed performed at compile time.
87
//
88
// Efficiency tip: The order of fields matters. In `Layout<T1, ..., TN>` try to
89
// ensure that `alignof(T1) >= ... >= alignof(TN)`. This way you'll have no
90
// padding in between arrays.
91
//
92
// You can manually override the alignment of an array by wrapping the type in
93
// `Aligned<T, N>`. `Layout<..., Aligned<T, N>, ...>` has exactly the same API
94
// and behavior as `Layout<..., T, ...>` except that the first element of the
95
// array of `T` is aligned to `N` (the rest of the elements follow without
96
// padding). `N` cannot be less than `alignof(T)`.
97
//
98
// `AllocSize()` and `Pointer()` are the most basic methods for dealing with
99
// memory layouts. Check out the reference or code below to discover more.
100
//
101
//                            EXAMPLE
102
//
103
//   // Immutable move-only string with sizeof equal to sizeof(void*). The
104
//   // string size and the characters are kept in the same heap allocation.
105
//   class CompactString {
106
//    public:
107
//     CompactString(const char* s = "") {
108
//       const size_t size = strlen(s);
109
//       // size_t[1] followed by char[size + 1].
110
//       const L layout(1, size + 1);
111
//       p_.reset(new unsigned char[layout.AllocSize()]);
112
//       // If running under ASAN, mark the padding bytes, if any, to catch
113
//       // memory errors.
114
//       layout.PoisonPadding(p_.get());
115
//       // Store the size in the allocation.
116
//       *layout.Pointer<size_t>(p_.get()) = size;
117
//       // Store the characters in the allocation.
118
//       memcpy(layout.Pointer<char>(p_.get()), s, size + 1);
119
//     }
120
//
121
//     size_t size() const {
122
//       // Equivalent to reinterpret_cast<size_t&>(*p).
123
//       return *L::Partial().Pointer<size_t>(p_.get());
124
//     }
125
//
126
//     const char* c_str() const {
127
//       // Equivalent to reinterpret_cast<char*>(p.get() + sizeof(size_t)).
128
//       // The argument in Partial(1) specifies that we have size_t[1] in front
129
//       // of the characters.
130
//       return L::Partial(1).Pointer<char>(p_.get());
131
//     }
132
//
133
//    private:
134
//     // Our heap allocation contains a size_t followed by an array of chars.
135
//     using L = Layout<size_t, char>;
136
//     std::unique_ptr<unsigned char[]> p_;
137
//   };
138
//
139
//   int main() {
140
//     CompactString s = "hello";
141
//     assert(s.size() == 5);
142
//     assert(strcmp(s.c_str(), "hello") == 0);
143
//   }
144
//
145
//                               DOCUMENTATION
146
//
147
// The interface exported by this file consists of:
148
// - class `Layout<>` and its public members.
149
// - The public members of class `internal_layout::LayoutImpl<>`. That class
150
//   isn't intended to be used directly, and its name and template parameter
151
//   list are internal implementation details, but the class itself provides
152
//   most of the functionality in this file. See comments on its members for
153
//   detailed documentation.
154
//
155
// `Layout<T1,... Tn>::Partial(count1,..., countm)` (where `m` <= `n`) returns a
156
// `LayoutImpl<>` object. `Layout<T1,..., Tn> layout(count1,..., countn)`
157
// creates a `Layout` object, which exposes the same functionality by inheriting
158
// from `LayoutImpl<>`.
159
160
#ifndef ABSL_CONTAINER_INTERNAL_LAYOUT_H_
161
#define ABSL_CONTAINER_INTERNAL_LAYOUT_H_
162
163
#include <assert.h>
164
#include <stddef.h>
165
#include <stdint.h>
166
167
#include <ostream>
168
#include <string>
169
#include <tuple>
170
#include <type_traits>
171
#include <typeinfo>
172
#include <utility>
173
174
#include "absl/base/config.h"
175
#include "absl/debugging/internal/demangle.h"
176
#include "absl/meta/type_traits.h"
177
#include "absl/strings/str_cat.h"
178
#include "absl/types/span.h"
179
#include "absl/utility/utility.h"
180
181
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
182
#include <sanitizer/asan_interface.h>
183
#endif
184
185
namespace absl {
186
ABSL_NAMESPACE_BEGIN
187
namespace container_internal {
188
189
// A type wrapper that instructs `Layout` to use the specific alignment for the
190
// array. `Layout<..., Aligned<T, N>, ...>` has exactly the same API
191
// and behavior as `Layout<..., T, ...>` except that the first element of the
192
// array of `T` is aligned to `N` (the rest of the elements follow without
193
// padding).
194
//
195
// Requires: `N >= alignof(T)` and `N` is a power of 2.
196
template <class T, size_t N>
197
struct Aligned;
198
199
namespace internal_layout {
200
201
template <class T>
202
struct NotAligned {};
203
204
template <class T, size_t N>
205
struct NotAligned<const Aligned<T, N>> {
206
  static_assert(sizeof(T) == 0, "Aligned<T, N> cannot be const-qualified");
207
};
208
209
template <size_t>
210
using IntToSize = size_t;
211
212
template <class>
213
using TypeToSize = size_t;
214
215
template <class T>
216
struct Type : NotAligned<T> {
217
  using type = T;
218
};
219
220
template <class T, size_t N>
221
struct Type<Aligned<T, N>> {
222
  using type = T;
223
};
224
225
template <class T>
226
struct SizeOf : NotAligned<T>, std::integral_constant<size_t, sizeof(T)> {};
227
228
template <class T, size_t N>
229
struct SizeOf<Aligned<T, N>> : std::integral_constant<size_t, sizeof(T)> {};
230
231
// Note: workaround for https://gcc.gnu.org/PR88115
232
template <class T>
233
struct AlignOf : NotAligned<T> {
234
  static constexpr size_t value = alignof(T);
235
};
236
237
template <class T, size_t N>
238
struct AlignOf<Aligned<T, N>> {
239
  static_assert(N % alignof(T) == 0,
240
                "Custom alignment can't be lower than the type's alignment");
241
  static constexpr size_t value = N;
242
};
243
244
// Does `Ts...` contain `T`?
245
template <class T, class... Ts>
246
using Contains = absl::disjunction<std::is_same<T, Ts>...>;
247
248
template <class From, class To>
249
using CopyConst =
250
    typename std::conditional<std::is_const<From>::value, const To, To>::type;
251
252
// Note: We're not qualifying this with absl:: because it doesn't compile under
253
// MSVC.
254
template <class T>
255
using SliceType = Span<T>;
256
257
// This namespace contains no types. It prevents functions defined in it from
258
// being found by ADL.
259
namespace adl_barrier {
260
261
template <class Needle, class... Ts>
262
constexpr size_t Find(Needle, Needle, Ts...) {
263
  static_assert(!Contains<Needle, Ts...>(), "Duplicate element type");
264
  return 0;
265
}
266
267
template <class Needle, class T, class... Ts>
268
constexpr size_t Find(Needle, T, Ts...) {
269
  return adl_barrier::Find(Needle(), Ts()...) + 1;
270
}
271
272
0
constexpr bool IsPow2(size_t n) { return !(n & (n - 1)); }
273
274
// Returns `q * m` for the smallest `q` such that `q * m >= n`.
275
// Requires: `m` is a power of two. It's enforced by IsLegalElementType below.
276
0
constexpr size_t Align(size_t n, size_t m) { return (n + m - 1) & ~(m - 1); }
277
278
0
constexpr size_t Min(size_t a, size_t b) { return b < a ? b : a; }
279
280
0
constexpr size_t Max(size_t a) { return a; }
281
282
template <class... Ts>
283
0
constexpr size_t Max(size_t a, size_t b, Ts... rest) {
284
0
  return adl_barrier::Max(b < a ? a : b, rest...);
285
0
}
Unexecuted instantiation: unsigned long absl::lts_20240116::container_internal::internal_layout::adl_barrier::Max<>(unsigned long, unsigned long)
Unexecuted instantiation: unsigned long absl::lts_20240116::container_internal::internal_layout::adl_barrier::Max<unsigned long>(unsigned long, unsigned long, unsigned long)
Unexecuted instantiation: unsigned long absl::lts_20240116::container_internal::internal_layout::adl_barrier::Max<unsigned long, unsigned long>(unsigned long, unsigned long, unsigned long, unsigned long)
Unexecuted instantiation: unsigned long absl::lts_20240116::container_internal::internal_layout::adl_barrier::Max<unsigned long, unsigned long, unsigned long>(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long)
286
287
template <class T>
288
std::string TypeName() {
289
  std::string out;
290
#if ABSL_INTERNAL_HAS_RTTI
291
  absl::StrAppend(&out, "<",
292
                  absl::debugging_internal::DemangleString(typeid(T).name()),
293
                  ">");
294
#endif
295
  return out;
296
}
297
298
}  // namespace adl_barrier
299
300
template <bool C>
301
using EnableIf = typename std::enable_if<C, int>::type;
302
303
// Can `T` be a template argument of `Layout`?
304
template <class T>
305
using IsLegalElementType = std::integral_constant<
306
    bool, !std::is_reference<T>::value && !std::is_volatile<T>::value &&
307
              !std::is_reference<typename Type<T>::type>::value &&
308
              !std::is_volatile<typename Type<T>::type>::value &&
309
              adl_barrier::IsPow2(AlignOf<T>::value)>;
310
311
template <class Elements, class SizeSeq, class OffsetSeq>
312
class LayoutImpl;
313
314
// Public base class of `Layout` and the result type of `Layout::Partial()`.
315
//
316
// `Elements...` contains all template arguments of `Layout` that created this
317
// instance.
318
//
319
// `SizeSeq...` is `[0, NumSizes)` where `NumSizes` is the number of arguments
320
// passed to `Layout::Partial()` or `Layout::Layout()`.
321
//
322
// `OffsetSeq...` is `[0, NumOffsets)` where `NumOffsets` is
323
// `Min(sizeof...(Elements), NumSizes + 1)` (the number of arrays for which we
324
// can compute offsets).
325
template <class... Elements, size_t... SizeSeq, size_t... OffsetSeq>
326
class LayoutImpl<std::tuple<Elements...>, absl::index_sequence<SizeSeq...>,
327
                 absl::index_sequence<OffsetSeq...>> {
328
 private:
329
  static_assert(sizeof...(Elements) > 0, "At least one field is required");
330
  static_assert(absl::conjunction<IsLegalElementType<Elements>...>::value,
331
                "Invalid element type (see IsLegalElementType)");
332
333
  enum {
334
    NumTypes = sizeof...(Elements),
335
    NumSizes = sizeof...(SizeSeq),
336
    NumOffsets = sizeof...(OffsetSeq),
337
  };
338
339
  // These are guaranteed by `Layout`.
340
  static_assert(NumOffsets == adl_barrier::Min(NumTypes, NumSizes + 1),
341
                "Internal error");
342
  static_assert(NumTypes > 0, "Internal error");
343
344
  // Returns the index of `T` in `Elements...`. Results in a compilation error
345
  // if `Elements...` doesn't contain exactly one instance of `T`.
346
  template <class T>
347
  static constexpr size_t ElementIndex() {
348
    static_assert(Contains<Type<T>, Type<typename Type<Elements>::type>...>(),
349
                  "Type not found");
350
    return adl_barrier::Find(Type<T>(),
351
                             Type<typename Type<Elements>::type>()...);
352
  }
353
354
  template <size_t N>
355
  using ElementAlignment =
356
      AlignOf<typename std::tuple_element<N, std::tuple<Elements...>>::type>;
357
358
 public:
359
  // Element types of all arrays packed in a tuple.
360
  using ElementTypes = std::tuple<typename Type<Elements>::type...>;
361
362
  // Element type of the Nth array.
363
  template <size_t N>
364
  using ElementType = typename std::tuple_element<N, ElementTypes>::type;
365
366
  constexpr explicit LayoutImpl(IntToSize<SizeSeq>... sizes)
367
      : size_{sizes...} {}
368
369
  // Alignment of the layout, equal to the strictest alignment of all elements.
370
  // All pointers passed to the methods of layout must be aligned to this value.
371
0
  static constexpr size_t Alignment() {
372
0
    return adl_barrier::Max(AlignOf<Elements>::value...);
373
0
  }
374
375
  // Offset in bytes of the Nth array.
376
  //
377
  //   // int[3], 4 bytes of padding, double[4].
378
  //   Layout<int, double> x(3, 4);
379
  //   assert(x.Offset<0>() == 0);   // The ints starts from 0.
380
  //   assert(x.Offset<1>() == 16);  // The doubles starts from 16.
381
  //
382
  // Requires: `N <= NumSizes && N < sizeof...(Ts)`.
383
  template <size_t N, EnableIf<N == 0> = 0>
384
0
  constexpr size_t Offset() const {
385
0
    return 0;
386
0
  }
Unexecuted instantiation: _ZNK4absl12lts_2024011618container_internal15internal_layout10LayoutImplINSt3__15tupleIJPNS1_10btree_nodeINS1_10map_paramsIiN6google8protobuf8internal12ExtensionSet9ExtensionENS4_4lessIiEENS4_9allocatorINS4_4pairIKiSC_EEEELi256ELb0EEEEEjhNS1_13map_slot_typeIiSC_EESM_EEENS4_16integer_sequenceImJLm0ELm1ELm2ELm3ELm4EEEESR_E6OffsetILm0ETnNS4_9enable_ifIXeqT_Li0EEiE4typeELi0EEEmv
Unexecuted instantiation: _ZNK4absl12lts_2024011618container_internal15internal_layout10LayoutImplINSt3__15tupleIJPNS1_10btree_nodeINS1_10map_paramsIN6google8protobuf8internal10VariantKeyEPNSA_8NodeBaseENS4_4lessISB_EENSA_12MapAllocatorINS4_4pairIKSB_SD_EEEELi256ELb0EEEEEjhNS1_13map_slot_typeISB_SD_EESN_EEENS4_16integer_sequenceImJLm0ELm1ELm2ELm3ELm4EEEESS_E6OffsetILm0ETnNS4_9enable_ifIXeqT_Li0EEiE4typeELi0EEEmv
387
388
  template <size_t N, EnableIf<N != 0> = 0>
389
0
  constexpr size_t Offset() const {
390
0
    static_assert(N < NumOffsets, "Index out of bounds");
391
0
    return adl_barrier::Align(
392
0
        Offset<N - 1>() + SizeOf<ElementType<N - 1>>::value * size_[N - 1],
393
0
        ElementAlignment<N>::value);
394
0
  }
Unexecuted instantiation: _ZNK4absl12lts_2024011618container_internal15internal_layout10LayoutImplINSt3__15tupleIJPNS1_10btree_nodeINS1_10map_paramsIiN6google8protobuf8internal12ExtensionSet9ExtensionENS4_4lessIiEENS4_9allocatorINS4_4pairIKiSC_EEEELi256ELb0EEEEEjhNS1_13map_slot_typeIiSC_EESM_EEENS4_16integer_sequenceImJLm0ELm1ELm2ELm3ELm4EEEESR_E6OffsetILm1ETnNS4_9enable_ifIXneT_Li0EEiE4typeELi0EEEmv
Unexecuted instantiation: _ZNK4absl12lts_2024011618container_internal15internal_layout10LayoutImplINSt3__15tupleIJPNS1_10btree_nodeINS1_10map_paramsIiN6google8protobuf8internal12ExtensionSet9ExtensionENS4_4lessIiEENS4_9allocatorINS4_4pairIKiSC_EEEELi256ELb0EEEEEjhNS1_13map_slot_typeIiSC_EESM_EEENS4_16integer_sequenceImJLm0ELm1ELm2ELm3ELm4EEEESR_E6OffsetILm2ETnNS4_9enable_ifIXneT_Li0EEiE4typeELi0EEEmv
Unexecuted instantiation: _ZNK4absl12lts_2024011618container_internal15internal_layout10LayoutImplINSt3__15tupleIJPNS1_10btree_nodeINS1_10map_paramsIiN6google8protobuf8internal12ExtensionSet9ExtensionENS4_4lessIiEENS4_9allocatorINS4_4pairIKiSC_EEEELi256ELb0EEEEEjhNS1_13map_slot_typeIiSC_EESM_EEENS4_16integer_sequenceImJLm0ELm1ELm2ELm3ELm4EEEESR_E6OffsetILm3ETnNS4_9enable_ifIXneT_Li0EEiE4typeELi0EEEmv
Unexecuted instantiation: _ZNK4absl12lts_2024011618container_internal15internal_layout10LayoutImplINSt3__15tupleIJPNS1_10btree_nodeINS1_10map_paramsIiN6google8protobuf8internal12ExtensionSet9ExtensionENS4_4lessIiEENS4_9allocatorINS4_4pairIKiSC_EEEELi256ELb0EEEEEjhNS1_13map_slot_typeIiSC_EESM_EEENS4_16integer_sequenceImJLm0ELm1ELm2ELm3ELm4EEEESR_E6OffsetILm4ETnNS4_9enable_ifIXneT_Li0EEiE4typeELi0EEEmv
Unexecuted instantiation: _ZNK4absl12lts_2024011618container_internal15internal_layout10LayoutImplINSt3__15tupleIJPNS1_10btree_nodeINS1_10map_paramsIN6google8protobuf8internal10VariantKeyEPNSA_8NodeBaseENS4_4lessISB_EENSA_12MapAllocatorINS4_4pairIKSB_SD_EEEELi256ELb0EEEEEjhNS1_13map_slot_typeISB_SD_EESN_EEENS4_16integer_sequenceImJLm0ELm1ELm2ELm3ELm4EEEESS_E6OffsetILm1ETnNS4_9enable_ifIXneT_Li0EEiE4typeELi0EEEmv
Unexecuted instantiation: _ZNK4absl12lts_2024011618container_internal15internal_layout10LayoutImplINSt3__15tupleIJPNS1_10btree_nodeINS1_10map_paramsIN6google8protobuf8internal10VariantKeyEPNSA_8NodeBaseENS4_4lessISB_EENSA_12MapAllocatorINS4_4pairIKSB_SD_EEEELi256ELb0EEEEEjhNS1_13map_slot_typeISB_SD_EESN_EEENS4_16integer_sequenceImJLm0ELm1ELm2ELm3ELm4EEEESS_E6OffsetILm2ETnNS4_9enable_ifIXneT_Li0EEiE4typeELi0EEEmv
Unexecuted instantiation: _ZNK4absl12lts_2024011618container_internal15internal_layout10LayoutImplINSt3__15tupleIJPNS1_10btree_nodeINS1_10map_paramsIN6google8protobuf8internal10VariantKeyEPNSA_8NodeBaseENS4_4lessISB_EENSA_12MapAllocatorINS4_4pairIKSB_SD_EEEELi256ELb0EEEEEjhNS1_13map_slot_typeISB_SD_EESN_EEENS4_16integer_sequenceImJLm0ELm1ELm2ELm3ELm4EEEESS_E6OffsetILm3ETnNS4_9enable_ifIXneT_Li0EEiE4typeELi0EEEmv
Unexecuted instantiation: _ZNK4absl12lts_2024011618container_internal15internal_layout10LayoutImplINSt3__15tupleIJPNS1_10btree_nodeINS1_10map_paramsIN6google8protobuf8internal10VariantKeyEPNSA_8NodeBaseENS4_4lessISB_EENSA_12MapAllocatorINS4_4pairIKSB_SD_EEEELi256ELb0EEEEEjhNS1_13map_slot_typeISB_SD_EESN_EEENS4_16integer_sequenceImJLm0ELm1ELm2ELm3ELm4EEEESS_E6OffsetILm4ETnNS4_9enable_ifIXneT_Li0EEiE4typeELi0EEEmv
395
396
  // Offset in bytes of the array with the specified element type. There must
397
  // be exactly one such array and its zero-based index must be at most
398
  // `NumSizes`.
399
  //
400
  //   // int[3], 4 bytes of padding, double[4].
401
  //   Layout<int, double> x(3, 4);
402
  //   assert(x.Offset<int>() == 0);      // The ints starts from 0.
403
  //   assert(x.Offset<double>() == 16);  // The doubles starts from 16.
404
  template <class T>
405
  constexpr size_t Offset() const {
406
    return Offset<ElementIndex<T>()>();
407
  }
408
409
  // Offsets in bytes of all arrays for which the offsets are known.
410
  constexpr std::array<size_t, NumOffsets> Offsets() const {
411
    return {{Offset<OffsetSeq>()...}};
412
  }
413
414
  // The number of elements in the Nth array. This is the Nth argument of
415
  // `Layout::Partial()` or `Layout::Layout()` (zero-based).
416
  //
417
  //   // int[3], 4 bytes of padding, double[4].
418
  //   Layout<int, double> x(3, 4);
419
  //   assert(x.Size<0>() == 3);
420
  //   assert(x.Size<1>() == 4);
421
  //
422
  // Requires: `N < NumSizes`.
423
  template <size_t N>
424
  constexpr size_t Size() const {
425
    static_assert(N < NumSizes, "Index out of bounds");
426
    return size_[N];
427
  }
428
429
  // The number of elements in the array with the specified element type.
430
  // There must be exactly one such array and its zero-based index must be
431
  // at most `NumSizes`.
432
  //
433
  //   // int[3], 4 bytes of padding, double[4].
434
  //   Layout<int, double> x(3, 4);
435
  //   assert(x.Size<int>() == 3);
436
  //   assert(x.Size<double>() == 4);
437
  template <class T>
438
  constexpr size_t Size() const {
439
    return Size<ElementIndex<T>()>();
440
  }
441
442
  // The number of elements of all arrays for which they are known.
443
  constexpr std::array<size_t, NumSizes> Sizes() const {
444
    return {{Size<SizeSeq>()...}};
445
  }
446
447
  // Pointer to the beginning of the Nth array.
448
  //
449
  // `Char` must be `[const] [signed|unsigned] char`.
450
  //
451
  //   // int[3], 4 bytes of padding, double[4].
452
  //   Layout<int, double> x(3, 4);
453
  //   unsigned char* p = new unsigned char[x.AllocSize()];
454
  //   int* ints = x.Pointer<0>(p);
455
  //   double* doubles = x.Pointer<1>(p);
456
  //
457
  // Requires: `N <= NumSizes && N < sizeof...(Ts)`.
458
  // Requires: `p` is aligned to `Alignment()`.
459
  template <size_t N, class Char>
460
0
  CopyConst<Char, ElementType<N>>* Pointer(Char* p) const {
461
0
    using C = typename std::remove_const<Char>::type;
462
0
    static_assert(
463
0
        std::is_same<C, char>() || std::is_same<C, unsigned char>() ||
464
0
            std::is_same<C, signed char>(),
465
0
        "The argument must be a pointer to [const] [signed|unsigned] char");
466
0
    constexpr size_t alignment = Alignment();
467
0
    (void)alignment;
468
0
    assert(reinterpret_cast<uintptr_t>(p) % alignment == 0);
469
0
    return reinterpret_cast<CopyConst<Char, ElementType<N>>*>(p + Offset<N>());
470
0
  }
Unexecuted instantiation: _ZNK4absl12lts_2024011618container_internal15internal_layout10LayoutImplINSt3__15tupleIJPNS1_10btree_nodeINS1_10map_paramsIN6google8protobuf8internal10VariantKeyEPNSA_8NodeBaseENS4_4lessISB_EENSA_12MapAllocatorINS4_4pairIKSB_SD_EEEELi256ELb0EEEEEjhNS1_13map_slot_typeISB_SD_EESN_EEENS4_16integer_sequenceImJLm0ELm1ELm2ELm3ELm4EEEESS_E7PointerILm0EKcEEPNS4_11conditionalIXsr3std8is_constIT0_EE5valueEKNS4_13tuple_elementIXT_ESQ_E4typeES10_E4typeEPSX_
Unexecuted instantiation: _ZNK4absl12lts_2024011618container_internal15internal_layout10LayoutImplINSt3__15tupleIJPNS1_10btree_nodeINS1_10map_paramsIN6google8protobuf8internal10VariantKeyEPNSA_8NodeBaseENS4_4lessISB_EENSA_12MapAllocatorINS4_4pairIKSB_SD_EEEELi256ELb0EEEEEjhNS1_13map_slot_typeISB_SD_EESN_EEENS4_16integer_sequenceImJLm0ELm1ELm2ELm3ELm4EEEESS_E7PointerILm2EKcEEPNS4_11conditionalIXsr3std8is_constIT0_EE5valueEKNS4_13tuple_elementIXT_ESQ_E4typeES10_E4typeEPSX_
Unexecuted instantiation: _ZNK4absl12lts_2024011618container_internal15internal_layout10LayoutImplINSt3__15tupleIJPNS1_10btree_nodeINS1_10map_paramsIN6google8protobuf8internal10VariantKeyEPNSA_8NodeBaseENS4_4lessISB_EENSA_12MapAllocatorINS4_4pairIKSB_SD_EEEELi256ELb0EEEEEjhNS1_13map_slot_typeISB_SD_EESN_EEENS4_16integer_sequenceImJLm0ELm1ELm2ELm3ELm4EEEESS_E7PointerILm1EKcEEPNS4_11conditionalIXsr3std8is_constIT0_EE5valueEKNS4_13tuple_elementIXT_ESQ_E4typeES10_E4typeEPSX_
Unexecuted instantiation: _ZNK4absl12lts_2024011618container_internal15internal_layout10LayoutImplINSt3__15tupleIJPNS1_10btree_nodeINS1_10map_paramsIN6google8protobuf8internal10VariantKeyEPNSA_8NodeBaseENS4_4lessISB_EENSA_12MapAllocatorINS4_4pairIKSB_SD_EEEELi256ELb0EEEEEjhNS1_13map_slot_typeISB_SD_EESN_EEENS4_16integer_sequenceImJLm0ELm1ELm2ELm3ELm4EEEESS_E7PointerILm3EcEEPNS4_11conditionalIXsr3std8is_constIT0_EE5valueEKNS4_13tuple_elementIXT_ESQ_E4typeESZ_E4typeEPSW_
471
472
  // Pointer to the beginning of the array with the specified element type.
473
  // There must be exactly one such array and its zero-based index must be at
474
  // most `NumSizes`.
475
  //
476
  // `Char` must be `[const] [signed|unsigned] char`.
477
  //
478
  //   // int[3], 4 bytes of padding, double[4].
479
  //   Layout<int, double> x(3, 4);
480
  //   unsigned char* p = new unsigned char[x.AllocSize()];
481
  //   int* ints = x.Pointer<int>(p);
482
  //   double* doubles = x.Pointer<double>(p);
483
  //
484
  // Requires: `p` is aligned to `Alignment()`.
485
  template <class T, class Char>
486
  CopyConst<Char, T>* Pointer(Char* p) const {
487
    return Pointer<ElementIndex<T>()>(p);
488
  }
489
490
  // Pointers to all arrays for which pointers are known.
491
  //
492
  // `Char` must be `[const] [signed|unsigned] char`.
493
  //
494
  //   // int[3], 4 bytes of padding, double[4].
495
  //   Layout<int, double> x(3, 4);
496
  //   unsigned char* p = new unsigned char[x.AllocSize()];
497
  //
498
  //   int* ints;
499
  //   double* doubles;
500
  //   std::tie(ints, doubles) = x.Pointers(p);
501
  //
502
  // Requires: `p` is aligned to `Alignment()`.
503
  //
504
  // Note: We're not using ElementType alias here because it does not compile
505
  // under MSVC.
506
  template <class Char>
507
  std::tuple<CopyConst<
508
      Char, typename std::tuple_element<OffsetSeq, ElementTypes>::type>*...>
509
  Pointers(Char* p) const {
510
    return std::tuple<CopyConst<Char, ElementType<OffsetSeq>>*...>(
511
        Pointer<OffsetSeq>(p)...);
512
  }
513
514
  // The Nth array.
515
  //
516
  // `Char` must be `[const] [signed|unsigned] char`.
517
  //
518
  //   // int[3], 4 bytes of padding, double[4].
519
  //   Layout<int, double> x(3, 4);
520
  //   unsigned char* p = new unsigned char[x.AllocSize()];
521
  //   Span<int> ints = x.Slice<0>(p);
522
  //   Span<double> doubles = x.Slice<1>(p);
523
  //
524
  // Requires: `N < NumSizes`.
525
  // Requires: `p` is aligned to `Alignment()`.
526
  template <size_t N, class Char>
527
  SliceType<CopyConst<Char, ElementType<N>>> Slice(Char* p) const {
528
    return SliceType<CopyConst<Char, ElementType<N>>>(Pointer<N>(p), Size<N>());
529
  }
530
531
  // The array with the specified element type. There must be exactly one
532
  // such array and its zero-based index must be less than `NumSizes`.
533
  //
534
  // `Char` must be `[const] [signed|unsigned] char`.
535
  //
536
  //   // int[3], 4 bytes of padding, double[4].
537
  //   Layout<int, double> x(3, 4);
538
  //   unsigned char* p = new unsigned char[x.AllocSize()];
539
  //   Span<int> ints = x.Slice<int>(p);
540
  //   Span<double> doubles = x.Slice<double>(p);
541
  //
542
  // Requires: `p` is aligned to `Alignment()`.
543
  template <class T, class Char>
544
  SliceType<CopyConst<Char, T>> Slice(Char* p) const {
545
    return Slice<ElementIndex<T>()>(p);
546
  }
547
548
  // All arrays with known sizes.
549
  //
550
  // `Char` must be `[const] [signed|unsigned] char`.
551
  //
552
  //   // int[3], 4 bytes of padding, double[4].
553
  //   Layout<int, double> x(3, 4);
554
  //   unsigned char* p = new unsigned char[x.AllocSize()];
555
  //
556
  //   Span<int> ints;
557
  //   Span<double> doubles;
558
  //   std::tie(ints, doubles) = x.Slices(p);
559
  //
560
  // Requires: `p` is aligned to `Alignment()`.
561
  //
562
  // Note: We're not using ElementType alias here because it does not compile
563
  // under MSVC.
564
  template <class Char>
565
  std::tuple<SliceType<CopyConst<
566
      Char, typename std::tuple_element<SizeSeq, ElementTypes>::type>>...>
567
  Slices(Char* p) const {
568
    // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63875 (fixed
569
    // in 6.1).
570
    (void)p;
571
    return std::tuple<SliceType<CopyConst<Char, ElementType<SizeSeq>>>...>(
572
        Slice<SizeSeq>(p)...);
573
  }
574
575
  // The size of the allocation that fits all arrays.
576
  //
577
  //   // int[3], 4 bytes of padding, double[4].
578
  //   Layout<int, double> x(3, 4);
579
  //   unsigned char* p = new unsigned char[x.AllocSize()];  // 48 bytes
580
  //
581
  // Requires: `NumSizes == sizeof...(Ts)`.
582
0
  constexpr size_t AllocSize() const {
583
0
    static_assert(NumTypes == NumSizes, "You must specify sizes of all fields");
584
0
    return Offset<NumTypes - 1>() +
585
0
        SizeOf<ElementType<NumTypes - 1>>::value * size_[NumTypes - 1];
586
0
  }
Unexecuted instantiation: absl::lts_20240116::container_internal::internal_layout::LayoutImpl<std::__1::tuple<absl::lts_20240116::container_internal::btree_node<absl::lts_20240116::container_internal::map_params<int, google::protobuf::internal::ExtensionSet::Extension, std::__1::less<int>, std::__1::allocator<std::__1::pair<int const, google::protobuf::internal::ExtensionSet::Extension> >, 256, false> >*, unsigned int, unsigned char, absl::lts_20240116::container_internal::map_slot_type<int, google::protobuf::internal::ExtensionSet::Extension>, absl::lts_20240116::container_internal::btree_node<absl::lts_20240116::container_internal::map_params<int, google::protobuf::internal::ExtensionSet::Extension, std::__1::less<int>, std::__1::allocator<std::__1::pair<int const, google::protobuf::internal::ExtensionSet::Extension> >, 256, false> >*>, std::__1::integer_sequence<unsigned long, 0ul, 1ul, 2ul, 3ul, 4ul>, std::__1::integer_sequence<unsigned long, 0ul, 1ul, 2ul, 3ul, 4ul> >::AllocSize() const
Unexecuted instantiation: absl::lts_20240116::container_internal::internal_layout::LayoutImpl<std::__1::tuple<absl::lts_20240116::container_internal::btree_node<absl::lts_20240116::container_internal::map_params<google::protobuf::internal::VariantKey, google::protobuf::internal::NodeBase*, std::__1::less<google::protobuf::internal::VariantKey>, google::protobuf::internal::MapAllocator<std::__1::pair<google::protobuf::internal::VariantKey const, google::protobuf::internal::NodeBase*> >, 256, false> >*, unsigned int, unsigned char, absl::lts_20240116::container_internal::map_slot_type<google::protobuf::internal::VariantKey, google::protobuf::internal::NodeBase*>, absl::lts_20240116::container_internal::btree_node<absl::lts_20240116::container_internal::map_params<google::protobuf::internal::VariantKey, google::protobuf::internal::NodeBase*, std::__1::less<google::protobuf::internal::VariantKey>, google::protobuf::internal::MapAllocator<std::__1::pair<google::protobuf::internal::VariantKey const, google::protobuf::internal::NodeBase*> >, 256, false> >*>, std::__1::integer_sequence<unsigned long, 0ul, 1ul, 2ul, 3ul, 4ul>, std::__1::integer_sequence<unsigned long, 0ul, 1ul, 2ul, 3ul, 4ul> >::AllocSize() const
587
588
  // If built with --config=asan, poisons padding bytes (if any) in the
589
  // allocation. The pointer must point to a memory block at least
590
  // `AllocSize()` bytes in length.
591
  //
592
  // `Char` must be `[const] [signed|unsigned] char`.
593
  //
594
  // Requires: `p` is aligned to `Alignment()`.
595
  template <class Char, size_t N = NumOffsets - 1, EnableIf<N == 0> = 0>
596
  void PoisonPadding(const Char* p) const {
597
    Pointer<0>(p);  // verify the requirements on `Char` and `p`
598
  }
599
600
  template <class Char, size_t N = NumOffsets - 1, EnableIf<N != 0> = 0>
601
  void PoisonPadding(const Char* p) const {
602
    static_assert(N < NumOffsets, "Index out of bounds");
603
    (void)p;
604
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
605
    PoisonPadding<Char, N - 1>(p);
606
    // The `if` is an optimization. It doesn't affect the observable behaviour.
607
    if (ElementAlignment<N - 1>::value % ElementAlignment<N>::value) {
608
      size_t start =
609
          Offset<N - 1>() + SizeOf<ElementType<N - 1>>::value * size_[N - 1];
610
      ASAN_POISON_MEMORY_REGION(p + start, Offset<N>() - start);
611
    }
612
#endif
613
  }
614
615
  // Human-readable description of the memory layout. Useful for debugging.
616
  // Slow.
617
  //
618
  //   // char[5], 3 bytes of padding, int[3], 4 bytes of padding, followed
619
  //   // by an unknown number of doubles.
620
  //   auto x = Layout<char, int, double>::Partial(5, 3);
621
  //   assert(x.DebugString() ==
622
  //          "@0<char>(1)[5]; @8<int>(4)[3]; @24<double>(8)");
623
  //
624
  // Each field is in the following format: @offset<type>(sizeof)[size] (<type>
625
  // may be missing depending on the target platform). For example,
626
  // @8<int>(4)[3] means that at offset 8 we have an array of ints, where each
627
  // int is 4 bytes, and we have 3 of those ints. The size of the last field may
628
  // be missing (as in the example above). Only fields with known offsets are
629
  // described. Type names may differ across platforms: one compiler might
630
  // produce "unsigned*" where another produces "unsigned int *".
631
  std::string DebugString() const {
632
    const auto offsets = Offsets();
633
    const size_t sizes[] = {SizeOf<ElementType<OffsetSeq>>::value...};
634
    const std::string types[] = {
635
        adl_barrier::TypeName<ElementType<OffsetSeq>>()...};
636
    std::string res = absl::StrCat("@0", types[0], "(", sizes[0], ")");
637
    for (size_t i = 0; i != NumOffsets - 1; ++i) {
638
      absl::StrAppend(&res, "[", size_[i], "]; @", offsets[i + 1], types[i + 1],
639
                      "(", sizes[i + 1], ")");
640
    }
641
    // NumSizes is a constant that may be zero. Some compilers cannot see that
642
    // inside the if statement "size_[NumSizes - 1]" must be valid.
643
    int last = static_cast<int>(NumSizes) - 1;
644
    if (NumTypes == NumSizes && last >= 0) {
645
      absl::StrAppend(&res, "[", size_[last], "]");
646
    }
647
    return res;
648
  }
649
650
 private:
651
  // Arguments of `Layout::Partial()` or `Layout::Layout()`.
652
  size_t size_[NumSizes > 0 ? NumSizes : 1];
653
};
654
655
template <size_t NumSizes, class... Ts>
656
using LayoutType = LayoutImpl<
657
    std::tuple<Ts...>, absl::make_index_sequence<NumSizes>,
658
    absl::make_index_sequence<adl_barrier::Min(sizeof...(Ts), NumSizes + 1)>>;
659
660
}  // namespace internal_layout
661
662
// Descriptor of arrays of various types and sizes laid out in memory one after
663
// another. See the top of the file for documentation.
664
//
665
// Check out the public API of internal_layout::LayoutImpl above. The type is
666
// internal to the library but its methods are public, and they are inherited
667
// by `Layout`.
668
template <class... Ts>
669
class Layout : public internal_layout::LayoutType<sizeof...(Ts), Ts...> {
670
 public:
671
  static_assert(sizeof...(Ts) > 0, "At least one field is required");
672
  static_assert(
673
      absl::conjunction<internal_layout::IsLegalElementType<Ts>...>::value,
674
      "Invalid element type (see IsLegalElementType)");
675
676
  // The result type of `Partial()` with `NumSizes` arguments.
677
  template <size_t NumSizes>
678
  using PartialType = internal_layout::LayoutType<NumSizes, Ts...>;
679
680
  // `Layout` knows the element types of the arrays we want to lay out in
681
  // memory but not the number of elements in each array.
682
  // `Partial(size1, ..., sizeN)` allows us to specify the latter. The
683
  // resulting immutable object can be used to obtain pointers to the
684
  // individual arrays.
685
  //
686
  // It's allowed to pass fewer array sizes than the number of arrays. E.g.,
687
  // if all you need is to the offset of the second array, you only need to
688
  // pass one argument -- the number of elements in the first array.
689
  //
690
  //   // int[3] followed by 4 bytes of padding and an unknown number of
691
  //   // doubles.
692
  //   auto x = Layout<int, double>::Partial(3);
693
  //   // doubles start at byte 16.
694
  //   assert(x.Offset<1>() == 16);
695
  //
696
  // If you know the number of elements in all arrays, you can still call
697
  // `Partial()` but it's more convenient to use the constructor of `Layout`.
698
  //
699
  //   Layout<int, double> x(3, 5);
700
  //
701
  // Note: The sizes of the arrays must be specified in number of elements,
702
  // not in bytes.
703
  //
704
  // Requires: `sizeof...(Sizes) <= sizeof...(Ts)`.
705
  // Requires: all arguments are convertible to `size_t`.
706
  template <class... Sizes>
707
  static constexpr PartialType<sizeof...(Sizes)> Partial(Sizes&&... sizes) {
708
    static_assert(sizeof...(Sizes) <= sizeof...(Ts), "");
709
    return PartialType<sizeof...(Sizes)>(absl::forward<Sizes>(sizes)...);
710
  }
711
712
  // Creates a layout with the sizes of all arrays specified. If you know
713
  // only the sizes of the first N arrays (where N can be zero), you can use
714
  // `Partial()` defined above. The constructor is essentially equivalent to
715
  // calling `Partial()` and passing in all array sizes; the constructor is
716
  // provided as a convenient abbreviation.
717
  //
718
  // Note: The sizes of the arrays must be specified in number of elements,
719
  // not in bytes.
720
  constexpr explicit Layout(internal_layout::TypeToSize<Ts>... sizes)
721
      : internal_layout::LayoutType<sizeof...(Ts), Ts...>(sizes...) {}
722
};
723
724
}  // namespace container_internal
725
ABSL_NAMESPACE_END
726
}  // namespace absl
727
728
#endif  // ABSL_CONTAINER_INTERNAL_LAYOUT_H_