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