| 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" | 
| 52 | #include "llvm/Support/MathExtras.h" | 
| 53 | #include "llvm/Support/type_traits.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), | 
| 66 |     RestAlignment = AlignmentCalcHelper<Rest...>::Alignment, | 
| 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. | 
| 81 | class TrailingObjectsBase { | 
| 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 | // Just a little helper for transforming a type pack into the same | 
| 92 | // number of a different type. e.g.: | 
| 93 | //   ExtractSecondType<Foo..., int>::type | 
| 94 | template <typename Ty1, typename Ty2> struct  { | 
| 95 |   typedef Ty2 ; | 
| 96 | }; | 
| 97 |  | 
| 98 | // TrailingObjectsImpl is somewhat complicated, because it is a | 
| 99 | // recursively inheriting template, in order to handle the template | 
| 100 | // varargs. Each level of inheritance picks off a single trailing type | 
| 101 | // then recurses on the rest. The "Align", "BaseTy", and | 
| 102 | // "TopTrailingObj" arguments are passed through unchanged through the | 
| 103 | // recursion. "PrevTy" is, at each level, the type handled by the | 
| 104 | // level right above it. | 
| 105 |  | 
| 106 | template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy, | 
| 107 |           typename... MoreTys> | 
| 108 | class TrailingObjectsImpl { | 
| 109 |   // The main template definition is never used -- the two | 
| 110 |   // specializations cover all possibilities. | 
| 111 | }; | 
| 112 |  | 
| 113 | template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy, | 
| 114 |           typename NextTy, typename... MoreTys> | 
| 115 | class TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, PrevTy, NextTy, | 
| 116 |                           MoreTys...> | 
| 117 |     : public TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, NextTy, | 
| 118 |                                  MoreTys...> { | 
| 119 |  | 
| 120 |   typedef TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, NextTy, MoreTys...> | 
| 121 |       ParentType; | 
| 122 |  | 
| 123 |   struct RequiresRealignment { | 
| 124 |     static const bool value = alignof(PrevTy) < alignof(NextTy); | 
| 125 |   }; | 
| 126 |  | 
| 127 |   static constexpr bool requiresRealignment() { | 
| 128 |     return RequiresRealignment::value; | 
| 129 |   } | 
| 130 |  | 
| 131 | protected: | 
| 132 |   // Ensure the inherited getTrailingObjectsImpl is not hidden. | 
| 133 |   using ParentType::getTrailingObjectsImpl; | 
| 134 |  | 
| 135 |   // These two functions are helper functions for | 
| 136 |   // TrailingObjects::getTrailingObjects. They recurse to the left -- | 
| 137 |   // the result for each type in the list of trailing types depends on | 
| 138 |   // the result of calling the function on the type to the | 
| 139 |   // left. However, the function for the type to the left is | 
| 140 |   // implemented by a *subclass* of this class, so we invoke it via | 
| 141 |   // the TopTrailingObj, which is, via the | 
| 142 |   // curiously-recurring-template-pattern, the most-derived type in | 
| 143 |   // this recursion, and thus, contains all the overloads. | 
| 144 |   static const NextTy * | 
| 145 |   getTrailingObjectsImpl(const BaseTy *Obj, | 
| 146 |                          TrailingObjectsBase::OverloadToken<NextTy>) { | 
| 147 |     auto *Ptr = TopTrailingObj::getTrailingObjectsImpl( | 
| 148 |                     Obj, TrailingObjectsBase::OverloadToken<PrevTy>()) + | 
| 149 |                 TopTrailingObj::callNumTrailingObjects( | 
| 150 |                     Obj, TrailingObjectsBase::OverloadToken<PrevTy>()); | 
| 151 |  | 
| 152 |     if (requiresRealignment()) | 
| 153 |       return reinterpret_cast<const NextTy *>( | 
| 154 |           alignAddr(Ptr, Align::Of<NextTy>())); | 
| 155 |     else | 
| 156 |       return reinterpret_cast<const NextTy *>(Ptr); | 
| 157 |   } | 
| 158 |  | 
| 159 |   static NextTy * | 
| 160 |   getTrailingObjectsImpl(BaseTy *Obj, | 
| 161 |                          TrailingObjectsBase::OverloadToken<NextTy>) { | 
| 162 |     auto *Ptr = TopTrailingObj::getTrailingObjectsImpl( | 
| 163 |                     Obj, TrailingObjectsBase::OverloadToken<PrevTy>()) + | 
| 164 |                 TopTrailingObj::callNumTrailingObjects( | 
| 165 |                     Obj, TrailingObjectsBase::OverloadToken<PrevTy>()); | 
| 166 |  | 
| 167 |     if (requiresRealignment()) | 
| 168 |       return reinterpret_cast<NextTy *>(alignAddr(Ptr, Align::Of<NextTy>())); | 
| 169 |     else | 
| 170 |       return reinterpret_cast<NextTy *>(Ptr); | 
| 171 |   } | 
| 172 |  | 
| 173 |   // Helper function for TrailingObjects::additionalSizeToAlloc: this | 
| 174 |   // function recurses to superclasses, each of which requires one | 
| 175 |   // fewer size_t argument, and adds its own size. | 
| 176 |   static constexpr size_t ( | 
| 177 |       size_t SizeSoFar, size_t Count1, | 
| 178 |       typename ExtractSecondType<MoreTys, size_t>::type... MoreCounts) { | 
| 179 |     return ParentType::additionalSizeToAllocImpl( | 
| 180 |         (requiresRealignment() ? llvm::alignTo<alignof(NextTy)>(SizeSoFar) | 
| 181 |                                : SizeSoFar) + | 
| 182 |             sizeof(NextTy) * Count1, | 
| 183 |         MoreCounts...); | 
| 184 |   } | 
| 185 | }; | 
| 186 |  | 
| 187 | // The base case of the TrailingObjectsImpl inheritance recursion, | 
| 188 | // when there's no more trailing types. | 
| 189 | template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy> | 
| 190 | class alignas(Align) TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, PrevTy> | 
| 191 |     : public TrailingObjectsBase { | 
| 192 | protected: | 
| 193 |   // This is a dummy method, only here so the "using" doesn't fail -- | 
| 194 |   // it will never be called, because this function recurses backwards | 
| 195 |   // up the inheritance chain to subclasses. | 
| 196 |   static void getTrailingObjectsImpl(); | 
| 197 |  | 
| 198 |   static constexpr size_t additionalSizeToAllocImpl(size_t SizeSoFar) { | 
| 199 |     return SizeSoFar; | 
| 200 |   } | 
| 201 |  | 
| 202 |   template <bool CheckAlignment> static void verifyTrailingObjectsAlignment() {} | 
| 203 | }; | 
| 204 |  | 
| 205 | } // end namespace trailing_objects_internal | 
| 206 |  | 
| 207 | // Finally, the main type defined in this file, the one intended for users... | 
| 208 |  | 
| 209 | /// See the file comment for details on the usage of the | 
| 210 | /// TrailingObjects type. | 
| 211 | template <typename BaseTy, typename... TrailingTys> | 
| 212 | class TrailingObjects : private trailing_objects_internal::TrailingObjectsImpl< | 
| 213 |                             trailing_objects_internal::AlignmentCalcHelper< | 
| 214 |                                 TrailingTys...>::Alignment, | 
| 215 |                             BaseTy, TrailingObjects<BaseTy, TrailingTys...>, | 
| 216 |                             BaseTy, TrailingTys...> { | 
| 217 |  | 
| 218 |   template <int A, typename B, typename T, typename P, typename... M> | 
| 219 |   friend class trailing_objects_internal::TrailingObjectsImpl; | 
| 220 |  | 
| 221 |   template <typename... Tys> class Foo {}; | 
| 222 |  | 
| 223 |   typedef trailing_objects_internal::TrailingObjectsImpl< | 
| 224 |       trailing_objects_internal::AlignmentCalcHelper<TrailingTys...>::Alignment, | 
| 225 |       BaseTy, TrailingObjects<BaseTy, TrailingTys...>, BaseTy, TrailingTys...> | 
| 226 |       ParentType; | 
| 227 |   using TrailingObjectsBase = trailing_objects_internal::TrailingObjectsBase; | 
| 228 |  | 
| 229 |   using ParentType::getTrailingObjectsImpl; | 
| 230 |  | 
| 231 |   // This function contains only a static_assert BaseTy is final. The | 
| 232 |   // static_assert must be in a function, and not at class-level | 
| 233 |   // because BaseTy isn't complete at class instantiation time, but | 
| 234 |   // will be by the time this function is instantiated. | 
| 235 |   static void verifyTrailingObjectsAssertions() { | 
| 236 |     static_assert(std::is_final<BaseTy>(), "BaseTy must be final." ); | 
| 237 |   } | 
| 238 |  | 
| 239 |   // These two methods are the base of the recursion for this method. | 
| 240 |   static const BaseTy * | 
| 241 |   getTrailingObjectsImpl(const BaseTy *Obj, | 
| 242 |                          TrailingObjectsBase::OverloadToken<BaseTy>) { | 
| 243 |     return Obj; | 
| 244 |   } | 
| 245 |  | 
| 246 |   static BaseTy * | 
| 247 |   getTrailingObjectsImpl(BaseTy *Obj, | 
| 248 |                          TrailingObjectsBase::OverloadToken<BaseTy>) { | 
| 249 |     return Obj; | 
| 250 |   } | 
| 251 |  | 
| 252 |   // callNumTrailingObjects simply calls numTrailingObjects on the | 
| 253 |   // provided Obj -- except when the type being queried is BaseTy | 
| 254 |   // itself. There is always only one of the base object, so that case | 
| 255 |   // is handled here. (An additional benefit of indirecting through | 
| 256 |   // this function is that consumers only say "friend | 
| 257 |   // TrailingObjects", and thus, only this class itself can call the | 
| 258 |   // numTrailingObjects function.) | 
| 259 |   static size_t | 
| 260 |   callNumTrailingObjects(const BaseTy *Obj, | 
| 261 |                          TrailingObjectsBase::OverloadToken<BaseTy>) { | 
| 262 |     return 1; | 
| 263 |   } | 
| 264 |  | 
| 265 |   template <typename T> | 
| 266 |   static size_t callNumTrailingObjects(const BaseTy *Obj, | 
| 267 |                                        TrailingObjectsBase::OverloadToken<T>) { | 
| 268 |     return Obj->numTrailingObjects(TrailingObjectsBase::OverloadToken<T>()); | 
| 269 |   } | 
| 270 |  | 
| 271 | public: | 
| 272 |   // Make this (privately inherited) member public. | 
| 273 | #ifndef _MSC_VER | 
| 274 |   using ParentType::OverloadToken; | 
| 275 | #else | 
| 276 |   // An MSVC bug prevents the above from working, (last tested at CL version | 
| 277 |   // 19.28). "Class5" in TrailingObjectsTest.cpp tests the problematic case. | 
| 278 |   template <typename T> | 
| 279 |   using OverloadToken = typename ParentType::template OverloadToken<T>; | 
| 280 | #endif | 
| 281 |  | 
| 282 |   /// Returns a pointer to the trailing object array of the given type | 
| 283 |   /// (which must be one of those specified in the class template). The | 
| 284 |   /// array may have zero or more elements in it. | 
| 285 |   template <typename T> const T *getTrailingObjects() const { | 
| 286 |     verifyTrailingObjectsAssertions(); | 
| 287 |     // Forwards to an impl function with overloads, since member | 
| 288 |     // function templates can't be specialized. | 
| 289 |     return this->getTrailingObjectsImpl( | 
| 290 |         static_cast<const BaseTy *>(this), | 
| 291 |         TrailingObjectsBase::OverloadToken<T>()); | 
| 292 |   } | 
| 293 |  | 
| 294 |   /// Returns a pointer to the trailing object array of the given type | 
| 295 |   /// (which must be one of those specified in the class template). The | 
| 296 |   /// array may have zero or more elements in it. | 
| 297 |   template <typename T> T *getTrailingObjects() { | 
| 298 |     verifyTrailingObjectsAssertions(); | 
| 299 |     // Forwards to an impl function with overloads, since member | 
| 300 |     // function templates can't be specialized. | 
| 301 |     return this->getTrailingObjectsImpl( | 
| 302 |         static_cast<BaseTy *>(this), TrailingObjectsBase::OverloadToken<T>()); | 
| 303 |   } | 
| 304 |  | 
| 305 |   /// Returns the size of the trailing data, if an object were | 
| 306 |   /// allocated with the given counts (The counts are in the same order | 
| 307 |   /// as the template arguments). This does not include the size of the | 
| 308 |   /// base object.  The template arguments must be the same as those | 
| 309 |   /// used in the class; they are supplied here redundantly only so | 
| 310 |   /// that it's clear what the counts are counting in callers. | 
| 311 |   template <typename... Tys> | 
| 312 |   static constexpr std::enable_if_t< | 
| 313 |       std::is_same_v<Foo<TrailingTys...>, Foo<Tys...>>, size_t> | 
| 314 |   (typename trailing_objects_internal::ExtractSecondType< | 
| 315 |                         TrailingTys, size_t>::type... Counts) { | 
| 316 |     return ParentType::additionalSizeToAllocImpl(0, Counts...); | 
| 317 |   } | 
| 318 |  | 
| 319 |   /// Returns the total size of an object if it were allocated with the | 
| 320 |   /// given trailing object counts. This is the same as | 
| 321 |   /// additionalSizeToAlloc, except it *does* include the size of the base | 
| 322 |   /// object. | 
| 323 |   template <typename... Tys> | 
| 324 |   static constexpr std::enable_if_t< | 
| 325 |       std::is_same_v<Foo<TrailingTys...>, Foo<Tys...>>, size_t> | 
| 326 |   (typename trailing_objects_internal::ExtractSecondType< | 
| 327 |                    TrailingTys, size_t>::type... Counts) { | 
| 328 |     return sizeof(BaseTy) + ParentType::additionalSizeToAllocImpl(0, Counts...); | 
| 329 |   } | 
| 330 |  | 
| 331 |   TrailingObjects() = default; | 
| 332 |   TrailingObjects(const TrailingObjects &) = delete; | 
| 333 |   TrailingObjects(TrailingObjects &&) = delete; | 
| 334 |   TrailingObjects &operator=(const TrailingObjects &) = delete; | 
| 335 |   TrailingObjects &operator=(TrailingObjects &&) = delete; | 
| 336 |  | 
| 337 |   /// A type where its ::with_counts template member has a ::type member | 
| 338 |   /// suitable for use as uninitialized storage for an object with the given | 
| 339 |   /// trailing object counts. The template arguments are similar to those | 
| 340 |   /// of additionalSizeToAlloc. | 
| 341 |   /// | 
| 342 |   /// Use with FixedSizeStorageOwner, e.g.: | 
| 343 |   /// | 
| 344 |   /// \code{.cpp} | 
| 345 |   /// | 
| 346 |   /// MyObj::FixedSizeStorage<void *>::with_counts<1u>::type myStackObjStorage; | 
| 347 |   /// MyObj::FixedSizeStorageOwner | 
| 348 |   ///     myStackObjOwner(new ((void *)&myStackObjStorage) MyObj); | 
| 349 |   /// MyObj *const myStackObjPtr = myStackObjOwner.get(); | 
| 350 |   /// | 
| 351 |   /// \endcode | 
| 352 |   template <typename... Tys> struct FixedSizeStorage { | 
| 353 |     template <size_t... Counts> struct with_counts { | 
| 354 |       enum { Size = totalSizeToAlloc<Tys...>(Counts...) }; | 
| 355 |       struct type { | 
| 356 |         alignas(BaseTy) char buffer[Size]; | 
| 357 |       }; | 
| 358 |     }; | 
| 359 |   }; | 
| 360 |  | 
| 361 |   /// A type that acts as the owner for an object placed into fixed storage. | 
| 362 |   class FixedSizeStorageOwner { | 
| 363 |   public: | 
| 364 |     FixedSizeStorageOwner(BaseTy *p) : p(p) {} | 
| 365 |     ~FixedSizeStorageOwner() { | 
| 366 |       assert(p && "FixedSizeStorageOwner owns null?" ); | 
| 367 |       p->~BaseTy(); | 
| 368 |     } | 
| 369 |  | 
| 370 |     BaseTy *get() { return p; } | 
| 371 |     const BaseTy *get() const { return p; } | 
| 372 |  | 
| 373 |   private: | 
| 374 |     FixedSizeStorageOwner(const FixedSizeStorageOwner &) = delete; | 
| 375 |     FixedSizeStorageOwner(FixedSizeStorageOwner &&) = delete; | 
| 376 |     FixedSizeStorageOwner &operator=(const FixedSizeStorageOwner &) = delete; | 
| 377 |     FixedSizeStorageOwner &operator=(FixedSizeStorageOwner &&) = delete; | 
| 378 |  | 
| 379 |     BaseTy *const p; | 
| 380 |   }; | 
| 381 | }; | 
| 382 |  | 
| 383 | } // end namespace llvm | 
| 384 |  | 
| 385 | #endif | 
| 386 |  |