Backout 2ea2669b53c3, Bug 917642 - [Helix] Please update the helix blobs
[gecko.git] / mfbt / Maybe.h
blob25683a28ab1ce0737d61c8c482cdab1e71ac6e46
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/. */
7 /* A class for lazily constructing an object without sticking it on the heap. */
9 #ifndef mozilla_Maybe_h
10 #define mozilla_Maybe_h
12 #include "mozilla/Alignment.h"
13 #include "mozilla/Assertions.h"
15 // For placement new
16 #include <new>
18 namespace mozilla {
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.
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.
31 template<class T>
32 class Maybe
34 AlignedStorage2<T> storage;
35 bool constructed;
37 T& asT() { return *storage.addr(); }
39 public:
40 Maybe() { constructed = false; }
41 ~Maybe() { if (constructed) asT().~T(); }
43 bool empty() const { return !constructed; }
45 void construct() {
46 MOZ_ASSERT(!constructed);
47 ::new (storage.addr()) T();
48 constructed = true;
51 template<class T1>
52 void construct(const T1& t1) {
53 MOZ_ASSERT(!constructed);
54 ::new (storage.addr()) T(t1);
55 constructed = true;
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;
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;
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;
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;
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;
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;
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;
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;
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;
131 T* addr() {
132 MOZ_ASSERT(constructed);
133 return &asT();
136 T& ref() {
137 MOZ_ASSERT(constructed);
138 return asT();
141 const T& ref() const {
142 MOZ_ASSERT(constructed);
143 return const_cast<Maybe*>(this)->asT();
146 void destroy() {
147 ref().~T();
148 constructed = false;
151 void destroyIfConstructed() {
152 if (!empty())
153 destroy();
156 private:
157 Maybe(const Maybe& other) MOZ_DELETE;
158 const Maybe& operator=(const Maybe& other) MOZ_DELETE;
161 } // namespace mozilla
163 #endif /* mozilla_Maybe_h */