logging: fix compiler compatibility for one more constexpr function
[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(!std::is_reference<Value>::value,
93                 "Optional may not be used with reference types");
94   static_assert(!std::is_abstract<Value>::value,
95                 "Optional may not be used with abstract types");
96
97   Optional() noexcept {
98   }
99
100   Optional(const Optional& src)
101     noexcept(std::is_nothrow_copy_constructible<Value>::value) {
102
103     if (src.hasValue()) {
104       construct(src.value());
105     }
106   }
107
108   Optional(Optional&& src)
109     noexcept(std::is_nothrow_move_constructible<Value>::value) {
110
111     if (src.hasValue()) {
112       construct(std::move(src.value()));
113       src.clear();
114     }
115   }
116
117   /* implicit */ Optional(const None&) noexcept {
118   }
119
120   /* implicit */ Optional(Value&& newValue)
121     noexcept(std::is_nothrow_move_constructible<Value>::value) {
122     construct(std::move(newValue));
123   }
124
125   /* implicit */ Optional(const Value& newValue)
126     noexcept(std::is_nothrow_copy_constructible<Value>::value) {
127     construct(newValue);
128   }
129
130   template <typename... Args>
131   explicit Optional(in_place_t, Args&&... args)
132     noexcept(noexcept(::new (nullptr) Value(std::declval<Args&&>()...))) {
133     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 = std::move(newValue);
162     } else {
163       construct(std::move(newValue));
164     }
165   }
166
167   void assign(const Value& newValue) {
168     if (hasValue()) {
169       storage_.value = newValue;
170     } else {
171       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)
182     noexcept (std::is_nothrow_move_assignable<Value>::value) {
183
184     assign(std::move(other));
185     return *this;
186   }
187
188   Optional& operator=(const Optional &other)
189     noexcept (std::is_nothrow_copy_assignable<Value>::value) {
190
191     assign(other);
192     return *this;
193   }
194
195   template<class... Args>
196   void emplace(Args&&... args) {
197     clear();
198     construct(std::forward<Args>(args)...);
199   }
200
201   void clear() {
202     storage_.clear();
203   }
204
205   const Value& value() const& {
206     require_value();
207     return storage_.value;
208   }
209
210   Value& value() & {
211     require_value();
212     return storage_.value;
213   }
214
215   Value&& value() && {
216     require_value();
217     return std::move(storage_.value);
218   }
219
220   const Value&& value() const&& {
221     require_value();
222     return std::move(storage_.value);
223   }
224
225   const Value* get_pointer() const&  {
226     return storage_.hasValue ? &storage_.value : nullptr;
227   }
228   Value* get_pointer() & {
229     return storage_.hasValue ? &storage_.value : nullptr;
230   }
231   Value* get_pointer() && = delete;
232
233   bool hasValue() const { return storage_.hasValue; }
234
235   explicit operator bool() const {
236     return hasValue();
237   }
238
239   const Value& operator*()  const&  { return value(); }
240         Value& operator*()       &  { return value(); }
241   const Value&& operator*() const&& { return std::move(value()); }
242         Value&& operator*()      && { return std::move(value()); }
243
244   const Value* operator->() const { return &value(); }
245         Value* operator->()       { return &value(); }
246
247   // Return a copy of the value if set, or a given default if not.
248   template <class U>
249   Value value_or(U&& dflt) const& {
250     if (storage_.hasValue) {
251       return storage_.value;
252     }
253
254     return std::forward<U>(dflt);
255   }
256
257   template <class U>
258   Value value_or(U&& dflt) && {
259     if (storage_.hasValue) {
260       return std::move(storage_.value);
261     }
262
263     return std::forward<U>(dflt);
264   }
265
266  private:
267   void require_value() const {
268     if (!storage_.hasValue) {
269       detail::throw_optional_empty_exception();
270     }
271   }
272
273   template<class... Args>
274   void construct(Args&&... args) {
275     const void* ptr = &storage_.value;
276     // for supporting const types
277     new(const_cast<void*>(ptr)) Value(std::forward<Args>(args)...);
278     storage_.hasValue = true;
279   }
280
281   struct StorageTriviallyDestructible {
282     // The union trick allows to initialize the Optional's memory,
283     // so that compiler/tools don't complain about uninitialized memory,
284     // without actually calling Value's default constructor.
285     // The rest of the implementation enforces that hasValue/value are
286     // synchronized.
287     union {
288       bool hasValue;
289       struct {
290         bool paddingForHasValue_[1];
291         Value value;
292       };
293     };
294
295     StorageTriviallyDestructible() : hasValue{false} {}
296
297     void clear() {
298       hasValue = false;
299     }
300   };
301
302   struct StorageNonTriviallyDestructible {
303     // See StorageTriviallyDestructible's union
304     union {
305       bool hasValue;
306       struct {
307         bool paddingForHasValue_[1];
308         Value value;
309       };
310     };
311
312     FOLLY_PUSH_WARNING
313     // These are both informational warnings, but they trigger rare enough
314     // that we've left them enabled.
315     FOLLY_MSVC_DISABLE_WARNING(4587) // constructor of .value is not called
316     FOLLY_MSVC_DISABLE_WARNING(4588) // destructor of .value is not called
317     StorageNonTriviallyDestructible() : hasValue{false} {}
318     ~StorageNonTriviallyDestructible() {
319       clear();
320     }
321     FOLLY_POP_WARNING
322
323     void clear() {
324       if (hasValue) {
325         hasValue = false;
326         value.~Value();
327       }
328     }
329   };
330
331   using Storage =
332     typename std::conditional<std::is_trivially_destructible<Value>::value,
333                               StorageTriviallyDestructible,
334                               StorageNonTriviallyDestructible>::type;
335
336   Storage storage_;
337 };
338
339 template<class T>
340 const T* get_pointer(const Optional<T>& opt) {
341   return opt.get_pointer();
342 }
343
344 template<class T>
345 T* get_pointer(Optional<T>& opt) {
346   return opt.get_pointer();
347 }
348
349 template<class T>
350 void swap(Optional<T>& a, Optional<T>& b) {
351   if (a.hasValue() && b.hasValue()) {
352     // both full
353     using std::swap;
354     swap(a.value(), b.value());
355   } else if (a.hasValue() || b.hasValue()) {
356     std::swap(a, b); // fall back to default implementation if they're mixed.
357   }
358 }
359
360 template<class T,
361          class Opt = Optional<typename std::decay<T>::type>>
362 Opt make_optional(T&& v) {
363   return Opt(std::forward<T>(v));
364 }
365
366 ///////////////////////////////////////////////////////////////////////////////
367 // Comparisons.
368
369 template <class U, class V>
370 bool operator==(const Optional<U>& a, const V& b) {
371   return a.hasValue() && a.value() == b;
372 }
373
374 template <class U, class V>
375 bool operator!=(const Optional<U>& a, const V& b) {
376   return !(a == b);
377 }
378
379 template <class U, class V>
380 bool operator==(const U& a, const Optional<V>& b) {
381   return b.hasValue() && b.value() == a;
382 }
383
384 template <class U, class V>
385 bool operator!=(const U& a, const Optional<V>& b) {
386   return !(a == b);
387 }
388
389 template <class U, class V>
390 bool operator==(const Optional<U>& a, const Optional<V>& b) {
391   if (a.hasValue() != b.hasValue()) { return false; }
392   if (a.hasValue())                 { return a.value() == b.value(); }
393   return true;
394 }
395
396 template <class U, class V>
397 bool operator!=(const Optional<U>& a, const Optional<V>& b) {
398   return !(a == b);
399 }
400
401 template <class U, class V>
402 bool operator<(const Optional<U>& a, const Optional<V>& b) {
403   if (a.hasValue() != b.hasValue()) { return a.hasValue() < b.hasValue(); }
404   if (a.hasValue())                 { return a.value()    < b.value(); }
405   return false;
406 }
407
408 template <class U, class V>
409 bool operator>(const Optional<U>& a, const Optional<V>& b) {
410   return b < a;
411 }
412
413 template <class U, class V>
414 bool operator<=(const Optional<U>& a, const Optional<V>& b) {
415   return !(b < a);
416 }
417
418 template <class U, class V>
419 bool operator>=(const Optional<U>& a, const Optional<V>& b) {
420   return !(a < b);
421 }
422
423 // Suppress comparability of Optional<T> with T, despite implicit conversion.
424 template<class V> bool operator< (const Optional<V>&, const V& other) = delete;
425 template<class V> bool operator<=(const Optional<V>&, const V& other) = delete;
426 template<class V> bool operator>=(const Optional<V>&, const V& other) = delete;
427 template<class V> bool operator> (const Optional<V>&, const V& other) = delete;
428 template<class V> bool operator< (const V& other, const Optional<V>&) = delete;
429 template<class V> bool operator<=(const V& other, const Optional<V>&) = delete;
430 template<class V> bool operator>=(const V& other, const Optional<V>&) = delete;
431 template<class V> bool operator> (const V& other, const Optional<V>&) = delete;
432
433 ///////////////////////////////////////////////////////////////////////////////
434
435 } // namespace folly
436
437 // Allow usage of Optional<T> in std::unordered_map and std::unordered_set
438 FOLLY_NAMESPACE_STD_BEGIN
439 template <class T>
440 struct hash<folly::Optional<T>> {
441   size_t operator()(folly::Optional<T> const& obj) const {
442     if (!obj.hasValue()) {
443       return 0;
444     }
445     return hash<typename remove_const<T>::type>()(*obj);
446   }
447 };
448 FOLLY_NAMESPACE_STD_END