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