Home | History | Annotate | Download | only in util
      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(implicit)
     48 
     49   Maybe(Maybe&& rhs);
     50 
     51   template <typename U>
     52   Maybe(Maybe<U>&& rhs);  // NOLINT(implicit)
     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);
     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(implicit)
     68 
     69   /**
     70    * Construct a Maybe holding a value.
     71    */
     72   Maybe(T&& value);  // NOLINT(implicit)
     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) : 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) {
    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