Minor clang compiler fixes
[folly.git] / folly / Optional.h
1 /*
2  * Copyright 2013 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 <utility>
58 #include <cassert>
59 #include <cstddef>
60 #include <type_traits>
61
62 #include <boost/operators.hpp>
63
64 namespace folly {
65
66 namespace detail { struct NoneHelper {}; }
67
68 typedef int detail::NoneHelper::*None;
69
70 const None none = nullptr;
71
72 template<class Value>
73 class Optional : boost::totally_ordered<Optional<Value>,
74                  boost::totally_ordered<Optional<Value>, Value>> {
75   typedef void (Optional::*bool_type)() const;
76   void truthy() const {};
77  public:
78   static_assert(!std::is_reference<Value>::value,
79                 "Optional may not be used with reference types");
80
81   Optional()
82     : hasValue_(false) {
83   }
84
85   Optional(const Optional& src) {
86     if (src.hasValue()) {
87       construct(src.value());
88     } else {
89       hasValue_ = false;
90     }
91   }
92
93   Optional(Optional&& src) {
94     if (src.hasValue()) {
95       construct(std::move(src.value()));
96       src.clear();
97     } else {
98       hasValue_ = false;
99     }
100   }
101
102   /* implicit */ Optional(const None& empty)
103     : hasValue_(false) {
104   }
105
106   /* implicit */ Optional(Value&& newValue) {
107     construct(std::move(newValue));
108   }
109
110   /* implicit */ Optional(const Value& newValue) {
111     construct(newValue);
112   }
113
114   ~Optional() {
115     clear();
116   }
117
118   void assign(const None&) {
119     clear();
120   }
121
122   void assign(Optional&& src) {
123     if (src.hasValue()) {
124       assign(std::move(src.value()));
125       src.clear();
126     } else {
127       clear();
128     }
129   }
130
131   void assign(const Optional& src) {
132     if (src.hasValue()) {
133       assign(src.value());
134     } else {
135       clear();
136     }
137   }
138
139   void assign(Value&& newValue) {
140     if (hasValue()) {
141       value_ = std::move(newValue);
142     } else {
143       construct(std::move(newValue));
144     }
145   }
146
147   void assign(const Value& newValue) {
148     if (hasValue()) {
149       value_ = newValue;
150     } else {
151       construct(newValue);
152     }
153   }
154
155   template<class Arg>
156   Optional& operator=(Arg&& arg) {
157     assign(std::forward<Arg>(arg));
158     return *this;
159   }
160
161   bool operator<(const Optional& other) const {
162     if (hasValue() != other.hasValue()) {
163       return hasValue() < other.hasValue();
164     }
165     if (hasValue()) {
166       return value() < other.value();
167     }
168     return false; // both empty
169   }
170
171   bool operator<(const Value& other) const {
172     return !hasValue() || value() < other;
173   }
174
175   bool operator==(const Optional& other) const {
176     if (hasValue()) {
177       return other.hasValue() && value() == other.value();
178     } else {
179       return !other.hasValue();
180     }
181   }
182
183   bool operator==(const Value& other) const {
184     return hasValue() && value() == other;
185   }
186
187   template<class... Args>
188   void emplace(Args&&... args) {
189     clear();
190     construct(std::forward<Args>(args)...);
191   }
192
193   void clear() {
194     if (hasValue()) {
195       hasValue_ = false;
196       value_.~Value();
197     }
198   }
199
200   const Value& value() const {
201     assert(hasValue());
202     return value_;
203   }
204
205   Value& value() {
206     assert(hasValue());
207     return value_;
208   }
209
210   bool hasValue() const { return hasValue_; }
211
212   /* safe bool idiom */
213   operator bool_type() const {
214     return hasValue() ? &Optional::truthy : nullptr;
215   }
216
217   const Value& operator*() const { return value(); }
218         Value& operator*()       { return value(); }
219
220   const Value* operator->() const { return &value(); }
221         Value* operator->()       { return &value(); }
222
223  private:
224   template<class... Args>
225   void construct(Args&&... args) {
226     const void* ptr = &value_;
227     // for supporting const types
228     new(const_cast<void*>(ptr)) Value(std::forward<Args>(args)...);
229     hasValue_ = true;
230   }
231
232   // uninitialized
233   union { Value value_; };
234   bool hasValue_;
235 };
236
237 template<class T>
238 const T* get_pointer(const Optional<T>& opt) {
239   return opt ? &opt.value() : nullptr;
240 }
241
242 template<class T>
243 T* get_pointer(Optional<T>& opt) {
244   return opt ? &opt.value() : nullptr;
245 }
246
247 template<class T>
248 void swap(Optional<T>& a, Optional<T>& b) {
249   if (a.hasValue() && b.hasValue()) {
250     // both full
251     using std::swap;
252     swap(a.value(), b.value());
253   } else if (a.hasValue() || b.hasValue()) {
254     std::swap(a, b); // fall back to default implementation if they're mixed.
255   }
256 }
257
258 }// namespace folly
259
260 #endif//FOLLY_OPTIONAL_H_