From 2d73a57001a0721537ca786c6e7040d8ffe0640d Mon Sep 17 00:00:00 2001 From: Wim Haeck Date: Wed, 1 Nov 2023 15:51:34 -0600 Subject: [PATCH 01/18] Removing the TransformationIterator --- src/tools/ranges/TransformIterator.hpp | 157 ------------------ .../TransformIterator/test/CMakeLists.txt | 1 - .../test/TransformIterator.test.cpp | 85 ---------- 3 files changed, 243 deletions(-) delete mode 100644 src/tools/ranges/TransformIterator.hpp delete mode 100644 src/tools/ranges/TransformIterator/test/CMakeLists.txt delete mode 100644 src/tools/ranges/TransformIterator/test/TransformIterator.test.cpp diff --git a/src/tools/ranges/TransformIterator.hpp b/src/tools/ranges/TransformIterator.hpp deleted file mode 100644 index 0c80996..0000000 --- a/src/tools/ranges/TransformIterator.hpp +++ /dev/null @@ -1,157 +0,0 @@ -#ifndef NJOY_UTILITY_TRANSFORMITERATOR -#define NJOY_UTILITY_TRANSFORMITERATOR - -// system includes -#include - -// other includes - -namespace njoy { -namespace tools { -namespace ranges { - -/** - * - * @brief An iterator class that applies a transformation when dereferencing - * the iterator - */ -template < typename Iterator, typename Transformation > -class TransformIterator { - - /* fields */ - Iterator iter_; - Transformation transform_; - -public: - - using iterator_category = typename Iterator::iterator_category; - using difference_type = typename Iterator::difference_type; - using value_type = decltype( std::declval< Transformation >()( std::declval< typename Iterator::value_type >() ) ); - using pointer = value_type*; - using reference = value_type; - - /* constructor */ - - constexpr TransformIterator() = delete; - - /** - * @brief Constructor - * - * @param[in] iter the iterator - * @param[in] transformation the transformation to be applied - */ - constexpr TransformIterator( Iterator iter, Transformation transformation ) : - iter_( std::move( iter ) ), transform_( std::move( transformation ) ) {} - - /* methods */ - - constexpr reference operator*() const { - - return this->transform_( *this->iter_ ); - } - - constexpr reference operator[]( difference_type i ) const { - - return this->transform_( this->iter_[i] ); - } - - constexpr TransformIterator& operator+=( difference_type i ) { - - this->iter_ += i; - return *this; - } - - constexpr TransformIterator& operator-=( difference_type i ) { - - this->iter_ -= i; - return *this; - } - - constexpr TransformIterator& operator++( void ) { - - ++this->iter_; - return *this; - } - - constexpr TransformIterator operator++( int ) { - - return TransformIterator( this->iter_++, transform_ ); - } - - constexpr TransformIterator& operator--( void ) { - - --this->iter_; - return *this; - } - - constexpr TransformIterator operator--( int ) { - - return TransformIterator( this->iter_--, this->transform_ ); - } - - friend constexpr TransformIterator operator+( difference_type i, - TransformIterator iter ) { - - return TransformIterator( iter.iter_ + i, iter.transform_ ); - } - - friend constexpr TransformIterator operator+( TransformIterator iter, - difference_type i ) { - - return TransformIterator( iter.iter_ + i, iter.transform_ ); - } - - friend constexpr TransformIterator operator-( TransformIterator iter, - difference_type i ) { - - return TransformIterator( iter.iter_ - i, iter.transform_ ); - } - - friend constexpr difference_type operator-( const TransformIterator& left, - const TransformIterator& right ) { - - return left.iter_ - right.iter_; - } - - friend constexpr bool operator==( const TransformIterator& left, - const TransformIterator& right ) { - - return left.iter_ == right.iter_; - }; - - friend constexpr bool operator!=( const TransformIterator& left, - const TransformIterator& right ) { - - return !( left == right ); - }; - - friend constexpr bool operator<( const TransformIterator& left, - const TransformIterator& right) { - - return left.iter_ < right.iter_; - } - - friend constexpr bool operator>( const TransformIterator& left, - const TransformIterator& right ) { - - return right < left; - } - - friend constexpr bool operator<=( const TransformIterator& left, - const TransformIterator& right ) { - - return !( right < left ); - } - - friend constexpr bool operator>=( const TransformIterator& left, - const TransformIterator& right ) { - - return !( left < right ); - } -}; - -} // ranges namespace -} // tools namespace -} // njoy namespace - -#endif diff --git a/src/tools/ranges/TransformIterator/test/CMakeLists.txt b/src/tools/ranges/TransformIterator/test/CMakeLists.txt deleted file mode 100644 index dea3472..0000000 --- a/src/tools/ranges/TransformIterator/test/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -add_cpp_test( ranges.TransformIterator TransformIterator.test.cpp ) diff --git a/src/tools/ranges/TransformIterator/test/TransformIterator.test.cpp b/src/tools/ranges/TransformIterator/test/TransformIterator.test.cpp deleted file mode 100644 index c7293f5..0000000 --- a/src/tools/ranges/TransformIterator/test/TransformIterator.test.cpp +++ /dev/null @@ -1,85 +0,0 @@ -// include Catch2 -#include - -// what we are testing -#include "tools/ranges/TransformIterator.hpp" - -// other includes - -// convenience typedefs -using namespace njoy::tools::ranges; - -SCENARIO( "TransformIterator" ) { - - GIVEN( "a container with values and a transformation operation" ) { - - std::vector< int > values = { -2, -1, 0, 1, 2 }; - auto transform = [] ( auto&& value ) { return 2 * value; }; - - WHEN( "when iterators are used" ) { - - TransformIterator iter( values.begin(), transform ); - TransformIterator begin( values.begin(), transform ); - TransformIterator end( values.end(), transform ); - - THEN( "TransformIterator behaves as an iterator" ) { - - CHECK( *iter == -4 ); - - CHECK( iter[0] == -4 ); - CHECK( iter[1] == -2 ); - CHECK( iter[2] == 0 ); - CHECK( iter[3] == 2 ); - CHECK( iter[4] == 4 ); - - CHECK( *( begin + 0 ) == -4 ); - CHECK( *( begin + 1 ) == -2 ); - CHECK( *( begin + 2 ) == 0 ); - CHECK( *( begin + 3 ) == 2 ); - CHECK( *( begin + 4 ) == 4 ); - - CHECK( *( 0 + begin ) == -4 ); - CHECK( *( 1 + begin ) == -2 ); - CHECK( *( 2 + begin ) == 0 ); - CHECK( *( 3 + begin ) == 2 ); - CHECK( *( 4 + begin ) == 4 ); - - CHECK( *( end - 1 ) == 4 ); - CHECK( *( end - 2 ) == 2 ); - CHECK( *( end - 3 ) == 0 ); - CHECK( *( end - 4 ) == -2 ); - CHECK( *( end - 5 ) == -4 ); - - CHECK( end - begin == 5 ); - - iter += 3; - CHECK( *iter == 2 ); - iter -= 3; - CHECK( *iter == -4 ); - - ++iter; - CHECK( *iter == -2 ); - --iter; - CHECK( *iter == -4 ); - - CHECK( *( iter++ ) == -4 ); - CHECK( *iter == -2 ); - CHECK( *( iter-- ) == -2 ); - CHECK( *iter == -4 ); - - CHECK( true == ( iter == begin ) ); - CHECK( false == ( iter == end ) ); - CHECK( true == ( iter != end ) ); - CHECK( false == ( iter != begin ) ); - CHECK( true == ( iter < end ) ); - CHECK( false == ( iter < begin ) ); - CHECK( true == ( iter <= begin ) ); - CHECK( false == ( end <= iter ) ); - CHECK( true == ( end > iter ) ); - CHECK( false == ( iter > begin ) ); - CHECK( true == ( end >= iter ) ); - CHECK( false == ( begin >= end ) ); - } // THEN - } // WHEN - } // GIVEN -} // SCENARIO From fdc13b1cef401db3673b0be360eb4c3675f1a401 Mon Sep 17 00:00:00 2001 From: Wim Haeck Date: Wed, 1 Nov 2023 15:52:09 -0600 Subject: [PATCH 02/18] Adding unused include --- src/tools/ranges/IteratorView.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tools/ranges/IteratorView.hpp b/src/tools/ranges/IteratorView.hpp index 5a09759..3359456 100644 --- a/src/tools/ranges/IteratorView.hpp +++ b/src/tools/ranges/IteratorView.hpp @@ -3,7 +3,6 @@ // system includes #include -#include // other includes #include "tools/ranges/ViewBase.hpp" From c9c5119cdcf548fb08174036b7645a6ff73d6a63 Mon Sep 17 00:00:00 2001 From: Wim Haeck Date: Wed, 1 Nov 2023 15:52:47 -0600 Subject: [PATCH 03/18] Adding TransformView --- src/tools/ranges/TransformView.hpp | 239 ++++++++++++++++++ .../ranges/TransformView/test/CMakeLists.txt | 1 + .../TransformView/test/TransformView.test.cpp | 150 +++++++++++ 3 files changed, 390 insertions(+) create mode 100644 src/tools/ranges/TransformView.hpp create mode 100644 src/tools/ranges/TransformView/test/CMakeLists.txt create mode 100644 src/tools/ranges/TransformView/test/TransformView.test.cpp diff --git a/src/tools/ranges/TransformView.hpp b/src/tools/ranges/TransformView.hpp new file mode 100644 index 0000000..cfd20fd --- /dev/null +++ b/src/tools/ranges/TransformView.hpp @@ -0,0 +1,239 @@ +#ifndef NJOY_TOOLS_RANGES_TRANSFORMVIEW +#define NJOY_TOOLS_RANGES_TRANSFORMVIEW + +// system includes +#include +#include + +// other includes +#include "tools/ranges/ViewBase.hpp" +#include "tools/ranges/IteratorView.hpp" +#include "tools/ranges/make_view.hpp" + +namespace njoy { +namespace tools { +namespace ranges { + +/** + * + * @brief A simple iterator based view class + * + * Currently only defined for random access iterators. + */ +template < typename Range, typename Transform > +class TransformView : public ViewBase< TransformView< Range, Transform > > { + + /* type aliases */ + using BaseIterator = typename Range::const_iterator; + + /* fields */ + IteratorView< BaseIterator > base_; + Transform transform_; + +public: + + class Iterator { + + BaseIterator iter_; + std::reference_wrapper< const Transform > transform_; + + public: + + using iterator_category = typename BaseIterator::iterator_category; + using difference_type = typename BaseIterator::difference_type; + using value_type = decltype( std::declval< Transform >()( std::declval< typename BaseIterator::value_type >() ) ); + using pointer = value_type*; + using reference = value_type; + + /* constructor */ + + constexpr Iterator() = default; + + /** + * @brief Constructor + * + * @param[in] iter the iterator + * @param[in] transform the transformation to be applied + */ + constexpr Iterator( BaseIterator iter, + const Transform& transform ) : + iter_( std::move( iter ) ), transform_( std::cref( transform ) ) {} + + /* methods */ + + constexpr reference operator*() const { + + return this->transform_( *this->iter_ ); + } + + constexpr reference operator[]( difference_type i ) const { + + return this->transform_( this->iter_[i] ); + } + + constexpr Iterator& operator+=( difference_type i ) { + + this->iter_ += i; + return *this; + } + + constexpr Iterator& operator-=( difference_type i ) { + + this->iter_ -= i; + return *this; + } + + constexpr Iterator& operator++( void ) { + + ++this->iter_; + return *this; + } + + constexpr Iterator operator++( int ) { + + return Iterator( this->iter_++, transform_ ); + } + + constexpr Iterator& operator--( void ) { + + --this->iter_; + return *this; + } + + constexpr Iterator operator--( int ) { + + return Iterator( this->iter_--, this->transform_ ); + } + + friend constexpr Iterator operator+( difference_type i, Iterator iter ) { + + return Iterator( iter.iter_ + i, iter.transform_ ); + } + + friend constexpr Iterator operator+( Iterator iter, difference_type i ) { + + return Iterator( iter.iter_ + i, iter.transform_ ); + } + + friend constexpr Iterator operator-( Iterator iter, difference_type i ) { + + return Iterator( iter.iter_ - i, iter.transform_ ); + } + + friend constexpr difference_type operator-( const Iterator& left, + const Iterator& right ) { + + return left.iter_ - right.iter_; + } + + friend constexpr bool operator==( const Iterator& left, + const Iterator& right ) { + + return left.iter_ == right.iter_; + }; + + friend constexpr bool operator!=( const Iterator& left, + const Iterator& right ) { + + return !( left == right ); + }; + + friend constexpr bool operator<( const Iterator& left, + const Iterator& right) { + + return left.iter_ < right.iter_; + } + + friend constexpr bool operator>( const Iterator& left, + const Iterator& right ) { + + return right < left; + } + + friend constexpr bool operator<=( const Iterator& left, + const Iterator& right ) { + + return !( right < left ); + } + + friend constexpr bool operator>=( const Iterator& left, + const Iterator& right ) { + + return !( left < right ); + } + }; + + using value_type = typename std::iterator_traits< Iterator >::value_type; + using difference_type = typename std::iterator_traits< Iterator >::difference_type; + using size_type = std::size_t; + using pointer = typename std::iterator_traits< Iterator >::pointer; + using reference = typename std::iterator_traits< Iterator >::reference; + using const_reference = const reference; + using iterator = Iterator; + + /* constructor */ + + /** + * @brief Default constructor + */ + constexpr TransformView() = delete; + + /** + * @brief Constructor + * + * @param[in] begin the iterator to the beginning of the view + * @param[in] end the iterator to the end of the view + */ + constexpr TransformView( const Range& range, Transform transform ) : + base_( make_view( range ) ), + transform_( std::move( transform ) ) {} + + /* methods */ + + /** + * @brief Return the begin iterator to the view + */ + constexpr iterator begin() const noexcept { + + return Iterator{ this->base_.begin(), this->transform_ }; + } + + /** + * @brief Return the end iterator to the view + */ + constexpr iterator end() const noexcept { + + return Iterator{ this->base_.end(), this->transform_ }; + } +}; + + +/** + * @brief Verify if the TransformView is equal to another container + * + * @param[in] other the other container to compare with + */ +template < typename Container, typename Range, typename Transform > +constexpr bool operator==( const Container& left, + TransformView< Range, Transform > right ) { + + return right == left; +} + +/** + * @brief Verify if the TransformView is equal to another container + * + * @param[in] other the other container to compare with + */ +template < typename Container, typename Range, typename Transform > +constexpr bool operator!=( const Container& left, + TransformView< Range, Transform > right ) { + + return right != left; +} + +} // ranges namespace +} // tools namespace +} // njoy namespace + +#endif diff --git a/src/tools/ranges/TransformView/test/CMakeLists.txt b/src/tools/ranges/TransformView/test/CMakeLists.txt new file mode 100644 index 0000000..466f579 --- /dev/null +++ b/src/tools/ranges/TransformView/test/CMakeLists.txt @@ -0,0 +1 @@ +add_cpp_test( ranges.TransformView TransformView.test.cpp ) diff --git a/src/tools/ranges/TransformView/test/TransformView.test.cpp b/src/tools/ranges/TransformView/test/TransformView.test.cpp new file mode 100644 index 0000000..adb2f82 --- /dev/null +++ b/src/tools/ranges/TransformView/test/TransformView.test.cpp @@ -0,0 +1,150 @@ +// include Catch2 +#include + +// what we are testing +#include "tools/ranges/TransformView.hpp" + +// other includes +#include +#include +#include + +// convenience typedefs +using namespace njoy::tools::ranges; + +SCENARIO( "TransformView" ) { + + auto transform = [] ( auto&& value ) { return value - 2; }; + + GIVEN( "a container with forward iterators" ) { + + std::forward_list< int > values = { 0, 1, 2, 3, 4 }; + + WHEN( "when the container and the transformation are used" ) { + + TransformView chunk( values, transform ); + + THEN( "an TransformView can be constructed and members can be tested" ) { + + CHECK( 5 == chunk.size() ); + CHECK( false == chunk.empty() ); + CHECK( false == bool( chunk ) ); + + // the following should not compile: no random access iterator + // CHECK( -2 == chunk[0] ); + // CHECK( -2 == chunk.at(0) ); + + CHECK( -2 == chunk.front() ); + + // the following should not compile: no bidirectional iterator + // CHECK( 2 == chunk.back() ); + } // THEN + } // WHEN + } // GIVEN + + GIVEN( "a container with bidirectional iterators" ) { + + std::list< int > values = { 0, 1, 2, 3, 4 }; + + WHEN( "when the container and the transformation are used" ) { + + TransformView chunk( values, transform ); + + THEN( "an TransformView can be constructed and members can be tested" ) { + + CHECK( 5 == chunk.size() ); + CHECK( false == chunk.empty() ); + CHECK( false == bool( chunk ) ); + + // the following should not compile: no random access iterator + // CHECK( -2 == chunk[0] ); + // CHECK( -2 == chunk.at(0) ); + + CHECK( -2 == chunk.front() ); + CHECK( 2 == chunk.back() ); + } // THEN + } // WHEN + } // GIVEN + + GIVEN( "a container with random access iterators" ) { + + std::vector< int > values = { 0, 1, 2, 3, 4 }; + + WHEN( "when the container and the transformation are used" ) { + + TransformView chunk( values, transform ); + + THEN( "an TransformView can be constructed and members can be tested" ) { + + CHECK( 5 == chunk.size() ); + CHECK( false == chunk.empty() ); + CHECK( false == bool( chunk ) ); + + CHECK( -2 == chunk[0] ); + CHECK( -1 == chunk[1] ); + CHECK( 0 == chunk[2] ); + CHECK( 1 == chunk[3] ); + CHECK( 2 == chunk[4] ); + + CHECK( -2 == chunk.at( 0 ) ); + CHECK( -1 == chunk.at( 1 ) ); + CHECK( 0 == chunk.at( 2 ) ); + CHECK( 1 == chunk.at( 3 ) ); + CHECK( 2 == chunk.at( 4 ) ); + + CHECK( -2 == chunk.front() ); + CHECK( 2 == chunk.back() ); + } // THEN + + THEN( "an exception is thrown when using an index that is too large or " + "too small" ) { + + CHECK_NOTHROW( chunk.at( 0 ) ); + CHECK_NOTHROW( chunk.at( 4 ) ); + CHECK_THROWS( chunk.at( 5 ) ); + CHECK_THROWS( chunk.at( 10 ) ); + } // THEN + } // WHEN + } // GIVEN + + GIVEN( "containers and views with values" ) { + + std::vector< double > base1 = { 1., 2., 3., 4. }; + std::vector< double > base2 = { 1., 2., 3. }; + + std::vector< double > container1 = { -1., 0., 1., 2. }; + std::vector< double > container2 = { -1., 0., 1. }; + + std::vector< double > copy1 = container1; + std::vector< double > copy2 = container2; + + TransformView view1( base1, transform ); + TransformView view2( base2, transform ); + + WHEN( "when comparison functions are used" ) { + + THEN( "views and containers can be compared" ) { + + CHECK( view1 == container1 ); + CHECK( view1 == copy1 ); + CHECK( container1 == view1 ); + CHECK( copy1 == view1 ); + + CHECK( view1 != container2 ); + CHECK( view1 != copy2 ); + CHECK( container2 != view1 ); + CHECK( copy2 != view1 ); + + CHECK( view2 == container2 ); + CHECK( view2 == copy2 ); + CHECK( container2 == view2 ); + CHECK( copy2 == view2 ); + + CHECK( view2 != container1 ); + CHECK( view2 != copy1 ); + CHECK( container1 != view2 ); + CHECK( copy1 != view2 ); + } // THEN + } // WHEN + } // GIVEN +} // SCENARIO From e7a1e0b42f76b32092f65e1734ab0ddc00286435 Mon Sep 17 00:00:00 2001 From: Wim Haeck Date: Wed, 1 Nov 2023 15:53:15 -0600 Subject: [PATCH 04/18] updating make_transform_view --- src/tools/ranges/make_transform_view.hpp | 24 +----- .../test/make_transform_view.test.cpp | 85 +++++++++++++------ 2 files changed, 60 insertions(+), 49 deletions(-) diff --git a/src/tools/ranges/make_transform_view.hpp b/src/tools/ranges/make_transform_view.hpp index 29a3244..34600ad 100644 --- a/src/tools/ranges/make_transform_view.hpp +++ b/src/tools/ranges/make_transform_view.hpp @@ -4,31 +4,14 @@ // system includes // other includes -#include "tools/ranges/IteratorView.hpp" -#include "tools/ranges/TransformIterator.hpp" +#include "tools/ranges/TransformView.hpp" namespace njoy { namespace tools { namespace ranges { /** - * @brief Make an IteratorView based on two iterators and a transformation - * - * @param[in] begin the iterator to the beginning of the view - * @param[in] end the iterator to the end of the view - * @param[in] transformation the transformation to be applied - */ -template < typename Iterator, typename Transformation > -constexpr auto make_transform_view( Iterator begin, Iterator end, - Transformation transformation ) { - - using Iter = TransformIterator< Iterator, Transformation >; - return IteratorView< Iter >{ Iter( std::move( begin ), transformation ), - Iter( std::move( end ), transformation ) }; -} - -/** - * @brief Make an IteratorView based on a container and a transformation + * @brief Make an TransformView based on a container and a transformation * * @param[in] container the container * @param[in] transformation the transformation to be applied @@ -37,8 +20,7 @@ template < typename Container, typename Transformation > constexpr auto make_transform_view( Container&& container, Transformation transformation ) { - return make_transform_view( container.begin(), container.end(), - std::move( transformation ) ); + return TransformView( container, std::move( transformation ) ); } } // ranges namespace diff --git a/src/tools/ranges/make_transform_view/test/make_transform_view.test.cpp b/src/tools/ranges/make_transform_view/test/make_transform_view.test.cpp index 2b787fc..55e6797 100644 --- a/src/tools/ranges/make_transform_view/test/make_transform_view.test.cpp +++ b/src/tools/ranges/make_transform_view/test/make_transform_view.test.cpp @@ -5,44 +5,72 @@ #include "tools/ranges/make_transform_view.hpp" // other includes +#include +#include +#include // convenience typedefs using namespace njoy::tools::ranges; SCENARIO( "make_view" ) { - GIVEN( "a container with values and a transformation" ) { + auto transform = [] ( auto&& value ) { return value - 2; }; - std::vector< int > values = { -2, -1, 0, 1, 2 }; - auto transform = [] ( auto&& value ) { return 2 * value; }; + GIVEN( "a container with forward iterators" ) { - WHEN( "when using iterators and the transformation" ) { + std::forward_list< int > values = { 0, 1, 2, 3, 4 }; - auto chunk = make_transform_view( values.begin(), values.end(), transform ); + WHEN( "when the container and the transformation are used" ) { + + auto chunk = make_transform_view( values, transform ); THEN( "an IteratorView can be constructed and members can be tested" ) { CHECK( 5 == chunk.size() ); CHECK( false == chunk.empty() ); + CHECK( false == bool( chunk ) ); - CHECK( -4 == chunk[0] ); - CHECK( -2 == chunk[1] ); - CHECK( 0 == chunk[2] ); - CHECK( 2 == chunk[3] ); - CHECK( 4 == chunk[4] ); + // the following should not compile: no random access iterator + // CHECK( -2 == chunk[0] ); + // CHECK( -2 == chunk.at(0) ); - CHECK( -4 == chunk.at( 0 ) ); - CHECK( -2 == chunk.at( 1 ) ); - CHECK( 0 == chunk.at( 2 ) ); - CHECK( 2 == chunk.at( 3 ) ); - CHECK( 4 == chunk.at( 4 ) ); + CHECK( -2 == chunk.front() ); + + // the following should not compile: no bidirectional iterator + // CHECK( 2 == chunk.back() ); + } // THEN + } // WHEN + } // GIVEN + + GIVEN( "a container with bidirectional iterators" ) { + + std::list< int > values = { 0, 1, 2, 3, 4 }; + + WHEN( "when the container and the transformation are used" ) { - CHECK( -4 == chunk.front() ); - CHECK( 4 == chunk.back() ); + auto chunk = make_transform_view( values, transform ); + + THEN( "an IteratorView can be constructed and members can be tested" ) { + + CHECK( 5 == chunk.size() ); + CHECK( false == chunk.empty() ); + CHECK( false == bool( chunk ) ); + + // the following should not compile: no random access iterator + // CHECK( -2 == chunk[0] ); + // CHECK( -2 == chunk.at(0) ); + + CHECK( -2 == chunk.front() ); + CHECK( 2 == chunk.back() ); } // THEN } // WHEN + } // GIVEN + + GIVEN( "a container with random access iterators" ) { + + std::vector< int > values = { 0, 1, 2, 3, 4 }; - WHEN( "when using the container and the transformation" ) { + WHEN( "when the container and the transformation are used" ) { auto chunk = make_transform_view( values, transform ); @@ -50,21 +78,22 @@ SCENARIO( "make_view" ) { CHECK( 5 == chunk.size() ); CHECK( false == chunk.empty() ); + CHECK( false == bool( chunk ) ); - CHECK( -4 == chunk[0] ); - CHECK( -2 == chunk[1] ); + CHECK( -2 == chunk[0] ); + CHECK( -1 == chunk[1] ); CHECK( 0 == chunk[2] ); - CHECK( 2 == chunk[3] ); - CHECK( 4 == chunk[4] ); + CHECK( 1 == chunk[3] ); + CHECK( 2 == chunk[4] ); - CHECK( -4 == chunk.at( 0 ) ); - CHECK( -2 == chunk.at( 1 ) ); + CHECK( -2 == chunk.at( 0 ) ); + CHECK( -1 == chunk.at( 1 ) ); CHECK( 0 == chunk.at( 2 ) ); - CHECK( 2 == chunk.at( 3 ) ); - CHECK( 4 == chunk.at( 4 ) ); + CHECK( 1 == chunk.at( 3 ) ); + CHECK( 2 == chunk.at( 4 ) ); - CHECK( -4 == chunk.front() ); - CHECK( 4 == chunk.back() ); + CHECK( -2 == chunk.front() ); + CHECK( 2 == chunk.back() ); } // THEN } // WHEN } // GIVEN From 13c05bd3436eeab948ac5c35d61b16ff8c3820bc Mon Sep 17 00:00:00 2001 From: Wim Haeck Date: Wed, 1 Nov 2023 15:53:34 -0600 Subject: [PATCH 05/18] Updating unit test file --- cmake/unit_testing.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/unit_testing.cmake b/cmake/unit_testing.cmake index c859835..8830482 100644 --- a/cmake/unit_testing.cmake +++ b/cmake/unit_testing.cmake @@ -33,6 +33,6 @@ add_subdirectory( src/tools/concepts/IsRange/test ) add_subdirectory( src/tools/concepts/IsIterator/test ) add_subdirectory( src/tools/ranges/IteratorView/test ) -add_subdirectory( src/tools/ranges/TransformIterator/test ) +add_subdirectory( src/tools/ranges/TransformView/test ) add_subdirectory( src/tools/ranges/make_view/test ) add_subdirectory( src/tools/ranges/make_transform_view/test ) From 2ebca9df323c5c4a7fafb4bde88fa37a75606f2c Mon Sep 17 00:00:00 2001 From: Wim Haeck Date: Wed, 1 Nov 2023 18:13:33 -0600 Subject: [PATCH 06/18] Moving code around --- src/tools/ranges/TransformView.hpp | 137 +------------------- src/tools/ranges/TransformView/Iterator.hpp | 130 +++++++++++++++++++ 2 files changed, 134 insertions(+), 133 deletions(-) create mode 100644 src/tools/ranges/TransformView/Iterator.hpp diff --git a/src/tools/ranges/TransformView.hpp b/src/tools/ranges/TransformView.hpp index cfd20fd..d6b7b38 100644 --- a/src/tools/ranges/TransformView.hpp +++ b/src/tools/ranges/TransformView.hpp @@ -32,136 +32,7 @@ class TransformView : public ViewBase< TransformView< Range, Transform > > { public: - class Iterator { - - BaseIterator iter_; - std::reference_wrapper< const Transform > transform_; - - public: - - using iterator_category = typename BaseIterator::iterator_category; - using difference_type = typename BaseIterator::difference_type; - using value_type = decltype( std::declval< Transform >()( std::declval< typename BaseIterator::value_type >() ) ); - using pointer = value_type*; - using reference = value_type; - - /* constructor */ - - constexpr Iterator() = default; - - /** - * @brief Constructor - * - * @param[in] iter the iterator - * @param[in] transform the transformation to be applied - */ - constexpr Iterator( BaseIterator iter, - const Transform& transform ) : - iter_( std::move( iter ) ), transform_( std::cref( transform ) ) {} - - /* methods */ - - constexpr reference operator*() const { - - return this->transform_( *this->iter_ ); - } - - constexpr reference operator[]( difference_type i ) const { - - return this->transform_( this->iter_[i] ); - } - - constexpr Iterator& operator+=( difference_type i ) { - - this->iter_ += i; - return *this; - } - - constexpr Iterator& operator-=( difference_type i ) { - - this->iter_ -= i; - return *this; - } - - constexpr Iterator& operator++( void ) { - - ++this->iter_; - return *this; - } - - constexpr Iterator operator++( int ) { - - return Iterator( this->iter_++, transform_ ); - } - - constexpr Iterator& operator--( void ) { - - --this->iter_; - return *this; - } - - constexpr Iterator operator--( int ) { - - return Iterator( this->iter_--, this->transform_ ); - } - - friend constexpr Iterator operator+( difference_type i, Iterator iter ) { - - return Iterator( iter.iter_ + i, iter.transform_ ); - } - - friend constexpr Iterator operator+( Iterator iter, difference_type i ) { - - return Iterator( iter.iter_ + i, iter.transform_ ); - } - - friend constexpr Iterator operator-( Iterator iter, difference_type i ) { - - return Iterator( iter.iter_ - i, iter.transform_ ); - } - - friend constexpr difference_type operator-( const Iterator& left, - const Iterator& right ) { - - return left.iter_ - right.iter_; - } - - friend constexpr bool operator==( const Iterator& left, - const Iterator& right ) { - - return left.iter_ == right.iter_; - }; - - friend constexpr bool operator!=( const Iterator& left, - const Iterator& right ) { - - return !( left == right ); - }; - - friend constexpr bool operator<( const Iterator& left, - const Iterator& right) { - - return left.iter_ < right.iter_; - } - - friend constexpr bool operator>( const Iterator& left, - const Iterator& right ) { - - return right < left; - } - - friend constexpr bool operator<=( const Iterator& left, - const Iterator& right ) { - - return !( right < left ); - } - - friend constexpr bool operator>=( const Iterator& left, - const Iterator& right ) { - - return !( left < right ); - } - }; + #include "tools/ranges/TransformView/Iterator.hpp" using value_type = typename std::iterator_traits< Iterator >::value_type; using difference_type = typename std::iterator_traits< Iterator >::difference_type; @@ -193,15 +64,15 @@ class TransformView : public ViewBase< TransformView< Range, Transform > > { /** * @brief Return the begin iterator to the view */ - constexpr iterator begin() const noexcept { + constexpr iterator begin() const noexcept { - return Iterator{ this->base_.begin(), this->transform_ }; + return Iterator{ this->base_.begin(), this->transform_ }; } /** * @brief Return the end iterator to the view */ - constexpr iterator end() const noexcept { + constexpr iterator end() const noexcept { return Iterator{ this->base_.end(), this->transform_ }; } diff --git a/src/tools/ranges/TransformView/Iterator.hpp b/src/tools/ranges/TransformView/Iterator.hpp new file mode 100644 index 0000000..6b334c6 --- /dev/null +++ b/src/tools/ranges/TransformView/Iterator.hpp @@ -0,0 +1,130 @@ +class Iterator { + + BaseIterator iter_; + std::reference_wrapper< const Transform > transform_; + +public: + + using iterator_category = typename BaseIterator::iterator_category; + using difference_type = typename BaseIterator::difference_type; + using value_type = decltype( std::declval< Transform >()( std::declval< typename BaseIterator::value_type >() ) ); + using pointer = value_type*; + using reference = value_type; + + /* constructor */ + + constexpr Iterator() = default; + + /** + * @brief Constructor + * + * @param[in] iter the iterator + * @param[in] transform the transformation to be applied + */ + constexpr Iterator( BaseIterator iter, + const Transform& transform ) : + iter_( std::move( iter ) ), transform_( std::cref( transform ) ) {} + + /* methods */ + + constexpr reference operator*() const { + + return this->transform_( *this->iter_ ); + } + + constexpr reference operator[]( difference_type i ) const { + + return this->transform_( this->iter_[i] ); + } + + constexpr Iterator& operator+=( difference_type i ) { + + this->iter_ += i; + return *this; + } + + constexpr Iterator& operator-=( difference_type i ) { + + this->iter_ -= i; + return *this; + } + + constexpr Iterator& operator++( void ) { + + ++this->iter_; + return *this; + } + + constexpr Iterator operator++( int ) { + + return Iterator( this->iter_++, transform_ ); + } + + constexpr Iterator& operator--( void ) { + + --this->iter_; + return *this; + } + + constexpr Iterator operator--( int ) { + + return Iterator( this->iter_--, this->transform_ ); + } + + friend constexpr Iterator operator+( difference_type i, Iterator iter ) { + + return Iterator( iter.iter_ + i, iter.transform_ ); + } + + friend constexpr Iterator operator+( Iterator iter, difference_type i ) { + + return Iterator( iter.iter_ + i, iter.transform_ ); + } + + friend constexpr Iterator operator-( Iterator iter, difference_type i ) { + + return Iterator( iter.iter_ - i, iter.transform_ ); + } + + friend constexpr difference_type operator-( const Iterator& left, + const Iterator& right ) { + + return left.iter_ - right.iter_; + } + + friend constexpr bool operator==( const Iterator& left, + const Iterator& right ) { + + return left.iter_ == right.iter_; + }; + + friend constexpr bool operator!=( const Iterator& left, + const Iterator& right ) { + + return !( left == right ); + }; + + friend constexpr bool operator<( const Iterator& left, + const Iterator& right) { + + return left.iter_ < right.iter_; + } + + friend constexpr bool operator>( const Iterator& left, + const Iterator& right ) { + + return right < left; + } + + friend constexpr bool operator<=( const Iterator& left, + const Iterator& right ) { + + return !( right < left ); + } + + friend constexpr bool operator>=( const Iterator& left, + const Iterator& right ) { + + return !( left < right ); + } +}; From 760409bc82cbe47aa1ea34ffdaf711aa9d9c6158 Mon Sep 17 00:00:00 2001 From: Wim Haeck Date: Wed, 1 Nov 2023 18:13:52 -0600 Subject: [PATCH 07/18] Updating includes and removing whitespace --- src/tools.hpp | 1 + src/tools/ranges/ViewBase.hpp | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/tools.hpp b/src/tools.hpp index 149d220..1280c77 100644 --- a/src/tools.hpp +++ b/src/tools.hpp @@ -1,4 +1,5 @@ #include "tools/overload.hpp" +#include "tools/concepts.hpp" #include "tools/ranges.hpp" #include "tools/Log.hpp" diff --git a/src/tools/ranges/ViewBase.hpp b/src/tools/ranges/ViewBase.hpp index f9ea6dd..99c7de1 100644 --- a/src/tools/ranges/ViewBase.hpp +++ b/src/tools/ranges/ViewBase.hpp @@ -162,8 +162,8 @@ class ViewBase { typename Range::iterator > = true > constexpr bool empty() const noexcept { - static_assert( - concepts::IsForwardIterator< typename Range::iterator >::value == true, + static_assert( + concepts::IsForwardIterator< typename Range::iterator >::value == true, "the empty() method can only be made available for forward iterators" ); return true; } @@ -173,8 +173,8 @@ class ViewBase { typename Range::iterator > = true > constexpr explicit operator bool() const noexcept { - static_assert( - concepts::IsForwardIterator< typename Range::iterator >::value == true, + static_assert( + concepts::IsForwardIterator< typename Range::iterator >::value == true, "the operator bool() method can only be made available for forward iterators" ); return true; } @@ -184,8 +184,8 @@ class ViewBase { typename Range::iterator > = true > constexpr std::size_t size() const noexcept { - static_assert( - concepts::IsForwardIterator< typename Range::iterator >::value == true, + static_assert( + concepts::IsForwardIterator< typename Range::iterator >::value == true, "the size() method can only be made available for forward iterators" ); return std::size_t{}; } @@ -195,8 +195,8 @@ class ViewBase { typename Range::iterator > = true > constexpr decltype(auto) front() const noexcept { - static_assert( - concepts::IsBidirectionalIterator< typename Range::iterator >::value == true, + static_assert( + concepts::IsBidirectionalIterator< typename Range::iterator >::value == true, "the front() method can only be made available for bidirectional iterators" ); return typename Derived::value_type{}; } @@ -206,8 +206,8 @@ class ViewBase { typename Range::iterator > = true > constexpr decltype(auto) back() const noexcept { - static_assert( - concepts::IsBidirectionalIterator< typename Range::iterator >::value == true, + static_assert( + concepts::IsBidirectionalIterator< typename Range::iterator >::value == true, "the back() method can only be made available for bidirectional iterators" ); return typename Derived::value_type{}; } @@ -217,8 +217,8 @@ class ViewBase { typename Range::iterator > = true > constexpr decltype(auto) operator[]( std::size_t i ) const { - static_assert( - concepts::IsRandomAccessIterator< typename Range::iterator >::value == true, + static_assert( + concepts::IsRandomAccessIterator< typename Range::iterator >::value == true, "the operator[] method can only be made available for random access iterators" ); return typename Derived::value_type{}; } @@ -228,8 +228,8 @@ class ViewBase { typename Range::iterator > = true > constexpr decltype(auto) at( std::size_t i ) const { - static_assert( - concepts::IsRandomAccessIterator< typename Range::iterator >::value == true, + static_assert( + concepts::IsRandomAccessIterator< typename Range::iterator >::value == true, "the at() method can only be made available for random access iterators" ); return typename Derived::value_type{}; } From a0ee6ce75c7d895fd7fcaa9f1e5bf33d41b62d73 Mon Sep 17 00:00:00 2001 From: Wim Haeck Date: Thu, 2 Nov 2023 09:14:04 -0600 Subject: [PATCH 08/18] The transform view needs to take possession of the base range --- src/tools/ranges/TransformView.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/ranges/TransformView.hpp b/src/tools/ranges/TransformView.hpp index d6b7b38..762ce86 100644 --- a/src/tools/ranges/TransformView.hpp +++ b/src/tools/ranges/TransformView.hpp @@ -27,7 +27,7 @@ class TransformView : public ViewBase< TransformView< Range, Transform > > { using BaseIterator = typename Range::const_iterator; /* fields */ - IteratorView< BaseIterator > base_; + Range base_; Transform transform_; public: @@ -55,8 +55,8 @@ class TransformView : public ViewBase< TransformView< Range, Transform > > { * @param[in] begin the iterator to the beginning of the view * @param[in] end the iterator to the end of the view */ - constexpr TransformView( const Range& range, Transform transform ) : - base_( make_view( range ) ), + constexpr TransformView( Range range, Transform transform ) : + base_( std::move( range ) ), transform_( std::move( transform ) ) {} /* methods */ From 2d0fab5daa945e3ebca1ff8e6e94dcfd8e947f2b Mon Sep 17 00:00:00 2001 From: Wim Haeck Date: Thu, 2 Nov 2023 09:34:18 -0600 Subject: [PATCH 09/18] Small update --- src/tools/ranges/TransformView.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tools/ranges/TransformView.hpp b/src/tools/ranges/TransformView.hpp index 762ce86..ce0ee57 100644 --- a/src/tools/ranges/TransformView.hpp +++ b/src/tools/ranges/TransformView.hpp @@ -47,13 +47,13 @@ class TransformView : public ViewBase< TransformView< Range, Transform > > { /** * @brief Default constructor */ - constexpr TransformView() = delete; + constexpr TransformView() = default; /** * @brief Constructor * - * @param[in] begin the iterator to the beginning of the view - * @param[in] end the iterator to the end of the view + * @param[in] range the range to be transformed + * @param[in] transform the transformation to be applied to the range */ constexpr TransformView( Range range, Transform transform ) : base_( std::move( range ) ), From faa464ddea04a9928ac752023cf74981f48e301d Mon Sep 17 00:00:00 2001 From: Wim Haeck Date: Thu, 2 Nov 2023 13:56:58 -0600 Subject: [PATCH 10/18] Making sure the views are const --- src/tools/ranges/IteratorView.hpp | 1 + src/tools/ranges/TransformView.hpp | 3 ++- src/tools/ranges/make_transform_view.hpp | 4 +++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/tools/ranges/IteratorView.hpp b/src/tools/ranges/IteratorView.hpp index 3359456..c32986d 100644 --- a/src/tools/ranges/IteratorView.hpp +++ b/src/tools/ranges/IteratorView.hpp @@ -29,6 +29,7 @@ class IteratorView : public ViewBase< IteratorView< Iterator > > { using reference = typename std::iterator_traits< Iterator >::reference; using const_reference = const reference; using iterator = Iterator; + using const_iterator = const Iterator; private: diff --git a/src/tools/ranges/TransformView.hpp b/src/tools/ranges/TransformView.hpp index ce0ee57..27f8a13 100644 --- a/src/tools/ranges/TransformView.hpp +++ b/src/tools/ranges/TransformView.hpp @@ -24,7 +24,7 @@ template < typename Range, typename Transform > class TransformView : public ViewBase< TransformView< Range, Transform > > { /* type aliases */ - using BaseIterator = typename Range::const_iterator; + using BaseIterator = decltype( std::cbegin( std::declval< Range& >() ) ); /* fields */ Range base_; @@ -41,6 +41,7 @@ class TransformView : public ViewBase< TransformView< Range, Transform > > { using reference = typename std::iterator_traits< Iterator >::reference; using const_reference = const reference; using iterator = Iterator; + using const_iterator = const Iterator; /* constructor */ diff --git a/src/tools/ranges/make_transform_view.hpp b/src/tools/ranges/make_transform_view.hpp index 34600ad..4943d66 100644 --- a/src/tools/ranges/make_transform_view.hpp +++ b/src/tools/ranges/make_transform_view.hpp @@ -4,6 +4,7 @@ // system includes // other includes +#include "tools/ranges/IteratorView.hpp" #include "tools/ranges/TransformView.hpp" namespace njoy { @@ -20,7 +21,8 @@ template < typename Container, typename Transformation > constexpr auto make_transform_view( Container&& container, Transformation transformation ) { - return TransformView( container, std::move( transformation ) ); + return TransformView( IteratorView( container.cbegin(), container.cend() ), + std::move( transformation ) ); } } // ranges namespace From e240df7be11d47880add45b713c35d8c8eb461fc Mon Sep 17 00:00:00 2001 From: Wim Haeck Date: Thu, 2 Nov 2023 15:48:32 -0600 Subject: [PATCH 11/18] Adding cbegin and cend to views --- src/tools/ranges/IteratorView.hpp | 10 ++++++++++ src/tools/ranges/TransformView.hpp | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/tools/ranges/IteratorView.hpp b/src/tools/ranges/IteratorView.hpp index c32986d..6074956 100644 --- a/src/tools/ranges/IteratorView.hpp +++ b/src/tools/ranges/IteratorView.hpp @@ -66,6 +66,16 @@ class IteratorView : public ViewBase< IteratorView< Iterator > > { * @brief Return the end iterator to the view */ constexpr iterator end() const noexcept { return end_; } + + /** + * @brief Return the begin iterator to the view + */ + constexpr const_iterator cbegin() const noexcept { return this->begin(); } + + /** + * @brief Return the end iterator to the view + */ + constexpr const_iterator cend() const noexcept { return this->end(); } }; /** diff --git a/src/tools/ranges/TransformView.hpp b/src/tools/ranges/TransformView.hpp index 27f8a13..dc8a686 100644 --- a/src/tools/ranges/TransformView.hpp +++ b/src/tools/ranges/TransformView.hpp @@ -77,6 +77,16 @@ class TransformView : public ViewBase< TransformView< Range, Transform > > { return Iterator{ this->base_.end(), this->transform_ }; } + + /** + * @brief Return the begin iterator to the view + */ + constexpr const_iterator cbegin() const noexcept { return this->begin(); } + + /** + * @brief Return the end iterator to the view + */ + constexpr const_iterator cend() const noexcept { return this->end(); } }; From 9ec048b92e838746afdaab647f0b98debca1f64e Mon Sep 17 00:00:00 2001 From: Wim Haeck Date: Mon, 6 Nov 2023 08:57:34 -0700 Subject: [PATCH 12/18] Updating some documentation --- src/tools/ranges/IteratorView.hpp | 2 +- src/tools/ranges/TransformView.hpp | 4 +--- src/tools/ranges/make_transform_view.hpp | 4 ++++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/tools/ranges/IteratorView.hpp b/src/tools/ranges/IteratorView.hpp index 6074956..8c992ae 100644 --- a/src/tools/ranges/IteratorView.hpp +++ b/src/tools/ranges/IteratorView.hpp @@ -15,7 +15,7 @@ namespace ranges { * * @brief A simple iterator based view class * - * Currently only defined for random access iterators. + * It works on all types of iterators (input, forward, bidirectional and random). */ template < typename Iterator > class IteratorView : public ViewBase< IteratorView< Iterator > > { diff --git a/src/tools/ranges/TransformView.hpp b/src/tools/ranges/TransformView.hpp index dc8a686..263b2a6 100644 --- a/src/tools/ranges/TransformView.hpp +++ b/src/tools/ranges/TransformView.hpp @@ -16,9 +16,7 @@ namespace ranges { /** * - * @brief A simple iterator based view class - * - * Currently only defined for random access iterators. + * @brief A view that applies a transformation on every element of a range */ template < typename Range, typename Transform > class TransformView : public ViewBase< TransformView< Range, Transform > > { diff --git a/src/tools/ranges/make_transform_view.hpp b/src/tools/ranges/make_transform_view.hpp index 4943d66..d560df6 100644 --- a/src/tools/ranges/make_transform_view.hpp +++ b/src/tools/ranges/make_transform_view.hpp @@ -14,6 +14,10 @@ namespace ranges { /** * @brief Make an TransformView based on a container and a transformation * + * To avoid copying containers like vectors, maps, etc. into the TransportView, + * an IteratorView using constant iterators into the container is created + * to be moved into the TransportView. + * * @param[in] container the container * @param[in] transformation the transformation to be applied */ From 3207fe49c9b425b412e3034d5fd39d8c1fc13163 Mon Sep 17 00:00:00 2001 From: Wim Haeck Date: Tue, 7 Nov 2023 08:46:38 -0700 Subject: [PATCH 13/18] TransformView now contains an IteratorView --- src/tools/ranges/TransformView.hpp | 6 +++--- src/tools/ranges/make_transform_view.hpp | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/tools/ranges/TransformView.hpp b/src/tools/ranges/TransformView.hpp index 263b2a6..a2aacc5 100644 --- a/src/tools/ranges/TransformView.hpp +++ b/src/tools/ranges/TransformView.hpp @@ -25,7 +25,7 @@ class TransformView : public ViewBase< TransformView< Range, Transform > > { using BaseIterator = decltype( std::cbegin( std::declval< Range& >() ) ); /* fields */ - Range base_; + IteratorView< BaseIterator > base_; Transform transform_; public: @@ -54,8 +54,8 @@ class TransformView : public ViewBase< TransformView< Range, Transform > > { * @param[in] range the range to be transformed * @param[in] transform the transformation to be applied to the range */ - constexpr TransformView( Range range, Transform transform ) : - base_( std::move( range ) ), + constexpr TransformView( const Range& range, Transform transform ) : + base_( IteratorView( range.cbegin(), range.cend() ) ), transform_( std::move( transform ) ) {} /* methods */ diff --git a/src/tools/ranges/make_transform_view.hpp b/src/tools/ranges/make_transform_view.hpp index d560df6..5ed18bb 100644 --- a/src/tools/ranges/make_transform_view.hpp +++ b/src/tools/ranges/make_transform_view.hpp @@ -25,8 +25,7 @@ template < typename Container, typename Transformation > constexpr auto make_transform_view( Container&& container, Transformation transformation ) { - return TransformView( IteratorView( container.cbegin(), container.cend() ), - std::move( transformation ) ); + return TransformView( container, std::move( transformation ) ); } } // ranges namespace From afb0a54d15590e7d6b0518028c6f0cc57decc0a4 Mon Sep 17 00:00:00 2001 From: Wim Haeck Date: Tue, 7 Nov 2023 08:48:46 -0700 Subject: [PATCH 14/18] Moving documentation --- src/tools/ranges/TransformView.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tools/ranges/TransformView.hpp b/src/tools/ranges/TransformView.hpp index a2aacc5..12ee1a0 100644 --- a/src/tools/ranges/TransformView.hpp +++ b/src/tools/ranges/TransformView.hpp @@ -17,6 +17,10 @@ namespace ranges { /** * * @brief A view that applies a transformation on every element of a range + * + * To avoid copying containers like vectors, maps, etc. into the TransportView, + * an IteratorView using constant iterators into the container is created + * and stored inside the TransformView. */ template < typename Range, typename Transform > class TransformView : public ViewBase< TransformView< Range, Transform > > { From 1380282f0e350b7ad657ccdcfeb1c38c46e46164 Mon Sep 17 00:00:00 2001 From: Wim Haeck Date: Tue, 7 Nov 2023 08:49:48 -0700 Subject: [PATCH 15/18] Removed dpcumentation --- src/tools/ranges/make_transform_view.hpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/tools/ranges/make_transform_view.hpp b/src/tools/ranges/make_transform_view.hpp index 5ed18bb..35ba542 100644 --- a/src/tools/ranges/make_transform_view.hpp +++ b/src/tools/ranges/make_transform_view.hpp @@ -14,10 +14,6 @@ namespace ranges { /** * @brief Make an TransformView based on a container and a transformation * - * To avoid copying containers like vectors, maps, etc. into the TransportView, - * an IteratorView using constant iterators into the container is created - * to be moved into the TransportView. - * * @param[in] container the container * @param[in] transformation the transformation to be applied */ From 5015b1a8a43e30c0c848042430da484265394bee Mon Sep 17 00:00:00 2001 From: Wim Haeck Date: Tue, 7 Nov 2023 09:48:17 -0700 Subject: [PATCH 16/18] Adding range based loop test to views --- .../IteratorView/test/IteratorView.test.cpp | 21 +++++++++++++++++++ .../TransformView/test/TransformView.test.cpp | 21 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/src/tools/ranges/IteratorView/test/IteratorView.test.cpp b/src/tools/ranges/IteratorView/test/IteratorView.test.cpp index a129750..b338229 100644 --- a/src/tools/ranges/IteratorView/test/IteratorView.test.cpp +++ b/src/tools/ranges/IteratorView/test/IteratorView.test.cpp @@ -31,6 +31,13 @@ SCENARIO( "IteratorView" ) { CHECK( false == chunk.empty() ); CHECK( false == bool( chunk ) ); + unsigned int counter = 0; + for ( auto value : chunk ) { + + ++counter; + } + CHECK( 5 == counter ); + // the following should not compile: no random access iterator // CHECK( -2 == chunk[0] ); // CHECK( -2 == chunk.at(0) ); @@ -60,6 +67,13 @@ SCENARIO( "IteratorView" ) { CHECK( false == chunk.empty() ); CHECK( false == bool( chunk ) ); + unsigned int counter = 0; + for ( auto value : chunk ) { + + ++counter; + } + CHECK( 5 == counter ); + // the following should not compile: no random access iterator // CHECK( -2 == chunk[0] ); // CHECK( -2 == chunk.at(0) ); @@ -87,6 +101,13 @@ SCENARIO( "IteratorView" ) { CHECK( false == chunk.empty() ); CHECK( false == bool( chunk ) ); + unsigned int counter = 0; + for ( auto value : chunk ) { + + ++counter; + } + CHECK( 5 == counter ); + CHECK( -2 == chunk[0] ); CHECK( -1 == chunk[1] ); CHECK( 0 == chunk[2] ); diff --git a/src/tools/ranges/TransformView/test/TransformView.test.cpp b/src/tools/ranges/TransformView/test/TransformView.test.cpp index adb2f82..e1a5162 100644 --- a/src/tools/ranges/TransformView/test/TransformView.test.cpp +++ b/src/tools/ranges/TransformView/test/TransformView.test.cpp @@ -30,6 +30,13 @@ SCENARIO( "TransformView" ) { CHECK( false == chunk.empty() ); CHECK( false == bool( chunk ) ); + unsigned int counter = 0; + for ( auto value : chunk ) { + + ++counter; + } + CHECK( 5 == counter ); + // the following should not compile: no random access iterator // CHECK( -2 == chunk[0] ); // CHECK( -2 == chunk.at(0) ); @@ -56,6 +63,13 @@ SCENARIO( "TransformView" ) { CHECK( false == chunk.empty() ); CHECK( false == bool( chunk ) ); + unsigned int counter = 0; + for ( auto value : chunk ) { + + ++counter; + } + CHECK( 5 == counter ); + // the following should not compile: no random access iterator // CHECK( -2 == chunk[0] ); // CHECK( -2 == chunk.at(0) ); @@ -80,6 +94,13 @@ SCENARIO( "TransformView" ) { CHECK( false == chunk.empty() ); CHECK( false == bool( chunk ) ); + unsigned int counter = 0; + for ( auto value : chunk ) { + + ++counter; + } + CHECK( 5 == counter ); + CHECK( -2 == chunk[0] ); CHECK( -1 == chunk[1] ); CHECK( 0 == chunk[2] ); From 416d05686c4342c0409f37503310ee71b0a21230 Mon Sep 17 00:00:00 2001 From: Wim Haeck Date: Tue, 7 Nov 2023 09:49:37 -0700 Subject: [PATCH 17/18] Adding TransformView::Iterator test --- cmake/unit_testing.cmake | 1 + src/tools/ranges/TransformView/Iterator.hpp | 36 ++++ .../Iterator/test/CMakeLists.txt | 1 + .../Iterator/test/Iterator.test.cpp | 203 ++++++++++++++++++ 4 files changed, 241 insertions(+) create mode 100644 src/tools/ranges/TransformView/Iterator/test/CMakeLists.txt create mode 100644 src/tools/ranges/TransformView/Iterator/test/Iterator.test.cpp diff --git a/cmake/unit_testing.cmake b/cmake/unit_testing.cmake index 8830482..519262c 100644 --- a/cmake/unit_testing.cmake +++ b/cmake/unit_testing.cmake @@ -34,5 +34,6 @@ add_subdirectory( src/tools/concepts/IsIterator/test ) add_subdirectory( src/tools/ranges/IteratorView/test ) add_subdirectory( src/tools/ranges/TransformView/test ) +add_subdirectory( src/tools/ranges/TransformView/Iterator/test ) add_subdirectory( src/tools/ranges/make_view/test ) add_subdirectory( src/tools/ranges/make_transform_view/test ) diff --git a/src/tools/ranges/TransformView/Iterator.hpp b/src/tools/ranges/TransformView/Iterator.hpp index 6b334c6..7474d28 100644 --- a/src/tools/ranges/TransformView/Iterator.hpp +++ b/src/tools/ranges/TransformView/Iterator.hpp @@ -34,17 +34,29 @@ class Iterator { constexpr reference operator[]( difference_type i ) const { + static_assert( + concepts::IsRandomAccessIterator< Iterator >::value == true, + "the at() method can only be made available for random access iterators" ); + return this->transform_( this->iter_[i] ); } constexpr Iterator& operator+=( difference_type i ) { + static_assert( + concepts::IsRandomAccessIterator< Iterator >::value == true, + "the at() method can only be made available for random access iterators" ); + this->iter_ += i; return *this; } constexpr Iterator& operator-=( difference_type i ) { + static_assert( + concepts::IsRandomAccessIterator< Iterator >::value == true, + "the at() method can only be made available for random access iterators" ); + this->iter_ -= i; return *this; } @@ -62,33 +74,57 @@ class Iterator { constexpr Iterator& operator--( void ) { + static_assert( + concepts::IsBidirectionalIterator< Iterator >::value == true, + "the at() method can only be made available for bidirectional iterators" ); + --this->iter_; return *this; } constexpr Iterator operator--( int ) { + static_assert( + concepts::IsBidirectionalIterator< Iterator >::value == true, + "the at() method can only be made available for bidirectional iterators" ); + return Iterator( this->iter_--, this->transform_ ); } friend constexpr Iterator operator+( difference_type i, Iterator iter ) { + static_assert( + concepts::IsRandomAccessIterator< Iterator >::value == true, + "the at() method can only be made available for random access iterators" ); + return Iterator( iter.iter_ + i, iter.transform_ ); } friend constexpr Iterator operator+( Iterator iter, difference_type i ) { + static_assert( + concepts::IsRandomAccessIterator< Iterator >::value == true, + "the at() method can only be made available for random access iterators" ); + return Iterator( iter.iter_ + i, iter.transform_ ); } friend constexpr Iterator operator-( Iterator iter, difference_type i ) { + static_assert( + concepts::IsRandomAccessIterator< Iterator >::value == true, + "the at() method can only be made available for random access iterators" ); + return Iterator( iter.iter_ - i, iter.transform_ ); } friend constexpr difference_type operator-( const Iterator& left, const Iterator& right ) { + static_assert( + concepts::IsRandomAccessIterator< Iterator >::value == true, + "the at() method can only be made available for random access iterators" ); + return left.iter_ - right.iter_; } diff --git a/src/tools/ranges/TransformView/Iterator/test/CMakeLists.txt b/src/tools/ranges/TransformView/Iterator/test/CMakeLists.txt new file mode 100644 index 0000000..304d7ff --- /dev/null +++ b/src/tools/ranges/TransformView/Iterator/test/CMakeLists.txt @@ -0,0 +1 @@ +add_cpp_test( ranges.TransformView.Iterator Iterator.test.cpp ) diff --git a/src/tools/ranges/TransformView/Iterator/test/Iterator.test.cpp b/src/tools/ranges/TransformView/Iterator/test/Iterator.test.cpp new file mode 100644 index 0000000..1d7ae0f --- /dev/null +++ b/src/tools/ranges/TransformView/Iterator/test/Iterator.test.cpp @@ -0,0 +1,203 @@ +// include Catch2 +#include + +// what we are testing +#include "tools/ranges/TransformView.hpp" + +// other includes +#include +#include +#include + +// convenience typedefs +using namespace njoy::tools::ranges; + +SCENARIO( "TransformView" ) { + + auto transform = [] ( auto&& value ) { return value - 2; }; + + GIVEN( "a container with forward iterators" ) { + + std::forward_list< int > values = { 0, 1, 2, 3, 4 }; + + WHEN( "when the container and the transformation are used" ) { + + TransformView chunk( values, transform ); + + THEN( "the TransformView::Iterator functions as a normal forward iterator" ) { + + auto begin = chunk.begin(); + auto second = ++chunk.begin(); + auto end = chunk.end(); + auto iter = begin; + + unsigned int counter = 0; + for ( auto iter = begin; iter != end; ++iter ) { + + ++counter; + } + CHECK( 5 == counter ); + + CHECK( 5 == std::distance( begin, end ) ); + CHECK( begin != end ); + + CHECK( -2 == *begin ); + CHECK( -1 == *second ); + + // the following should not compile: no random access iterator + // CHECK( -2 == begin[0] ); + // CHECK( -1 == begin[1] ); + // CHECK( 0 == begin[2] ); + // CHECK( 1 == begin[3] ); + // CHECK( 2 == begin[4] ); + + // the following should not compile: no random access iterator + // iter += 1; + // CHECK( second == iter ); + // iter -= 1; + // CHECK( begin == iter ); + + CHECK( second == ++begin ); + // the following should not compile: no bidirectional iterator + // CHECK( begin == --begin ); + + begin = chunk.begin(); + iter = begin; + CHECK( begin == iter++ ); + CHECK( second == iter ); + // the following should not compile: no bidirectional iterator + // CHECK( second == iter-- ); + // CHECK( begin == iter ); + + // the following should not compile: no random access iterator + // iter = begin + 1; + // CHECK( second == iter ); + // iter = second - 1; + // CHECK( begin == iter ); + // iter = 1 + begin; + // CHECK( second == iter ); + } // THEN + } // WHEN + } // GIVEN + + GIVEN( "a container with bidirectional iterators" ) { + + std::list< int > values = { 0, 1, 2, 3, 4 }; + + WHEN( "when the container and the transformation are used" ) { + + TransformView chunk( values, transform ); + + THEN( "the TransformView::Iterator functions as a normal bidirectional iterator" ) { + + auto begin = chunk.begin(); + auto second = ++chunk.begin(); + auto end = chunk.end(); + auto iter = begin; + + unsigned int counter = 0; + for ( auto iter = begin; iter != end; ++iter ) { + + ++counter; + } + CHECK( 5 == counter ); + + CHECK( 5 == std::distance( begin, end ) ); + CHECK( begin != end ); + + CHECK( -2 == *begin ); + CHECK( -1 == *second ); + + // the following should not compile: no random access iterator + // CHECK( -2 == begin[0] ); + // CHECK( -1 == begin[1] ); + // CHECK( 0 == begin[2] ); + // CHECK( 1 == begin[3] ); + // CHECK( 2 == begin[4] ); + + // the following should not compile: no random access iterator + // iter += 1; + // CHECK( second == iter ); + // iter -= 1; + // CHECK( begin == iter ); + + CHECK( second == ++begin ); + CHECK( begin == --begin ); + + iter = begin; + CHECK( begin == iter++ ); + CHECK( second == iter ); + CHECK( second == iter-- ); + CHECK( begin == iter ); + + // the following should not compile: no random access iterator + // iter = begin + 1; + // CHECK( second == iter ); + // iter = second - 1; + // CHECK( begin == iter ); + // iter = 1 + begin; + // CHECK( second == iter ); + } // THEN + } // WHEN + } // GIVEN + + GIVEN( "a container with random access iterators" ) { + + std::vector< int > values = { 0, 1, 2, 3, 4 }; + + WHEN( "when the container and the transformation are used" ) { + + TransformView chunk( values, transform ); + + THEN( "the TransformView::Iterator functions as a normal random access " + "iterator" ) { + + auto begin = chunk.begin(); + auto second = begin + 1; + auto end = chunk.end(); + auto iter = begin; + + unsigned int counter = 0; + for ( auto iter = begin; iter != end; ++iter ) { + + ++counter; + } + CHECK( 5 == counter ); + + CHECK( 5 == std::distance( begin, end ) ); + CHECK( 5 == end - begin ); + CHECK( begin != end ); + + CHECK( -2 == *begin ); + CHECK( -1 == *second ); + + CHECK( -2 == begin[0] ); + CHECK( -1 == begin[1] ); + CHECK( 0 == begin[2] ); + CHECK( 1 == begin[3] ); + CHECK( 2 == begin[4] ); + + iter += 1; + CHECK( second == iter ); + iter -= 1; + CHECK( begin == iter ); + + CHECK( second == ++begin ); + CHECK( begin == --begin ); + + iter = begin; + CHECK( begin == iter++ ); + CHECK( second == iter ); + CHECK( second == iter-- ); + CHECK( begin == iter ); + + iter = begin + 1; + CHECK( second == iter ); + iter = second - 1; + CHECK( begin == iter ); + iter = 1 + begin; + CHECK( second == iter ); + } // THEN + } // WHEN + } // GIVEN +} // SCENARIO From b07d0c04ce4c0cab782f230030301bb650ebfdb0 Mon Sep 17 00:00:00 2001 From: Wim Haeck Date: Tue, 7 Nov 2023 09:56:20 -0700 Subject: [PATCH 18/18] Adding more comaprison tests --- src/tools/ranges/TransformView/Iterator.hpp | 16 ++++++++++++++++ .../Iterator/test/Iterator.test.cpp | 17 +++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/src/tools/ranges/TransformView/Iterator.hpp b/src/tools/ranges/TransformView/Iterator.hpp index 7474d28..908e31e 100644 --- a/src/tools/ranges/TransformView/Iterator.hpp +++ b/src/tools/ranges/TransformView/Iterator.hpp @@ -143,24 +143,40 @@ class Iterator { friend constexpr bool operator<( const Iterator& left, const Iterator& right) { + static_assert( + concepts::IsRandomAccessIterator< Iterator >::value == true, + "the at() method can only be made available for random access iterators" ); + return left.iter_ < right.iter_; } friend constexpr bool operator>( const Iterator& left, const Iterator& right ) { + static_assert( + concepts::IsRandomAccessIterator< Iterator >::value == true, + "the at() method can only be made available for random access iterators" ); + return right < left; } friend constexpr bool operator<=( const Iterator& left, const Iterator& right ) { + static_assert( + concepts::IsRandomAccessIterator< Iterator >::value == true, + "the at() method can only be made available for random access iterators" ); + return !( right < left ); } friend constexpr bool operator>=( const Iterator& left, const Iterator& right ) { + static_assert( + concepts::IsRandomAccessIterator< Iterator >::value == true, + "the at() method can only be made available for random access iterators" ); + return !( left < right ); } }; diff --git a/src/tools/ranges/TransformView/Iterator/test/Iterator.test.cpp b/src/tools/ranges/TransformView/Iterator/test/Iterator.test.cpp index 1d7ae0f..8bae389 100644 --- a/src/tools/ranges/TransformView/Iterator/test/Iterator.test.cpp +++ b/src/tools/ranges/TransformView/Iterator/test/Iterator.test.cpp @@ -76,6 +76,12 @@ SCENARIO( "TransformView" ) { // CHECK( begin == iter ); // iter = 1 + begin; // CHECK( second == iter ); + + // the following should not compile: no random access iterator + // CHECK( second >= begin ); + // CHECK( second > begin ); + // CHECK( begin <= second ); + // CHECK( begin < second ); } // THEN } // WHEN } // GIVEN @@ -137,6 +143,12 @@ SCENARIO( "TransformView" ) { // CHECK( begin == iter ); // iter = 1 + begin; // CHECK( second == iter ); + + // the following should not compile: no random access iterator + // CHECK( second >= begin ); + // CHECK( second > begin ); + // CHECK( begin <= second ); + // CHECK( begin < second ); } // THEN } // WHEN } // GIVEN @@ -197,6 +209,11 @@ SCENARIO( "TransformView" ) { CHECK( begin == iter ); iter = 1 + begin; CHECK( second == iter ); + + CHECK( second >= begin ); + CHECK( second > begin ); + CHECK( begin <= second ); + CHECK( begin < second ); } // THEN } // WHEN } // GIVEN