/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/include/llvm/Support/TrailingObjects.h
Line | Count | Source (jump to first uncovered line) |
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, and takes care that they |
20 | | /// are all allocated at their required alignment. Additionally, it |
21 | | /// ensures that the base type is final -- deriving from a class that |
22 | | /// expects data appended immediately after it is typically not safe. |
23 | | /// |
24 | | /// Users are expected to derive from this template, and provide |
25 | | /// numTrailingObjects implementations for each trailing type except |
26 | | /// the last, e.g. like this sample: |
27 | | /// |
28 | | /// \code |
29 | | /// class VarLengthObj : private TrailingObjects<VarLengthObj, int, double> { |
30 | | /// friend TrailingObjects; |
31 | | /// |
32 | | /// unsigned NumInts, NumDoubles; |
33 | | /// size_t numTrailingObjects(OverloadToken<int>) const { return NumInts; } |
34 | | /// }; |
35 | | /// \endcode |
36 | | /// |
37 | | /// You can access the appended arrays via 'getTrailingObjects', and |
38 | | /// determine the size needed for allocation via |
39 | | /// 'additionalSizeToAlloc' and 'totalSizeToAlloc'. |
40 | | /// |
41 | | /// All the methods implemented by this class are are intended for use |
42 | | /// by the implementation of the class, not as part of its interface |
43 | | /// (thus, private inheritance is suggested). |
44 | | /// |
45 | | //===----------------------------------------------------------------------===// |
46 | | |
47 | | #ifndef LLVM_SUPPORT_TRAILINGOBJECTS_H |
48 | | #define LLVM_SUPPORT_TRAILINGOBJECTS_H |
49 | | |
50 | | #include "llvm/Support/AlignOf.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 | | /// This helper template works-around MSVC 2013's lack of useful |
92 | | /// alignas() support. The argument to LLVM_ALIGNAS(), in MSVC, is |
93 | | /// required to be a literal integer. But, you *can* use template |
94 | | /// specialization to select between a bunch of different LLVM_ALIGNAS |
95 | | /// expressions... |
96 | | template <int Align> |
97 | | class TrailingObjectsAligner : public TrailingObjectsBase {}; |
98 | | template <> |
99 | | class LLVM_ALIGNAS(1) TrailingObjectsAligner<1> : public TrailingObjectsBase {}; |
100 | | template <> |
101 | | class LLVM_ALIGNAS(2) TrailingObjectsAligner<2> : public TrailingObjectsBase {}; |
102 | | template <> |
103 | | class LLVM_ALIGNAS(4) TrailingObjectsAligner<4> : public TrailingObjectsBase {}; |
104 | | template <> |
105 | | class LLVM_ALIGNAS(8) TrailingObjectsAligner<8> : public TrailingObjectsBase {}; |
106 | | template <> |
107 | | class LLVM_ALIGNAS(16) TrailingObjectsAligner<16> : public TrailingObjectsBase { |
108 | | }; |
109 | | template <> |
110 | | class LLVM_ALIGNAS(32) TrailingObjectsAligner<32> : public TrailingObjectsBase { |
111 | | }; |
112 | | |
113 | | // Just a little helper for transforming a type pack into the same |
114 | | // number of a different type. e.g.: |
115 | | // ExtractSecondType<Foo..., int>::type |
116 | | template <typename Ty1, typename Ty2> struct ExtractSecondType { |
117 | | typedef Ty2 type; |
118 | | }; |
119 | | |
120 | | // TrailingObjectsImpl is somewhat complicated, because it is a |
121 | | // recursively inheriting template, in order to handle the template |
122 | | // varargs. Each level of inheritance picks off a single trailing type |
123 | | // then recurses on the rest. The "Align", "BaseTy", and |
124 | | // "TopTrailingObj" arguments are passed through unchanged through the |
125 | | // recursion. "PrevTy" is, at each level, the type handled by the |
126 | | // level right above it. |
127 | | |
128 | | template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy, |
129 | | typename... MoreTys> |
130 | | class TrailingObjectsImpl { |
131 | | // The main template definition is never used -- the two |
132 | | // specializations cover all possibilities. |
133 | | }; |
134 | | |
135 | | template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy, |
136 | | typename NextTy, typename... MoreTys> |
137 | | class TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, PrevTy, NextTy, |
138 | | MoreTys...> |
139 | | : public TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, NextTy, |
140 | | MoreTys...> { |
141 | | |
142 | | typedef TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, NextTy, MoreTys...> |
143 | | ParentType; |
144 | | |
145 | | struct RequiresRealignment { |
146 | | static const bool value = alignof(PrevTy) < alignof(NextTy); |
147 | | }; |
148 | | |
149 | 0 | static constexpr bool requiresRealignment() { |
150 | 0 | return RequiresRealignment::value; |
151 | 0 | } Unexecuted instantiation: llvm::trailing_objects_internal::TrailingObjectsImpl<8, llvm::AttributeListImpl, llvm::TrailingObjects<llvm::AttributeListImpl, llvm::AttributeSet>, llvm::AttributeListImpl, llvm::AttributeSet>::requiresRealignment() Unexecuted instantiation: llvm::trailing_objects_internal::TrailingObjectsImpl<8, llvm::AttributeSetNode, llvm::TrailingObjects<llvm::AttributeSetNode, llvm::Attribute>, llvm::AttributeSetNode, llvm::Attribute>::requiresRealignment() Unexecuted instantiation: LowerTypeTests.cpp:llvm::trailing_objects_internal::TrailingObjectsImpl<8, (anonymous namespace)::GlobalTypeMember, llvm::TrailingObjects<(anonymous namespace)::GlobalTypeMember, llvm::MDNode*>, (anonymous namespace)::GlobalTypeMember, llvm::MDNode*>::requiresRealignment() |
152 | | |
153 | | protected: |
154 | | // Ensure the inherited getTrailingObjectsImpl is not hidden. |
155 | | using ParentType::getTrailingObjectsImpl; |
156 | | |
157 | | // These two functions are helper functions for |
158 | | // TrailingObjects::getTrailingObjects. They recurse to the left -- |
159 | | // the result for each type in the list of trailing types depends on |
160 | | // the result of calling the function on the type to the |
161 | | // left. However, the function for the type to the left is |
162 | | // implemented by a *subclass* of this class, so we invoke it via |
163 | | // the TopTrailingObj, which is, via the |
164 | | // curiously-recurring-template-pattern, the most-derived type in |
165 | | // this recursion, and thus, contains all the overloads. |
166 | | static const NextTy * |
167 | | getTrailingObjectsImpl(const BaseTy *Obj, |
168 | 2.43G | TrailingObjectsBase::OverloadToken<NextTy>) { |
169 | 2.43G | auto *Ptr = TopTrailingObj::getTrailingObjectsImpl( |
170 | 2.43G | Obj, TrailingObjectsBase::OverloadToken<PrevTy>()) + |
171 | 2.43G | TopTrailingObj::callNumTrailingObjects( |
172 | 2.43G | Obj, TrailingObjectsBase::OverloadToken<PrevTy>()); |
173 | 2.43G | |
174 | 2.43G | if (requiresRealignment()) |
175 | 0 | return reinterpret_cast<const NextTy *>( |
176 | 0 | llvm::alignAddr(Ptr, alignof(NextTy))); |
177 | 2.43G | else |
178 | 2.43G | return reinterpret_cast<const NextTy *>(Ptr); |
179 | 2.43G | } llvm::trailing_objects_internal::TrailingObjectsImpl<8, llvm::AttributeSetNode, llvm::TrailingObjects<llvm::AttributeSetNode, llvm::Attribute>, llvm::AttributeSetNode, llvm::Attribute>::getTrailingObjectsImpl(llvm::AttributeSetNode const*, llvm::trailing_objects_internal::TrailingObjectsBase::OverloadToken<llvm::Attribute>) Line | Count | Source | 168 | 241M | TrailingObjectsBase::OverloadToken<NextTy>) { | 169 | 241M | auto *Ptr = TopTrailingObj::getTrailingObjectsImpl( | 170 | 241M | Obj, TrailingObjectsBase::OverloadToken<PrevTy>()) + | 171 | 241M | TopTrailingObj::callNumTrailingObjects( | 172 | 241M | Obj, TrailingObjectsBase::OverloadToken<PrevTy>()); | 173 | 241M | | 174 | 241M | if (requiresRealignment()) | 175 | 0 | return reinterpret_cast<const NextTy *>( | 176 | 0 | llvm::alignAddr(Ptr, alignof(NextTy))); | 177 | 241M | else | 178 | 241M | return reinterpret_cast<const NextTy *>(Ptr); | 179 | 241M | } |
LowerTypeTests.cpp:llvm::trailing_objects_internal::TrailingObjectsImpl<8, (anonymous namespace)::GlobalTypeMember, llvm::TrailingObjects<(anonymous namespace)::GlobalTypeMember, llvm::MDNode*>, (anonymous namespace)::GlobalTypeMember, llvm::MDNode*>::getTrailingObjectsImpl((anonymous namespace)::GlobalTypeMember const*, llvm::trailing_objects_internal::TrailingObjectsBase::OverloadToken<llvm::MDNode*>) Line | Count | Source | 168 | 189 | TrailingObjectsBase::OverloadToken<NextTy>) { | 169 | 189 | auto *Ptr = TopTrailingObj::getTrailingObjectsImpl( | 170 | 189 | Obj, TrailingObjectsBase::OverloadToken<PrevTy>()) + | 171 | 189 | TopTrailingObj::callNumTrailingObjects( | 172 | 189 | Obj, TrailingObjectsBase::OverloadToken<PrevTy>()); | 173 | 189 | | 174 | 189 | if (requiresRealignment()) | 175 | 0 | return reinterpret_cast<const NextTy *>( | 176 | 0 | llvm::alignAddr(Ptr, alignof(NextTy))); | 177 | 189 | else | 178 | 189 | return reinterpret_cast<const NextTy *>(Ptr); | 179 | 189 | } |
llvm::trailing_objects_internal::TrailingObjectsImpl<8, llvm::AttributeListImpl, llvm::TrailingObjects<llvm::AttributeListImpl, llvm::AttributeSet>, llvm::AttributeListImpl, llvm::AttributeSet>::getTrailingObjectsImpl(llvm::AttributeListImpl const*, llvm::trailing_objects_internal::TrailingObjectsBase::OverloadToken<llvm::AttributeSet>) Line | Count | Source | 168 | 2.18G | TrailingObjectsBase::OverloadToken<NextTy>) { | 169 | 2.18G | auto *Ptr = TopTrailingObj::getTrailingObjectsImpl( | 170 | 2.18G | Obj, TrailingObjectsBase::OverloadToken<PrevTy>()) + | 171 | 2.18G | TopTrailingObj::callNumTrailingObjects( | 172 | 2.18G | Obj, TrailingObjectsBase::OverloadToken<PrevTy>()); | 173 | 2.18G | | 174 | 2.18G | if (requiresRealignment()) | 175 | 0 | return reinterpret_cast<const NextTy *>( | 176 | 0 | llvm::alignAddr(Ptr, alignof(NextTy))); | 177 | 2.18G | else | 178 | 2.18G | return reinterpret_cast<const NextTy *>(Ptr); | 179 | 2.18G | } |
|
180 | | |
181 | | static NextTy * |
182 | | getTrailingObjectsImpl(BaseTy *Obj, |
183 | 1.16M | TrailingObjectsBase::OverloadToken<NextTy>) { |
184 | 1.16M | auto *Ptr = TopTrailingObj::getTrailingObjectsImpl( |
185 | 1.16M | Obj, TrailingObjectsBase::OverloadToken<PrevTy>()) + |
186 | 1.16M | TopTrailingObj::callNumTrailingObjects( |
187 | 1.16M | Obj, TrailingObjectsBase::OverloadToken<PrevTy>()); |
188 | 1.16M | |
189 | 1.16M | if (requiresRealignment()) |
190 | 0 | return reinterpret_cast<NextTy *>(llvm::alignAddr(Ptr, alignof(NextTy))); |
191 | 1.16M | else |
192 | 1.16M | return reinterpret_cast<NextTy *>(Ptr); |
193 | 1.16M | } llvm::trailing_objects_internal::TrailingObjectsImpl<8, llvm::AttributeSetNode, llvm::TrailingObjects<llvm::AttributeSetNode, llvm::Attribute>, llvm::AttributeSetNode, llvm::Attribute>::getTrailingObjectsImpl(llvm::AttributeSetNode*, llvm::trailing_objects_internal::TrailingObjectsBase::OverloadToken<llvm::Attribute>) Line | Count | Source | 183 | 359k | TrailingObjectsBase::OverloadToken<NextTy>) { | 184 | 359k | auto *Ptr = TopTrailingObj::getTrailingObjectsImpl( | 185 | 359k | Obj, TrailingObjectsBase::OverloadToken<PrevTy>()) + | 186 | 359k | TopTrailingObj::callNumTrailingObjects( | 187 | 359k | Obj, TrailingObjectsBase::OverloadToken<PrevTy>()); | 188 | 359k | | 189 | 359k | if (requiresRealignment()) | 190 | 0 | return reinterpret_cast<NextTy *>(llvm::alignAddr(Ptr, alignof(NextTy))); | 191 | 359k | else | 192 | 359k | return reinterpret_cast<NextTy *>(Ptr); | 193 | 359k | } |
llvm::trailing_objects_internal::TrailingObjectsImpl<8, llvm::AttributeListImpl, llvm::TrailingObjects<llvm::AttributeListImpl, llvm::AttributeSet>, llvm::AttributeListImpl, llvm::AttributeSet>::getTrailingObjectsImpl(llvm::AttributeListImpl*, llvm::trailing_objects_internal::TrailingObjectsBase::OverloadToken<llvm::AttributeSet>) Line | Count | Source | 183 | 803k | TrailingObjectsBase::OverloadToken<NextTy>) { | 184 | 803k | auto *Ptr = TopTrailingObj::getTrailingObjectsImpl( | 185 | 803k | Obj, TrailingObjectsBase::OverloadToken<PrevTy>()) + | 186 | 803k | TopTrailingObj::callNumTrailingObjects( | 187 | 803k | Obj, TrailingObjectsBase::OverloadToken<PrevTy>()); | 188 | 803k | | 189 | 803k | if (requiresRealignment()) | 190 | 0 | return reinterpret_cast<NextTy *>(llvm::alignAddr(Ptr, alignof(NextTy))); | 191 | 803k | else | 192 | 803k | return reinterpret_cast<NextTy *>(Ptr); | 193 | 803k | } |
LowerTypeTests.cpp:llvm::trailing_objects_internal::TrailingObjectsImpl<8, (anonymous namespace)::GlobalTypeMember, llvm::TrailingObjects<(anonymous namespace)::GlobalTypeMember, llvm::MDNode*>, (anonymous namespace)::GlobalTypeMember, llvm::MDNode*>::getTrailingObjectsImpl((anonymous namespace)::GlobalTypeMember*, llvm::trailing_objects_internal::TrailingObjectsBase::OverloadToken<llvm::MDNode*>) Line | Count | Source | 183 | 85 | TrailingObjectsBase::OverloadToken<NextTy>) { | 184 | 85 | auto *Ptr = TopTrailingObj::getTrailingObjectsImpl( | 185 | 85 | Obj, TrailingObjectsBase::OverloadToken<PrevTy>()) + | 186 | 85 | TopTrailingObj::callNumTrailingObjects( | 187 | 85 | Obj, TrailingObjectsBase::OverloadToken<PrevTy>()); | 188 | 85 | | 189 | 85 | if (requiresRealignment()) | 190 | 0 | return reinterpret_cast<NextTy *>(llvm::alignAddr(Ptr, alignof(NextTy))); | 191 | 85 | else | 192 | 85 | return reinterpret_cast<NextTy *>(Ptr); | 193 | 85 | } |
|
194 | | |
195 | | // Helper function for TrailingObjects::additionalSizeToAlloc: this |
196 | | // function recurses to superclasses, each of which requires one |
197 | | // fewer size_t argument, and adds its own size. |
198 | | static constexpr size_t additionalSizeToAllocImpl( |
199 | | size_t SizeSoFar, size_t Count1, |
200 | 1.16M | typename ExtractSecondType<MoreTys, size_t>::type... MoreCounts) { |
201 | 1.16M | return ParentType::additionalSizeToAllocImpl( |
202 | 0 | (requiresRealignment() ? llvm::alignTo<alignof(NextTy)>(SizeSoFar) |
203 | 1.16M | : SizeSoFar) + |
204 | 1.16M | sizeof(NextTy) * Count1, |
205 | 1.16M | MoreCounts...); |
206 | 1.16M | } llvm::trailing_objects_internal::TrailingObjectsImpl<8, llvm::AttributeSetNode, llvm::TrailingObjects<llvm::AttributeSetNode, llvm::Attribute>, llvm::AttributeSetNode, llvm::Attribute>::additionalSizeToAllocImpl(unsigned long, unsigned long) Line | Count | Source | 200 | 359k | typename ExtractSecondType<MoreTys, size_t>::type... MoreCounts) { | 201 | 359k | return ParentType::additionalSizeToAllocImpl( | 202 | 0 | (requiresRealignment() ? llvm::alignTo<alignof(NextTy)>(SizeSoFar) | 203 | 359k | : SizeSoFar) + | 204 | 359k | sizeof(NextTy) * Count1, | 205 | 359k | MoreCounts...); | 206 | 359k | } |
llvm::trailing_objects_internal::TrailingObjectsImpl<8, llvm::AttributeListImpl, llvm::TrailingObjects<llvm::AttributeListImpl, llvm::AttributeSet>, llvm::AttributeListImpl, llvm::AttributeSet>::additionalSizeToAllocImpl(unsigned long, unsigned long) Line | Count | Source | 200 | 803k | typename ExtractSecondType<MoreTys, size_t>::type... MoreCounts) { | 201 | 803k | return ParentType::additionalSizeToAllocImpl( | 202 | 0 | (requiresRealignment() ? llvm::alignTo<alignof(NextTy)>(SizeSoFar) | 203 | 803k | : SizeSoFar) + | 204 | 803k | sizeof(NextTy) * Count1, | 205 | 803k | MoreCounts...); | 206 | 803k | } |
LowerTypeTests.cpp:llvm::trailing_objects_internal::TrailingObjectsImpl<8, (anonymous namespace)::GlobalTypeMember, llvm::TrailingObjects<(anonymous namespace)::GlobalTypeMember, llvm::MDNode*>, (anonymous namespace)::GlobalTypeMember, llvm::MDNode*>::additionalSizeToAllocImpl(unsigned long, unsigned long) Line | Count | Source | 200 | 85 | typename ExtractSecondType<MoreTys, size_t>::type... MoreCounts) { | 201 | 85 | return ParentType::additionalSizeToAllocImpl( | 202 | 0 | (requiresRealignment() ? llvm::alignTo<alignof(NextTy)>(SizeSoFar) | 203 | 85 | : SizeSoFar) + | 204 | 85 | sizeof(NextTy) * Count1, | 205 | 85 | MoreCounts...); | 206 | 85 | } |
|
207 | | }; |
208 | | |
209 | | // The base case of the TrailingObjectsImpl inheritance recursion, |
210 | | // when there's no more trailing types. |
211 | | template <int Align, typename BaseTy, typename TopTrailingObj, typename PrevTy> |
212 | | class TrailingObjectsImpl<Align, BaseTy, TopTrailingObj, PrevTy> |
213 | | : public TrailingObjectsAligner<Align> { |
214 | | protected: |
215 | | // This is a dummy method, only here so the "using" doesn't fail -- |
216 | | // it will never be called, because this function recurses backwards |
217 | | // up the inheritance chain to subclasses. |
218 | | static void getTrailingObjectsImpl(); |
219 | | |
220 | 1.16M | static constexpr size_t additionalSizeToAllocImpl(size_t SizeSoFar) { |
221 | 1.16M | return SizeSoFar; |
222 | 1.16M | } llvm::trailing_objects_internal::TrailingObjectsImpl<8, llvm::AttributeListImpl, llvm::TrailingObjects<llvm::AttributeListImpl, llvm::AttributeSet>, llvm::AttributeSet>::additionalSizeToAllocImpl(unsigned long) Line | Count | Source | 220 | 803k | static constexpr size_t additionalSizeToAllocImpl(size_t SizeSoFar) { | 221 | 803k | return SizeSoFar; | 222 | 803k | } |
llvm::trailing_objects_internal::TrailingObjectsImpl<8, llvm::AttributeSetNode, llvm::TrailingObjects<llvm::AttributeSetNode, llvm::Attribute>, llvm::Attribute>::additionalSizeToAllocImpl(unsigned long) Line | Count | Source | 220 | 359k | static constexpr size_t additionalSizeToAllocImpl(size_t SizeSoFar) { | 221 | 359k | return SizeSoFar; | 222 | 359k | } |
LowerTypeTests.cpp:llvm::trailing_objects_internal::TrailingObjectsImpl<8, (anonymous namespace)::GlobalTypeMember, llvm::TrailingObjects<(anonymous namespace)::GlobalTypeMember, llvm::MDNode*>, llvm::MDNode*>::additionalSizeToAllocImpl(unsigned long) Line | Count | Source | 220 | 85 | static constexpr size_t additionalSizeToAllocImpl(size_t SizeSoFar) { | 221 | 85 | return SizeSoFar; | 222 | 85 | } |
|
223 | | |
224 | | template <bool CheckAlignment> static void verifyTrailingObjectsAlignment() {} |
225 | | }; |
226 | | |
227 | | } // end namespace trailing_objects_internal |
228 | | |
229 | | // Finally, the main type defined in this file, the one intended for users... |
230 | | |
231 | | /// See the file comment for details on the usage of the |
232 | | /// TrailingObjects type. |
233 | | template <typename BaseTy, typename... TrailingTys> |
234 | | class TrailingObjects : private trailing_objects_internal::TrailingObjectsImpl< |
235 | | trailing_objects_internal::AlignmentCalcHelper< |
236 | | TrailingTys...>::Alignment, |
237 | | BaseTy, TrailingObjects<BaseTy, TrailingTys...>, |
238 | | BaseTy, TrailingTys...> { |
239 | | |
240 | | template <int A, typename B, typename T, typename P, typename... M> |
241 | | friend class trailing_objects_internal::TrailingObjectsImpl; |
242 | | |
243 | | template <typename... Tys> class Foo {}; |
244 | | |
245 | | typedef trailing_objects_internal::TrailingObjectsImpl< |
246 | | trailing_objects_internal::AlignmentCalcHelper<TrailingTys...>::Alignment, |
247 | | BaseTy, TrailingObjects<BaseTy, TrailingTys...>, BaseTy, TrailingTys...> |
248 | | ParentType; |
249 | | using TrailingObjectsBase = trailing_objects_internal::TrailingObjectsBase; |
250 | | |
251 | | using ParentType::getTrailingObjectsImpl; |
252 | | |
253 | | // This function contains only a static_assert BaseTy is final. The |
254 | | // static_assert must be in a function, and not at class-level |
255 | | // because BaseTy isn't complete at class instantiation time, but |
256 | | // will be by the time this function is instantiated. |
257 | 2.43G | static void verifyTrailingObjectsAssertions() { |
258 | 2.43G | #ifdef LLVM_IS_FINAL |
259 | 2.43G | static_assert(LLVM_IS_FINAL(BaseTy), "BaseTy must be final."); |
260 | 2.43G | #endif |
261 | 2.43G | } llvm::TrailingObjects<llvm::AttributeSetNode, llvm::Attribute>::verifyTrailingObjectsAssertions() Line | Count | Source | 257 | 242M | static void verifyTrailingObjectsAssertions() { | 258 | 242M | #ifdef LLVM_IS_FINAL | 259 | 242M | static_assert(LLVM_IS_FINAL(BaseTy), "BaseTy must be final."); | 260 | 242M | #endif | 261 | 242M | } |
llvm::TrailingObjects<llvm::AttributeListImpl, llvm::AttributeSet>::verifyTrailingObjectsAssertions() Line | Count | Source | 257 | 2.19G | static void verifyTrailingObjectsAssertions() { | 258 | 2.19G | #ifdef LLVM_IS_FINAL | 259 | 2.19G | static_assert(LLVM_IS_FINAL(BaseTy), "BaseTy must be final."); | 260 | 2.19G | #endif | 261 | 2.19G | } |
LowerTypeTests.cpp:llvm::TrailingObjects<(anonymous namespace)::GlobalTypeMember, llvm::MDNode*>::verifyTrailingObjectsAssertions() Line | Count | Source | 257 | 274 | static void verifyTrailingObjectsAssertions() { | 258 | 274 | #ifdef LLVM_IS_FINAL | 259 | 274 | static_assert(LLVM_IS_FINAL(BaseTy), "BaseTy must be final."); | 260 | 274 | #endif | 261 | 274 | } |
|
262 | | |
263 | | // These two methods are the base of the recursion for this method. |
264 | | static const BaseTy * |
265 | | getTrailingObjectsImpl(const BaseTy *Obj, |
266 | 2.43G | TrailingObjectsBase::OverloadToken<BaseTy>) { |
267 | 2.43G | return Obj; |
268 | 2.43G | } LowerTypeTests.cpp:llvm::TrailingObjects<(anonymous namespace)::GlobalTypeMember, llvm::MDNode*>::getTrailingObjectsImpl((anonymous namespace)::GlobalTypeMember const*, llvm::trailing_objects_internal::TrailingObjectsBase::OverloadToken<(anonymous namespace)::GlobalTypeMember>) Line | Count | Source | 266 | 189 | TrailingObjectsBase::OverloadToken<BaseTy>) { | 267 | 189 | return Obj; | 268 | 189 | } |
llvm::TrailingObjects<llvm::AttributeSetNode, llvm::Attribute>::getTrailingObjectsImpl(llvm::AttributeSetNode const*, llvm::trailing_objects_internal::TrailingObjectsBase::OverloadToken<llvm::AttributeSetNode>) Line | Count | Source | 266 | 241M | TrailingObjectsBase::OverloadToken<BaseTy>) { | 267 | 241M | return Obj; | 268 | 241M | } |
llvm::TrailingObjects<llvm::AttributeListImpl, llvm::AttributeSet>::getTrailingObjectsImpl(llvm::AttributeListImpl const*, llvm::trailing_objects_internal::TrailingObjectsBase::OverloadToken<llvm::AttributeListImpl>) Line | Count | Source | 266 | 2.18G | TrailingObjectsBase::OverloadToken<BaseTy>) { | 267 | 2.18G | return Obj; | 268 | 2.18G | } |
|
269 | | |
270 | | static BaseTy * |
271 | | getTrailingObjectsImpl(BaseTy *Obj, |
272 | 1.16M | TrailingObjectsBase::OverloadToken<BaseTy>) { |
273 | 1.16M | return Obj; |
274 | 1.16M | } LowerTypeTests.cpp:llvm::TrailingObjects<(anonymous namespace)::GlobalTypeMember, llvm::MDNode*>::getTrailingObjectsImpl((anonymous namespace)::GlobalTypeMember*, llvm::trailing_objects_internal::TrailingObjectsBase::OverloadToken<(anonymous namespace)::GlobalTypeMember>) Line | Count | Source | 272 | 85 | TrailingObjectsBase::OverloadToken<BaseTy>) { | 273 | 85 | return Obj; | 274 | 85 | } |
llvm::TrailingObjects<llvm::AttributeListImpl, llvm::AttributeSet>::getTrailingObjectsImpl(llvm::AttributeListImpl*, llvm::trailing_objects_internal::TrailingObjectsBase::OverloadToken<llvm::AttributeListImpl>) Line | Count | Source | 272 | 803k | TrailingObjectsBase::OverloadToken<BaseTy>) { | 273 | 803k | return Obj; | 274 | 803k | } |
llvm::TrailingObjects<llvm::AttributeSetNode, llvm::Attribute>::getTrailingObjectsImpl(llvm::AttributeSetNode*, llvm::trailing_objects_internal::TrailingObjectsBase::OverloadToken<llvm::AttributeSetNode>) Line | Count | Source | 272 | 359k | TrailingObjectsBase::OverloadToken<BaseTy>) { | 273 | 359k | return Obj; | 274 | 359k | } |
|
275 | | |
276 | | // callNumTrailingObjects simply calls numTrailingObjects on the |
277 | | // provided Obj -- except when the type being queried is BaseTy |
278 | | // itself. There is always only one of the base object, so that case |
279 | | // is handled here. (An additional benefit of indirecting through |
280 | | // this function is that consumers only say "friend |
281 | | // TrailingObjects", and thus, only this class itself can call the |
282 | | // numTrailingObjects function.) |
283 | | static size_t |
284 | | callNumTrailingObjects(const BaseTy *Obj, |
285 | 2.43G | TrailingObjectsBase::OverloadToken<BaseTy>) { |
286 | 2.43G | return 1; |
287 | 2.43G | } llvm::TrailingObjects<llvm::AttributeSetNode, llvm::Attribute>::callNumTrailingObjects(llvm::AttributeSetNode const*, llvm::trailing_objects_internal::TrailingObjectsBase::OverloadToken<llvm::AttributeSetNode>) Line | Count | Source | 285 | 242M | TrailingObjectsBase::OverloadToken<BaseTy>) { | 286 | 242M | return 1; | 287 | 242M | } |
llvm::TrailingObjects<llvm::AttributeListImpl, llvm::AttributeSet>::callNumTrailingObjects(llvm::AttributeListImpl const*, llvm::trailing_objects_internal::TrailingObjectsBase::OverloadToken<llvm::AttributeListImpl>) Line | Count | Source | 285 | 2.19G | TrailingObjectsBase::OverloadToken<BaseTy>) { | 286 | 2.19G | return 1; | 287 | 2.19G | } |
LowerTypeTests.cpp:llvm::TrailingObjects<(anonymous namespace)::GlobalTypeMember, llvm::MDNode*>::callNumTrailingObjects((anonymous namespace)::GlobalTypeMember const*, llvm::trailing_objects_internal::TrailingObjectsBase::OverloadToken<(anonymous namespace)::GlobalTypeMember>) Line | Count | Source | 285 | 274 | TrailingObjectsBase::OverloadToken<BaseTy>) { | 286 | 274 | return 1; | 287 | 274 | } |
|
288 | | |
289 | | template <typename T> |
290 | | static size_t callNumTrailingObjects(const BaseTy *Obj, |
291 | | TrailingObjectsBase::OverloadToken<T>) { |
292 | | return Obj->numTrailingObjects(TrailingObjectsBase::OverloadToken<T>()); |
293 | | } |
294 | | |
295 | | public: |
296 | | // Make this (privately inherited) member public. |
297 | | #ifndef _MSC_VER |
298 | | using ParentType::OverloadToken; |
299 | | #else |
300 | | // MSVC bug prevents the above from working, at least up through CL |
301 | | // 19.10.24629. |
302 | | template <typename T> |
303 | | using OverloadToken = typename ParentType::template OverloadToken<T>; |
304 | | #endif |
305 | | |
306 | | /// Returns a pointer to the trailing object array of the given type |
307 | | /// (which must be one of those specified in the class template). The |
308 | | /// array may have zero or more elements in it. |
309 | 2.43G | template <typename T> const T *getTrailingObjects() const { |
310 | 2.43G | verifyTrailingObjectsAssertions(); |
311 | 2.43G | // Forwards to an impl function with overloads, since member |
312 | 2.43G | // function templates can't be specialized. |
313 | 2.43G | return this->getTrailingObjectsImpl( |
314 | 2.43G | static_cast<const BaseTy *>(this), |
315 | 2.43G | TrailingObjectsBase::OverloadToken<T>()); |
316 | 2.43G | } LowerTypeTests.cpp:llvm::MDNode* const* llvm::TrailingObjects<(anonymous namespace)::GlobalTypeMember, llvm::MDNode*>::getTrailingObjects<llvm::MDNode*>() const Line | Count | Source | 309 | 189 | template <typename T> const T *getTrailingObjects() const { | 310 | 189 | verifyTrailingObjectsAssertions(); | 311 | 189 | // Forwards to an impl function with overloads, since member | 312 | 189 | // function templates can't be specialized. | 313 | 189 | return this->getTrailingObjectsImpl( | 314 | 189 | static_cast<const BaseTy *>(this), | 315 | 189 | TrailingObjectsBase::OverloadToken<T>()); | 316 | 189 | } |
llvm::AttributeSet const* llvm::TrailingObjects<llvm::AttributeListImpl, llvm::AttributeSet>::getTrailingObjects<llvm::AttributeSet>() const Line | Count | Source | 309 | 2.18G | template <typename T> const T *getTrailingObjects() const { | 310 | 2.18G | verifyTrailingObjectsAssertions(); | 311 | 2.18G | // Forwards to an impl function with overloads, since member | 312 | 2.18G | // function templates can't be specialized. | 313 | 2.18G | return this->getTrailingObjectsImpl( | 314 | 2.18G | static_cast<const BaseTy *>(this), | 315 | 2.18G | TrailingObjectsBase::OverloadToken<T>()); | 316 | 2.18G | } |
llvm::Attribute const* llvm::TrailingObjects<llvm::AttributeSetNode, llvm::Attribute>::getTrailingObjects<llvm::Attribute>() const Line | Count | Source | 309 | 241M | template <typename T> const T *getTrailingObjects() const { | 310 | 241M | verifyTrailingObjectsAssertions(); | 311 | 241M | // Forwards to an impl function with overloads, since member | 312 | 241M | // function templates can't be specialized. | 313 | 241M | return this->getTrailingObjectsImpl( | 314 | 241M | static_cast<const BaseTy *>(this), | 315 | 241M | TrailingObjectsBase::OverloadToken<T>()); | 316 | 241M | } |
|
317 | | |
318 | | /// Returns a pointer to the trailing object array of the given type |
319 | | /// (which must be one of those specified in the class template). The |
320 | | /// array may have zero or more elements in it. |
321 | 1.16M | template <typename T> T *getTrailingObjects() { |
322 | 1.16M | verifyTrailingObjectsAssertions(); |
323 | 1.16M | // Forwards to an impl function with overloads, since member |
324 | 1.16M | // function templates can't be specialized. |
325 | 1.16M | return this->getTrailingObjectsImpl( |
326 | 1.16M | static_cast<BaseTy *>(this), TrailingObjectsBase::OverloadToken<T>()); |
327 | 1.16M | } llvm::Attribute* llvm::TrailingObjects<llvm::AttributeSetNode, llvm::Attribute>::getTrailingObjects<llvm::Attribute>() Line | Count | Source | 321 | 359k | template <typename T> T *getTrailingObjects() { | 322 | 359k | verifyTrailingObjectsAssertions(); | 323 | 359k | // Forwards to an impl function with overloads, since member | 324 | 359k | // function templates can't be specialized. | 325 | 359k | return this->getTrailingObjectsImpl( | 326 | 359k | static_cast<BaseTy *>(this), TrailingObjectsBase::OverloadToken<T>()); | 327 | 359k | } |
llvm::AttributeSet* llvm::TrailingObjects<llvm::AttributeListImpl, llvm::AttributeSet>::getTrailingObjects<llvm::AttributeSet>() Line | Count | Source | 321 | 803k | template <typename T> T *getTrailingObjects() { | 322 | 803k | verifyTrailingObjectsAssertions(); | 323 | 803k | // Forwards to an impl function with overloads, since member | 324 | 803k | // function templates can't be specialized. | 325 | 803k | return this->getTrailingObjectsImpl( | 326 | 803k | static_cast<BaseTy *>(this), TrailingObjectsBase::OverloadToken<T>()); | 327 | 803k | } |
LowerTypeTests.cpp:llvm::MDNode** llvm::TrailingObjects<(anonymous namespace)::GlobalTypeMember, llvm::MDNode*>::getTrailingObjects<llvm::MDNode*>() Line | Count | Source | 321 | 85 | template <typename T> T *getTrailingObjects() { | 322 | 85 | verifyTrailingObjectsAssertions(); | 323 | 85 | // Forwards to an impl function with overloads, since member | 324 | 85 | // function templates can't be specialized. | 325 | 85 | return this->getTrailingObjectsImpl( | 326 | 85 | static_cast<BaseTy *>(this), TrailingObjectsBase::OverloadToken<T>()); | 327 | 85 | } |
|
328 | | |
329 | | /// Returns the size of the trailing data, if an object were |
330 | | /// allocated with the given counts (The counts are in the same order |
331 | | /// as the template arguments). This does not include the size of the |
332 | | /// base object. The template arguments must be the same as those |
333 | | /// used in the class; they are supplied here redundantly only so |
334 | | /// that it's clear what the counts are counting in callers. |
335 | | template <typename... Tys> |
336 | | static constexpr typename std::enable_if< |
337 | | std::is_same<Foo<TrailingTys...>, Foo<Tys...>>::value, size_t>::type |
338 | | additionalSizeToAlloc(typename trailing_objects_internal::ExtractSecondType< |
339 | | TrailingTys, size_t>::type... Counts) { |
340 | | return ParentType::additionalSizeToAllocImpl(0, Counts...); |
341 | | } |
342 | | |
343 | | /// Returns the total size of an object if it were allocated with the |
344 | | /// given trailing object counts. This is the same as |
345 | | /// additionalSizeToAlloc, except it *does* include the size of the base |
346 | | /// object. |
347 | | template <typename... Tys> |
348 | | static constexpr typename std::enable_if< |
349 | | std::is_same<Foo<TrailingTys...>, Foo<Tys...>>::value, size_t>::type |
350 | | totalSizeToAlloc(typename trailing_objects_internal::ExtractSecondType< |
351 | 1.16M | TrailingTys, size_t>::type... Counts) { |
352 | 1.16M | return sizeof(BaseTy) + ParentType::additionalSizeToAllocImpl(0, Counts...); |
353 | 1.16M | } std::__1::enable_if<std::is_same<llvm::TrailingObjects<llvm::AttributeListImpl, llvm::AttributeSet>::Foo<llvm::AttributeSet>, llvm::TrailingObjects<llvm::AttributeListImpl, llvm::AttributeSet>::Foo<llvm::AttributeSet> >::value, unsigned long>::type llvm::TrailingObjects<llvm::AttributeListImpl, llvm::AttributeSet>::totalSizeToAlloc<llvm::AttributeSet>(unsigned long) Line | Count | Source | 351 | 803k | TrailingTys, size_t>::type... Counts) { | 352 | 803k | return sizeof(BaseTy) + ParentType::additionalSizeToAllocImpl(0, Counts...); | 353 | 803k | } |
std::__1::enable_if<std::is_same<llvm::TrailingObjects<llvm::AttributeSetNode, llvm::Attribute>::Foo<llvm::Attribute>, llvm::TrailingObjects<llvm::AttributeSetNode, llvm::Attribute>::Foo<llvm::Attribute> >::value, unsigned long>::type llvm::TrailingObjects<llvm::AttributeSetNode, llvm::Attribute>::totalSizeToAlloc<llvm::Attribute>(unsigned long) Line | Count | Source | 351 | 359k | TrailingTys, size_t>::type... Counts) { | 352 | 359k | return sizeof(BaseTy) + ParentType::additionalSizeToAllocImpl(0, Counts...); | 353 | 359k | } |
LowerTypeTests.cpp:std::__1::enable_if<std::is_same<llvm::TrailingObjects<(anonymous namespace)::GlobalTypeMember, llvm::MDNode*>::Foo<llvm::MDNode*>, llvm::TrailingObjects<(anonymous namespace)::GlobalTypeMember, llvm::MDNode*>::Foo<llvm::MDNode*> >::value, unsigned long>::type llvm::TrailingObjects<(anonymous namespace)::GlobalTypeMember, llvm::MDNode*>::totalSizeToAlloc<llvm::MDNode*>(unsigned long) Line | Count | Source | 351 | 85 | TrailingTys, size_t>::type... Counts) { | 352 | 85 | return sizeof(BaseTy) + ParentType::additionalSizeToAllocImpl(0, Counts...); | 353 | 85 | } |
|
354 | | |
355 | | /// A type where its ::with_counts template member has a ::type member |
356 | | /// suitable for use as uninitialized storage for an object with the given |
357 | | /// trailing object counts. The template arguments are similar to those |
358 | | /// of additionalSizeToAlloc. |
359 | | /// |
360 | | /// Use with FixedSizeStorageOwner, e.g.: |
361 | | /// |
362 | | /// \code{.cpp} |
363 | | /// |
364 | | /// MyObj::FixedSizeStorage<void *>::with_counts<1u>::type myStackObjStorage; |
365 | | /// MyObj::FixedSizeStorageOwner |
366 | | /// myStackObjOwner(new ((void *)&myStackObjStorage) MyObj); |
367 | | /// MyObj *const myStackObjPtr = myStackObjOwner.get(); |
368 | | /// |
369 | | /// \endcode |
370 | | template <typename... Tys> struct FixedSizeStorage { |
371 | | template <size_t... Counts> struct with_counts { |
372 | | enum { Size = totalSizeToAlloc<Tys...>(Counts...) }; |
373 | | typedef llvm::AlignedCharArray<alignof(BaseTy), Size> type; |
374 | | }; |
375 | | }; |
376 | | |
377 | | /// A type that acts as the owner for an object placed into fixed storage. |
378 | | class FixedSizeStorageOwner { |
379 | | public: |
380 | | FixedSizeStorageOwner(BaseTy *p) : p(p) {} |
381 | | ~FixedSizeStorageOwner() { |
382 | | assert(p && "FixedSizeStorageOwner owns null?"); |
383 | | p->~BaseTy(); |
384 | | } |
385 | | |
386 | | BaseTy *get() { return p; } |
387 | | const BaseTy *get() const { return p; } |
388 | | |
389 | | private: |
390 | | FixedSizeStorageOwner(const FixedSizeStorageOwner &) = delete; |
391 | | FixedSizeStorageOwner(FixedSizeStorageOwner &&) = delete; |
392 | | FixedSizeStorageOwner &operator=(const FixedSizeStorageOwner &) = delete; |
393 | | FixedSizeStorageOwner &operator=(FixedSizeStorageOwner &&) = delete; |
394 | | |
395 | | BaseTy *const p; |
396 | | }; |
397 | | }; |
398 | | |
399 | | } // end namespace llvm |
400 | | |
401 | | #endif |