clone_ptr.h

Back to Cloning pointer

pastel/sys/pointer/clone_ptr/

// Description: Cloning pointer

#ifndef PASTELSYS_CLONE_PTR_H
#define PASTELSYS_CLONE_PTR_H

#include "pastel/sys/pointer/clone_ptr/clone_ptr_concepts.h"
#include "pastel/sys/pointer/clone_ptr/clone_ptr_private.h"

#include <cstddef>
#include <memory>
#include <utility>

#include <boost/operators.hpp>

namespace Pastel
{

    /*
   Note: The code here follows closely to that in the paper
   "A Preliminary Proposal for a Deep-Copying Smart Pointer",
   Walter Bright, 2012, WG21/N3339 = PL22.16/12-0029.
   */

    template <
        typename Type_, 
        typename Cloner_ = typename ClonePtr_::Default_Cloner<Type_>::type, 
        typename Deleter_ = std::default_delete<Type_>>
    class ClonePtr
        : boost::less_than_comparable<ClonePtr<Type_, Cloner_, Deleter_>
        , boost::equality_comparable<ClonePtr<Type_, Cloner_, Deleter_>
        , boost::less_than_comparable2<ClonePtr<Type_, Cloner_, Deleter_>, std::nullptr_t
        , boost::equality_comparable2<ClonePtr<Type_, Cloner_, Deleter_>, std::nullptr_t
        > > > >
    {
    public:
        using Type = Type_;
        using Cloner = Cloner_;
        using Deleter = Deleter_;

    private:
        template<typename That>
        struct is_compatible
            : std::is_convertible<That*, Type*> 
        {
        };

    public:
        ClonePtr() 
            : data_(nullptr) 
        { 
        }

        ClonePtr(std::nullptr_t) 
            : data_(nullptr) 
        { 
        }

        template<typename That>
        explicit ClonePtr(That* that)
            : data_(that)
        {
            static_assert(
                is_compatible<That>::value,
                "ClonePtr's pointee type is incompatible.");

            static_assert(
                !std::is_polymorphic<Type>::value || 
                ClonePtr_::is_cloneable<Type>::value, 
                "ClonePtr's pointee type would slice on copying. "
                "Provide a clone() member function or remove polymorphism.");
        }

        ClonePtr(const ClonePtr& that )
            : data_(clone(that.data_))
        { 
        }

        template<typename That>
        ClonePtr(const  ClonePtr<That, Cloner, Deleter>& that
            , typename std::enable_if<is_compatible<That>::value>::type * = nullptr)
            : data_(clone(that.data_))
        { 
        }

        ClonePtr(ClonePtr&& that)
            : data_(that.release())
        { 
        }

        template<typename That>
        ClonePtr(ClonePtr<That, Cloner, Deleter>&& that,
            typename std::enable_if< is_compatible<That>::value>::type * = nullptr)
            : data_(that.release())
        { 
        }

        ~ClonePtr()
        { 
            reset(); 
        }

        void swap(ClonePtr& that) 
        { 
            std::swap(data_, that.data_); 
        }

        ClonePtr& operator=(std::nullptr_t)
        { 
            reset(nullptr); 
            return *this; 
        }

        ClonePtr& operator=(const ClonePtr& that)
        { 
            ClonePtr copy(that); 
            swap(copy); 
            return *this; 
        }

        template<typename That >
        typename std::enable_if<is_compatible<That>::value, ClonePtr&>::type
            operator=(const ClonePtr<That, Cloner, Deleter>& that)
        { 
            ClonePtr copy(that); 
            swap(copy); 
            return *this; 
        }

        ClonePtr& operator=(ClonePtr&& that)
        { 
            ClonePtr copy(std::move(that)); 
            swap(copy);
            return *this; 
        }        

        template<typename That >
        typename std::enable_if<is_compatible<That>::value, ClonePtr&>::type
            operator=(ClonePtr<That, Cloner, Deleter>&& that)
        { 
            ClonePtr copy(std::move(that)); 
            swap(copy); 
            return *this; 
        }

        bool operator<(const ClonePtr& that) const
        {
            return data_ < that.data_;
        }

        bool operator==(const ClonePtr& that) const
        {
            return data_ == that.data_;
        }

        bool operator<(std::nullptr_t) const
        {
            // data_ < nullptr;
            return false;
        }

        bool operator==(std::nullptr_t) const
        {
            return data_ == nullptr;
        }

        Type& operator*() const 
        { 
            return *get(); 
        }

        Type* operator->() const 
        { 
            return get(); 
        }

        Type* get() const 
        { 
            return data_; 
        }

        Type* release() 
        { 
            Type* old = data_; 
            data_ = nullptr; 
            return old; 
        }

        void reset(Type* that = nullptr) 
        {
            Deleter()(data_); 
            data_ = that;
        }

    private:
        template<typename That>
        Type* clone(const That* that) const
        { 
            return that ? Cloner()(*that) : nullptr; 
        }

        Type* data_;
    }; 

    template<typename Type, typename Cloner, typename Deleter>
    void swap(
        ClonePtr<Type,Cloner,Deleter> &left, 
        ClonePtr<Type,Cloner,Deleter> & right)
    { 
        left.swap(right); 
    }

}

#endif