|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
|
3 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 /* A class for lazily constructing an object without sticking it on the heap. */ |
|
8 |
|
9 #ifndef mozilla_Maybe_h |
|
10 #define mozilla_Maybe_h |
|
11 |
|
12 #include "mozilla/Alignment.h" |
|
13 #include "mozilla/Assertions.h" |
|
14 |
|
15 // For placement new |
|
16 #include <new> |
|
17 |
|
18 namespace mozilla { |
|
19 |
|
20 /* |
|
21 * Small utility for lazily constructing objects without using dynamic storage. |
|
22 * When a Maybe<T> is constructed, it is |empty()|, i.e., no value of T has |
|
23 * been constructed and no T destructor will be called when the Maybe<T> is |
|
24 * destroyed. Upon calling |construct|, a T object will be constructed with the |
|
25 * given arguments and that object will be destroyed when the owning Maybe<T> |
|
26 * is destroyed. |
|
27 * |
|
28 * N.B. GCC seems to miss some optimizations with Maybe and may generate extra |
|
29 * branches/loads/stores. Use with caution on hot paths. |
|
30 */ |
|
31 template<class T> |
|
32 class Maybe |
|
33 { |
|
34 AlignedStorage2<T> storage; |
|
35 bool constructed; |
|
36 |
|
37 T& asT() { return *storage.addr(); } |
|
38 |
|
39 public: |
|
40 Maybe() { constructed = false; } |
|
41 ~Maybe() { if (constructed) asT().~T(); } |
|
42 |
|
43 bool empty() const { return !constructed; } |
|
44 |
|
45 void construct() { |
|
46 MOZ_ASSERT(!constructed); |
|
47 ::new (storage.addr()) T(); |
|
48 constructed = true; |
|
49 } |
|
50 |
|
51 template<class T1> |
|
52 void construct(const T1& t1) { |
|
53 MOZ_ASSERT(!constructed); |
|
54 ::new (storage.addr()) T(t1); |
|
55 constructed = true; |
|
56 } |
|
57 |
|
58 template<class T1, class T2> |
|
59 void construct(const T1& t1, const T2& t2) { |
|
60 MOZ_ASSERT(!constructed); |
|
61 ::new (storage.addr()) T(t1, t2); |
|
62 constructed = true; |
|
63 } |
|
64 |
|
65 template<class T1, class T2, class T3> |
|
66 void construct(const T1& t1, const T2& t2, const T3& t3) { |
|
67 MOZ_ASSERT(!constructed); |
|
68 ::new (storage.addr()) T(t1, t2, t3); |
|
69 constructed = true; |
|
70 } |
|
71 |
|
72 template<class T1, class T2, class T3, class T4> |
|
73 void construct(const T1& t1, const T2& t2, const T3& t3, const T4& t4) { |
|
74 MOZ_ASSERT(!constructed); |
|
75 ::new (storage.addr()) T(t1, t2, t3, t4); |
|
76 constructed = true; |
|
77 } |
|
78 |
|
79 template<class T1, class T2, class T3, class T4, class T5> |
|
80 void construct(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5) { |
|
81 MOZ_ASSERT(!constructed); |
|
82 ::new (storage.addr()) T(t1, t2, t3, t4, t5); |
|
83 constructed = true; |
|
84 } |
|
85 |
|
86 template<class T1, class T2, class T3, class T4, class T5, |
|
87 class T6> |
|
88 void construct(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5, |
|
89 const T6& t6) { |
|
90 MOZ_ASSERT(!constructed); |
|
91 ::new (storage.addr()) T(t1, t2, t3, t4, t5, t6); |
|
92 constructed = true; |
|
93 } |
|
94 |
|
95 template<class T1, class T2, class T3, class T4, class T5, |
|
96 class T6, class T7> |
|
97 void construct(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5, |
|
98 const T6& t6, const T7& t7) { |
|
99 MOZ_ASSERT(!constructed); |
|
100 ::new (storage.addr()) T(t1, t2, t3, t4, t5, t6, t7); |
|
101 constructed = true; |
|
102 } |
|
103 |
|
104 template<class T1, class T2, class T3, class T4, class T5, |
|
105 class T6, class T7, class T8> |
|
106 void construct(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5, |
|
107 const T6& t6, const T7& t7, const T8& t8) { |
|
108 MOZ_ASSERT(!constructed); |
|
109 ::new (storage.addr()) T(t1, t2, t3, t4, t5, t6, t7, t8); |
|
110 constructed = true; |
|
111 } |
|
112 |
|
113 template<class T1, class T2, class T3, class T4, class T5, |
|
114 class T6, class T7, class T8, class T9> |
|
115 void construct(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5, |
|
116 const T6& t6, const T7& t7, const T8& t8, const T9& t9) { |
|
117 MOZ_ASSERT(!constructed); |
|
118 ::new (storage.addr()) T(t1, t2, t3, t4, t5, t6, t7, t8, t9); |
|
119 constructed = true; |
|
120 } |
|
121 |
|
122 template<class T1, class T2, class T3, class T4, class T5, |
|
123 class T6, class T7, class T8, class T9, class T10> |
|
124 void construct(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5, |
|
125 const T6& t6, const T7& t7, const T8& t8, const T9& t9, const T10& t10) { |
|
126 MOZ_ASSERT(!constructed); |
|
127 ::new (storage.addr()) T(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); |
|
128 constructed = true; |
|
129 } |
|
130 |
|
131 T* addr() { |
|
132 MOZ_ASSERT(constructed); |
|
133 return &asT(); |
|
134 } |
|
135 |
|
136 T& ref() { |
|
137 MOZ_ASSERT(constructed); |
|
138 return asT(); |
|
139 } |
|
140 |
|
141 const T& ref() const { |
|
142 MOZ_ASSERT(constructed); |
|
143 return const_cast<Maybe*>(this)->asT(); |
|
144 } |
|
145 |
|
146 void destroy() { |
|
147 ref().~T(); |
|
148 constructed = false; |
|
149 } |
|
150 |
|
151 void destroyIfConstructed() { |
|
152 if (!empty()) |
|
153 destroy(); |
|
154 } |
|
155 |
|
156 private: |
|
157 Maybe(const Maybe& other) MOZ_DELETE; |
|
158 const Maybe& operator=(const Maybe& other) MOZ_DELETE; |
|
159 }; |
|
160 |
|
161 } // namespace mozilla |
|
162 |
|
163 #endif /* mozilla_Maybe_h */ |