Skip to content

Commit

Permalink
Merge pull request #7 from njoy/feature/ranges-part1
Browse files Browse the repository at this point in the history
Feature/ranges part1
  • Loading branch information
whaeck authored Nov 8, 2023
2 parents 8794ddd + d6e0893 commit 28db74e
Show file tree
Hide file tree
Showing 16 changed files with 719 additions and 87 deletions.
4 changes: 4 additions & 0 deletions cmake/unit_testing.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ endfunction()

add_subdirectory( src/tools/Log/test )

add_subdirectory( src/tools/concepts/Requires/test )
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/make_view/test )
Expand Down
4 changes: 4 additions & 0 deletions src/tools/concepts.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#include "tools/concepts/Require.hpp"

#include "tools/concepts/IsIterator.hpp"
#include "tools/concepts/IsRange.hpp"
68 changes: 68 additions & 0 deletions src/tools/concepts/IsIterator.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#ifndef NJOY_TOOLS_CONCEPTS_ISITERATOR
#define NJOY_TOOLS_CONCEPTS_ISITERATOR

// system includes
#include <type_traits>

// other includes

namespace njoy {
namespace tools {
namespace concepts {

template< typename Iterator >
using iterator_category =
typename std::iterator_traits< Iterator >::iterator_category;

// sfinae structures for iterator objects

template< typename Iterator, typename = void >
struct IsIterator : std::false_type {};

template< typename Iterator >
struct IsIterator<
Iterator,
std::void_t< iterator_category< Iterator > > > : std::true_type {};

// the following template aliases only work on iterators

// sfinae structures for input iterator objects

template< typename Iterator >
using IsInputIterator =
typename std::is_base_of< std::input_iterator_tag,
iterator_category< Iterator > >;

// sfinae structures for output iterator objects

template< typename Iterator >
using IsOutputIterator =
typename std::is_base_of< std::output_iterator_tag,
iterator_category< Iterator > >;

// sfinae structures for forward iterator objects

template< typename Iterator >
using IsForwardIterator =
typename std::is_base_of< std::forward_iterator_tag,
iterator_category< Iterator > >;

// sfinae structures for bidirectional iterator objects

template< typename Iterator >
using IsBidirectionalIterator =
typename std::is_base_of< std::bidirectional_iterator_tag,
iterator_category< Iterator > >;

// sfinae structures for random access iterator objects

template< typename Iterator >
using IsRandomAccessIterator =
typename std::is_base_of< std::random_access_iterator_tag,
iterator_category< Iterator > >;

} // ranges namespace
} // tools namespace
} // njoy namespace

#endif
1 change: 1 addition & 0 deletions src/tools/concepts/IsIterator/test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
add_cpp_test( concepts.IsIterator IsIterator.test.cpp )
177 changes: 177 additions & 0 deletions src/tools/concepts/IsIterator/test/IsIterator.test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
// include Catch2
#include <catch2/catch_test_macros.hpp>

// what we are testing
#include "tools/concepts/IsIterator.hpp"

// other includes
#include <iterator>
#include <forward_list>
#include <list>
#include <map>
#include <unordered_map>
#include <set>
#include <unordered_set>
#include <vector>

// convenience typedefs
using namespace njoy::tools::concepts;

