Update documentation for Synchronized
[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* get_pointer() const&  {
215     return storage_.hasValue ? &storage_.value : nullptr;
216   }
217   Value* get_pointer() & {
218     return storage_.hasValue ? &storage_.value : nullptr;
219   }
220   Value* get_pointer() && = delete;
221
222   bool hasValue() const { return storage_.hasValue; }
223
224   explicit operator bool() const {
225     return hasValue();
226   }
227
228   const Value& operator*() const&  { return value(); }
229         Value& operator*()      &  { return value(); }
230         Value  operator*()      && { return std::move(value()); }
231
232   const Value* operator->() const { return &value(); }
233         Value* operator->()       { return &value(); }
234
235   // Return a copy of the value if set, or a given default if not.
236   template <class U>
237   Value value_or(U&& dflt) const& {
238     if (storage_.hasValue) {
239       return storage_.value;
240     }
241
242     return std::forward<U>(dflt);
243   }
244
245   template <class U>
246   Value value_or(U&& dflt) && {
247     if (storage_.hasValue) {
248       return std::move(storage_.value);
249     }
250
251     return std::forward<U>(dflt);
252   }
253
254  private:
255   void require_value() const {
256     if (!storage_.hasValue) {
257       throw OptionalEmptyException();
258     }
259   }
260
261   template<class... Args>
262   void construct(Args&&... args) {
263     const void* ptr = &storage_.value;
264     // for supporting const types
265     new(const_cast<void*>(ptr)) Value(std::forward<Args>(args)...);
266     storage_.hasValue = true;
267   }
268
269   struct StorageTriviallyDestructible {
270     // uninitialized
271     union { Value value; };
272     bool hasValue;
273
274     StorageTriviallyDestructible() : hasValue{false} {}
275
276     void clear() {
277       hasValue = false;
278     }
279   };
280
281   struct StorageNonTriviallyDestructible {
282     // uninitialized
283     union { Value value; };
284     bool hasValue;
285
286     StorageNonTriviallyDestructible() : hasValue{false} {}
287
288     ~StorageNonTriviallyDestructible() {
289       clear();
290     }
291
292     void clear() {
293       if (hasValue) {
294         hasValue = false;
295         value.~Value();
296       }
297     }
298   };
299
300   using Storage =
301     typename std::conditional<std::is_trivially_destructible<Value>::value,
302                               StorageTriviallyDestructible,
303                               StorageNonTriviallyDestructible>::type;
304
305   Storage storage_;
306 };
307
308 #if defined(__GNUC__) && !defined(__clang__)
309 #pragma GCC diagnostic pop
310 #endif
311
312 template<class T>
313 const T* get_pointer(const Optional<T>& opt) {
314   return opt.get_pointer();
315 }
316
317 template<class T>
318 T* get_pointer(Optional<T>& opt) {
319   return opt.get_pointer();
320 }
321
322 template<class T>
323 void swap(Optional<T>& a, Optional<T>& b) {
324   if (a.hasValue() && b.hasValue()) {
325     // both full
326     using std::swap;
327     swap(a.value(), b.value());
328   } else if (a.hasValue() || b.hasValue()) {
329     std::swap(a, b); // fall back to default implementation if they're mixed.
330   }
331 }
332
333 template<class T,
334          class Opt = Optional<typename std::decay<T>::type>>
335 Opt make_optional(T&& v) {
336   return Opt(std::forward<T>(v));
337 }
338
339 ///////////////////////////////////////////////////////////////////////////////
340 // Comparisons.
341
342 template<class V>
343 bool operator==(const Optional<V>& a, const V& b) {
344   return a.hasValue() && a.value() == b;
345 }
346
347 template<class V>
348 bool operator!=(const Optional<V>& a, const V& b) {
349   return !(a == b);
350 }
351
352 template<class V>
353 bool operator==(const V& a, const Optional<V>& b) {
354   return b.hasValue() && b.value() == a;
355 }
356
357 template<class V>
358 bool operator!=(const V& a, const Optional<V>& b) {
359   return !(a == b);
360 }
361
362 template<class V>
363 bool operator==(const Optional<V>& a, const Optional<V>& b) {
364   if (a.hasValue() != b.hasValue()) { return false; }
365   if (a.hasValue())                 { return a.value() == b.value(); }
366   return true;
367 }
368
369 template<class V>
370 bool operator!=(const Optional<V>& a, const Optional<V>& b) {
371   return !(a == b);
372 }
373
374 template<class V>
375 bool operator< (const Optional<V>& a, const Optional<V>& b) {
376   if (a.hasValue() != b.hasValue()) { return a.hasValue() < b.hasValue(); }
377   if (a.hasValue())                 { return a.value()    < b.value(); }
378   return false;
379 }
380
381 template<class V>
382 bool operator> (const Optional<V>& a, const Optional<V>& b) {
383   return b < a;
384 }
385
386 template<class V>
387 bool operator<=(const Optional<V>& a, const Optional<V>& b) {
388   return !(b < a);
389 }
390
391 template<class V>
392 bool operator>=(const Optional<V>& a, const Optional<V>& b) {
393   return !(a < b);
394 }
395
396 // Suppress comparability of Optional<T> with T, despite implicit conversion.
397 template<class V> bool operator< (const Optional<V>&, const V& other) = delete;
398 template<class V> bool operator<=(const Optional<V>&, const V& other) = delete;
399 template<class V> bool operator>=(const Optional<V>&, const V& other) = delete;
400 template<class V> bool operator> (const Optional<V>&, const V& other) = delete;
401 template<class V> bool operator< (const V& other, const Optional<V>&) = delete;
402 template<class V> bool operator<=(const V& other, const Optional<V>&) = delete;
403 template<class V> bool operator>=(const V& other, const Optional<V>&) = delete;
404 template<class V> bool operator> (const V& other, const Optional<V>&) = delete;
405
406 ///////////////////////////////////////////////////////////////////////////////
407
408 } // namespace folly