Home | History | Annotate | Download | only in aapt2
      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