Making Optional throw exceptions instead of assert
[folly.git] / folly / Optional.h
1 /*
2  * Copyright 2015 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #ifndef FOLLY_OPTIONAL_H_
18 #define FOLLY_OPTIONAL_H_
19
20 /*
21  * Optional - For conditional initialization of values, like boost::optional,
22  * but with support for move semantics and emplacement.  Reference type support
23  * has not been included due to limited use cases and potential confusion with
24  * semantics of assignment: Assigning to an optional reference could quite
25  * reasonably copy its value or redirect the reference.
26  *
27  * Optional can be useful when a variable might or might not be needed:
28  *
29  *  Optional<Logger> maybeLogger = ...;
30  *  if (maybeLogger) {
31  *    maybeLogger->log("hello");
32  *  }
33  *
34  * Optional enables a 'null' value for types which do not otherwise have
35  * nullability, especially useful for parameter passing:
36  *
37  * void testIterator(const unique_ptr<Iterator>& it,
38  *                   initializer_list<int> idsExpected,
39  *                   Optional<initializer_list<int>> ranksExpected = none) {
40  *   for (int i = 0; it->next(); ++i) {
41  *     EXPECT_EQ(it->doc().id(), idsExpected[i]);
42  *     if (ranksExpected) {
43  *       EXPECT_EQ(it->doc().rank(), (*ranksExpected)[i]);
44  *     }
45  *   }
46  * }
47  *
48  * Optional models OptionalPointee, so calling 'get_pointer(opt)' will return a
49  * pointer to nullptr if the 'opt' is empty, and a pointer to the value if it is
50  * not:
51  *
52  *  Optional<int> maybeInt = ...;
53  *  if (int* v = get_pointer(maybeInt)) {
54  *    cout << *v << endl;
55  *  }
56  */
57 #include <cstddef>
58 #include <stdexcept>
59 #include <type_traits>
60 #include <utility>
61
62 #include <boost/operators.hpp>
63
64 #include <folly/Portability.h>
65
66 namespace folly {
67
68 namespace detail { struct NoneHelper {}; }
69
70 typedef int detail::NoneHelper::*None;
71
72 const None none = nullptr;
73
74 /**
75  * gcc-4.7 warns about use of uninitialized memory around the use of storage_
76  * even though this is explicitly initialized at each point.
77  */
78 #if defined(__GNUC__) && !defined(__clang__)
79 # pragma GCC diagnostic push
80 # pragma GCC diagnostic ignored "-Wuninitialized"
81 # pragma GCC diagnostic ignored "-Wpragmas"
82 # pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
83 #endif // __GNUC__
84
85 class OptionalEmptyException : public std::runtime_error {
86  public:
87   OptionalEmptyException()
88       : std::runtime_error("Empty Optional cannot be unwrapped") {}
89 };
90
91 template<class Value>
92 class Optional {
93  public:
94   static_assert(!std::is_reference<Value>::value,
95                 "Optional may not be used with reference types");
96   static_assert(!std::is_abstract<Value>::value,
97                 "Optional may not be used with abstract types");
98
99   Optional()
100     : hasValue_(false) {
101   }
102
103   Optional(const Optional& src)
104     noexcept(std::is_nothrow_copy_constructible<Value>::value) {
105
106     if (src.hasValue()) {
107       construct(src.value());
108     } else {
109       hasValue_ = false;
110     }
111   }
112
113   Optional(Optional&& src)
114     noexcept(std::is_nothrow_move_constructible<Value>::value) {
115
116     if (src.hasValue()) {
117       construct(std::move(src.value()));
118       src.clear();
119     } else {
120       hasValue_ = false;
121     }
122   }
123
124   /* implicit */ Optional(const None&) noexcept
125     : hasValue_(false) {
126   }
127
128   /* implicit */ Optional(Value&& newValue)
129     noexcept(std::is_nothrow_move_constructible<Value>::value) {
130     construct(std::move(newValue));
131   }
132
133   /* implicit */ Optional(const Value& newValue)
134     noexcept(std::is_nothrow_copy_constructible<Value>::value) {
135     construct(newValue);
136   }
137
138   ~Optional() noexcept {
139     clear();
140   }
141
142   void assign(const None&) {
143     clear();
144   }
145
146   void assign(Optional&& src) {
147     if (this != &src) {
148       if (src.hasValue()) {
149         assign(std::move(src.value()));
150         src.clear();
151       } else {
152         clear();
153       }
154     }
155   }
156
157   void assign(const Optional& src) {
158     if (src.hasValue()) {
159       assign(src.value());
160     } else {
161       clear();
162     }
163   }
164
165   void assign(Value&& newValue) {
166     if (hasValue()) {
167       value_ = std::move(newValue);
168     } else {
169       construct(std::move(newValue));
170     }
171   }
172
173   void assign(const Value& newValue) {
174     if (hasValue()) {
175       value_ = newValue;
176     } else {
177       construct(newValue);
178     }
179   }
180
181   template<class Arg>
182   Optional& operator=(Arg&& arg) {
183     assign(std::forward<Arg>(arg));
184     return *this;
185   }
186
187   Optional& operator=(Optional &&other)
188     noexcept (std::is_nothrow_move_assignable<Value>::value) {
189
190     assign(std::move(other));
191     return *this;
192   }
193
194   Optional& operator=(const Optional &other)
195     noexcept (std::is_nothrow_copy_assignable<Value>::value) {
196
197     assign(other);
198     return *this;
199   }
200
201   template<class... Args>
202   void emplace(Args&&... args) {
203     clear();
204     construct(std::forward<Args>(args)...);
205   }
206
207   void clear() {
208     if (hasValue()) {
209       hasValue_ = false;
210       value_.~Value();
211     }
212   }
213
214   const Value& value() const {
215     require_value();
216     return value_;
217   }
218
219   Value& value() {
220     require_value();
221     return value_;
222   }
223
224   Value* get_pointer() { return hasValue_ ? &value_ : nullptr; }
225   const Value* get_pointer() const { return hasValue_ ? &value_ : nullptr; }
226
227   bool hasValue() const { return hasValue_; }
228
229   explicit operator bool() const {
230     return hasValue();
231   }
232
233   const Value& operator*() const { return value(); }
234         Value& operator*()       { return value(); }
235
236   const Value* operator->() const { return &value(); }
237         Value* operator->()       { return &value(); }
238
239   // Return a copy of the value if set, or a given default if not.
240   template <class U>
241   Value value_or(U&& dflt) const& {
242     return hasValue_ ? value_ : std::forward<U>(dflt);
243   }
244
245   template <class U>
246   Value value_or(U&& dflt) && {
247     return hasValue_ ? std::move(value_) : std::forward<U>(dflt);
248   }
249
250  private:
251   void require_value() const {
252     if (!hasValue_) {
253       throw OptionalEmptyException();
254     }
255   }
256
257   template<class... Args>
258   void construct(Args&&... args) {
259     const void* ptr = &value_;
260     // for supporting const types
261     new(const_cast<void*>(ptr)) Value(std::forward<Args>(args)...);
262     hasValue_ = true;
263   }
264
265   // uninitialized
266   union { Value value_; };
267   bool hasValue_;
268 };
269
270 #if defined(__GNUC__) && !defined(__clang__)
271 #pragma GCC diagnostic pop
272 #endif
273
274 template<class T>
275 const T* get_pointer(const Optional<T>& opt) {
276   return opt.get_pointer();
277 }
278
279 template<class T>
280 T* get_pointer(Optional<T>& opt) {
281   return opt.get_pointer();
282 }
283
284 template<class T>
285 void swap(Optional<T>& a, Optional<T>& b) {
286   if (a.hasValue() && b.hasValue()) {
287     // both full
288     using std::swap;
289     swap(a.value(), b.value());
290   } else if (a.hasValue() || b.hasValue()) {
291     std::swap(a, b); // fall back to default implementation if they're mixed.
292   }
293 }
294
295 template<class T,
296          class Opt = Optional<typename std::decay<T>::type>>
297 Opt make_optional(T&& v) {
298   return Opt(std::forward<T>(v));
299 }
300
301 ///////////////////////////////////////////////////////////////////////////////
302 // Comparisons.
303
304 template<class V>
305 bool operator==(const Optional<V>& a, const V& b) {
306   return a.hasValue() && a.value() == b;
307 }
308
309 template<class V>
310 bool operator!=(const Optional<V>& a, const V& b) {
311   return !(a == b);
312 }
313
314 template<class V>
315 bool operator==(const V& a, const Optional<V>& b) {
316   return b.hasValue() && b.value() == a;
317 }
318
319 template<class V>
320 bool operator!=(const V& a, const Optional<V>& b) {
321   return !(a == b);
322 }
323
324 template<class V>
325 bool operator==(const Optional<V>& a, const Optional<V>& b) {
326   if (a.hasValue() != b.hasValue()) { return false; }
327   if (a.hasValue())                 { return a.value() == b.value(); }
328   return true;
329 }
330
331 template<class V>
332 bool operator!=(const Optional<V>& a, const Optional<V>& b) {
333   return !(a == b);
334 }
335
336 template<class V>
337 bool operator< (const Optional<V>& a, const Optional<V>& b) {
338   if (a.hasValue() != b.hasValue()) { return a.hasValue() < b.hasValue(); }
339   if (a.hasValue())                 { return a.value()    < b.value(); }
340   return false;
341 }
342
343 template<class V>
344 bool operator> (const Optional<V>& a, const Optional<V>& b) {
345   return b < a;
346 }
347
348 template<class V>
349 bool operator<=(const Optional<V>& a, const Optional<V>& b) {
350   return !(b < a);
351 }
352
353 template<class V>
354 bool operator>=(const Optional<V>& a, const Optional<V>& b) {
355   return !(a < b);
356 }
357
358 // Suppress comparability of Optional<T> with T, despite implicit conversion.
359 template<class V> bool operator< (const Optional<V>&, const V& other) = delete;
360 template<class V> bool operator<=(const Optional<V>&, const V& other) = delete;
361 template<class V> bool operator>=(const Optional<V>&, const V& other) = delete;
362 template<class V> bool operator> (const Optional<V>&, const V& other) = delete;
363 template<class V> bool operator< (const V& other, const Optional<V>&) = delete;
364 template<class V> bool operator<=(const V& other, const Optional<V>&) = delete;
365 template<class V> bool operator>=(const V& other, const Optional<V>&) = delete;
366 template<class V> bool operator> (const V& other, const Optional<V>&) = delete;
367
368 ///////////////////////////////////////////////////////////////////////////////
369
370 } // namespace folly
371
372 #endif // FOLLY_OPTIONAL_H_