blob: a5d430cff3d9bc40e136e76d417439c362fc9b7a [file] [log] [blame]
Brian Silverman70325d62015-09-20 17:00:43 -04001// Copyright (c) 2006, Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14// * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29// ---
30//
31// Author: kenton@google.com (Kenton Varda)
32//
33// ManualConstructor statically-allocates space in which to store some
34// object, but does not initialize it. You can then call the constructor
35// and destructor for the object yourself as you see fit. This is useful
36// for memory management optimizations, where you want to initialize and
37// destroy an object multiple times but only allocate it once.
38//
39// (When I say ManualConstructor statically allocates space, I mean that
40// the ManualConstructor object itself is forced to be the right size.)
41//
42// For example usage, check out util/gtl/small_map.h.
43
44#ifndef UTIL_GTL_MANUAL_CONSTRUCTOR_H_
45#define UTIL_GTL_MANUAL_CONSTRUCTOR_H_
46
47#include <config.h>
48
49namespace ctemplate {
50
51namespace util {
52namespace gtl {
53namespace internal {
54
55//
56// Provides a char array with the exact same alignment as another type. The
57// first parameter must be a complete type, the second parameter is how many
58// of that type to provide space for.
59//
60// UTIL_GTL_ALIGNED_CHAR_ARRAY(struct stat, 16) storage_;
61//
62// Because MSVC and older GCCs require that the argument to their alignment
63// construct to be a literal constant integer, we use a template instantiated
64// at all the possible powers of two.
65#ifndef SWIG
66template<int alignment, int size> struct AlignType { };
67template<int size> struct AlignType<0, size> { typedef char result[size]; };
68#if defined(_MSC_VER)
69#define UTIL_GTL_ALIGN_ATTRIBUTE(X) __declspec(align(X))
70#define UTIL_GTL_ALIGN_OF(T) __alignof(T)
71#elif defined(__GNUC__) || defined(__APPLE__) || defined(__INTEL_COMPILER) \
72 || defined(__nacl__)
73#define UTIL_GTL_ALIGN_ATTRIBUTE(X) __attribute__((aligned(X)))
74#define UTIL_GTL_ALIGN_OF(T) __alignof__(T)
75#endif
76
77#if defined(UTIL_GTL_ALIGN_ATTRIBUTE)
78
79#define UTIL_GTL_ALIGNTYPE_TEMPLATE(X) \
80 template<int size> struct AlignType<X, size> { \
81 typedef UTIL_GTL_ALIGN_ATTRIBUTE(X) char result[size]; \
82 }
83
84UTIL_GTL_ALIGNTYPE_TEMPLATE(1);
85UTIL_GTL_ALIGNTYPE_TEMPLATE(2);
86UTIL_GTL_ALIGNTYPE_TEMPLATE(4);
87UTIL_GTL_ALIGNTYPE_TEMPLATE(8);
88UTIL_GTL_ALIGNTYPE_TEMPLATE(16);
89UTIL_GTL_ALIGNTYPE_TEMPLATE(32);
90UTIL_GTL_ALIGNTYPE_TEMPLATE(64);
91UTIL_GTL_ALIGNTYPE_TEMPLATE(128);
92UTIL_GTL_ALIGNTYPE_TEMPLATE(256);
93UTIL_GTL_ALIGNTYPE_TEMPLATE(512);
94UTIL_GTL_ALIGNTYPE_TEMPLATE(1024);
95UTIL_GTL_ALIGNTYPE_TEMPLATE(2048);
96UTIL_GTL_ALIGNTYPE_TEMPLATE(4096);
97UTIL_GTL_ALIGNTYPE_TEMPLATE(8192);
98// Any larger and MSVC++ will complain.
99
100#define UTIL_GTL_ALIGNED_CHAR_ARRAY(T, Size) \
101 typename util::gtl::internal::AlignType<UTIL_GTL_ALIGN_OF(T), \
102 sizeof(T) * Size>::result
103
104#undef UTIL_GTL_ALIGNTYPE_TEMPLATE
105#undef UTIL_GTL_ALIGN_ATTRIBUTE
106
107#else // defined(UTIL_GTL_ALIGN_ATTRIBUTE)
108#error "You must define UTIL_GTL_ALIGNED_CHAR_ARRAY for your compiler."
109#endif // defined(UTIL_GTL_ALIGN_ATTRIBUTE)
110
111#else // !SWIG
112
113// SWIG can't represent alignment and doesn't care about alignment on data
114// members (it works fine without it).
115template<typename Size>
116struct AlignType { typedef char result[Size]; };
117#define UTIL_GTL_ALIGNED_CHAR_ARRAY(T, Size) \
118 util::gtl::internal::AlignType<Size * sizeof(T)>::result
119
120#endif // !SWIG
121
122} // namespace internal
123} // namespace gtl
124} // namespace util
125
126template <typename Type>
127class ManualConstructor {
128 public:
129 // No constructor or destructor because one of the most useful uses of
130 // this class is as part of a union, and members of a union cannot have
131 // constructors or destructors. And, anyway, the whole point of this
132 // class is to bypass these.
133
134 inline Type* get() {
135 return reinterpret_cast<Type*>(space_);
136 }
137 inline const Type* get() const {
138 return reinterpret_cast<const Type*>(space_);
139 }
140
141 inline Type* operator->() { return get(); }
142 inline const Type* operator->() const { return get(); }
143
144 inline Type& operator*() { return *get(); }
145 inline const Type& operator*() const { return *get(); }
146
147 // You can pass up to four constructor arguments as arguments of Init().
148 inline void Init() {
149 new(space_) Type;
150 }
151
152 template <typename T1>
153 inline void Init(const T1& p1) {
154 new(space_) Type(p1);
155 }
156
157 template <typename T1, typename T2>
158 inline void Init(const T1& p1, const T2& p2) {
159 new(space_) Type(p1, p2);
160 }
161
162 template <typename T1, typename T2, typename T3>
163 inline void Init(const T1& p1, const T2& p2, const T3& p3) {
164 new(space_) Type(p1, p2, p3);
165 }
166
167 template <typename T1, typename T2, typename T3, typename T4>
168 inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4) {
169 new(space_) Type(p1, p2, p3, p4);
170 }
171
172 template <typename T1, typename T2, typename T3, typename T4, typename T5>
173 inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
174 const T5& p5) {
175 new(space_) Type(p1, p2, p3, p4, p5);
176 }
177
178 template <typename T1, typename T2, typename T3, typename T4, typename T5,
179 typename T6>
180 inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
181 const T5& p5, const T6& p6) {
182 new(space_) Type(p1, p2, p3, p4, p5, p6);
183 }
184
185 template <typename T1, typename T2, typename T3, typename T4, typename T5,
186 typename T6, typename T7>
187 inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
188 const T5& p5, const T6& p6, const T7& p7) {
189 new(space_) Type(p1, p2, p3, p4, p5, p6, p7);
190 }
191
192 template <typename T1, typename T2, typename T3, typename T4, typename T5,
193 typename T6, typename T7, typename T8>
194 inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
195 const T5& p5, const T6& p6, const T7& p7, const T8& p8) {
196 new(space_) Type(p1, p2, p3, p4, p5, p6, p7, p8);
197 }
198
199 template <typename T1, typename T2, typename T3, typename T4, typename T5,
200 typename T6, typename T7, typename T8, typename T9>
201 inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
202 const T5& p5, const T6& p6, const T7& p7, const T8& p8,
203 const T9& p9) {
204 new(space_) Type(p1, p2, p3, p4, p5, p6, p7, p8, p9);
205 }
206
207 template <typename T1, typename T2, typename T3, typename T4, typename T5,
208 typename T6, typename T7, typename T8, typename T9, typename T10>
209 inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
210 const T5& p5, const T6& p6, const T7& p7, const T8& p8,
211 const T9& p9, const T10& p10) {
212 new(space_) Type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);
213 }
214
215 template <typename T1, typename T2, typename T3, typename T4, typename T5,
216 typename T6, typename T7, typename T8, typename T9, typename T10,
217 typename T11>
218 inline void Init(const T1& p1, const T2& p2, const T3& p3, const T4& p4,
219 const T5& p5, const T6& p6, const T7& p7, const T8& p8,
220 const T9& p9, const T10& p10, const T11& p11) {
221 new(space_) Type(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11);
222 }
223
224 inline void Destroy() {
225 get()->~Type();
226 }
227
228 private:
229 UTIL_GTL_ALIGNED_CHAR_ARRAY(Type, 1) space_;
230};
231
232#undef UTIL_GTL_ALIGNED_CHAR_ARRAY
233#undef UTIL_GTL_ALIGN_OF
234
235}
236
237#endif // UTIL_GTL_MANUAL_CONSTRUCTOR_H_