Advertisement
sp2danny

Polymorphic Container

Nov 6th, 2015
297
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 16.17 KB | None | 0 0
  1.  
  2. #pragma once
  3.  
  4. #include <cstddef>
  5. #include <type_traits>
  6. #include <iterator>
  7. #include <vector>
  8. #include <cassert>
  9. #include <typeinfo>
  10. #include <functional>
  11.  
  12. // ---------------------------------------------------------------------------------------------------------------------
  13.  
  14. namespace library {
  15.  
  16. template< typename, template<typename...> class, template<typename...> class >
  17. class polymorphic_container;
  18.  
  19. namespace detail
  20. {
  21.  
  22.     template<typename T>
  23.     using clean = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
  24.  
  25.     template<typename,typename,typename>
  26.     struct iterator;
  27.  
  28.     template<typename T,typename underlying_iterator>
  29.     struct iterator_base
  30.     {
  31.         iterator_base() = default;
  32.         iterator_base& operator++() { ++iter; return *this; }
  33.         iterator_base& operator--() { --iter; return *this; }
  34.         iterator_base operator++(int) { iterator_base tmp = *this; ++iter; return tmp; }
  35.         iterator_base operator--(int) { iterator_base tmp = *this; --iter; return tmp; }
  36.         bool operator==(const iterator_base& other) const { return iter==other.iter; }
  37.         bool operator!=(const iterator_base& other) const { return iter!=other.iter; }
  38.         T& operator*() const { return *ptr(); }
  39.         T* operator->() const { return ptr(); };
  40.  
  41.     protected:
  42.         underlying_iterator iter;
  43.         iterator_base(underlying_iterator i) : iter(i) {}
  44.     private:
  45.         T* ptr() const { return (T*)iter->value; }
  46.  
  47.         template<typename,typename,typename>
  48.         friend struct iterator;
  49.  
  50.     };
  51.  
  52.     template<typename T,typename underlying_iterator,typename category>
  53.     struct iterator : std::iterator< category, T > , iterator_base<T,underlying_iterator>
  54.     {
  55.         iterator() = default;
  56.         iterator( const iterator_base<T,underlying_iterator>& ib )
  57.             : iterator_base<T,underlying_iterator>(ib.iter) {}
  58.  
  59.         using iterator_base<T,underlying_iterator>::iterator_base;
  60.  
  61.         template< typename, template<typename...> class, template<typename...> class >
  62.         friend class library::polymorphic_container;
  63.  
  64.         // if the underlying iterator can convert, support it
  65.         template<typename T2,typename UI2,typename C2>
  66.         operator iterator<T2,UI2,C2>() { return {this->iter}; }
  67.  
  68.         template<typename U,typename UI2,typename C2>
  69.         friend struct iterator;
  70.     };
  71.  
  72.     template<typename T,typename underlying_iterator>
  73.     struct iterator< T, underlying_iterator, std::random_access_iterator_tag >
  74.         : std::iterator< std::random_access_iterator_tag, T > , iterator_base<T,underlying_iterator>
  75.     {
  76.         iterator() = default;
  77.         iterator( const iterator_base<T,underlying_iterator>& ib )
  78.             : iterator_base<T,underlying_iterator>(ib.iter) {}
  79.  
  80.         using iterator_base<T,underlying_iterator>::iterator_base;
  81.  
  82.         iterator& operator+=(std::ptrdiff_t diff) { this->iter+=diff; return *this; }
  83.         iterator& operator-=(std::ptrdiff_t diff) { this->iter-=diff; return *this; }
  84.         iterator operator+(std::ptrdiff_t diff) { auto tmp = *this; tmp+=diff; return tmp; }
  85.         iterator operator-(std::ptrdiff_t diff) { auto tmp = *this; tmp-=diff; return tmp; }
  86.  
  87.         bool operator<(const iterator& other) const { return this->iter < other.iter; }
  88.         bool operator>(const iterator& other) const { return this->iter > other.iter; }
  89.         bool operator<=(const iterator& other) const { return this->iter <= other.iter; }
  90.         bool operator>=(const iterator& other) const { return this->iter >= other.iter; }
  91.  
  92.         T& operator[](std::size_t idx) const { return *this->iter[idx].value; }
  93.  
  94.         std::ptrdiff_t operator-(const iterator& other) const { return this->iter - other.iter; }
  95.  
  96.         template< typename, template<typename...> class, template<typename...> class >
  97.         friend class library::polymorphic_container;
  98.  
  99.         // if the underlying iterator can convert, support it
  100.         template<typename T2,typename UI2,typename C2>
  101.         operator iterator<T2,UI2,C2>() { return {this->iter}; }
  102.  
  103.         template<typename U,typename UI2,typename C2>
  104.         friend struct iterator;
  105.     };
  106.  
  107. }
  108.  
  109. // ---------------------------------------------------------------------------------------------------------------------
  110.  
  111. template<
  112.     typename T,
  113.     template<typename...> class Underlying = std::vector,
  114.     template<typename...> class Allocator = std::allocator
  115. >
  116. class polymorphic_container
  117. {
  118. private:
  119.     typedef std::function<T*(T*)> cloner_t;
  120.     typedef std::function<void(T*)> deleter_t;
  121.     struct Item
  122.     {
  123.         T* value = nullptr;
  124.         cloner_t cloner = nullptr;
  125.         deleter_t deleter = nullptr;
  126.  
  127.         Item() = default;
  128.         Item( const Item& other ) : Item() { copy(other); }
  129.         Item( Item&& other ) noexcept : Item() { swap(other); }
  130.         Item& operator=( const Item& other ) { clear(); copy(other); return *this; }
  131.         Item& operator=( Item&& other ) noexcept { clear(); swap(other); return *this; }
  132.         ~Item() { clear(); }
  133.         T& operator*() const;
  134.         void swap(Item&) noexcept;
  135.         void clear();
  136.  
  137.         bool operator <  (const Item& i) { return (*value) <  *i; }
  138.         bool operator <= (const Item& i) { return (*value) <= *i; }
  139.         bool operator >  (const Item& i) { return (*value) >  *i; }
  140.         bool operator >= (const Item& i) { return (*value) >= *i; }
  141.         bool operator == (const Item& i) { return (*value) == *i; }
  142.         bool operator != (const Item& i) { return (*value) != *i; }
  143.  
  144.     private:
  145.         void copy( const Item& );
  146.     };
  147.  
  148.     template<typename U>
  149.     cloner_t make_cloner();
  150.  
  151.     template<typename U>
  152.     deleter_t make_deleter();
  153.  
  154.     template<typename U>
  155.     static Allocator<U>& allocator()
  156.     {
  157.         static Allocator<U> a;
  158.         return a;
  159.     }
  160.  
  161.     typedef Underlying<Item,Allocator<Item>> underlying_container;
  162.     typedef typename underlying_container::iterator underlying_iterator;
  163.     typedef typename underlying_container::const_iterator underlying_const_iterator;
  164.     typedef typename std::iterator_traits< underlying_iterator >::iterator_category underlying_iterator_category;
  165.  
  166.     template<typename U>
  167.     struct sub_or_same
  168.     {
  169.         using CT = detail::clean<T>;
  170.         using CU = detail::clean<U>;
  171.         static const bool value =
  172.             std::is_base_of < CT, CU >::value ||
  173.             std::is_same    < CT, CU >::value ;
  174.     };
  175.  
  176.     static const bool underlying_swap_noexcept =
  177.         noexcept( std::declval<underlying_container&>() .swap( std::declval<underlying_container&>() ) );
  178. public:
  179.  
  180.     typedef std::size_t size_type;
  181.     typedef T value_type;
  182.     typedef T& reference;
  183.     typedef const T& const_reference;
  184.  
  185.     polymorphic_container() = default;
  186.     polymorphic_container(const polymorphic_container&) = default;
  187.     polymorphic_container(polymorphic_container&&) = default;
  188.  
  189.     polymorphic_container& operator=(const polymorphic_container&) = default;
  190.     polymorphic_container& operator=(polymorphic_container&&) = default;
  191.  
  192.     ~polymorphic_container() = default;
  193.  
  194.     void assign( const polymorphic_container& other ) { data.assign(other.data); }
  195.     void assign( polymorphic_container&& other ) noexcept(underlying_swap_noexcept) { data.swap(other.data); }
  196.  
  197.     void clear() { data.clear(); }
  198.     void swap( polymorphic_container&  other ) noexcept(underlying_swap_noexcept) { data.swap(other.data); }
  199.     void swap( polymorphic_container&& other ) noexcept(underlying_swap_noexcept) { data.swap(other.data); }
  200.  
  201.     size_type size() { return data.size(); }
  202.     bool empty() { return data.empty(); }
  203.  
  204.     typedef detail::iterator<T,underlying_iterator,underlying_iterator_category> iterator;
  205.     typedef detail::iterator<const T,underlying_const_iterator,underlying_iterator_category> const_iterator;
  206.  
  207.     iterator begin() { return { data.begin() }; }
  208.     iterator end()   { return { data.end()   }; }
  209.     const_iterator begin()  const { return { data.begin() }; }
  210.     const_iterator end()    const { return { data.end()   }; }
  211.     const_iterator cbegin() const { return { data.begin() }; }
  212.     const_iterator cend()   const { return { data.end()   }; }
  213.  
  214.     typedef std::reverse_iterator<iterator> reverse_iterator;
  215.     typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
  216.  
  217.     reverse_iterator rbegin() { return reverse_iterator{ end()   }; }
  218.     reverse_iterator rend()   { return reverse_iterator{ begin() }; }
  219.     const_reverse_iterator rbegin()  const { return const_reverse_iterator{ end()   }; }
  220.     const_reverse_iterator rend()    const { return const_reverse_iterator{ begin() }; }
  221.     const_reverse_iterator crbegin() const { return const_reverse_iterator{ end()   }; }
  222.     const_reverse_iterator crend()   const { return const_reverse_iterator{ begin() }; }
  223.  
  224. private:
  225.     template<typename U>
  226.     iterator explicit_insert( const_iterator, const U& );
  227.  
  228.     template<typename U>
  229.     iterator explicit_insert( const_iterator, U&& );
  230.  
  231. public:
  232.     template<typename U, typename = std::enable_if_t<sub_or_same<U>::value>>
  233.     iterator insert( const_iterator i, U&& u )
  234.     {
  235.         return explicit_insert< detail::clean<U> > ( i, std::forward<U>(u) );
  236.     }
  237.  
  238.     // can take over ownership of pointers, but user must supply cloner & deleter
  239.     iterator insert( const_iterator i, T* ptr, std::function<T*(T*)> cloner, std::function<void(T*)> deleter );
  240.  
  241.     template<typename U=T, typename... Args, typename = std::enable_if_t<sub_or_same<U>::value>>
  242.     iterator emplace( const_iterator, Args&&... );
  243.  
  244.     iterator erase( const_iterator i ) { return { data.erase(i.iter) }; }
  245.  
  246.     template<typename U, typename = std::enable_if_t<sub_or_same<U>::value>>
  247.     void push_back( U&& u )
  248.     { insert( end(), std::forward<U>(u) ); }
  249.  
  250.     template<typename U=T, typename... Args, typename = std::enable_if_t<sub_or_same<U>::value>>
  251.     void emplace_back( Args&&... args )
  252.     { emplace<U>( end(), std::forward<Args>(args)... ); }
  253.  
  254.     void pop_back() { erase(end()); }
  255.  
  256.     T& back() { return *data.back(); }
  257.     const T& back() const { return *data.back(); }
  258.  
  259.     T& front() { return *data.front(); }
  260.     const T& front() const { return *data.front(); }
  261.  
  262.     T& operator[](std::size_t idx)
  263.     {
  264.         static_assert(
  265.             std::is_same< underlying_iterator_category, std::random_access_iterator_tag >::value,
  266.             "underlying container does not support random access"
  267.         );
  268.         return begin()[idx];
  269.     }
  270.     const T& operator[](std::size_t idx) const
  271.     {
  272.         static_assert(
  273.             std::is_same< underlying_iterator_category, std::random_access_iterator_tag >::value,
  274.             "underlying container does not support random access"
  275.         );
  276.         return begin()[idx];
  277.     }
  278.  
  279. private:
  280.  
  281.     underlying_container data;
  282.  
  283. };
  284.  
  285. // ---------------------------------------------------------------------------------------------------------------------
  286.  
  287. template< typename T, template<typename...> class U, template<typename...> class A >
  288. void swap(polymorphic_container<T,U,A>& lhs, polymorphic_container<T, U, A>& rhs)
  289. {
  290.     lhs.swap(rhs);
  291. }
  292.  
  293. template< typename T, template<typename...> class U, template<typename...> class A >
  294. bool operator == (polymorphic_container<T, U, A>& lhs, polymorphic_container<T, U, A>& rhs)
  295. {
  296.     auto li = lhs.begin();
  297.     auto ri = rhs.begin();
  298.     while(true)
  299.     {
  300.         bool le = li==lhs.end();
  301.         bool re = ri==rhs.end();
  302.         if(le&&re) return true;
  303.         if(le||re) return false;
  304.         if( *li != *ri ) return false;
  305.         ++li; ++ri;
  306.     }
  307. }
  308.  
  309. template< typename T, template<typename...> class U, template<typename...> class A >
  310. bool operator != (polymorphic_container<T, U, A>& lhs, polymorphic_container<T, U, A>& rhs)
  311. {
  312.     return ! (lhs==rhs);
  313. }
  314.  
  315. template< typename T, template<typename...> class U, template<typename...> class A >
  316. bool operator < (polymorphic_container<T, U, A>& lhs, polymorphic_container<T, U, A>& rhs)
  317. {
  318.     auto li = lhs.begin();
  319.     auto ri = rhs.begin();
  320.     while(true)
  321.     {
  322.         bool le = li==lhs.end();
  323.         bool re = ri==rhs.end();
  324.         if(le&&re) return false;
  325.         if(le||re) return le;
  326.         if( *li < *ri ) return true;
  327.         if( *li > *ri ) return false;
  328.         ++li; ++ri;
  329.     }
  330. }
  331.  
  332. template< typename T, template<typename...> class U, template<typename...> class A >
  333. bool operator <= (polymorphic_container<T, U, A>& lhs, polymorphic_container<T, U, A>& rhs)
  334. {
  335.     auto li = lhs.begin();
  336.     auto ri = rhs.begin();
  337.     while(true)
  338.     {
  339.         bool le = li==lhs.end();
  340.         bool re = ri==rhs.end();
  341.         if(le&&re) return true;
  342.         if(le||re) return le;
  343.         if( *li < *ri ) return true;
  344.         if( *li > *ri ) return false;
  345.         ++li; ++ri;
  346.     }
  347. }
  348.  
  349. template< typename T, template<typename...> class U, template<typename...> class A >
  350. bool operator > (polymorphic_container<T, U, A>& lhs, polymorphic_container<T, U, A>& rhs)
  351. {
  352.     return ! (lhs<=rhs);
  353. }
  354.  
  355. template< typename T, template<typename...> class U, template<typename...> class A >
  356. bool operator >= (polymorphic_container<T, U, A>& lhs, polymorphic_container<T, U, A>& rhs)
  357. {
  358.     return ! (lhs<rhs);
  359. }
  360.  
  361. // ---------------------------------------------------------------------------------------------------------------------
  362.  
  363. template< typename T, template<typename...> class Underlying, template<typename...> class Allocator >
  364. void polymorphic_container<T,Underlying,Allocator>::Item::swap(Item& other) noexcept
  365. {
  366.     using std::swap;
  367.     swap(value, other.value);
  368.     swap(cloner, other.cloner);
  369.     swap(deleter, other.deleter);
  370. }
  371.  
  372. template< typename T, template<typename...> class Underlying, template<typename...> class Allocator >
  373. template<typename U>
  374. auto polymorphic_container<T,Underlying,Allocator>::make_cloner() -> cloner_t
  375. {
  376.     auto cloner = [](T* t) -> T*
  377.     {
  378.         U* space = allocator<U>().allocate(1);
  379.         U* item = (U*)t;
  380.         U* new_ptr = new (space) U(*item);
  381.         return (T*)new_ptr;
  382.     };
  383.     return cloner;
  384. }
  385.  
  386. template< typename T, template<typename...> class Underlying, template<typename...> class Allocator >
  387. template<typename U>
  388. auto polymorphic_container<T,Underlying,Allocator>::make_deleter() -> deleter_t
  389. {
  390.     auto deleter = [](T* t) -> void
  391.     {
  392.         U* item = (U*)t;
  393.         allocator<U>().deallocate(item,1);
  394.     };
  395.     return deleter;
  396. }
  397.  
  398. template< typename T, template<typename...> class Underlying, template<typename...> class Allocator >
  399. void polymorphic_container<T,Underlying,Allocator>::Item::clear()
  400. {
  401.     if(value)
  402.     {
  403.         assert(deleter);
  404.         deleter(value);
  405.     }
  406.     value = nullptr;
  407.     cloner = nullptr;
  408.     deleter = nullptr;
  409. }
  410.  
  411. template< typename T, template<typename...> class Underlying, template<typename...> class Allocator >
  412. void polymorphic_container<T,Underlying,Allocator>::Item::copy( const Item& other )
  413. {
  414.     if(other.value)
  415.     {
  416.         cloner = other.cloner;
  417.         deleter = other.deleter;
  418.         assert(cloner&&deleter);
  419.         value = cloner(other.value);
  420.     }
  421. }
  422.  
  423. template< typename T, template<typename...> class Underlying, template<typename...> class Allocator >
  424. auto polymorphic_container<T,Underlying,Allocator>::Item::operator*() const -> T&
  425. {
  426.     assert(value);
  427.     return *value;
  428. }
  429.  
  430. template< typename T, template<typename...> class Underlying, template<typename...> class Allocator >
  431. template<typename U>
  432. auto polymorphic_container<T,Underlying,Allocator>::explicit_insert( const_iterator i, const U& u ) -> iterator
  433. {
  434.     assert( (typeid(u) == typeid(U)) && "polymorphic_container need to know the exact type" );
  435.     U* space = allocator<U>().allocate(1);
  436.     U* value = new (space) U(u);
  437.     auto iter = data.emplace(i.iter);
  438.     iter->value = value;
  439.     iter->cloner = make_cloner<U>();
  440.     iter->deleter = make_deleter<U>();
  441.     return {iter};
  442. }
  443.  
  444. template< typename T, template<typename...> class Underlying, template<typename...> class Allocator >
  445. template<typename U>
  446. auto polymorphic_container<T,Underlying,Allocator>::explicit_insert( const_iterator i, U&& u ) -> iterator
  447. {
  448.     assert( (typeid(u) == typeid(U)) && "polymorphic_container need to know the exact type" );
  449.     U* space = allocator<U>().allocate(1);
  450.     U* value = new (space) U(std::move(u));
  451.     auto iter = data.emplace(i.iter);
  452.     iter->value = value;
  453.     iter->cloner = make_cloner<U>();
  454.     iter->deleter = make_deleter<U>();
  455.     return {iter};
  456. }
  457.  
  458. template< typename T, template<typename...> class Underlying, template<typename...> class Allocator >
  459. auto polymorphic_container<T,Underlying,Allocator>::insert(
  460.         const_iterator i, T* ptr, std::function<T*(T*)> cloner, std::function<void(T*)> deleter
  461.     ) -> iterator
  462. {
  463.     auto ui = data.emplace(i.iter);
  464.     ui->value = ptr;
  465.     ui->cloner = std::move(cloner);
  466.     ui->deleter = std::move(deleter);
  467.     return {ui};
  468. }
  469.  
  470. template< typename T, template<typename...> class Underlying, template<typename...> class Allocator >
  471. template<typename U, typename... Args, typename >
  472. auto polymorphic_container<T,Underlying,Allocator>::emplace( const_iterator i, Args&&... args ) -> iterator
  473. {
  474.     U* space = allocator<U>().allocate(1);
  475.     U* value = new (space) U( std::forward<Args>(args)... );
  476.     auto iter = data.emplace(i.iter);
  477.     iter->value = value;
  478.     iter->cloner = make_cloner<U>();
  479.     iter->deleter = make_deleter<U>();
  480.     return {iter};
  481. }
  482.  
  483. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement