Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(274)

Side by Side Diff: base/optional.h

Issue 1245163002: Base: add Optional<T>. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: moar test changes for msvc Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef BASE_OPTIONAL_H_
6 #define BASE_OPTIONAL_H_
7
8 #include <type_traits>
9
10 #include "base/logging.h"
11 #include "base/memory/aligned_memory.h"
12
13 namespace base {
14
15 // Specification:
16 // http://en.cppreference.com/w/cpp/utility/optional/in_place_t
17 struct in_place_t {};
18
19 // Specification:
20 // http://en.cppreference.com/w/cpp/utility/optional/nullopt_t
21 struct nullopt_t {
22 constexpr explicit nullopt_t(int) {}
23 };
24
25 // Specification:
26 // http://en.cppreference.com/w/cpp/utility/optional/in_place
27 constexpr in_place_t in_place = {};
28
29 // Specification:
30 // http://en.cppreference.com/w/cpp/utility/optional/nullopt
31 constexpr nullopt_t nullopt(0);
32
33 // base::Optional is a Chromium version of the C++17 optional class:
34 // http://en.cppreference.com/w/cpp/utility/optional
danakj 2016/04/14 20:16:20 Point to the markdown as well?
mlamouri (slow - plz ping) 2016/04/16 11:43:43 Done.
35 // The following known differences apply:
36 // - The constructor and emplace method using initializer_list are not
37 // implemented because 'initializer_list' is banned from Chromium.
38 // - Constructors do not use 'constexpr' as it is a C++14 extension.
39 // - 'constexpr' might be missing in some places for reasons specified locally.
40 // - No exceptions are thrown, because they are banned from Chromium.
41 // - All the non-members are in the 'base' namespace instead of 'std'.
42 template <typename T>
43 class Optional {
44 public:
45 constexpr Optional() = default;
46 Optional(base::nullopt_t) : Optional() {}
47
48 Optional(const Optional& other) {
49 if (!other.is_null_)
50 Init(other.value());
51 }
52
53 Optional(Optional&& other) {
54 if (!other.is_null_)
55 Init(std::move(other.value()));
56 }
57
58 Optional(const T& value) { Init(value); }
59
60 Optional(T&& value) { Init(std::move(value)); }
61
62 template <class... Args>
63 explicit Optional(base::in_place_t, Args&&... args) {
64 emplace(std::forward<Args>(args)...);
65 }
66
67 ~Optional() {
68 // TODO(mlamouri): use is_trivially_destructible<T>::value when possible.
69 FreeIfNeeded();
70 }
71
72 Optional& operator=(base::nullopt_t) {
73 FreeIfNeeded();
74 return *this;
75 }
76
77 Optional& operator=(const Optional& other) {
78 if (other.is_null_) {
79 FreeIfNeeded();
80 return *this;
81 }
82
83 InitOrAssign(other.value());
84 return *this;
85 }
86
87 Optional& operator=(Optional&& other) {
88 if (other.is_null_) {
89 FreeIfNeeded();
90 return *this;
91 }
92
93 InitOrAssign(std::move(other.value()));
94 return *this;
95 }
96
97 template <class U>
98 typename std::enable_if<std::is_same<std::decay<U>, T>::value,
99 Optional&>::type
100 operator=(U&& value) {
101 InitOrAssign(std::forward<U>(value));
102 return *this;
103 }
104
105 // TODO(mlamouri): can't use 'constexpr' with DCHECK.
106 const T* operator->() const {
107 DCHECK(!is_null_);
108 return &value();
109 }
110
111 // TODO(mlamouri): using 'constexpr' here breaks compiler that assume it was
112 // meant to be 'constexpr const'.
113 T* operator->() {
114 DCHECK(!is_null_);
115 return &value();
116 }
117
118 constexpr const T& operator*() const& { return value(); }
119
120 // TODO(mlamouri): using 'constexpr' here breaks compiler that assume it was
121 // meant to be 'constexpr const'.
122 T& operator*() & { return value(); }
123
124 constexpr const T&& operator*() const&& { return std::move(value()); }
125
126 // TODO(mlamouri): using 'constexpr' here breaks compiler that assume it was
127 // meant to be 'constexpr const'.
128 T&& operator*() && { return std::move(value()); }
129
130 constexpr explicit operator bool() const { return !is_null_; }
131
132 // TODO(mlamouri): using 'constexpr' here breaks compiler that assume it was
133 // meant to be 'constexpr const'.
134 T& value() & {
135 DCHECK(!is_null_);
136 return *buffer_.template data_as<T>();
137 }
138
139 // TODO(mlamouri): can't use 'constexpr' with DCHECK.
140 const T& value() const& {
141 DCHECK(!is_null_);
142 return *buffer_.template data_as<T>();
143 }
144
145 // TODO(mlamouri): using 'constexpr' here breaks compiler that assume it was
146 // meant to be 'constexpr const'.
147 T&& value() && {
148 DCHECK(!is_null_);
149 return std::move(*buffer_.template data_as<T>());
150 }
151
152 // TODO(mlamouri): can't use 'constexpr' with DCHECK.
153 const T&& value() const&& {
154 DCHECK(!is_null_);
155 return std::move(*buffer_.template data_as<T>());
156 }
157
158 template <class U>
159 constexpr T value_or(U&& default_value) const& {
160 // TODO(mlamouri): add the following assert when possible:
161 // static_assert(std::is_copy_constructible<T>::value,
162 // "T must be copy constructible");
163 static_assert(std::is_convertible<U, T>::value,
164 "U must be convertible to T");
165 return is_null_ ? static_cast<T>(std::forward<U>(default_value)) : value();
166 }
167
168 template <class U>
169 T value_or(U&& default_value) && {
170 // TODO(mlamouri): add the following assert when possible:
171 // static_assert(std::is_move_constructible<T>::value,
172 // "T must be move constructible");
173 static_assert(std::is_convertible<U, T>::value,
174 "U must be convertible to T");
175 return is_null_ ? static_cast<T>(std::forward<U>(default_value))
176 : std::move(value());
177 }
178
179 void swap(Optional& other) {
180 if (is_null_ && other.is_null_)
181 return;
182
183 if (is_null_ != other.is_null_) {
184 if (is_null_) {
185 Init(std::move(*other.buffer_.template data_as<T>()));
186 other.FreeIfNeeded();
187 } else {
188 other.Init(std::move(*buffer_.template data_as<T>()));
189 FreeIfNeeded();
190 }
191 return;
192 }
193
194 DCHECK(!is_null_ && !other.is_null_);
195 using std::swap;
196 swap(**this, *other);
197 }
198
199 template <class... Args>
200 void emplace(Args&&... args) {
201 FreeIfNeeded();
202 Init(std::forward<Args>(args)...);
203 }
204
205 private:
206 void Init(const T& value) {
207 DCHECK(is_null_);
208 new (buffer_.template data_as<T>()) T(value);
209 is_null_ = false;
210 }
211
212 void Init(T&& value) {
213 DCHECK(is_null_);
214 new (buffer_.template data_as<T>()) T(std::move(value));
215 is_null_ = false;
216 }
217
218 template <class... Args>
219 void Init(Args&&... args) {
220 DCHECK(is_null_);
221 new (buffer_.template data_as<T>()) T(std::forward<Args>(args)...);
222 is_null_ = false;
223 }
224
225 void InitOrAssign(const T& value) {
226 if (is_null_)
227 Init(value);
228 else
229 *buffer_.template data_as<T>() = value;
230 }
231
232 void InitOrAssign(T&& value) {
233 if (is_null_)
234 Init(std::move(value));
235 else
236 *buffer_.template data_as<T>() = std::move(value);
237 }
238
239 void FreeIfNeeded() {
240 if (is_null_)
241 return;
242 buffer_.template data_as<T>()->~T();
243 is_null_ = true;
244 }
245
246 bool is_null_ = true;
247 base::AlignedMemory<sizeof(T), ALIGNOF(T)> buffer_;
248 };
249
250 template <class T>
251 constexpr bool operator==(const Optional<T>& lhs, const Optional<T>& rhs) {
252 return !!lhs != !!rhs ? false : lhs == nullopt || (*lhs == *rhs);
253 }
254
255 template <class T>
256 constexpr bool operator!=(const Optional<T>& lhs, const Optional<T>& rhs) {
257 return !(lhs == rhs);
258 }
259
260 template <class T>
261 constexpr bool operator<(const Optional<T>& lhs, const Optional<T>& rhs) {
262 return rhs == nullopt ? false : (lhs == nullopt ? true : *lhs < *rhs);
263 }
264
265 template <class T>
266 constexpr bool operator<=(const Optional<T>& lhs, const Optional<T>& rhs) {
267 return !(rhs < lhs);
268 }
269
270 template <class T>
271 constexpr bool operator>(const Optional<T>& lhs, const Optional<T>& rhs) {
272 return rhs < lhs;
273 }
274
275 template <class T>
276 constexpr bool operator>=(const Optional<T>& lhs, const Optional<T>& rhs) {
277 return !(lhs < rhs);
278 }
279
280 template <class T>
281 constexpr bool operator==(const Optional<T>& opt, base::nullopt_t) {
282 return !opt;
283 }
284
285 template <class T>
286 constexpr bool operator==(base::nullopt_t, const Optional<T>& opt) {
287 return !opt;
288 }
289
290 template <class T>
291 constexpr bool operator!=(const Optional<T>& opt, base::nullopt_t) {
292 return !!opt;
293 }
294
295 template <class T>
296 constexpr bool operator!=(base::nullopt_t, const Optional<T>& opt) {
297 return !!opt;
298 }
299
300 template <class T>
301 constexpr bool operator<(const Optional<T>& opt, base::nullopt_t) {
302 return false;
303 }
304
305 template <class T>
306 constexpr bool operator<(base::nullopt_t, const Optional<T>& opt) {
307 return !!opt;
308 }
309
310 template <class T>
311 constexpr bool operator<=(const Optional<T>& opt, base::nullopt_t) {
312 return !opt;
313 }
314
315 template <class T>
316 constexpr bool operator<=(base::nullopt_t, const Optional<T>& opt) {
317 return true;
318 }
319
320 template <class T>
321 constexpr bool operator>(const Optional<T>& opt, base::nullopt_t) {
322 return !!opt;
323 }
324
325 template <class T>
326 constexpr bool operator>(base::nullopt_t, const Optional<T>& opt) {
327 return false;
328 }
329
330 template <class T>
331 constexpr bool operator>=(const Optional<T>& opt, base::nullopt_t) {
332 return true;
333 }
334
335 template <class T>
336 constexpr bool operator>=(base::nullopt_t, const Optional<T>& opt) {
337 return !opt;
338 }
339
340 template <class T>
341 constexpr bool operator==(const Optional<T>& opt, const T& value) {
342 return opt != nullopt ? *opt == value : false;
343 }
344
345 template <class T>
346 constexpr bool operator==(const T& value, const Optional<T>& opt) {
347 return opt == value;
348 }
349
350 template <class T>
351 constexpr bool operator!=(const Optional<T>& opt, const T& value) {
352 return !(opt == value);
353 }
354
355 template <class T>
356 constexpr bool operator!=(const T& value, const Optional<T>& opt) {
357 return !(opt == value);
358 }
359
360 template <class T>
361 constexpr bool operator<(const Optional<T>& opt, const T& value) {
362 return opt != nullopt ? *opt < value : true;
363 }
364
365 template <class T>
366 constexpr bool operator<(const T& value, const Optional<T>& opt) {
367 return opt != nullopt ? value < *opt : false;
368 }
369
370 template <class T>
371 constexpr bool operator<=(const Optional<T>& opt, const T& value) {
372 return !(opt > value);
373 }
374
375 template <class T>
376 constexpr bool operator<=(const T& value, const Optional<T>& opt) {
377 return !(value > opt);
378 }
379
380 template <class T>
381 constexpr bool operator>(const Optional<T>& opt, const T& value) {
382 return value < opt;
383 }
384
385 template <class T>
386 constexpr bool operator>(const T& value, const Optional<T>& opt) {
387 return opt < value;
388 }
389
390 template <class T>
391 constexpr bool operator>=(const Optional<T>& opt, const T& value) {
392 return !(opt < value);
393 }
394
395 template <class T>
396 constexpr bool operator>=(const T& value, const Optional<T>& opt) {
397 return !(value < opt);
398 }
399
400 template <class T>
401 constexpr Optional<typename std::decay<T>::type> make_optional(T&& value) {
402 return Optional<typename std::decay<T>::type>(std::forward<T>(value));
403 }
404
405 template <class T>
406 void swap(Optional<T>& lhs, Optional<T>& rhs) {
407 lhs.swap(rhs);
408 }
409
410 } // namespace base
411
412 namespace std {
413
414 template <class T>
415 struct hash<base::Optional<T>> {
416 size_t operator()(const base::Optional<T>& opt) const {
417 return opt == base::nullopt ? 0 : std::hash<T>()(*opt);
418 }
419 };
420
421 } // namespace std
422
423 #endif // BASE_OPTIONAL_H_
OLDNEW
« no previous file with comments | « base/base.gypi ('k') | base/optional_unittest.cc » ('j') | docs/optional.md » ('J')

Powered by Google App Engine
This is Rietveld 408576698