Replace WTF::move with WTFMove
[WebKit-https.git] / Source / WTF / wtf / Optional.h
1 /*
2  * Copyright (C) 2014 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #ifndef Optional_h
27 #define Optional_h
28
29 #include <type_traits>
30 #include <wtf/Assertions.h>
31 #include <wtf/StdLibExtras.h>
32
33 // WTF::Optional is a class based on std::optional, described here:
34 // http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3527.html
35 // If this ends up in a C++ standard, we should replace our implementation with it.
36
37 namespace WTF {
38
39 enum InPlaceTag { InPlace };
40 enum NulloptTag { Nullopt };
41
42 template<typename T>
43 class Optional {
44 public:
45     Optional()
46         : m_isEngaged(false)
47     {
48     }
49
50     Optional(NulloptTag)
51         : m_isEngaged(false)
52     {
53     }
54
55     Optional(const T& value)
56         : m_isEngaged(true)
57     {
58         new (NotNull, &m_value) T(value);
59     }
60
61     Optional(const Optional& other)
62         : m_isEngaged(other.m_isEngaged)
63     {
64         if (m_isEngaged)
65             new (NotNull, &m_value) T(*other.asPtr());
66     }
67
68     Optional(Optional&& other)
69         : m_isEngaged(other.m_isEngaged)
70     {
71         if (m_isEngaged)
72             new (NotNull, &m_value) T(WTFMove(*other.asPtr()));
73     }
74
75     Optional(T&& value)
76         : m_isEngaged(true)
77     {
78         new (NotNull, &m_value) T(WTFMove(value));
79     }
80
81     template<typename... Args>
82     Optional(InPlaceTag, Args&&... args)
83         : m_isEngaged(true)
84     {
85         new (NotNull, &m_value) T(std::forward<Args>(args)...);
86     }
87
88     ~Optional()
89     {
90         destroy();
91     }
92
93     Optional& operator=(NulloptTag)
94     {
95         destroy();
96         return *this;
97     }
98
99     Optional& operator=(const Optional& other)
100     {
101         if (this == &other)
102             return *this;
103
104         destroy();
105         if (other.m_isEngaged) {
106             new (NotNull, &m_value) T(*other.asPtr());
107             m_isEngaged = true;
108         }
109         return *this;
110     }
111
112     Optional& operator=(Optional&& other)
113     {
114         if (this == &other)
115             return *this;
116
117         destroy();
118         if (other.m_isEngaged) {
119             new (NotNull, &m_value) T(WTFMove(*other.asPtr()));
120             m_isEngaged = true;
121         }
122         return *this;
123     }
124
125     template<typename U, class = typename std::enable_if<std::is_same<typename std::remove_reference<U>::type, T>::value>::type>
126     Optional& operator=(U&& u)
127     {
128         destroy();
129         new (NotNull, &m_value) T(std::forward<U>(u));
130         m_isEngaged = true;
131         return *this;
132     }
133
134     explicit operator bool() const { return m_isEngaged; }
135
136     const T* operator->() const
137     {
138         ASSERT(m_isEngaged);
139         return asPtr();
140     }
141
142     T* operator->()
143     {
144         ASSERT(m_isEngaged);
145         return asPtr();
146     }
147
148     const T& operator*() const { return value(); }
149     T& operator*() { return value(); }
150
151     T& value()
152     {
153         ASSERT(m_isEngaged);
154         return *asPtr();
155     }
156
157     const T& value() const
158     {
159         ASSERT(m_isEngaged);
160         return *asPtr();
161     }
162
163     template<typename U>
164     T valueOr(U&& value) const
165     {
166         if (m_isEngaged)
167             return *asPtr();
168
169         return std::forward<U>(value);
170     }
171
172     template<typename U>
173     T valueOrCompute(U callback) const
174     {
175         if (m_isEngaged)
176             return *asPtr();
177
178         return callback();
179     }
180
181 private:
182     const T* asPtr() const { return reinterpret_cast<const T*>(&m_value); }
183     T* asPtr() { return reinterpret_cast<T*>(&m_value); }
184     void destroy()
185     {
186         if (m_isEngaged) {
187             asPtr()->~T();
188             m_isEngaged = false;
189         }
190     }
191
192     bool m_isEngaged;
193     typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type m_value;
194 };
195
196 } // namespace WTF
197
198 using WTF::InPlace;
199 using WTF::Nullopt;
200 using WTF::Optional;
201
202 #endif // Optional_h