unique_interface_ptr.h
// unique_interface_ptr.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2021
@import "IObject.h"
#include <memory>
/*
todo:
- std::unique_ptr<T,D> seems to allow the pointer type to be provided by the D.
Does that mean we can actually use std::unique_ptr<> to implement unique_interface_ptr<>?
- Do we need reflection of
gcroot<T*>
gcroot<ptr<I>>
std::optional<T>
std::variant
std::array
std::vector, std::deque, std::list, std::set, std::map
std::unique_ptr, std::shared_ptr
unique_interface_ptr<I>
shared_interface_ptr
- Unit test unique_interface_ptr<I>
- Illustrate how an application programmer might use a unique_interface_ptr<I>
- Does swap exist on ptr<T>?
- C++ has a named requirement called NullablePointer.
- EqualityComparable (must have == and this is an equivalence relation)
- DefaultConstructible (a public default constructor must be defined)
- CopyConstructible (T is MoveConstrictible AND T u=v, T(v) must be valid and have specified effects)
Is a ptr<T> a NullablePointer?
*/
namespace ceda
{
template <class T>
class unique_interface_ptr
{
public:
using pointer_type = ptr<T>;
using interface_type = T;
constexpr unique_interface_ptr() noexcept {}
constexpr unique_interface_ptr(nullptr_t) noexcept {}
unique_interface_ptr& operator=(nullptr_t) noexcept
{
reset();
return *this;
}
explicit unique_interface_ptr(pointer_type p) noexcept : ptr_(p) {}
unique_interface_ptr(unique_interface_ptr&& right) noexcept : ptr_(right.release()) {}
template <class T2, std::enable_if_t<std::is_convertible<typename unique_interface_ptr<T2>::pointer_type,pointer_type>::value, int> = 0>
unique_interface_ptr(unique_interface_ptr<T2> right) noexcept : ptr_(right.release()) {}
template <class T2, std::enable_if_t<std::is_convertible<typename unique_interface_ptr<T2>::pointer_type,pointer_type>::value, int> = 0>
unique_interface_ptr& operator=(unique_interface_ptr<T2>&& right) noexcept
{
reset(right.release());
return *this;
}
unique_interface_ptr& operator=(unique_interface_ptr&& right) noexcept
{
if (this != std::addressof(right))
{
reset(right.release());
}
return *this;
}
void swap(unique_interface_ptr& right) noexcept
{
using std::swap;
swap(ptr_, right.ptr_);
}
~unique_interface_ptr() noexcept
{
if (ptr_)
{
ptr_->Destroy();
}
}
[[nodiscard]] std::add_lvalue_reference_t<T> operator*() const noexcept
{
return *ptr_;
}
[[nodiscard]] pointer_type operator->() const noexcept
{
return ptr_;
}
[[nodiscard]] pointer_type get() const noexcept
{
return ptr_;
}
explicit operator bool() const noexcept
{
return static_cast<bool>(ptr_);
}
pointer_type release() noexcept
{
return std::exchange(ptr_, nullptr);
}
void reset(pointer_type p = nullptr) noexcept
{
pointer_type prev = std::exchange(ptr_, p);
if (prev)
{
prev->Destroy();
}
}
unique_interface_ptr(const unique_interface_ptr&) = delete;
unique_interface_ptr& operator=(const unique_interface_ptr&) = delete;
private:
template <class>
friend class unique_interface_ptr;
pointer_type ptr_;
};
template <class T, class X, class... _Types>
[[nodiscard]] unique_interface_ptr<T> make_unique_interface_ptr(_Types&&... _Args)
{
return unique_interface_ptr<T>(new X(std::forward<_Types>(_Args)...));
}
template <class T>
void swap(unique_interface_ptr<T>& left, unique_interface_ptr<T>& right) noexcept
{
left.swap(right);
}
template <class _Ty1, class _Ty2>
[[nodiscard]] bool operator==(const unique_interface_ptr<_Ty1>& left, const unique_interface_ptr<_Ty2>& right)
{
return left.get() == right.get();
}
template <class _Ty1, class _Ty2>
[[nodiscard]] bool operator!=(const unique_interface_ptr<_Ty1>& left, const unique_interface_ptr<_Ty2>& right)
{
return !(left == right);
}
template <class _Ty1, class _Ty2>
[[nodiscard]] bool operator<(const unique_interface_ptr<_Ty1>& left, const unique_interface_ptr<_Ty2>& right)
{
using _Ptr1 = typename unique_interface_ptr<_Ty1>::pointer_type;
using _Ptr2 = typename unique_interface_ptr<_Ty2>::pointer_type;
using _Common = std::common_type_t<_Ptr1, _Ptr2>;
return std::less<_Common>{}(left.get(), right.get());
}
template <class _Ty1, class _Ty2>
[[nodiscard]] bool operator>=(const unique_interface_ptr<_Ty1>& left, const unique_interface_ptr<_Ty2>& right)
{
return !(left < right);
}
template <class _Ty1, class _Ty2>
[[nodiscard]] bool operator>(const unique_interface_ptr<_Ty1>& left, const unique_interface_ptr<_Ty2>& right)
{
return right < left;
}
template <class _Ty1, class _Ty2>
[[nodiscard]] bool operator<=(const unique_interface_ptr<_Ty1>& left, const unique_interface_ptr<_Ty2>& right)
{
return !(right < left);
}
template <class T>
[[nodiscard]] bool operator==(const unique_interface_ptr<T>& left, nullptr_t) noexcept
{
return !left;
}
template <class T>
[[nodiscard]] bool operator==(nullptr_t, const unique_interface_ptr<T>& right) noexcept
{
return !right;
}
template <class T>
[[nodiscard]] bool operator!=(const unique_interface_ptr<T>& left, nullptr_t right) noexcept
{
return !(left == right);
}
template <class T>
[[nodiscard]] bool operator!=(nullptr_t left, const unique_interface_ptr<T>& right) noexcept
{
return !(left == right);
}
template <class T>
[[nodiscard]] bool operator<(const unique_interface_ptr<T>& left, nullptr_t right)
{
using _Ptr = typename unique_interface_ptr<T>::pointer_type;
return std::less<_Ptr>{}(left.get(), right);
}
template <class T>
[[nodiscard]] bool operator<(nullptr_t left, const unique_interface_ptr<T>& right)
{
using _Ptr = typename unique_interface_ptr<T>::pointer_type;
return std::less<_Ptr>{}(left, right.get());
}
template <class T>
[[nodiscard]] bool operator>=(const unique_interface_ptr<T>& left, nullptr_t right)
{
return !(left < right);
}
template <class T>
[[nodiscard]] bool operator>=(nullptr_t left, const unique_interface_ptr<T>& right)
{
return !(left < right);
}
template <class T>
[[nodiscard]] bool operator>(const unique_interface_ptr<T>& left, nullptr_t right)
{
return right < left;
}
template <class T>
[[nodiscard]] bool operator>(nullptr_t left, const unique_interface_ptr<T>& right)
{
return right < left;
}
template <class T>
[[nodiscard]] bool operator<=(const unique_interface_ptr<T>& left, nullptr_t right)
{
return !(right < left);
}
template <class T>
[[nodiscard]] bool operator<=(nullptr_t left, const unique_interface_ptr<T>& right)
{
return !(right < left);
}
template <class Elem, class Traits, class T>
std::basic_ostream<Elem, Traits>& operator<<(std::basic_ostream<Elem, Traits>& os, const unique_interface_ptr<T>& p)
{
os << p.get();
return os;
}
} // namespace ceda