Fix optional default initialization
[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 class OptionalEmptyException : public std::runtime_error {
71  public:
72   OptionalEmptyException()
73       : std::runtime_error("Empty Optional cannot be unwrapped") {}
74 };
75
76 template<class Value>
77 class Optional {
78  public:
79   typedef Value value_type;
80
81   static_assert(!std::is_reference<Value>::value,
82                 "Optional may not be used with reference types");
83   static_assert(!std::is_abstract<Value>::value,
84                 "Optional may not be used with abstract types");
85
86   Optional() noexcept {
87   }
88
89   Optional(const Optional& src)
90     noexcept(std::is_nothrow_copy_constructible<Value>::value) {
91
92     if (src.hasValue()) {
93       construct(src.value());
94     }
95   }
96
97   Optional(Optional&& src)
98     noexcept(std::is_nothrow_move_constructible<Value>::value) {
99
100     if (src.hasValue()) {
101       construct(std::move(src.value()));
102       src.clear();
103     }
104   }
105
106   /* implicit */ Optional(const None&) noexcept {
107   }
108
109   /* implicit */ Optional(Value&& newValue)
110     noexcept(std::is_nothrow_move_constructible<Value>::value) {
111     construct(std::move(newValue));
112   }
113
114   /* implicit */ Optional(const Value& newValue)
115     noexcept(std::is_nothrow_copy_constructible<Value>::value) {
116     construct(newValue);
117   }
118
119   void assign(const None&) {
120     clear();
121   }
122
123   void assign(Optional&& src) {
124     if (this != &src) {
125       if (src.hasValue()) {
126         assign(std::move(src.value()));
127         src.clear();
128       } else {
129         clear();
130       }
131     }
132   }
133
134   void assign(const Optional& src) {
135     if (src.hasValue()) {
136       assign(src.value());
137     } else {
138       clear();
139     }
140   }
141
142   void assign(Value&& newValue) {
143     if (hasValue()) {
144       storage_.value = std::move(newValue);
145     } else {
146       construct(std::move(newValue));
147     }
148   }
149
150   void assign(const Value& newValue) {
151     if (hasValue()) {
152       storage_.value = newValue;
153     } else {
154       construct(newValue);
155     }
156   }
157
158   template<class Arg>
159   Optional& operator=(Arg&& arg) {
160     assign(std::forward<Arg>(arg));
161     return *this;
162   }
163
164   Optional& operator=(Optional &&other)
165     noexcept (std::is_nothrow_move_assignable<Value>::value) {
166
167     assign(std::move(other));
168     return *this;
169   }
170
171   Optional& operator=(const Optional &other)
172     noexcept (std::is_nothrow_copy_assignable<Value>::value) {
173
174     assign(other);
175     return *this;
176   }
177
178   template<class... Args>
179   void emplace(Args&&... args) {
180     clear();
181     construct(std::forward<Args>(args)...);
182   }
183
184   void clear() {
185     storage_.clear();
186   }
187
188   const Value& value() const& {
189     require_value();
190     return storage_.value;
191   }
192
193   Value& value() & {
194     require_value();
195     return storage_.value;
196   }
197
198   Value&& value() && {
199     require_value();
200     return std::move(storage_.value);
201   }
202
203   const Value&& value() const&& {
204     require_value();
205     return std::move(storage_.value);
206   }
207
208   const Value* get_pointer() const&  {
209     return storage_.hasValue ? &storage_.value : nullptr;
210   }
211   Value* get_pointer() & {
212     return storage_.hasValue ? &storage_.value : nullptr;
213   }
214   Value* get_pointer() && = delete;
215
216   bool hasValue() const { return storage_.hasValue; }
217
218   explicit operator bool() const {
219     return hasValue();
220   }
221
222   const Value& operator*()  const&  { return value(); }
223         Value& operator*()       &  { return value(); }
224   const Value&& operator*() const&& { return std::move(value()); }
225         Value&& operator*()      && { return std::move(value()); }
226
227   const Value* operator->() const { return &value(); }
228         Value* operator->()       { return &value(); }
229
230   // Return a copy of the value if set, or a given default if not.
231   template <class U>
232   Value value_or(U&& dflt) const& {
233     if (storage_.hasValue) {
234       return storage_.value;
235     }
236
237     return std::forward<U>(dflt);
238   }
239
240   template <class U>
241   Value value_or(U&& dflt) && {
242     if (storage_.hasValue) {
243       return std::move(storage_.value);
244     }
245
246     return std::forward<U>(dflt);
247   }
248
249  private:
250   void require_value() const {
251     if (!storage_.hasValue) {
252       throw OptionalEmptyException();
253     }
254   }
255
256   template<class... Args>
257   void construct(Args&&... args) {
258     const void* ptr = &storage_.value;
259     // for supporting const types
260     new(const_cast<void*>(ptr)) Value(std::forward<Args>(args)...);
261     storage_.hasValue = true;
262   }
263
264   struct StorageTriviallyDestructible {
265     // The union trick allows to initialize the Optional's memory,
266     // so that compiler/tools don't complain about unitialized memory,
267     // without actually calling Value's default constructor.
268     // The rest of the implementation enforces that hasValue/value are
269     // synchronized.
270     union {
271       bool hasValue;
272       struct {
273         bool paddingForHasValue_[1];
274         Value value;
275       };
276     };
277
278     StorageTriviallyDestructible() : hasValue{false} {}
279
280     void clear() {
281       hasValue = false;
282     }
283   };
284
285   struct StorageNonTriviallyDestructible {
286     // See StorageTriviallyDestructible's union
287     union {
288       bool hasValue;
289       struct {
290         bool paddingForHasValue_[1];
291         Value value;
292       };
293     };
294
295     StorageNonTriviallyDestructible() : hasValue{false} {}
296     ~StorageNonTriviallyDestructible() {
297       clear();
298     }
299
300     void clear() {
301       if (hasValue) {
302         hasValue = false;
303         value.~Value();
304       }
305     }
306   };
307
308   using Storage =
309     typename std::conditional<std::is_trivially_destructible<Value>::value,
310                               StorageTriviallyDestructible,
311                               StorageNonTriviallyDestructible>::type;
312
313   Storage storage_;
314 };
315
316 template<class T>
317 const T* get_pointer(const Optional<T>& opt) {
318   return opt.get_pointer();
319 }
320
321 template<class T>
322 T* get_pointer(Optional<T>& opt) {
323   return opt.get_pointer();
324 }
325
326 template<class T>
327 void swap(Optional<T>& a, Optional<T>& b) {
328   if (a.hasValue() && b.hasValue()) {
329     // both full
330     using std::swap;
331     swap(a.value(), b.value());
332   } else if (a.hasValue() || b.hasValue()) {
333     std::swap(a, b); // fall back to default implementation if they're mixed.
334   }
335 }
336
337 template<class T,
338          class Opt = Optional<typename std::decay<T>::type>>
339 Opt make_optional(T&& v) {
340   return Opt(std::forward<T>(v));
341 }
342
343 ///////////////////////////////////////////////////////////////////////////////
344 // Comparisons.
345
346 template<class V>
347 bool operator==(const Optional<V>& a, const V& b) {
348   return a.hasValue() && a.value() == b;
349 }
350
351 template<class V>
352 bool operator!=(const Optional<V>& a, const V& b) {
353   return !(a == b);
354 }
355
356 template<class V>
357 bool operator==(const V& a, const Optional<V>& b) {
358   return b.hasValue() && b.value() == a;
359 }
360
361 template<class V>
362 bool operator!=(const V& a, const Optional<V>& b) {
363   return !(a == b);
364 }
365
366 template<class V>
367 bool operator==(const Optional<V>& a, const Optional<V>& b) {
368   if (a.hasValue() != b.hasValue()) { return false; }
369   if (a.hasValue())                 { return a.value() == b.value(); }
370   return true;
371 }
372
373 template<class V>
374 bool operator!=(const Optional<V>& a, const Optional<V>& b) {
375   return !(a == b);
376 }
377
378 template<class V>
379 bool operator< (const Optional<V>& a, const Optional<V>& b) {
380   if (a.hasValue() != b.hasValue()) { return a.hasValue() < b.hasValue(); }
381   if (a.hasValue())                 { return a.value()    < b.value(); }
382   return false;
383 }
384
385 template<class V>
386 bool operator> (const Optional<V>& a, const Optional<V>& b) {
387   return b < a;
388 }
389
390 template<class V>
391 bool operator<=(const Optional<V>& a, const Optional<V>& b) {
392   return !(b < a);
393 }
394
395 template<class V>
396 bool operator>=(const Optional<V>& a, const Optional<V>& b) {
397   return !(a < b);
398 }
399
400 // Suppress comparability of Optional<T> with T, despite implicit conversion.
401 template<class V> bool operator< (const Optional<V>&, const V& other) = delete;
402 template<class V> bool operator<=(const Optional<V>&, const V& other) = delete;
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 V& other, const Optional<V>&) = delete;
406 template<class V> bool operator<=(const V& other, const Optional<V>&) = 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
410 ///////////////////////////////////////////////////////////////////////////////
411
412 } // namespace folly