// // copy_ptr.hpp // pointers // // Created by Sam Jaffe on 12/6/16. // #pragma once #include #include "detail/compare.hpp" #include "pointer_fwd.hpp" namespace pointers { namespace detail { template using clone_func = T * (T::*)() const; template class value_ptr_copy; template struct value_ptr_copy::value>> { T * Copy(T * ptr) const { return ptr ? new T(*ptr) : nullptr; } }; #define POLYMORPHIC_VALUE_PTR_GROUP_FROM_CLONE_FUNCTION(fclone) \ template \ struct value_ptr_copy< \ T, std::enable_if_t< \ std::is_polymorphic::value && \ std::is_same, decltype(&T::fclone)>::value>> { \ T * Copy(T * ptr) const { return ptr ? ptr->fclone() : nullptr; } \ } POLYMORPHIC_VALUE_PTR_GROUP_FROM_CLONE_FUNCTION(Clone); POLYMORPHIC_VALUE_PTR_GROUP_FROM_CLONE_FUNCTION(clone); POLYMORPHIC_VALUE_PTR_GROUP_FROM_CLONE_FUNCTION(Copy); POLYMORPHIC_VALUE_PTR_GROUP_FROM_CLONE_FUNCTION(copy); } template class value_ptr : private detail::value_ptr_copy, public detail::pointer_compare> { public: using element_type = T; using pointer = element_type *; using reference = element_type &; value_ptr() noexcept : _ptr(nullptr) {} value_ptr(T * const & p) = delete; value_ptr(T *&& p) noexcept(std::is_nothrow_move_constructible::value) : _ptr(std::move(p)) {} value_ptr(value_ptr const & other) : _ptr(detail::value_ptr_copy::Copy(other._ptr)) {} value_ptr(value_ptr && other) noexcept(noexcept(std::swap(_ptr, other._ptr))) : _ptr(nullptr) { std::swap(_ptr, other._ptr); } static value_ptr copy_of(T * const & p) { return detail::value_ptr_copy().Copy(p); } template explicit operator value_ptr() const { return Copy(_ptr); } ~value_ptr() { delete _ptr; } value_ptr & operator=(value_ptr const & other) { swap(_ptr, value_ptr{other}._ptr); return *this; } value_ptr & operator=(value_ptr && other) noexcept { swap(_ptr, other._ptr); return *this; } operator bool() const noexcept { return static_cast(_ptr); } pointer get() const noexcept { return _ptr; } pointer operator->() const noexcept { return get(); } reference operator*() const noexcept { return *get(); } private: static void swap(T * a, T * b) { T * tmp = a; a = b; b = tmp; } T * _ptr; }; template value_ptr make_value(Args &&... args) { return value_ptr(new T(std::forward(args)...)); } }