// Copyright (C) 2014 ChaosForge Ltd // http://chaosforge.org/ // // This file is part of NV Libraries. // For conditions of distribution and use, see copyright notice in nv.hh /** * @file array.hh * @author Kornel Kisielewicz epyon@chaosforge.org * @brief exception free array classes */ #ifndef NV_CORE_ARRAY_HH #define NV_CORE_ARRAY_HH #include #include #include #include #include #include #include namespace nv { using std::vector; template < typename T, typename Storage > class array_base : public detail::pointer_iterators < array_base< T, Storage >, Storage > { public: typedef T value_type; typedef size_t size_type; typedef ptrdiff_t difference_type; typedef T* pointer; typedef const T* const_pointer; typedef T* iterator; typedef const T* const_iterator; typedef T& reference; typedef const T& const_reference; typedef nv::reverse_iterator reverse_iterator; typedef nv::reverse_iterator const_reverse_iterator; inline const_pointer data() const { return m_storage.data(); } inline pointer data() { return m_storage.data(); } inline size_t size() const { return m_storage.size(); } inline bool empty() const { return m_storage.size() == 0; } inline size_type raw_size() const { return m_storage.size() * sizeof( value_type ); } inline const char* raw_data() const { return (const char*)m_storage.data(); } inline char* raw_data() { return (char*)m_storage.data(); } inline reference front() { NV_ASSERT( !empty(), "front() called on empty data!" ); return m_storage.data()[0]; } inline const_reference front() const { NV_ASSERT( !empty(), "front() called on empty data!" ); return m_storage.data()[0]; } inline reference back() { NV_ASSERT( !empty(), "front() called on empty data!" ); return m_storage.data()[size() - 1]; } inline const_reference back() const { NV_ASSERT( !empty(), "front() called on empty data!" ); return m_storage.data()[size() - 1]; } reference operator[]( size_type i ) { NV_ASSERT( i < m_storage.size(), "Out of range" ); return m_storage.data()[i]; } const_reference operator[]( size_type i ) const { NV_ASSERT( i < m_storage.size(), "Out of range" ); return m_storage.data()[i]; } inline void assign( const value_type& value ) { fill( value ); } inline void fill( const value_type& value ) { fill_n( this->begin(), this->size(), value ); } inline void clear() { fill_default_n( this->begin(), this->size() ); } protected: Storage m_storage; }; template< typename T, size_t N > using array = array_base < T, fixed_container_storage < static_storage< T, N > > >; #if 0 template< typename T, size_t N > class array : public detail::pointer_iterators < array< T, N >, T, false > { public: typedef T value_type; typedef size_t size_type; typedef ptrdiff_t difference_type; typedef T* pointer; typedef const T* const_pointer; typedef T* iterator; typedef const T* const_iterator; typedef T& reference; typedef const T& const_reference; typedef nv::reverse_iterator reverse_iterator; typedef nv::reverse_iterator const_reverse_iterator; static const size_type SIZE = N; static const size_type ELEMENT_SIZE = sizeof( value_type ); inline const_pointer data() const { return m_data; } inline pointer data() { return m_data; } inline size_type size() const { return SIZE; } inline bool empty() const { return false; } inline size_type raw_size() const { return SIZE * sizeof( T ); } inline const char* raw_data() const { return (const char*)m_data; } inline char* raw_data() { return (char*)m_data; } inline reference front() { NV_ASSERT( !empty(), "front() called on empty data!" ); return m_data[0]; } inline const_reference front() const { NV_ASSERT( !empty(), "front() called on empty data!" ); return m_data[0]; } inline reference back() { NV_ASSERT( !empty(), "front() called on empty data!" ); return m_data[SIZE - 1]; } inline const_reference back() const { NV_ASSERT( !empty(), "front() called on empty data!" ); return m_data[SIZE - 1]; } reference operator[]( size_type i ) { NV_ASSERT( i < N, "Out of range" ); return this->m_data[i]; } const_reference operator[]( size_type i ) const { NV_ASSERT( i < N, "Out of range" ); return this->m_data[i]; } reference at( size_type i ) { NV_ASSERT( i < N, "Out of range" ); return this->m_data[i]; } const_reference at( size_type i ) const { NV_ASSERT( i < N, "Out of range" ); return this->m_data[i]; } void assign( const value_type& value ) { fill( value ); } void fill( const value_type& value ) { std::fill_n( this->begin(), this->size(), value ); } private: value_type m_data[SIZE]; }; #endif // template < typename T, typename ContainerAllocator > // class vector_base // { // public: // typedef T value_type; // typedef size_t size_type; // typedef ptrdiff_t difference_type; // typedef T* pointer; // typedef const T* const_pointer; // typedef T* iterator; // typedef const T* const_iterator; // typedef T& reference; // typedef const T& const_reference; // // protected: // ContainerAllocator m_storage; // }; // template< typename T, size_t N > // class static_vector : public detail::pointer_iterators < static_vector< T, N >, T, false > // { // public: // typedef T value_type; // typedef size_t size_type; // typedef ptrdiff_t difference_type; // typedef T* pointer; // typedef const T* const_pointer; // typedef T* iterator; // typedef const T* const_iterator; // typedef T& reference; // typedef const T& const_reference; // typedef nv::reverse_iterator reverse_iterator; // typedef nv::reverse_iterator const_reverse_iterator; // // static_vector() : m_size(0) {} // // inline const_pointer data() const { return m_data; } // inline pointer data() { return m_data; } // inline size_type size() const { return m_size; } // inline bool empty() const { return !m_size; } // inline size_type raw_size() const { return N * sizeof( T ); } // inline const char* raw_data() const { return (const char*)m_data; } // inline char* raw_data() { return (char*)m_data; } // // inline reference front() { NV_ASSERT( !empty(), "front() called on empty data!" ); return m_data[0]; } // inline const_reference front() const { NV_ASSERT( !empty(), "front() called on empty data!" ); return m_data[0]; } // inline reference back() { NV_ASSERT( !empty(), "front() called on empty data!" ); return m_data[m_size - 1]; } // inline const_reference back() const { NV_ASSERT( !empty(), "front() called on empty data!" ); return m_data[m_size - 1]; } // protected: // value_type m_data[N]; // size_type m_size; // }; template< typename T > class dynamic_array : public detail::data_base< storage_view< T > > { public: typedef T value_type; typedef T* iterator; typedef const T* const_iterator; typedef T& reference; typedef const T& const_reference; typedef size_t size_type; typedef ptrdiff_t difference_type; typedef nv::reverse_iterator reverse_iterator; typedef nv::reverse_iterator const_reverse_iterator; dynamic_array() : detail::data_base< storage_view< T > >() {} // : m_data( nullptr ), m_size(0) {} explicit dynamic_array( size_type new_size ) : detail::data_base< storage_view< T > >( new value_type[new_size], new_size ) {} // : m_data( new value_type[ new_size ] ), m_size( new_size ) {} dynamic_array( const value_type& value, size_type size ) : detail::data_base< storage_view< T > >() // : m_data( nullptr ), m_size(0) { assign( value, size ); } dynamic_array( const_iterator values, size_type size ) : detail::data_base< storage_view< T > >() // : m_data( nullptr ), m_size(0) { assign( values, size ); } void resize( size_type new_size ) { if ( new_size != this->size() ) { value_type* old_data = this->data(); value_type* new_data = new_size > 0 ? new value_type[new_size] : nullptr; if ( old_data && this->data() ) { std::copy_n( old_data, new_size > this->size() ? this->size() : new_size, new_data ); } delete[] old_data; assign( new_data, new_size ); } } // iterator begin() { return m_data; } // const_iterator begin() const { return m_data; } // const_iterator cbegin() const { return m_data; } // // iterator end() { return m_data+m_size; } // const_iterator end() const { return m_data+m_size; } // const_iterator cend() const { return m_data+m_size; } // // reverse_iterator rbegin() { return reverse_iterator( end() ); } // const_reverse_iterator rbegin() const { return const_reverse_iterator( end() ); } // const_reverse_iterator crbegin() const { return const_reverse_iterator( end() ); } // // reverse_iterator rend() { return reverse_iterator( begin() ); } // const_reverse_iterator rend() const { return const_reverse_iterator( begin() ); } // const_reverse_iterator crend() const { return const_reverse_iterator( begin() ); } reference operator[]( size_type i ) { NV_ASSERT( i < this->size(), "Out of range" ); return this->data()[i]; } const_reference operator[]( size_type i ) const { NV_ASSERT( i < this->size(), "Out of range" ); return this->data()[i]; } // reference front() { return m_data[0]; } // const_reference front() const { return m_data[0]; } // reference back() { return m_data[m_size-1]; } // const_reference back() const { return m_data[m_size-1]; } // // size_type size() const { return m_size; } // bool empty() const { return m_size == 0; } // static size_type max_size() { return numeric_limits< size_type >::max(); } // const value_type* data() const { return m_data; } // value_type* data() { return m_data; } // // size_type raw_size() const { return m_size * ELEMENT_SIZE; } // const char* raw_data() const { return (const char*)m_data; } // char* raw_data() { return (char*)m_data; } void assign( const value_type& value ) { std::fill_n( this->begin(), this->size(), value ); } void assign( const value_type& value, size_type new_size ) { resize( new_size ); std::fill_n( this->begin(), this->size(), value ); } void assign( const_iterator values, size_type new_size ) { resize( new_size ); std::copy_n( values, this->size(), this->data() ); } ~dynamic_array() { delete[] this->data(); } static const size_type ELEMENT_SIZE = sizeof(T); }; } #endif // NV_CORE_ARRAY_HH