Delete dead code: only functions are materializable.
[oota-llvm.git] / include / llvm / Support / TrailingObjects.h
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, as well as asserts that
20 /// the alignment of the classes involved are appropriate for the
21 /// usage. Additionally, it ensures that the base type is final --
22 /// deriving from a class that expects data appended immediately after
23 /// it is typically not safe.
24 ///
25 /// Users are expected to derive from this template, and provide
26 /// numTrailingObjects implementations for each trailing type,
27 /// e.g. like this sample:
28 ///
29 /// \code
30 /// class VarLengthObj : private TrailingObjects<VarLengthObj, int, double> {
31 ///   friend TrailingObjects;
32 ///
33 ///   unsigned NumInts, NumDoubles;
34 ///   size_t numTrailingObjects(OverloadToken<int>) const { return NumInts; }
35 ///   size_t numTrailingObjects(OverloadToken<double>) const {
36 ///     return NumDoubles;
37 ///   }
38 ///  };
39 /// \endcode
40 ///
41 /// You can access the appended arrays via 'getTrailingObjects', and
42 /// determine the size needed for allocation via
43 /// 'additionalSizeToAlloc' and 'totalSizeToAlloc'.
44 ///
45 /// All the methods implemented by this class are are intended for use
46 /// by the implementation of the class, not as part of its interface
47 /// (thus, private inheritance is suggested).
48 ///
49 //===----------------------------------------------------------------------===//
50
51 #ifndef LLVM_SUPPORT_TRAILINGOBJECTS_H
52 #define LLVM_SUPPORT_TRAILINGOBJECTS_H
53
54 #include <new>
55 #include <type_traits>
56 #include "llvm/Support/AlignOf.h"
57 #include "llvm/Support/Compiler.h"
58 #include "llvm/Support/type_traits.h"
59
60 namespace llvm {
61
62 /// The base class for TrailingObjects* classes.
63 class TrailingObjectsBase {
64 protected:
65   /// OverloadToken's purpose is to allow specifying function overloads
66   /// for different types, without actually taking the types as
67   /// parameters. (Necessary because member function templates cannot
68   /// be specialized, so overloads must be used instead of
69   /// specialization.)
70   template <typename T> struct OverloadToken {};
71 };
72
73 // Internally used to indicate that the user didn't supply this value,
74 // so the explicit-specialization for fewer args will be used.
75 class NoTrailingTypeArg {};
76
77 // TODO: Consider using a single variadic implementation instead of
78 // multiple copies of the TrailingObjects template? [but, variadic
79 // template recursive implementations are annoying...]
80
81 /// This is the two-type version of the TrailingObjects template; see
82 /// file docstring for details.
83 template <typename BaseTy, typename TrailingTy1,
84           typename TrailingTy2 = NoTrailingTypeArg>
85 class TrailingObjects : public TrailingObjectsBase {
86 private:
87   // Contains static_assert statements for the alignment of the
88   // types. Must not be at class-level, because BaseTy isn't complete
89   // at class instantiation time, but will be by the time this
90   // function is instantiated.
91   static void verifyTrailingObjectsAssertions() {
92     static_assert(llvm::AlignOf<BaseTy>::Alignment >=
93                       llvm::AlignOf<TrailingTy1>::Alignment,
94                   "TrailingTy1 requires more alignment than BaseTy provides");
95     static_assert(
96         llvm::AlignOf<TrailingTy1>::Alignment >=
97             llvm::AlignOf<TrailingTy2>::Alignment,
98         "TrailingTy2 requires more alignment than TrailingTy1 provides");
99
100 #ifdef LLVM_IS_FINAL
101     static_assert(LLVM_IS_FINAL(BaseTy), "BaseTy must be final.");
102 #endif
103   }
104
105   // The next four functions are internal helpers for getTrailingObjects.
106   static const TrailingTy1 *getTrailingObjectsImpl(const BaseTy *Obj,
107                                                    OverloadToken<TrailingTy1>) {
108     return reinterpret_cast<const TrailingTy1 *>(Obj + 1);
109   }
110
111   static TrailingTy1 *getTrailingObjectsImpl(BaseTy *Obj,
112                                              OverloadToken<TrailingTy1>) {
113     return reinterpret_cast<TrailingTy1 *>(Obj + 1);
114   }
115
116   static const TrailingTy2 *getTrailingObjectsImpl(const BaseTy *Obj,
117                                                    OverloadToken<TrailingTy2>) {
118     return reinterpret_cast<const TrailingTy2 *>(
119         getTrailingObjectsImpl(Obj, OverloadToken<TrailingTy1>()) +
120         Obj->numTrailingObjects(OverloadToken<TrailingTy1>()));
121   }
122
123   static TrailingTy2 *getTrailingObjectsImpl(BaseTy *Obj,
124                                              OverloadToken<TrailingTy2>) {
125     return reinterpret_cast<TrailingTy2 *>(
126         getTrailingObjectsImpl(Obj, OverloadToken<TrailingTy1>()) +
127         Obj->numTrailingObjects(OverloadToken<TrailingTy1>()));
128   }
129
130 protected:
131   /// Returns a pointer to the trailing object array of the given type
132   /// (which must be one of those specified in the class template). The
133   /// array may have zero or more elements in it.
134   template <typename T> const T *getTrailingObjects() const {
135     verifyTrailingObjectsAssertions();
136     // Forwards to an impl function with overloads, since member
137     // function templates can't be specialized.
138     return getTrailingObjectsImpl(static_cast<const BaseTy *>(this),
139                                   OverloadToken<T>());
140   }
141
142   /// Returns a pointer to the trailing object array of the given type
143   /// (which must be one of those specified in the class template). The
144   /// array may have zero or more elements in it.
145   template <typename T> T *getTrailingObjects() {
146     verifyTrailingObjectsAssertions();
147     // Forwards to an impl function with overloads, since member
148     // function templates can't be specialized.
149     return getTrailingObjectsImpl(static_cast<BaseTy *>(this),
150                                   OverloadToken<T>());
151   }
152
153   /// Returns the size of the trailing data, if an object were
154   /// allocated with the given counts (The counts are in the same order
155   /// as the template arguments). This does not include the size of the
156   /// base object.  The template arguments must be the same as those
157   /// used in the class; they are supplied here redundantly only so
158   /// that it's clear what the counts are counting in callers.
159   template <typename Ty1, typename Ty2,
160             typename std::enable_if<std::is_same<Ty1, TrailingTy1>::value &&
161                                         std::is_same<Ty2, TrailingTy2>::value,
162                                     int>::type = 0>
163   static LLVM_CONSTEXPR size_t additionalSizeToAlloc(size_t Count1, size_t Count2) {
164     return sizeof(TrailingTy1) * Count1 + sizeof(TrailingTy2) * Count2;
165   }
166
167   /// Returns the total size of an object if it were allocated with the
168   /// given trailing object counts. This is the same as
169   /// additionalSizeToAlloc, except it *does* include the size of the base
170   /// object.
171   template <typename Ty1, typename Ty2>
172   static LLVM_CONSTEXPR size_t totalSizeToAlloc(size_t Count1, size_t Count2) {
173     return sizeof(BaseTy) + additionalSizeToAlloc<Ty1, Ty2>(Count1, Count2);
174   }
175 };
176
177 /// This is the one-type version of the TrailingObjects template. See
178 /// the two-type version for more documentation.
179 template <typename BaseTy, typename TrailingTy1>
180 class TrailingObjects<BaseTy, TrailingTy1, NoTrailingTypeArg>
181     : public TrailingObjectsBase {
182 private:
183   static void verifyTrailingObjectsAssertions() {
184     static_assert(llvm::AlignOf<BaseTy>::Alignment >=
185                       llvm::AlignOf<TrailingTy1>::Alignment,
186                   "TrailingTy1 requires more alignment than BaseTy provides");
187
188 #ifdef LLVM_IS_FINAL
189     static_assert(LLVM_IS_FINAL(BaseTy), "BaseTy must be final.");
190 #endif
191   }
192
193   static const TrailingTy1 *getTrailingObjectsImpl(const BaseTy *Obj,
194                                                    OverloadToken<TrailingTy1>) {
195     return reinterpret_cast<const TrailingTy1 *>(Obj + 1);
196   }
197
198   static TrailingTy1 *getTrailingObjectsImpl(BaseTy *Obj,
199                                              OverloadToken<TrailingTy1>) {
200     return reinterpret_cast<TrailingTy1 *>(Obj + 1);
201   }
202
203 protected:
204   template <typename T> const T *getTrailingObjects() const {
205     verifyTrailingObjectsAssertions();
206     return getTrailingObjectsImpl(static_cast<const BaseTy *>(this),
207                                   OverloadToken<T>());
208   }
209
210   template <typename T> T *getTrailingObjects() {
211     verifyTrailingObjectsAssertions();
212     return getTrailingObjectsImpl(static_cast<BaseTy *>(this),
213                                   OverloadToken<T>());
214   }
215
216   template <typename Ty1,
217             typename std::enable_if<std::is_same<Ty1, TrailingTy1>::value,
218                                     int>::type = 0>
219   static LLVM_CONSTEXPR size_t additionalSizeToAlloc(size_t Count1) {
220     return sizeof(TrailingTy1) * Count1;
221   }
222
223   template <typename Ty1>
224   static LLVM_CONSTEXPR size_t totalSizeToAlloc(size_t Count1) {
225     return sizeof(BaseTy) + additionalSizeToAlloc<Ty1>(Count1);
226   }
227 };
228
229 } // end namespace llvm
230
231 #endif