SCENARIO( "IsIterator sfinae objects" ) {

GIVEN( "different types" ) {

WHEN( "when applying IsIterator" ) {

THEN( "true is returned for iterators and false for everything else" ) {

// non iterator type
CHECK( false == IsIterator< int >::value );

// input iterator types
CHECK( true == IsIterator< std::istream_iterator< int > >::value );

// output iterator types
CHECK( true == IsIterator< std::ostream_iterator< int > >::value );

// forward iterator types
CHECK( true == IsIterator< std::forward_list< int >::iterator >::value );
CHECK( true == IsIterator< std::unordered_set< int >::iterator >::value );
CHECK( true == IsIterator< std::unordered_map< int, int >::iterator >::value );

// bidirectional iterator types
CHECK( true == IsIterator< std::list< int >::iterator >::value );
CHECK( true == IsIterator< std::set< int >::iterator >::value );
CHECK( true == IsIterator< std::map< int, int >::iterator >::value );

// random access iterator types
CHECK( true == IsIterator< std::vector< int >::iterator >::value );
} // THEN
} // WHEN

WHEN( "when applying IsInputIterator" ) {

THEN( "true is returned for iterators that conform to input iterators" ) {

// input iterator type
CHECK( true == IsInputIterator< std::istream_iterator< int > >::value );

// output iterator types
CHECK( false == IsInputIterator< std::ostream_iterator< int > >::value );

// forward iterator types
CHECK( true == IsInputIterator< std::forward_list< int >::iterator >::value );
CHECK( true == IsInputIterator< std::unordered_set< int >::iterator >::value );
CHECK( true == IsInputIterator< std::unordered_map< int, int >::iterator >::value );

// bidirectional iterator types
CHECK( true == IsInputIterator< std::list< int >::iterator >::value );
CHECK( true == IsInputIterator< std::set< int >::iterator >::value );
CHECK( true == IsInputIterator< std::map< int, int >::iterator >::value );

// random access iterator types
CHECK( true == IsInputIterator< std::vector< int >::iterator >::value );
} // THEN
} // WHEN

WHEN( "when applying IsOutputIterator" ) {

THEN( "true is returned for iterators that conform to output iterators" ) {

// input iterator types
CHECK( false == IsOutputIterator< std::istream_iterator< int > >::value );

// output iterator types
CHECK( true == IsOutputIterator< std::ostream_iterator< int > >::value );

// forward iterator types
CHECK( false == IsOutputIterator< std::forward_list< int >::iterator >::value );
CHECK( false == IsOutputIterator< std::unordered_set< int >::iterator >::value );
CHECK( false == IsOutputIterator< std::unordered_map< int, int >::iterator >::value );

// bidirectional iterator types
CHECK( false == IsOutputIterator< std::list< int >::iterator >::value );
CHECK( false == IsOutputIterator< std::set< int >::iterator >::value );
CHECK( false == IsOutputIterator< std::map< int, int >::iterator >::value );

// random access iterator types
CHECK( false == IsOutputIterator< std::vector< int >::iterator >::value );
} // THEN
} // WHEN

WHEN( "when applying IsForwardIterator" ) {

THEN( "true is returned for iterators that conform to forward iterators" ) {

// input iterator types
CHECK( false == IsForwardIterator< std::istream_iterator< int > >::value );

// output iterator types
CHECK( false == IsForwardIterator< std::ostream_iterator< int > >::value );

// forward iterator types
CHECK( true == IsForwardIterator< std::forward_list< int >::iterator >::value );
CHECK( true == IsForwardIterator< std::unordered_set< int >::iterator >::value );
CHECK( true == IsForwardIterator< std::unordered_map< int, int >::iterator >::value );

// bidirectional iterator types
CHECK( true == IsForwardIterator< std::list< int >::iterator >::value );
CHECK( true == IsForwardIterator< std::set< int >::iterator >::value );
CHECK( true == IsForwardIterator< std::map< int, int >::iterator >::value );

// random access iterator types
CHECK( true == IsForwardIterator< std::vector< int >::iterator >::value );
} // THEN
} // WHEN

WHEN( "when applying IsBidirectionalIterator" ) {

THEN( "true is returned for iterators that conform to bidirectional iterators" ) {

// input iterator types
CHECK( false == IsBidirectionalIterator< std::istream_iterator< int > >::value );

// output iterator types
CHECK( false == IsBidirectionalIterator< std::ostream_iterator< int > >::value );

// forward iterator types
CHECK( false == IsBidirectionalIterator< std::forward_list< int >::iterator >::value );
CHECK( false == IsBidirectionalIterator< std::unordered_set< int >::iterator >::value );
CHECK( false == IsBidirectionalIterator< std::unordered_map< int, int >::iterator >::value );

// bidirectional iterator types
CHECK( true == IsBidirectionalIterator< std::list< int >::iterator >::value );
CHECK( true == IsBidirectionalIterator< std::set< int >::iterator >::value );
CHECK( true == IsBidirectionalIterator< std::map< int, int >::iterator >::value );

// random access iterator types
CHECK( true == IsBidirectionalIterator< std::vector< int >::iterator >::value );
} // THEN
} // WHEN

WHEN( "when applying IsRandomAccessIterator" ) {

THEN( "true is returned for iterators that conform to random access iterators" ) {

// input iterator types
CHECK( false == IsRandomAccessIterator< std::istream_iterator< int > >::value );

// output iterator types
CHECK( false == IsRandomAccessIterator< std::ostream_iterator< int > >::value );

// forward iterator types
CHECK( false == IsRandomAccessIterator< std::forward_list< int >::iterator >::value );
CHECK( false == IsRandomAccessIterator< std::unordered_set< int >::iterator >::value );
CHECK( false == IsRandomAccessIterator< std::unordered_map< int, int >::iterator >::value );

// bidirectional iterator types
CHECK( false == IsRandomAccessIterator< std::list< int >::iterator >::value );
CHECK( false == IsRandomAccessIterator< std::set< int >::iterator >::value );
CHECK( false == IsRandomAccessIterator< std::map< int, int >::iterator >::value );

// random access iterator types
CHECK( true == IsRandomAccessIterator< std::vector< int >::iterator >::value );
} // THEN
} // WHEN
} // GIVEN
} // SCENARIO
26 changes: 26 additions & 0 deletions src/tools/concepts/IsRange.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#ifndef NJOY_TOOLS_CONCEPTS_ISRANGE
#define NJOY_TOOLS_CONCEPTS_ISRANGE

