Home | History | Annotate | Download | only in Support
      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, as well as asserts that
     20 /// the alignment of the classes involved are appropriate for the
     21 /// usage. Additionally, it ensures that the base type is final --
     22 /// deriving from a class that expects data appended immediately after
     23 /// it is typically not safe.
     24 ///
     25 /// Users are expected to derive from this template, and provide
     26 /// numTrailingObjects implementations for each trailing type,
     27 /// e.g. like this sample:
     28 ///
     29 /// \code
     30 /// class VarLengthObj : private TrailingObjects<VarLengthObj, int, double> {
     31 ///   friend TrailingObjects;
     32 ///
     33 ///   unsigned NumInts, NumDoubles;
     34 ///   size_t numTrailingObjects(OverloadToken<int>) const { return NumInts; }
     35 ///   size_t numTrailingObjects(OverloadToken<double>) const {
     36 ///     return NumDoubles;
     37 ///   }
     38 ///  };
     39 /// \endcode
     40 ///
     41 /// You can access the appended arrays via 'getTrailingObjects', and
     42 /// determine the size needed for allocation via
     43 /// 'additionalSizeToAlloc' and 'totalSizeToAlloc'.
     44 ///
     45 /// All the methods implemented by this class are are intended for use
     46 /// by the implementation of the class, not as part of its interface
     47 /// (thus, private inheritance is suggested).
     48 ///
     49 //===----------------------------------------------------------------------===//
     50 
     51 #ifndef LLVM_SUPPORT_TRAILINGOBJECTS_H
     52 #define LLVM_SUPPORT_TRAILINGOBJECTS_H
     53 
     54 #include <new>
     55 #include <type_traits>
     56 #include "llvm/Support/AlignOf.h"
     57 #include "llvm/Support/Compiler.h"
     58 #include "llvm/Support/type_traits.h"
     59 
     60 namespace llvm {
     61 
     62 namespace trailing_objects_internal {
     63 /// Helper template to calculate the max alignment requirement for a set of
     64 /// objects.
     65 template <typename First, typename... Rest> class AlignmentCalcHelper {
     66 private:
     67   enum {
     68     FirstAlignment = AlignOf<First>::Alignment,
     69     RestAlignment = AlignmentCalcHelper<Rest...>::Alignment,
     70   };
     71 
     72 public:
     73   enum {
     74     Alignment = FirstAlignment > RestAlignment ? FirstAlignment : RestAlignment
     75   };
     76 };
     77 
     78 template <typename First> class AlignmentCalcHelper<First> {
     79 public:
     80   enum { Alignment = AlignOf<First>::Alignment };
     81 };
     82 
     83 /// The base class for TrailingObjects* classes.
     84 class TrailingObjectsBase {
     85 protected:
     86   /// OverloadToken's purpose is to allow specifying function overloads
     87   /// for different types, without actually taking the types as
     88   /// parameters. (Necessary because member function templates cannot
     89   /// be specialized, so overloads must be used instead of
     90   /// specialization.)
     91   template <typename T> struct OverloadToken {};
     92 };
     93 
     94 /// This helper template works-around MSVC 2013's lack of useful
     95 /// alignas() support. The argument to LLVM_ALIGNAS(), in MSVC, is
     96 /// required to be a literal integer. But, you *can* use template
     97 /// specialization to select between a bunch of different LLVM_ALIGNAS
     98 /// expressions...
     99 template <int Align>
    100 class TrailingObjectsAligner : public TrailingObjectsBase {};
    101 template <>
    102 class LLVM_ALIGNAS(1) TrailingObjectsAligner<1> : public TrailingObjectsBase {};
    103 template <>
    104 class LLVM_ALIGNAS(2) TrailingObjectsAligner<2> : public TrailingObjectsBase {};
    105 template <>
    106 class LLVM_ALIGNAS(4) TrailingObjectsAligner<4> : public TrailingObjectsBase {};
    107 template <>
    108 class LLVM_ALIGNAS(8) TrailingObjectsAligner<8> : public TrailingObjectsBase {};
    109 template <>
    110 class LLVM_ALIGNAS(16) TrailingObjectsAligner<16> : public TrailingObjectsBase {
    111 };
    112 template <>
    113 class LLVM_ALIGNAS(32) TrailingObjectsAligner<32> : public TrailingObjectsBase {
    114 };
    115 
    116 // Just a little helper for transforming a type pack into the same
    117 // number of a different type. e.g.:
    118 //   ExtractSecondType<Foo..., int>::type
    119 template <typename Ty1, typename Ty2> struct ExtractSecondType {
    120   typedef Ty2 type;
    121 };
    122 
    123 // TrailingObjectsImpl is somewhat complicated, because it is a
    124 // recursively inheriting template, in order to handle the template
    125 // varargs. Each level of inheritance picks off a single trailing type
    126 // then recurses on the rest. The "Align", "BaseTy", and
    127 // "TopTrailingObj" arguments are passed through unchanged through the
    128 // recursion. "PrevTy" is, at each level, the type handled by the
    129 // level right above it.
    130 
    131 template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy,
    132           typename... MoreTys>
    133 struct TrailingObjectsImpl {
    134   // The main template definition is never used -- the two
    135   // specializations cover all possibilities.
    136 };
    137 
    138 template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy,
    139           typename NextTy, typename... MoreTys>
    140 struct TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, PrevTy, NextTy,
    141                            MoreTys...>
    142     : public TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, NextTy,
    143                                  MoreTys...> {
    144 
    145   typedef TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, NextTy, MoreTys...>
    146       ParentType;
    147 
    148   // Ensure the methods we inherit are not hidden.
    149   using ParentType::getTrailingObjectsImpl;
    150   using ParentType::additionalSizeToAllocImpl;
    151 
    152   static void verifyTrailingObjectsAssertions() {
    153     static_assert(llvm::AlignOf<PrevTy>::Alignment >=
    154                       llvm::AlignOf<NextTy>::Alignment,
    155                   "A trailing object requires more alignment than the previous "
    156                   "trailing object provides");
    157 
    158     ParentType::verifyTrailingObjectsAssertions();
    159   }
    160 
    161   // These two functions are helper functions for
    162   // TrailingObjects::getTrailingObjects. They recurse to the left --
    163   // the result for each type in the list of trailing types depends on
    164   // the result of calling the function on the type to the
    165   // left. However, the function for the type to the left is
    166   // implemented by a *subclass* of this class, so we invoke it via
    167   // the TopTrailingObj, which is, via the
    168   // curiously-recurring-template-pattern, the most-derived type in
    169   // this recursion, and thus, contains all the overloads.
    170   static const NextTy *
    171   getTrailingObjectsImpl(const BaseTy *Obj,
    172                          TrailingObjectsBase::OverloadToken<NextTy>) {
    173     return reinterpret_cast<const NextTy *>(
    174         TopTrailingObj::getTrailingObjectsImpl(
    175             Obj, TrailingObjectsBase::OverloadToken<PrevTy>()) +
    176         TopTrailingObj::callNumTrailingObjects(
    177             Obj, TrailingObjectsBase::OverloadToken<PrevTy>()));
    178   }
    179 
    180   static NextTy *
    181   getTrailingObjectsImpl(BaseTy *Obj,
    182                          TrailingObjectsBase::OverloadToken<NextTy>) {
    183     return reinterpret_cast<NextTy *>(
    184         TopTrailingObj::getTrailingObjectsImpl(
    185             Obj, TrailingObjectsBase::OverloadToken<PrevTy>()) +
    186         TopTrailingObj::callNumTrailingObjects(
    187             Obj, TrailingObjectsBase::OverloadToken<PrevTy>()));
    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 LLVM_CONSTEXPR size_t additionalSizeToAllocImpl(
    194       size_t Count1,
    195       typename ExtractSecondType<MoreTys, size_t>::type... MoreCounts) {
    196     return sizeof(NextTy) * Count1 + additionalSizeToAllocImpl(MoreCounts...);
    197   }
    198 };
    199 
    200 // The base case of the TrailingObjectsImpl inheritance recursion,
    201 // when there's no more trailing types.
    202 template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy>
    203 struct TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, PrevTy>
    204     : public TrailingObjectsAligner<Align> {
    205   // This is a dummy method, only here so the "using" doesn't fail --
    206   // it will never be called, because this function recurses backwards
    207   // up the inheritance chain to subclasses.
    208   static void getTrailingObjectsImpl();
    209 
    210   static LLVM_CONSTEXPR size_t additionalSizeToAllocImpl() { return 0; }
    211 
    212   static void verifyTrailingObjectsAssertions() {}
    213 };
    214 
    215 } // end namespace trailing_objects_internal
    216 
    217 // Finally, the main type defined in this file, the one intended for users...
    218 
    219 /// See the file comment for details on the usage of the
    220 /// TrailingObjects type.
    221 template <typename BaseTy, typename... TrailingTys>
    222 class TrailingObjects : private trailing_objects_internal::TrailingObjectsImpl<
    223                             trailing_objects_internal::AlignmentCalcHelper<
    224                                 TrailingTys...>::Alignment,
    225                             BaseTy, TrailingObjects<BaseTy, TrailingTys...>,
    226                             BaseTy, TrailingTys...> {
    227 
    228   template <int A, typename B, typename T, typename P, typename... M>
    229   friend struct trailing_objects_internal::TrailingObjectsImpl;
    230 
    231   template <typename... Tys> class Foo {};
    232 
    233   typedef trailing_objects_internal::TrailingObjectsImpl<
    234       trailing_objects_internal::AlignmentCalcHelper<TrailingTys...>::Alignment,
    235       BaseTy, TrailingObjects<BaseTy, TrailingTys...>, BaseTy, TrailingTys...>
    236       ParentType;
    237   using TrailingObjectsBase = trailing_objects_internal::TrailingObjectsBase;
    238 
    239   using ParentType::getTrailingObjectsImpl;
    240 
    241   // Contains static_assert statements for the alignment of the
    242   // types. Must not be at class-level, because BaseTy isn't complete
    243   // at class instantiation time, but will be by the time this
    244   // function is instantiated. Recurses through the superclasses.
    245   static void verifyTrailingObjectsAssertions() {
    246 #ifdef LLVM_IS_FINAL
    247     static_assert(LLVM_IS_FINAL(BaseTy), "BaseTy must be final.");
    248 #endif
    249     ParentType::verifyTrailingObjectsAssertions();
    250   }
    251 
    252   // These two methods are the base of the recursion for this method.
    253   static const BaseTy *
    254   getTrailingObjectsImpl(const BaseTy *Obj,
    255                          TrailingObjectsBase::OverloadToken<BaseTy>) {
    256     return Obj;
    257   }
    258 
    259   static BaseTy *
    260   getTrailingObjectsImpl(BaseTy *Obj,
    261                          TrailingObjectsBase::OverloadToken<BaseTy>) {
    262     return Obj;
    263   }
    264 
    265   // callNumTrailingObjects simply calls numTrailingObjects on the
    266   // provided Obj -- except when the type being queried is BaseTy
    267   // itself. There is always only one of the base object, so that case
    268   // is handled here. (An additional benefit of indirecting through
    269   // this function is that consumers only say "friend
    270   // TrailingObjects", and thus, only this class itself can call the
    271   // numTrailingObjects function.)
    272   static size_t
    273   callNumTrailingObjects(const BaseTy *Obj,
    274                          TrailingObjectsBase::OverloadToken<BaseTy>) {
    275     return 1;
    276   }
    277 
    278   template <typename T>
    279   static size_t callNumTrailingObjects(const BaseTy *Obj,
    280                                        TrailingObjectsBase::OverloadToken<T>) {
    281     return Obj->numTrailingObjects(TrailingObjectsBase::OverloadToken<T>());
    282   }
    283 
    284 public:
    285   // make this (privately inherited) class public.
    286   using ParentType::OverloadToken;
    287 
    288   /// Returns a pointer to the trailing object array of the given type
    289   /// (which must be one of those specified in the class template). The
    290   /// array may have zero or more elements in it.
    291   template <typename T> const T *getTrailingObjects() const {
    292     verifyTrailingObjectsAssertions();
    293     // Forwards to an impl function with overloads, since member
    294     // function templates can't be specialized.
    295     return this->getTrailingObjectsImpl(
    296         static_cast<const BaseTy *>(this),
    297         TrailingObjectsBase::OverloadToken<T>());
    298   }
    299 
    300   /// Returns a pointer to the trailing object array of the given type
    301   /// (which must be one of those specified in the class template). The
    302   /// array may have zero or more elements in it.
    303   template <typename T> T *getTrailingObjects() {
    304     verifyTrailingObjectsAssertions();
    305     // Forwards to an impl function with overloads, since member
    306     // function templates can't be specialized.
    307     return this->getTrailingObjectsImpl(
    308         static_cast<BaseTy *>(this), TrailingObjectsBase::OverloadToken<T>());
    309   }
    310 
    311   /// Returns the size of the trailing data, if an object were
    312   /// allocated with the given counts (The counts are in the same order
    313   /// as the template arguments). This does not include the size of the
    314   /// base object.  The template arguments must be the same as those
    315   /// used in the class; they are supplied here redundantly only so
    316   /// that it's clear what the counts are counting in callers.
    317   template <typename... Tys>
    318   static LLVM_CONSTEXPR typename std::enable_if<
    319       std::is_same<Foo<TrailingTys...>, Foo<Tys...>>::value, size_t>::type
    320       additionalSizeToAlloc(
    321           typename trailing_objects_internal::ExtractSecondType<
    322               TrailingTys, size_t>::type... Counts) {
    323     return ParentType::additionalSizeToAllocImpl(Counts...);
    324   }
    325 
    326   /// Returns the total size of an object if it were allocated with the
    327   /// given trailing object counts. This is the same as
    328   /// additionalSizeToAlloc, except it *does* include the size of the base
    329   /// object.
    330   template <typename... Tys>
    331   static LLVM_CONSTEXPR typename std::enable_if<
    332       std::is_same<Foo<TrailingTys...>, Foo<Tys...>>::value, size_t>::type
    333       totalSizeToAlloc(typename trailing_objects_internal::ExtractSecondType<
    334                        TrailingTys, size_t>::type... Counts) {
    335     return sizeof(BaseTy) + ParentType::additionalSizeToAllocImpl(Counts...);
    336   }
    337 };
    338 
    339 } // end namespace llvm
    340 
    341 #endif
    342