Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/ranges part1 #7

Merged
merged 12 commits into from
Nov 8, 2023
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