Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
|
ossu
2016/06/17 14:51:48
I kept the original copyright message, since I don
| |
| 2 * Copyright 2015 The WebRTC Project Authors. All rights reserved. | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 * | 3 // found in the LICENSE file. |
| 4 * Use of this source code is governed by a BSD-style license | |
| 5 * that can be found in the LICENSE file in the root of the source | |
| 6 * tree. An additional intellectual property rights grant can be found | |
| 7 * in the file PATENTS. All contributing project authors may | |
| 8 * be found in the AUTHORS file in the root of the source tree. | |
| 9 */ | |
| 10 | 4 |
| 11 #ifndef WEBRTC_BASE_OPTIONAL_H_ | 5 #ifndef WEBRTC_BASE_OPTIONAL_H_ |
| 12 #define WEBRTC_BASE_OPTIONAL_H_ | 6 #define WEBRTC_BASE_OPTIONAL_H_ |
| 13 | 7 |
| 14 #include <algorithm> | 8 #include <type_traits> |
| 15 #include <memory> | |
| 16 #include <utility> | |
| 17 | 9 |
| 18 #include "webrtc/base/checks.h" | 10 #include "webrtc/base/checks.h" |
| 11 #include "webrtc/base/template_util.h" | |
| 19 | 12 |
| 20 namespace rtc { | 13 namespace rtc { |
| 21 | 14 |
| 22 // Simple std::optional-wannabe. It either contains a T or not. | 15 // Specification: |
| 23 // | 16 // http://en.cppreference.com/w/cpp/utility/optional/in_place_t |
| 24 // A moved-from Optional<T> may only be destroyed, and assigned to if T allows | 17 struct in_place_t {}; |
| 25 // being assigned to after having been moved from. Specifically, you may not | 18 |
| 26 // assume that it just doesn't contain a value anymore. | 19 // Specification: |
| 27 // | 20 // http://en.cppreference.com/w/cpp/utility/optional/nullopt_t |
| 28 // Examples of good places to use Optional: | 21 struct nullopt_t { |
| 29 // | 22 constexpr explicit nullopt_t(int) {} |
| 30 // - As a class or struct member, when the member doesn't always have a value: | 23 }; |
| 31 // struct Prisoner { | 24 |
| 32 // std::string name; | 25 // Specification: |
| 33 // Optional<int> cell_number; // Empty if not currently incarcerated. | 26 // http://en.cppreference.com/w/cpp/utility/optional/in_place |
| 34 // }; | 27 constexpr in_place_t in_place = {}; |
| 35 // | 28 |
| 36 // - As a return value for functions that may fail to return a value on all | 29 // Specification: |
| 37 // allowed inputs. For example, a function that searches an array might | 30 // http://en.cppreference.com/w/cpp/utility/optional/nullopt |
| 38 // return an Optional<size_t> (the index where it found the element, or | 31 constexpr nullopt_t nullopt(0); |
| 39 // nothing if it didn't find it); and a function that parses numbers might | 32 |
| 40 // return Optional<double> (the parsed number, or nothing if parsing failed). | 33 namespace internal { |
| 41 // | 34 |
| 42 // Examples of bad places to use Optional: | 35 template <typename T, bool = rtc::is_trivially_destructible<T>::value> |
| 43 // | 36 struct OptionalStorage { |
| 44 // - As a return value for functions that may fail because of disallowed | 37 OptionalStorage() {}; |
| 45 // inputs. For example, a string length function should not return | 38 // When T is not trivially destructible we must call its |
| 46 // Optional<size_t> so that it can return nothing in case the caller passed | 39 // destructor before deallocating its memory. |
| 47 // it a null pointer; the function should probably use RTC_[D]CHECK instead, | 40 ~OptionalStorage() { |
| 48 // and return plain size_t. | 41 if (!is_null_) |
| 49 // | |
| 50 // - As a return value for functions that may fail to return a value on all | |
| 51 // allowed inputs, but need to tell the caller what went wrong. Returning | |
| 52 // Optional<double> when parsing a single number as in the example above | |
| 53 // might make sense, but any larger parse job is probably going to need to | |
| 54 // tell the caller what the problem was, not just that there was one. | |
| 55 // | |
| 56 // TODO(kwiberg): Get rid of this class when the standard library has | |
| 57 // std::optional (and we're allowed to use it). | |
| 58 template <typename T> | |
| 59 class Optional final { | |
| 60 public: | |
| 61 // Construct an empty Optional. | |
| 62 Optional() : has_value_(false) {} | |
| 63 | |
| 64 // Construct an Optional that contains a value. | |
| 65 explicit Optional(const T& value) : has_value_(true) { | |
| 66 new (&value_) T(value); | |
| 67 } | |
| 68 explicit Optional(T&& value) : has_value_(true) { | |
| 69 new (&value_) T(std::move(value)); | |
| 70 } | |
| 71 | |
| 72 // Copy constructor: copies the value from m if it has one. | |
| 73 Optional(const Optional& m) : has_value_(m.has_value_) { | |
| 74 if (has_value_) | |
| 75 new (&value_) T(m.value_); | |
| 76 } | |
| 77 | |
| 78 // Move constructor: if m has a value, moves the value from m, leaving m | |
| 79 // still in a state where it has a value, but a moved-from one (the | |
| 80 // properties of which depends on T; the only general guarantee is that we | |
| 81 // can destroy m). | |
| 82 Optional(Optional&& m) : has_value_(m.has_value_) { | |
| 83 if (has_value_) | |
| 84 new (&value_) T(std::move(m.value_)); | |
| 85 } | |
| 86 | |
| 87 ~Optional() { | |
| 88 if (has_value_) | |
| 89 value_.~T(); | 42 value_.~T(); |
| 90 } | 43 } |
| 91 | 44 |
| 92 // Copy assignment. Uses T's copy assignment if both sides have a value, T's | 45 bool is_null_ = true; |
| 93 // copy constructor if only the right-hand side has a value. | |
| 94 Optional& operator=(const Optional& m) { | |
| 95 if (m.has_value_) { | |
| 96 if (has_value_) { | |
| 97 value_ = m.value_; // T's copy assignment. | |
| 98 } else { | |
| 99 new (&value_) T(m.value_); // T's copy constructor. | |
| 100 has_value_ = true; | |
| 101 } | |
| 102 } else if (has_value_) { | |
| 103 value_.~T(); | |
| 104 has_value_ = false; | |
| 105 } | |
| 106 return *this; | |
| 107 } | |
| 108 | |
| 109 // Move assignment. Uses T's move assignment if both sides have a value, T's | |
| 110 // move constructor if only the right-hand side has a value. The state of m | |
| 111 // after it's been moved from is as for the move constructor. | |
| 112 Optional& operator=(Optional&& m) { | |
| 113 if (m.has_value_) { | |
| 114 if (has_value_) { | |
| 115 value_ = std::move(m.value_); // T's move assignment. | |
| 116 } else { | |
| 117 new (&value_) T(std::move(m.value_)); // T's move constructor. | |
| 118 has_value_ = true; | |
| 119 } | |
| 120 } else if (has_value_) { | |
| 121 value_.~T(); | |
| 122 has_value_ = false; | |
| 123 } | |
| 124 return *this; | |
| 125 } | |
| 126 | |
| 127 // Swap the values if both m1 and m2 have values; move the value if only one | |
| 128 // of them has one. | |
| 129 friend void swap(Optional& m1, Optional& m2) { | |
| 130 if (m1.has_value_) { | |
| 131 if (m2.has_value_) { | |
| 132 // Both have values: swap. | |
| 133 using std::swap; | |
| 134 swap(m1.value_, m2.value_); | |
| 135 } else { | |
| 136 // Only m1 has a value: move it to m2. | |
| 137 new (&m2.value_) T(std::move(m1.value_)); | |
| 138 m1.value_.~T(); // Destroy the moved-from value. | |
| 139 m1.has_value_ = false; | |
| 140 m2.has_value_ = true; | |
| 141 } | |
| 142 } else if (m2.has_value_) { | |
| 143 // Only m2 has a value: move it to m1. | |
| 144 new (&m1.value_) T(std::move(m2.value_)); | |
| 145 m2.value_.~T(); // Destroy the moved-from value. | |
| 146 m1.has_value_ = true; | |
| 147 m2.has_value_ = false; | |
| 148 } | |
| 149 } | |
| 150 | |
| 151 // Conversion to bool to test if we have a value. | |
| 152 explicit operator bool() const { return has_value_; } | |
| 153 | |
| 154 // Dereferencing. Only allowed if we have a value. | |
| 155 const T* operator->() const { | |
| 156 RTC_DCHECK(has_value_); | |
| 157 return &value_; | |
| 158 } | |
| 159 T* operator->() { | |
| 160 RTC_DCHECK(has_value_); | |
| 161 return &value_; | |
| 162 } | |
| 163 const T& operator*() const { | |
| 164 RTC_DCHECK(has_value_); | |
| 165 return value_; | |
| 166 } | |
| 167 T& operator*() { | |
| 168 RTC_DCHECK(has_value_); | |
| 169 return value_; | |
| 170 } | |
| 171 | |
| 172 // Dereference with a default value in case we don't have a value. | |
| 173 const T& value_or(const T& default_val) const { | |
| 174 return has_value_ ? value_ : default_val; | |
| 175 } | |
| 176 | |
| 177 // Equality tests. Two Optionals are equal if they contain equivalent values, | |
| 178 // or | |
| 179 // if they're both empty. | |
| 180 friend bool operator==(const Optional& m1, const Optional& m2) { | |
| 181 return m1.has_value_ && m2.has_value_ ? m1.value_ == m2.value_ | |
| 182 : m1.has_value_ == m2.has_value_; | |
| 183 } | |
| 184 friend bool operator!=(const Optional& m1, const Optional& m2) { | |
| 185 return m1.has_value_ && m2.has_value_ ? m1.value_ != m2.value_ | |
| 186 : m1.has_value_ != m2.has_value_; | |
| 187 } | |
| 188 | |
| 189 private: | |
| 190 bool has_value_; // True iff value_ contains a live value. | |
| 191 union { | 46 union { |
| 192 // By placing value_ in a union, we get to manage its construction and | |
| 193 // destruction manually: the Optional constructors won't automatically | |
| 194 // construct it, and the Optional destructor won't automatically destroy | |
| 195 // it. Basically, this just allocates a properly sized and aligned block of | |
| 196 // memory in which we can manually put a T with placement new. | |
| 197 T value_; | 47 T value_; |
| 198 }; | 48 }; |
| 199 }; | 49 }; |
| 200 | 50 |
| 51 template <typename T> | |
| 52 struct OptionalStorage<T, true> { | |
| 53 OptionalStorage() {}; | |
| 54 // When T is trivially destructible (i.e. its destructor does nothing) | |
| 55 // there is no need to call it. | |
| 56 // Since |rtc::AlignedMemory| is just an array its destructor | |
| 57 // is trivial. Explicitly defaulting the destructor means it's not | |
| 58 // user-provided. All of this together make this destructor trivial. | |
| 59 ~OptionalStorage() = default; | |
| 60 | |
| 61 bool is_null_ = true; | |
| 62 union { | |
| 63 T value_; | |
| 64 }; | |
| 65 }; | |
| 66 | |
| 67 } // namespace internal | |
| 68 | |
| 69 // rtc::Optional has been borrowed from Chromium's base::Optional, with some | |
| 70 // alterations. It is a version of the C++17 optional class: | |
| 71 // std::optional documentation: | |
| 72 // http://en.cppreference.com/w/cpp/utility/optional Chromium documentation: | |
| 73 // https://chromium.googlesource.com/chromium/src/+/master/docs/optional.md | |
| 74 // | |
| 75 // These are the differences between the specification and the implementation: | |
| 76 // - The constructor and emplace method using initializer_list are not | |
| 77 // implemented because 'initializer_list' is banned from WebRTC. | |
| 78 // - Constructors do not use 'constexpr' as it is a C++14 extension. | |
| 79 // - 'constexpr' might be missing in some places for reasons specified locally. | |
| 80 // - No exceptions are thrown, because they are banned from WebRTC. | |
| 81 // - All the non-members are in the 'rtc' namespace instead of 'std'. | |
| 82 // | |
| 83 // The WebRTC version uses this one neat union trick to implement | |
| 84 // OptionalStorage rather than using Chromium's AlignedStorage. | |
| 85 template <typename T> | |
| 86 class Optional { | |
| 87 public: | |
| 88 using value_type = T; | |
| 89 | |
| 90 constexpr Optional() = default; | |
| 91 Optional(rtc::nullopt_t) : Optional() {} | |
| 92 | |
| 93 Optional(const Optional& other) { | |
| 94 if (!other.storage_.is_null_) | |
| 95 Init(other.value()); | |
| 96 } | |
| 97 | |
| 98 Optional(Optional&& other) { | |
| 99 if (!other.storage_.is_null_) | |
| 100 Init(std::move(other.value())); | |
| 101 } | |
| 102 | |
| 103 Optional(const T& value) { Init(value); } | |
| 104 | |
| 105 Optional(T&& value) { Init(std::move(value)); } | |
| 106 | |
| 107 template <class... Args> | |
| 108 explicit Optional(rtc::in_place_t, Args&&... args) { | |
| 109 emplace(std::forward<Args>(args)...); | |
| 110 } | |
| 111 | |
| 112 ~Optional() = default; | |
| 113 | |
| 114 Optional& operator=(rtc::nullopt_t) { | |
| 115 FreeIfNeeded(); | |
| 116 return *this; | |
| 117 } | |
| 118 | |
| 119 Optional& operator=(const Optional& other) { | |
| 120 if (other.storage_.is_null_) { | |
| 121 FreeIfNeeded(); | |
| 122 return *this; | |
| 123 } | |
| 124 | |
| 125 InitOrAssign(other.value()); | |
| 126 return *this; | |
| 127 } | |
| 128 | |
| 129 Optional& operator=(Optional&& other) { | |
| 130 if (other.storage_.is_null_) { | |
| 131 FreeIfNeeded(); | |
| 132 return *this; | |
| 133 } | |
| 134 | |
| 135 InitOrAssign(std::move(other.value())); | |
| 136 return *this; | |
| 137 } | |
| 138 | |
| 139 template <class U> | |
| 140 typename std::enable_if<std::is_same<std::decay<U>, T>::value, | |
| 141 Optional&>::type | |
| 142 operator=(U&& value) { | |
| 143 InitOrAssign(std::forward<U>(value)); | |
| 144 return *this; | |
| 145 } | |
| 146 | |
| 147 // TODO(mlamouri): can't use 'constexpr' with RTC_DCHECK. | |
| 148 const T* operator->() const { | |
| 149 RTC_DCHECK(!storage_.is_null_); | |
| 150 return &value(); | |
| 151 } | |
| 152 | |
| 153 // TODO(mlamouri): using 'constexpr' here breaks compiler that assume it was | |
| 154 // meant to be 'constexpr const'. | |
| 155 T* operator->() { | |
| 156 RTC_DCHECK(!storage_.is_null_); | |
| 157 return &value(); | |
| 158 } | |
| 159 | |
| 160 constexpr const T& operator*() const& { return value(); } | |
| 161 | |
| 162 // TODO(mlamouri): using 'constexpr' here breaks compiler that assume it was | |
| 163 // meant to be 'constexpr const'. | |
| 164 T& operator*() & { return value(); } | |
| 165 | |
| 166 constexpr const T&& operator*() const&& { return std::move(value()); } | |
| 167 | |
| 168 // TODO(mlamouri): using 'constexpr' here breaks compiler that assume it was | |
| 169 // meant to be 'constexpr const'. | |
| 170 T&& operator*() && { return std::move(value()); } | |
| 171 | |
| 172 constexpr explicit operator bool() const { return !storage_.is_null_; } | |
| 173 | |
| 174 // TODO(mlamouri): using 'constexpr' here breaks compiler that assume it was | |
| 175 // meant to be 'constexpr const'. | |
| 176 T& value() & { | |
| 177 RTC_DCHECK(!storage_.is_null_); | |
| 178 return storage_.value_; | |
| 179 } | |
| 180 | |
| 181 // TODO(mlamouri): can't use 'constexpr' with RTC_DCHECK. | |
| 182 const T& value() const& { | |
| 183 RTC_DCHECK(!storage_.is_null_); | |
| 184 return storage_.value_; | |
| 185 } | |
| 186 | |
| 187 // TODO(mlamouri): using 'constexpr' here breaks compiler that assume it was | |
| 188 // meant to be 'constexpr const'. | |
| 189 T&& value() && { | |
| 190 RTC_DCHECK(!storage_.is_null_); | |
| 191 return std::move(storage_.value_); | |
| 192 } | |
| 193 | |
| 194 // TODO(mlamouri): can't use 'constexpr' with RTC_DCHECK. | |
| 195 const T&& value() const&& { | |
| 196 RTC_DCHECK(!storage_.is_null_); | |
| 197 return std::move(storage_.value_); | |
| 198 } | |
| 199 | |
| 200 template <class U> | |
| 201 constexpr T value_or(U&& default_value) const& { | |
| 202 // TODO(mlamouri): add the following assert when possible: | |
| 203 // static_assert(std::is_copy_constructible<T>::value, | |
| 204 // "T must be copy constructible"); | |
| 205 static_assert(std::is_convertible<U, T>::value, | |
| 206 "U must be convertible to T"); | |
| 207 return storage_.is_null_ ? static_cast<T>(std::forward<U>(default_value)) | |
| 208 : value(); | |
| 209 } | |
| 210 | |
| 211 template <class U> | |
| 212 T value_or(U&& default_value) && { | |
| 213 // TODO(mlamouri): add the following assert when possible: | |
| 214 // static_assert(std::is_move_constructible<T>::value, | |
| 215 // "T must be move constructible"); | |
| 216 static_assert(std::is_convertible<U, T>::value, | |
| 217 "U must be convertible to T"); | |
| 218 return storage_.is_null_ ? static_cast<T>(std::forward<U>(default_value)) | |
| 219 : std::move(value()); | |
| 220 } | |
| 221 | |
| 222 void swap(Optional& other) { | |
| 223 if (storage_.is_null_ && other.storage_.is_null_) | |
| 224 return; | |
| 225 | |
| 226 if (storage_.is_null_ != other.storage_.is_null_) { | |
| 227 if (storage_.is_null_) { | |
| 228 Init(std::move(other.storage_.value_)); | |
| 229 other.FreeIfNeeded(); | |
| 230 } else { | |
| 231 other.Init(std::move(storage_.value_)); | |
| 232 FreeIfNeeded(); | |
| 233 } | |
| 234 return; | |
| 235 } | |
| 236 | |
| 237 RTC_DCHECK(!storage_.is_null_ && !other.storage_.is_null_); | |
| 238 using std::swap; | |
| 239 swap(**this, *other); | |
| 240 } | |
| 241 | |
| 242 template <class... Args> | |
| 243 void emplace(Args&&... args) { | |
| 244 FreeIfNeeded(); | |
| 245 Init(std::forward<Args>(args)...); | |
| 246 } | |
| 247 | |
| 248 private: | |
| 249 void Init(const T& value) { | |
| 250 RTC_DCHECK(storage_.is_null_); | |
| 251 new (&storage_.value_) T(value); | |
| 252 storage_.is_null_ = false; | |
| 253 } | |
| 254 | |
| 255 void Init(T&& value) { | |
| 256 RTC_DCHECK(storage_.is_null_); | |
| 257 new (&storage_.value_) T(std::move(value)); | |
| 258 storage_.is_null_ = false; | |
| 259 } | |
| 260 | |
| 261 template <class... Args> | |
| 262 void Init(Args&&... args) { | |
| 263 RTC_DCHECK(storage_.is_null_); | |
| 264 new (&storage_.value_) T(std::forward<Args>(args)...); | |
| 265 storage_.is_null_ = false; | |
| 266 } | |
| 267 | |
| 268 void InitOrAssign(const T& value) { | |
| 269 if (storage_.is_null_) | |
| 270 Init(value); | |
| 271 else | |
| 272 storage_.value_ = value; | |
| 273 } | |
| 274 | |
| 275 void InitOrAssign(T&& value) { | |
| 276 if (storage_.is_null_) | |
| 277 Init(std::move(value)); | |
| 278 else | |
| 279 storage_.value_ = std::move(value); | |
| 280 } | |
| 281 | |
| 282 void FreeIfNeeded() { | |
| 283 if (storage_.is_null_) | |
| 284 return; | |
| 285 storage_.value_.~T(); | |
| 286 storage_.is_null_ = true; | |
| 287 } | |
| 288 | |
| 289 internal::OptionalStorage<T> storage_; | |
| 290 }; | |
| 291 | |
| 292 template <class T> | |
| 293 constexpr bool operator==(const Optional<T>& lhs, const Optional<T>& rhs) { | |
| 294 return !!lhs != !!rhs ? false : lhs == nullopt || (*lhs == *rhs); | |
| 295 } | |
| 296 | |
| 297 template <class T> | |
| 298 constexpr bool operator!=(const Optional<T>& lhs, const Optional<T>& rhs) { | |
| 299 return !(lhs == rhs); | |
| 300 } | |
| 301 | |
| 302 template <class T> | |
| 303 constexpr bool operator<(const Optional<T>& lhs, const Optional<T>& rhs) { | |
| 304 return rhs == nullopt ? false : (lhs == nullopt ? true : *lhs < *rhs); | |
| 305 } | |
| 306 | |
| 307 template <class T> | |
| 308 constexpr bool operator<=(const Optional<T>& lhs, const Optional<T>& rhs) { | |
| 309 return !(rhs < lhs); | |
| 310 } | |
| 311 | |
| 312 template <class T> | |
| 313 constexpr bool operator>(const Optional<T>& lhs, const Optional<T>& rhs) { | |
| 314 return rhs < lhs; | |
| 315 } | |
| 316 | |
| 317 template <class T> | |
| 318 constexpr bool operator>=(const Optional<T>& lhs, const Optional<T>& rhs) { | |
| 319 return !(lhs < rhs); | |
| 320 } | |
| 321 | |
| 322 template <class T> | |
| 323 constexpr bool operator==(const Optional<T>& opt, rtc::nullopt_t) { | |
| 324 return !opt; | |
| 325 } | |
| 326 | |
| 327 template <class T> | |
| 328 constexpr bool operator==(rtc::nullopt_t, const Optional<T>& opt) { | |
| 329 return !opt; | |
| 330 } | |
| 331 | |
| 332 template <class T> | |
| 333 constexpr bool operator!=(const Optional<T>& opt, rtc::nullopt_t) { | |
| 334 return !!opt; | |
| 335 } | |
| 336 | |
| 337 template <class T> | |
| 338 constexpr bool operator!=(rtc::nullopt_t, const Optional<T>& opt) { | |
| 339 return !!opt; | |
| 340 } | |
| 341 | |
| 342 template <class T> | |
| 343 constexpr bool operator<(const Optional<T>& opt, rtc::nullopt_t) { | |
| 344 return false; | |
| 345 } | |
| 346 | |
| 347 template <class T> | |
| 348 constexpr bool operator<(rtc::nullopt_t, const Optional<T>& opt) { | |
| 349 return !!opt; | |
| 350 } | |
| 351 | |
| 352 template <class T> | |
| 353 constexpr bool operator<=(const Optional<T>& opt, rtc::nullopt_t) { | |
| 354 return !opt; | |
| 355 } | |
| 356 | |
| 357 template <class T> | |
| 358 constexpr bool operator<=(rtc::nullopt_t, const Optional<T>& opt) { | |
| 359 return true; | |
| 360 } | |
| 361 | |
| 362 template <class T> | |
| 363 constexpr bool operator>(const Optional<T>& opt, rtc::nullopt_t) { | |
| 364 return !!opt; | |
| 365 } | |
| 366 | |
| 367 template <class T> | |
| 368 constexpr bool operator>(rtc::nullopt_t, const Optional<T>& opt) { | |
| 369 return false; | |
| 370 } | |
| 371 | |
| 372 template <class T> | |
| 373 constexpr bool operator>=(const Optional<T>& opt, rtc::nullopt_t) { | |
| 374 return true; | |
| 375 } | |
| 376 | |
| 377 template <class T> | |
| 378 constexpr bool operator>=(rtc::nullopt_t, const Optional<T>& opt) { | |
| 379 return !opt; | |
| 380 } | |
| 381 | |
| 382 template <class T> | |
| 383 constexpr bool operator==(const Optional<T>& opt, const T& value) { | |
| 384 return opt != nullopt ? *opt == value : false; | |
| 385 } | |
| 386 | |
| 387 template <class T> | |
| 388 constexpr bool operator==(const T& value, const Optional<T>& opt) { | |
| 389 return opt == value; | |
| 390 } | |
| 391 | |
| 392 template <class T> | |
| 393 constexpr bool operator!=(const Optional<T>& opt, const T& value) { | |
| 394 return !(opt == value); | |
| 395 } | |
| 396 | |
| 397 template <class T> | |
| 398 constexpr bool operator!=(const T& value, const Optional<T>& opt) { | |
| 399 return !(opt == value); | |
| 400 } | |
| 401 | |
| 402 template <class T> | |
| 403 constexpr bool operator<(const Optional<T>& opt, const T& value) { | |
| 404 return opt != nullopt ? *opt < value : true; | |
| 405 } | |
| 406 | |
| 407 template <class T> | |
| 408 constexpr bool operator<(const T& value, const Optional<T>& opt) { | |
| 409 return opt != nullopt ? value < *opt : false; | |
| 410 } | |
| 411 | |
| 412 template <class T> | |
| 413 constexpr bool operator<=(const Optional<T>& opt, const T& value) { | |
| 414 return !(opt > value); | |
| 415 } | |
| 416 | |
| 417 template <class T> | |
| 418 constexpr bool operator<=(const T& value, const Optional<T>& opt) { | |
| 419 return !(value > opt); | |
| 420 } | |
| 421 | |
| 422 template <class T> | |
| 423 constexpr bool operator>(const Optional<T>& opt, const T& value) { | |
| 424 return value < opt; | |
| 425 } | |
| 426 | |
| 427 template <class T> | |
| 428 constexpr bool operator>(const T& value, const Optional<T>& opt) { | |
| 429 return opt < value; | |
| 430 } | |
| 431 | |
| 432 template <class T> | |
| 433 constexpr bool operator>=(const Optional<T>& opt, const T& value) { | |
| 434 return !(opt < value); | |
| 435 } | |
| 436 | |
| 437 template <class T> | |
| 438 constexpr bool operator>=(const T& value, const Optional<T>& opt) { | |
| 439 return !(value < opt); | |
| 440 } | |
| 441 | |
| 442 template <class T> | |
| 443 constexpr Optional<typename std::decay<T>::type> make_optional(T&& value) { | |
| 444 return Optional<typename std::decay<T>::type>(std::forward<T>(value)); | |
| 445 } | |
| 446 | |
| 447 template <class T> | |
| 448 void swap(Optional<T>& lhs, Optional<T>& rhs) { | |
| 449 lhs.swap(rhs); | |
| 450 } | |
| 451 | |
| 201 } // namespace rtc | 452 } // namespace rtc |
| 202 | 453 |
| 454 namespace std { | |
| 455 | |
| 456 template <class T> | |
| 457 struct hash<rtc::Optional<T>> { | |
| 458 size_t operator()(const rtc::Optional<T>& opt) const { | |
| 459 return opt == rtc::nullopt ? 0 : std::hash<T>()(*opt); | |
| 460 } | |
| 461 }; | |
| 462 | |
| 463 } // namespace std | |
| 464 | |
| 203 #endif // WEBRTC_BASE_OPTIONAL_H_ | 465 #endif // WEBRTC_BASE_OPTIONAL_H_ |
| OLD | NEW |