1 /* 2 * Copyright 2021 Google LLC. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #ifndef SkTOptional_DEFINED 9 #define SkTOptional_DEFINED 10 11 #include "include/core/SkTypes.h" 12 13 #include <utility> 14 15 namespace skstd { 16 17 /** 18 * An empty optional is represented with `nullopt`. 19 */ 20 struct nullopt_t { 21 struct tag {}; 22 23 // nullopt_t must not be default-constructible. nullopt_tnullopt_t24 explicit constexpr nullopt_t(tag) {} 25 }; 26 27 static constexpr nullopt_t nullopt{nullopt_t::tag{}}; 28 29 /** 30 * Simple drop-in replacement for std::optional until we move to C++17. This does not have all of 31 * std::optional's capabilities, but it covers our needs for the time being. 32 */ 33 template<typename T> 34 class optional { 35 public: optional(const T & value)36 optional(const T& value) 37 : fHasValue(true) { 38 new(&fPayload.fValue) T(value); 39 } 40 optional(T && value)41 optional(T&& value) 42 : fHasValue(true) { 43 new(&fPayload.fValue) T(std::move(value)); 44 } 45 optional()46 optional() {} 47 optional(const optional & other)48 optional(const optional& other) { 49 *this = other; 50 } 51 52 // Construction with nullopt is the same as default construction. optional(nullopt_t)53 optional(nullopt_t) : optional() {} 54 55 // We need a non-const copy constructor because otherwise optional(nonConstSrc) isn't an exact 56 // match for the copy constructor, and we'd end up invoking the Args&&... template by mistake. optional(optional & other)57 optional(optional& other) { 58 *this = other; 59 } 60 optional(optional && other)61 optional(optional&& other) { 62 *this = std::move(other); 63 } 64 65 template<typename... Args> optional(Args &&...args)66 optional(Args&&... args) { 67 fHasValue = true; 68 new(&fPayload.fValue) T(std::forward<Args>(args)...); 69 } 70 ~optional()71 ~optional() { 72 this->reset(); 73 } 74 75 optional& operator=(const optional& other) { 76 if (this != &other) { 77 if (fHasValue) { 78 if (other.fHasValue) { 79 fPayload.fValue = other.fPayload.fValue; 80 } else { 81 this->reset(); 82 } 83 } else { 84 if (other.fHasValue) { 85 fHasValue = true; 86 new (&fPayload.fValue) T(other.fPayload.fValue); 87 } else { 88 // do nothing, no value on either side 89 } 90 } 91 } 92 return *this; 93 } 94 95 optional& operator=(optional&& other) { 96 if (this != &other) { 97 if (fHasValue) { 98 if (other.fHasValue) { 99 fPayload.fValue = std::move(other.fPayload.fValue); 100 } else { 101 this->reset(); 102 } 103 } else { 104 if (other.fHasValue) { 105 fHasValue = true; 106 new (&fPayload.fValue) T(std::move(other.fPayload.fValue)); 107 } else { 108 // do nothing, no value on either side 109 } 110 } 111 } 112 return *this; 113 } 114 115 template<typename... Args> emplace(Args &&...args)116 optional& emplace(Args&&... args) { 117 this->reset(); 118 fHasValue = true; 119 new(&fPayload.fValue) T(std::forward<Args>(args)...); 120 return *this; 121 } 122 123 template<typename U, typename... Args> emplace(std::initializer_list<U> il,Args &&...args)124 optional& emplace(std::initializer_list<U> il, Args&&... args) { 125 this->reset(); 126 fHasValue = true; 127 new(&fPayload.fValue) T(il, std::forward<Args>(args)...); 128 return *this; 129 } 130 131 // Assignment to nullopt is the same as reset(). 132 optional& operator=(nullopt_t) { 133 this->reset(); 134 return *this; 135 } 136 137 T& operator*() & { 138 SkASSERT(fHasValue); 139 return fPayload.fValue; 140 } 141 142 const T& operator*() const& { 143 SkASSERT(fHasValue); 144 return fPayload.fValue; 145 } 146 147 T&& operator*() && { 148 SkASSERT(fHasValue); 149 return std::move(fPayload.fValue); 150 } 151 152 const T&& operator*() const&& { 153 SkASSERT(fHasValue); 154 return std::move(fPayload.fValue); 155 } 156 value()157 const T& value() const& { 158 SkASSERT_RELEASE(fHasValue); 159 return **this; 160 } 161 value()162 T& value() & { 163 SkASSERT_RELEASE(fHasValue); 164 return **this; 165 } 166 value()167 const T&& value() const&& { 168 SkASSERT_RELEASE(fHasValue); 169 return std::move(**this); 170 } 171 value()172 T&& value() && { 173 SkASSERT_RELEASE(fHasValue); 174 return std::move(**this); 175 } 176 177 T* operator->() { 178 return &**this; 179 } 180 181 const T* operator->() const { 182 return &**this; 183 } 184 185 template<typename U> value_or(U && value)186 T value_or(U&& value) const& { 187 return this->has_value() ? **this : static_cast<T>(std::forward<U>(value)); 188 } 189 190 template<typename U> value_or(U && value)191 T value_or(U&& value) && { 192 return this->has_value() ? std::move(**this) : static_cast<T>(std::forward<U>(value)); 193 } 194 has_value()195 bool has_value() const { 196 return fHasValue; 197 } 198 199 explicit operator bool() const { 200 return this->has_value(); 201 } 202 reset()203 void reset() { 204 if (fHasValue) { 205 fPayload.fValue.~T(); 206 fHasValue = false; 207 } 208 } 209 210 private: 211 union Payload { 212 T fValue; 213 Payload()214 Payload() {} 215 ~Payload()216 ~Payload() {} 217 } fPayload; 218 219 bool fHasValue = false; 220 }; 221 222 // Comparison operators for optional x optional 223 template <typename T, typename U> bool operator==(const optional<T>& a, const optional<U>& b) { 224 return (a.has_value() != b.has_value()) ? false : 225 !a.has_value() ? true : 226 (*a == *b); 227 } 228 229 template <typename T, typename U> bool operator!=(const optional<T>& a, const optional<U>& b) { 230 return (a.has_value() != b.has_value()) ? true : 231 !a.has_value() ? false : 232 (*a != *b); 233 } 234 235 template <typename T, typename U> bool operator<(const optional<T>& a, const optional<U>& b) { 236 return !b.has_value() ? false : 237 !a.has_value() ? true : 238 (*a < *b); 239 } 240 241 template <typename T, typename U> bool operator<=(const optional<T>& a, const optional<U>& b) { 242 return !a.has_value() ? true : 243 !b.has_value() ? false : 244 (*a <= *b); 245 } 246 247 template <typename T, typename U> bool operator>(const optional<T>& a, const optional<U>& b) { 248 return !a.has_value() ? false : 249 !b.has_value() ? true : 250 (*a > *b); 251 } 252 253 template <typename T, typename U> bool operator>=(const optional<T>& a, const optional<U>& b) { 254 return !b.has_value() ? true : 255 !a.has_value() ? false : 256 (*a >= *b); 257 } 258 259 // Comparison operators for optional x nullopt 260 template <typename T> bool operator==(const optional<T>& a, nullopt_t) { 261 return !a.has_value(); 262 } 263 264 template <typename T> bool operator!=(const optional<T>& a, nullopt_t) { 265 return a.has_value(); 266 } 267 268 template <typename T> bool operator<(const optional<T>&, nullopt_t) { 269 return false; 270 } 271 272 template <typename T> bool operator<=(const optional<T>& a, nullopt_t) { 273 return !a.has_value(); 274 } 275 276 template <typename T> bool operator>(const optional<T>& a, nullopt_t) { 277 return a.has_value(); 278 } 279 280 template <typename T> 281 bool operator>=(const optional<T>&, nullopt_t) { 282 return true; 283 } 284 285 // Comparison operators for nullopt x optional 286 template <typename U> bool operator==(nullopt_t, const optional<U>& b) { 287 return !b.has_value(); 288 } 289 290 template <typename U> bool operator!=(nullopt_t, const optional<U>& b) { 291 return b.has_value(); 292 } 293 294 template <typename U> bool operator<(nullopt_t, const optional<U>& b) { 295 return b.has_value(); 296 } 297 298 template <typename U> bool operator<=(nullopt_t, const optional<U>&) { 299 return true; 300 } 301 302 template <typename U> bool operator>(nullopt_t, const optional<U>&) { 303 return false; 304 } 305 306 template <typename U> bool operator>=(nullopt_t, const optional<U>& b) { 307 return !b.has_value(); 308 } 309 310 // Comparison operators for optional x value 311 template <typename T, typename U> bool operator==(const optional<T>& a, const U& b) { 312 return a.has_value() && (*a == b); 313 } 314 315 template <typename T, typename U> bool operator!=(const optional<T>& a, const U& b) { 316 return !a.has_value() || (*a != b); 317 } 318 319 template <typename T, typename U> bool operator<(const optional<T>& a, const U& b) { 320 return !a.has_value() || (*a < b); 321 } 322 323 template <typename T, typename U> bool operator<=(const optional<T>& a, const U& b) { 324 return !a.has_value() || (*a <= b); 325 } 326 327 template <typename T, typename U> bool operator>(const optional<T>& a, const U& b) { 328 return a.has_value() && (*a > b); 329 } 330 331 template <typename T, typename U> bool operator>=(const optional<T>& a, const U& b) { 332 return a.has_value() && (*a >= b); 333 } 334 335 // Comparison operators for value x optional 336 template <typename T, typename U> bool operator==(const T& a, const optional<U>& b) { 337 return b.has_value() && (a == *b); 338 } 339 340 template <typename T, typename U> bool operator!=(const T& a, const optional<U>& b) { 341 return !b.has_value() || (a != *b); 342 } 343 344 template <typename T, typename U> bool operator<(const T& a, const optional<U>& b) { 345 return b.has_value() && (a < *b); 346 } 347 348 template <typename T, typename U> bool operator<=(const T& a, const optional<U>& b) { 349 return b.has_value() && (a <= *b); 350 } 351 352 template <typename T, typename U> bool operator>(const T& a, const optional<U>& b) { 353 return !b.has_value() || (a > *b); 354 } 355 356 template <typename T, typename U> bool operator>=(const T& a, const optional<U>& b) { 357 return !b.has_value() || (a >= *b); 358 } 359 360 } // namespace skstd 361 362 #endif 363