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