Stefan Scholz / ETL
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers optional.h Source File

optional.h

Go to the documentation of this file.
00001 ///\file
00002 
00003 /******************************************************************************
00004 The MIT License(MIT)
00005 
00006 Embedded Template Library.
00007 https://github.com/ETLCPP/etl
00008 http://www.etlcpp.com
00009 
00010 Copyright(c) 2015 jwellbelove
00011 
00012 Permission is hereby granted, free of charge, to any person obtaining a copy
00013 of this software and associated documentation files(the "Software"), to deal
00014 in the Software without restriction, including without limitation the rights
00015 to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
00016 copies of the Software, and to permit persons to whom the Software is
00017 furnished to do so, subject to the following conditions :
00018 
00019 The above copyright notice and this permission notice shall be included in all
00020 copies or substantial portions of the Software.
00021 
00022 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00023 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00024 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
00025 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00026 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00027 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
00028 SOFTWARE.
00029 ******************************************************************************/
00030 
00031 #ifndef __ETL_OPTIONAL__
00032 #define __ETL_OPTIONAL__
00033 
00034 #include "platform.h "
00035 #include "alignment.h "
00036 #include "type_traits.h "
00037 #include "exception.h "
00038 #include "error_handler.h "
00039 
00040 namespace etl
00041 {
00042   //*****************************************************************************
00043   /// A null option type.
00044   ///\ingroup utilities
00045   //*****************************************************************************
00046   class nullopt_t
00047   {
00048   public:
00049 
00050     // Convertible to any type of null non-member pointer.
00051     template<class T>
00052     operator T*() const
00053     {
00054       return 0;
00055     }
00056 
00057   private:
00058 
00059     // Can't take address of nullopt.
00060     void operator&() const;
00061   };
00062 
00063   //*****************************************************************************
00064   /// A null option.
00065   ///\ingroup utilities
00066   //*****************************************************************************
00067   const nullopt_t nullopt = {};
00068 
00069   //***************************************************************************
00070   /// Exception for optional.
00071   ///\ingroup list
00072   //***************************************************************************
00073   class optional_exception : public exception
00074   {
00075   public:
00076 
00077     optional_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
00078       : exception(reason_, file_name_, line_number_)
00079     {
00080     }
00081   };
00082 
00083   //***************************************************************************
00084   /// Invalid exception for optional.
00085   ///\ingroup list
00086   //***************************************************************************
00087   class optional_invalid : public optional_exception
00088   {
00089   public:
00090 
00091     optional_invalid(string_type file_name_, numeric_type line_number_)
00092       : optional_exception("optional: invalid", file_name_, line_number_)
00093     {
00094     }
00095   };
00096 
00097   //*****************************************************************************
00098   /// An optional type.
00099   /// If the optional type is not initialised then a type is not constructed.
00100   ///\tparam The type to store.
00101   ///\ingroup utilities
00102   //*****************************************************************************
00103   template <typename T>
00104   class optional
00105   {
00106   public:
00107 
00108     //***************************************************************************
00109     /// Constructor.
00110     //***************************************************************************
00111     optional()
00112       : valid(false)
00113     {
00114     }
00115 
00116     //***************************************************************************
00117     /// Constructor with nullopt.
00118     //***************************************************************************
00119     optional(etl::nullopt_t)
00120       : valid(false)
00121     {
00122     }
00123 
00124     //***************************************************************************
00125     /// Copy constructor.
00126     //***************************************************************************
00127     optional(const optional& other)
00128       : valid(bool(other))
00129     {
00130       if (valid)
00131       {
00132        ::new (storage.template get_address<T>()) T(other.value());
00133       }
00134     }
00135 
00136     //***************************************************************************
00137     /// Constructor from value type.
00138     //***************************************************************************
00139     optional(const T& value_)
00140     {
00141      ::new (storage.template get_address<T>()) T(value_);
00142       valid = true;
00143     }
00144 
00145     //***************************************************************************
00146     /// Destructor.
00147     //***************************************************************************
00148     ~optional()
00149     {
00150       if (valid)
00151       {
00152         storage.template get_reference<T>().~T();
00153       }
00154     }
00155 
00156     //***************************************************************************
00157     /// Assignment operator from nullopt.
00158     //***************************************************************************
00159     optional& operator =(etl::nullopt_t)
00160     {
00161       if (valid)
00162       {
00163         storage.template get_reference<T>().~T();
00164         valid = false;
00165       }
00166 
00167       return *this;
00168     }
00169 
00170     //***************************************************************************
00171     /// Assignment operator from optional.
00172     //***************************************************************************
00173     optional& operator =(const optional& other)
00174     {
00175       if (this != &other)
00176       {
00177         if (valid && !bool(other))
00178         {
00179           storage.template get_reference<T>().~T();
00180           valid = false;
00181         }
00182         else if (bool(other))
00183         {
00184           if (valid)
00185           {
00186             storage.template get_reference<T>() = other.value();
00187           }
00188           else
00189           {
00190            ::new (storage.template get_address<T>()) T(other.value());
00191             valid = true;
00192           }
00193         }
00194       }
00195 
00196       return *this;
00197     }
00198 
00199     //***************************************************************************
00200     /// Assignment operator from value type.
00201     //***************************************************************************
00202     optional& operator =(const T& value_)
00203     {
00204       if (valid)
00205       {
00206         storage.template get_reference<T>() = value_;
00207       }
00208       else
00209       {
00210        ::new (storage.template get_address<T>()) T(value_);
00211         valid = true;
00212       }
00213 
00214       return *this;
00215     }
00216 
00217     //***************************************************************************
00218     /// Pointer operator.
00219     //***************************************************************************
00220     T* operator ->()
00221     {
00222 #if defined(ETL_DEBUG)
00223       ETL_ASSERT(valid, ETL_ERROR(optional_invalid));
00224 #endif
00225 
00226       return storage.template get_address<T>();
00227     }
00228 
00229     //***************************************************************************
00230     /// Pointer operator.
00231     //***************************************************************************
00232     const T* operator ->() const
00233     {
00234 #if defined(ETL_DEBUG)
00235       ETL_ASSERT(valid, ETL_ERROR(optional_invalid));
00236 #endif
00237 
00238       return storage.template get_address<T>();
00239     }
00240 
00241     //***************************************************************************
00242     /// Dereference operator.
00243     //***************************************************************************
00244     T& operator *()
00245     {
00246 #if defined(ETL_DEBUG)
00247       ETL_ASSERT(valid, ETL_ERROR(optional_invalid));
00248 #endif
00249 
00250       return storage.template get_reference<T>();
00251     }
00252 
00253     //***************************************************************************
00254     /// Dereference operator.
00255     //***************************************************************************
00256     const T& operator *() const
00257     {
00258 #if defined(ETL_DEBUG)
00259       ETL_ASSERT(valid, ETL_ERROR(optional_invalid));
00260 #endif
00261 
00262       return storage.template get_reference<T>();
00263     }
00264 
00265     //***************************************************************************
00266     /// Bool conversion operator.
00267     //***************************************************************************
00268     explicit operator bool() const
00269     {
00270       return valid;
00271     }
00272 
00273     //***************************************************************************
00274     /// Get a reference to the value.
00275     //***************************************************************************
00276     T& value()
00277     {
00278 #if defined(ETL_DEBUG)
00279       ETL_ASSERT(valid, ETL_ERROR(optional_invalid));
00280 #endif
00281 
00282       return storage.template get_reference<T>();
00283     }
00284 
00285     //***************************************************************************
00286     /// Get a const reference to the value.
00287     //***************************************************************************
00288     const T& value() const
00289     {
00290 #if defined(ETL_DEBUG)
00291       ETL_ASSERT(valid, ETL_ERROR(optional_invalid));
00292 #endif
00293 
00294       return storage.template get_reference<T>();
00295     }
00296 
00297     //***************************************************************************
00298     /// Gets the value or a default if no valid.
00299     //***************************************************************************
00300     T value_or(T default_value) const
00301     {
00302       return valid ? value() : default_value;
00303     }
00304 
00305     //***************************************************************************
00306     /// Swaps this value with another.
00307     //***************************************************************************
00308     void swap(optional& other)
00309     {
00310       optional temp(*this);
00311       *this = other;
00312       other = temp;
00313     }
00314 
00315   private:
00316 
00317     typename etl::aligned_storage_as<sizeof(T), T>::type storage;
00318     bool valid;
00319   };
00320 }
00321 
00322 //*************************************************************************
00323 /// Swaps the values.
00324 //*************************************************************************
00325 template <typename T>
00326 void swap(etl::optional<T>& lhs, etl::optional<T>& rhs)
00327 {
00328   lhs.swap(rhs);
00329 }
00330 
00331 //***************************************************************************
00332 /// Equality operator.
00333 //***************************************************************************
00334 template <typename T>
00335 bool operator ==(const etl::optional<T>& lhs, const etl::optional<T>& rhs)
00336 {
00337   if (bool(lhs) != bool(rhs))
00338   {
00339     return false;
00340   }
00341   else if (!bool(lhs) && !bool(rhs))
00342   {
00343     return true;
00344   }
00345   else
00346   {
00347     return lhs.value() == rhs.value();
00348   }
00349 }
00350 
00351 //***************************************************************************
00352 /// Less than operator.
00353 //***************************************************************************
00354 template <typename T>
00355 bool operator <(const etl::optional<T>& lhs, const etl::optional<T>& rhs)
00356 {
00357   if (!bool(rhs))
00358   {
00359     return false;
00360   }
00361   else if (!bool(lhs))
00362   {
00363     return true;
00364   }
00365   else
00366   {
00367     return lhs.value() < rhs.value();
00368   }
00369 }
00370 
00371 //***************************************************************************
00372 /// Equality operator.
00373 //***************************************************************************
00374 template <typename T>
00375 bool operator ==(const etl::optional<T>& lhs, etl::nullopt_t)
00376 {
00377   return !bool(lhs);
00378 }
00379 
00380 //***************************************************************************
00381 /// Equality operator.
00382 //***************************************************************************
00383 template <typename T>
00384 bool operator ==(etl::nullopt_t, const etl::optional<T>& rhs)
00385 {
00386   return false;
00387 }
00388 
00389 //***************************************************************************
00390 /// Less than operator.
00391 //***************************************************************************
00392 template <typename T>
00393 bool operator <(const etl::optional<T>& lhs, etl::nullopt_t)
00394 {
00395   return !bool(lhs);
00396 }
00397 
00398 //***************************************************************************
00399 /// Less than operator.
00400 //***************************************************************************
00401 template <typename T>
00402 bool operator <(etl::nullopt_t, const etl::optional<T>& rhs)
00403 {
00404   return bool(rhs);
00405 }
00406 
00407 //***************************************************************************
00408 /// Equality operator.
00409 //**************************************************************************
00410 template <typename T>
00411 bool operator ==(const etl::optional<T>& lhs, const T& rhs)
00412 {
00413   return bool(lhs) ? lhs.value() == rhs : false;
00414 }
00415 
00416 //***************************************************************************
00417 /// Equality operator.
00418 //**************************************************************************
00419 template <typename T>
00420 bool operator ==(const T& value, const etl::optional<T>& rhs)
00421 {
00422   return bool(rhs) ? rhs.value() == value : false;
00423 }
00424 
00425 //***************************************************************************
00426 /// Less than operator.
00427 //***************************************************************************
00428 template <typename T>
00429 bool operator <(const etl::optional<T>& lhs, const T& rhs)
00430 {
00431   return bool(lhs) ? lhs.value() < rhs : true;
00432 }
00433 
00434 //***************************************************************************
00435 /// Make an optional.
00436 //***************************************************************************
00437 template <typename T>
00438 etl::optional<typename etl::decay<T>::type> make_optional(T& value)
00439 {
00440   return etl::optional<typename etl::decay<T>::type>(value);
00441 }
00442 
00443 #endif
00444