NEST main@caf0ae8
 
Loading...
Searching...
No Matches
block_vector.h
Go to the documentation of this file.
1/*
2 * block_vector.h
3 *
4 * This file is part of NEST.
5 *
6 * Copyright (C) 2004 The NEST Initiative
7 *
8 * NEST is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * NEST is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with NEST. If not, see <http://www.gnu.org/licenses/>.
20 *
21 */
22
23#ifndef BLOCK_VECTOR_H_
24#define BLOCK_VECTOR_H_
25
26#include <cassert>
27#include <cmath>
28#include <iostream>
29#include <iterator>
30#include <vector>
31
32#include "exceptions.h"
33
34template < typename value_type_ >
35class BlockVector;
36template < typename value_type_, typename ref_, typename ptr_ >
37class bv_iterator;
38
39constexpr int block_size_shift = 10;
40constexpr int max_block_size = 1L << block_size_shift;
42
51template < typename value_type_, typename ref_, typename ptr_ >
53{
54 friend class BlockVector< value_type_ >;
55
56 // Making all templated iterators friends to allow converting
57 // iterator to const_iterator.
58 template < typename, typename, typename >
59 friend class bv_iterator;
60
61private:
62 template < typename cv_value_type_ >
64
68 typename std::vector< std::vector< value_type_ > >::const_iterator block_vector_it_;
70 typename std::vector< value_type_ >::const_iterator block_it_;
72 typename std::vector< value_type_ >::const_iterator current_block_end_;
73
74public:
77
78 using iterator_category = std::random_access_iterator_tag;
79 using value_type = value_type_;
80 using pointer = ptr_;
81 using reference = ref_;
83
85 : block_vector_( nullptr )
86 {
87 }
88
94
100
109 const typename std::vector< std::vector< value_type_ > >::const_iterator,
110 const typename std::vector< value_type_ >::const_iterator,
111 const typename std::vector< value_type_ >::const_iterator );
112
125
127
129
130 bool operator==( const bv_iterator& ) const;
131 bool operator!=( const bv_iterator& ) const;
132 bool operator<( const bv_iterator& ) const;
133 bool operator>( const bv_iterator& ) const;
134 bool operator<=( const bv_iterator& ) const;
135 bool operator>=( const bv_iterator& ) const;
136
137private:
142};
143
154template < typename value_type_ >
156{
157 template < typename cv_value_type_, typename ref_, typename ptr_ >
158 friend class bv_iterator;
159
160public:
161 using value_type = value_type_;
162 using difference_type = typename std::vector< value_type >::difference_type;
164 using const_pointer = const value_type*;
167 using reverse_iterator = std::reverse_iterator< iterator >;
168 using const_reverse_iterator = std::reverse_iterator< const_iterator >;
169 using size_type = size_t;
170
175
180 explicit BlockVector( size_t );
181
187 virtual ~BlockVector();
188
196 value_type_& operator[]( const size_t pos );
197
205 const value_type_& operator[]( const size_t pos ) const;
206
212
218
224
230
237 void push_back( const value_type_& value );
238
245 void push_back( value_type_&& value );
246
250 void clear();
251
255 size_t size() const;
256
268
273 void print_blocks() const;
274
279
284
291
298
305
312
313private:
315 std::vector< std::vector< value_type_ > > blockmap_;
317};
318
320// BlockVector method implementation //
322
323template < typename value_type_ >
325 : blockmap_(
326 std::vector< std::vector< value_type_ > >( 1, std::move( std::vector< value_type_ >( max_block_size ) ) ) )
327 , finish_( begin() )
328{
329}
330
331template < typename value_type_ >
333 : blockmap_(
334 std::vector< std::vector< value_type_ > >( 1, std::move( std::vector< value_type_ >( max_block_size ) ) ) )
335 , finish_( begin() )
336{
337 size_t num_blocks_needed = std::ceil( static_cast< double >( n ) / max_block_size );
338 for ( size_t i = 0; i < num_blocks_needed - 1; ++i )
339 {
340 blockmap_.emplace_back( max_block_size );
341 }
342 finish_ = begin(); // Because the blockmap has changed we need to recreate the iterator
343 finish_ += n;
344}
345
346template < typename value_type_ >
348 : blockmap_( other.blockmap_ )
349 , finish_( begin() + ( other.finish_ - other.begin() ) )
350{
351}
352
353template < typename value_type_ >
355
356template < typename value_type_ >
357inline value_type_&
359{
360 // Using bitwise operations to efficiently map the index to the
361 // right block and element.
362 const auto block_index = pos >> block_size_shift;
363 const auto element_index = pos & max_block_size_sub_1;
364 return blockmap_[ block_index ][ element_index ];
365}
366
367template < typename value_type_ >
368inline const value_type_&
370{
371 // Using bitwise operations to efficiently map the index to the
372 // right block and element.
373 const auto block_index = pos >> block_size_shift;
374 const auto element_index = pos & max_block_size_sub_1;
375 return blockmap_[ block_index ][ element_index ];
376}
377
378template < typename value_type_ >
381{
382 return iterator( *this );
383}
384
385template < typename value_type_ >
388{
389 return const_iterator( *this );
390}
391
392template < typename value_type_ >
395{
396 return finish_;
397}
398
399template < typename value_type_ >
402{
403 return finish_;
404}
405
406template < typename value_type_ >
407void
408BlockVector< value_type_ >::push_back( const value_type_& value )
409{
410 // If this is the last element in the current block, add another block
411 if ( finish_.block_it_ == finish_.current_block_end_ - 1 )
412 {
413 // Need to get the current position here, then recreate the iterator after we extend the blockmap,
414 // because after the blockmap is changed the iterator becomes invalid.
415 const auto current_block = finish_.block_vector_it_ - finish_.block_vector_->blockmap_.begin();
416 blockmap_.emplace_back( max_block_size );
417 finish_.block_vector_it_ = finish_.block_vector_->blockmap_.begin() + current_block;
418 }
419 *finish_ = value;
420 ++finish_;
421}
422
423template < typename value_type_ >
424void
426{
427 // If this is the last element in the current block, add another block
428 if ( finish_.block_it_ == finish_.current_block_end_ - 1 )
429 {
430 // Need to get the current position here, then recreate the iterator after we extend the blockmap,
431 // because after the blockmap is changed the iterator becomes invalid.
432 const auto current_block = finish_.block_vector_it_ - finish_.block_vector_->blockmap_.begin();
433 blockmap_.emplace_back( max_block_size );
434 finish_.block_vector_it_ = finish_.block_vector_->blockmap_.begin() + current_block;
435 }
436 *finish_ = std::move( value );
437 ++finish_;
438}
439
440template < typename value_type_ >
441void
443{
444 for ( auto it = blockmap_.begin(); it != blockmap_.end(); ++it )
445 {
446 it->clear();
447 }
448 blockmap_.clear();
449 // Initialise the first block
450 blockmap_.emplace_back( max_block_size );
451 finish_ = begin();
452}
453
454template < typename value_type_ >
455inline size_t
457{
458 size_t element_index; // Where we are in the current block
459 if ( finish_.block_vector_it_ >= blockmap_.end() )
460 {
461 // If the current block is completely filled
462 element_index = 0;
463 }
464 else
465 {
466 element_index = finish_.block_it_ - finish_.block_vector_it_->begin();
467 }
468 return ( finish_.block_vector_it_ - finish_.block_vector_->blockmap_.begin() ) * max_block_size + element_index;
469}
470
471template < typename value_type_ >
474{
475 assert( first.block_vector_ == this );
476 assert( last.block_vector_ == this );
477 assert( last < finish_ or last == finish_ );
478 if ( first == last )
479 {
480 return iterator( first.const_cast_() );
481 }
482 else if ( first == begin() and last == end() )
483 {
484 clear();
485 return end();
486 }
487 else
488 {
489 auto repl_it = first.const_cast_(); // Iterator for elements to be replaced.
490 for ( auto element = last; element != end(); ++element )
491 {
492 *repl_it = std::move( *element );
493 ++repl_it;
494 }
495 // The block that repl_it ends up in is the new final block. Using iterator arithmetics to avoid issues with the
496 // const iterator.
497 auto& new_final_block = blockmap_[ repl_it.block_vector_it_ - blockmap_.begin() ];
498 // Here, the arithmetic says that we first subtract
499 // new_final_block.begin(), then add it again (which seems unnecessary).
500 // But what we really do is extracting the element index of repl_it, then
501 // fast-forwarding new_final_block.begin() to that index.
502 auto element_index = repl_it.block_it_ - new_final_block.begin();
503 // Erase everything after the replaced elements in the current block.
504 new_final_block.erase( new_final_block.begin() + element_index, new_final_block.end() );
505 // Refill the erased elements in the final block with default-initialised
506 // elements.
507 int num_default_init = max_block_size - new_final_block.size();
508 for ( int i = 0; i < num_default_init; ++i )
509 {
510 new_final_block.emplace_back();
511 }
512 assert( new_final_block.size() == max_block_size );
513 // Erase all subsequent blocks.
514 blockmap_.erase( repl_it.block_vector_it_ + 1, blockmap_.end() );
515 // Construct new finish_ iterator
516 finish_ = repl_it;
517 // The iterator which is to be returned is located where the first element
518 // after the last deleted element will be after filling the erased elements,
519 // which is the position of the first deleted element.
520 return first.const_cast_();
521 }
522}
523
524template < typename value_type_ >
525void
527{
528 std::cerr << "this: \t\t" << this << "\n";
529 std::cerr << "finish block_vector: \t" << finish_.block_vector_ << "\n";
530 std::cerr << "Blockmap size: " << blockmap_.size() << "\n";
531 std::cerr << "==============================================\n";
532 auto seq_iter = begin();
533 for ( size_t block_index = 0; block_index != blockmap_.size() and seq_iter != end(); ++block_index )
534 {
535 std::cerr << "----------------------------------------------\n";
536 auto& block = blockmap_[ block_index ];
537 std::cerr << "Block size: " << block.size() << "\n";
538 for ( auto block_it = block.begin(); block_it != block.end() and seq_iter != end(); ++block_it )
539 {
540 std::cerr << *block_it << " ";
541 ++seq_iter;
542 }
543 std::cerr << "\n----------------------------------------------\n";
544 }
545 std::cerr << "==============================================\n";
546}
547
548template < typename value_type_ >
549inline int
554
555template < typename value_type_ >
558{
559 throw nest::NotImplemented( "BlockVector max_size() is not implemented." );
560}
561
562template < typename value_type_ >
565{
566 throw nest::NotImplemented( "BlockVector rbegin() is not implemented." );
567}
568
569template < typename value_type_ >
572{
573 throw nest::NotImplemented( "BlockVector rbegin() is not implemented." );
574}
575
576template < typename value_type_ >
579{
580 throw nest::NotImplemented( "BlockVector rend() is not implemented." );
581}
582
583template < typename value_type_ >
586{
587 throw nest::NotImplemented( "BlockVector rend() is not implemented." );
588}
589
591// BlockVector iterator method implementation //
593
594template < typename value_type_, typename ref_, typename ptr_ >
596 : block_vector_( &block_vector )
597 , block_vector_it_( block_vector_->blockmap_.begin() )
598 , block_it_( block_vector_it_->begin() )
600{
601}
602
603template < typename value_type_, typename ref_, typename ptr_ >
611
612template < typename value_type_, typename ref_, typename ptr_ >
614 const typename std::vector< std::vector< value_type_ > >::const_iterator block_vector_it,
615 const typename std::vector< value_type_ >::const_iterator block_it,
616 const typename std::vector< value_type_ >::const_iterator current_block_end )
617 : block_vector_( block_vector )
618 , block_vector_it_( block_vector_it )
619 , block_it_( block_it )
620 , current_block_end_( current_block_end )
621{
622}
623
624template < typename value_type_, typename ref_, typename ptr_ >
627{
628 ++block_it_;
630 {
632 // If we are at end() now, we are outside of the blockmap, which is
633 // undefined. The outer iterator can be in an undefined position that
634 // will compare as safely larger or equal to end(), but we don't set
635 // the inner iterators.
636 if ( block_vector_it_ != block_vector_->blockmap_.end() )
637 {
638 block_it_ = block_vector_it_->begin();
640 }
641 }
642 return *this;
643}
644
645template < typename value_type_, typename ref_, typename ptr_ >
648{
649 // If we are still within the block, we can just decrement the block iterator.
650 // If not, we need to switch to the previous block.
651 if ( block_it_ != block_vector_it_->begin() )
652 {
653 --block_it_;
654 }
655 else if ( block_vector_it_ != block_vector_->blockmap_.begin() )
656 {
660 }
661 else
662 {
663 // We are before begin(), which is undefined. We mark this by moving the
664 // outer iterator to an undefined position that will compare as safely smaller
665 // than begin(). According to C++17 Standard, §27.2.6, decrementing an
666 // iterator that is equal to begin() yields undefined behavior.
668 }
669 return *this;
670}
671
672template < typename value_type_, typename ref_, typename ptr_ >
675{
676 if ( val < 0 )
677 {
678 return operator-=( -val );
679 }
680 for ( difference_type i = 0; i < val; ++i )
681 {
682 operator++();
683 }
684 return *this;
685}
686
687template < typename value_type_, typename ref_, typename ptr_ >
690{
691 if ( val < 0 )
692 {
693 return operator+=( -val );
694 }
695 for ( difference_type i = 0; i < val; ++i )
696 {
697 operator--();
698 }
699 return *this;
700}
701
702template < typename value_type_, typename ref_, typename ptr_ >
705{
706 bv_iterator tmp = *this;
707 return tmp += val;
708}
709
710template < typename value_type_, typename ref_, typename ptr_ >
713{
714 bv_iterator tmp = *this;
715 return tmp -= val;
716}
717
718template < typename value_type_, typename ref_, typename ptr_ >
721{
723 ++( *this );
724 return old;
725}
726
727template < typename value_type_, typename ref_, typename ptr_ >
730{
732 --( *this );
733 return old;
734}
735
736template < typename value_type_, typename ref_, typename ptr_ >
739{
740 // TODO: Using const_cast to remove the constness isn't the most elegant
741 // solution. There is probably a better way to do this.
742 return const_cast< reference >( *block_it_ );
743}
744
745template < typename value_type_, typename ref_, typename ptr_ >
748{
749 // TODO: Again, using const_cast to remove the constness isn't the most
750 // elegant solution. There is probably a better way to do this.
751 return const_cast< pointer >( &( *block_it_ ) );
752}
753
754template < typename value_type_, typename ref_, typename ptr_ >
757{
758 const auto this_element_index = block_it_ - block_vector_it_->begin();
759 const auto other_element_index = other.block_it_ - other.block_vector_it_->begin();
760 return ( block_vector_it_ - other.block_vector_it_ ) * max_block_size + ( this_element_index - other_element_index );
761}
762
763template < typename value_type_, typename ref_, typename ptr_ >
766{
767 const auto this_element_index = block_it_ - block_vector_it_->begin();
768 const auto other_element_index = other.block_it_ - other.block_vector_it_->begin();
769 return ( block_vector_it_ - other.block_vector_it_ ) * max_block_size + ( this_element_index - other_element_index );
770}
771
772template < typename value_type_, typename ref_, typename ptr_ >
775{
776 block_vector_ = other.block_vector_;
777 block_vector_it_ = other.block_vector_it_;
778 block_it_ = other.block_it_;
779 current_block_end_ = other.current_block_end_;
780 return *this;
781}
782
783template < typename value_type_, typename ref_, typename ptr_ >
786{
787 return *( *this + n );
788}
789
790template < typename value_type_, typename ref_, typename ptr_ >
791inline bool
796
797template < typename value_type_, typename ref_, typename ptr_ >
798inline bool
803
804template < typename value_type_, typename ref_, typename ptr_ >
805inline bool
807{
809 or ( block_vector_it_ == rhs.block_vector_it_ and block_it_ < rhs.block_it_ ) );
810}
811
812template < typename value_type_, typename ref_, typename ptr_ >
813inline bool
819
820template < typename value_type_, typename ref_, typename ptr_ >
821inline bool
823{
824 return operator<( rhs ) or operator==( rhs );
825}
826
827template < typename value_type_, typename ref_, typename ptr_ >
828inline bool
830{
831 return operator>( rhs ) or operator==( rhs );
832}
833
834template < typename value_type_, typename ref_, typename ptr_ >
840
841template < typename value_type_, typename ref_, typename ptr_ >
845{
846 return x + n;
847}
848
849#endif /* BLOCK_VECTOR_H_ */
constexpr int max_block_size_sub_1
Definition block_vector.h:41
constexpr int max_block_size
Definition block_vector.h:40
constexpr int block_size_shift
max_block_size = 2^block_size_shift
Definition block_vector.h:39
bv_iterator< value_type_, ref_, ptr_ > operator+(typename bv_iterator< value_type_, ref_, ptr_ >::difference_type n, bv_iterator< value_type_, ref_, ptr_ > &x)
Definition block_vector.h:843
Container with a vector-of-vectors structure.
Definition block_vector.h:156
iterator finish_
Iterator pointing to one past the last element.
Definition block_vector.h:316
const_iterator begin() const
Returns a read-only (constant) iterator that points to the first element in the BlockVector.
Definition block_vector.h:387
reverse_iterator rend() const
Returns a read-only (constant) reverse iterator that points to one before the first element in the Bl...
Definition block_vector.h:585
const value_type_ & operator[](const size_t pos) const
Subscript access to the data contained in the BlockVector.
Definition block_vector.h:369
typename std::vector< value_type >::difference_type difference_type
Definition block_vector.h:162
size_t size_type
Definition block_vector.h:169
iterator begin()
Returns a read/write iterator that points to the first element in the BlockVector.
Definition block_vector.h:380
reverse_iterator rbegin()
Returns a read/write reverse iterator that points to the last element in the BlockVector.
Definition block_vector.h:564
void clear()
Erases all the elements.
Definition block_vector.h:442
reverse_iterator rend()
Returns a read/write reverse iterator that points to one before the first element in the BlockVector.
Definition block_vector.h:578
const value_type & const_reference
Definition block_vector.h:163
size_type max_size() const
Returns the size() of the largest possible BlockVector.
Definition block_vector.h:557
void print_blocks() const
Writes the contents of the BlockVector, separated into blocks, to cerr.
Definition block_vector.h:526
const_iterator end() const
Returns a read-only (constant) iterator that points one past the last element in the BlockVector.
Definition block_vector.h:401
iterator end()
Returns a read/write iterator that points one past the last element in the BlockVector.
Definition block_vector.h:394
int get_max_block_size() const
Returns the block-size.
Definition block_vector.h:550
iterator erase(const_iterator, const_iterator)
Remove a range of elements.
Definition block_vector.h:473
size_t size() const
Returns the number of elements in the BlockVector.
Definition block_vector.h:456
value_type_ & operator[](const size_t pos)
Subscript access to the data contained in the BlockVector.
Definition block_vector.h:358
virtual ~BlockVector()
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition block_vector.h:168
std::vector< std::vector< value_type_ > > blockmap_
Vector holding blocks containing data.
Definition block_vector.h:315
BlockVector()
Creates an empty BlockVector.
Definition block_vector.h:324
value_type_ value_type
Definition block_vector.h:161
void push_back(value_type_ &&value)
Move data to the end of the BlockVector.
Definition block_vector.h:425
void push_back(const value_type_ &value)
Add data to the end of the BlockVector.
Definition block_vector.h:408
BlockVector(size_t)
Creates a BlockVector containing a number of elements.
Definition block_vector.h:332
BlockVector(const BlockVector< value_type_ > &)
BlockVector copy constructor.
Definition block_vector.h:347
std::reverse_iterator< iterator > reverse_iterator
Definition block_vector.h:167
const value_type * const_pointer
Definition block_vector.h:164
reverse_iterator rbegin() const
Returns a read-only (constant) reverse iterator that points to the last element in the BlockVector.
Definition block_vector.h:571
A BlockVector::iterator.
Definition block_vector.h:53
bv_iterator operator--(int)
Definition block_vector.h:729
std::random_access_iterator_tag iterator_category
Definition block_vector.h:78
bool operator<=(const bv_iterator &) const
Definition block_vector.h:822
value_type_ value_type
Definition block_vector.h:79
ptr_ pointer
Definition block_vector.h:80
bool operator==(const bv_iterator &) const
Definition block_vector.h:792
bv_iterator()
Definition block_vector.h:84
bv_iterator & operator-=(difference_type)
Definition block_vector.h:689
bv_iterator operator++(int)
Definition block_vector.h:720
iterator const_cast_() const
Converts the iterator to a non-const iterator.
Definition block_vector.h:836
ref_ reference
Definition block_vector.h:81
iterator & operator=(const iterator &)
Definition block_vector.h:774
const BlockVector< value_type_ > * block_vector_
BlockVector to which this iterator points.
Definition block_vector.h:66
bv_iterator operator-(difference_type) const
Definition block_vector.h:712
difference_type operator-(const const_iterator &) const
Definition block_vector.h:765
reference operator*() const
Definition block_vector.h:738
iter_< const value_type_ > const_iterator
Definition block_vector.h:76
pointer operator->() const
Definition block_vector.h:747
friend class bv_iterator
Definition block_vector.h:59
bv_iterator(const BlockVector< value_type_ > &)
Creates an iterator pointing to the first element in a BlockVector.
Definition block_vector.h:595
bv_iterator operator+(difference_type) const
Definition block_vector.h:704
typename BlockVector< value_type >::difference_type difference_type
Definition block_vector.h:82
reference operator[](difference_type n) const
Definition block_vector.h:785
bv_iterator(const iterator &)
Iterator copy constructor.
Definition block_vector.h:604
bool operator<(const bv_iterator &) const
Definition block_vector.h:806
difference_type operator-(const iterator &) const
Definition block_vector.h:756
std::vector< value_type_ >::const_iterator block_it_
Iterator pointing to the current element in the current block.
Definition block_vector.h:70
std::vector< std::vector< value_type_ > >::const_iterator block_vector_it_
Iterator for the current block in the blockmap.
Definition block_vector.h:68
bv_iterator(const BlockVector< value_type_ > *, const typename std::vector< std::vector< value_type_ > >::const_iterator, const typename std::vector< value_type_ >::const_iterator, const typename std::vector< value_type_ >::const_iterator)
Creates an iterator with specified parameters.
Definition block_vector.h:613
iter_< value_type_ > iterator
Definition block_vector.h:75
bool operator!=(const bv_iterator &) const
Definition block_vector.h:799
bv_iterator & operator+=(difference_type)
Definition block_vector.h:674
bool operator>=(const bv_iterator &) const
Definition block_vector.h:829
bool operator>(const bv_iterator &) const
Definition block_vector.h:814
bv_iterator & operator++()
Definition block_vector.h:626
std::vector< value_type_ >::const_iterator current_block_end_
Iterator pointing to the end of the current block.
Definition block_vector.h:72
bv_iterator & operator--()
Definition block_vector.h:647
Exception to be thrown if a feature is unavailable.
Definition exceptions.h:108