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