//===--- TrailingObjects.h - Variable-length classes ------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// /// /// \file /// This header defines support for implementing classes that have /// some trailing object (or arrays of objects) appended to them. The /// main purpose is to make it obvious where this idiom is being used, /// and to make the usage more idiomatic and more difficult to get /// wrong. /// /// The TrailingObject template abstracts away the reinterpret_cast, /// pointer arithmetic, and size calculations used for the allocation /// and access of appended arrays of objects, and takes care that they /// are all allocated at their required alignment. Additionally, it /// ensures that the base type is final -- deriving from a class that /// expects data appended immediately after it is typically not safe. /// /// Users are expected to derive from this template, and provide /// numTrailingObjects implementations for each trailing type except /// the last, e.g. like this sample: /// /// \code /// class VarLengthObj : private TrailingObjects<VarLengthObj, int, double> { /// friend TrailingObjects; /// /// unsigned NumInts, NumDoubles; /// size_t numTrailingObjects(OverloadToken<int>) const { return NumInts; } /// }; /// \endcode /// /// You can access the appended arrays via 'getTrailingObjects', and /// determine the size needed for allocation via /// 'additionalSizeToAlloc' and 'totalSizeToAlloc'. /// /// All the methods implemented by this class are intended for use /// by the implementation of the class, not as part of its interface /// (thus, private inheritance is suggested). /// //===----------------------------------------------------------------------===// #ifndef LLVM_SUPPORT_TRAILINGOBJECTS_H #define LLVM_SUPPORT_TRAILINGOBJECTS_H #include "llvm/Support/AlignOf.h" #include "llvm/Support/Alignment.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/type_traits.h" #include <new> #include <type_traits> namespace llvm { namespace trailing_objects_internal { /// Helper template to calculate the max alignment requirement for a set of /// objects. template <typename First, typename... Rest> class AlignmentCalcHelper { … }; AlignmentCalcHelper<First>; /// The base class for TrailingObjects* classes. class TrailingObjectsBase { … }; // Just a little helper for transforming a type pack into the same // number of a different type. e.g.: // ExtractSecondType<Foo..., int>::type template <typename Ty1, typename Ty2> struct ExtractSecondType { … }; // TrailingObjectsImpl is somewhat complicated, because it is a // recursively inheriting template, in order to handle the template // varargs. Each level of inheritance picks off a single trailing type // then recurses on the rest. The "Align", "BaseTy", and // "TopTrailingObj" arguments are passed through unchanged through the // recursion. "PrevTy" is, at each level, the type handled by the // level right above it. template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy, typename... MoreTys> class TrailingObjectsImpl { … }; TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, PrevTy, NextTy, MoreTys...>; // The base case of the TrailingObjectsImpl inheritance recursion, // when there's no more trailing types. TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, PrevTy>; } // end namespace trailing_objects_internal // Finally, the main type defined in this file, the one intended for users... /// See the file comment for details on the usage of the /// TrailingObjects type. template <typename BaseTy, typename... TrailingTys> class TrailingObjects : private trailing_objects_internal::TrailingObjectsImpl< trailing_objects_internal::AlignmentCalcHelper< TrailingTys...>::Alignment, BaseTy, TrailingObjects<BaseTy, TrailingTys...>, BaseTy, TrailingTys...> { … }; } // end namespace llvm #endif