Program Listing for File optional.hpp

Return to documentation for file (include/fastcdr/xcdr/optional.hpp)

// Copyright 2023 Proyectos y Sistemas de Mantenimiento SL (eProsima).
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef _FASTCDR_XCDR_OPTIONAL_HPP_
#define _FASTCDR_XCDR_OPTIONAL_HPP_

#include <new>
#include <utility>

#include "detail/optional.hpp"
#include "../exceptions/BadOptionalAccessException.hpp"

namespace eprosima {
namespace fastcdr {

struct nullopt_t
{
    constexpr explicit nullopt_t(
            int)
    {
    }

};

static constexpr nullopt_t nullopt {0};

template<class T>
class optional
{
public:

    using type = T;

    optional() = default;

    optional(
            const T& val) noexcept
    {
        ::new(&storage_.val_)T(val);
        storage_.engaged_ = true;
    }

    optional(
            T&& val) noexcept
    {
        ::new(&storage_.val_)T(std::move(val));
        storage_.engaged_ = true;
    }

    optional(
            const optional<T>& val) noexcept
    {
        if (val.storage_.engaged_)
        {
            ::new(&storage_.val_)T(val.storage_.val_);
            storage_.engaged_ = true;
        }
    }

    optional(
            optional<T>&& val) noexcept
    {
        if (val.storage_.engaged_)
        {
            ::new(&storage_.val_)T(std::move(val.storage_.val_));
            storage_.engaged_ = true;
        }
    }

    ~optional() = default;

    template<class ... Args> void emplace(
            Args&&... _args)
    {
        reset();
        storage_.val_.T(std::forward<Args>(_args)...);
        storage_.engaged_ = true;
    }

    void reset(
            bool initial_engaged = false)
    {
        if (storage_.engaged_)
        {
            storage_.val_.~T();
        }
        storage_.engaged_ = initial_engaged;
        if (storage_.engaged_)
        {
            ::new(&storage_.val_)T();
        }
    }

    T& value()&
    {
        if (!storage_.engaged_)
        {
            throw exception::BadOptionalAccessException(
                      exception::BadOptionalAccessException::BAD_OPTIONAL_ACCESS_MESSAGE_DEFAULT);
        }

        return storage_.val_;
    }

    const T& value() const&
    {
        if (!storage_.engaged_)
        {
            throw exception::BadOptionalAccessException(
                      exception::BadOptionalAccessException::BAD_OPTIONAL_ACCESS_MESSAGE_DEFAULT);
        }

        return storage_.val_;
    }

    T&& value() &&
    {
        if (!storage_.engaged_)
        {
            throw exception::BadOptionalAccessException(
                      exception::BadOptionalAccessException::BAD_OPTIONAL_ACCESS_MESSAGE_DEFAULT);
        }

        return std::move(storage_.val_);
    }

    const T&& value() const&&
    {
        if (!storage_.engaged_)
        {
            throw exception::BadOptionalAccessException(
                      exception::BadOptionalAccessException::BAD_OPTIONAL_ACCESS_MESSAGE_DEFAULT);
        }

        return std::move(storage_.val_);
    }

    bool has_value() const
    {
        return storage_.engaged_;
    }

    optional& operator =(
            const optional& opt)
    {
        reset();
        storage_.engaged_ = opt.storage_.engaged_;
        if (opt.storage_.engaged_)
        {
            ::new(&storage_.val_)T(opt.storage_.val_);
        }
        return *this;
    }

    optional& operator =(
            optional&& opt)
    {
        reset();
        storage_.engaged_ = opt.storage_.engaged_;
        if (opt.storage_.engaged_)
        {
            ::new(&storage_.val_)T(std::move(opt.storage_.val_));
        }
        return *this;
    }

    optional& operator =(
            const T& val)
    {
        reset();
        ::new(&storage_.val_)T(val);
        storage_.engaged_ = true;
        return *this;
    }

    optional& operator =(
            T&& val)
    {
        reset();
        ::new(&storage_.val_)T(std::move(val));
        storage_.engaged_ = true;
        return *this;
    }

    optional& operator = (
            nullopt_t) noexcept
    {
        reset();
        return *this;
    }

    bool operator ==(
            const optional& opt_val) const
    {
        return opt_val.storage_.engaged_ == storage_.engaged_ &&
               (storage_.engaged_ ? opt_val.storage_.val_ == storage_.val_ : true);
    }

    bool operator !=(
            const optional& opt_val) const
    {
        return !operator ==(opt_val);
    }

    T& operator *() & noexcept
    {
        return storage_.val_;
    }

    const T& operator *() const& noexcept
    {
        return storage_.val_;
    }

    T&& operator *() && noexcept
    {
        return std::move(storage_.val_);
    }

    const T&& operator *() const&& noexcept
    {
        return std::move(storage_.val_);
    }

    T* operator ->() noexcept
    {
        return std::addressof(storage_.val_);
    }

    const T* operator ->() const noexcept
    {
        return std::addressof(storage_.val_);
    }

    explicit operator bool() const noexcept
    {
        return storage_.engaged_;
    }

private:

    detail::optional_storage<T> storage_;
};

} // namespace fastcdr
} // namespace eprosima

#endif //_FASTCDR_XCDR_OPTIONAL_HPP_