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/Alignment.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 template <int Align>
93 template <>
94 class alignas(1) TrailingObjectsAligner<1> : public TrailingObjectsBase {};
95 template <>
96 class alignas(2) TrailingObjectsAligner<2> : public TrailingObjectsBase {};
97 template <>
98 class alignas(4) TrailingObjectsAligner<4> : public TrailingObjectsBase {};
99 template <>
100 class alignas(8) TrailingObjectsAligner<8> : public TrailingObjectsBase {};
101 template <>
102 class alignas(16) TrailingObjectsAligner<16> : public TrailingObjectsBase {
103 };
104 template <>
105 class alignas(32) TrailingObjectsAligner<32> : public TrailingObjectsBase {
106 };
107 
108 // Just a little helper for transforming a type pack into the same
109 // number of a different type. e.g.:
110 // ExtractSecondType<Foo..., int>::type
111 template <typename Ty1, typename Ty2> struct ExtractSecondType {
112  typedef Ty2 type;
113 };
114 
115 // TrailingObjectsImpl is somewhat complicated, because it is a
116 // recursively inheriting template, in order to handle the template
117 // varargs. Each level of inheritance picks off a single trailing type
118 // then recurses on the rest. The "Align", "BaseTy", and
119 // "TopTrailingObj" arguments are passed through unchanged through the
120 // recursion. "PrevTy" is, at each level, the type handled by the
121 // level right above it.
122 
123 template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy,
124  typename... MoreTys>
126  // The main template definition is never used -- the two
127  // specializations cover all possibilities.
128 };
129 
130 template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy,
131  typename NextTy, typename... MoreTys>
132 class TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, PrevTy, NextTy,
133  MoreTys...>
134  : public TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, NextTy,
135  MoreTys...> {
136 
137  typedef TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, NextTy, MoreTys...>
138  ParentType;
139 
140  struct RequiresRealignment {
141  static const bool value = alignof(PrevTy) < alignof(NextTy);
142  };
143 
144  static constexpr bool requiresRealignment() {
145  return RequiresRealignment::value;
146  }
147 
148 protected:
149  // Ensure the inherited getTrailingObjectsImpl is not hidden.
150  using ParentType::getTrailingObjectsImpl;
151 
152  // These two functions are helper functions for
153  // TrailingObjects::getTrailingObjects. They recurse to the left --
154  // the result for each type in the list of trailing types depends on
155  // the result of calling the function on the type to the
156  // left. However, the function for the type to the left is
157  // implemented by a *subclass* of this class, so we invoke it via
158  // the TopTrailingObj, which is, via the
159  // curiously-recurring-template-pattern, the most-derived type in
160  // this recursion, and thus, contains all the overloads.
161  static const NextTy *
162  getTrailingObjectsImpl(const BaseTy *Obj,
164  auto *Ptr = TopTrailingObj::getTrailingObjectsImpl(
166  TopTrailingObj::callNumTrailingObjects(
168 
169  if (requiresRealignment())
170  return reinterpret_cast<const NextTy *>(
171  alignAddr(Ptr, Align::Of<NextTy>()));
172  else
173  return reinterpret_cast<const NextTy *>(Ptr);
174  }
175 
176  static NextTy *
179  auto *Ptr = TopTrailingObj::getTrailingObjectsImpl(
181  TopTrailingObj::callNumTrailingObjects(
183 
184  if (requiresRealignment())
185  return reinterpret_cast<NextTy *>(alignAddr(Ptr, Align::Of<NextTy>()));
186  else
187  return reinterpret_cast<NextTy *>(Ptr);
188  }
189 
190  // Helper function for TrailingObjects::additionalSizeToAlloc: this
191  // function recurses to superclasses, each of which requires one
192  // fewer size_t argument, and adds its own size.
193  static constexpr size_t additionalSizeToAllocImpl(
194  size_t SizeSoFar, size_t Count1,
195  typename ExtractSecondType<MoreTys, size_t>::type... MoreCounts) {
196  return ParentType::additionalSizeToAllocImpl(
197  (requiresRealignment() ? llvm::alignTo<alignof(NextTy)>(SizeSoFar)
198  : SizeSoFar) +
199  sizeof(NextTy) * Count1,
200  MoreCounts...);
201  }
202 };
203 
204 // The base case of the TrailingObjectsImpl inheritance recursion,
205 // when there's no more trailing types.
206 template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy>
207 class TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, PrevTy>
208  : public TrailingObjectsAligner<Align> {
209 protected:
210  // This is a dummy method, only here so the "using" doesn't fail --
211  // it will never be called, because this function recurses backwards
212  // up the inheritance chain to subclasses.
213  static void getTrailingObjectsImpl();
214 
215  static constexpr size_t additionalSizeToAllocImpl(size_t SizeSoFar) {
216  return SizeSoFar;
217  }
218 
219  template <bool CheckAlignment> static void verifyTrailingObjectsAlignment() {}
220 };
221 
222 } // end namespace trailing_objects_internal
223 
224 // Finally, the main type defined in this file, the one intended for users...
225 
226 /// See the file comment for details on the usage of the
227 /// TrailingObjects type.
228 template <typename BaseTy, typename... TrailingTys>
230  trailing_objects_internal::AlignmentCalcHelper<
231  TrailingTys...>::Alignment,
232  BaseTy, TrailingObjects<BaseTy, TrailingTys...>,
233  BaseTy, TrailingTys...> {
234 
235  template <int A, typename B, typename T, typename P, typename... M>
237 
238  template <typename... Tys> class Foo {};
239 
241  trailing_objects_internal::AlignmentCalcHelper<TrailingTys...>::Alignment,
242  BaseTy, TrailingObjects<BaseTy, TrailingTys...>, BaseTy, TrailingTys...>
243  ParentType;
245 
246  using ParentType::getTrailingObjectsImpl;
247 
248  // This function contains only a static_assert BaseTy is final. The
249  // static_assert must be in a function, and not at class-level
250  // because BaseTy isn't complete at class instantiation time, but
251  // will be by the time this function is instantiated.
252  static void verifyTrailingObjectsAssertions() {
253  static_assert(std::is_final<BaseTy>(), "BaseTy must be final.");
254  }
255 
256  // These two methods are the base of the recursion for this method.
257  static const BaseTy *
258  getTrailingObjectsImpl(const BaseTy *Obj,
260  return Obj;
261  }
262 
263  static BaseTy *
264  getTrailingObjectsImpl(BaseTy *Obj,
266  return Obj;
267  }
268 
269  // callNumTrailingObjects simply calls numTrailingObjects on the
270  // provided Obj -- except when the type being queried is BaseTy
271  // itself. There is always only one of the base object, so that case
272  // is handled here. (An additional benefit of indirecting through
273  // this function is that consumers only say "friend
274  // TrailingObjects", and thus, only this class itself can call the
275  // numTrailingObjects function.)
276  static size_t
277  callNumTrailingObjects(const BaseTy *Obj,
279  return 1;
280  }
281 
282  template <typename T>
283  static size_t callNumTrailingObjects(const BaseTy *Obj,
285  return Obj->numTrailingObjects(TrailingObjectsBase::OverloadToken<T>());
286  }
287 
288 public:
289  // Make this (privately inherited) member public.
290 #ifndef _MSC_VER
291  using ParentType::OverloadToken;
292 #else
293  // MSVC bug prevents the above from working, at least up through CL
294  // 19.10.24629.
295  template <typename T>
296  using OverloadToken = typename ParentType::template OverloadToken<T>;
297 #endif
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...) };
366  struct type {
367  alignas(BaseTy) char buffer[Size];
368  };
369  };
370  };
371 
372  /// A type that acts as the owner for an object placed into fixed storage.
374  public:
375  FixedSizeStorageOwner(BaseTy *p) : p(p) {}
377  assert(p && "FixedSizeStorageOwner owns null?");
378  p->~BaseTy();
379  }
380 
381  BaseTy *get() { return p; }
382  const BaseTy *get() const { return p; }
383 
384  private:
387  FixedSizeStorageOwner &operator=(const FixedSizeStorageOwner &) = delete;
388  FixedSizeStorageOwner &operator=(FixedSizeStorageOwner &&) = delete;
389 
390  BaseTy *const p;
391  };
392 };
393 
394 } // end namespace llvm
395 
396 #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 ...
uintptr_t alignAddr(const void *Addr, Align Alignment)
Aligns Addr to Alignment bytes, rounding up.
Definition: Alignment.h:184
#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...
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:163
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.