diff --git a/include/rosa/support/types.hpp b/include/rosa/support/types.hpp index 74c22f3..e0a69a4 100644 --- a/include/rosa/support/types.hpp +++ b/include/rosa/support/types.hpp @@ -1,555 +1,555 @@ //===-- rosa/support/types.hpp ----------------------------------*- C++ -*-===// // // The RoSA Framework // // Distributed under the terms and conditions of the Boost Software License 1.0. // See accompanying file LICENSE. // // If you did not receive a copy of the license file, see // http://www.boost.org/LICENSE_1_0.txt. // //===----------------------------------------------------------------------===// /// /// \file rosa/support/types.hpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017-2019 /// /// \brief Implementation of some basic convenience types. /// /// \note This implementation is partially based on the implementation of /// corresponding parts of CAF. /// //===----------------------------------------------------------------------===// #ifndef ROSA_SUPPORT_TYPES_HPP #define ROSA_SUPPORT_TYPES_HPP #include "rosa/support/debug.hpp" #include namespace rosa { /* ************************************************************************** * * Unit * * ************************************************************************** */ /// A safe type to replace \c void. /// /// \c rosa::UnitType is analogous to \c void, but can be safely returned, /// stored, etc. to enable higher-order abstraction without cluttering code with /// exceptions for \c void (which can't be stored, for example). struct UnitType { /// Constructor, needs to do nothing. constexpr UnitType() noexcept = default; /// Copy-constructor, needs to do nothing. - constexpr UnitType(const UnitType &) noexcept = default; + //constexpr UnitType(const UnitType &) noexcept = default; }; /// Aliasing \c rosa::UnitType as \c rosa::unit_t. using unit_t = UnitType; /// The value of \c rosa::unit_t. /// /// \note Since a value of \c rosa::UnitType has no state, all instances of /// \c rosa::UnitType is equal and considered *the \c rosa::unit_t value*. static constexpr unit_t unit = unit_t{}; // NOLINT /// \name LiftVoid /// \brief Lifts a type to avoid \c void. /// /// A type \c T can be lifted as \code /// typename LiftVoid::Type /// \endcode /// The resulted type is \c rosa::unit_t if \c T is \c void, and \c T itself /// otherwise. ///@{ /// Definition for the general case. /// /// \tparam T type to lift template struct LiftVoid { using Type = T; }; /// Specialization for \c void. template <> struct LiftVoid { using Type = unit_t; }; ///@} /// \name UnliftVoid /// \brief Unlifts a type already lifted by \c rosa::LiftVoid. /// /// A type \c T can be unlifted as \code /// typename UnliftVoid::Type /// \endcode /// The resulted type is \c void if \c T is \c rosa::unit_t -- that is \c void /// lifted by \c rosa::LiftVoid --, and \c T itself otherwise. /// ///@{ /// Definition for the general case. /// /// \tparam T type to unlift template struct UnliftVoid { using Type = T; }; /// Specialization for \c rosa::unit_t. template <> struct UnliftVoid { using Type = void; }; ///@} /* ************************************************************************** * * None * * ************************************************************************** */ /// Represents *nothing*. /// /// An instance of the type represents *nothing*, that can be used, e.g., for /// clearing an instance of \c rosa::Optional by assigning an instance of /// \c rosa::NoneType to it. struct NoneType { /// Constructor, needs to do nothing. constexpr NoneType(void) = default; /// Evaluates the instance to \c bool. /// /// A "nothing" is always evaluates to \c false. constexpr explicit operator bool(void) const { return false; } }; /// Aliasing type \c rosa::NoneType as \c rosa::none_t. using none_t = NoneType; /// The value of \c rosa::none_t. /// /// \note Since a value of \c rosa::NoneType has no state, all instances of /// \c rosa::NoneType is equal and considered *the \c rosa::none_t value*. static constexpr none_t none = none_t{}; // NOLINT /* ************************************************************************** * * Optional * * ************************************************************************** */ /// \defgroup Optional Specializations of rosa::Optional /// /// \brief Represents an optional value. /// /// \note This implementation is compatible with \c std::optional of C++17. ///@{ /// Definition for the general case, optionally storing a value. /// /// \tparam T type of the optional value template class Optional { public: using Type = T; /// Creates an instance without value. /// /// \note Use it with its default parameter. Optional(const none_t & = none) : Valid(false) {} /// Creates a valid instance with value. /// /// \tparam U type of the \p X /// \tparam E always use it with default value! /// /// \param X value to store in the object /// /// \note The constructor is available for types that are convertible to \p T. template ::value>::type> Optional(U X) : Valid(false) { cr(std::move(X)); } /// Creates an instance as a copy of another one. /// /// \param Other the instance whose state to copy Optional(const Optional &Other) : Valid(false) { if (Other.Valid) { cr(Other.Value); } } /// Creates an instance by moving the state of another one. /// /// \param Other the instance whose state to obtain Optional(Optional &&Other) noexcept( std::is_nothrow_move_constructible::value) : Valid(false) { if (Other.Valid) { cr(std::move(Other.Value)); } } /// Destroys \p this object. ~Optional(void) { destroy(); } /// Updates \p this object by copying the state of another one. /// /// \param Other the instance whose state to copy /// /// \return reference of the updated instance Optional &operator=(const Optional &Other) { if (Valid) { if (Other.Valid) { Value = Other.Value; } else { destroy(); } } else if (Other.Valid) { cr(Other.Value); } return *this; } /// Updates \p this object by moving the state of another one. /// /// \param Other the instance whose state to obtain /// /// \return reference of the updated instance Optional &operator=(Optional &&Other) noexcept( std::is_nothrow_destructible::value &&std::is_nothrow_move_assignable::value) { if (Valid) { if (Other.Valid) { Value = std::move(Other.Value); } else { destroy(); } } else if (Other.Valid) { cr(std::move(Other.Value)); } return *this; } /// Checks whether \p this object contains a value. /// /// \return if \p this object contains a value explicit operator bool(void) const { return Valid; } /// Checks whether \p this object does not contain a value. /// /// \return if \p this object does not contain a value bool operator!(void)const { return !Valid; } /// Returns the value stored in \p this object. /// /// \return reference of the stored value /// /// \pre \p this object contains a value T &operator*(void) { ASSERT(Valid); return Value; } /// Returns the value stored in \p this object. /// /// \return reference of the stored value /// /// \pre \p this object contains a value const T &operator*(void)const { ASSERT(Valid); return Value; } /// Returns the value stored in \p this object. /// /// \return pointer to the stored value /// /// \pre \p this object contains a value const T *operator->(void)const { ASSERT(Valid); return &Value; } /// Returns the value stored in \p this object. /// /// \return pointer of the stored value /// /// \pre \p this object contains a value T *operator->(void) { ASSERT(Valid); return &Value; } /// Returns the value stored in \p this object. /// /// \return reference of the stored value /// /// \pre \p this object contains a value T &value(void) { ASSERT(Valid); return Value; } /// Returns the value stored in \p this object. /// /// \return reference of the stored value /// /// \pre \p this object contains a value const T &value(void) const { ASSERT(Valid); return Value; } /// Returns the stored value or a default. /// /// If \p this object contains a value, then the stored value is returned. A /// given default value is returned otherwise. /// /// \param DefaultValue the value to return if \p this object does not contain /// a value /// /// \return reference to either the stored value or \p DefaultValue if \p this /// object does not contain a value const T &valueOr(const T &DefaultValue) const { return Valid ? Value : DefaultValue; } private: /// Deallocates the stored value if any. void destroy(void) { if (Valid) { Value.~T(); Valid = false; } } /// Updates the state of \p this object by moving a value into it. /// /// \tparam V type of \p X /// /// \param X value to move /// /// \pre \p this object does not contain a value template void cr(V &&X) { ASSERT(!Valid); Valid = true; new (&Value) T(std::forward(X)); } /// Denotes if \p this object contains a value. bool Valid; /// Holds the stored value if any. union { T Value; ///< The stored value. }; }; /// Specialization storing a reference. /// /// The specialization allows \p rosa::Optional to hold a reference /// rather than an actual value with minimal overhead. /// /// \tparam T the base type whose reference is to be stored template class Optional { public: using Type = T; /// Creates an instance without reference /// /// \note Use it with its default parameter. Optional(const none_t & = none) : Value(nullptr) {} /// Creates a valid instance with reference. /// /// \param X reference to store in the object Optional(T &X) : Value(&X) {} /// Creates a valid instance with reference. /// /// \param X pointer to store in the object as reference Optional(T *X) : Value(X) {} /// Creates an instance as a copy of another one. /// /// \param Other the instance whose state to copy Optional(const Optional &Other) = default; /// Updates \p this object by copying the state of another one. /// /// \param Other the instance whose state to copy /// /// \return reference of the updated instance Optional &operator=(const Optional &Other) = default; /// Checks whether \p this object contains a reference. /// /// \return if \p this object contains a reference explicit operator bool(void) const { return Value != nullptr; } /// Checks whether \p this object does not contain a reference. /// /// \return if \p this object does not contain a reference bool operator!(void)const { return !Value; } /// Returns the reference stored in \p this object. /// /// \return the stored reference /// /// \pre \p this object contains a reference T &operator*(void) { ASSERT(Value); return *Value; } /// Returns the value stored in \p this object. /// /// \return the stored reference /// /// \pre \p this object contains a reference const T &operator*(void)const { ASSERT(Value); return *Value; } /// Returns the value stored in \p this object. /// /// \return the stored reference /// /// \pre \p this object contains a reference T *operator->(void) { ASSERT(Value); return Value; } /// Returns the value stored in \p this object. /// /// \return the stored reference /// /// \pre \p this object contains a reference const T *operator->(void)const { ASSERT(Value); return Value; } /// Returns the value stored in \p this object. /// /// \return the stored reference /// /// \pre \p this object contains a reference T &value(void) { ASSERT(Value); return *Value; } /// Returns the value stored in \p this object. /// /// \return the stored reference /// /// \pre \p this object contains a reference const T &value(void) const { ASSERT(Value); return *Value; } /// Returns the stored reference or a default. /// /// If \p this object contains a reference, then the stored reference is /// returned. A given default value is returned otherwise. /// /// \param DefaultValue the value to return if \p this object does not contain /// a reference /// /// \return either the stored reference or \p DefaultValue if \p this object /// does not contain a reference const T &valueOr(const T &DefaultValue) const { return Value ? Value : DefaultValue; } private: /// The stored reference as a pointer. T *Value; }; /// Specialization storing \c void. /// /// The specialization allows \c rosa::Optional to implement a flag for \c void. template <> class Optional { public: using Type = unit_t; /// Creates an instance with a \c false flag. /// /// \note Use it with its default parameter. Optional(none_t = none) : Value(false) {} /// Creates an instance with a \c true flag. /// /// \note The only argument is ignored because it can be *the \c rosa::unit_t /// value* only. Optional(unit_t) : Value(true) {} /// Creates an instance as a copy of another one. /// /// \param Other the instance whose state to copy Optional(const Optional &Other) = default; /// Updates \p this object by copying the state of another one. /// /// \param Other the instance whose state to copy /// /// \return reference of the updated instance Optional &operator=(const Optional &Other) = default; /// Checks whether \p this object contains a \p true flag. /// /// \return if \p this object contains a \p true flag. explicit operator bool(void) const { return Value; } /// Checks whether \p this object contains a \p false flag. /// /// \return if \p this object contains a \p false flag. bool operator!(void)const { return !Value; } private: /// The stored flag. bool Value; }; ///@} } // End namespace rosa namespace std { /// Returns the textual representation of any value of \c rosa::unit_t. /// /// \return textual representation of \c rosa::UnitType. inline std::string to_string(const rosa::unit_t &) { return "unit"; } /// Dumps a \c rosa::Unit to a given \c std::ostream. /// /// \param [in,out] OS output stream to dump to /// \param U \c rosa::Unit to dump /// /// \return \p OS after dumping \p U to it inline ostream &operator<<(ostream &OS, const rosa::unit_t &U) { OS << to_string(U); return OS; } /// Returns the textual representation of any value of \c rosa::none_t. /// /// \return textual representation of \c rosa::NoneType. inline std::string to_string(const rosa::none_t &) { return "none"; } /// Dumps a \c rosa::none_t to a given \c std::ostream. /// /// \param [in,out] OS output stream to dump to /// \param N \c rosa::none_t to dump /// /// \return \p OS after dumping \p N to it inline ostream &operator<<(ostream &OS, const rosa::none_t &N) { OS << to_string(N); return OS; } } // End namespace std #endif // ROSA_SUPPORT_TYPES_HPP