commit 3d499e3c0412d4fb75ee7e095644eca356017dfc
parent bf87fa7b393dd0f95c253726ee11b7cb0a6bb3d2
Author: Morel BĂ©renger <berengermorel76@gmail.com>
Date: Wed, 12 Aug 2020 20:45:58 +0200
vector improvements
Added:
* const_iterator
* value_type
* empty()
* capacity()
* all constructors are now explicitly defined
* rbegin()/rend()/front(), all const and non-const
* push_back(), move and copy
* pop_back()
Changed:
* assign() now uses const_iterator
* destructor is now virtual (this reduce compat with STL when
inheritance is used, which should anyway always be avoided, but it's
convenient to be able to do that sometimes, and there is no good
reason to prevent it. STL actually encourages bugs by not making it
"final")
* debug build uses stdio
Diffstat:
M | btl/src/vector.hpp | | | 225 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- |
1 file changed, 220 insertions(+), 5 deletions(-)
diff --git a/btl/src/vector.hpp b/btl/src/vector.hpp
@@ -2,6 +2,15 @@
#define VECTOR_HPP
#ifndef WITH_STL
+
+#ifndef NDEBUG
+#include <stdio.h>
+#endif
+
+//methods return true on error
+//public API should rely as much as possible on private API:
+//no need to pile useless calls: this just makes debug harder
+//code should never throw
template <typename T>
class vector
{
@@ -14,24 +23,52 @@ class vector
bool construct( size_t new_size );
public:
typedef T* iterator;
+ typedef T const* const_iterator;
+ typedef T value_type;
+ bool empty( void ) const;
size_t size( void ) const;
+ size_t capacity( void ) const;
T const& operator[]( size_t index ) const;
T& operator[]( size_t index );
bool shrink_to_fit( void );
bool reserve( size_t size );
bool resize( size_t size );
- bool assign( iterator start, iterator end );
- ~vector( void );
- T const* data( void ) const;
- T * data( void );
+ bool assign( const_iterator start, const_iterator end );
+
+ //default
+ vector( void ) = default;
+ //copy
+ vector( vector<T> const& );
+ vector<T>& operator=( vector<T> const& );
+ //move
+ vector( vector<T> && );
+ vector<T>& operator=( vector<T> && );
+ //destructor
+ virtual ~vector( void );
+
T const* begin( void ) const;
T * begin( void );
T const* end( void ) const;
T * end( void );
+
+ T const* rbegin( void ) const;
+ T * rbegin( void );
+ T const* rend( void ) const;
+ T * rend( void );
+
+ T const* data( void ) const;
+ T * data( void );
+
+ T const& front( void ) const;
+ T & front( void );
+
T const& back( void ) const;
T & back( void );
+ bool push_back( const T& value );
+ bool push_back( T&& value );
+ void pop_back( void );
};
template <typename T>
@@ -82,6 +119,18 @@ bool vector<T>::construct( size_t new_size )
}
template <typename T>
+size_t vector<T>::capacity( void ) const
+{
+ return m_alloc;
+}
+
+template <typename T>
+bool vector<T>::empty( void ) const
+{
+ return m_size == 0;
+}
+
+template <typename T>
size_t vector<T>::size( void ) const
{
return m_size;
@@ -131,7 +180,7 @@ bool vector<T>::resize( size_t size )
}
template <typename T>
-bool vector<T>::assign( iterator start, iterator end )
+bool vector<T>::assign( const_iterator start, const_iterator end )
{
if( end - start < 0 )
{
@@ -156,6 +205,48 @@ bool vector<T>::assign( iterator start, iterator end )
}
template <typename T>
+vector<T>::vector( vector<T> const& other )
+{
+#ifndef NDEBUG
+ fprintf( stderr, "vector copy ctor: from %p[%zu] to %p[%zu]\n",
+ static_cast<void*>( other.m_data ), other.m_size,
+ static_cast<void*>( m_data ), m_size
+ );
+#endif
+ assign( other.begin(), other.end() );
+}
+
+template <typename T>
+vector<T>& vector<T>::operator=( vector<T> const& other )
+{
+#ifndef NDEBUG
+ fprintf( stderr, "vector copy assign: from %p[%zu] to %p[%zu]\n",
+ static_cast<void*>( other.m_data ), other.m_size,
+ static_cast<void*>( m_data ), m_size
+ );
+#endif
+ assign( other.begin(), other.end() );
+ return *this;
+}
+
+template <typename T>
+vector<T>::vector( vector<T> && other )
+{
+ std::swap( other.m_data , m_data );
+ std::swap( other.m_size , m_size );
+ std::swap( other.m_alloc, m_alloc );
+}
+
+template <typename T>
+vector<T>& vector<T>::operator=( vector<T> && other )
+{
+ std::swap( other.m_data , m_data );
+ std::swap( other.m_size , m_size );
+ std::swap( other.m_alloc, m_alloc );
+ return *this;
+}
+
+template <typename T>
vector<T>::~vector( void )
{
release( m_size );
@@ -187,6 +278,44 @@ T * vector<T>::begin( void )
}
template <typename T>
+T const* vector<T>::rbegin( void ) const
+{
+ return end() - 1;
+}
+
+template <typename T>
+T * vector<T>::rbegin( void )
+{
+ return end() - 1;
+}
+
+template <typename T>
+T const* vector<T>::rend( void ) const
+{
+ return begin() - 1;
+}
+
+template <typename T>
+T * vector<T>::rend( void )
+{
+ return begin() - 1;
+}
+
+
+template <typename T>
+T const& vector<T>::front( void ) const
+{
+ return *m_data;
+}
+
+template <typename T>
+T & vector<T>::front( void )
+{
+ return *m_data;
+}
+
+
+template <typename T>
T const* vector<T>::end( void ) const
{
return m_data + m_size;
@@ -210,9 +339,95 @@ T & vector<T>::back( void )
return m_data[m_size - 1];
}
+template <typename T>
+bool vector<T>::push_back( const T& value )
+{
+ size_t new_size = m_size + 1;
+ if( new_size >= capacity() && allocate( new_size ) )
+ {
+ return true;
+ }
+ m_data[m_size] = value;
+ ++m_size;
+ return false;
+}
+
+template <typename T>
+bool vector<T>::push_back( T&& value )
+{
+ size_t new_size = m_size + 1;
+ if( new_size >= capacity() && allocate( new_size ) )
+ {
+ return true;
+ }
+ new (m_data + m_size ) T( std::move( value ) );
+ //m_data[m_size] = std::move( value );
+ ++m_size;
+ return false;
+}
+
+template <typename T>
+void vector<T>::pop_back( void )
+{
+ if( m_size )
+ {
+ --m_size;
+ m_data[m_size].~T();
+ }
+}
+
#else
#include <vector>
using std::vector;
#endif
+// append a single element to dst
+template<typename C, typename T>
+auto append( C& dst, T && src ) -> decltype( std::declval<C>().push_back( T() ) )
+{
+ return dst.push_back( src );
+}
+
+// append a single element to dst
+template<typename C, typename T>
+auto append( C& dst, T const& src ) -> decltype( std::declval<C>().push_back( T() ) )
+{
+ return dst.push_back( src );
+}
+
+// append a set to dst
+template<typename C>
+auto append( C& dst, typename C::const_iterator src_start, typename C::const_iterator src_end )
+ -> decltype( std::declval<C>().push_back( typename C::value_type() ) )
+{
+ assert( src_end >= src_start );
+ if( dst.reserve( dst.size() + static_cast<size_t>( src_end - src_start ) ) )
+ {
+ return true;
+ }
+ for( ; src_start != src_end; ++src_start )
+ {
+ if( dst.push_back( *src_start ) )
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+template<typename C>
+auto append( C& dst, C const& src )
+ -> decltype( std::declval<C>().push_back( typename C::value_type() ) )
+{
+ if( dst.reserve( dst.size() + src.size() ) )
+ {
+ return true;
+ }
+ for( auto el : src )
+ {
+ dst.push_back( el );
+ }
+ return false;
+}
+
#endif