You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

layout.h 34 kB

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