Advertisement
sp2danny

clone_ptr

Jun 5th, 2015
423
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.15 KB | None | 0 0
  1. // A clone pointer template, that does not require the contained object to
  2. // have a clone method (but will use it if present).
  3. // (cc by) 2015 Daniel Nyström
  4.  
  5. #include <functional>
  6. #include <utility>
  7. #include <iostream>
  8. #include <type_traits>
  9.  
  10. template <typename T>
  11. struct has_clone
  12. {
  13.     typedef char (& yes)[1];
  14.     typedef char (& no)[2];
  15.  
  16.     template <typename C> static yes check(decltype(&C::clone));
  17.     template <typename> static no check(...);
  18.  
  19.     static bool const value = sizeof(check<T>(0)) == sizeof(yes);
  20. };
  21.  
  22. template<typename T> struct clone_ptr;
  23.  
  24. template<typename T, typename U=T, typename ...Ts>
  25. clone_ptr<T> make_cloned( Ts&& ...ts );
  26.  
  27. template<typename T>
  28. struct clone_ptr
  29. {
  30.     typedef T element_type;
  31.  
  32.     clone_ptr() noexcept : ptr(nullptr) , cloner(nullptr) {}
  33.     clone_ptr(clone_ptr&& other) noexcept
  34.         : clone_ptr()
  35.     {
  36.         swap( other );
  37.     }
  38.     clone_ptr(const clone_ptr& other)
  39.         : clone_ptr()
  40.     {
  41.         if( other )
  42.         {
  43.             cloner = other.cloner;
  44.             ptr = (T*)cloner(other.ptr);
  45.         }
  46.     }
  47.     void swap( clone_ptr& other ) noexcept
  48.     {
  49.         using std::swap;
  50.         swap( ptr,    other.ptr    );
  51.         swap( cloner, other.cloner );
  52.     }
  53.  
  54.     clone_ptr& operator=( clone_ptr copy ) noexcept
  55.     {
  56.         swap(copy);
  57.         return *this;
  58.     }
  59.  
  60.     clone_ptr& operator=( std::nullptr_t )
  61.     {
  62.         clear();
  63.         return *this;
  64.     }
  65.  
  66.     T* operator->()              { return ptr;  }
  67.     const T* operator->() const  { return ptr;  }
  68.     T& operator*()               { return *ptr; }
  69.     const T& operator*() const   { return *ptr; }
  70.  
  71.     explicit operator bool() const { return ptr != nullptr; }
  72.  
  73.     template<typename U, typename = typename std::enable_if< std::is_base_of<U,T>::value >::type >
  74.     operator clone_ptr<U>()
  75.     {
  76.         return clone_ptr<U>( (U*)cloner(ptr), cloner );
  77.     }
  78.  
  79.     bool operator<(const clone_ptr& other) const
  80.     {
  81.         bool have_self = ptr;
  82.         bool have_othr = other.ptr;
  83.         if( have_self && have_othr )
  84.             return (*ptr) < (*other.ptr);
  85.         else
  86.             return have_self < have_othr;
  87.     }
  88.     bool operator>(const clone_ptr& other) const
  89.     {
  90.         bool have_self = ptr;
  91.         bool have_othr = other.ptr;
  92.         if( have_self && have_othr )
  93.             return (*ptr) > (*other.ptr);
  94.         else
  95.             return have_self > have_othr;
  96.     }
  97.     bool operator==(const clone_ptr& other) const
  98.     {
  99.         bool have_self = ptr;
  100.         bool have_othr = other.ptr;
  101.         if( have_self && have_othr )
  102.             return (*ptr) == (*other.ptr);
  103.         else
  104.             return have_self == have_othr;
  105.     }
  106.  
  107.     bool operator!=(const clone_ptr& other) const { return ! ( other == *this ) ; }
  108.     bool operator<=(const clone_ptr& other) const { return ! ( other  < *this ) ; }
  109.     bool operator>=(const clone_ptr& other) const { return ! ( other  > *this ) ; }
  110.  
  111.     std::ostream& output( std::ostream& os, const char* null_ptr_msg = "<nullptr>" ) const
  112.     {
  113.         return ptr ? (os << *ptr) : (os << null_ptr_msg) ;
  114.     }
  115.  
  116.     void clear() { delete ptr; ptr=nullptr; cloner=nullptr; }
  117.     void reset() { clear(); }
  118.     T* get() const { return ptr; }
  119.  
  120.     ~clone_ptr() { clear(); }
  121.  
  122. private:
  123.  
  124.     template<typename T2=T, typename ...Ts>
  125.     typename std::enable_if< ! has_clone<T2>::value , void >::type
  126.     /*void*/ make( Ts&& ...ts )
  127.     {
  128.         clear();
  129.         ptr = new T2( std::forward<Ts>(ts)... );
  130.         cloner = [](void* p) -> void* { return new T2( * (T2*) p ); };
  131.     }
  132.  
  133.     template<typename T2=T, typename ...Ts>
  134.     typename std::enable_if<   has_clone<T2>::value , void >::type
  135.     /*void*/ make( Ts&& ...ts )
  136.     {
  137.         clear();
  138.         ptr = new T2( std::forward<Ts>(ts)... );
  139.         cloner = [](void* p) -> void* { return ((T2*)p)->clone(); };
  140.     }
  141.  
  142.     typedef std::function<void*(void*)> Func;
  143.  
  144.     T* ptr;
  145.     Func cloner;
  146.  
  147.     clone_ptr(T* ptr, Func cloner) : ptr(ptr), cloner(cloner) {}
  148.  
  149.     template<typename>
  150.     friend struct clone_ptr;
  151.  
  152.     template<typename T2, typename U, typename ...Ts>
  153.     friend clone_ptr<T2> make_cloned( Ts&& ...ts );
  154.  
  155. };
  156.  
  157. template<typename T, typename U, typename ...Ts>
  158. clone_ptr<T> make_cloned( Ts&& ...ts )
  159. {
  160.     static_assert( std::is_base_of<T,U>::value || std::is_same<T,U>::value, "make_cloned<T,T2>: cant convert T to U" );
  161.     clone_ptr<T> p;
  162.     p.template make<U>( std::forward<Ts>(ts)... );
  163.     return p;
  164. }
  165.  
  166. template<typename T>
  167. std::ostream& operator<<(std::ostream& os, const clone_ptr<T>& p) { return p.output(os); }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement