-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
498 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
#include "tools/std23/views/chunk.hpp" | ||
#include "tools/std23/views/chunk_by.hpp" | ||
#include "tools/std23/views/stride.hpp" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,363 @@ | ||
#ifndef NJOY_TOOLS_STD23_RANGES_VIEWS_STRIDE | ||
#define NJOY_TOOLS_STD23_RANGES_VIEWS_STRIDE | ||
|
||
#include "tools/std20/detail/views/range_adaptors.hpp" | ||
#include "tools/std20/views/interface.hpp" | ||
#include "tools/std20/views/all.hpp" | ||
|
||
namespace njoy { | ||
namespace tools { | ||
namespace std23 { | ||
inline namespace ranges { | ||
|
||
/** | ||
* @brief A range adaptor that takes a view and a number n and produces a view, | ||
* that consists of elements of the original view by advancing over n elements | ||
* at a time | ||
* | ||
* See https://en.cppreference.com/w/cpp/ranges/stride_view | ||
*/ | ||
template < typename R > | ||
struct stride_view : std20::ranges::view_interface< stride_view< R > > { | ||
|
||
static_assert( std20::ranges::view< R > ); | ||
static_assert( std20::ranges::input_range< R > ); | ||
|
||
private: | ||
|
||
R base_; | ||
std20::ranges::range_difference_t< R > stride_; | ||
|
||
template < bool Const > | ||
struct iterator { | ||
|
||
private: | ||
|
||
friend stride_view; | ||
|
||
using Parent = std20::ranges::detail::conditional_t< Const, const stride_view, stride_view >; | ||
using Base = std20::ranges::detail::conditional_t< Const, const R, R >; | ||
|
||
stride_view* parent_ = nullptr; | ||
std20::ranges::iterator_t< Base > current_ = std20::ranges::iterator_t< Base >(); | ||
std20::ranges::iterator_t< Base > end_ = std20::ranges::iterator_t< Base >(); | ||
std20::ranges::range_difference_t< Base > stride_ = 0; | ||
std20::ranges::range_difference_t< Base > missing_ = 0; | ||
|
||
constexpr iterator( Parent* parent, std20::ranges::iterator_t< Base > current, | ||
std20::ranges::range_difference_t< Base > missing = 0 ) : | ||
current_( std::move( current ) ), | ||
end_( std20::ranges::end( parent->base_ ) ), | ||
stride_( parent->stride_ ), | ||
missing_( missing ) {} | ||
|
||
public: | ||
|
||
using value_type = std20::ranges::range_value_t< Base >; | ||
using difference_type = std20::ranges::range_difference_t< Base >; | ||
using iterator_category = std::conditional_t< | ||
std20::ranges::random_access_range< Base >, | ||
std20::random_access_iterator_tag, | ||
std::conditional_t< | ||
std20::ranges::bidirectional_range< Base >, | ||
std20::bidirectional_iterator_tag, | ||
std::conditional_t< | ||
std20::ranges::forward_range< Base >, | ||
std20::forward_iterator_tag, | ||
std20::input_iterator_tag > > >; | ||
|
||
iterator() = default; | ||
|
||
template < typename Iterator, | ||
std::enable_if_t< std20::same_as< Iterator, iterator< ! Const > >, int > = 0, | ||
bool C = Const, typename RR = R, | ||
std::enable_if_t< C && std20::convertible_to< std20::ranges::iterator_t< RR >, | ||
std20::ranges::iterator_t< Base > >, int > = 0 > | ||
constexpr iterator( Iterator iter ) : | ||
current_( std::move( iter.current_ ) ), | ||
end_( std::move( iter.end_ ) ), | ||
stride_( iter.stride_ ), | ||
missing_( iter.missing_ ) {} | ||
|
||
constexpr std20::ranges::iterator_t< Base > base() const { return this->current_; } | ||
|
||
constexpr decltype(auto) operator*() const { return *this->current_; } | ||
|
||
constexpr iterator& operator++() { | ||
|
||
this->missing_ = std20::ranges::advance( this->current_, this->stride_, this->end_ ); | ||
return *this; | ||
} | ||
|
||
constexpr iterator operator++(int) { | ||
|
||
auto temp = *this; | ||
++*this; | ||
return temp; | ||
} | ||
|
||
template < typename B = Base > | ||
constexpr auto operator--() | ||
-> std::enable_if_t< std20::ranges::bidirectional_range< B >, iterator& > { | ||
|
||
std20::ranges::advance( this->current_, this->missing_ - this->stride_ ); | ||
this->missing_ = 0; | ||
return *this; | ||
} | ||
|
||
template < typename B = Base > | ||
constexpr auto operator--(int) | ||
-> std::enable_if_t< std20::ranges::bidirectional_range< B >, iterator > { | ||
|
||
auto temp = *this; | ||
--*this; | ||
return temp; | ||
} | ||
|
||
template < typename B = Base > | ||
constexpr auto operator+=( difference_type n ) | ||
-> std::enable_if_t< std20::ranges::random_access_range< B >, iterator& > { | ||
|
||
if ( n > 0 ) { | ||
|
||
std20::ranges::advance( this->current_, this->stride_ * ( n - 1 ) ); | ||
this->missing_ = std20::ranges::advance( this->current_, this->stride_, this->end_ ); | ||
} | ||
else if ( n < 0 ) { | ||
|
||
std20::ranges::advance( this->current_, this->stride_ * n + this->missing_ ); | ||
this->missing_ = 0; | ||
} | ||
return *this; | ||
} | ||
|
||
template < typename B = Base > | ||
constexpr auto operator-=( difference_type n ) | ||
-> std::enable_if_t< std20::ranges::random_access_range< B >, iterator& > { | ||
|
||
return *this += -n; | ||
} | ||
|
||
// this version of operator[] does not work on gcc | ||
// template < typename B = Base > | ||
// constexpr auto operator[]( difference_type n ) const | ||
// -> std::enable_if_t< std20::ranges::random_access_range< B >, value_type > { | ||
// | ||
// return *( *this + n ); | ||
// } | ||
|
||
template < typename B = Base, | ||
typename = std::enable_if_t< std20::ranges::random_access_range< B > > > | ||
constexpr decltype(auto) operator[]( difference_type n ) const { | ||
|
||
return *( *this + n ); | ||
} | ||
|
||
template < typename B = Base > | ||
friend constexpr auto operator==( const iterator& left, const iterator& right ) | ||
-> std::enable_if_t< std20::equality_comparable< std20::ranges::iterator_t< B > >, bool > { | ||
|
||
return left.current_ == right.current_; | ||
} | ||
|
||
template < typename B = Base > | ||
friend constexpr auto operator!=( const iterator& left, const iterator& right ) | ||
-> std::enable_if_t< std20::equality_comparable< std20::ranges::iterator_t< B > >, bool > { | ||
|
||
return ! ( left == right ); | ||
} | ||
|
||
template < typename B = Base > | ||
friend constexpr auto operator<( const iterator& left, const iterator& right ) | ||
-> std::enable_if_t< std20::ranges::random_access_range< B >, bool > { | ||
|
||
return left.current_ < right.current_; | ||
} | ||
|
||
template < typename B = Base> | ||
friend constexpr auto operator>( const iterator& left, const iterator& right ) | ||
-> std::enable_if_t< std20::ranges::random_access_range< B >, bool > { | ||
|
||
return right < left; | ||
} | ||
|
||
template < typename B = Base > | ||
friend constexpr auto operator<=( const iterator& left, const iterator& right ) | ||
-> std::enable_if_t< std20::ranges::random_access_range< B >, bool > { | ||
|
||
return ! ( right < left ); | ||
} | ||
|
||
template < typename B = Base > | ||
friend constexpr auto operator>=( const iterator& left, const iterator& right ) | ||
-> std::enable_if_t< std20::ranges::random_access_range< B >, bool > { | ||
|
||
return ! ( left < right ); | ||
} | ||
|
||
template < typename B = Base > | ||
friend constexpr auto operator+( const iterator& left, const difference_type n ) | ||
-> std::enable_if_t< std20::ranges::random_access_range< B >, iterator > { | ||
|
||
return iterator{ left } += n; | ||
} | ||
|
||
template < typename B = Base > | ||
friend constexpr auto operator+( const difference_type n, const iterator& right ) | ||
-> std::enable_if_t< std20::ranges::random_access_range< B >, iterator > { | ||
|
||
return right + n; | ||
} | ||
|
||
template < typename B = Base > | ||
friend constexpr auto operator-( const iterator& left, const difference_type n ) | ||
-> std::enable_if_t< std20::ranges::random_access_range< B >, iterator > { | ||
|
||
return iterator{ left } -= n; | ||
} | ||
|
||
template < typename B = Base > | ||
friend constexpr auto operator-( const iterator& left, const iterator& right ) | ||
-> std::enable_if_t< | ||
std20::ranges::sized_sentinel_for< std20::ranges::iterator_t< B >, | ||
std20::ranges::iterator_t< B > >, | ||
difference_type > { | ||
|
||
return ( left.current_ - right.current_ + left.missing_ - right.missing_ ) / left.stride_; | ||
} | ||
|
||
template < typename B = Base > | ||
friend constexpr auto operator-( const std20::ranges::default_sentinel_t, const iterator& right ) | ||
-> std::enable_if_t< | ||
std20::ranges::sized_sentinel_for< std20::ranges::sentinel_t< B >, | ||
std20::ranges::iterator_t< B > >, | ||
difference_type > { | ||
|
||
return div_ceil( right.end_ - right.current_, right.stride_ ); | ||
} | ||
|
||
template < typename B = Base > | ||
friend constexpr auto operator-( const iterator& left, const std20::ranges::default_sentinel_t right ) | ||
-> std::enable_if_t< | ||
std20::ranges::sized_sentinel_for< std20::ranges::sentinel_t< B >, | ||
std20::ranges::iterator_t< B > >, | ||
difference_type > { | ||
|
||
return -( right - left ); | ||
} | ||
}; | ||
|
||
public: | ||
|
||
stride_view() = default; | ||
|
||
constexpr stride_view( R base, std20::ranges::range_difference_t< R > stride ) : | ||
base_( std::move( base ) ), stride_( stride ) { | ||
|
||
assert( this->stride_ > 0 ); | ||
} | ||
|
||
constexpr R base() const { return base_; } | ||
|
||
constexpr iterator< false > begin() { | ||
|
||
return { this, std20::ranges::begin( this->base_ ) }; | ||
} | ||
|
||
constexpr iterator< true > begin() const { | ||
|
||
return { this, std20::ranges::begin( this->base_ ) }; | ||
} | ||
|
||
constexpr iterator< false > end() { | ||
|
||
if constexpr ( std20::ranges::common_range< R > && std20::ranges::sized_range< R >) { | ||
|
||
auto missing = ( this->stride_ - std20::ranges::distance( this->base_ ) % this->stride_ ) % this->stride_; | ||
return iterator< false >( this, std20::ranges::end( this->base_ ), missing ); | ||
} | ||
else if constexpr ( std20::ranges::common_range< R > && ! std20::ranges::bidirectional_range< R >) { | ||
|
||
return iterator< false >( this, std20::ranges::end( this->base_ ) ); | ||
} | ||
else { | ||
|
||
return std20::ranges::default_sentinel; | ||
} | ||
} | ||
|
||
constexpr iterator< true > end() const { | ||
|
||
if constexpr ( std20::ranges::common_range< R > && std20::ranges::sized_range< R >) { | ||
|
||
auto missing = ( this->stride_ - std20::ranges::distance( this->base_ ) % this->stride_ ) % this->stride_; | ||
return iterator< true >( this, std20::ranges::end( this->base_ ), missing ); | ||
} | ||
else if constexpr ( std20::ranges::common_range< R > && ! std20::ranges::bidirectional_range< R >) { | ||
|
||
return iterator< true >( this, std20::ranges::end( this->base_ ), 0 ); | ||
} | ||
else { | ||
|
||
return std20::ranges::default_sentinel; | ||
} | ||
} | ||
|
||
template < typename B = R > | ||
constexpr auto size() | ||
-> std::enable_if_t< std20::ranges::sized_range< B >, std::size_t > { | ||
|
||
return div_ceil( std20::ranges::distance( this->base_ ), this->stride_ ); | ||
} | ||
|
||
template < typename B = R > | ||
constexpr auto size() const | ||
-> std::enable_if_t< std20::ranges::sized_range< B >, std::size_t > { | ||
|
||
return div_ceil( std20::ranges::distance( this->base_ ), this->stride_ ); | ||
} | ||
|
||
}; | ||
|
||
template < typename R > | ||
stride_view( R&&, std20::ranges::range_difference_t< R > ) -> stride_view< std20::ranges::all_view< R > >; | ||
|
||
namespace detail { | ||
|
||
struct stride_view_fn { | ||
|
||
template < typename E, typename F > | ||
constexpr auto operator()( E&& e, F&& f ) const | ||
-> decltype( stride_view{ std::forward< E >( e ), std::forward< F >( f ) } ) | ||
{ | ||
return stride_view{ std::forward< E >( e ), std::forward< F >( f ) }; | ||
} | ||
|
||
template < typename C > | ||
constexpr auto operator()( C&& c ) const | ||
{ | ||
return std20::ranges::detail::rao_proxy{ [p = std::forward< C >( c ) ] ( auto&& r ) mutable | ||
#ifndef NANO_MSVC_LAMBDA_PIPE_WORKAROUND | ||
-> decltype( stride_view{ std::forward< decltype(r) >( r ), std::declval< C&& >() } ) | ||
#endif | ||
{ | ||
return stride_view{ std::forward< decltype(r) >( r ), std::move( p ) }; | ||
}}; | ||
} | ||
|
||
}; | ||
|
||
} | ||
|
||
namespace views { | ||
|
||
NANO_INLINE_VAR(ranges::detail::stride_view_fn, stride) | ||
|
||
} | ||
|
||
} // namespace ranges | ||
} // namespace std23 | ||
} // namespace tools | ||
} // namespace njoy | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
add_cpp_test( std23.views.chunk chunk.test.cpp ) | ||
add_cpp_test( std23.views.chunk_by chunk_by.test.cpp ) | ||
add_cpp_test( std23.views.stride stride.test.cpp ) |
Oops, something went wrong.