LLVM  10.0.0svn
TrailingObjects.h
Go to the documentation of this file.
1 //===--- TrailingObjects.h - Variable-length classes ------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file
10 /// This header defines support for implementing classes that have
11 /// some trailing object (or arrays of objects) appended to them. The
12 /// main purpose is to make it obvious where this idiom is being used,
13 /// and to make the usage more idiomatic and more difficult to get
14 /// wrong.
15 ///
16 /// The TrailingObject template abstracts away the reinterpret_cast,
17 /// pointer arithmetic, and size calculations used for the allocation
18 /// and access of appended arrays of objects, and takes care that they
19 /// are all allocated at their required alignment. Additionally, it
20 /// ensures that the base type is final -- deriving from a class that
21 /// expects data appended immediately after it is typically not safe.
22 ///
23 /// Users are expected to derive from this template, and provide
24 /// numTrailingObjects implementations for each trailing type except
25 /// the last, e.g. like this sample:
26 ///
27 /// \code
28 /// class VarLengthObj : private TrailingObjects<VarLengthObj, int, double> {
29 /// friend TrailingObjects;
30 ///
31 /// unsigned NumInts, NumDoubles;
32 /// size_t numTrailingObjects(OverloadToken<int>) const { return NumInts; }
33 /// };
34 /// \endcode
35 ///
36 /// You can access the appended arrays via 'getTrailingObjects', and
37 /// determine the size needed for allocation via
38 /// 'additionalSizeToAlloc' and 'totalSizeToAlloc'.
39 ///
40 /// All the methods implemented by this class are are intended for use
41 /// by the implementation of the class, not as part of its interface
42 /// (thus, private inheritance is suggested).
43 ///
44 //===----------------------------------------------------------------------===//
45 
46 #ifndef LLVM_SUPPORT_TRAILINGOBJECTS_H
47 #define LLVM_SUPPORT_TRAILINGOBJECTS_H
48 
49 #include "llvm/Support/AlignOf.h"
50 #include "llvm/Support/Compiler.h"
53 #include <new>
54 #include <type_traits>
55 
56 namespace llvm {
57 
58 namespace trailing_objects_internal {
59 /// Helper template to calculate the max alignment requirement for a set of
60 /// objects.
61 template <typename First, typename... Rest> class AlignmentCalcHelper {
62 private:
63  enum {
64  FirstAlignment = alignof(First),
66  };
67 
68 public:
69  enum {
70  Alignment = FirstAlignment > RestAlignment ? FirstAlignment : RestAlignment
71  };
72 };
73 
74 template <typename First> class AlignmentCalcHelper<First> {
75 public:
76  enum { Alignment = alignof(First) };
77 };
78 
79 /// The base class for TrailingObjects* classes.
81 protected:
82  /// OverloadToken's purpose is to allow specifying function overloads
83  /// for different types, without actually taking the types as
84  /// parameters. (Necessary because member function templates cannot
85  /// be specialized, so overloads must be used instead of
86  /// specialization.)
87  template <typename T> struct OverloadToken {};
88 };
89 
90 template <int Align>
92 template <>
93 class alignas(1) TrailingObjectsAligner<1> : public TrailingObjectsBase {};
94 template <>
95 class alignas(2) TrailingObjectsAligner<2> : public TrailingObjectsBase {};
96 template <>
97 class alignas(4) TrailingObjectsAligner<4> : public TrailingObjectsBase {};
98 template <>
99 class alignas(8) TrailingObjectsAligner<8> : public TrailingObjectsBase {};
100 template <>
101 class alignas(16) TrailingObjectsAligner<16> : public TrailingObjectsBase {
102 };
103 template <>
104 class alignas(32) TrailingObjectsAligner<32> : public TrailingObjectsBase {
105 };
106 
107 // Just a little helper for transforming a type pack into the same
108 // number of a different type. e.g.:
109 // ExtractSecondType<Foo..., int>::type
110 template <typename Ty1, typename Ty2> struct ExtractSecondType {
111  typedef Ty2 type;
112 };
113 
114 // TrailingObjectsImpl is somewhat complicated, because it is a
115 // recursively inheriting template, in order to handle the template
116 // varargs. Each level of inheritance picks off a single trailing type
117 // then recurses on the rest. The "Align", "BaseTy", and
118 // "TopTrailingObj" arguments are passed through unchanged through the
119 // recursion. "PrevTy" is, at each level, the type handled by the
120 // level right above it.
121 
122 template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy,
123  typename... MoreTys>
125  // The main template definition is never used -- the two
126  // specializations cover all possibilities.
127 };
128 
129 template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy,
130  typename NextTy, typename... MoreTys>
131 class TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, PrevTy, NextTy,
132  MoreTys...>
133  : public TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, NextTy,
134  MoreTys...> {
135 
136  typedef TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, NextTy, MoreTys...>
137  ParentType;
138 
139  struct RequiresRealignment {
140  static const bool value = alignof(PrevTy) < alignof(NextTy);
141  };
142 
143  static constexpr bool requiresRealignment() {
144  return RequiresRealignment::value;
145  }
146 
147 protected:
148  // Ensure the inherited getTrailingObjectsImpl is not hidden.
149  using ParentType::getTrailingObjectsImpl;
150 
151  // These two functions are helper functions for
152  // TrailingObjects::getTrailingObjects. They recurse to the left --
153  // the result for each type in the list of trailing types depends on
154  // the result of calling the function on the type to the
155  // left. However, the function for the type to the left is
156  // implemented by a *subclass* of this class, so we invoke it via
157  // the TopTrailingObj, which is, via the
158  // curiously-recurring-template-pattern, the most-derived type in
159  // this recursion, and thus, contains all the overloads.
160  static const NextTy *
161  getTrailingObjectsImpl(const BaseTy *Obj,
163  auto *Ptr = TopTrailingObj::getTrailingObjectsImpl(
165  TopTrailingObj::callNumTrailingObjects(
167 
168  if (requiresRealignment())
169  return reinterpret_cast<const NextTy *>(
170  llvm::alignAddr(Ptr, alignof(NextTy)));
171  else
172  return reinterpret_cast<const NextTy *>(Ptr);
173  }
174 
175  static NextTy *
178  auto *Ptr = TopTrailingObj::getTrailingObjectsImpl(
180  TopTrailingObj::callNumTrailingObjects(
182 
183  if (requiresRealignment())
184  return reinterpret_cast<NextTy *>(llvm::alignAddr(Ptr, alignof(NextTy)));
185  else
186  return reinterpret_cast<NextTy *>(Ptr);
187  }
188 
189  // Helper function for TrailingObjects::additionalSizeToAlloc: this
190  // function recurses to superclasses, each of which requires one
191  // fewer size_t argument, and adds its own size.
192  static constexpr size_t additionalSizeToAllocImpl(
193  size_t SizeSoFar, size_t Count1,
194  typename ExtractSecondType<MoreTys, size_t>::type... MoreCounts) {
195  return ParentType::additionalSizeToAllocImpl(
196  (requiresRealignment() ? llvm::alignTo<alignof(NextTy)>(SizeSoFar)
197  : SizeSoFar) +
198  sizeof(NextTy) * Count1,
199  MoreCounts...);
200  }
201 };
202 
203 // The base case of the TrailingObjectsImpl inheritance recursion,
204 // when there's no more trailing types.
205 template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy>
206 class TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, PrevTy>
207  : public TrailingObjectsAligner<Align> {
208 protected:
209  // This is a dummy method, only here so the "using" doesn't fail --
210  // it will never be called, because this function recurses backwards
211  // up the inheritance chain to subclasses.
212  static void getTrailingObjectsImpl();
213 
214  static constexpr size_t additionalSizeToAllocImpl(size_t SizeSoFar) {
215  return SizeSoFar;
216  }
217 
218  template <bool CheckAlignment> static void verifyTrailingObjectsAlignment() {}
219 };
220 
221 } // end namespace trailing_objects_internal
222 
223 // Finally, the main type defined in this file, the one intended for users...
224 
225 /// See the file comment for details on the usage of the
226 /// TrailingObjects type.
227 template <typename BaseTy, typename... TrailingTys>
229  trailing_objects_internal::AlignmentCalcHelper<
230  TrailingTys...>::Alignment,
231  BaseTy, TrailingObjects<BaseTy, TrailingTys...>,
232  BaseTy, TrailingTys...> {
233 
234  template <int A, typename B, typename T, typename P, typename... M>
236 
237  template <typename... Tys> class Foo {};
238 
240  trailing_objects_internal::AlignmentCalcHelper<TrailingTys...>::Alignment,
241  BaseTy, TrailingObjects<BaseTy, TrailingTys...>, BaseTy, TrailingTys...>
242  ParentType;
244 
245  using ParentType::getTrailingObjectsImpl;
246 
247  // This function contains only a static_assert BaseTy is final. The
248  // static_assert must be in a function, and not at class-level
249  // because BaseTy isn't complete at class instantiation time, but
250  // will be by the time this function is instantiated.
251  static void verifyTrailingObjectsAssertions() {
252  static_assert(std::is_final<BaseTy>(), "BaseTy must be final.");
253  }
254 
255  // These two methods are the base of the recursion for this method.
256  static const BaseTy *
257  getTrailingObjectsImpl(const BaseTy *Obj,
259  return Obj;
260  }
261 
262  static BaseTy *
263  getTrailingObjectsImpl(BaseTy *Obj,
265  return Obj;
266  }
267 
268  // callNumTrailingObjects simply calls numTrailingObjects on the
269  // provided Obj -- except when the type being queried is BaseTy
270  // itself. There is always only one of the base object, so that case
271  // is handled here. (An additional benefit of indirecting through
272  // this function is that consumers only say "friend
273  // TrailingObjects", and thus, only this class itself can call the
274  // numTrailingObjects function.)
275  static size_t
276  callNumTrailingObjects(const BaseTy *Obj,
278  return 1;
279  }
280 
281  template <typename T>
282  static size_t callNumTrailingObjects(const BaseTy *Obj,
284  return Obj->numTrailingObjects(TrailingObjectsBase::OverloadToken<T>());
285  }
286 
287 public:
288  // Make this (privately inherited) member public.
289 #ifndef _MSC_VER
290  using ParentType::OverloadToken;
291 #else
292  // MSVC bug prevents the above from working, at least up through CL
293  // 19.10.24629.
294  template <typename T>
295  using OverloadToken = typename ParentType::template OverloadToken<T>;
296 #endif
297 
298  /// Returns a pointer to the trailing object array of the given type
299  /// (which must be one of those specified in the class template). The
300  /// array may have zero or more elements in it.
301  template <typename T> const T *getTrailingObjects() const {
302  verifyTrailingObjectsAssertions();
303  // Forwards to an impl function with overloads, since member
304  // function templates can't be specialized.
305  return this->getTrailingObjectsImpl(
306  static_cast<const BaseTy *>(this),
308  }
309 
310  /// Returns a pointer to the trailing object array of the given type
311  /// (which must be one of those specified in the class template). The
312  /// array may have zero or more elements in it.
313  template <typename T> T *getTrailingObjects() {
314  verifyTrailingObjectsAssertions();
315  // Forwards to an impl function with overloads, since member
316  // function templates can't be specialized.
317  return this->getTrailingObjectsImpl(
318  static_cast<BaseTy *>(this), TrailingObjectsBase::OverloadToken<T>());
319  }
320 
321  /// Returns the size of the trailing data, if an object were
322  /// allocated with the given counts (The counts are in the same order
323  /// as the template arguments). This does not include the size of the
324  /// base object. The template arguments must be the same as those
325  /// used in the class; they are supplied here redundantly only so
326  /// that it's clear what the counts are counting in callers.
327  template <typename... Tys>
328  static constexpr typename std::enable_if<
329  std::is_same<Foo<TrailingTys...>, Foo<Tys...>>::value, size_t>::type
331  TrailingTys, size_t>::type... Counts) {
332  return ParentType::additionalSizeToAllocImpl(0, Counts...);
333  }
334 
335  /// Returns the total size of an object if it were allocated with the
336  /// given trailing object counts. This is the same as
337  /// additionalSizeToAlloc, except it *does* include the size of the base
338  /// object.
339  template <typename... Tys>
340  static constexpr typename std::enable_if<
341  std::is_same<Foo<TrailingTys...>, Foo<Tys...>>::value, size_t>::type
343  TrailingTys, size_t>::type... Counts) {
344  return sizeof(BaseTy) + ParentType::additionalSizeToAllocImpl(0, Counts...);
345  }
346 
347  /// A type where its ::with_counts template member has a ::type member
348  /// suitable for use as uninitialized storage for an object with the given
349  /// trailing object counts. The template arguments are similar to those
350  /// of additionalSizeToAlloc.
351  ///
352  /// Use with FixedSizeStorageOwner, e.g.:
353  ///
354  /// \code{.cpp}
355  ///
356  /// MyObj::FixedSizeStorage<void *>::with_counts<1u>::type myStackObjStorage;
357  /// MyObj::FixedSizeStorageOwner
358  /// myStackObjOwner(new ((void *)&myStackObjStorage) MyObj);
359  /// MyObj *const myStackObjPtr = myStackObjOwner.get();
360  ///
361  /// \endcode
362  template <typename... Tys> struct FixedSizeStorage {
363  template <size_t... Counts> struct with_counts {
364  enum { Size = totalSizeToAlloc<Tys...>(Counts...) };
365  struct type {
366  alignas(BaseTy) char buffer[Size];
367  };
368  };
369  };
370 
371  /// A type that acts as the owner for an object placed into fixed storage.
373  public:
374  FixedSizeStorageOwner(BaseTy *p) : p(p) {}
376  assert(p && "FixedSizeStorageOwner owns null?");
377  p->~BaseTy();
378  }
379 
380  BaseTy *get() { return p; }
381  const BaseTy *get() const { return p; }
382 
383  private:
386  FixedSizeStorageOwner &operator=(const FixedSizeStorageOwner &) = delete;
387  FixedSizeStorageOwner &operator=(FixedSizeStorageOwner &&) = delete;
388 
389  BaseTy *const p;
390  };
391 };
392 
393 } // end namespace llvm
394 
395 #endif
A type that acts as the owner for an object placed into fixed storage.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
This class represents lattice values for constants.
Definition: AllocatorList.h:23
A type where its ::with_counts template member has a ::type member suitable for use as uninitialized ...
static constexpr std::enable_if< std::is_same< Foo< TrailingTys... >, Foo< Tys... > >::value, size_t >::type additionalSizeToAlloc(typename trailing_objects_internal::ExtractSecondType< TrailingTys, size_t >::type... Counts)
Returns the size of the trailing data, if an object were allocated with the given counts (The counts ...
#define P(N)
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static NextTy * getTrailingObjectsImpl(BaseTy *Obj, TrailingObjectsBase::OverloadToken< NextTy >)
T * getTrailingObjects()
Returns a pointer to the trailing object array of the given type (which must be one of those specifie...
static constexpr size_t additionalSizeToAllocImpl(size_t SizeSoFar, size_t Count1, typename ExtractSecondType< MoreTys, size_t >::type... MoreCounts)
const T * getTrailingObjects() const
Returns a pointer to the trailing object array of the given type (which must be one of those specifie...
See the file comment for details on the usage of the TrailingObjects type.
static constexpr std::enable_if< std::is_same< Foo< TrailingTys... >, Foo< Tys... > >::value, size_t >::type totalSizeToAlloc(typename trailing_objects_internal::ExtractSecondType< TrailingTys, size_t >::type... Counts)
Returns the total size of an object if it were allocated with the given trailing object counts...
uintptr_t alignAddr(const void *Addr, size_t Alignment)
Aligns Addr to Alignment bytes, rounding up.
Definition: MathExtras.h:627
The base class for TrailingObjects* classes.
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition: Alignment.h:133
uint32_t Size
Definition: Profile.cpp:46
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static const NextTy * getTrailingObjectsImpl(const BaseTy *Obj, TrailingObjectsBase::OverloadToken< NextTy >)
Helper template to calculate the max alignment requirement for a set of objects.
OverloadToken&#39;s purpose is to allow specifying function overloads for different types, without actually taking the types as parameters.