From 5430e3fcfba99581ff2b58d8e9671158a979951a Mon Sep 17 00:00:00 2001 From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz> Date: Wed, 18 Apr 2018 22:39:16 +0200 Subject: [PATCH] introduce ptr_vector --- alib2std/src/alib/ptr_vector | 1 + alib2std/src/extensions/ptr_vector.hpp | 436 ++++++++++++++++++ .../test-src/extensions/PtrVectorTest.cpp | 79 ++++ alib2std/test-src/extensions/PtrVectorTest.h | 73 +++ 4 files changed, 589 insertions(+) create mode 100644 alib2std/src/alib/ptr_vector create mode 100644 alib2std/src/extensions/ptr_vector.hpp create mode 100644 alib2std/test-src/extensions/PtrVectorTest.cpp create mode 100644 alib2std/test-src/extensions/PtrVectorTest.h diff --git a/alib2std/src/alib/ptr_vector b/alib2std/src/alib/ptr_vector new file mode 100644 index 0000000000..cd12220a0e --- /dev/null +++ b/alib2std/src/alib/ptr_vector @@ -0,0 +1 @@ +#include <extensions/ptr_vector.hpp> diff --git a/alib2std/src/extensions/ptr_vector.hpp b/alib2std/src/extensions/ptr_vector.hpp new file mode 100644 index 0000000000..9234646a4d --- /dev/null +++ b/alib2std/src/extensions/ptr_vector.hpp @@ -0,0 +1,436 @@ +/* + * ptr_vector.hpp + * + * Created on: Feb 28, 2014 + * Author: Jan Travnicek + */ + +#ifndef __PTR_VECTOR_HPP_ +#define __PTR_VECTOR_HPP_ + +#include <vector> +#include <ostream> +#include <sstream> +#include <string> + +#include "compare.hpp" +#include "allocFix.hpp" +#include "iterator.hpp" +#include "clone.hpp" + +namespace ext { + +template < class T > +class ptr_vector { + std::vector < T * > m_data; + +public: + + using value_type = T; + + using size_type = std::size_t; + using diference_type = std::ptrdiff_t; + + using reference = value_type &; + using const_reference = const value_type &; + using pointer = T *; + using const_pointer = T * const; + + using iterator = dereferencing_iterator < typename std::vector < T * >::iterator >; + using const_iterator = dereferencing_iterator < typename std::vector < T * >::const_iterator >; + + using reverse_iterator = dereferencing_iterator < typename std::vector < T * >::reverse_iterator >; + using const_reverse_iterator = dereferencing_iterator < typename std::vector < T * >::const_reverse_iterator >; + + ptr_vector ( ) noexcept { + } + + template < class R > + ptr_vector ( std::initializer_list < R > init ) { + insert ( cbegin ( ), std::move ( init ) ); + } + + ptr_vector ( std::initializer_list < T * > init ) : m_data ( init ) { + } + + explicit ptr_vector ( size_type count ) { + resize ( count ); + } + + template < class InputIt > + ptr_vector ( InputIt first, InputIt last ) { + insert ( cbegin ( ), first, last ); + } + + ptr_vector ( size_type count, const T& value ) { + insert ( cbegin ( ), count, value ); + } + + ptr_vector ( const ptr_vector& other ) { + insert ( cbegin ( ), other.begin ( ), other.end ( ) ); + } + + ptr_vector ( ptr_vector && other ) noexcept { + std::swap ( m_data, other.m_data ); + } + + ~ptr_vector ( ) noexcept { + clear ( ); + } + + ptr_vector < T > & operator = ( const ptr_vector < T > & other ) { + if ( this == & other ) + return * this; + + clear ( ); + insert ( cbegin ( ), other.begin ( ), other.end ( ) ); + + return *this; + } + + ptr_vector < T > & operator = ( ptr_vector < T > && other ) noexcept { + std::swap ( m_data, other.m_data ); + + return *this; + } + + void assign ( size_type count, const T& value ) { + clear ( ); + insert ( cbegin ( ), count, value ); + } + + template< class InputIt > + void assign ( InputIt first, InputIt last ) { + clear ( ); + insert ( cbegin ( ), first, last ); + } + + template < class R > + void assign ( std::initializer_list < R > ilist ) { + clear ( ); + insert ( cbegin ( ), std::move ( ilist ) ); + } + + reference at ( size_type index ) { + return * m_data.at ( index ); + } + + const_reference at ( size_type index ) const { + return * m_data.at ( index ); + } + + reference operator [ ] ( size_type index ) { + return * m_data [ index ]; + } + + const_reference operator [ ] ( size_type index ) const { + return * m_data [ index ]; + } + + reference front ( ) { + return * m_data.front ( ); + } + + const_reference front ( ) const { + return * m_data.front ( ); + } + + reference back ( ) { + return * m_data.back ( ); + } + + const_reference back ( ) const { + return * m_data.back ( ); + } + + bool null ( size_type index ) const { + return m_data.at ( index ) == NULL; + } + + /* T * const * data ( ) noexcept { + return m_data.data ( ); + } + + T const * const * data ( ) const noexcept { + return m_data.data ( ); + } */ + + iterator begin ( ) noexcept { + return dereferencer ( m_data.begin ( ) ); + } + + const_iterator begin ( ) const noexcept { + return dereferencer ( m_data.begin ( ) ); + } + + const_iterator cbegin ( ) const noexcept { + return dereferencer ( m_data.cbegin ( ) ); + } + + iterator end ( ) noexcept { + return dereferencer ( m_data.end ( ) ); + } + + const_iterator end ( ) const noexcept { + return dereferencer ( m_data.end ( ) ); + } + + const_iterator cend ( ) const noexcept { + return dereferencer ( m_data.cend ( ) ); + } + + reverse_iterator rbegin ( ) noexcept { + return dereferencer ( m_data.rbegin ( ) ); + } + + const_reverse_iterator rbegin ( ) const noexcept { + return dereferencer ( m_data.rbegin ( ) ); + } + + const_reverse_iterator crbegin ( ) const noexcept { + return dereferencer ( m_data.crbegin ( ) ); + } + + reverse_iterator rend ( ) noexcept { + return dereferencer ( m_data.rend ( ) ); + } + + const_reverse_iterator rend ( ) const noexcept { + return dereferencer ( m_data.rend ( ) ); + } + + const_reverse_iterator crend ( ) const noexcept { + return dereferencer ( m_data.crend ( ) ); + } + + bool empty ( ) const noexcept { + return m_data.empty ( ); + } + + size_type size ( ) const noexcept { + return m_data.size ( ); + } + + size_type max_size ( ) const noexcept { + return m_data.max_size ( ); + } + + void reserve ( size_type new_cap ) { + m_data.reserve ( new_cap ); + } + + size_type capacity ( ) const noexcept { + return m_data.capacity ( ); + } + + void shrink_to_fit ( ) { + m_data.shrink_to_fit ( ); + } + + void clear ( ) noexcept { + for ( T * data : m_data ) { + delete data; + } + m_data.clear ( ); + } + + template < class R > + iterator set ( const_iterator pos, R && value ) { + m_data.at ( std::distance ( cbegin ( ), pos ) ) = ext::clone ( std::forward < R > ( value ) ); + return dereferencer ( m_data.begin ( ) + std::distance ( cbegin ( ), pos ) ); + } + + template < class R > + iterator set ( const_iterator pos, T * value ) { + m_data.at ( std::distance ( cbegin ( ), pos ) ) = value ; + return dereferencer ( m_data.begin ( ) + std::distance ( cbegin ( ), pos ) ); + } + + template < class R, class ... Args > + iterator emplace_set ( const_iterator pos, Args && ... args ) { + m_data.at ( std::distance ( cbegin ( ), pos ) ) = new R ( std::forward < Args > ( args ) ... ) ; + return dereferencer ( m_data.begin ( ) + std::distance ( cbegin ( ), pos ) ); + } + + template < class R > + iterator insert ( const_iterator pos, R && value ) { + return dereferencer ( m_data.insert ( pos.base ( ), ext::clone ( std::forward < R > ( value ) ) ) ); + } + + template < class R > + iterator insert ( const_iterator pos, size_type count, const R & value ) { + iterator res = dereferencer ( m_data.insert ( pos.base ( ), count, NULL ) ); + for ( size_type i = 0; i < count; ++ i ) { + * ( res.base ( ) + i ) = ext::clone ( value ); + } + return res; + } + + template < class InputIt > + iterator insert ( const_iterator pos, InputIt first, InputIt last ) { + size_type size = std::distance ( first, last ); + iterator res = dereferencer ( m_data.insert ( pos.base ( ), size, NULL ) ); + + for ( size_type i = 0; i < size; ++ first, ++ i ) + * ( res.base ( ) + i ) = ext::clone ( * first ); + + return res; + } + + template < class R > + iterator insert ( const_iterator pos, std::initializer_list < R > ilist ) { + return insert ( pos, ilist.begin ( ), ilist.end ( ) ); + } + + template < class R > + iterator insert ( const_iterator pos, T * value ) { + return m_data.insert ( pos.base ( ), value ); + } + + template < class R, class ... Args > + iterator emplace ( const_iterator pos, Args && ... args ) { + return dereferencer ( m_data.insert ( pos.base ( ), new R ( std::forward < Args > ( args ) ... ) ) ); + } + + iterator erase ( const_iterator pos ) { + delete * pos.base ( ); + return dereferencer ( m_data.erase ( pos.base ( ) ) ); + } + + iterator erase ( const_iterator first, const_iterator last ) { + for ( const_iterator first_copy = first; first_copy != last; ++ first_copy ) { + delete * first_copy.base ( ); + } + return dereferencer ( m_data.erase ( first.base ( ), last.base ( ) ) ); + } + + template < class R > + void push_back ( R && value ) { + insert ( cend ( ), std::forward < R > ( value ) ); + } + + template < class ... Args > + reference emplace_back ( Args && ... args ) { + return * emplace ( cend ( ), std::forward < Args > ( args ) ... ); + } + + void pop_back ( ) { + T * value = m_data.back ( ); + delete value; + m_data.pop_back ( ); + } + + void resize ( size_type count ) { + for ( size_type i = count; i < m_data.size ( ); ++ i ) { + delete m_data [ i ]; + } + size_type i = m_data.size ( ); + m_data.resize ( count ); + for ( ; i < count; ++ i ) { + m_data [ i ] = NULL; + } + } + + template < class R > + void resize ( size_type count, const R & value ) { + for ( size_type i = count; i < m_data.size ( ); ++ i ) { + delete m_data [ i ]; + } + size_type i = m_data.size ( ); + m_data.resize ( count ); + for ( ; i < count; ++ i ) { + m_data [ i ] = ext::clone ( value ); + } + } + + void swap ( ptr_vector & other ) { + std::swap ( this->m_data, other.m_data ); + } + +}; + +} /* namespace ext */ + +namespace std { + +template < class ... Ts > +void swap ( ext::ptr_vector < Ts ... > & first, ext::ptr_vector < Ts ... > & second ) { + first.swap ( second ); +} + +} /* namespace std */ + +namespace ext { + +template< class T > +std::ostream& operator<<(std::ostream& out, const ext::ptr_vector < T > & ptr_vector) { + out << "["; + + bool first = true; + for(const T& item : ptr_vector) { + if(!first) out << ", "; + first = false; + out << item; + } + + out << "]"; + return out; +} + +template<class T > +struct compare < ext::ptr_vector < T > > { + int operator()(const ext::ptr_vector < T >& first, const ext::ptr_vector < T > & second) const { + if(first.size() < second.size()) return -1; + if(first.size() > second.size()) return 1; + + static compare<typename std::decay < T >::type > comp; + for(auto iterF = first.begin(), iterS = second.begin(); iterF != first.end(); ++iterF, ++iterS) { + int res = comp(*iterF, *iterS); + if(res != 0) return res; + } + return 0; + } +}; + +template < class T > +std::string to_string ( const ext::ptr_vector < T > & value ) { + std::stringstream ss; + ss << value; + return ss.str(); +} + +template < class T > +bool operator == ( const ptr_vector < T > & first, const ptr_vector < T > & second ) { + static compare < ptr_vector < T > > comp; + return comp ( first, second ) == 0; +} + +template < class T > +bool operator != ( const ptr_vector < T > & first, const ptr_vector < T > & second ) { + return ! ( first == second ); +} + +template < class T > +bool operator < ( const ptr_vector < T > & first, const ptr_vector < T > & second ) { + static compare < ptr_vector < T > > comp; + return comp ( first, second ) < 0; +} + +template < class T > +bool operator > ( const ptr_vector < T > & first, const ptr_vector < T > & second ) { + return second < first; +} + +template < class T > +bool operator <= ( const ptr_vector < T > & first, const ptr_vector < T > & second ) { + return ! ( first > second ); +} + +template < class T > +bool operator >= ( const ptr_vector < T > & first, const ptr_vector < T > & second ) { + return ! ( first < second ); +} + +} /* namespace ext */ + +#endif /* __PTR_VECTOR_HPP_ */ diff --git a/alib2std/test-src/extensions/PtrVectorTest.cpp b/alib2std/test-src/extensions/PtrVectorTest.cpp new file mode 100644 index 0000000000..ca07959f7b --- /dev/null +++ b/alib2std/test-src/extensions/PtrVectorTest.cpp @@ -0,0 +1,79 @@ +#include "PtrVectorTest.h" +#include <alib/ptr_vector> +#include <alib/algorithm> + +CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( PtrVectorTest, "bits" ); +CPPUNIT_TEST_SUITE_REGISTRATION( PtrVectorTest ); + +void PtrVectorTest::setUp() { +} + +void PtrVectorTest::tearDown() { +} + +void PtrVectorTest::testProperties() { + ext::ptr_vector < int > data = {1, 2, 3, 4}; + + std::cout << data [ 0 ] << std::endl; + + CPPUNIT_ASSERT ( data [ 0 ] == 1 ); + CPPUNIT_ASSERT ( data.size ( ) == 4 ); + CPPUNIT_ASSERT ( data [ 3 ] == 4 ); + + data.push_back ( 1 ); + CPPUNIT_ASSERT ( data.size ( ) == 5 ); + CPPUNIT_ASSERT ( data [ 4 ] == 1 ); + + data.insert ( data.cbegin ( ) + 1, 2 ); + CPPUNIT_ASSERT ( data.size ( ) == 6 ); + CPPUNIT_ASSERT ( data [ 1 ] == 2 ); + CPPUNIT_ASSERT ( data [ 2 ] == 2 ); + CPPUNIT_ASSERT ( data [ 3 ] == 3 ); +} + +void PtrVectorTest::testPolymorph() { + ext::ptr_vector < Base > data = { Child2 ( ) }; + + CPPUNIT_ASSERT ( data [ 0 ].type ( ) == PtrVectorTest::Type::CHILD2 ); + CPPUNIT_ASSERT ( data.size ( ) == 1 ); + + data.push_back ( Child1 ( ) ); + CPPUNIT_ASSERT ( data.size ( ) == 2 ); + CPPUNIT_ASSERT ( data [ 1 ].type ( ) == PtrVectorTest::Type::CHILD1 ); + + ext::ptr_vector < Base >::const_iterator iter = data.cbegin ( ); + CPPUNIT_ASSERT ( iter->type ( ) == PtrVectorTest::Type::CHILD2 ); + ++ iter; + CPPUNIT_ASSERT ( iter->type ( ) == PtrVectorTest::Type::CHILD1 ); + ++ iter; + CPPUNIT_ASSERT ( iter == data.cend ( ) ); + + data.insert ( data.cbegin ( ) + 1, Child1 ( ) ); + CPPUNIT_ASSERT ( data.size ( ) == 3 ); + CPPUNIT_ASSERT ( data [ 0 ].type ( ) == PtrVectorTest::Type::CHILD2 ); + CPPUNIT_ASSERT ( data [ 1 ].type ( ) == PtrVectorTest::Type::CHILD1 ); + CPPUNIT_ASSERT ( data [ 2 ].type ( ) == PtrVectorTest::Type::CHILD1 ); + + data.resize ( 4 ); + CPPUNIT_ASSERT ( data.null ( 3 ) ); + data.resize ( 3 ); + + ext::ptr_vector < Base > data2 = data; + + CPPUNIT_ASSERT ( data2 [ 0 ].type ( ) == PtrVectorTest::Type::CHILD2 ); + CPPUNIT_ASSERT ( data2 [ 1 ].type ( ) == PtrVectorTest::Type::CHILD1 ); + CPPUNIT_ASSERT ( data2 [ 2 ].type ( ) == PtrVectorTest::Type::CHILD1 ); + + auto iter2 = data2.insert ( data2.cbegin ( ) + 1, data.begin ( ), data.end ( ) ); + + CPPUNIT_ASSERT ( iter2 == data2.begin ( ) + 1 ); + + CPPUNIT_ASSERT ( data2 [ 0 ].type ( ) == PtrVectorTest::Type::CHILD2 ); + CPPUNIT_ASSERT ( data2 [ 1 ].type ( ) == PtrVectorTest::Type::CHILD2 ); + CPPUNIT_ASSERT ( data2 [ 2 ].type ( ) == PtrVectorTest::Type::CHILD1 ); + CPPUNIT_ASSERT ( data2 [ 3 ].type ( ) == PtrVectorTest::Type::CHILD1 ); + CPPUNIT_ASSERT ( data2 [ 4 ].type ( ) == PtrVectorTest::Type::CHILD1 ); + CPPUNIT_ASSERT ( data2 [ 5 ].type ( ) == PtrVectorTest::Type::CHILD1 ); + + data2.erase ( ext::dereferencer ( ext::unique ( data2.begin ( ).base ( ), data2.end ( ).base ( ), [ ] ( const Base * a, const Base * b ) { return * a == * b; } ) ), data2.end ( ) ); +} diff --git a/alib2std/test-src/extensions/PtrVectorTest.h b/alib2std/test-src/extensions/PtrVectorTest.h new file mode 100644 index 0000000000..eefdd25411 --- /dev/null +++ b/alib2std/test-src/extensions/PtrVectorTest.h @@ -0,0 +1,73 @@ +#ifndef PTR_VECTOR_TEST_H_ +#define PTR_VECTOR_TEST_H_ + +#include <cppunit/extensions/HelperMacros.h> +#include <alib/compare> + +class PtrVectorTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE( PtrVectorTest ); + CPPUNIT_TEST( testProperties ); + CPPUNIT_TEST( testPolymorph ); + CPPUNIT_TEST_SUITE_END(); + + enum class Type { + CHILD1, + CHILD2 + }; + + class Base { + public: + virtual ~Base ( ) { + } + + virtual Base * clone ( ) const = 0; + virtual Base * plunder ( ) && = 0; + + virtual Type type ( ) const = 0; + + bool operator == ( const PtrVectorTest::Base & other ) const { + return this->type ( ) == other.type ( ); + } + + }; + + class Child1 : public Base { + public: + virtual Base * clone ( ) const { + return new Child1 ( * this ); + } + + virtual Base * plunder ( ) && { + return new Child1 ( * this ); + } + + virtual Type type ( ) const { + return Type::CHILD1; + } + }; + + class Child2 : public Base { + public: + virtual Base * clone ( ) const { + return new Child2 ( * this ); + } + + virtual Base * plunder ( ) && { + return new Child2 ( * this ); + } + + virtual Type type ( ) const { + return Type::CHILD2; + } + }; + +public: + void setUp(); + void tearDown(); + + void testProperties(); + void testPolymorph(); +}; + +#endif // PTR_VECTOR_TEST_H_ -- GitLab