// system includes
#include <type_traits>

// other includes

namespace njoy {
namespace tools {
namespace concepts {

template< typename Range, typename = void >
struct IsRange : std::false_type {};

template< typename Range >
struct IsRange< Range,
std::void_t< decltype( std::begin( std::declval< Range >() ) ),
decltype( std::end( std::declval< Range >() ) )
> > : std::true_type {};

} // ranges namespace
} // tools namespace
} // njoy namespace

#endif
1 change: 1 addition & 0 deletions src/tools/concepts/IsRange/test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
add_cpp_test( concepts.IsRange IsRange.test.cpp )
30 changes: 30 additions & 0 deletions src/tools/concepts/IsRange/test/IsRange.test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// include Catch2
#include <catch2/catch_test_macros.hpp>

// what we are testing
#include "tools/concepts/IsRange.hpp"

// other includes
#include <vector>
#include <map>

// convenience typedefs
using namespace njoy::tools::concepts;

SCENARIO( "IsRange" ) {

GIVEN( "different types" ) {

WHEN( "when applying IsRange" ) {

THEN( "true is returned for ranges and false for everything else" ) {

CHECK( false == IsRange< int >::value );

CHECK( true == IsRange< std::vector< int > >::value );
CHECK( true == IsRange< const std::vector< int > >::value );
CHECK( true == IsRange< std::map< int, int > >::value );
} // THEN
} // WHEN
} // GIVEN
} // SCENARIO
20 changes: 20 additions & 0 deletions src/tools/concepts/Requires.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#ifndef NJOY_TOOLS_CONCEPTS_REQUIRES
#define NJOY_TOOLS_CONCEPTS_REQUIRES

// system includes
#include <type_traits>

// other includes

namespace njoy {
namespace tools {
namespace concepts {

template< bool TrueFalse, template< typename...> class Concept, typename... T >
using Requires = typename std::enable_if< Concept< T... >::value == TrueFalse, bool >::type;

} // ranges namespace
} // tools namespace
} // njoy namespace

#endif
1 change: 1 addition & 0 deletions src/tools/concepts/Requires/test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
add_cpp_test( concepts.Requires Requires.test.cpp )
32 changes: 32 additions & 0 deletions src/tools/concepts/Requires/test/Requires.test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// include Catch2
#include <catch2/catch_test_macros.hpp>

// what we are testing
#include "tools/concepts/Requires.hpp"

// other includes

// convenience typedefs
using namespace njoy::tools::concepts;

template< typename T, Requires< true, std::is_integral, T > = true >
bool integer_type( const T& ){ return true; }

template< typename T, Requires< false, std::is_integral, T > = true >
bool integer_type( const T& ){ return false; }

SCENARIO( "Require" ) {

GIVEN( "different types" ) {

WHEN( "when applying Require" ) {

THEN( "true is returned for integers and false for everything else" ) {

CHECK( true == integer_type( 1 ) );
CHECK( false == integer_type( 1.0 ) );
CHECK( false == integer_type( std::vector< int >{} ) );
} // THEN
} // WHEN
} // GIVEN
} // SCENARIO
Loading

0 comments on commit 28db74e

Please sign in to comment.