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