allow comparing Optional<T> with none
[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 noexcept {
232     return storage_.hasValue();
233   }
234
235   explicit operator bool() const noexcept {
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     typename std::aligned_storage<sizeof(Value), alignof(Value)>::type
289         value_[1];
290
291    public:
292     StorageTriviallyDestructible() : hasValue_{false} {}
293     void clear() {
294       hasValue_ = false;
295     }
296   };
297
298   struct StorageNonTriviallyDestructible {
299    protected:
300     bool hasValue_;
301     typename std::aligned_storage<sizeof(Value), alignof(Value)>::type
302         value_[1];
303
304    public:
305     StorageNonTriviallyDestructible() : hasValue_{false} {}
306     ~StorageNonTriviallyDestructible() {
307       clear();
308     }
309
310     void clear() {
311       if (hasValue_) {
312         hasValue_ = false;
313         launder(reinterpret_cast<Value*>(value_))->~Value();
314       }
315     }
316   };
317
318   struct Storage : std::conditional<
319                        std::is_trivially_destructible<Value>::value,
320                        StorageTriviallyDestructible,
321                        StorageNonTriviallyDestructible>::type {
322     bool hasValue() const noexcept {
323       return this->hasValue_;
324     }
325
326     Value* value_pointer() {
327       if (this->hasValue_) {
328         return launder(reinterpret_cast<Value*>(this->value_));
329       }
330       return nullptr;
331     }
332
333     Value const* value_pointer() const {
334       if (this->hasValue_) {
335         return launder(reinterpret_cast<Value const*>(this->value_));
336       }
337       return nullptr;
338     }
339
340     template <class... Args>
341     void construct(Args&&... args) {
342       new (raw_pointer()) Value(std::forward<Args>(args)...);
343       this->hasValue_ = true;
344     }
345
346    private:
347     void* raw_pointer() {
348       return static_cast<void*>(this->value_);
349     }
350   };
351
352   Storage storage_;
353 };
354
355 template <class T>
356 const T* get_pointer(const Optional<T>& opt) {
357   return opt.get_pointer();
358 }
359
360 template <class T>
361 T* get_pointer(Optional<T>& opt) {
362   return opt.get_pointer();
363 }
364
365 template <class T>
366 void swap(Optional<T>& a, Optional<T>& b) {
367   if (a.hasValue() && b.hasValue()) {
368     // both full
369     using std::swap;
370     swap(a.value(), b.value());
371   } else if (a.hasValue() || b.hasValue()) {
372     std::swap(a, b); // fall back to default implementation if they're mixed.
373   }
374 }
375
376 template <class T, class Opt = Optional<typename std::decay<T>::type>>
377 Opt make_optional(T&& v) {
378   return Opt(std::forward<T>(v));
379 }
380
381 ///////////////////////////////////////////////////////////////////////////////
382 // Comparisons.
383
384 template <class U, class V>
385 bool operator==(const Optional<U>& a, const V& b) {
386   return a.hasValue() && a.value() == b;
387 }
388
389 template <class U, class V>
390 bool operator!=(const Optional<U>& a, const V& b) {
391   return !(a == b);
392 }
393
394 template <class U, class V>
395 bool operator==(const U& a, const Optional<V>& b) {
396   return b.hasValue() && b.value() == a;
397 }
398
399 template <class U, class V>
400 bool operator!=(const U& a, const Optional<V>& b) {
401   return !(a == b);
402 }
403
404 template <class U, class V>
405 bool operator==(const Optional<U>& a, const Optional<V>& b) {
406   if (a.hasValue() != b.hasValue()) {
407     return false;
408   }
409   if (a.hasValue()) {
410     return a.value() == b.value();
411   }
412   return true;
413 }
414
415 template <class U, class V>
416 bool operator!=(const Optional<U>& a, const Optional<V>& b) {
417   return !(a == b);
418 }
419
420 template <class U, class V>
421 bool operator<(const Optional<U>& a, const Optional<V>& b) {
422   if (a.hasValue() != b.hasValue()) {
423     return a.hasValue() < b.hasValue();
424   }
425   if (a.hasValue()) {
426     return a.value() < b.value();
427   }
428   return false;
429 }
430
431 template <class U, class V>
432 bool operator>(const Optional<U>& a, const Optional<V>& b) {
433   return b < a;
434 }
435
436 template <class U, class V>
437 bool operator<=(const Optional<U>& a, const Optional<V>& b) {
438   return !(b < a);
439 }
440
441 template <class U, class V>
442 bool operator>=(const Optional<U>& a, const Optional<V>& b) {
443   return !(a < b);
444 }
445
446 // Suppress comparability of Optional<T> with T, despite implicit conversion.
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 Optional<V>&, const V& other) = 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 template <class V>
462 bool operator>(const V& other, const Optional<V>&) = delete;
463
464 // Comparisons with none
465 template <class V>
466 bool operator==(const Optional<V>& a, None) noexcept {
467   return !a.hasValue();
468 }
469 template <class V>
470 bool operator==(None, const Optional<V>& a) noexcept {
471   return !a.hasValue();
472 }
473 template <class V>
474 bool operator<(const Optional<V>&, None) noexcept {
475   return false;
476 }
477 template <class V>
478 bool operator<(None, const Optional<V>& a) noexcept {
479   return a.hasValue();
480 }
481 template <class V>
482 bool operator>(const Optional<V>& a, None) noexcept {
483   return a.hasValue();
484 }
485 template <class V>
486 bool operator>(None, const Optional<V>&) noexcept {
487   return false;
488 }
489 template <class V>
490 bool operator<=(None, const Optional<V>&) noexcept {
491   return true;
492 }
493 template <class V>
494 bool operator<=(const Optional<V>& a, None) noexcept {
495   return !a.hasValue();
496 }
497 template <class V>
498 bool operator>=(const Optional<V>&, None) noexcept {
499   return true;
500 }
501 template <class V>
502 bool operator>=(None, const Optional<V>& a) noexcept {
503   return !a.hasValue();
504 }
505
506 ///////////////////////////////////////////////////////////////////////////////
507
508 } // namespace folly
509
510 // Allow usage of Optional<T> in std::unordered_map and std::unordered_set
511 FOLLY_NAMESPACE_STD_BEGIN
512 template <class T>
513 struct hash<folly::Optional<T>> {
514   size_t operator()(folly::Optional<T> const& obj) const {
515     if (!obj.hasValue()) {
516       return 0;
517     }
518     return hash<typename remove_const<T>::type>()(*obj);
519   }
520 };
521 FOLLY_NAMESPACE_STD_END