xref: /freebsd-src/contrib/llvm-project/llvm/include/llvm/Support/TrailingObjects.h (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
10b57cec5SDimitry Andric //===--- TrailingObjects.h - Variable-length classes ------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric ///
90b57cec5SDimitry Andric /// \file
100b57cec5SDimitry Andric /// This header defines support for implementing classes that have
110b57cec5SDimitry Andric /// some trailing object (or arrays of objects) appended to them. The
120b57cec5SDimitry Andric /// main purpose is to make it obvious where this idiom is being used,
130b57cec5SDimitry Andric /// and to make the usage more idiomatic and more difficult to get
140b57cec5SDimitry Andric /// wrong.
150b57cec5SDimitry Andric ///
160b57cec5SDimitry Andric /// The TrailingObject template abstracts away the reinterpret_cast,
170b57cec5SDimitry Andric /// pointer arithmetic, and size calculations used for the allocation
180b57cec5SDimitry Andric /// and access of appended arrays of objects, and takes care that they
190b57cec5SDimitry Andric /// are all allocated at their required alignment. Additionally, it
200b57cec5SDimitry Andric /// ensures that the base type is final -- deriving from a class that
210b57cec5SDimitry Andric /// expects data appended immediately after it is typically not safe.
220b57cec5SDimitry Andric ///
230b57cec5SDimitry Andric /// Users are expected to derive from this template, and provide
240b57cec5SDimitry Andric /// numTrailingObjects implementations for each trailing type except
250b57cec5SDimitry Andric /// the last, e.g. like this sample:
260b57cec5SDimitry Andric ///
270b57cec5SDimitry Andric /// \code
280b57cec5SDimitry Andric /// class VarLengthObj : private TrailingObjects<VarLengthObj, int, double> {
290b57cec5SDimitry Andric ///   friend TrailingObjects;
300b57cec5SDimitry Andric ///
310b57cec5SDimitry Andric ///   unsigned NumInts, NumDoubles;
320b57cec5SDimitry Andric ///   size_t numTrailingObjects(OverloadToken<int>) const { return NumInts; }
330b57cec5SDimitry Andric ///  };
340b57cec5SDimitry Andric /// \endcode
350b57cec5SDimitry Andric ///
360b57cec5SDimitry Andric /// You can access the appended arrays via 'getTrailingObjects', and
370b57cec5SDimitry Andric /// determine the size needed for allocation via
380b57cec5SDimitry Andric /// 'additionalSizeToAlloc' and 'totalSizeToAlloc'.
390b57cec5SDimitry Andric ///
40*5f757f3fSDimitry Andric /// All the methods implemented by this class are intended for use
410b57cec5SDimitry Andric /// by the implementation of the class, not as part of its interface
420b57cec5SDimitry Andric /// (thus, private inheritance is suggested).
430b57cec5SDimitry Andric ///
440b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric #ifndef LLVM_SUPPORT_TRAILINGOBJECTS_H
470b57cec5SDimitry Andric #define LLVM_SUPPORT_TRAILINGOBJECTS_H
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric #include "llvm/Support/AlignOf.h"
508bcb0991SDimitry Andric #include "llvm/Support/Alignment.h"
510b57cec5SDimitry Andric #include "llvm/Support/Compiler.h"
520b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h"
530b57cec5SDimitry Andric #include "llvm/Support/type_traits.h"
540b57cec5SDimitry Andric #include <new>
550b57cec5SDimitry Andric #include <type_traits>
560b57cec5SDimitry Andric 
570b57cec5SDimitry Andric namespace llvm {
580b57cec5SDimitry Andric 
590b57cec5SDimitry Andric namespace trailing_objects_internal {
600b57cec5SDimitry Andric /// Helper template to calculate the max alignment requirement for a set of
610b57cec5SDimitry Andric /// objects.
620b57cec5SDimitry Andric template <typename First, typename... Rest> class AlignmentCalcHelper {
630b57cec5SDimitry Andric private:
640b57cec5SDimitry Andric   enum {
650b57cec5SDimitry Andric     FirstAlignment = alignof(First),
660b57cec5SDimitry Andric     RestAlignment = AlignmentCalcHelper<Rest...>::Alignment,
670b57cec5SDimitry Andric   };
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric public:
700b57cec5SDimitry Andric   enum {
710b57cec5SDimitry Andric     Alignment = FirstAlignment > RestAlignment ? FirstAlignment : RestAlignment
720b57cec5SDimitry Andric   };
730b57cec5SDimitry Andric };
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric template <typename First> class AlignmentCalcHelper<First> {
760b57cec5SDimitry Andric public:
770b57cec5SDimitry Andric   enum { Alignment = alignof(First) };
780b57cec5SDimitry Andric };
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric /// The base class for TrailingObjects* classes.
810b57cec5SDimitry Andric class TrailingObjectsBase {
820b57cec5SDimitry Andric protected:
830b57cec5SDimitry Andric   /// OverloadToken's purpose is to allow specifying function overloads
840b57cec5SDimitry Andric   /// for different types, without actually taking the types as
850b57cec5SDimitry Andric   /// parameters. (Necessary because member function templates cannot
860b57cec5SDimitry Andric   /// be specialized, so overloads must be used instead of
870b57cec5SDimitry Andric   /// specialization.)
880b57cec5SDimitry Andric   template <typename T> struct OverloadToken {};
890b57cec5SDimitry Andric };
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric // Just a little helper for transforming a type pack into the same
920b57cec5SDimitry Andric // number of a different type. e.g.:
930b57cec5SDimitry Andric //   ExtractSecondType<Foo..., int>::type
940b57cec5SDimitry Andric template <typename Ty1, typename Ty2> struct ExtractSecondType {
950b57cec5SDimitry Andric   typedef Ty2 type;
960b57cec5SDimitry Andric };
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric // TrailingObjectsImpl is somewhat complicated, because it is a
990b57cec5SDimitry Andric // recursively inheriting template, in order to handle the template
1000b57cec5SDimitry Andric // varargs. Each level of inheritance picks off a single trailing type
1010b57cec5SDimitry Andric // then recurses on the rest. The "Align", "BaseTy", and
1020b57cec5SDimitry Andric // "TopTrailingObj" arguments are passed through unchanged through the
1030b57cec5SDimitry Andric // recursion. "PrevTy" is, at each level, the type handled by the
1040b57cec5SDimitry Andric // level right above it.
1050b57cec5SDimitry Andric 
1060b57cec5SDimitry Andric template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy,
1070b57cec5SDimitry Andric           typename... MoreTys>
1080b57cec5SDimitry Andric class TrailingObjectsImpl {
1090b57cec5SDimitry Andric   // The main template definition is never used -- the two
1100b57cec5SDimitry Andric   // specializations cover all possibilities.
1110b57cec5SDimitry Andric };
1120b57cec5SDimitry Andric 
1130b57cec5SDimitry Andric template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy,
1140b57cec5SDimitry Andric           typename NextTy, typename... MoreTys>
1150b57cec5SDimitry Andric class TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, PrevTy, NextTy,
1160b57cec5SDimitry Andric                           MoreTys...>
1170b57cec5SDimitry Andric     : public TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, NextTy,
1180b57cec5SDimitry Andric                                  MoreTys...> {
1190b57cec5SDimitry Andric 
1200b57cec5SDimitry Andric   typedef TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, NextTy, MoreTys...>
1210b57cec5SDimitry Andric       ParentType;
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric   struct RequiresRealignment {
1240b57cec5SDimitry Andric     static const bool value = alignof(PrevTy) < alignof(NextTy);
1250b57cec5SDimitry Andric   };
1260b57cec5SDimitry Andric 
requiresRealignment()1270b57cec5SDimitry Andric   static constexpr bool requiresRealignment() {
1280b57cec5SDimitry Andric     return RequiresRealignment::value;
1290b57cec5SDimitry Andric   }
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric protected:
1320b57cec5SDimitry Andric   // Ensure the inherited getTrailingObjectsImpl is not hidden.
1330b57cec5SDimitry Andric   using ParentType::getTrailingObjectsImpl;
1340b57cec5SDimitry Andric 
1350b57cec5SDimitry Andric   // These two functions are helper functions for
1360b57cec5SDimitry Andric   // TrailingObjects::getTrailingObjects. They recurse to the left --
1370b57cec5SDimitry Andric   // the result for each type in the list of trailing types depends on
1380b57cec5SDimitry Andric   // the result of calling the function on the type to the
1390b57cec5SDimitry Andric   // left. However, the function for the type to the left is
1400b57cec5SDimitry Andric   // implemented by a *subclass* of this class, so we invoke it via
1410b57cec5SDimitry Andric   // the TopTrailingObj, which is, via the
1420b57cec5SDimitry Andric   // curiously-recurring-template-pattern, the most-derived type in
1430b57cec5SDimitry Andric   // this recursion, and thus, contains all the overloads.
1440b57cec5SDimitry Andric   static const NextTy *
getTrailingObjectsImpl(const BaseTy * Obj,TrailingObjectsBase::OverloadToken<NextTy>)1450b57cec5SDimitry Andric   getTrailingObjectsImpl(const BaseTy *Obj,
1460b57cec5SDimitry Andric                          TrailingObjectsBase::OverloadToken<NextTy>) {
1470b57cec5SDimitry Andric     auto *Ptr = TopTrailingObj::getTrailingObjectsImpl(
1480b57cec5SDimitry Andric                     Obj, TrailingObjectsBase::OverloadToken<PrevTy>()) +
1490b57cec5SDimitry Andric                 TopTrailingObj::callNumTrailingObjects(
1500b57cec5SDimitry Andric                     Obj, TrailingObjectsBase::OverloadToken<PrevTy>());
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric     if (requiresRealignment())
1530b57cec5SDimitry Andric       return reinterpret_cast<const NextTy *>(
1548bcb0991SDimitry Andric           alignAddr(Ptr, Align::Of<NextTy>()));
1550b57cec5SDimitry Andric     else
1560b57cec5SDimitry Andric       return reinterpret_cast<const NextTy *>(Ptr);
1570b57cec5SDimitry Andric   }
1580b57cec5SDimitry Andric 
1590b57cec5SDimitry Andric   static NextTy *
getTrailingObjectsImpl(BaseTy * Obj,TrailingObjectsBase::OverloadToken<NextTy>)1600b57cec5SDimitry Andric   getTrailingObjectsImpl(BaseTy *Obj,
1610b57cec5SDimitry Andric                          TrailingObjectsBase::OverloadToken<NextTy>) {
1620b57cec5SDimitry Andric     auto *Ptr = TopTrailingObj::getTrailingObjectsImpl(
1630b57cec5SDimitry Andric                     Obj, TrailingObjectsBase::OverloadToken<PrevTy>()) +
1640b57cec5SDimitry Andric                 TopTrailingObj::callNumTrailingObjects(
1650b57cec5SDimitry Andric                     Obj, TrailingObjectsBase::OverloadToken<PrevTy>());
1660b57cec5SDimitry Andric 
1670b57cec5SDimitry Andric     if (requiresRealignment())
1688bcb0991SDimitry Andric       return reinterpret_cast<NextTy *>(alignAddr(Ptr, Align::Of<NextTy>()));
1690b57cec5SDimitry Andric     else
1700b57cec5SDimitry Andric       return reinterpret_cast<NextTy *>(Ptr);
1710b57cec5SDimitry Andric   }
1720b57cec5SDimitry Andric 
1730b57cec5SDimitry Andric   // Helper function for TrailingObjects::additionalSizeToAlloc: this
1740b57cec5SDimitry Andric   // function recurses to superclasses, each of which requires one
1750b57cec5SDimitry Andric   // fewer size_t argument, and adds its own size.
additionalSizeToAllocImpl(size_t SizeSoFar,size_t Count1,typename ExtractSecondType<MoreTys,size_t>::type...MoreCounts)1760b57cec5SDimitry Andric   static constexpr size_t additionalSizeToAllocImpl(
1770b57cec5SDimitry Andric       size_t SizeSoFar, size_t Count1,
1780b57cec5SDimitry Andric       typename ExtractSecondType<MoreTys, size_t>::type... MoreCounts) {
1790b57cec5SDimitry Andric     return ParentType::additionalSizeToAllocImpl(
1800b57cec5SDimitry Andric         (requiresRealignment() ? llvm::alignTo<alignof(NextTy)>(SizeSoFar)
1810b57cec5SDimitry Andric                                : SizeSoFar) +
1820b57cec5SDimitry Andric             sizeof(NextTy) * Count1,
1830b57cec5SDimitry Andric         MoreCounts...);
1840b57cec5SDimitry Andric   }
1850b57cec5SDimitry Andric };
1860b57cec5SDimitry Andric 
1870b57cec5SDimitry Andric // The base case of the TrailingObjectsImpl inheritance recursion,
1880b57cec5SDimitry Andric // when there's no more trailing types.
1890b57cec5SDimitry Andric template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy>
190fe6060f1SDimitry Andric class alignas(Align) TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, PrevTy>
191fe6060f1SDimitry Andric     : public TrailingObjectsBase {
1920b57cec5SDimitry Andric protected:
1930b57cec5SDimitry Andric   // This is a dummy method, only here so the "using" doesn't fail --
1940b57cec5SDimitry Andric   // it will never be called, because this function recurses backwards
1950b57cec5SDimitry Andric   // up the inheritance chain to subclasses.
1960b57cec5SDimitry Andric   static void getTrailingObjectsImpl();
1970b57cec5SDimitry Andric 
additionalSizeToAllocImpl(size_t SizeSoFar)1980b57cec5SDimitry Andric   static constexpr size_t additionalSizeToAllocImpl(size_t SizeSoFar) {
1990b57cec5SDimitry Andric     return SizeSoFar;
2000b57cec5SDimitry Andric   }
2010b57cec5SDimitry Andric 
verifyTrailingObjectsAlignment()2020b57cec5SDimitry Andric   template <bool CheckAlignment> static void verifyTrailingObjectsAlignment() {}
2030b57cec5SDimitry Andric };
2040b57cec5SDimitry Andric 
2050b57cec5SDimitry Andric } // end namespace trailing_objects_internal
2060b57cec5SDimitry Andric 
2070b57cec5SDimitry Andric // Finally, the main type defined in this file, the one intended for users...
2080b57cec5SDimitry Andric 
2090b57cec5SDimitry Andric /// See the file comment for details on the usage of the
2100b57cec5SDimitry Andric /// TrailingObjects type.
2110b57cec5SDimitry Andric template <typename BaseTy, typename... TrailingTys>
2120b57cec5SDimitry Andric class TrailingObjects : private trailing_objects_internal::TrailingObjectsImpl<
2130b57cec5SDimitry Andric                             trailing_objects_internal::AlignmentCalcHelper<
2140b57cec5SDimitry Andric                                 TrailingTys...>::Alignment,
2150b57cec5SDimitry Andric                             BaseTy, TrailingObjects<BaseTy, TrailingTys...>,
2160b57cec5SDimitry Andric                             BaseTy, TrailingTys...> {
2170b57cec5SDimitry Andric 
2180b57cec5SDimitry Andric   template <int A, typename B, typename T, typename P, typename... M>
2190b57cec5SDimitry Andric   friend class trailing_objects_internal::TrailingObjectsImpl;
2200b57cec5SDimitry Andric 
2210b57cec5SDimitry Andric   template <typename... Tys> class Foo {};
2220b57cec5SDimitry Andric 
2230b57cec5SDimitry Andric   typedef trailing_objects_internal::TrailingObjectsImpl<
2240b57cec5SDimitry Andric       trailing_objects_internal::AlignmentCalcHelper<TrailingTys...>::Alignment,
2250b57cec5SDimitry Andric       BaseTy, TrailingObjects<BaseTy, TrailingTys...>, BaseTy, TrailingTys...>
2260b57cec5SDimitry Andric       ParentType;
2270b57cec5SDimitry Andric   using TrailingObjectsBase = trailing_objects_internal::TrailingObjectsBase;
2280b57cec5SDimitry Andric 
2290b57cec5SDimitry Andric   using ParentType::getTrailingObjectsImpl;
2300b57cec5SDimitry Andric 
2310b57cec5SDimitry Andric   // This function contains only a static_assert BaseTy is final. The
2320b57cec5SDimitry Andric   // static_assert must be in a function, and not at class-level
2330b57cec5SDimitry Andric   // because BaseTy isn't complete at class instantiation time, but
2340b57cec5SDimitry Andric   // will be by the time this function is instantiated.
verifyTrailingObjectsAssertions()2350b57cec5SDimitry Andric   static void verifyTrailingObjectsAssertions() {
2368bcb0991SDimitry Andric     static_assert(std::is_final<BaseTy>(), "BaseTy must be final.");
2370b57cec5SDimitry Andric   }
2380b57cec5SDimitry Andric 
2390b57cec5SDimitry Andric   // These two methods are the base of the recursion for this method.
2400b57cec5SDimitry Andric   static const BaseTy *
getTrailingObjectsImpl(const BaseTy * Obj,TrailingObjectsBase::OverloadToken<BaseTy>)2410b57cec5SDimitry Andric   getTrailingObjectsImpl(const BaseTy *Obj,
2420b57cec5SDimitry Andric                          TrailingObjectsBase::OverloadToken<BaseTy>) {
2430b57cec5SDimitry Andric     return Obj;
2440b57cec5SDimitry Andric   }
2450b57cec5SDimitry Andric 
2460b57cec5SDimitry Andric   static BaseTy *
getTrailingObjectsImpl(BaseTy * Obj,TrailingObjectsBase::OverloadToken<BaseTy>)2470b57cec5SDimitry Andric   getTrailingObjectsImpl(BaseTy *Obj,
2480b57cec5SDimitry Andric                          TrailingObjectsBase::OverloadToken<BaseTy>) {
2490b57cec5SDimitry Andric     return Obj;
2500b57cec5SDimitry Andric   }
2510b57cec5SDimitry Andric 
2520b57cec5SDimitry Andric   // callNumTrailingObjects simply calls numTrailingObjects on the
2530b57cec5SDimitry Andric   // provided Obj -- except when the type being queried is BaseTy
2540b57cec5SDimitry Andric   // itself. There is always only one of the base object, so that case
2550b57cec5SDimitry Andric   // is handled here. (An additional benefit of indirecting through
2560b57cec5SDimitry Andric   // this function is that consumers only say "friend
2570b57cec5SDimitry Andric   // TrailingObjects", and thus, only this class itself can call the
2580b57cec5SDimitry Andric   // numTrailingObjects function.)
2590b57cec5SDimitry Andric   static size_t
callNumTrailingObjects(const BaseTy * Obj,TrailingObjectsBase::OverloadToken<BaseTy>)2600b57cec5SDimitry Andric   callNumTrailingObjects(const BaseTy *Obj,
2610b57cec5SDimitry Andric                          TrailingObjectsBase::OverloadToken<BaseTy>) {
2620b57cec5SDimitry Andric     return 1;
2630b57cec5SDimitry Andric   }
2640b57cec5SDimitry Andric 
2650b57cec5SDimitry Andric   template <typename T>
callNumTrailingObjects(const BaseTy * Obj,TrailingObjectsBase::OverloadToken<T>)2660b57cec5SDimitry Andric   static size_t callNumTrailingObjects(const BaseTy *Obj,
2670b57cec5SDimitry Andric                                        TrailingObjectsBase::OverloadToken<T>) {
2680b57cec5SDimitry Andric     return Obj->numTrailingObjects(TrailingObjectsBase::OverloadToken<T>());
2690b57cec5SDimitry Andric   }
2700b57cec5SDimitry Andric 
2710b57cec5SDimitry Andric public:
2720b57cec5SDimitry Andric   // Make this (privately inherited) member public.
2730b57cec5SDimitry Andric #ifndef _MSC_VER
2740b57cec5SDimitry Andric   using ParentType::OverloadToken;
2750b57cec5SDimitry Andric #else
276fe6060f1SDimitry Andric   // An MSVC bug prevents the above from working, (last tested at CL version
277fe6060f1SDimitry Andric   // 19.28). "Class5" in TrailingObjectsTest.cpp tests the problematic case.
2780b57cec5SDimitry Andric   template <typename T>
2790b57cec5SDimitry Andric   using OverloadToken = typename ParentType::template OverloadToken<T>;
2800b57cec5SDimitry Andric #endif
2810b57cec5SDimitry Andric 
2820b57cec5SDimitry Andric   /// Returns a pointer to the trailing object array of the given type
2830b57cec5SDimitry Andric   /// (which must be one of those specified in the class template). The
2840b57cec5SDimitry Andric   /// array may have zero or more elements in it.
getTrailingObjects()2850b57cec5SDimitry Andric   template <typename T> const T *getTrailingObjects() const {
2860b57cec5SDimitry Andric     verifyTrailingObjectsAssertions();
2870b57cec5SDimitry Andric     // Forwards to an impl function with overloads, since member
2880b57cec5SDimitry Andric     // function templates can't be specialized.
2890b57cec5SDimitry Andric     return this->getTrailingObjectsImpl(
2900b57cec5SDimitry Andric         static_cast<const BaseTy *>(this),
2910b57cec5SDimitry Andric         TrailingObjectsBase::OverloadToken<T>());
2920b57cec5SDimitry Andric   }
2930b57cec5SDimitry Andric 
2940b57cec5SDimitry Andric   /// Returns a pointer to the trailing object array of the given type
2950b57cec5SDimitry Andric   /// (which must be one of those specified in the class template). The
2960b57cec5SDimitry Andric   /// array may have zero or more elements in it.
getTrailingObjects()2970b57cec5SDimitry Andric   template <typename T> T *getTrailingObjects() {
2980b57cec5SDimitry Andric     verifyTrailingObjectsAssertions();
2990b57cec5SDimitry Andric     // Forwards to an impl function with overloads, since member
3000b57cec5SDimitry Andric     // function templates can't be specialized.
3010b57cec5SDimitry Andric     return this->getTrailingObjectsImpl(
3020b57cec5SDimitry Andric         static_cast<BaseTy *>(this), TrailingObjectsBase::OverloadToken<T>());
3030b57cec5SDimitry Andric   }
3040b57cec5SDimitry Andric 
3050b57cec5SDimitry Andric   /// Returns the size of the trailing data, if an object were
3060b57cec5SDimitry Andric   /// allocated with the given counts (The counts are in the same order
3070b57cec5SDimitry Andric   /// as the template arguments). This does not include the size of the
3080b57cec5SDimitry Andric   /// base object.  The template arguments must be the same as those
3090b57cec5SDimitry Andric   /// used in the class; they are supplied here redundantly only so
3100b57cec5SDimitry Andric   /// that it's clear what the counts are counting in callers.
3110b57cec5SDimitry Andric   template <typename... Tys>
3125ffd83dbSDimitry Andric   static constexpr std::enable_if_t<
31306c3fb27SDimitry Andric       std::is_same_v<Foo<TrailingTys...>, Foo<Tys...>>, size_t>
additionalSizeToAlloc(typename trailing_objects_internal::ExtractSecondType<TrailingTys,size_t>::type...Counts)3140b57cec5SDimitry Andric   additionalSizeToAlloc(typename trailing_objects_internal::ExtractSecondType<
3150b57cec5SDimitry Andric                         TrailingTys, size_t>::type... Counts) {
3160b57cec5SDimitry Andric     return ParentType::additionalSizeToAllocImpl(0, Counts...);
3170b57cec5SDimitry Andric   }
3180b57cec5SDimitry Andric 
3190b57cec5SDimitry Andric   /// Returns the total size of an object if it were allocated with the
3200b57cec5SDimitry Andric   /// given trailing object counts. This is the same as
3210b57cec5SDimitry Andric   /// additionalSizeToAlloc, except it *does* include the size of the base
3220b57cec5SDimitry Andric   /// object.
3230b57cec5SDimitry Andric   template <typename... Tys>
3245ffd83dbSDimitry Andric   static constexpr std::enable_if_t<
32506c3fb27SDimitry Andric       std::is_same_v<Foo<TrailingTys...>, Foo<Tys...>>, size_t>
totalSizeToAlloc(typename trailing_objects_internal::ExtractSecondType<TrailingTys,size_t>::type...Counts)3260b57cec5SDimitry Andric   totalSizeToAlloc(typename trailing_objects_internal::ExtractSecondType<
3270b57cec5SDimitry Andric                    TrailingTys, size_t>::type... Counts) {
3280b57cec5SDimitry Andric     return sizeof(BaseTy) + ParentType::additionalSizeToAllocImpl(0, Counts...);
3290b57cec5SDimitry Andric   }
3300b57cec5SDimitry Andric 
331fe6060f1SDimitry Andric   TrailingObjects() = default;
332fe6060f1SDimitry Andric   TrailingObjects(const TrailingObjects &) = delete;
333fe6060f1SDimitry Andric   TrailingObjects(TrailingObjects &&) = delete;
334fe6060f1SDimitry Andric   TrailingObjects &operator=(const TrailingObjects &) = delete;
335fe6060f1SDimitry Andric   TrailingObjects &operator=(TrailingObjects &&) = delete;
336fe6060f1SDimitry Andric 
3370b57cec5SDimitry Andric   /// A type where its ::with_counts template member has a ::type member
3380b57cec5SDimitry Andric   /// suitable for use as uninitialized storage for an object with the given
3390b57cec5SDimitry Andric   /// trailing object counts. The template arguments are similar to those
3400b57cec5SDimitry Andric   /// of additionalSizeToAlloc.
3410b57cec5SDimitry Andric   ///
3420b57cec5SDimitry Andric   /// Use with FixedSizeStorageOwner, e.g.:
3430b57cec5SDimitry Andric   ///
3440b57cec5SDimitry Andric   /// \code{.cpp}
3450b57cec5SDimitry Andric   ///
3460b57cec5SDimitry Andric   /// MyObj::FixedSizeStorage<void *>::with_counts<1u>::type myStackObjStorage;
3470b57cec5SDimitry Andric   /// MyObj::FixedSizeStorageOwner
3480b57cec5SDimitry Andric   ///     myStackObjOwner(new ((void *)&myStackObjStorage) MyObj);
3490b57cec5SDimitry Andric   /// MyObj *const myStackObjPtr = myStackObjOwner.get();
3500b57cec5SDimitry Andric   ///
3510b57cec5SDimitry Andric   /// \endcode
3520b57cec5SDimitry Andric   template <typename... Tys> struct FixedSizeStorage {
3530b57cec5SDimitry Andric     template <size_t... Counts> struct with_counts {
3540b57cec5SDimitry Andric       enum { Size = totalSizeToAlloc<Tys...>(Counts...) };
3558bcb0991SDimitry Andric       struct type {
3568bcb0991SDimitry Andric         alignas(BaseTy) char buffer[Size];
3578bcb0991SDimitry Andric       };
3580b57cec5SDimitry Andric     };
3590b57cec5SDimitry Andric   };
3600b57cec5SDimitry Andric 
3610b57cec5SDimitry Andric   /// A type that acts as the owner for an object placed into fixed storage.
3620b57cec5SDimitry Andric   class FixedSizeStorageOwner {
3630b57cec5SDimitry Andric   public:
FixedSizeStorageOwner(BaseTy * p)3640b57cec5SDimitry Andric     FixedSizeStorageOwner(BaseTy *p) : p(p) {}
~FixedSizeStorageOwner()3650b57cec5SDimitry Andric     ~FixedSizeStorageOwner() {
3660b57cec5SDimitry Andric       assert(p && "FixedSizeStorageOwner owns null?");
3670b57cec5SDimitry Andric       p->~BaseTy();
3680b57cec5SDimitry Andric     }
3690b57cec5SDimitry Andric 
get()3700b57cec5SDimitry Andric     BaseTy *get() { return p; }
get()3710b57cec5SDimitry Andric     const BaseTy *get() const { return p; }
3720b57cec5SDimitry Andric 
3730b57cec5SDimitry Andric   private:
3740b57cec5SDimitry Andric     FixedSizeStorageOwner(const FixedSizeStorageOwner &) = delete;
3750b57cec5SDimitry Andric     FixedSizeStorageOwner(FixedSizeStorageOwner &&) = delete;
3760b57cec5SDimitry Andric     FixedSizeStorageOwner &operator=(const FixedSizeStorageOwner &) = delete;
3770b57cec5SDimitry Andric     FixedSizeStorageOwner &operator=(FixedSizeStorageOwner &&) = delete;
3780b57cec5SDimitry Andric 
3790b57cec5SDimitry Andric     BaseTy *const p;
3800b57cec5SDimitry Andric   };
3810b57cec5SDimitry Andric };
3820b57cec5SDimitry Andric 
3830b57cec5SDimitry Andric } // end namespace llvm
3840b57cec5SDimitry Andric 
3850b57cec5SDimitry Andric #endif
386