1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 : * vim: set ts=8 sw=4 et tw=99 ft=cpp:
3 : *
4 : * ***** BEGIN LICENSE BLOCK *****
5 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 : *
7 : * The contents of this file are subject to the Mozilla Public License Version
8 : * 1.1 (the "License"); you may not use this file except in compliance with
9 : * the License. You may obtain a copy of the License at:
10 : * http://www.mozilla.org/MPL/
11 : *
12 : * Software distributed under the License is distributed on an "AS IS" basis,
13 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 : * for the specific language governing rights and limitations under the
15 : * License.
16 : *
17 : * The Original Code is Mozilla Code.
18 : *
19 : * The Initial Developer of the Original Code is
20 : * The Mozilla Foundation
21 : * Portions created by the Initial Developer are Copyright (C) 2011
22 : * the Initial Developer. All Rights Reserved.
23 : *
24 : * Contributor(s):
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either the GNU General Public License Version 2 or later (the "GPL"), or
28 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : /*
41 : * Miscellaneous uncategorized functionality. Please add new functionality to
42 : * new headers, or to other appropriate existing headers, not here.
43 : */
44 :
45 : #ifndef mozilla_Util_h_
46 : #define mozilla_Util_h_
47 :
48 : #include "mozilla/Assertions.h"
49 : #include "mozilla/Attributes.h"
50 : #include "mozilla/Types.h"
51 :
52 : #ifdef __cplusplus
53 :
54 : namespace mozilla {
55 :
56 : /**
57 : * DebugOnly contains a value of type T, but only in debug builds. In
58 : * release builds, it does not contain a value. This helper is
59 : * intended to be used along with ASSERT()-style macros, allowing one
60 : * to write
61 : *
62 : * DebugOnly<bool> check = Func();
63 : * ASSERT(check);
64 : *
65 : * more concisely than declaring |check| conditional on #ifdef DEBUG,
66 : * but also without allocating storage space for |check| in release
67 : * builds.
68 : *
69 : * DebugOnly instances can only be coerced to T in debug builds; in
70 : * release builds, they don't have a value so type coercion is not
71 : * well defined.
72 : */
73 : template <typename T>
74 : struct DebugOnly
75 : {
76 : #ifdef DEBUG
77 : T value;
78 :
79 0 : DebugOnly() {}
80 246254409 : DebugOnly(const T& other) : value(other) {}
81 : DebugOnly(const DebugOnly& other) : value(other.value) {}
82 167000 : DebugOnly& operator=(const T& rhs) {
83 167000 : value = rhs;
84 167000 : return *this;
85 : }
86 495436358 : void operator++(int) {
87 495436358 : value++;
88 495436358 : }
89 52010 : void operator--(int) {
90 52010 : value--;
91 52010 : }
92 :
93 549338810 : operator T&() { return value; }
94 : operator const T&() const { return value; }
95 :
96 21187703 : T& operator->() { return value; }
97 :
98 : #else
99 : DebugOnly() {}
100 : DebugOnly(const T&) {}
101 : DebugOnly(const DebugOnly&) {}
102 : DebugOnly& operator=(const T&) { return *this; }
103 : void operator++(int) {}
104 : void operator--(int) {}
105 : #endif
106 :
107 : /*
108 : * DebugOnly must always have a destructor or else it will
109 : * generate "unused variable" warnings, exactly what it's intended
110 : * to avoid!
111 : */
112 246254378 : ~DebugOnly() {}
113 : };
114 :
115 : /*
116 : * This class, and the corresponding macro MOZ_ALIGNOF, figure out how many
117 : * bytes of alignment a given type needs.
118 : */
119 : template<class T>
120 : struct AlignmentFinder
121 : {
122 : private:
123 : struct Aligner
124 : {
125 : char c;
126 : T t;
127 : };
128 :
129 : public:
130 : static const int alignment = sizeof(Aligner) - sizeof(T);
131 : };
132 :
133 : #define MOZ_ALIGNOF(T) mozilla::AlignmentFinder<T>::alignment
134 :
135 : /*
136 : * Declare the MOZ_ALIGNED_DECL macro for declaring aligned types.
137 : *
138 : * For instance,
139 : *
140 : * MOZ_ALIGNED_DECL(char arr[2], 8);
141 : *
142 : * will declare a two-character array |arr| aligned to 8 bytes.
143 : */
144 :
145 : #if defined(__GNUC__)
146 : # define MOZ_ALIGNED_DECL(_type, _align) \
147 : _type __attribute__((aligned(_align)))
148 : #elif defined(_MSC_VER)
149 : # define MOZ_ALIGNED_DECL(_type, _align) \
150 : __declspec(align(_align)) _type
151 : #else
152 : # warning "We don't know how to align variables on this compiler."
153 : # define MOZ_ALIGNED_DECL(_type, _align) _type
154 : #endif
155 :
156 : /*
157 : * AlignedElem<N> is a structure whose alignment is guaranteed to be at least N bytes.
158 : *
159 : * We support 1, 2, 4, 8, and 16-bit alignment.
160 : */
161 : template<size_t align>
162 : struct AlignedElem;
163 :
164 : /*
165 : * We have to specialize this template because GCC doesn't like __attribute__((aligned(foo))) where
166 : * foo is a template parameter.
167 : */
168 :
169 : template<>
170 : struct AlignedElem<1>
171 : {
172 : MOZ_ALIGNED_DECL(uint8_t elem, 1);
173 : };
174 :
175 : template<>
176 : struct AlignedElem<2>
177 : {
178 : MOZ_ALIGNED_DECL(uint8_t elem, 2);
179 : };
180 :
181 : template<>
182 : struct AlignedElem<4>
183 : {
184 : MOZ_ALIGNED_DECL(uint8_t elem, 4);
185 : };
186 :
187 : template<>
188 : struct AlignedElem<8>
189 : {
190 : MOZ_ALIGNED_DECL(uint8_t elem, 8);
191 : };
192 :
193 : template<>
194 : struct AlignedElem<16>
195 : {
196 : MOZ_ALIGNED_DECL(uint8_t elem, 16);
197 : };
198 :
199 : /*
200 : * This utility pales in comparison to Boost's aligned_storage. The utility
201 : * simply assumes that uint64_t is enough alignment for anyone. This may need
202 : * to be extended one day...
203 : *
204 : * As an important side effect, pulling the storage into this template is
205 : * enough obfuscation to confuse gcc's strict-aliasing analysis into not giving
206 : * false negatives when we cast from the char buffer to whatever type we've
207 : * constructed using the bytes.
208 : */
209 : template <size_t nbytes>
210 : struct AlignedStorage
211 : {
212 : union U {
213 : char bytes[nbytes];
214 : uint64_t _;
215 : } u;
216 :
217 1071926031 : const void *addr() const { return u.bytes; }
218 57015103 : void *addr() { return u.bytes; }
219 : };
220 :
221 : template <class T>
222 : struct AlignedStorage2
223 : {
224 : union U {
225 : char bytes[sizeof(T)];
226 : uint64_t _;
227 : } u;
228 :
229 : const T *addr() const { return (const T *)u.bytes; }
230 10352745 : T *addr() { return (T *)(void *)u.bytes; }
231 : };
232 :
233 : /*
234 : * Small utility for lazily constructing objects without using dynamic storage.
235 : * When a Maybe<T> is constructed, it is |empty()|, i.e., no value of T has
236 : * been constructed and no T destructor will be called when the Maybe<T> is
237 : * destroyed. Upon calling |construct|, a T object will be constructed with the
238 : * given arguments and that object will be destroyed when the owning Maybe<T>
239 : * is destroyed.
240 : *
241 : * N.B. GCC seems to miss some optimizations with Maybe and may generate extra
242 : * branches/loads/stores. Use with caution on hot paths.
243 : */
244 : template <class T>
245 : class Maybe
246 : {
247 : AlignedStorage2<T> storage;
248 : bool constructed;
249 :
250 3732848 : T &asT() { return *storage.addr(); }
251 :
252 : explicit Maybe(const Maybe &other);
253 : const Maybe &operator=(const Maybe &other);
254 :
255 : public:
256 14777697 : Maybe() { constructed = false; }
257 14777692 : ~Maybe() { if (constructed) asT().~T(); }
258 :
259 389303 : bool empty() const { return !constructed; }
260 :
261 260965 : void construct() {
262 260965 : MOZ_ASSERT(!constructed);
263 260965 : new(storage.addr()) T();
264 260965 : constructed = true;
265 260965 : }
266 :
267 : template <class T1>
268 32032 : void construct(const T1 &t1) {
269 32032 : MOZ_ASSERT(!constructed);
270 32032 : new(storage.addr()) T(t1);
271 32032 : constructed = true;
272 32032 : }
273 :
274 : template <class T1, class T2>
275 2862540 : void construct(const T1 &t1, const T2 &t2) {
276 2862540 : MOZ_ASSERT(!constructed);
277 2862540 : new(storage.addr()) T(t1, t2);
278 2862540 : constructed = true;
279 2862540 : }
280 :
281 : template <class T1, class T2, class T3>
282 : void construct(const T1 &t1, const T2 &t2, const T3 &t3) {
283 : MOZ_ASSERT(!constructed);
284 : new(storage.addr()) T(t1, t2, t3);
285 : constructed = true;
286 : }
287 :
288 : template <class T1, class T2, class T3, class T4>
289 0 : void construct(const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4) {
290 0 : MOZ_ASSERT(!constructed);
291 0 : new(storage.addr()) T(t1, t2, t3, t4);
292 0 : constructed = true;
293 0 : }
294 :
295 55784 : T *addr() {
296 55784 : MOZ_ASSERT(constructed);
297 55784 : return &asT();
298 : }
299 :
300 782492 : T &ref() {
301 782492 : MOZ_ASSERT(constructed);
302 782492 : return asT();
303 : }
304 :
305 : const T &ref() const {
306 : MOZ_ASSERT(constructed);
307 : return const_cast<Maybe *>(this)->asT();
308 : }
309 :
310 260965 : void destroy() {
311 260965 : ref().~T();
312 260965 : constructed = false;
313 260965 : }
314 :
315 127756 : void destroyIfConstructed() {
316 127756 : if (!empty())
317 1219 : destroy();
318 127756 : }
319 : };
320 :
321 : /*
322 : * Safely subtract two pointers when it is known that end >= begin. This avoids
323 : * the common compiler bug that if (size_t(end) - size_t(begin)) has the MSB
324 : * set, the unsigned subtraction followed by right shift will produce -1, or
325 : * size_t(-1), instead of the real difference.
326 : */
327 : template <class T>
328 : MOZ_ALWAYS_INLINE size_t
329 48650217 : PointerRangeSize(T* begin, T* end)
330 : {
331 48650217 : MOZ_ASSERT(end >= begin);
332 48650217 : return (size_t(end) - size_t(begin)) / sizeof(T);
333 : }
334 :
335 : /*
336 : * Compute the length of an array with constant length. (Use of this method
337 : * with a non-array pointer will not compile.)
338 : *
339 : * Beware of the implicit trailing '\0' when using this with string constants.
340 : */
341 : template<typename T, size_t N>
342 : size_t
343 149315535 : ArrayLength(T (&arr)[N])
344 : {
345 149315535 : return N;
346 : }
347 :
348 : /*
349 : * Compute the address one past the last element of a constant-length array.
350 : *
351 : * Beware of the implicit trailing '\0' when using this with string constants.
352 : */
353 : template<typename T, size_t N>
354 : T*
355 3627433 : ArrayEnd(T (&arr)[N])
356 : {
357 3627433 : return arr + ArrayLength(arr);
358 : }
359 :
360 : } /* namespace mozilla */
361 :
362 : #endif /* __cplusplus */
363 :
364 : #endif /* mozilla_Util_h_ */
|