@@ -62,8 +62,10 @@ class bv_iterator
6262 template < typename cv_value_type_ >
6363 using iter_ = bv_iterator< value_type_, cv_value_type_&, cv_value_type_* >;
6464
65- const BlockVector< value_type_ >* block_vector_; // !< BlockVector to which this iterator points
66- size_t block_index_; // !< Index of the current block in the blockmap
65+ // ! BlockVector to which this iterator points
66+ const BlockVector< value_type_ >* block_vector_;
67+ // ! Iterator for the current block in the blockmap
68+ typename std::vector< std::vector< value_type_ > >::const_iterator block_vector_it_;
6769 // ! Iterator pointing to the current element in the current block.
6870 typename std::vector< value_type_ >::const_iterator block_it_;
6971 // ! Iterator pointing to the end of the current block.
@@ -81,7 +83,6 @@ class bv_iterator
8183
8284 bv_iterator ()
8385 : block_vector_( nullptr )
84- , block_index_( 0 )
8586 {
8687 }
8788
@@ -105,7 +106,7 @@ class bv_iterator
105106 * @param current_block_end Iterator pointing to the end of the current block.
106107 */
107108 bv_iterator ( const BlockVector< value_type_ >*,
108- const size_t ,
109+ const typename std::vector< std::vector< value_type_ > >::const_iterator ,
109110 const typename std::vector< value_type_ >::const_iterator,
110111 const typename std::vector< value_type_ >::const_iterator );
111112
@@ -328,6 +329,7 @@ inline BlockVector< value_type_ >::BlockVector( size_t n )
328329 {
329330 blockmap_.emplace_back ( max_block_size );
330331 }
332+ finish_ = begin (); // Because the blockmap has changed we need to recreate the iterator
331333 finish_ += n;
332334}
333335
@@ -396,7 +398,11 @@ BlockVector< value_type_ >::push_back( const value_type_& value )
396398 // If this is the last element in the current block, add another block
397399 if ( finish_.block_it_ == finish_.current_block_end_ - 1 )
398400 {
401+ // Need to get the current position here, then recreate the iterator after we extend the blockmap,
402+ // because after the blockmap is changed the iterator becomes invalid.
403+ const auto current_block = finish_.block_vector_it_ - finish_.block_vector_ ->blockmap_ .begin ();
399404 blockmap_.emplace_back ( max_block_size );
405+ finish_.block_vector_it_ = finish_.block_vector_ ->blockmap_ .begin () + current_block;
400406 }
401407 *finish_ = value;
402408 ++finish_;
@@ -421,16 +427,16 @@ inline size_t
421427BlockVector< value_type_ >::size() const
422428{
423429 size_t element_index; // Where we are in the current block
424- if ( finish_.block_index_ >= blockmap_.size () )
430+ if ( finish_.block_vector_it_ >= blockmap_.end () )
425431 {
426432 // If the current block is completely filled
427433 element_index = 0 ;
428434 }
429435 else
430436 {
431- element_index = finish_.block_it_ - blockmap_[ finish_.block_index_ ]. begin ();
437+ element_index = finish_.block_it_ - finish_.block_vector_it_ -> begin ();
432438 }
433- return finish_.block_index_ * max_block_size + element_index;
439+ return ( finish_.block_vector_it_ - finish_. block_vector_ -> blockmap_ . begin () ) * max_block_size + element_index;
434440}
435441
436442template < typename value_type_ >
@@ -457,8 +463,9 @@ BlockVector< value_type_ >::erase( const_iterator first, const_iterator last )
457463 *repl_it = std::move ( *element );
458464 ++repl_it;
459465 }
460- // The block that repl_it ends up in is the new final block.
461- auto & new_final_block = blockmap_[ repl_it.block_index_ ];
466+ // The block that repl_it ends up in is the new final block. Using iterator arithmetics to avoid issues with the
467+ // const iterator.
468+ auto & new_final_block = blockmap_[ repl_it.block_vector_it_ - blockmap_.begin () ];
462469 // Here, the arithmetic says that we first subtract
463470 // new_final_block.begin(), then add it again (which seems unnecessary).
464471 // But what we really do is extracting the element index of repl_it, then
@@ -475,7 +482,7 @@ BlockVector< value_type_ >::erase( const_iterator first, const_iterator last )
475482 }
476483 assert ( new_final_block.size () == max_block_size );
477484 // Erase all subsequent blocks.
478- blockmap_.erase ( blockmap_. begin () + repl_it.block_index_ + 1 , blockmap_.end () );
485+ blockmap_.erase ( repl_it.block_vector_it_ + 1 , blockmap_.end () );
479486 // Construct new finish_ iterator
480487 finish_ = repl_it;
481488 // The iterator which is to be returned is located where the first element
@@ -492,7 +499,6 @@ BlockVector< value_type_ >::print_blocks() const
492499 std::cerr << " this: \t\t " << this << " \n " ;
493500 std::cerr << " finish block_vector: \t " << finish_.block_vector_ << " \n " ;
494501 std::cerr << " Blockmap size: " << blockmap_.size () << " \n " ;
495- std::cerr << " Finish block: " << finish_.block_index_ << " \n " ;
496502 std::cerr << " ==============================================\n " ;
497503 auto seq_iter = begin ();
498504 for ( size_t block_index = 0 ; block_index != blockmap_.size () and seq_iter != end (); ++block_index )
@@ -559,28 +565,28 @@ BlockVector< value_type_ >::rend() const
559565template < typename value_type_, typename ref_, typename ptr_ >
560566inline bv_iterator< value_type_, ref_, ptr_ >::bv_iterator( const BlockVector< value_type_ >& block_vector )
561567 : block_vector_( &block_vector )
562- , block_index_( 0 )
563- , block_it_( block_vector_->blockmap_[ block_index_ ]. begin() )
564- , current_block_end_( block_vector_->blockmap_[ block_index_ ]. end() )
568+ , block_vector_it_( block_vector_->blockmap_.begin() )
569+ , block_it_( block_vector_it_-> begin () )
570+ , current_block_end_( block_vector_it_-> end () )
565571{
566572}
567573
568574template < typename value_type_, typename ref_, typename ptr_ >
569575inline bv_iterator< value_type_, ref_, ptr_ >::bv_iterator( const iterator& other )
570576 : block_vector_( other.block_vector_ )
571- , block_index_ ( other.block_index_ )
577+ , block_vector_it_ ( other.block_vector_it_ )
572578 , block_it_( other.block_it_ )
573579 , current_block_end_( other.current_block_end_ )
574580{
575581}
576582
577583template < typename value_type_, typename ref_, typename ptr_ >
578584inline bv_iterator< value_type_, ref_, ptr_ >::bv_iterator( const BlockVector< value_type_ >* block_vector,
579- const size_t block_index ,
585+ const typename std::vector< std::vector< value_type_ > >::const_iterator block_vector_it ,
580586 const typename std::vector< value_type_ >::const_iterator block_it,
581587 const typename std::vector< value_type_ >::const_iterator current_block_end )
582588 : block_vector_( block_vector )
583- , block_index_( block_index )
589+ , block_vector_it_( block_vector_it )
584590 , block_it_( block_it )
585591 , current_block_end_( current_block_end )
586592{
@@ -592,9 +598,16 @@ inline bv_iterator< value_type_, ref_, ptr_ >& bv_iterator< value_type_, ref_, p
592598 ++block_it_;
593599 if ( block_it_ == current_block_end_ )
594600 {
595- ++block_index_;
596- block_it_ = block_vector_->blockmap_ [ block_index_ ].begin ();
597- current_block_end_ = block_vector_->blockmap_ [ block_index_ ].end ();
601+ ++block_vector_it_;
602+ // If we are at end() now, we are outside of the blockmap, which is
603+ // undefined. The outer iterator can be in an undefined position that
604+ // will compare as safely larger or equal to end(), but we don't set
605+ // the inner iterators.
606+ if ( block_vector_it_ != block_vector_->blockmap_ .end () )
607+ {
608+ block_it_ = block_vector_it_->begin ();
609+ current_block_end_ = block_vector_it_->end ();
610+ }
598611 }
599612 return *this ;
600613}
@@ -604,16 +617,24 @@ inline bv_iterator< value_type_, ref_, ptr_ >& bv_iterator< value_type_, ref_, p
604617{
605618 // If we are still within the block, we can just decrement the block iterator.
606619 // If not, we need to switch to the previous block.
607- if ( block_it_ != block_vector_-> blockmap_ [ block_index_ ]. begin () )
620+ if ( block_it_ != block_vector_it_-> begin () )
608621 {
609622 --block_it_;
610623 }
611- else
624+ else if ( block_vector_it_ != block_vector_-> blockmap_ . begin () )
612625 {
613- --block_index_ ;
614- current_block_end_ = block_vector_-> blockmap_ [ block_index_ ]. end ();
626+ --block_vector_it_ ;
627+ current_block_end_ = block_vector_it_-> end ();
615628 block_it_ = current_block_end_ - 1 ;
616629 }
630+ else
631+ {
632+ // We are before begin(), which is undefined. We mark this by moving the
633+ // outer iterator to an undefined position that will compare as safely smaller
634+ // than begin(). According to C++17 Standard, §27.2.6, decrementing an
635+ // iterator that is equal to begin() yields undefined behavior.
636+ --block_vector_it_;
637+ }
617638 return *this ;
618639}
619640
@@ -699,26 +720,26 @@ template < typename value_type_, typename ref_, typename ptr_ >
699720inline typename bv_iterator< value_type_, ref_, ptr_ >::difference_type bv_iterator< value_type_, ref_, ptr_ >::
700721operator -( const iterator& other ) const
701722{
702- auto this_element_index = block_it_ - block_vector_-> blockmap_ [ block_index_ ]. begin ();
703- auto other_element_index = other.block_it_ - other.block_vector_ -> blockmap_ [ other. block_index_ ]. begin ();
704- return ( block_index_ - other.block_index_ ) * max_block_size + ( this_element_index - other_element_index );
723+ const auto this_element_index = block_it_ - block_vector_it_-> begin ();
724+ const auto other_element_index = other.block_it_ - other.block_vector_it_ -> begin ();
725+ return ( block_vector_it_ - other.block_vector_it_ ) * max_block_size + ( this_element_index - other_element_index );
705726}
706727
707728template < typename value_type_, typename ref_, typename ptr_ >
708729inline typename bv_iterator< value_type_, ref_, ptr_ >::difference_type bv_iterator< value_type_, ref_, ptr_ >::
709730operator -( const const_iterator& other ) const
710731{
711- auto this_element_index = block_it_ - block_vector_-> blockmap_ [ block_index_ ]. begin ();
712- auto other_element_index = other.block_it_ - other.block_vector_ -> blockmap_ [ other. block_index_ ]. begin ();
713- return ( block_index_ - other.block_index_ ) * max_block_size + ( this_element_index - other_element_index );
732+ const auto this_element_index = block_it_ - block_vector_it_-> begin ();
733+ const auto other_element_index = other.block_it_ - other.block_vector_it_ -> begin ();
734+ return ( block_vector_it_ - other.block_vector_it_ ) * max_block_size + ( this_element_index - other_element_index );
714735}
715736
716737template < typename value_type_, typename ref_, typename ptr_ >
717738inline typename bv_iterator< value_type_, ref_, ptr_ >::iterator& bv_iterator< value_type_, ref_, ptr_ >::operator =(
718739 const iterator& other )
719740{
720741 block_vector_ = other.block_vector_ ;
721- block_index_ = other.block_index_ ;
742+ block_vector_it_ = other.block_vector_it_ ;
722743 block_it_ = other.block_it_ ;
723744 current_block_end_ = other.current_block_end_ ;
724745 return *this ;
@@ -735,26 +756,28 @@ template < typename value_type_, typename ref_, typename ptr_ >
735756inline bool bv_iterator< value_type_, ref_, ptr_ >::operator ==(
736757 const bv_iterator< value_type_, ref_, ptr_ >& rhs ) const
737758{
738- return ( block_index_ == rhs.block_index_ and block_it_ == rhs.block_it_ );
759+ return ( block_vector_it_ == rhs.block_vector_it_ and block_it_ == rhs.block_it_ );
739760}
740761
741762template < typename value_type_, typename ref_, typename ptr_ >
742763inline bool bv_iterator< value_type_, ref_, ptr_ >::operator !=(
743764 const bv_iterator< value_type_, ref_, ptr_ >& rhs ) const
744765{
745- return ( block_index_ != rhs.block_index_ or block_it_ != rhs.block_it_ );
766+ return ( block_vector_it_ != rhs.block_vector_it_ or block_it_ != rhs.block_it_ );
746767}
747768
748769template < typename value_type_, typename ref_, typename ptr_ >
749770inline bool bv_iterator< value_type_, ref_, ptr_ >::operator <( const bv_iterator& rhs ) const
750771{
751- return ( block_index_ < rhs.block_index_ or ( block_index_ == rhs.block_index_ and block_it_ < rhs.block_it_ ) );
772+ return ( block_vector_it_ < rhs.block_vector_it_
773+ or ( block_vector_it_ == rhs.block_vector_it_ and block_it_ < rhs.block_it_ ) );
752774}
753775
754776template < typename value_type_, typename ref_, typename ptr_ >
755777inline bool bv_iterator< value_type_, ref_, ptr_ >::operator >( const bv_iterator& rhs ) const
756778{
757- return ( block_index_ > rhs.block_index_ or ( block_index_ == rhs.block_index_ and block_it_ > rhs.block_it_ ) );
779+ return ( block_vector_it_ > rhs.block_vector_it_
780+ or ( block_vector_it_ == rhs.block_vector_it_ and block_it_ > rhs.block_it_ ) );
758781}
759782
760783template < typename value_type_, typename ref_, typename ptr_ >
@@ -773,7 +796,7 @@ template < typename value_type_, typename ref_, typename ptr_ >
773796inline typename bv_iterator< value_type_, ref_, ptr_ >::iterator
774797bv_iterator< value_type_, ref_, ptr_ >::const_cast_() const
775798{
776- return iterator ( block_vector_, block_index_ , block_it_, current_block_end_ );
799+ return iterator ( block_vector_, block_vector_it_ , block_it_, current_block_end_ );
777800}
778801
779802template < typename value_type_, typename ref_, typename ptr_ >
0 commit comments