Containers (STL-compatible) StateMachines MessageBus and more for Embedded Systems. See www.etlcpp.com

Revision:
0:b47c2a7920c2
diff -r 000000000000 -r b47c2a7920c2 optional.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/optional.h	Fri Mar 16 16:34:18 2018 +0000
@@ -0,0 +1,444 @@
+///\file
+
+/******************************************************************************
+The MIT License(MIT)
+
+Embedded Template Library.
+https://github.com/ETLCPP/etl
+http://www.etlcpp.com
+
+Copyright(c) 2015 jwellbelove
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files(the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions :
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+******************************************************************************/
+
+#ifndef __ETL_OPTIONAL__
+#define __ETL_OPTIONAL__
+
+#include "platform.h"
+#include "alignment.h"
+#include "type_traits.h"
+#include "exception.h"
+#include "error_handler.h"
+
+namespace etl
+{
+  //*****************************************************************************
+  /// A null option type.
+  ///\ingroup utilities
+  //*****************************************************************************
+  class nullopt_t
+  {
+  public:
+
+    // Convertible to any type of null non-member pointer.
+    template<class T>
+    operator T*() const
+    {
+      return 0;
+    }
+
+  private:
+
+    // Can't take address of nullopt.
+    void operator&() const;
+  };
+
+  //*****************************************************************************
+  /// A null option.
+  ///\ingroup utilities
+  //*****************************************************************************
+  const nullopt_t nullopt = {};
+
+  //***************************************************************************
+  /// Exception for optional.
+  ///\ingroup list
+  //***************************************************************************
+  class optional_exception : public exception
+  {
+  public:
+
+    optional_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
+      : exception(reason_, file_name_, line_number_)
+    {
+    }
+  };
+
+  //***************************************************************************
+  /// Invalid exception for optional.
+  ///\ingroup list
+  //***************************************************************************
+  class optional_invalid : public optional_exception
+  {
+  public:
+
+    optional_invalid(string_type file_name_, numeric_type line_number_)
+      : optional_exception("optional: invalid", file_name_, line_number_)
+    {
+    }
+  };
+
+  //*****************************************************************************
+  /// An optional type.
+  /// If the optional type is not initialised then a type is not constructed.
+  ///\tparam The type to store.
+  ///\ingroup utilities
+  //*****************************************************************************
+  template <typename T>
+  class optional
+  {
+  public:
+
+    //***************************************************************************
+    /// Constructor.
+    //***************************************************************************
+    optional()
+      : valid(false)
+    {
+    }
+
+    //***************************************************************************
+    /// Constructor with nullopt.
+    //***************************************************************************
+    optional(etl::nullopt_t)
+      : valid(false)
+    {
+    }
+
+    //***************************************************************************
+    /// Copy constructor.
+    //***************************************************************************
+    optional(const optional& other)
+      : valid(bool(other))
+    {
+      if (valid)
+      {
+       ::new (storage.template get_address<T>()) T(other.value());
+      }
+    }
+
+    //***************************************************************************
+    /// Constructor from value type.
+    //***************************************************************************
+    optional(const T& value_)
+    {
+     ::new (storage.template get_address<T>()) T(value_);
+      valid = true;
+    }
+
+    //***************************************************************************
+    /// Destructor.
+    //***************************************************************************
+    ~optional()
+    {
+      if (valid)
+      {
+        storage.template get_reference<T>().~T();
+      }
+    }
+
+    //***************************************************************************
+    /// Assignment operator from nullopt.
+    //***************************************************************************
+    optional& operator =(etl::nullopt_t)
+    {
+      if (valid)
+      {
+        storage.template get_reference<T>().~T();
+        valid = false;
+      }
+
+      return *this;
+    }
+
+    //***************************************************************************
+    /// Assignment operator from optional.
+    //***************************************************************************
+    optional& operator =(const optional& other)
+    {
+      if (this != &other)
+      {
+        if (valid && !bool(other))
+        {
+          storage.template get_reference<T>().~T();
+          valid = false;
+        }
+        else if (bool(other))
+        {
+          if (valid)
+          {
+            storage.template get_reference<T>() = other.value();
+          }
+          else
+          {
+           ::new (storage.template get_address<T>()) T(other.value());
+            valid = true;
+          }
+        }
+      }
+
+      return *this;
+    }
+
+    //***************************************************************************
+    /// Assignment operator from value type.
+    //***************************************************************************
+    optional& operator =(const T& value_)
+    {
+      if (valid)
+      {
+        storage.template get_reference<T>() = value_;
+      }
+      else
+      {
+       ::new (storage.template get_address<T>()) T(value_);
+        valid = true;
+      }
+
+      return *this;
+    }
+
+    //***************************************************************************
+    /// Pointer operator.
+    //***************************************************************************
+    T* operator ->()
+    {
+#if defined(ETL_DEBUG)
+      ETL_ASSERT(valid, ETL_ERROR(optional_invalid));
+#endif
+
+      return storage.template get_address<T>();
+    }
+
+    //***************************************************************************
+    /// Pointer operator.
+    //***************************************************************************
+    const T* operator ->() const
+    {
+#if defined(ETL_DEBUG)
+      ETL_ASSERT(valid, ETL_ERROR(optional_invalid));
+#endif
+
+      return storage.template get_address<T>();
+    }
+
+    //***************************************************************************
+    /// Dereference operator.
+    //***************************************************************************
+    T& operator *()
+    {
+#if defined(ETL_DEBUG)
+      ETL_ASSERT(valid, ETL_ERROR(optional_invalid));
+#endif
+
+      return storage.template get_reference<T>();
+    }
+
+    //***************************************************************************
+    /// Dereference operator.
+    //***************************************************************************
+    const T& operator *() const
+    {
+#if defined(ETL_DEBUG)
+      ETL_ASSERT(valid, ETL_ERROR(optional_invalid));
+#endif
+
+      return storage.template get_reference<T>();
+    }
+
+    //***************************************************************************
+    /// Bool conversion operator.
+    //***************************************************************************
+    explicit operator bool() const
+    {
+      return valid;
+    }
+
+    //***************************************************************************
+    /// Get a reference to the value.
+    //***************************************************************************
+    T& value()
+    {
+#if defined(ETL_DEBUG)
+      ETL_ASSERT(valid, ETL_ERROR(optional_invalid));
+#endif
+
+      return storage.template get_reference<T>();
+    }
+
+    //***************************************************************************
+    /// Get a const reference to the value.
+    //***************************************************************************
+    const T& value() const
+    {
+#if defined(ETL_DEBUG)
+      ETL_ASSERT(valid, ETL_ERROR(optional_invalid));
+#endif
+
+      return storage.template get_reference<T>();
+    }
+
+    //***************************************************************************
+    /// Gets the value or a default if no valid.
+    //***************************************************************************
+    T value_or(T default_value) const
+    {
+      return valid ? value() : default_value;
+    }
+
+    //***************************************************************************
+    /// Swaps this value with another.
+    //***************************************************************************
+    void swap(optional& other)
+    {
+      optional temp(*this);
+      *this = other;
+      other = temp;
+    }
+
+  private:
+
+    typename etl::aligned_storage_as<sizeof(T), T>::type storage;
+    bool valid;
+  };
+}
+
+//*************************************************************************
+/// Swaps the values.
+//*************************************************************************
+template <typename T>
+void swap(etl::optional<T>& lhs, etl::optional<T>& rhs)
+{
+  lhs.swap(rhs);
+}
+
+//***************************************************************************
+/// Equality operator.
+//***************************************************************************
+template <typename T>
+bool operator ==(const etl::optional<T>& lhs, const etl::optional<T>& rhs)
+{
+  if (bool(lhs) != bool(rhs))
+  {
+    return false;
+  }
+  else if (!bool(lhs) && !bool(rhs))
+  {
+    return true;
+  }
+  else
+  {
+    return lhs.value() == rhs.value();
+  }
+}
+
+//***************************************************************************
+/// Less than operator.
+//***************************************************************************
+template <typename T>
+bool operator <(const etl::optional<T>& lhs, const etl::optional<T>& rhs)
+{
+  if (!bool(rhs))
+  {
+    return false;
+  }
+  else if (!bool(lhs))
+  {
+    return true;
+  }
+  else
+  {
+    return lhs.value() < rhs.value();
+  }
+}
+
+//***************************************************************************
+/// Equality operator.
+//***************************************************************************
+template <typename T>
+bool operator ==(const etl::optional<T>& lhs, etl::nullopt_t)
+{
+  return !bool(lhs);
+}
+
+//***************************************************************************
+/// Equality operator.
+//***************************************************************************
+template <typename T>
+bool operator ==(etl::nullopt_t, const etl::optional<T>& rhs)
+{
+  return false;
+}
+
+//***************************************************************************
+/// Less than operator.
+//***************************************************************************
+template <typename T>
+bool operator <(const etl::optional<T>& lhs, etl::nullopt_t)
+{
+  return !bool(lhs);
+}
+
+//***************************************************************************
+/// Less than operator.
+//***************************************************************************
+template <typename T>
+bool operator <(etl::nullopt_t, const etl::optional<T>& rhs)
+{
+  return bool(rhs);
+}
+
+//***************************************************************************
+/// Equality operator.
+//**************************************************************************
+template <typename T>
+bool operator ==(const etl::optional<T>& lhs, const T& rhs)
+{
+  return bool(lhs) ? lhs.value() == rhs : false;
+}
+
+//***************************************************************************
+/// Equality operator.
+//**************************************************************************
+template <typename T>
+bool operator ==(const T& value, const etl::optional<T>& rhs)
+{
+  return bool(rhs) ? rhs.value() == value : false;
+}
+
+//***************************************************************************
+/// Less than operator.
+//***************************************************************************
+template <typename T>
+bool operator <(const etl::optional<T>& lhs, const T& rhs)
+{
+  return bool(lhs) ? lhs.value() < rhs : true;
+}
+
+//***************************************************************************
+/// Make an optional.
+//***************************************************************************
+template <typename T>
+etl::optional<typename etl::decay<T>::type> make_optional(T& value)
+{
+  return etl::optional<typename etl::decay<T>::type>(value);
+}
+
+#endif
+