Update Optional
[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
57 #include <cstddef>
58 #include <functional>
59 #include <new>
60 #include <stdexcept>
61 #include <type_traits>
62 #include <utility>
63
64 #include <folly/Launder.h>
65 #include <folly/Portability.h>
66 #include <folly/Utility.h>
67
68 namespace folly {
69
70 namespace detail {
71 struct NoneHelper {};
72
73 // Allow each translation unit to control its own -fexceptions setting.
74 // If exceptions are disabled, std::terminate() will be called instead of
75 // throwing OptionalEmptyException when the condition fails.
76 [[noreturn]] void throw_optional_empty_exception();
77 }
78
79 typedef int detail::NoneHelper::*None;
80
81 const None none = nullptr;
82
83 class OptionalEmptyException : public std::runtime_error {
84  public:
85   OptionalEmptyException()
86       : std::runtime_error("Empty Optional cannot be unwrapped") {}
87 };
88
89 template <class Value>
90 class Optional {
91  public:
92   typedef Value value_type;
93
94   static_assert(
95       !std::is_reference<Value>::value,
96       "Optional may not be used with reference types");
97   static_assert(
98       !std::is_abstract<Value>::value,
99       "Optional may not be used with abstract types");
100
101   Optional() noexcept {}
102
103   Optional(const Optional& src) noexcept(
104       std::is_nothrow_copy_constructible<Value>::value) {
105     if (src.hasValue()) {
106       storage_.construct(src.value());
107     }
108   }
109
110   Optional(Optional&& src) noexcept(
111       std::is_nothrow_move_constructible<Value>::value) {
112     if (src.hasValue()) {
113       storage_.construct(std::move(src.value()));
114       src.clear();
115     }
116   }
117
118   /* implicit */ Optional(const None&) noexcept {}
119
120   /* implicit */ Optional(Value&& newValue) noexcept(
121       std::is_nothrow_move_constructible<Value>::value) {
122     storage_.construct(std::move(newValue));
123   }
124
125   /* implicit */ Optional(const Value& newValue) noexcept(
126       std::is_nothrow_copy_constructible<Value>::value) {
127     storage_.construct(newValue);
128   }
129
130   template <typename... Args>
131   explicit Optional(in_place_t, Args&&... args) noexcept(
132       std::is_nothrow_constructible<Value, Args...>::value) {
133     storage_.construct(std::forward<Args>(args)...);
134   }
135
136   void assign(const None&) {
137     clear();
138   }
139
140   void assign(Optional&& src) {
141     if (this != &src) {
142       if (src.hasValue()) {
143         assign(std::move(src.value()));
144         src.clear();
145       } else {
146         clear();
147       }
148     }
149   }
150
151   void assign(const Optional& src) {
152     if (src.hasValue()) {
153       assign(src.value());
154     } else {
155       clear();
156     }
157   }
158
159   void assign(Value&& newValue) {
160     if (hasValue()) {
161       *storage_.value_pointer() = std::move(newValue);
162     } else {
163       storage_.construct(std::move(newValue));
164     }
165   }
166
167   void assign(const Value& newValue) {
168     if (hasValue()) {
169       *storage_.value_pointer() = newValue;
170     } else {
171       storage_.construct(newValue);
172     }
173   }
174
175   template <class Arg>
176   Optional& operator=(Arg&& arg) {
177     assign(std::forward<Arg>(arg));
178     return *this;
179   }
180
181   Optional& operator=(Optional&& other) noexcept(
182       std::is_nothrow_move_assignable<Value>::value) {
183     assign(std::move(other));
184     return *this;
185   }
186
187   Optional& operator=(const Optional& other) noexcept(
188       std::is_nothrow_copy_assignable<Value>::value) {
189     assign(other);
190     return *this;
191   }
192
193   template <class... Args>
194   void emplace(Args&&... args) {
195     clear();
196     storage_.construct(std::forward<Args>(args)...);
197   }
198
199   void clear() {
200     storage_.clear();
201   }
202
203   const Value& value() const & {
204     require_value();
205     return *storage_.value_pointer();
206   }
207
208   Value& value() & {
209     require_value();
210     return *storage_.value_pointer();
211   }
212
213   Value&& value() && {
214     require_value();
215     return std::move(*storage_.value_pointer());
216   }
217
218   const Value&& value() const && {
219     require_value();
220     return std::move(*storage_.value_pointer());
221   }
222
223   const Value* get_pointer() const & {
224     return storage_.value_pointer();
225   }
226   Value* get_pointer() & {
227     return storage_.value_pointer();
228   }
229   Value* get_pointer() && = delete;
230
231   bool hasValue() const {
232     return storage_.hasValue();
233   }
234
235   explicit operator bool() const {
236     return hasValue();
237   }
238
239   const Value& operator*() const & {
240     return value();
241   }
242   Value& operator*() & {
243     return value();
244   }
245   const Value&& operator*() const && {
246     return std::move(value());
247   }
248   Value&& operator*() && {
249     return std::move(value());
250   }
251
252   const Value* operator->() const {
253     return &value();
254   }
255   Value* operator->() {
256     return &value();
257   }
258
259   // Return a copy of the value if set, or a given default if not.
260   template <class U>
261   Value value_or(U&& dflt) const & {
262     if (storage_.hasValue()) {
263       return *storage_.value_pointer();
264     }
265
266     return std::forward<U>(dflt);
267   }
268
269   template <class U>
270   Value value_or(U&& dflt) && {
271     if (storage_.hasValue()) {
272       return std::move(*storage_.value_pointer());
273     }
274
275     return std::forward<U>(dflt);
276   }
277
278  private:
279   void require_value() const {
280     if (!storage_.hasValue()) {
281       detail::throw_optional_empty_exception();
282     }
283   }
284
285   struct StorageTriviallyDestructible {
286    protected:
287     bool hasValue_;
288     std::aligned_storage_t<sizeof(Value), alignof(Value)> value_[1];
289
290    public:
291     StorageTriviallyDestructible() : hasValue_{false} {}
292     void clear() {
293       hasValue_ = false;
294     }
295   };
296
297   struct StorageNonTriviallyDestructible {
298    protected:
299     bool hasValue_;
300     std::aligned_storage_t<sizeof(Value), alignof(Value)> value_[1];
301
302    public:
303     StorageNonTriviallyDestructible() : hasValue_{false} {}
304     ~StorageNonTriviallyDestructible() {
305       clear();
306     }
307
308     void clear() {
309       if (hasValue_) {
310         hasValue_ = false;
311         launder(reinterpret_cast<Value*>(value_))->~Value();
312       }
313     }
314   };
315
316   struct Storage : std::conditional_t<
317                        std::is_trivially_destructible<Value>::value,
318                        StorageTriviallyDestructible,
319                        StorageNonTriviallyDestructible> {
320     bool hasValue() const {
321       return this->hasValue_;
322     }
323
324     Value* value_pointer() {
325       if (this->hasValue_) {
326         return launder(reinterpret_cast<Value*>(this->value_));
327       }
328       return nullptr;
329     }
330
331     Value const* value_pointer() const {
332       if (this->hasValue_) {
333         return launder(reinterpret_cast<Value const*>(this->value_));
334       }
335       return nullptr;
336     }
337
338     template <class... Args>
339     void construct(Args&&... args) {
340       new (raw_pointer()) Value(std::forward<Args>(args)...);
341       this->hasValue_ = true;
342     }
343
344    private:
345     void* raw_pointer() {
346       return static_cast<void*>(this->value_);
347     }
348   };
349
350   Storage storage_;
351 };
352
353 template <class T>
354 const T* get_pointer(const Optional<T>& opt) {
355   return opt.get_pointer();
356 }
357
358 template <class T>
359 T* get_pointer(Optional<T>& opt) {
360   return opt.get_pointer();
361 }
362
363 template <class T>
364 void swap(Optional<T>& a, Optional<T>& b) {
365   if (a.hasValue() && b.hasValue()) {
366     // both full
367     using std::swap;
368     swap(a.value(), b.value());
369   } else if (a.hasValue() || b.hasValue()) {
370     std::swap(a, b); // fall back to default implementation if they're mixed.
371   }
372 }
373
374 template <class T, class Opt = Optional<std::decay_t<T>>>
375 Opt make_optional(T&& v) {
376   return Opt(std::forward<T>(v));
377 }
378
379 ///////////////////////////////////////////////////////////////////////////////
380 // Comparisons.
381
382 template <class U, class V>
383 bool operator==(const Optional<U>& a, const V& b) {
384   return a.hasValue() && a.value() == b;
385 }
386
387 template <class U, class V>
388 bool operator!=(const Optional<U>& a, const V& b) {
389   return !(a == b);
390 }
391
392 template <class U, class V>
393 bool operator==(const U& a, const Optional<V>& b) {
394   return b.hasValue() && b.value() == a;
395 }
396
397 template <class U, class V>
398 bool operator!=(const U& a, const Optional<V>& b) {
399   return !(a == b);
400 }
401
402 template <class U, class V>
403 bool operator==(const Optional<U>& a, const Optional<V>& b) {
404   if (a.hasValue() != b.hasValue()) {
405     return false;
406   }
407   if (a.hasValue()) {
408     return a.value() == b.value();
409   }
410   return true;
411 }
412
413 template <class U, class V>
414 bool operator!=(const Optional<U>& a, const Optional<V>& b) {
415   return !(a == b);
416 }
417
418 template <class U, class V>
419 bool operator<(const Optional<U>& a, const Optional<V>& b) {
420   if (a.hasValue() != b.hasValue()) {
421     return a.hasValue() < b.hasValue();
422   }
423   if (a.hasValue()) {
424     return a.value() < b.value();
425   }
426   return false;
427 }
428
429 template <class U, class V>
430 bool operator>(const Optional<U>& a, const Optional<V>& b) {
431   return b < a;
432 }
433
434 template <class U, class V>
435 bool operator<=(const Optional<U>& a, const Optional<V>& b) {
436   return !(b < a);
437 }
438
439 template <class U, class V>
440 bool operator>=(const Optional<U>& a, const Optional<V>& b) {
441   return !(a < b);
442 }
443
444 // Suppress comparability of Optional<T> with T, despite implicit conversion.
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 Optional<V>&, const V& other) = delete;
451 template <class V>
452 bool operator>(const Optional<V>&, const V& other) = 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 template <class V>
458 bool operator>=(const V& other, const Optional<V>&) = delete;
459 template <class V>
460 bool operator>(const V& other, const Optional<V>&) = delete;
461
462 ///////////////////////////////////////////////////////////////////////////////
463
464 } // namespace folly
465
466 // Allow usage of Optional<T> in std::unordered_map and std::unordered_set
467 FOLLY_NAMESPACE_STD_BEGIN
468 template <class T>
469 struct hash<folly::Optional<T>> {
470   size_t operator()(folly::Optional<T> const& obj) const {
471     if (!obj.hasValue()) {
472       return 0;
473     }
474     return hash<remove_const_t<T>>()(*obj);
475   }
476 };
477 FOLLY_NAMESPACE_STD_END