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