update stats APIs to use TimePoint vs Duration correctly
[folly.git] / folly / Optional.h
1 /*
2  * Copyright 2016 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 <new>
58 #include <stdexcept>
59 #include <type_traits>
60 #include <utility>
61
62 namespace folly {
63
64 namespace detail { struct NoneHelper {}; }
65
66 typedef int detail::NoneHelper::*None;
67
68 const None none = nullptr;
69
70 /**
71  * gcc-4.7 warns about use of uninitialized memory around the use of storage_
72  * even though this is explicitly initialized at each point.
73  */
74 #if defined(__GNUC__) && !defined(__clang__)
75 # pragma GCC diagnostic push
76 # pragma GCC diagnostic ignored "-Wuninitialized"
77 # pragma GCC diagnostic ignored "-Wpragmas"
78 # pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
79 #endif // __GNUC__
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   void assign(const None&) {
131     clear();
132   }
133
134   void assign(Optional&& src) {
135     if (this != &src) {
136       if (src.hasValue()) {
137         assign(std::move(src.value()));
138         src.clear();
139       } else {
140         clear();
141       }
142     }
143   }
144
145   void assign(const Optional& src) {
146     if (src.hasValue()) {
147       assign(src.value());
148     } else {
149       clear();
150     }
151   }
152
153   void assign(Value&& newValue) {
154     if (hasValue()) {
155       storage_.value = std::move(newValue);
156     } else {
157       construct(std::move(newValue));
158     }
159   }
160
161   void assign(const Value& newValue) {
162     if (hasValue()) {
163       storage_.value = newValue;
164     } else {
165       construct(newValue);
166     }
167   }
168
169   template<class Arg>
170   Optional& operator=(Arg&& arg) {
171     assign(std::forward<Arg>(arg));
172     return *this;
173   }
174
175   Optional& operator=(Optional &&other)
176     noexcept (std::is_nothrow_move_assignable<Value>::value) {
177
178     assign(std::move(other));
179     return *this;
180   }
181
182   Optional& operator=(const Optional &other)
183     noexcept (std::is_nothrow_copy_assignable<Value>::value) {
184
185     assign(other);
186     return *this;
187   }
188
189   template<class... Args>
190   void emplace(Args&&... args) {
191     clear();
192     construct(std::forward<Args>(args)...);
193   }
194
195   void clear() {
196     storage_.clear();
197   }
198
199   const Value& value() const& {
200     require_value();
201     return storage_.value;
202   }
203
204   Value& value() & {
205     require_value();
206     return storage_.value;
207   }
208
209   Value&& value() && {
210     require_value();
211     return std::move(storage_.value);
212   }
213
214   const Value&& value() const&& {
215     require_value();
216     return std::move(storage_.value);
217   }
218
219   const Value* get_pointer() const&  {
220     return storage_.hasValue ? &storage_.value : nullptr;
221   }
222   Value* get_pointer() & {
223     return storage_.hasValue ? &storage_.value : nullptr;
224   }
225   Value* get_pointer() && = delete;
226
227   bool hasValue() const { return storage_.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   const Value&& operator*() const&& { return std::move(value()); }
236         Value&& operator*()      && { return std::move(value()); }
237
238   const Value* operator->() const { return &value(); }
239         Value* operator->()       { return &value(); }
240
241   // Return a copy of the value if set, or a given default if not.
242   template <class U>
243   Value value_or(U&& dflt) const& {
244     if (storage_.hasValue) {
245       return storage_.value;
246     }
247
248     return std::forward<U>(dflt);
249   }
250
251   template <class U>
252   Value value_or(U&& dflt) && {
253     if (storage_.hasValue) {
254       return std::move(storage_.value);
255     }
256
257     return std::forward<U>(dflt);
258   }
259
260  private:
261   void require_value() const {
262     if (!storage_.hasValue) {
263       throw OptionalEmptyException();
264     }
265   }
266
267   template<class... Args>
268   void construct(Args&&... args) {
269     const void* ptr = &storage_.value;
270     // for supporting const types
271     new(const_cast<void*>(ptr)) Value(std::forward<Args>(args)...);
272     storage_.hasValue = true;
273   }
274
275   struct StorageTriviallyDestructible {
276     // uninitialized
277     union { Value value; };
278     bool hasValue;
279
280     StorageTriviallyDestructible() : hasValue{false} {}
281
282     void clear() {
283       hasValue = false;
284     }
285   };
286
287   struct StorageNonTriviallyDestructible {
288     // uninitialized
289     union { Value value; };
290     bool hasValue;
291
292     StorageNonTriviallyDestructible() : hasValue{false} {}
293
294     ~StorageNonTriviallyDestructible() {
295       clear();
296     }
297
298     void clear() {
299       if (hasValue) {
300         hasValue = false;
301         value.~Value();
302       }
303     }
304   };
305
306   using Storage =
307     typename std::conditional<std::is_trivially_destructible<Value>::value,
308                               StorageTriviallyDestructible,
309                               StorageNonTriviallyDestructible>::type;
310
311   Storage storage_;
312 };
313
314 #if defined(__GNUC__) && !defined(__clang__)
315 #pragma GCC diagnostic pop
316 #endif
317
318 template<class T>
319 const T* get_pointer(const Optional<T>& opt) {
320   return opt.get_pointer();
321 }
322
323 template<class T>
324 T* get_pointer(Optional<T>& opt) {
325   return opt.get_pointer();
326 }
327
328 template<class T>
329 void swap(Optional<T>& a, Optional<T>& b) {
330   if (a.hasValue() && b.hasValue()) {
331     // both full
332     using std::swap;
333     swap(a.value(), b.value());
334   } else if (a.hasValue() || b.hasValue()) {
335     std::swap(a, b); // fall back to default implementation if they're mixed.
336   }
337 }
338
339 template<class T,
340          class Opt = Optional<typename std::decay<T>::type>>
341 Opt make_optional(T&& v) {
342   return Opt(std::forward<T>(v));
343 }
344
345 ///////////////////////////////////////////////////////////////////////////////
346 // Comparisons.
347
348 template<class V>
349 bool operator==(const Optional<V>& a, const V& b) {
350   return a.hasValue() && a.value() == b;
351 }
352
353 template<class V>
354 bool operator!=(const Optional<V>& a, const V& b) {
355   return !(a == b);
356 }
357
358 template<class V>
359 bool operator==(const V& a, const Optional<V>& b) {
360   return b.hasValue() && b.value() == a;
361 }
362
363 template<class V>
364 bool operator!=(const V& a, const Optional<V>& b) {
365   return !(a == b);
366 }
367
368 template<class V>
369 bool operator==(const Optional<V>& a, const Optional<V>& b) {
370   if (a.hasValue() != b.hasValue()) { return false; }
371   if (a.hasValue())                 { return a.value() == b.value(); }
372   return true;
373 }
374
375 template<class V>
376 bool operator!=(const Optional<V>& a, const Optional<V>& b) {
377   return !(a == b);
378 }
379
380 template<class V>
381 bool operator< (const Optional<V>& a, const Optional<V>& b) {
382   if (a.hasValue() != b.hasValue()) { return a.hasValue() < b.hasValue(); }
383   if (a.hasValue())                 { return a.value()    < b.value(); }
384   return false;
385 }
386
387 template<class V>
388 bool operator> (const Optional<V>& a, const Optional<V>& b) {
389   return b < a;
390 }
391
392 template<class V>
393 bool operator<=(const Optional<V>& a, const Optional<V>& b) {
394   return !(b < a);
395 }
396
397 template<class V>
398 bool operator>=(const Optional<V>& a, const Optional<V>& b) {
399   return !(a < b);
400 }
401
402 // Suppress comparability of Optional<T> with T, despite implicit conversion.
403 template<class V> bool operator< (const Optional<V>&, const V& other) = delete;
404 template<class V> bool operator<=(const Optional<V>&, const V& other) = delete;
405 template<class V> bool operator>=(const Optional<V>&, const V& other) = delete;
406 template<class V> bool operator> (const Optional<V>&, const V& other) = delete;
407 template<class V> bool operator< (const V& other, const Optional<V>&) = delete;
408 template<class V> bool operator<=(const V& other, const Optional<V>&) = delete;
409 template<class V> bool operator>=(const V& other, const Optional<V>&) = delete;
410 template<class V> bool operator> (const V& other, const Optional<V>&) = delete;
411
412 ///////////////////////////////////////////////////////////////////////////////
413
414 } // namespace folly