// Copyright (c) 1997, 1998, 1999, 2000 // Utrecht University (The Netherlands), // ETH Zurich (Switzerland), // INRIA Sophia-Antipolis (France), // Max-Planck-Institute Saarbruecken (Germany), // and Tel-Aviv University (Israel). All rights reserved. // // This file is part of CGAL (www.cgal.org) // // $URL: https://github.com/CGAL/cgal/blob/v5.1/STL_Extension/include/CGAL/vector.h $ // $Id: vector.h 0779373 2020-03-26T13:31:46+01:00 Sébastien Loriot // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial // // // Author(s) : Andreas Fabri // Lutz Kettner #ifndef CGAL_VECTOR_H #define CGAL_VECTOR_H 1 #include #include #include #include #include #include #include #include #include namespace CGAL { namespace internal { // We give the vector container class a class based iterator implementation. // It ensures that iterator_traits work on compilers not supporting // partial specializations and it guarantees that default initialization // initializes the internal pointer to 0. Allows explicit construction // from a pointer. template < class T, class Ref, class Ptr> class vector_iterator { private: Ptr ptr; public: typedef vector_iterator< T, Ref, Ptr> Self; typedef T value_type; typedef Ref reference; typedef Ptr pointer; typedef std::ptrdiff_t difference_type; typedef std::random_access_iterator_tag iterator_category; // CREATION // -------- vector_iterator() : ptr(0) {} // explicitly set to 0 explicit vector_iterator( Ptr p) : ptr(p) {} // construction from pointer // Allows construction of const_iterator from iterator template < class A, class B, class C> vector_iterator( const vector_iterator& i) : ptr(i.operator->()) {} // OPERATIONS Forward Category // --------------------------- bool operator==( const Self& i) const { return ( ptr == i.ptr); } bool operator!=( const Self& i) const { return !(*this == i); } reference operator*() const { return *ptr; } pointer operator->() const { return ptr; } Self& operator++() { ++ptr; return *this; } Self operator++(int) { Self tmp = *this; ++*this; return tmp; } // OPERATIONS Bidirectional Category // --------------------------------- Self& operator--() { --ptr; return *this; } Self operator--(int) { Self tmp = *this; --*this; return tmp; } // OPERATIONS Random Access Category // --------------------------------- Self& operator+=( difference_type n) { ptr += n; return *this; } Self operator+( difference_type n) const { Self tmp = *this; return tmp += n; } Self& operator-=( difference_type n) { return operator+=( -n); } Self operator-( difference_type n) const { Self tmp = *this; return tmp += -n; } difference_type operator-( const Self& i) const { return ptr - i.ptr; } reference operator[]( difference_type n) const { Self tmp = *this; tmp += n; return tmp.operator*(); } bool operator< ( const Self& i) const { return ( ptr < i.ptr); } bool operator> ( const Self& i) const { return i < *this; } bool operator<=( const Self& i) const { return !(i < *this); } bool operator>=( const Self& i) const { return !(*this < i); } vector_iterator< T, typename boost::remove_const< typename boost::remove_reference::type >::type&, typename boost::remove_const< typename boost::remove_pointer::type >::type* > remove_const() const { typedef typename boost::remove_const< typename boost::remove_pointer::type >::type* Ptr_no_c; return vector_iterator< T, typename boost::remove_const::type>::type&, Ptr_no_c> ( const_cast(ptr) ); } }; template < class T, class Ref, class Ptr> inline vector_iterator operator+( std::ptrdiff_t n, vector_iterator i) { return i += n; } template < class T, class Alloc = CGAL_ALLOCATOR(T)> class vector { public: typedef Alloc Allocator; typedef Alloc allocator_type; // STL compliant // Note: the standard requires the following types to be equivalent // to T, T*, const T*, T&, const T&, size_t, and ptrdiff_t, respectively. // So we don't pass these types to the iterators explicitly. typedef typename std::allocator_traits::value_type value_type; typedef typename std::allocator_traits::pointer pointer; typedef typename std::allocator_traits::const_pointer const_pointer; typedef typename std::allocator_traits::size_type size_type; typedef typename std::allocator_traits::difference_type difference_type; typedef value_type& reference; typedef const value_type& const_reference; typedef std::random_access_iterator_tag iterator_category; typedef vector_iterator< T, reference, pointer> iterator; typedef vector_iterator< T, const_reference, const_pointer> const_iterator; typedef vector< T, Alloc> Self; typedef std::reverse_iterator reverse_iterator; typedef std::reverse_iterator const_reverse_iterator; protected: Allocator alloc; iterator start_; iterator finish; iterator end_of_storage; // ALLOCATION AND CONSTRUCTION HELPERS void construct( iterator i, const T& x) { std::allocator_traits::construct(alloc,&*i, x); } void destroy( iterator i) { std::allocator_traits::destroy(alloc,&*i); } void destroy( iterator first, iterator last) { // destroy in reverse order than construction while ( last != first) { --last; destroy( last); } } void deallocate() { if ( start_ != iterator() ) alloc.deallocate( &*start_, end_of_storage - start_ ); } protected: // pointer versions of begin()/end() to call the various // standard algorithms with the (possibly) more efficient pointers. pointer pbegin() { return &*start_; } const_pointer pbegin() const { return &*start_; } pointer pend() { return &*finish; } const_pointer pend() const { return &*finish; } public: // ACCESS // ------ iterator begin() { return start_; } const_iterator begin() const { return start_; } iterator end() { return finish; } const_iterator end() const { return finish; } size_type size() const { return size_type(end() - begin()); } size_type max_size() const { return size_type(-1) / sizeof(T); } size_type capacity() const { return size_type(end_of_storage - start_); } bool empty() const { return begin() == end(); } reference front() { return *begin(); } const_reference front() const { return *begin(); } reference back() { return *(end() - 1); } const_reference back() const { return *(end() - 1); } reference operator[] ( size_type n) { return *(begin() + n); } const_reference operator[] ( size_type n) const { return *(begin() + n); } reference at( size_type n) { return *(begin() + n); } const_reference at( size_type n) const { return *(begin() + n); } Allocator get_allocator() const { return alloc; } reverse_iterator rbegin() { return reverse_iterator(end()); } const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } reverse_iterator rend() { return reverse_iterator(begin()); } const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } // COMPARISON // ---------- bool operator==( const Self& y) const { return size() == y.size() && std::equal( pbegin(), pend(), y.pbegin()); } bool operator!=( const Self& y) const { return !(*this == y); } bool operator< ( const Self& y) const { return std::lexicographical_compare( pbegin(), pend(), y.pbegin(), y.pend()); } bool operator> ( const Self& y) const { return y < *this; } bool operator<=( const Self& y) const { return !(y < *this); } bool operator>=( const Self& y) const { return !(*this < y); } // CREATION // -------- explicit vector() : start_(0), finish(0), end_of_storage(0) {} explicit vector( const Alloc& a) : start_(0), finish(0), end_of_storage(0) { alloc = a; } explicit vector( size_type n, const T& val) { fill_initialize(n, val); } explicit vector( size_type n) { fill_initialize(n, T()); } vector( const Self& x) { start_ = allocate_and_copy( x.end() - x.begin(), x.begin(), x.end()); finish = start_ + (x.end() - x.begin()); end_of_storage = finish; } template vector( InputIterator first, InputIterator last, const Alloc& a = Alloc()) : start_(0), finish(0), end_of_storage(0) { alloc = a; typedef std::iterator_traits Traits; typedef typename Traits::iterator_category iterator_category; range_initialize( first, last, iterator_category()); } ~vector() { destroy( start_, finish); deallocate(); } vector& operator=(const Self& x) { if (&x != this) { if ( x.size() > capacity()) { iterator tmp = allocate_and_copy( x.end() - x.begin(), x.begin(), x.end()); destroy( start_, finish); deallocate(); start_ = tmp; end_of_storage = start_ + (x.end() - x.begin()); } else if (size() >= x.size()) { iterator i = std::copy( x.begin(), x.end(), begin()); destroy( i, finish); } else { std::copy( x.begin(), x.begin() + size(), begin()); std::uninitialized_copy(x.pbegin() + size(), x.pend(), pend()); } finish = start_ + x.size(); } return *this; } void swap( Self& x) { std::swap( start_, x.start_); std::swap( finish, x.finish); std::swap( end_of_storage, x.end_of_storage); } void reserve( size_type n) { if ( capacity() < n) { const size_type old_size = size(); iterator tmp = allocate_and_copy( n, start_, finish); destroy(start_, finish); deallocate(); start_ = tmp; finish = tmp + old_size; end_of_storage = start_ + n; } } // INSERTION // --------- void push_back( const T& x) { if ( finish != end_of_storage) { construct( finish, x); ++finish; } else { insert_aux( end(), x); } } iterator insert( iterator position, const T& x) { size_type n = position - begin(); if (finish != end_of_storage && position == end()) { construct( finish, x); ++finish; } else { insert_aux( position, x); } return begin() + n; } iterator insert(iterator position) { return insert( position, T()); } template void insert( iterator position, InputIterator first, InputIterator last) { typedef std::iterator_traits Traits; typedef typename Traits::iterator_category iterator_category; range_insert( position, first, last, iterator_category()); } void insert( iterator pos, size_type n, const T& x); // REMOVAL // ------- void pop_back() { --finish; destroy( finish); } iterator erase( iterator position) { if (position + 1 != end()) std::copy( position + 1, finish, position); --finish; destroy(finish); return position; } iterator erase( iterator first, iterator last) { iterator i = std::copy( last, finish, first); destroy( i, finish); finish = finish - (last - first); return first; } void clear() { erase( begin(), end()); } // ASSIGNMENT // ---------- template void assign( InputIterator first, InputIterator last) { clear(); insert( begin(), first, last); } void assign( size_type n, const T& u) { clear(); insert( begin(), n, u); } void resize( size_type new_size, const T& x) { if (new_size < size()) erase( begin() + new_size, end()); else insert( end(), new_size - size(), x); } void resize( size_type new_size) { resize( new_size, T()); } protected: // INTERNAL // -------- void insert_aux( iterator position, const T& x); void fill_initialize( size_type n, const T& value) { start_ = allocate_and_fill(n, value); finish = start_ + n; end_of_storage = finish; } iterator allocate_and_fill( size_type n, const T& x) { iterator result = iterator( alloc.allocate(n)); try { std::uninitialized_fill_n( &*result, n, x); return result; } catch(...) { alloc.deallocate( &*result, n); throw; } } template iterator allocate_and_copy( size_type n, ForwardIterator first, ForwardIterator last) { iterator result = iterator( alloc.allocate(n)); try { std::uninitialized_copy( first, last, &*result); return result; } catch(...) { alloc.deallocate( &*result, n); throw; } } template void range_initialize(InputIterator first, InputIterator last, std::input_iterator_tag) { for ( ; first != last; ++first) push_back(*first); } // This function is only called by the constructor. We have to worry // about resource leaks, but not about maintaining invariants. template void range_initialize( ForwardIterator first, ForwardIterator last, std::forward_iterator_tag) { size_type n = std::distance( first, last); start_ = allocate_and_copy( n, first, last); finish = start_ + n; end_of_storage = finish; } template void range_insert( iterator pos, InputIterator first, InputIterator last, std::input_iterator_tag) { for ( ; first != last; ++first) { pos = insert( pos, *first); ++pos; } } template void range_insert( iterator position, ForwardIterator first, ForwardIterator last, std::forward_iterator_tag) { if (first != last) { size_type n = std::distance(first, last); if ( size_type(end_of_storage - finish) >= n) { const size_type elems_after = finish - position; iterator old_finish = finish; if (elems_after > n) { std::uninitialized_copy( pend() - n, pend(), pend()); finish += n; std::copy_backward( position, old_finish - n, old_finish); std::copy( first, last, position); } else { ForwardIterator mid = first; std::advance( mid, elems_after); std::uninitialized_copy( mid, last, pend()); finish += n - elems_after; std::uninitialized_copy( position, old_finish, pend()); finish += elems_after; std::copy( first, mid, position); } } else { const size_type old_size = size(); const size_type len = old_size + (std::max)( old_size, n); iterator new_start = iterator( alloc.allocate(len)); iterator new_finish = new_start; try { new_finish = iterator( std::uninitialized_copy(start_, position,&*new_start)); new_finish = iterator( std::uninitialized_copy( first, last, &*new_finish)); new_finish = iterator( std::uninitialized_copy(position,finish,&*new_finish)); } catch(...) { destroy( new_start, new_finish); alloc.deallocate( &*new_start, len); throw; } destroy( start_, finish); deallocate(); start_ = new_start; finish = new_finish; end_of_storage = new_start + len; } } } }; // class vector template inline void swap( vector& x, vector& y) { x.swap(y); } template void vector::insert_aux( iterator position, const T& x) { if ( finish != end_of_storage) { construct( finish, *(finish - 1)); ++finish; T x_copy = x; std::copy_backward( position, finish - 2, finish - 1); *position = x_copy; } else { const size_type old_size = size(); const size_type len = old_size != 0 ? 2 * old_size : 1; iterator new_start = iterator( alloc.allocate(len)); iterator new_finish = new_start; try { new_finish = iterator( std::uninitialized_copy(start_, position, &*new_start)); construct( new_finish, x); ++new_finish; new_finish = iterator( std::uninitialized_copy(position,finish,&*new_finish)); } catch(...) { destroy( new_start, new_finish); alloc.deallocate( &*new_start, len); throw; } destroy( begin(), end()); deallocate(); start_ = new_start; finish = new_finish; end_of_storage = new_start + len; } } template void vector::insert( iterator position, size_type n, const T& x) { if (n != 0) { if ( size_type(end_of_storage - finish) >= n) { T x_copy = x; const size_type elems_after = finish - position; iterator old_finish = finish; if (elems_after > n) { std::uninitialized_copy( pend() - n, pend(), pend()); finish += n; std::copy_backward( position, old_finish - n, old_finish); std::fill( position, position + n, x_copy); } else { std::uninitialized_fill_n( pend(), n - elems_after, x_copy); finish += n - elems_after; std::uninitialized_copy( position, old_finish, pend()); finish += elems_after; std::fill(position, old_finish, x_copy); } } else { const size_type old_size = size(); const size_type len = old_size + (std::max)(old_size, n); iterator new_start = iterator( alloc.allocate(len)); iterator new_finish = new_start; try { new_finish = iterator( std::uninitialized_copy( start_, position, &*new_start)); std::uninitialized_fill_n( &*new_finish, n, x); new_finish += n; new_finish = iterator( std::uninitialized_copy( position, finish, &*new_finish)); } catch(...) { destroy( new_start, new_finish); alloc.deallocate( &*new_start, len); throw; } destroy( start_, finish); deallocate(); start_ = new_start; finish = new_finish; end_of_storage = new_start + len; } } } } // namespace internal } //namespace CGAL #endif // CGAL_VECTOR_H //