blob: ef93263b488733e32bb65ef57da6f1ccd72e4a8c [file] [log] [blame]
#pragma once
#include <optional>
#include <stdplus/handle/managed.hpp>
#include <type_traits>
#include <utility>
namespace stdplus
{
/** @brief Similar to the Managed Handle, but also allows for copying
* and performs an operation during that copy.
*/
template <typename T, typename... As>
struct Copyable
{
template <void (*drop)(T&&, As&...), T (*ref)(const T&, As&...)>
class Handle : public Managed<T, As...>::template Handle<drop>
{
public:
using MHandle = typename Managed<T, As...>::template Handle<drop>;
/** @brief Creates a handle referencing the object
*
* @param[in] maybeV - Optional object being managed
*/
template <typename... Vs>
constexpr explicit Handle(const std::optional<T>& maybeV, Vs&&... vs) :
MHandle(std::nullopt, std::forward<Vs>(vs)...)
{
reset(maybeV);
}
template <typename... Vs>
constexpr explicit Handle(const T& maybeV, Vs&&... vs) :
MHandle(std::nullopt, std::forward<Vs>(vs)...)
{
reset(maybeV);
}
/** @brief Creates a handle owning the object
*
* @param[in] maybeV - Maybe the object being managed
*/
template <typename... Vs>
constexpr explicit Handle(std::optional<T>&& maybeV, Vs&&... vs) :
MHandle(std::move(maybeV), std::forward<Vs>(vs)...)
{
}
template <typename... Vs>
constexpr explicit Handle(T&& maybeV, Vs&&... vs) :
MHandle(std::move(maybeV), std::forward<Vs>(vs)...)
{
}
constexpr Handle(const Handle& other) : MHandle(std::nullopt, other.as)
{
reset(other.maybe_value());
}
constexpr Handle(Handle&& other) noexcept(
std::is_nothrow_move_constructible_v<MHandle>) :
MHandle(std::move(other))
{
}
constexpr Handle& operator=(const Handle& other)
{
if (this != &other)
{
reset();
this->as = other.as;
reset(other.maybe_value());
}
return *this;
}
constexpr Handle& operator=(Handle&& other)
{
MHandle::operator=(std::move(other));
return *this;
}
using MHandle::reset;
/** @brief Resets the managed value to a new value
* Takes a new reference on the value
*
* @param[in] maybeV - Maybe the new value
*/
constexpr void reset(const std::optional<T>& maybeV)
{
if (maybeV)
{
reset(doRef(*maybeV, std::index_sequence_for<As...>()));
}
else
{
reset(std::nullopt);
}
}
constexpr void reset(const T& maybeV)
{
reset(doRef(maybeV, std::index_sequence_for<As...>()));
}
private:
template <size_t... Indices>
T doRef(const T& v, std::index_sequence<Indices...>)
{
return ref(v, std::get<Indices>(this->as)...);
}
};
};
} // namespace stdplus