folly copyright 2015 -> copyright 2016
[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 #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 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     : hasValue_(false) {
99   }
100
101   Optional(const Optional& src)
102     noexcept(std::is_nothrow_copy_constructible<Value>::value) {
103
104     if (src.hasValue()) {
105       construct(src.value());
106     } else {
107       hasValue_ = false;
108     }
109   }
110
111   Optional(Optional&& src)
112     noexcept(std::is_nothrow_move_constructible<Value>::value) {
113
114     if (src.hasValue()) {
115       construct(std::move(src.value()));
116       src.clear();
117     } else {
118       hasValue_ = false;
119     }
120   }
121
122   /* implicit */ Optional(const None&) noexcept
123     : hasValue_(false) {
124   }
125
126   /* implicit */ Optional(Value&& newValue)
127     noexcept(std::is_nothrow_move_constructible<Value>::value) {
128     construct(std::move(newValue));
129   }
130
131   /* implicit */ Optional(const Value& newValue)
132     noexcept(std::is_nothrow_copy_constructible<Value>::value) {
133     construct(newValue);
134   }
135
136   ~Optional() noexcept {
137     clear();
138   }
139
140   void assign(const None&) {
141     clear();
142   }
143
144   void assign(Optional&& src) {
145     if (this != &src) {
146       if (src.hasValue()) {
147         assign(std::move(src.value()));
148         src.clear();
149       } else {
150         clear();
151       }
152     }
153   }
154
155   void assign(const Optional& src) {
156     if (src.hasValue()) {
157       assign(src.value());
158     } else {
159       clear();
160     }
161   }
162
163   void assign(Value&& newValue) {
164     if (hasValue()) {
165       value_ = std::move(newValue);
166     } else {
167       construct(std::move(newValue));
168     }
169   }
170
171   void assign(const Value& newValue) {
172     if (hasValue()) {
173       value_ = newValue;
174     } else {
175       construct(newValue);
176     }
177   }
178
179   template<class Arg>
180   Optional& operator=(Arg&& arg) {
181     assign(std::forward<Arg>(arg));
182     return *this;
183   }
184
185   Optional& operator=(Optional &&other)
186     noexcept (std::is_nothrow_move_assignable<Value>::value) {
187
188     assign(std::move(other));
189     return *this;
190   }
191
192   Optional& operator=(const Optional &other)
193     noexcept (std::is_nothrow_copy_assignable<Value>::value) {
194
195     assign(other);
196     return *this;
197   }
198
199   template<class... Args>
200   void emplace(Args&&... args) {
201     clear();
202     construct(std::forward<Args>(args)...);
203   }
204
205   void clear() {
206     if (hasValue()) {
207       hasValue_ = false;
208       value_.~Value();
209     }
210   }
211
212   const Value& value() const& {
213     require_value();
214     return value_;
215   }
216
217   Value& value() & {
218     require_value();
219     return value_;
220   }
221
222   Value value() && {
223     require_value();
224     return std::move(value_);
225   }
226
227   const Value* get_pointer() const&  { return hasValue_ ? &value_ : nullptr; }
228         Value* get_pointer()      &  { return hasValue_ ? &value_ : nullptr; }
229         Value* get_pointer()      && = delete;
230
231   bool hasValue() const { return hasValue_; }
232
233   explicit operator bool() const {
234     return hasValue();
235   }
236
237   const Value& operator*() const&  { return value(); }
238         Value& operator*()      &  { return value(); }
239         Value  operator*()      && { return std::move(value()); }
240
241   const Value* operator->() const { return &value(); }
242         Value* operator->()       { return &value(); }
243
244   // Return a copy of the value if set, or a given default if not.
245   template <class U>
246   Value value_or(U&& dflt) const& {
247     return hasValue_ ? value_ : std::forward<U>(dflt);
248   }
249
250   template <class U>
251   Value value_or(U&& dflt) && {
252     return hasValue_ ? std::move(value_) : std::forward<U>(dflt);
253   }
254
255  private:
256   void require_value() const {
257     if (!hasValue_) {
258       throw OptionalEmptyException();
259     }
260   }
261
262   template<class... Args>
263   void construct(Args&&... args) {
264     const void* ptr = &value_;
265     // for supporting const types
266     new(const_cast<void*>(ptr)) Value(std::forward<Args>(args)...);
267     hasValue_ = true;
268   }
269
270   // uninitialized
271   union { Value value_; };
272   bool hasValue_;
273 };
274
275 #if defined(__GNUC__) && !defined(__clang__)
276 #pragma GCC diagnostic pop
277 #endif
278
279 template<class T>
280 const T* get_pointer(const Optional<T>& opt) {
281   return opt.get_pointer();
282 }
283
284 template<class T>
285 T* get_pointer(Optional<T>& opt) {
286   return opt.get_pointer();
287 }
288
289 template<class T>
290 void swap(Optional<T>& a, Optional<T>& b) {
291   if (a.hasValue() && b.hasValue()) {
292     // both full
293     using std::swap;
294     swap(a.value(), b.value());
295   } else if (a.hasValue() || b.hasValue()) {
296     std::swap(a, b); // fall back to default implementation if they're mixed.
297   }
298 }
299
300 template<class T,
301          class Opt = Optional<typename std::decay<T>::type>>
302 Opt make_optional(T&& v) {
303   return Opt(std::forward<T>(v));
304 }
305
306 ///////////////////////////////////////////////////////////////////////////////
307 // Comparisons.
308
309 template<class V>
310 bool operator==(const Optional<V>& a, const V& b) {
311   return a.hasValue() && a.value() == b;
312 }
313
314 template<class V>
315 bool operator!=(const Optional<V>& a, const V& b) {
316   return !(a == b);
317 }
318
319 template<class V>
320 bool operator==(const V& a, const Optional<V>& b) {
321   return b.hasValue() && b.value() == a;
322 }
323
324 template<class V>
325 bool operator!=(const V& a, const Optional<V>& b) {
326   return !(a == b);
327 }
328
329 template<class V>
330 bool operator==(const Optional<V>& a, const Optional<V>& b) {
331   if (a.hasValue() != b.hasValue()) { return false; }
332   if (a.hasValue())                 { return a.value() == b.value(); }
333   return true;
334 }
335
336 template<class V>
337 bool operator!=(const Optional<V>& a, const Optional<V>& b) {
338   return !(a == b);
339 }
340
341 template<class V>
342 bool operator< (const Optional<V>& a, const Optional<V>& b) {
343   if (a.hasValue() != b.hasValue()) { return a.hasValue() < b.hasValue(); }
344   if (a.hasValue())                 { return a.value()    < b.value(); }
345   return false;
346 }
347
348 template<class V>
349 bool operator> (const Optional<V>& a, const Optional<V>& b) {
350   return b < a;
351 }
352
353 template<class V>
354 bool operator<=(const Optional<V>& a, const Optional<V>& b) {
355   return !(b < a);
356 }
357
358 template<class V>
359 bool operator>=(const Optional<V>& a, const Optional<V>& b) {
360   return !(a < b);
361 }
362
363 // Suppress comparability of Optional<T> with T, despite implicit conversion.
364 template<class V> bool operator< (const Optional<V>&, const V& other) = delete;
365 template<class V> bool operator<=(const Optional<V>&, const V& other) = delete;
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 V& other, const Optional<V>&) = delete;
369 template<class V> bool operator<=(const V& other, const Optional<V>&) = 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
373 ///////////////////////////////////////////////////////////////////////////////
374
375 } // namespace folly
376
377 #endif // FOLLY_OPTIONAL_H_