1 /* 2 * Copyright (C) 2015 The Android Open Source Project 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 AAPT_MAYBE_H 18 #define AAPT_MAYBE_H 19 20 #include <type_traits> 21 #include <utility> 22 23 #include "android-base/logging.h" 24 25 #include "util/TypeTraits.h" 26 27 namespace aapt { 28 29 /** 30 * Either holds a valid value of type T, or holds Nothing. 31 * The value is stored inline in this structure, so no 32 * heap memory is used when creating a Maybe<T> object. 33 */ 34 template <typename T> 35 class Maybe { 36 public: 37 /** 38 * Construct Nothing. 39 */ 40 Maybe(); 41 42 ~Maybe(); 43 44 Maybe(const Maybe& rhs); 45 46 template <typename U> 47 Maybe(const Maybe<U>& rhs); // NOLINT(google-explicit-constructor) 48 49 Maybe(Maybe&& rhs) noexcept; 50 51 template <typename U> 52 Maybe(Maybe<U>&& rhs); // NOLINT(google-explicit-constructor) 53 54 Maybe& operator=(const Maybe& rhs); 55 56 template <typename U> 57 Maybe& operator=(const Maybe<U>& rhs); 58 59 Maybe& operator=(Maybe&& rhs) noexcept; 60 61 template <typename U> 62 Maybe& operator=(Maybe<U>&& rhs); 63 64 /** 65 * Construct a Maybe holding a value. 66 */ 67 Maybe(const T& value); // NOLINT(google-explicit-constructor) 68 69 /** 70 * Construct a Maybe holding a value. 71 */ 72 Maybe(T&& value); // NOLINT(google-explicit-constructor) 73 74 /** 75 * True if this holds a value, false if 76 * it holds Nothing. 77 */ 78 explicit operator bool() const; 79 80 /** 81 * Gets the value if one exists, or else 82 * panics. 83 */ 84 T& value(); 85 86 /** 87 * Gets the value if one exists, or else 88 * panics. 89 */ 90 const T& value() const; 91 92 T value_or_default(const T& def) const; 93 94 private: 95 template <typename U> 96 friend class Maybe; 97 98 template <typename U> 99 Maybe& copy(const Maybe<U>& rhs); 100 101 template <typename U> 102 Maybe& move(Maybe<U>&& rhs); 103 104 void destroy(); 105 106 bool nothing_; 107 108 typename std::aligned_storage<sizeof(T), alignof(T)>::type storage_; 109 }; 110 111 template <typename T> 112 Maybe<T>::Maybe() : nothing_(true) {} 113 114 template <typename T> 115 Maybe<T>::~Maybe() { 116 if (!nothing_) { 117 destroy(); 118 } 119 } 120 121 template <typename T> 122 Maybe<T>::Maybe(const Maybe& rhs) : nothing_(rhs.nothing_) { 123 if (!rhs.nothing_) { 124 new (&storage_) T(reinterpret_cast<const T&>(rhs.storage_)); 125 } 126 } 127 128 template <typename T> 129 template <typename U> 130 Maybe<T>::Maybe(const Maybe<U>& rhs) : nothing_(rhs.nothing_) { 131 if (!rhs.nothing_) { 132 new (&storage_) T(reinterpret_cast<const U&>(rhs.storage_)); 133 } 134 } 135 136 template <typename T> 137 Maybe<T>::Maybe(Maybe&& rhs) noexcept : nothing_(rhs.nothing_) { 138 if (!rhs.nothing_) { 139 rhs.nothing_ = true; 140 141 // Move the value from rhs. 142 new (&storage_) T(std::move(reinterpret_cast<T&>(rhs.storage_))); 143 rhs.destroy(); 144 } 145 } 146 147 template <typename T> 148 template <typename U> 149 Maybe<T>::Maybe(Maybe<U>&& rhs) : nothing_(rhs.nothing_) { 150 if (!rhs.nothing_) { 151 rhs.nothing_ = true; 152 153 // Move the value from rhs. 154 new (&storage_) T(std::move(reinterpret_cast<U&>(rhs.storage_))); 155 rhs.destroy(); 156 } 157 } 158 159 template <typename T> 160 inline Maybe<T>& Maybe<T>::operator=(const Maybe& rhs) { 161 // Delegate to the actual assignment. 162 return copy(rhs); 163 } 164 165 template <typename T> 166 template <typename U> 167 inline Maybe<T>& Maybe<T>::operator=(const Maybe<U>& rhs) { 168 return copy(rhs); 169 } 170 171 template <typename T> 172 template <typename U> 173 Maybe<T>& Maybe<T>::copy(const Maybe<U>& rhs) { 174 if (nothing_ && rhs.nothing_) { 175 // Both are nothing, nothing to do. 176 return *this; 177 } else if (!nothing_ && !rhs.nothing_) { 178 // We both are something, so assign rhs to us. 179 reinterpret_cast<T&>(storage_) = reinterpret_cast<const U&>(rhs.storage_); 180 } else if (nothing_) { 181 // We are nothing but rhs is something. 182 nothing_ = rhs.nothing_; 183 184 // Copy the value from rhs. 185 new (&storage_) T(reinterpret_cast<const U&>(rhs.storage_)); 186 } else { 187 // We are something but rhs is nothing, so destroy our value. 188 nothing_ = rhs.nothing_; 189 destroy(); 190 } 191 return *this; 192 } 193 194 template <typename T> 195 inline Maybe<T>& Maybe<T>::operator=(Maybe&& rhs) noexcept { 196 // Delegate to the actual assignment. 197 return move(std::forward<Maybe<T>>(rhs)); 198 } 199 200 template <typename T> 201 template <typename U> 202 inline Maybe<T>& Maybe<T>::operator=(Maybe<U>&& rhs) { 203 return move(std::forward<Maybe<U>>(rhs)); 204 } 205 206 template <typename T> 207 template <typename U> 208 Maybe<T>& Maybe<T>::move(Maybe<U>&& rhs) { 209 if (nothing_ && rhs.nothing_) { 210 // Both are nothing, nothing to do. 211 return *this; 212 } else if (!nothing_ && !rhs.nothing_) { 213 // We both are something, so move assign rhs to us. 214 rhs.nothing_ = true; 215 reinterpret_cast<T&>(storage_) = 216 std::move(reinterpret_cast<U&>(rhs.storage_)); 217 rhs.destroy(); 218 } else if (nothing_) { 219 // We are nothing but rhs is something. 220 nothing_ = false; 221 rhs.nothing_ = true; 222 223 // Move the value from rhs. 224 new (&storage_) T(std::move(reinterpret_cast<U&>(rhs.storage_))); 225 rhs.destroy(); 226 } else { 227 // We are something but rhs is nothing, so destroy our value. 228 nothing_ = true; 229 destroy(); 230 } 231 return *this; 232 } 233 234 template <typename T> 235 Maybe<T>::Maybe(const T& value) : nothing_(false) { 236 new (&storage_) T(value); 237 } 238 239 template <typename T> 240 Maybe<T>::Maybe(T&& value) : nothing_(false) { 241 new (&storage_) T(std::forward<T>(value)); 242 } 243 244 template <typename T> 245 Maybe<T>::operator bool() const { 246 return !nothing_; 247 } 248 249 template <typename T> 250 T& Maybe<T>::value() { 251 CHECK(!nothing_) << "Maybe<T>::value() called on Nothing"; 252 return reinterpret_cast<T&>(storage_); 253 } 254 255 template <typename T> 256 const T& Maybe<T>::value() const { 257 CHECK(!nothing_) << "Maybe<T>::value() called on Nothing"; 258 return reinterpret_cast<const T&>(storage_); 259 } 260 261 template <typename T> 262 T Maybe<T>::value_or_default(const T& def) const { 263 if (nothing_) { 264 return def; 265 } 266 return reinterpret_cast<const T&>(storage_); 267 } 268 269 template <typename T> 270 void Maybe<T>::destroy() { 271 reinterpret_cast<T&>(storage_).~T(); 272 } 273 274 template <typename T> 275 inline Maybe<typename std::remove_reference<T>::type> make_value(T&& value) { 276 return Maybe<typename std::remove_reference<T>::type>(std::forward<T>(value)); 277 } 278 279 template <typename T> 280 inline Maybe<T> make_nothing() { 281 return Maybe<T>(); 282 } 283 284 // Define the == operator between Maybe<T> and Maybe<U> only if the operator T == U is defined. 285 // That way the compiler will show an error at the callsite when comparing two Maybe<> objects 286 // whose inner types can't be compared. 287 template <typename T, typename U> 288 typename std::enable_if<has_eq_op<T, U>::value, bool>::type operator==(const Maybe<T>& a, 289 const Maybe<U>& b) { 290 if (a && b) { 291 return a.value() == b.value(); 292 } else if (!a && !b) { 293 return true; 294 } 295 return false; 296 } 297 298 template <typename T, typename U> 299 typename std::enable_if<has_eq_op<T, U>::value, bool>::type operator==(const Maybe<T>& a, 300 const U& b) { 301 return a ? a.value() == b : false; 302 } 303 304 // Same as operator== but negated. 305 template <typename T, typename U> 306 typename std::enable_if<has_eq_op<T, U>::value, bool>::type operator!=(const Maybe<T>& a, 307 const Maybe<U>& b) { 308 return !(a == b); 309 } 310 311 template <typename T, typename U> 312 typename std::enable_if<has_lt_op<T, U>::value, bool>::type operator<(const Maybe<T>& a, 313 const Maybe<U>& b) { 314 if (a && b) { 315 return a.value() < b.value(); 316 } else if (!a && !b) { 317 return false; 318 } 319 return !a; 320 } 321 322 } // namespace aapt 323 324 #endif // AAPT_MAYBE_H 325