nana/include/nana/pat/cloneable.hpp
2015-08-20 01:09:29 +08:00

210 lines
4.8 KiB
C++

/*
* A Generic Cloneable Pattern Implementation
* Nana C++ Library(http://www.nanapro.org)
* Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com)
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* @file: nana/pat/cloneable.hpp
* @description: A generic easy-to-use cloneable pattern implementation
*/
#ifndef NANA_PAT_CLONEABLE_HPP
#define NANA_PAT_CLONEABLE_HPP
#include <cstddef>
#include <type_traits>
#include <memory>
namespace nana{ namespace pat{
namespace detail
{
class cloneable_interface
{
public:
virtual ~cloneable_interface() = default;
virtual void * get() = 0;
virtual cloneable_interface* clone() const = 0;
virtual void self_delete() const = 0;
};
struct cloneable_interface_deleter
{
void operator()(cloneable_interface * p)
{
if (p)
p->self_delete();
}
};
template<typename T>
class cloneable_wrapper
: public cloneable_interface
{
public:
using value_type = T;
cloneable_wrapper() = default;
cloneable_wrapper(const value_type& obj)
:value_obj_(obj)
{}
cloneable_wrapper(value_type&& rv)
:value_obj_(std::move(rv))
{}
private:
//Implement cloneable_interface
virtual void* get() override
{
return &value_obj_;
}
virtual cloneable_interface* clone() const override
{
return (new cloneable_wrapper{ value_obj_ });
}
virtual void self_delete() const override
{
(delete this);
}
private:
value_type value_obj_;
};
}//end namespace detail
template<typename Base, bool Mutable = false>
class cloneable
{
using base_t = Base;
using cloneable_interface = detail::cloneable_interface;
using const_base_ptr = typename std::conditional<Mutable, base_t*, const base_t*>::type;
using const_base_ref = typename std::conditional<Mutable, base_t&, const base_t&>::type;
template<typename OtherBase, bool OtherMutable> friend class cloneable;
struct inner_bool
{
int true_stand;
};
typedef int inner_bool::* operator_bool_t;
template<typename U>
struct member_enabled
: public std::enable_if<(!std::is_base_of<cloneable, typename std::remove_reference<U>::type>::value) && std::is_base_of<base_t, typename std::remove_reference<U>::type>::value, int>
{};
public:
cloneable() = default;
cloneable(std::nullptr_t){}
template<typename T, typename member_enabled<T>::type* = nullptr>
cloneable(T&& t)
: cwrapper_(new detail::cloneable_wrapper<typename std::remove_cv<typename std::remove_reference<T>::type>::type>(std::forward<T>(t)), detail::cloneable_interface_deleter()),
fast_ptr_(reinterpret_cast<typename std::remove_cv<typename std::remove_reference<T>::type>::type*>(cwrapper_->get()))
{}
cloneable(const cloneable& r)
{
if(r.cwrapper_)
{
cwrapper_ = std::move(std::shared_ptr<cloneable_interface>(r.cwrapper_->clone(), detail::cloneable_interface_deleter{}));
fast_ptr_ = reinterpret_cast<base_t*>(cwrapper_->get());
}
}
cloneable(cloneable && r)
: cwrapper_(std::move(r.cwrapper_)),
fast_ptr_(r.fast_ptr_)
{
r.fast_ptr_ = nullptr;
}
template<typename OtherBase, typename std::enable_if<std::is_base_of<base_t, OtherBase>::value>::type* = nullptr>
cloneable(const cloneable<OtherBase, Mutable>& other)
{
if (other)
{
char* value_ptr = reinterpret_cast<char*>(other.cwrapper_->get());
char* base_ptr = reinterpret_cast<char*>(other.fast_ptr_);
auto ptr_diff = std::distance(base_ptr, value_ptr);
cwrapper_.reset(other.cwrapper_->clone(), detail::cloneable_interface_deleter{});
fast_ptr_ = reinterpret_cast<OtherBase*>(reinterpret_cast<char*>(cwrapper_->get()) - ptr_diff);
}
}
cloneable & operator=(const cloneable& r)
{
if((this != &r) && r.cwrapper_)
{
cwrapper_ = std::shared_ptr<cloneable_interface>(r.cwrapper_->clone(), detail::cloneable_interface_deleter());
fast_ptr_ = reinterpret_cast<base_t*>(cwrapper_->get());
}
return *this;
}
cloneable & operator=(cloneable&& r)
{
if(this != &r)
{
cwrapper_ = std::move(r.cwrapper_);
fast_ptr_ = r.fast_ptr_;
r.fast_ptr_ = nullptr;
}
return *this;
}
base_t& operator*()
{
return *fast_ptr_;
}
const_base_ref operator*() const
{
return *fast_ptr_;
}
base_t * operator->()
{
return fast_ptr_;
}
const_base_ptr operator->() const
{
return fast_ptr_;
}
base_t * get() const
{
return fast_ptr_;
}
void reset()
{
fast_ptr_ = nullptr;
cwrapper_.reset();
}
operator operator_bool_t() const volatile
{
return (fast_ptr_ ? &inner_bool::true_stand : nullptr);
}
private:
std::shared_ptr<cloneable_interface> cwrapper_;
base_t * fast_ptr_{nullptr};
};
template<typename T>
using mutable_cloneable = cloneable<T, true>;
}//end namespace pat
}//end namespace nana
#endif