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 #ifndef mozilla_MaybeOneOf_h
8 #define mozilla_MaybeOneOf_h
10 #include "mozilla/Alignment.h"
11 #include "mozilla/Assertions.h"
12 #include "mozilla/Move.h"
13 #include "mozilla/TemplateLib.h"
15 #include <new> // For placement new
20 * MaybeOneOf<T1, T2> is like Maybe, but it supports constructing either T1
21 * or T2. When a MaybeOneOf<T1, T2> is constructed, it is |empty()|, i.e.,
22 * no value has been constructed and no destructor will be called when the
23 * MaybeOneOf<T1, T2> is destroyed. Upon calling |construct<T1>()| or
24 * |construct<T2>()|, a T1 or T2 object will be constructed with the given
25 * arguments and that object will be destroyed when the owning MaybeOneOf is
28 template<class T1
, class T2
>
31 AlignedStorage
<tl::Max
<sizeof(T1
), sizeof(T2
)>::value
> storage
;
33 enum State
{ None
, SomeT1
, SomeT2
} state
;
34 template <class T
, class Ignored
= void> struct Type2State
{};
39 MOZ_ASSERT(state
== Type2State
<T
>::result
);
40 return *(T
*)storage
.addr();
46 MOZ_ASSERT(state
== Type2State
<T
>::result
);
47 return *(T
*)storage
.addr();
51 MaybeOneOf() : state(None
) {}
52 ~MaybeOneOf() { destroyIfConstructed(); }
54 bool empty() const { return state
== None
; }
57 bool constructed() const { return state
== Type2State
<T
>::result
; }
62 MOZ_ASSERT(state
== None
);
63 state
= Type2State
<T
>::result
;
64 ::new (storage
.addr()) T();
67 template <class T
, class U
>
68 void construct(U
&& aU
)
70 MOZ_ASSERT(state
== None
);
71 state
= Type2State
<T
>::result
;
72 ::new (storage
.addr()) T(Move(aU
));
75 template <class T
, class U1
>
76 void construct(const U1
& aU1
)
78 MOZ_ASSERT(state
== None
);
79 state
= Type2State
<T
>::result
;
80 ::new (storage
.addr()) T(aU1
);
83 template <class T
, class U1
, class U2
>
84 void construct(const U1
& aU1
, const U2
& aU2
)
86 MOZ_ASSERT(state
== None
);
87 state
= Type2State
<T
>::result
;
88 ::new (storage
.addr()) T(aU1
, aU2
);
105 MOZ_ASSERT(state
== SomeT1
|| state
== SomeT2
);
106 if (state
== SomeT1
) {
108 } else if (state
== SomeT2
) {
114 void destroyIfConstructed()
122 MaybeOneOf(const MaybeOneOf
& aOther
) = delete;
123 const MaybeOneOf
& operator=(const MaybeOneOf
& aOther
) = delete;
126 template <class T1
, class T2
>
127 template <class Ignored
>
128 struct MaybeOneOf
<T1
, T2
>::Type2State
<T1
, Ignored
>
130 typedef MaybeOneOf
<T1
, T2
> Enclosing
;
131 static const typename
Enclosing::State result
= Enclosing::SomeT1
;
134 template <class T1
, class T2
>
135 template <class Ignored
>
136 struct MaybeOneOf
<T1
, T2
>::Type2State
<T2
, Ignored
>
138 typedef MaybeOneOf
<T1
, T2
> Enclosing
;
139 static const typename
Enclosing::State result
= Enclosing::SomeT2
;
142 } // namespace mozilla
144 #endif /* mozilla_MaybeOneOf_h */