Overload Optional::value() on object reference type.
[folly.git] / folly / Optional.h
1 /*
2  * Copyright 2015 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 #ifndef FOLLY_OPTIONAL_H_
18 #define FOLLY_OPTIONAL_H_
19
20 /*
21  * Optional - For conditional initialization of values, like boost::optional,
22  * but with support for move semantics and emplacement.  Reference type support
23  * has not been included due to limited use cases and potential confusion with
24  * semantics of assignment: Assigning to an optional reference could quite
25  * reasonably copy its value or redirect the reference.
26  *
27  * Optional can be useful when a variable might or might not be needed:
28  *
29  *  Optional<Logger> maybeLogger = ...;
30  *  if (maybeLogger) {
31  *    maybeLogger->log("hello");
32  *  }
33  *
34  * Optional enables a 'null' value for types which do not otherwise have
35  * nullability, especially useful for parameter passing:
36  *
37  * void testIterator(const unique_ptr<Iterator>& it,
38  *                   initializer_list<int> idsExpected,
39  *                   Optional<initializer_list<int>> ranksExpected = none) {
40  *   for (int i = 0; it->next(); ++i) {
41  *     EXPECT_EQ(it->doc().id(), idsExpected[i]);
42  *     if (ranksExpected) {
43  *       EXPECT_EQ(it->doc().rank(), (*ranksExpected)[i]);
44  *     }
45  *   }
46  * }
47  *
48  * Optional models OptionalPointee, so calling 'get_pointer(opt)' will return a
49  * pointer to nullptr if the 'opt' is empty, and a pointer to the value if it is
50  * not:
51  *
52  *  Optional<int> maybeInt = ...;
53  *  if (int* v = get_pointer(maybeInt)) {
54  *    cout << *v << endl;
55  *  }
56  */
57 #include <cstddef>
58 #include <stdexcept>
59 #include <type_traits>
60 #include <utility>
61
62 #include <boost/operators.hpp>
63
64 #include <folly/Portability.h>
65
66 namespace folly {
67
68 namespace detail { struct NoneHelper {}; }
69
70 typedef int detail::NoneHelper::*None;
71
72 const None none = nullptr;
73
74 /**
75  * gcc-4.7 warns about use of uninitialized memory around the use of storage_
76  * even though this is explicitly initialized at each point.
77  */
78 #if defined(__GNUC__) && !defined(__clang__)
79 # pragma GCC diagnostic push
80 # pragma GCC diagnostic ignored "-Wuninitialized"
81 # pragma GCC diagnostic ignored "-Wpragmas"
82 # pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
83 #endif // __GNUC__
84
85 class OptionalEmptyException : public std::runtime_error {
86  public:
87   OptionalEmptyException()
88       : std::runtime_error("Empty Optional cannot be unwrapped") {}
89 };
90
91 template<class Value>
92 class Optional {
93  public:
94   static_assert(!std::is_reference<Value>::value,
95                 "Optional may not be used with reference types");
96   static_assert(!std::is_abstract<Value>::value,
97                 "Optional may not be used with abstract types");
98
99   Optional()
100     : hasValue_(false) {
101   }
102
103   Optional(const Optional& src)
104     noexcept(std::is_nothrow_copy_constructible<Value>::value) {
105
106     if (src.hasValue()) {
107       construct(src.value());
108     } else {
109       hasValue_ = false;
110     }
111   }
112
113   Optional(Optional&& src)
114     noexcept(std::is_nothrow_move_constructible<Value>::value) {
115
116     if (src.hasValue()) {
117       construct(std::move(src.value()));
118       src.clear();
119     } else {
120       hasValue_ = false;
121     }
122   }
123
124   /* implicit */ Optional(const None&) noexcept
125     : hasValue_(false) {
126   }
127
128   /* implicit */ Optional(Value&& newValue)
129     noexcept(std::is_nothrow_move_constructible<Value>::value) {
130     construct(std::move(newValue));
131   }
132
133   /* implicit */ Optional(const Value& newValue)
134     noexcept(std::is_nothrow_copy_constructible<Value>::value) {
135     construct(newValue);
136   }
137
138   ~Optional() noexcept {
139     clear();
140   }
141
142   void assign(const None&) {
143     clear();
144   }
145
146   void assign(Optional&& src) {
147     if (this != &src) {
148       if (src.hasValue()) {
149         assign(std::move(src.value()));
150         src.clear();
151       } else {
152         clear();
153       }
154     }
155   }
156
157   void assign(const Optional& src) {
158     if (src.hasValue()) {
159       assign(src.value());
160     } else {
161       clear();
162     }
163   }
164
165   void assign(Value&& newValue) {
166     if (hasValue()) {
167       value_ = std::move(newValue);
168     } else {
169       construct(std::move(newValue));
170     }
171   }
172
173   void assign(const Value& newValue) {
174     if (hasValue()) {
175       value_ = newValue;
176     } else {
177       construct(newValue);
178     }
179   }
180
181   template<class Arg>
182   Optional& operator=(Arg&& arg) {
183     assign(std::forward<Arg>(arg));
184     return *this;
185   }
186
187   Optional& operator=(Optional &&other)
188     noexcept (std::is_nothrow_move_assignable<Value>::value) {
189
190     assign(std::move(other));
191     return *this;
192   }
193
194   Optional& operator=(const Optional &other)
195     noexcept (std::is_nothrow_copy_assignable<Value>::value) {
196
197     assign(other);
198     return *this;
199   }
200
201   template<class... Args>
202   void emplace(Args&&... args) {
203     clear();
204     construct(std::forward<Args>(args)...);
205   }
206
207   void clear() {
208     if (hasValue()) {
209       hasValue_ = false;
210       value_.~Value();
211     }
212   }
213
214   const Value& value() const& {
215     require_value();
216     return value_;
217   }
218
219   Value& value() & {
220     require_value();
221     return value_;
222   }
223
224   Value value() && {
225     require_value();
226     return std::move(value_);
227   }
228
229   const Value* get_pointer() const&  { return hasValue_ ? &value_ : nullptr; }
230         Value* get_pointer()      &  { return hasValue_ ? &value_ : nullptr; }
231         Value* get_pointer()      && = delete;
232
233   bool hasValue() const { return 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         Value  operator*()      && { return std::move(value()); }
242
243   const Value* operator->() const { return &value(); }
244         Value* operator->()       { return &value(); }
245
246   // Return a copy of the value if set, or a given default if not.
247   template <class U>
248   Value value_or(U&& dflt) const& {
249     return hasValue_ ? value_ : std::forward<U>(dflt);
250   }
251
252   template <class U>
253   Value value_or(U&& dflt) && {
254     return hasValue_ ? std::move(value_) : std::forward<U>(dflt);
255   }
256
257  private:
258   void require_value() const {
259     if (!hasValue_) {
260       throw OptionalEmptyException();
261     }
262   }
263
264   template<class... Args>
265   void construct(Args&&... args) {
266     const void* ptr = &value_;
267     // for supporting const types
268     new(const_cast<void*>(ptr)) Value(std::forward<Args>(args)...);
269     hasValue_ = true;
270   }
271
272   // uninitialized
273   union { Value value_; };
274   bool hasValue_;
275 };
276
277 #if defined(__GNUC__) && !defined(__clang__)
278 #pragma GCC diagnostic pop
279 #endif
280
281 template<class T>
282 const T* get_pointer(const Optional<T>& opt) {
283   return opt.get_pointer();
284 }
285
286 template<class T>
287 T* get_pointer(Optional<T>& opt) {
288   return opt.get_pointer();
289 }
290
291 template<class T>
292 void swap(Optional<T>& a, Optional<T>& b) {
293   if (a.hasValue() && b.hasValue()) {
294     // both full
295     using std::swap;
296     swap(a.value(), b.value());
297   } else if (a.hasValue() || b.hasValue()) {
298     std::swap(a, b); // fall back to default implementation if they're mixed.
299   }
300 }
301
302 template<class T,
303          class Opt = Optional<typename std::decay<T>::type>>
304 Opt make_optional(T&& v) {
305   return Opt(std::forward<T>(v));
306 }
307
308 ///////////////////////////////////////////////////////////////////////////////
309 // Comparisons.
310
311 template<class V>
312 bool operator==(const Optional<V>& a, const V& b) {
313   return a.hasValue() && a.value() == b;
314 }
315
316 template<class V>
317 bool operator!=(const Optional<V>& a, const V& b) {
318   return !(a == b);
319 }
320
321 template<class V>
322 bool operator==(const V& a, const Optional<V>& b) {
323   return b.hasValue() && b.value() == a;
324 }
325
326 template<class V>
327 bool operator!=(const V& a, const Optional<V>& b) {
328   return !(a == b);
329 }
330
331 template<class V>
332 bool operator==(const Optional<V>& a, const Optional<V>& b) {
333   if (a.hasValue() != b.hasValue()) { return false; }
334   if (a.hasValue())                 { return a.value() == b.value(); }
335   return true;
336 }
337
338 template<class V>
339 bool operator!=(const Optional<V>& a, const Optional<V>& b) {
340   return !(a == b);
341 }
342
343 template<class V>
344 bool operator< (const Optional<V>& a, const Optional<V>& b) {
345   if (a.hasValue() != b.hasValue()) { return a.hasValue() < b.hasValue(); }
346   if (a.hasValue())                 { return a.value()    < b.value(); }
347   return false;
348 }
349
350 template<class V>
351 bool operator> (const Optional<V>& a, const Optional<V>& b) {
352   return b < a;
353 }
354
355 template<class V>
356 bool operator<=(const Optional<V>& a, const Optional<V>& b) {
357   return !(b < a);
358 }
359
360 template<class V>
361 bool operator>=(const Optional<V>& a, const Optional<V>& b) {
362   return !(a < b);
363 }
364
365 // Suppress comparability of Optional<T> with T, despite implicit conversion.
366 template<class V> bool operator< (const Optional<V>&, const V& other) = delete;
367 template<class V> bool operator<=(const Optional<V>&, const V& other) = delete;
368 template<class V> bool operator>=(const Optional<V>&, const V& other) = delete;
369 template<class V> bool operator> (const Optional<V>&, const V& other) = delete;
370 template<class V> bool operator< (const V& other, const Optional<V>&) = delete;
371 template<class V> bool operator<=(const V& other, const Optional<V>&) = delete;
372 template<class V> bool operator>=(const V& other, const Optional<V>&) = delete;
373 template<class V> bool operator> (const V& other, const Optional<V>&) = delete;
374
375 ///////////////////////////////////////////////////////////////////////////////
376
377 } // namespace folly
378
379 #endif // FOLLY_OPTIONAL_H_