Class compact_optional_storage

Synopsis

#include <include/type_safe/compact_optional.hpp>

template <class CompactPolicy>
class compact_optional_storage

Description

A StoragePolicy for [ts::basic_optional]() that is more space efficient than [ts::direct_optional_storage]().

It is designed to have no space overhead compared to a regular object of the stored type. This is accomplished by marking one value of the stored type as invalid and using that in the empty state. What the invalid value is is controlled by the CompactPolicy. It must provide the following static member functions and typedefs:

  • value_type - the value that is being stored conceptually
  • storage_type - the actual type that is being stored
  • storage_type invalid_value() - returns the value that marks the optional as empty
  • bool is_invalid(const storage_type&) - returns true if the given value is invalid, false otherwise

In the cases where value_type and storage_type differ, the get_value() functions will not return references, but a copy instead. The implementation assumes that invalid_value() and is_invalid() are noexcept and cheap. \notes For a compact optional of pointer type, use [ts::optional_ref](). \module optional

Methods

compact_optional_storage\effects Initializes it in the state without value, i.e
copy_value overload\effects Copy assigns the storage_type.
copy_value overload\effects Move assigns the storage_type.
create_value overload\effects Creates a temporary value_type by perfectly forwarding args, converts that to the storage_type and assigns it
create_value overload\effects Copy assigns the storage_type.
create_value overload\effects Move assigns the storage_type.
create_value_explicit
destroy_value\effects Destroys the value by setting it to the invalid storage value
get_value overloadReturns: A (suitable) reference to the stored value or a copy of the value depending on the policy
get_value overload\group get_value
get_value_orReturns: Either get_value() or u converted to value_type
has_valueReturns: Whether or not there is a value stored, i.e
swap_value\effects Swaps the storage_type.

Source

Lines 43-189 in include/type_safe/compact_optional.hpp.

template <class CompactPolicy>
class compact_optional_storage
{
public:
    using value_type = typename std::remove_cv<typename CompactPolicy::value_type>::type;
    static_assert(!std::is_reference<value_type>::value,
                  "value_type must not be a reference; use optional_ref<T> for that");
    using storage_type = typename CompactPolicy::storage_type;

    using lvalue_reference = detail::storage_reference<storage_type, value_type, value_type&>;
    using const_lvalue_reference
        = detail::storage_reference<storage_type, value_type, const value_type&>;

    using rvalue_reference = detail::storage_reference<storage_type, value_type, value_type&&>;
    using const_rvalue_reference
        = detail::storage_reference<storage_type, value_type, const value_type&&>;

    template <typename U>
    using rebind = direct_optional_storage<U>;

    /// \effects Initializes it in the state without value,
    /// i.e. sets the storage to the invalid value.
    compact_optional_storage() noexcept : storage_(CompactPolicy::invalid_value()) {}

    /// \effects Creates a temporary `value_type` by perfectly forwarding `args`,
    /// converts that to the `storage_type` and assigns it.
    /// Afterwards `has_value()` will return `true`.
    /// \throws Anything thrown by the constructor of `value_type`/`storage_type` or its move
    /// assignment operator in which case `has_value()` is still `false`. \requires `has_value() ==
    /// false` and the given value must not be invalid. \notes This function does not participate in
    /// overload resolution unless `value_type` is constructible from `args`. \synopsis template
    /// \<typename ... Args\>\nvoid create_value(Args&&... args);
    template <typename... Args>
    auto create_value(Args&&... args) ->
        typename std::enable_if<std::is_constructible<value_type, Args&&...>::value>::type
    {
        storage_ = static_cast<storage_type>(value_type(std::forward<Args>(args)...));
        DEBUG_ASSERT(has_value(), detail::precondition_error_handler{},
                     "create_value() called creating an invalid value");
    }

    /// \effects Copy assigns the `storage_type`.
    void create_value(const compact_optional_storage& other)
    {
        storage_ = other.storage_;
    }

    /// \effects Move assigns the `storage_type`.
    void create_value(compact_optional_storage&& other)
    {
        storage_ = std::move(other.storage_);
    }

    void create_value_explicit() {}

    /// \effects Copy assigns the `storage_type`.
    void copy_value(const compact_optional_storage& other)
    {
        storage_ = other.storage_;
    }

    /// \effects Move assigns the `storage_type`.
    void copy_value(compact_optional_storage&& other)
    {
        storage_ = std::move(other.storage_);
    }

    /// \effects Swaps the `storage_type`.
    void swap_value(compact_optional_storage& other)
    {
        using std::swap;
        swap(storage_, other.storage_);
    }

    /// \effects Destroys the value by setting it to the invalid storage value.
    /// Afterwards `has_value()` will return `false`.
    /// \requires `has_value() == true`.
    void destroy_value() noexcept
    {
        storage_ = CompactPolicy::invalid_value();
    }

    /// \returns Whether or not there is a value stored,
    /// i.e. whether the stored value is not invalid.
    bool has_value() const noexcept
    {
        return !CompactPolicy::is_invalid(storage_);
    }

    /// \returns A (suitable) reference to the stored value
    /// or a copy of the value depending on the policy.
    /// \requires `has_value() == true`.
    /// \group get_value
    lvalue_reference get_value() TYPE_SAFE_LVALUE_REF noexcept
    {
        return static_cast<lvalue_reference>(storage_);
    }

    /// \group get_value
    const_lvalue_reference get_value() const TYPE_SAFE_LVALUE_REF noexcept
    {
        return static_cast<const_lvalue_reference>(storage_);
    }

#if TYPE_SAFE_USE_REF_QUALIFIERS
    /// \group get_value
    rvalue_reference get_value() && noexcept
    {
        return static_cast<rvalue_reference>(storage_);
    }

    /// \group get_value
    const_rvalue_reference get_value() const&& noexcept
    {
        return static_cast<const_rvalue_reference>(storage_);
    }
#endif

    /// \returns Either `get_value()` or `u` converted to `value_type`.
    /// \requires `value_type` must be copy (1)/move (2) constructible and `u` convertible to
    /// `value_type`. \group get_value_or \param 1 \exclude
    template <typename U,
              typename
              = typename std::enable_if<std::is_copy_constructible<value_type>::value
                                        && std::is_convertible<U&&, value_type>::value>::type>
    value_type get_value_or(U&& u) const TYPE_SAFE_LVALUE_REF
    {
        return has_value() ? get_value() : static_cast<value_type>(std::forward<U>(u));
    }

#if TYPE_SAFE_USE_REF_QUALIFIERS
    /// \group get_value_or
    /// \param 1
    /// \exclude
    template <typename U,
              typename
              = typename std::enable_if<std::is_move_constructible<value_type>::value
                                        && std::is_convertible<U&&, value_type>::value>::type>
    value_type get_value_or(U&& u) &&
    {
        return has_value() ? std::move(get_value()) : static_cast<value_type>(std::forward<U>(u));
    }
#endif

private:
    storage_type storage_;
};





Add Discussion as Guest

Log in