clang-format Optional.h
[folly.git] / folly / Optional.h
1 /*
2  * Copyright 2017 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 #pragma once
18
19 /*
20  * Optional - For conditional initialization of values, like boost::optional,
21  * but with support for move semantics and emplacement.  Reference type support
22  * has not been included due to limited use cases and potential confusion with
23  * semantics of assignment: Assigning to an optional reference could quite
24  * reasonably copy its value or redirect the reference.
25  *
26  * Optional can be useful when a variable might or might not be needed:
27  *
28  *  Optional<Logger> maybeLogger = ...;
29  *  if (maybeLogger) {
30  *    maybeLogger->log("hello");
31  *  }
32  *
33  * Optional enables a 'null' value for types which do not otherwise have
34  * nullability, especially useful for parameter passing:
35  *
36  * void testIterator(const unique_ptr<Iterator>& it,
37  *                   initializer_list<int> idsExpected,
38  *                   Optional<initializer_list<int>> ranksExpected = none) {
39  *   for (int i = 0; it->next(); ++i) {
40  *     EXPECT_EQ(it->doc().id(), idsExpected[i]);
41  *     if (ranksExpected) {
42  *       EXPECT_EQ(it->doc().rank(), (*ranksExpected)[i]);
43  *     }
44  *   }
45  * }
46  *
47  * Optional models OptionalPointee, so calling 'get_pointer(opt)' will return a
48  * pointer to nullptr if the 'opt' is empty, and a pointer to the value if it is
49  * not:
50  *
51  *  Optional<int> maybeInt = ...;
52  *  if (int* v = get_pointer(maybeInt)) {
53  *    cout << *v << endl;
54  *  }
55  */
56 #include <cstddef>
57 #include <functional>
58 #include <new>
59 #include <stdexcept>
60 #include <type_traits>
61 #include <utility>
62
63 #include <folly/Portability.h>
64 #include <folly/Utility.h>
65
66 namespace folly {
67
68 namespace detail {
69 struct NoneHelper {};
70
71 // Allow each translation unit to control its own -fexceptions setting.
72 // If exceptions are disabled, std::terminate() will be called instead of
73 // throwing OptionalEmptyException when the condition fails.
74 [[noreturn]] void throw_optional_empty_exception();
75 }
76
77 typedef int detail::NoneHelper::*None;
78
79 const None none = nullptr;
80
81 class OptionalEmptyException : public std::runtime_error {
82  public:
83   OptionalEmptyException()
84       : std::runtime_error("Empty Optional cannot be unwrapped") {}
85 };
86
87 template <class Value>
88 class Optional {
89  public:
90   typedef Value value_type;
91
92   static_assert(
93       !std::is_reference<Value>::value,
94       "Optional may not be used with reference types");
95   static_assert(
96       !std::is_abstract<Value>::value,
97       "Optional may not be used with abstract types");
98
99   Optional() noexcept {}
100
101   Optional(const Optional& src) noexcept(
102       std::is_nothrow_copy_constructible<Value>::value) {
103     if (src.hasValue()) {
104       construct(src.value());
105     }
106   }
107
108   Optional(Optional&& src) noexcept(
109       std::is_nothrow_move_constructible<Value>::value) {
110     if (src.hasValue()) {
111       construct(std::move(src.value()));
112       src.clear();
113     }
114   }
115
116   /* implicit */ Optional(const None&) noexcept {}
117
118   /* implicit */ Optional(Value&& newValue) noexcept(
119       std::is_nothrow_move_constructible<Value>::value) {
120     construct(std::move(newValue));
121   }
122
123   /* implicit */ Optional(const Value& newValue) noexcept(
124       std::is_nothrow_copy_constructible<Value>::value) {
125     construct(newValue);
126   }
127
128   template <typename... Args>
129   explicit Optional(in_place_t, Args&&... args) noexcept(
130       std::is_nothrow_constructible<Value, Args...>::value) {
131     construct(std::forward<Args>(args)...);
132   }
133
134   void assign(const None&) {
135     clear();
136   }
137
138   void assign(Optional&& src) {
139     if (this != &src) {
140       if (src.hasValue()) {
141         assign(std::move(src.value()));
142         src.clear();
143       } else {
144         clear();
145       }
146     }
147   }
148
149   void assign(const Optional& src) {
150     if (src.hasValue()) {
151       assign(src.value());
152     } else {
153       clear();
154     }
155   }
156
157   void assign(Value&& newValue) {
158     if (hasValue()) {
159       storage_.value = std::move(newValue);
160     } else {
161       construct(std::move(newValue));
162     }
163   }
164
165   void assign(const Value& newValue) {
166     if (hasValue()) {
167       storage_.value = newValue;
168     } else {
169       construct(newValue);
170     }
171   }
172
173   template <class Arg>
174   Optional& operator=(Arg&& arg) {
175     assign(std::forward<Arg>(arg));
176     return *this;
177   }
178
179   Optional& operator=(Optional&& other) noexcept(
180       std::is_nothrow_move_assignable<Value>::value) {
181     assign(std::move(other));
182     return *this;
183   }
184
185   Optional& operator=(const Optional& other) noexcept(
186       std::is_nothrow_copy_assignable<Value>::value) {
187     assign(other);
188     return *this;
189   }
190
191   template <class... Args>
192   void emplace(Args&&... args) {
193     clear();
194     construct(std::forward<Args>(args)...);
195   }
196
197   void clear() {
198     storage_.clear();
199   }
200
201   const Value& value() const & {
202     require_value();
203     return storage_.value;
204   }
205
206   Value& value() & {
207     require_value();
208     return storage_.value;
209   }
210
211   Value&& value() && {
212     require_value();
213     return std::move(storage_.value);
214   }
215
216   const Value&& value() const && {
217     require_value();
218     return std::move(storage_.value);
219   }
220
221   const Value* get_pointer() const & {
222     return storage_.hasValue ? &storage_.value : nullptr;
223   }
224   Value* get_pointer() & {
225     return storage_.hasValue ? &storage_.value : nullptr;
226   }
227   Value* get_pointer() && = delete;
228
229   bool hasValue() const {
230     return storage_.hasValue;
231   }
232
233   explicit operator bool() const {
234     return hasValue();
235   }
236
237   const Value& operator*() const & {
238     return value();
239   }
240   Value& operator*() & {
241     return value();
242   }
243   const Value&& operator*() const && {
244     return std::move(value());
245   }
246   Value&& operator*() && {
247     return std::move(value());
248   }
249
250   const Value* operator->() const {
251     return &value();
252   }
253   Value* operator->() {
254     return &value();
255   }
256
257   // Return a copy of the value if set, or a given default if not.
258   template <class U>
259   Value value_or(U&& dflt) const & {
260     if (storage_.hasValue) {
261       return storage_.value;
262     }
263
264     return std::forward<U>(dflt);
265   }
266
267   template <class U>
268   Value value_or(U&& dflt) && {
269     if (storage_.hasValue) {
270       return std::move(storage_.value);
271     }
272
273     return std::forward<U>(dflt);
274   }
275
276  private:
277   void require_value() const {
278     if (!storage_.hasValue) {
279       detail::throw_optional_empty_exception();
280     }
281   }
282
283   template <class... Args>
284   void construct(Args&&... args) {
285     const void* ptr = &storage_.value;
286     // for supporting const types
287     new (const_cast<void*>(ptr)) Value(std::forward<Args>(args)...);
288     storage_.hasValue = true;
289   }
290
291   struct StorageTriviallyDestructible {
292     // The union trick allows to initialize the Optional's memory,
293     // so that compiler/tools don't complain about uninitialized memory,
294     // without actually calling Value's default constructor.
295     // The rest of the implementation enforces that hasValue/value are
296     // synchronized.
297     union {
298       bool hasValue;
299       struct {
300         bool paddingForHasValue_[1];
301         Value value;
302       };
303     };
304
305     StorageTriviallyDestructible() : hasValue{false} {}
306
307     void clear() {
308       hasValue = false;
309     }
310   };
311
312   struct StorageNonTriviallyDestructible {
313     // See StorageTriviallyDestructible's union
314     union {
315       bool hasValue;
316       struct {
317         bool paddingForHasValue_[1];
318         Value value;
319       };
320     };
321
322     FOLLY_PUSH_WARNING
323     // These are both informational warnings, but they trigger rare enough
324     // that we've left them enabled.
325     FOLLY_MSVC_DISABLE_WARNING(4587) // constructor of .value is not called
326     FOLLY_MSVC_DISABLE_WARNING(4588) // destructor of .value is not called
327     StorageNonTriviallyDestructible() : hasValue{false} {}
328     ~StorageNonTriviallyDestructible() {
329       clear();
330     }
331     FOLLY_POP_WARNING
332
333     void clear() {
334       if (hasValue) {
335         hasValue = false;
336         value.~Value();
337       }
338     }
339   };
340
341   using Storage = typename std::conditional<
342       std::is_trivially_destructible<Value>::value,
343       StorageTriviallyDestructible,
344       StorageNonTriviallyDestructible>::type;
345
346   Storage storage_;
347 };
348
349 template <class T>
350 const T* get_pointer(const Optional<T>& opt) {
351   return opt.get_pointer();
352 }
353
354 template <class T>
355 T* get_pointer(Optional<T>& opt) {
356   return opt.get_pointer();
357 }
358
359 template <class T>
360 void swap(Optional<T>& a, Optional<T>& b) {
361   if (a.hasValue() && b.hasValue()) {
362     // both full
363     using std::swap;
364     swap(a.value(), b.value());
365   } else if (a.hasValue() || b.hasValue()) {
366     std::swap(a, b); // fall back to default implementation if they're mixed.
367   }
368 }
369
370 template <class T, class Opt = Optional<typename std::decay<T>::type>>
371 Opt make_optional(T&& v) {
372   return Opt(std::forward<T>(v));
373 }
374
375 ///////////////////////////////////////////////////////////////////////////////
376 // Comparisons.
377
378 template <class U, class V>
379 bool operator==(const Optional<U>& a, const V& b) {
380   return a.hasValue() && a.value() == b;
381 }
382
383 template <class U, class V>
384 bool operator!=(const Optional<U>& a, const V& b) {
385   return !(a == b);
386 }
387
388 template <class U, class V>
389 bool operator==(const U& a, const Optional<V>& b) {
390   return b.hasValue() && b.value() == a;
391 }
392
393 template <class U, class V>
394 bool operator!=(const U& a, const Optional<V>& b) {
395   return !(a == b);
396 }
397
398 template <class U, class V>
399 bool operator==(const Optional<U>& a, const Optional<V>& b) {
400   if (a.hasValue() != b.hasValue()) {
401     return false;
402   }
403   if (a.hasValue()) {
404     return a.value() == b.value();
405   }
406   return true;
407 }
408
409 template <class U, class V>
410 bool operator!=(const Optional<U>& a, const Optional<V>& b) {
411   return !(a == b);
412 }
413
414 template <class U, class V>
415 bool operator<(const Optional<U>& a, const Optional<V>& b) {
416   if (a.hasValue() != b.hasValue()) {
417     return a.hasValue() < b.hasValue();
418   }
419   if (a.hasValue()) {
420     return a.value() < b.value();
421   }
422   return false;
423 }
424
425 template <class U, class V>
426 bool operator>(const Optional<U>& a, const Optional<V>& b) {
427   return b < a;
428 }
429
430 template <class U, class V>
431 bool operator<=(const Optional<U>& a, const Optional<V>& b) {
432   return !(b < a);
433 }
434
435 template <class U, class V>
436 bool operator>=(const Optional<U>& a, const Optional<V>& b) {
437   return !(a < b);
438 }
439
440 // Suppress comparability of Optional<T> with T, despite implicit conversion.
441 template <class V>
442 bool operator<(const Optional<V>&, const V& other) = delete;
443 template <class V>
444 bool operator<=(const Optional<V>&, const V& other) = delete;
445 template <class V>
446 bool operator>=(const Optional<V>&, const V& other) = delete;
447 template <class V>
448 bool operator>(const Optional<V>&, const V& other) = delete;
449 template <class V>
450 bool operator<(const V& other, const Optional<V>&) = delete;
451 template <class V>
452 bool operator<=(const V& other, const Optional<V>&) = delete;
453 template <class V>
454 bool operator>=(const V& other, const Optional<V>&) = delete;
455 template <class V>
456 bool operator>(const V& other, const Optional<V>&) = delete;
457
458 ///////////////////////////////////////////////////////////////////////////////
459
460 } // namespace folly
461
462 // Allow usage of Optional<T> in std::unordered_map and std::unordered_set
463 FOLLY_NAMESPACE_STD_BEGIN
464 template <class T>
465 struct hash<folly::Optional<T>> {
466   size_t operator()(folly::Optional<T> const& obj) const {
467     if (!obj.hasValue()) {
468       return 0;
469     }
470     return hash<typename remove_const<T>::type>()(*obj);
471   }
472 };
473 FOLLY_NAMESPACE_STD_END