layout.h 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844
  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. #ifndef ABSL_CONTAINER_INTERNAL_LAYOUT_H_
  181. #define ABSL_CONTAINER_INTERNAL_LAYOUT_H_
  182. #include <assert.h>
  183. #include <stddef.h>
  184. #include <stdint.h>
  185. #include <array>
  186. #include <string>
  187. #include <tuple>
  188. #include <type_traits>
  189. #include <typeinfo>
  190. #include <utility>
  191. #include "absl/base/attributes.h"
  192. #include "absl/base/config.h"
  193. #include "absl/debugging/internal/demangle.h"
  194. #include "absl/meta/type_traits.h"
  195. #include "absl/strings/str_cat.h"
  196. #include "absl/types/span.h"
  197. #include "absl/utility/utility.h"
  198. #ifdef ABSL_HAVE_ADDRESS_SANITIZER
  199. #include <sanitizer/asan_interface.h>
  200. #endif
  201. namespace absl {
  202. ABSL_NAMESPACE_BEGIN
  203. namespace container_internal {
  204. // A type wrapper that instructs `Layout` to use the specific alignment for the
  205. // array. `Layout<..., Aligned<T, N>, ...>` has exactly the same API
  206. // and behavior as `Layout<..., T, ...>` except that the first element of the
  207. // array of `T` is aligned to `N` (the rest of the elements follow without
  208. // padding).
  209. //
  210. // Requires: `N >= alignof(T)` and `N` is a power of 2.
  211. template <class T, size_t N>
  212. struct Aligned;
  213. namespace internal_layout {
  214. template <class T>
  215. struct NotAligned {};
  216. template <class T, size_t N>
  217. struct NotAligned<const Aligned<T, N>> {
  218. static_assert(sizeof(T) == 0, "Aligned<T, N> cannot be const-qualified");
  219. };
  220. template <size_t>
  221. using IntToSize = size_t;
  222. template <class T>
  223. struct Type : NotAligned<T> {
  224. using type = T;
  225. };
  226. template <class T, size_t N>
  227. struct Type<Aligned<T, N>> {
  228. using type = T;
  229. };
  230. template <class T>
  231. struct SizeOf : NotAligned<T>, std::integral_constant<size_t, sizeof(T)> {};
  232. template <class T, size_t N>
  233. struct SizeOf<Aligned<T, N>> : std::integral_constant<size_t, sizeof(T)> {};
  234. // Note: workaround for https://gcc.gnu.org/PR88115
  235. template <class T>
  236. struct AlignOf : NotAligned<T> {
  237. static constexpr size_t value = alignof(T);
  238. };
  239. template <class T, size_t N>
  240. struct AlignOf<Aligned<T, N>> {
  241. static_assert(N % alignof(T) == 0,
  242. "Custom alignment can't be lower than the type's alignment");
  243. static constexpr size_t value = N;
  244. };
  245. // Does `Ts...` contain `T`?
  246. template <class T, class... Ts>
  247. using Contains = absl::disjunction<std::is_same<T, Ts>...>;
  248. template <class From, class To>
  249. using CopyConst =
  250. typename std::conditional<std::is_const<From>::value, const To, To>::type;
  251. // Note: We're not qualifying this with absl:: because it doesn't compile under
  252. // MSVC.
  253. template <class T>
  254. using SliceType = Span<T>;
  255. // This namespace contains no types. It prevents functions defined in it from
  256. // being found by ADL.
  257. namespace adl_barrier {
  258. template <class Needle, class... Ts>
  259. constexpr size_t Find(Needle, Needle, Ts...) {
  260. static_assert(!Contains<Needle, Ts...>(), "Duplicate element type");
  261. return 0;
  262. }
  263. template <class Needle, class T, class... Ts>
  264. constexpr size_t Find(Needle, T, Ts...) {
  265. return adl_barrier::Find(Needle(), Ts()...) + 1;
  266. }
  267. constexpr bool IsPow2(size_t n) { return !(n & (n - 1)); }
  268. // Returns `q * m` for the smallest `q` such that `q * m >= n`.
  269. // Requires: `m` is a power of two. It's enforced by IsLegalElementType below.
  270. constexpr size_t Align(size_t n, size_t m) { return (n + m - 1) & ~(m - 1); }
  271. constexpr size_t Min(size_t a, size_t b) { return b < a ? b : a; }
  272. constexpr size_t Max(size_t a) { return a; }
  273. template <class... Ts>
  274. constexpr size_t Max(size_t a, size_t b, Ts... rest) {
  275. return adl_barrier::Max(b < a ? a : b, rest...);
  276. }
  277. template <class T>
  278. std::string TypeName() {
  279. std::string out;
  280. #if ABSL_INTERNAL_HAS_RTTI
  281. absl::StrAppend(&out, "<",
  282. absl::debugging_internal::DemangleString(typeid(T).name()),
  283. ">");
  284. #endif
  285. return out;
  286. }
  287. } // namespace adl_barrier
  288. template <bool C>
  289. using EnableIf = typename std::enable_if<C, int>::type;
  290. // Can `T` be a template argument of `Layout`?
  291. template <class T>
  292. using IsLegalElementType = std::integral_constant<
  293. bool, !std::is_reference<T>::value && !std::is_volatile<T>::value &&
  294. !std::is_reference<typename Type<T>::type>::value &&
  295. !std::is_volatile<typename Type<T>::type>::value &&
  296. adl_barrier::IsPow2(AlignOf<T>::value)>;
  297. template <class Elements, class StaticSizeSeq, class RuntimeSizeSeq,
  298. class SizeSeq, class OffsetSeq>
  299. class LayoutImpl;
  300. // Public base class of `Layout` and the result type of `Layout::Partial()`.
  301. //
  302. // `Elements...` contains all template arguments of `Layout` that created this
  303. // instance.
  304. //
  305. // `StaticSizeSeq...` is an index_sequence containing the sizes specified at
  306. // compile-time.
  307. //
  308. // `RuntimeSizeSeq...` is `[0, NumRuntimeSizes)`, where `NumRuntimeSizes` is the
  309. // number of arguments passed to `Layout::Partial()` or `Layout::Layout()`.
  310. //
  311. // `SizeSeq...` is `[0, NumSizes)` where `NumSizes` is `NumRuntimeSizes` plus
  312. // the number of sizes in `StaticSizeSeq`.
  313. //
  314. // `OffsetSeq...` is `[0, NumOffsets)` where `NumOffsets` is
  315. // `Min(sizeof...(Elements), NumSizes + 1)` (the number of arrays for which we
  316. // can compute offsets).
  317. template <class... Elements, size_t... StaticSizeSeq, size_t... RuntimeSizeSeq,
  318. size_t... SizeSeq, size_t... OffsetSeq>
  319. class LayoutImpl<
  320. std::tuple<Elements...>, absl::index_sequence<StaticSizeSeq...>,
  321. absl::index_sequence<RuntimeSizeSeq...>, absl::index_sequence<SizeSeq...>,
  322. absl::index_sequence<OffsetSeq...>> {
  323. private:
  324. static_assert(sizeof...(Elements) > 0, "At least one field is required");
  325. static_assert(absl::conjunction<IsLegalElementType<Elements>...>::value,
  326. "Invalid element type (see IsLegalElementType)");
  327. static_assert(sizeof...(StaticSizeSeq) <= sizeof...(Elements),
  328. "Too many static sizes specified");
  329. enum {
  330. NumTypes = sizeof...(Elements),
  331. NumStaticSizes = sizeof...(StaticSizeSeq),
  332. NumRuntimeSizes = sizeof...(RuntimeSizeSeq),
  333. NumSizes = sizeof...(SizeSeq),
  334. NumOffsets = sizeof...(OffsetSeq),
  335. };
  336. // These are guaranteed by `Layout`.
  337. static_assert(NumStaticSizes + NumRuntimeSizes == NumSizes, "Internal error");
  338. static_assert(NumSizes <= NumTypes, "Internal error");
  339. static_assert(NumOffsets == adl_barrier::Min(NumTypes, NumSizes + 1),
  340. "Internal error");
  341. static_assert(NumTypes > 0, "Internal error");
  342. static constexpr std::array<size_t, sizeof...(StaticSizeSeq)> kStaticSizes = {
  343. StaticSizeSeq...};
  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. template <size_t N>
  354. using ElementAlignment =
  355. AlignOf<typename std::tuple_element<N, std::tuple<Elements...>>::type>;
  356. public:
  357. // Element types of all arrays packed in a tuple.
  358. using ElementTypes = std::tuple<typename Type<Elements>::type...>;
  359. // Element type of the Nth array.
  360. template <size_t N>
  361. using ElementType = typename std::tuple_element<N, ElementTypes>::type;
  362. constexpr explicit LayoutImpl(IntToSize<RuntimeSizeSeq>... sizes)
  363. : size_{sizes...} {}
  364. // Alignment of the layout, equal to the strictest alignment of all elements.
  365. // All pointers passed to the methods of layout must be aligned to this value.
  366. static constexpr size_t Alignment() {
  367. return adl_barrier::Max(AlignOf<Elements>::value...);
  368. }
  369. // Offset in bytes of the Nth array.
  370. //
  371. // // int[3], 4 bytes of padding, double[4].
  372. // Layout<int, double> x(3, 4);
  373. // assert(x.Offset<0>() == 0); // The ints starts from 0.
  374. // assert(x.Offset<1>() == 16); // The doubles starts from 16.
  375. //
  376. // Requires: `N <= NumSizes && N < sizeof...(Ts)`.
  377. template <size_t N, EnableIf<N == 0> = 0>
  378. constexpr size_t Offset() const {
  379. return 0;
  380. }
  381. template <size_t N, EnableIf<N != 0> = 0>
  382. constexpr size_t Offset() const {
  383. static_assert(N < NumOffsets, "Index out of bounds");
  384. return adl_barrier::Align(
  385. Offset<N - 1>() + SizeOf<ElementType<N - 1>>::value * Size<N - 1>(),
  386. ElementAlignment<N>::value);
  387. }
  388. // Offset in bytes of the array with the specified element type. There must
  389. // be exactly one such array and its zero-based index must be at most
  390. // `NumSizes`.
  391. //
  392. // // int[3], 4 bytes of padding, double[4].
  393. // Layout<int, double> x(3, 4);
  394. // assert(x.Offset<int>() == 0); // The ints starts from 0.
  395. // assert(x.Offset<double>() == 16); // The doubles starts from 16.
  396. template <class T>
  397. constexpr size_t Offset() const {
  398. return Offset<ElementIndex<T>()>();
  399. }
  400. // Offsets in bytes of all arrays for which the offsets are known.
  401. constexpr std::array<size_t, NumOffsets> Offsets() const {
  402. return {{Offset<OffsetSeq>()...}};
  403. }
  404. // The number of elements in the Nth array (zero-based).
  405. //
  406. // // int[3], 4 bytes of padding, double[4].
  407. // Layout<int, double> x(3, 4);
  408. // assert(x.Size<0>() == 3);
  409. // assert(x.Size<1>() == 4);
  410. //
  411. // Requires: `N < NumSizes`.
  412. template <size_t N, EnableIf<(N < NumStaticSizes)> = 0>
  413. constexpr size_t Size() const {
  414. return kStaticSizes[N];
  415. }
  416. template <size_t N, EnableIf<(N >= NumStaticSizes)> = 0>
  417. constexpr size_t Size() const {
  418. static_assert(N < NumSizes, "Index out of bounds");
  419. return size_[N - NumStaticSizes];
  420. }
  421. // The number of elements in the array with the specified element type.
  422. // There must be exactly one such array and its zero-based index must be
  423. // at most `NumSizes`.
  424. //
  425. // // int[3], 4 bytes of padding, double[4].
  426. // Layout<int, double> x(3, 4);
  427. // assert(x.Size<int>() == 3);
  428. // assert(x.Size<double>() == 4);
  429. template <class T>
  430. constexpr size_t Size() const {
  431. return Size<ElementIndex<T>()>();
  432. }
  433. // The number of elements of all arrays for which they are known.
  434. constexpr std::array<size_t, NumSizes> Sizes() const {
  435. return {{Size<SizeSeq>()...}};
  436. }
  437. // Pointer to the beginning of the Nth array.
  438. //
  439. // `Char` must be `[const] [signed|unsigned] char`.
  440. //
  441. // // int[3], 4 bytes of padding, double[4].
  442. // Layout<int, double> x(3, 4);
  443. // unsigned char* p = new unsigned char[x.AllocSize()];
  444. // int* ints = x.Pointer<0>(p);
  445. // double* doubles = x.Pointer<1>(p);
  446. //
  447. // Requires: `N <= NumSizes && N < sizeof...(Ts)`.
  448. // Requires: `p` is aligned to `Alignment()`.
  449. template <size_t N, class Char>
  450. CopyConst<Char, ElementType<N>>* Pointer(Char* p) const {
  451. using C = typename std::remove_const<Char>::type;
  452. static_assert(
  453. std::is_same<C, char>() || std::is_same<C, unsigned char>() ||
  454. std::is_same<C, signed char>(),
  455. "The argument must be a pointer to [const] [signed|unsigned] char");
  456. constexpr size_t alignment = Alignment();
  457. (void)alignment;
  458. assert(reinterpret_cast<uintptr_t>(p) % alignment == 0);
  459. return reinterpret_cast<CopyConst<Char, ElementType<N>>*>(p + Offset<N>());
  460. }
  461. // Pointer to the beginning of the array with the specified element type.
  462. // There must be exactly one such array and its zero-based index must be at
  463. // most `NumSizes`.
  464. //
  465. // `Char` must be `[const] [signed|unsigned] char`.
  466. //
  467. // // int[3], 4 bytes of padding, double[4].
  468. // Layout<int, double> x(3, 4);
  469. // unsigned char* p = new unsigned char[x.AllocSize()];
  470. // int* ints = x.Pointer<int>(p);
  471. // double* doubles = x.Pointer<double>(p);
  472. //
  473. // Requires: `p` is aligned to `Alignment()`.
  474. template <class T, class Char>
  475. CopyConst<Char, T>* Pointer(Char* p) const {
  476. return Pointer<ElementIndex<T>()>(p);
  477. }
  478. // Pointers to all arrays for which pointers are known.
  479. //
  480. // `Char` must be `[const] [signed|unsigned] char`.
  481. //
  482. // // int[3], 4 bytes of padding, double[4].
  483. // Layout<int, double> x(3, 4);
  484. // unsigned char* p = new unsigned char[x.AllocSize()];
  485. //
  486. // int* ints;
  487. // double* doubles;
  488. // std::tie(ints, doubles) = x.Pointers(p);
  489. //
  490. // Requires: `p` is aligned to `Alignment()`.
  491. template <class Char>
  492. auto Pointers(Char* p) const {
  493. return std::tuple<CopyConst<Char, ElementType<OffsetSeq>>*...>(
  494. Pointer<OffsetSeq>(p)...);
  495. }
  496. // The Nth array.
  497. //
  498. // `Char` must be `[const] [signed|unsigned] char`.
  499. //
  500. // // int[3], 4 bytes of padding, double[4].
  501. // Layout<int, double> x(3, 4);
  502. // unsigned char* p = new unsigned char[x.AllocSize()];
  503. // Span<int> ints = x.Slice<0>(p);
  504. // Span<double> doubles = x.Slice<1>(p);
  505. //
  506. // Requires: `N < NumSizes`.
  507. // Requires: `p` is aligned to `Alignment()`.
  508. template <size_t N, class Char>
  509. SliceType<CopyConst<Char, ElementType<N>>> Slice(Char* p) const {
  510. return SliceType<CopyConst<Char, ElementType<N>>>(Pointer<N>(p), Size<N>());
  511. }
  512. // The array with the specified element type. There must be exactly one
  513. // such array and its zero-based index must be less than `NumSizes`.
  514. //
  515. // `Char` must be `[const] [signed|unsigned] char`.
  516. //
  517. // // int[3], 4 bytes of padding, double[4].
  518. // Layout<int, double> x(3, 4);
  519. // unsigned char* p = new unsigned char[x.AllocSize()];
  520. // Span<int> ints = x.Slice<int>(p);
  521. // Span<double> doubles = x.Slice<double>(p);
  522. //
  523. // Requires: `p` is aligned to `Alignment()`.
  524. template <class T, class Char>
  525. SliceType<CopyConst<Char, T>> Slice(Char* p) const {
  526. return Slice<ElementIndex<T>()>(p);
  527. }
  528. // All arrays with known sizes.
  529. //
  530. // `Char` must be `[const] [signed|unsigned] char`.
  531. //
  532. // // int[3], 4 bytes of padding, double[4].
  533. // Layout<int, double> x(3, 4);
  534. // unsigned char* p = new unsigned char[x.AllocSize()];
  535. //
  536. // Span<int> ints;
  537. // Span<double> doubles;
  538. // std::tie(ints, doubles) = x.Slices(p);
  539. //
  540. // Requires: `p` is aligned to `Alignment()`.
  541. //
  542. // Note: We mark the parameter as unused because GCC detects it is not used
  543. // when `SizeSeq` is empty [-Werror=unused-but-set-parameter].
  544. template <class Char>
  545. auto Slices(ABSL_ATTRIBUTE_UNUSED Char* p) const {
  546. return std::tuple<SliceType<CopyConst<Char, ElementType<SizeSeq>>>...>(
  547. Slice<SizeSeq>(p)...);
  548. }
  549. // The size of the allocation that fits all arrays.
  550. //
  551. // // int[3], 4 bytes of padding, double[4].
  552. // Layout<int, double> x(3, 4);
  553. // unsigned char* p = new unsigned char[x.AllocSize()]; // 48 bytes
  554. //
  555. // Requires: `NumSizes == sizeof...(Ts)`.
  556. constexpr size_t AllocSize() const {
  557. static_assert(NumTypes == NumSizes, "You must specify sizes of all fields");
  558. return Offset<NumTypes - 1>() +
  559. SizeOf<ElementType<NumTypes - 1>>::value * Size<NumTypes - 1>();
  560. }
  561. // If built with --config=asan, poisons padding bytes (if any) in the
  562. // allocation. The pointer must point to a memory block at least
  563. // `AllocSize()` bytes in length.
  564. //
  565. // `Char` must be `[const] [signed|unsigned] char`.
  566. //
  567. // Requires: `p` is aligned to `Alignment()`.
  568. template <class Char, size_t N = NumOffsets - 1, EnableIf<N == 0> = 0>
  569. void PoisonPadding(const Char* p) const {
  570. Pointer<0>(p); // verify the requirements on `Char` and `p`
  571. }
  572. template <class Char, size_t N = NumOffsets - 1, EnableIf<N != 0> = 0>
  573. void PoisonPadding(const Char* p) const {
  574. static_assert(N < NumOffsets, "Index out of bounds");
  575. (void)p;
  576. #ifdef ABSL_HAVE_ADDRESS_SANITIZER
  577. PoisonPadding<Char, N - 1>(p);
  578. // The `if` is an optimization. It doesn't affect the observable behaviour.
  579. if (ElementAlignment<N - 1>::value % ElementAlignment<N>::value) {
  580. size_t start =
  581. Offset<N - 1>() + SizeOf<ElementType<N - 1>>::value * Size<N - 1>();
  582. ASAN_POISON_MEMORY_REGION(p + start, Offset<N>() - start);
  583. }
  584. #endif
  585. }
  586. // Human-readable description of the memory layout. Useful for debugging.
  587. // Slow.
  588. //
  589. // // char[5], 3 bytes of padding, int[3], 4 bytes of padding, followed
  590. // // by an unknown number of doubles.
  591. // auto x = Layout<char, int, double>::Partial(5, 3);
  592. // assert(x.DebugString() ==
  593. // "@0<char>(1)[5]; @8<int>(4)[3]; @24<double>(8)");
  594. //
  595. // Each field is in the following format: @offset<type>(sizeof)[size] (<type>
  596. // may be missing depending on the target platform). For example,
  597. // @8<int>(4)[3] means that at offset 8 we have an array of ints, where each
  598. // int is 4 bytes, and we have 3 of those ints. The size of the last field may
  599. // be missing (as in the example above). Only fields with known offsets are
  600. // described. Type names may differ across platforms: one compiler might
  601. // produce "unsigned*" where another produces "unsigned int *".
  602. std::string DebugString() const {
  603. const auto offsets = Offsets();
  604. const size_t sizes[] = {SizeOf<ElementType<OffsetSeq>>::value...};
  605. const std::string types[] = {
  606. adl_barrier::TypeName<ElementType<OffsetSeq>>()...};
  607. std::string res = absl::StrCat("@0", types[0], "(", sizes[0], ")");
  608. for (size_t i = 0; i != NumOffsets - 1; ++i) {
  609. absl::StrAppend(&res, "[", DebugSize(i), "]; @", offsets[i + 1],
  610. types[i + 1], "(", sizes[i + 1], ")");
  611. }
  612. // NumSizes is a constant that may be zero. Some compilers cannot see that
  613. // inside the if statement "size_[NumSizes - 1]" must be valid.
  614. int last = static_cast<int>(NumSizes) - 1;
  615. if (NumTypes == NumSizes && last >= 0) {
  616. absl::StrAppend(&res, "[", DebugSize(static_cast<size_t>(last)), "]");
  617. }
  618. return res;
  619. }
  620. private:
  621. size_t DebugSize(size_t n) const {
  622. if (n < NumStaticSizes) {
  623. return kStaticSizes[n];
  624. } else {
  625. return size_[n - NumStaticSizes];
  626. }
  627. }
  628. // Arguments of `Layout::Partial()` or `Layout::Layout()`.
  629. size_t size_[NumRuntimeSizes > 0 ? NumRuntimeSizes : 1];
  630. };
  631. // Defining a constexpr static class member variable is redundant and deprecated
  632. // in C++17, but required in C++14.
  633. template <class... Elements, size_t... StaticSizeSeq, size_t... RuntimeSizeSeq,
  634. size_t... SizeSeq, size_t... OffsetSeq>
  635. constexpr std::array<size_t, sizeof...(StaticSizeSeq)> LayoutImpl<
  636. std::tuple<Elements...>, absl::index_sequence<StaticSizeSeq...>,
  637. absl::index_sequence<RuntimeSizeSeq...>, absl::index_sequence<SizeSeq...>,
  638. absl::index_sequence<OffsetSeq...>>::kStaticSizes;
  639. template <class StaticSizeSeq, size_t NumRuntimeSizes, class... Ts>
  640. using LayoutType = LayoutImpl<
  641. std::tuple<Ts...>, StaticSizeSeq,
  642. absl::make_index_sequence<NumRuntimeSizes>,
  643. absl::make_index_sequence<NumRuntimeSizes + StaticSizeSeq::size()>,
  644. absl::make_index_sequence<adl_barrier::Min(
  645. sizeof...(Ts), NumRuntimeSizes + StaticSizeSeq::size() + 1)>>;
  646. template <class StaticSizeSeq, class... Ts>
  647. class LayoutWithStaticSizes
  648. : public LayoutType<StaticSizeSeq,
  649. sizeof...(Ts) - adl_barrier::Min(sizeof...(Ts),
  650. StaticSizeSeq::size()),
  651. Ts...> {
  652. private:
  653. using Super =
  654. LayoutType<StaticSizeSeq,
  655. sizeof...(Ts) -
  656. adl_barrier::Min(sizeof...(Ts), StaticSizeSeq::size()),
  657. Ts...>;
  658. public:
  659. // The result type of `Partial()` with `NumSizes` arguments.
  660. template <size_t NumSizes>
  661. using PartialType =
  662. internal_layout::LayoutType<StaticSizeSeq, NumSizes, Ts...>;
  663. // `Layout` knows the element types of the arrays we want to lay out in
  664. // memory but not the number of elements in each array.
  665. // `Partial(size1, ..., sizeN)` allows us to specify the latter. The
  666. // resulting immutable object can be used to obtain pointers to the
  667. // individual arrays.
  668. //
  669. // It's allowed to pass fewer array sizes than the number of arrays. E.g.,
  670. // if all you need is to the offset of the second array, you only need to
  671. // pass one argument -- the number of elements in the first array.
  672. //
  673. // // int[3] followed by 4 bytes of padding and an unknown number of
  674. // // doubles.
  675. // auto x = Layout<int, double>::Partial(3);
  676. // // doubles start at byte 16.
  677. // assert(x.Offset<1>() == 16);
  678. //
  679. // If you know the number of elements in all arrays, you can still call
  680. // `Partial()` but it's more convenient to use the constructor of `Layout`.
  681. //
  682. // Layout<int, double> x(3, 5);
  683. //
  684. // Note: The sizes of the arrays must be specified in number of elements,
  685. // not in bytes.
  686. //
  687. // Requires: `sizeof...(Sizes) + NumStaticSizes <= sizeof...(Ts)`.
  688. // Requires: all arguments are convertible to `size_t`.
  689. template <class... Sizes>
  690. static constexpr PartialType<sizeof...(Sizes)> Partial(Sizes&&... sizes) {
  691. static_assert(sizeof...(Sizes) + StaticSizeSeq::size() <= sizeof...(Ts),
  692. "");
  693. return PartialType<sizeof...(Sizes)>(
  694. static_cast<size_t>(std::forward<Sizes>(sizes))...);
  695. }
  696. // Inherit LayoutType's constructor.
  697. //
  698. // Creates a layout with the sizes of all arrays specified. If you know
  699. // only the sizes of the first N arrays (where N can be zero), you can use
  700. // `Partial()` defined above. The constructor is essentially equivalent to
  701. // calling `Partial()` and passing in all array sizes; the constructor is
  702. // provided as a convenient abbreviation.
  703. //
  704. // Note: The sizes of the arrays must be specified in number of elements,
  705. // not in bytes.
  706. //
  707. // Implementation note: we do this via a `using` declaration instead of
  708. // defining our own explicit constructor because the signature of LayoutType's
  709. // constructor depends on RuntimeSizeSeq, which we don't have access to here.
  710. // If we defined our own constructor here, it would have to use a parameter
  711. // pack and then cast the arguments to size_t when calling the superclass
  712. // constructor, similar to what Partial() does. But that would suffer from the
  713. // same problem that Partial() has, which is that the parameter types are
  714. // inferred from the arguments, which may be signed types, which must then be
  715. // cast to size_t. This can lead to negative values being silently (i.e. with
  716. // no compiler warnings) cast to an unsigned type. Having a constructor with
  717. // size_t parameters helps the compiler generate better warnings about
  718. // potential bad casts, while avoiding false warnings when positive literal
  719. // arguments are used. If an argument is a positive literal integer (e.g.
  720. // `1`), the compiler will understand that it can be safely converted to
  721. // size_t, and hence not generate a warning. But if a negative literal (e.g.
  722. // `-1`) or a variable with signed type is used, then it can generate a
  723. // warning about a potentially unsafe implicit cast. It would be great if we
  724. // could do this for Partial() too, but unfortunately as of C++23 there seems
  725. // to be no way to define a function with a variable number of parameters of a
  726. // certain type, a.k.a. homogeneous function parameter packs. So we're forced
  727. // to choose between explicitly casting the arguments to size_t, which
  728. // suppresses all warnings, even potentially valid ones, or implicitly casting
  729. // them to size_t, which generates bogus warnings whenever literal arguments
  730. // are used, even if they're positive.
  731. using Super::Super;
  732. };
  733. } // namespace internal_layout
  734. // Descriptor of arrays of various types and sizes laid out in memory one after
  735. // another. See the top of the file for documentation.
  736. //
  737. // Check out the public API of internal_layout::LayoutWithStaticSizes and
  738. // internal_layout::LayoutImpl above. Those types are internal to the library
  739. // but their methods are public, and they are inherited by `Layout`.
  740. template <class... Ts>
  741. class Layout : public internal_layout::LayoutWithStaticSizes<
  742. absl::make_index_sequence<0>, Ts...> {
  743. private:
  744. using Super =
  745. internal_layout::LayoutWithStaticSizes<absl::make_index_sequence<0>,
  746. Ts...>;
  747. public:
  748. // If you know the sizes of some or all of the arrays at compile time, you can
  749. // use `WithStaticSizes` or `WithStaticSizeSequence` to create a `Layout` type
  750. // with those sizes baked in. This can help the compiler generate optimal code
  751. // for calculating array offsets and AllocSize().
  752. //
  753. // Like `Partial()`, the N sizes you specify are for the first N arrays, and
  754. // they specify the number of elements in each array, not the number of bytes.
  755. template <class StaticSizeSeq>
  756. using WithStaticSizeSequence =
  757. internal_layout::LayoutWithStaticSizes<StaticSizeSeq, Ts...>;
  758. template <size_t... StaticSizes>
  759. using WithStaticSizes =
  760. WithStaticSizeSequence<std::index_sequence<StaticSizes...>>;
  761. // Inherit LayoutWithStaticSizes's constructor, which requires you to specify
  762. // all the array sizes.
  763. using Super::Super;
  764. };
  765. } // namespace container_internal
  766. ABSL_NAMESPACE_END
  767. } // namespace absl
  768. #endif // ABSL_CONTAINER_INTERNAL_LAYOUT_H_