Page MenuHomePhorge

types.hpp
No OneTemporary

Size
13 KB
Referenced Files
None
Subscribers
None

types.hpp

/***************************************************************************//**
*
* \file rosa/support/types.hpp
*
* \author David Juhasz (david.juhasz@tuwien.ac.at)
*
* \date 2017
*
* \brief Implementation of some basic convenience types.
*
* \note This implementation is partially based on the implementation of
* corresponding parts of CAF.
* \todo Check license.
*
******************************************************************************/
#ifndef ROSA_SUPPORT_TYPES_HPP
#define ROSA_SUPPORT_TYPES_HPP
#include "rosa/support/debug.hpp"
#include <string>
namespace rosa {
/* ************************************************************************** *
* Unit *
* ************************************************************************** */
/// A safe type to replace `void`.
///
/// `rosa::UnitType` is analogous to `void`, but can be safely returned, stored,
/// etc. to enable higher-order abstraction without cluttering code with
/// exceptions for `void` (which can't be stored, for example).
struct UnitType {
/// Ctor, needs to do nothing.
constexpr UnitType() noexcept {}
/// Copy-ctor, needs to do nothing.
constexpr UnitType(const UnitType &) noexcept {}
};
/// Aliasing `rosa::UnitType` as `rosa::unit_t`.
using unit_t = UnitType;
/// The value of `rosa::unit_t`.
///
/// \note Since a value of `rosa::UnitType` has no state, all instances of
/// `rosa::UnitType` is equal and considered *the `rosa::unit_t` value*.
static constexpr unit_t unit = unit_t{}; // NOLINT
/// Returns the textual representation of any value of `rosa::unit_t`.
///
/// \return textual representation of `rosa::UnitType`.
inline std::string to_string(const unit_t &) { return "unit"; }
/// \name LiftVoid
/// \brief Lifts a type to avoid `void`.
///
/// A type `T` can be lifted as \code
/// typename LiftVoid<T>::Type
/// \endcode
/// The resulted type is `rosa::unit_t` if `T` is `void`, and `T` itself
/// otherwise.
///@{
/// Definition for the general case.
///
/// \tparam T type to lift
template <typename T> struct LiftVoid { using Type = T; };
/// Specialization for the type `void`.
template <> struct LiftVoid<void> { using Type = unit_t; };
///@}
/// \name UnliftVoid
/// \brief Unlifts a type already lifted by `rosa::LiftVoid`.
///
/// A type `T` can be unlifted as \code
/// typename UnliftVoid<T>::Type
/// \endcode
/// The resulted type is `void` if T is `rosa::unit_t` -- that is `void` lifted
/// by `rosa::LiftVoid --, and `T` itself otherwise.
///
///@{
/// Definition for the general case.
///
/// \tparam T type to unlift
template <typename T> struct UnliftVoid { using Type = T; };
/// Specialization for the type `rosa::unit_t`.
template <> struct UnliftVoid<unit_t> { using Type = void; };
///@}
/* ************************************************************************** *
* None *
* ************************************************************************** */
/// Represents *nothing*.
///
/// An instance of the type represents *nothing*, that can be used, e.g., for
/// clearing an instance of `rosa::Optional` by assigning an instance of
/// `rosa::NoneType` to it.
struct NoneType {
/// Ctor, needs to do nothing.
constexpr NoneType(void) {}
/// Evaluates the instance to `bool`.
///
/// A "nothing" is always evaluates to `false`.
constexpr explicit operator bool(void) const { return false; }
};
/// Aliasing type `rosa::NoneType` as `rosa::none_t`.
using none_t = NoneType;
/// The value of `rosa::none_t`.
///
/// \note Since a value of `rosa::NoneType` has no state, all instances of
/// `rosa::NoneType` is equal and considered *the `rosa::none_t` value*.
static constexpr none_t none = none_t{}; // NOLINT
/// Returns the textual representation of any value of `rosa::none_t`.
///
/// \return textual representation of `rosa::NoneType`.
inline std::string to_string(const none_t &) { return "none"; }
/* ************************************************************************** *
* Optional *
* ************************************************************************** */
/// \defgroup Optional
/// \brief Represents an optional value.
///
/// \note This implementation is compatible with `std::optional` of C++17.
///@{
/// Definition for the general case, optionally storing a value.
///
/// \tparam T type of the optional value
template <class T> 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 `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 `T`.
template <class U, class E = typename std::enable_if<
std::is_convertible<U, T>::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<T>::value)
: Valid(false) {
if (Other.Valid) {
cr(std::move(Other.Value));
}
}
/// Destroys the instance.
~Optional(void) { destroy(); }
/// Updates `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 `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<T>::value
&&std::is_nothrow_move_assignable<T>::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 `this` object contains a value.
///
/// \return if `this` object contains a value
explicit operator bool(void) const { return Valid; }
/// Checks whether `this` object does not contain a value.
///
/// \return if `this` object does not contain a value
bool operator!(void) const { return !Valid; }
/// Returns the value stored in `this` object.
///
/// \return reference of the stored value
///
/// \pre `this` object contains a value
T &operator*(void) {
ASSERT(Valid);
return Value;
}
/// Returns the value stored in `this` object.
///
/// \return reference of the stored value
///
/// \pre `this` object contains a value
const T &operator*(void) const {
ASSERT(Valid);
return Value;
}
/// Returns the value stored in `this` object.
///
/// \return pointer to the stored value
///
/// \pre `this` object contains a value
const T *operator->(void) const {
ASSERT(Valid);
return &Value;
}
/// Returns the value stored in `this` object.
///
/// \return pointer of the stored value
///
/// \pre `this` object contains a value
T *operator->(void) {
ASSERT(Valid);
return &Value;
}
/// Returns the value stored in `this` object.
///
/// \return reference of the stored value
///
/// \pre `this` object contains a value
T &value(void) {
ASSERT(Valid);
return Value;
}
/// Returns the value stored in `this` object.
///
/// \return reference of the stored value
///
/// \pre `this` object contains a value
const T &value(void) const {
ASSERT(Valid);
return Value;
}
/// Returns the stored value or a default.
///
/// If `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 `this` object does not contain
/// a value
///
/// \return reference to either the stored value or `DefaultValue` if `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 `this` object by moving a value into it.
///
/// \tparam V type of `X`
///
/// \param X value to move into
///
/// \pre `this` object does not contain a value
template <class V> void cr(V &&X) {
ASSERT(!Valid);
Valid = true;
new (&Value) T(std::forward<V>(X));
}
/// Denotes if `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 `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 <typename T> class Optional<T &> {
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 `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 `this` object contains a reference.
///
/// \return if `this` object contains a reference
explicit operator bool(void) const { return Value != nullptr; }
/// Checks whether `this` object does not contain a reference.
///
/// \return if `this` object does not contain a reference
bool operator!(void) const { return !Value; }
/// Returns the reference stored in `this` object.
///
/// \return the stored reference
///
/// \pre `this` object contains a reference
T &operator*(void) {
ASSERT(Value);
return *Value;
}
/// Returns the value stored in `this` object.
///
/// \return the stored reference
///
/// \pre `this` object contains a reference
const T &operator*(void) const {
ASSERT(Value);
return *Value;
}
/// Returns the value stored in `this` object.
///
/// \return the stored reference
///
/// \pre `this` object contains a reference
T *operator->(void) {
ASSERT(Value);
return Value;
}
/// Returns the value stored in `this` object.
///
/// \return the stored reference
///
/// \pre `this` object contains a reference
const T *operator->(void) const {
ASSERT(Value);
return Value;
}
/// Returns the value stored in `this` object.
///
/// \return the stored reference
///
/// \pre `this` object contains a reference
T &value(void) {
ASSERT(Value);
return *Value;
}
/// Returns the value stored in `this` object.
///
/// \return the stored reference
///
/// \pre `this` object contains a reference
const T &value(void) const {
ASSERT(Value);
return *Value;
}
/// Returns the stored reference or a default.
///
/// If `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 `this` object does not contain
/// a reference
///
/// \return either the stored reference or `DefaultValue` if `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 `void`.
///
/// The specialization allows `rosa::Optional` to implement a flag for `void`.
template <> class Optional<void> {
public:
using Type = unit_t;
/// Creates an instance with a `false` flag.
///
/// \note Use it with its default parameter.
Optional(none_t = none) : Value(false) {}
/// Creates an instance with a `true` flag.
///
/// \note The only argument is ignored because it can be *the `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 `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 `this` object contains a `true` flag.
///
/// \return if `this` object contains a `true` flag.
explicit operator bool(void) const { return Value; }
/// Checks whether `this` object contains a `false` flag.
///
/// \return if `this` object contains a `false` flag.
bool operator!(void) const { return !Value; }
private:
/// The stored flag.
bool Value;
};
///@}
} // End namespace rosa
#endif // ROSA_SUPPORT_TYPES_HPP

File Metadata

Mime Type
text/x-c++
Expires
Sat, Aug 29, 2:51 PM (1 d, 10 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
328107
Default Alt Text
types.hpp (13 KB)

Event Timeline