diff --git a/dune/common/container/Makefile.am b/dune/common/container/Makefile.am index a3cd7ddc2c25f5152c37aeb821e17672a69da9d7..4f2149c86b4d59132538588b706e2f6158f55bde 100644 --- a/dune/common/container/Makefile.am +++ b/dune/common/container/Makefile.am @@ -1,5 +1,5 @@ containerincludedir = $(includedir)/dune/common/container -containerinclude_HEADERS = array.hh arraylist.hh bitsetvector.hh sllist.hh +containerinclude_HEADERS = array.hh arraylist.hh bitsetvector.hh sllist.hh staticarray.hh SUBDIRS = test diff --git a/dune/common/container/staticarray.hh b/dune/common/container/staticarray.hh new file mode 100644 index 0000000000000000000000000000000000000000..93abaf2875bec2615e49033efbf44fd0f88171a1 --- /dev/null +++ b/dune/common/container/staticarray.hh @@ -0,0 +1,231 @@ +// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +// vi: set et ts=4 sw=2 sts=2: +#ifndef DUNE_STATICARRAY_HH +#define DUNE_STATICARRAY_HH + +#include <cassert> +#include <memory> + +#include <dune/common/nullptr.hh> + +namespace Dune +{ + + template< class T, class A = std::allocator< T > > + class StaticArray + { + typedef StaticArray< T, A > This; + + typedef typename A::template rebind< T >::other TAllocator; + + struct Storage + : public TAllocator + { + explicit Storage ( const TAllocator &allocator ) + : TAllocator( allocator ), begin( nullptr ), end( nullptr ) + {} + + typename TAllocator::pointer begin; + typename TAllocator::pointer end; + }; + + public: + typedef T value_type; + typedef A allocator_type; + + typedef typename TAllocator::const_pointer const_pointer; + typedef typename TAllocator::pointer pointer; + typedef typename TAllocator::const_reference const_reference; + typedef typename TAllocator::reference reference; + + typedef typename TAllocator::difference_type difference_type; + typedef typename TAllocator::size_type size_type; + + typedef const_pointer const_iterator; + typedef pointer iterator; + typedef std::reverse_iterator< const_iterator > const_reverse_iterator; + typedef std::reverse_iterator< iterator > reverse_iterator; + + explicit StaticArray ( const allocator_type &allocator = allocator_type() ) + : storage_( allocator ) + {} + + explicit StaticArray ( size_type size, const value_type &value = value_type(), + const allocator_type &allocator = allocator_type() ) + : storage_( allocator ) + { + allocate( size ); construct( value ); + } + + template< class InputIterator > + StaticArray ( InputIterator first, InputIterator last, const allocator_type &allocator = allocator_type() ) + : storage_( allocator ) + { + allocate( std::distance( first, last ) ); construct( first, last ); + } + + StaticArray ( const This &other ) + : storage_( other.allocator() ) + { + allocate( other.size() ); construct( other.begin(), other.end() ); + } + + ~StaticArray () { destroy(); deallocate(); } + + const This &operator= ( const This &other ) + { + destroy(); reallocate( other.size() ); construct( other.begin(), other.end() ); + return *this; + } + + void assign ( size_type size, const value_type &value ) + { + destroy(); reallocate( size ); construct( value ); + } + + template< class InputIterator > + void assign ( InputIterator first, InputIterator last ) + { + destroy(); reallocate( std::distance( first, last ) ); construct( first, last ); + } + + void clear () + { + destroy(); deallocate(); + storage_.begin = storage_.end = nullptr; + } + + void resize ( size_type size, const value_type &value = value_type() ); + + void swap ( This &other ) + { + std::swap( allocator(), other.allocator() ); + std::swap( storage_.begin, other.storage_.begin ); + std::swap( storage_.end, other.storage_.end ); + } + + const_reference back () const { assert( !empty ); return *(storage_.end-1); } + reference back () { assert( !empty ); return *(storage_.end-1); } + const_reference front () const { assert( !empty ); return *storage_.begin; } + reference front () { assert( !empty ); return *storage_.begin; } + + const_reference operator[] ( size_type i ) const { assert( i < size() ); return *(storage_.begin+i); } + reference operator[] ( size_type i ) { assert( i < size() ); return *(storage_.begin+i); } + + const_reference at ( size_type i ) const { rangeCheck( i ); return (*this)[ i ]; } + reference at ( size_type i ) { rangeCheck( i ); return (*this)[ i ]; } + + const_iterator begin () const { return const_iterator( storage_.begin ); } + iterator begin () { return iterator( storage_.begin ); } + const_iterator end () const { return const_iterator( storage_.end ); } + iterator end () { return iterator( storage_.end ); } + + const_reverse_iterator rbegin () const { return const_reverse_iterator( end() ); } + reverse_iterator rbegin () { return reverse_iterator( end() ); } + const_reverse_iterator rend () const { return const_reverse_iterator( begin() ); } + reverse_iterator rend () { return reverse_iterator( begin() ); } + + bool empty () const { return (storage_.begin == storage_.end); } + size_type size () const { return storage_.end - storage_.begin; } + + allocator_type get_allocator () const { return allocator(); } + size_type max_size () const { return allocator().max_size(); } + + protected: + const TAllocator &allocator () const { return static_cast< const TAllocator & >( storage_ ); } + TAllocator &allocator () { return static_cast< TAllocator & >( storage_ ); } + + void allocate ( size_type size ) + { + storage_.begin = (size != size_type( 0 ) ? allocator().allocate( size ) : nullptr); + storage_.end = storage_.begin + size; + } + + void reallocate ( size_type size ) + { + if( storage_.begin + size != storage_.end ) + { + deallocate(); + allocate( size ); + } + } + + void deallocate () + { + if( storage_.begin ) + allocator().deallocate( storage_.begin, size() ); + } + + void construct ( const value_type &value ) + { + for( pointer it = storage_.begin; it != storage_.end; ++it ) + allocator().construct( it, value ); + } + + template< class InputIterator > + void construct ( InputIterator first, InputIterator last ) + { + for( pointer it = storage_.begin; it != storage_.end; ++it, ++first ) + allocator().construct( it, *first ); + assert( first == last ); + } + + void destroy () + { + for( pointer it = storage_.begin; it != storage_.end; ++it ) + allocator().destroy( it ); + } + + private: + Storage storage_; + }; + + + + // Comparison Operators + // -------------------- + + template< class T, class A > + inline bool operator== ( const StaticArray< T, A > &a, const StaticArray< T, A > &b ) + { + return (a.size() == b.size()) && std::equal( a.begin(), a.end(), b.begin() ); + } + + template< class T, class A > + inline bool operator!= ( const StaticArray< T, A > &a, const StaticArray< T, A > &b ) + { + return !(a == b); + } + + + // Implementation of StaticArray + // ----------------------------- + + template< class T, class A > + inline void StaticArray< T, A >::resize ( size_type size, const value_type &value ) + { + if( storage_.begin + size != storage_.end ) + { + const pointer oldBegin = storage_.begin; + const pointer oldEnd = storage_.end; + const pointer copyEnd = oldBegin + std::min( size, oldEnd - oldBegin ); + + storage_.begin = allocate( size ); + storage_.end = storage_.begin + size; + + pointer it = storage_.begin; + for( pointer oldIt = oldBegin; oldIt != copyEnd; ++it, ++oldIt ) + { + allocator().construct( it, *oldIt ); + allocator().destroy( oldIt ); + } + for( ; it != end; ++it ) + allocator().construct( it, value ); + for( pointer oldIt = copyEnd; oldIt != oldEnd; ++oldIt ) + allocator().destroy( oldIt ); + } + } + +} // namespace Dune + +#endif // #ifndef DUNE_STATICARRAY_HH diff --git a/dune/common/container/test/.gitignore b/dune/common/container/test/.gitignore index 37d31e8e4c616fea908fdb47e8028bce32dca2fa..0e0348b77da8d50eafa9e17e813ca9d6e41f8b2f 100644 --- a/dune/common/container/test/.gitignore +++ b/dune/common/container/test/.gitignore @@ -2,6 +2,7 @@ arraytest arraylisttest bitsetvectortest sllisttest +staticarraytest Makefile Makefile.in diff --git a/dune/common/container/test/Makefile.am b/dune/common/container/test/Makefile.am index e6b80acf21ad459e1976df85bf46b7750bf9cc68..2eaa4163a34c960c47bb2ef0bb6f4e70529a76e6 100644 --- a/dune/common/container/test/Makefile.am +++ b/dune/common/container/test/Makefile.am @@ -1,5 +1,5 @@ # -*- tab-width: 8; indent-tabs-mode: nil -*- -TESTPROGS = arraytest arraylisttest bitsetvectortest sllisttest +TESTPROGS = arraytest arraylisttest bitsetvectortest sllisttest staticarraytest # programs to run when "make check" is used TESTS = $(TESTPROGS) @@ -15,4 +15,6 @@ bitsetvectortest_SOURCES = bitsetvectortest.cc sllisttest_SOURCES = sllisttest.cc +staticarraytest_SOURCES = staticarraytest.cc + include $(top_srcdir)/am/global-rules diff --git a/dune/common/container/test/staticarraytest.cc b/dune/common/container/test/staticarraytest.cc new file mode 100644 index 0000000000000000000000000000000000000000..dba8eeaa4d6725cbfd51dbc6b3a567797dc361b5 --- /dev/null +++ b/dune/common/container/test/staticarraytest.cc @@ -0,0 +1,20 @@ +// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +// vi: set et ts=4 sw=2 sts=2: +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif // #ifdef HAVE_CONFIG_H + +#include <iostream> + +#include <dune/common/container/staticarray.hh> + +int main ( int argc, char **argv ) +{ + std::cout << "sizeof( Dune::StaticArray< int > ) = " << sizeof( Dune::StaticArray< int > ) << std::endl; + + Dune::StaticArray< int > a( 4 ); + for( int i = 0; i < 4; ++i ) + a[ i ] = i+20; + + return 0; +}