Fix typo in 9b54bd30006c008b4a951331b273613d5bac3abf
[pm.git] / mfbt / MaybeOneOf.h
blob9c38ff8b039d5e299289d2e6bef35ccead3a5fd1
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
17 namespace mozilla {
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
26 * destroyed.
28 template<class T1, class T2>
29 class MaybeOneOf
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 {};
36 template <class T>
37 T& as()
39 MOZ_ASSERT(state == Type2State<T>::result);
40 return *(T*)storage.addr();
43 template <class T>
44 const T& as() const
46 MOZ_ASSERT(state == Type2State<T>::result);
47 return *(T*)storage.addr();
50 public:
51 MaybeOneOf() : state(None) {}
52 ~MaybeOneOf() { destroyIfConstructed(); }
54 MaybeOneOf(MaybeOneOf&& rhs)
55 : state(None)
57 if (!rhs.empty()) {
58 if (rhs.constructed<T1>()) {
59 construct<T1>(Move(rhs.as<T1>()));
60 rhs.as<T1>().~T1();
61 } else {
62 construct<T2>(Move(rhs.as<T2>()));
63 rhs.as<T2>().~T2();
65 rhs.state = None;
69 MaybeOneOf &operator=(MaybeOneOf&& rhs)
71 MOZ_ASSERT(this != &rhs, "Self-move is prohibited");
72 this->~MaybeOneOf();
73 new(this) MaybeOneOf(Move(rhs));
74 return *this;
77 bool empty() const { return state == None; }
79 template <class T>
80 bool constructed() const { return state == Type2State<T>::result; }
82 template <class T, class... Args>
83 void construct(Args&&... aArgs)
85 MOZ_ASSERT(state == None);
86 state = Type2State<T>::result;
87 ::new (storage.addr()) T(Forward<Args>(aArgs)...);
90 template <class T>
91 T& ref()
93 return as<T>();
96 template <class T>
97 const T& ref() const
99 return as<T>();
102 void destroy()
104 MOZ_ASSERT(state == SomeT1 || state == SomeT2);
105 if (state == SomeT1) {
106 as<T1>().~T1();
107 } else if (state == SomeT2) {
108 as<T2>().~T2();
110 state = None;
113 void destroyIfConstructed()
115 if (!empty()) {
116 destroy();
120 private:
121 MaybeOneOf(const MaybeOneOf& aOther) = delete;
122 const MaybeOneOf& operator=(const MaybeOneOf& aOther) = delete;
125 template <class T1, class T2>
126 template <class Ignored>
127 struct MaybeOneOf<T1, T2>::Type2State<T1, Ignored>
129 typedef MaybeOneOf<T1, T2> Enclosing;
130 static const typename Enclosing::State result = Enclosing::SomeT1;
133 template <class T1, class T2>
134 template <class Ignored>
135 struct MaybeOneOf<T1, T2>::Type2State<T2, Ignored>
137 typedef MaybeOneOf<T1, T2> Enclosing;
138 static const typename Enclosing::State result = Enclosing::SomeT2;
141 } // namespace mozilla
143 #endif /* mozilla_MaybeOneOf_h */