5 #ifndef NDS_LITE_UTILS_HH
6 #define NDS_LITE_UTILS_HH
17 template <
typename T >
18 class IdentityTransform
22 operator( )(
const T& input ) -> T
30 INCLUDE_EMPTY_STRING = 0,
31 EXCLUDE_EMPTY_STRING = 1,
34 static std::vector< std::string >
35 split(
const std::string& source,
36 const std::string& sep,
37 split_type filter_mode = INCLUDE_EMPTY_STRING )
39 std::vector< std::string > results;
43 std::string::size_type prev = 0;
44 std::string::size_type pos = 0;
45 if ( sep.size( ) > 0 )
47 std::string::size_type sep_size = sep.size( );
48 while ( pos < source.size( ) && pos != std::string::npos )
50 pos = source.find( sep, prev );
51 if ( pos != std::string::npos )
53 auto tmp = source.substr( prev, pos - prev );
54 if ( tmp !=
"" || filter_mode == INCLUDE_EMPTY_STRING )
55 results.push_back( tmp );
63 while ( pos < source.size( ) && pos != std::string::npos )
65 pos = source.find_first_of(
" \t\n\r", prev );
66 if ( pos != std::string::npos )
68 auto tmp = source.substr( prev, pos - prev );
69 if ( tmp !=
"" || filter_mode == INCLUDE_EMPTY_STRING )
70 results.push_back( tmp );
76 auto tmp = source.substr( prev );
77 if ( tmp !=
"" || filter_mode == INCLUDE_EMPTY_STRING )
78 results.push_back( tmp );
82 template <
typename T >
87 operator( )(
const T& input )
93 template <
typename T >
97 typedef std::size_t size_type;
99 FirstNPredicate( size_type max )
100 : max_{ max }, local_cur_{ 0 }, ext_cur_{ &local_cur_ }
103 FirstNPredicate( size_type max, size_type* ext_tracker )
104 : max_{ max }, local_cur_{ 0 }, ext_cur_{ ext_tracker }
108 operator( )(
const T& input )
110 if ( *ext_cur_ < max_ )
126 size_type local_cur_;
134 template <
typename T >
138 typedef T value_type;
139 typedef std::size_t size_type;
141 typedef std::ptrdiff_t difference_type;
142 typedef T& reference;
145 Span(
const Span< T >& other )
146 : data_{ other.data_ }, size_{ other.size_ }
149 Span( T* data, size_type count )
150 : data_{ data }, size_{ ( data ? count : 0 ) }
181 return data_ + size_;
184 at(
size_t index )
const
186 if ( index >= size_ )
187 throw std::out_of_range(
188 "accessing outside of the array range" );
189 return data_[ index ];
191 reference operator[](
size_t index )
193 return data_[ index ];
203 return data_[ size_ - 1 ];
206 swap( Span< T >& other )
208 std::swap( other.data_, data_ );
209 std::swap( other.size_, size_ );
214 std::fill( begin( ), end( ), value );
222 template <
typename It,
typename BinaryPred >
224 adjacent_find( It begin, It end, BinaryPred p )
233 for ( ; cur != end; ++cur, prev = cur )
235 if ( p( *prev, *cur ) )
249 #ifdef _NDS_IMPL_ENABLE_CATCH_TESTS_
255 namespace nds_impl_cmn_utils
264 TEST_CASE(
"An identity transform transforms an object to itself",
265 "[nds2][utils][transforms]" )
268 nds_impl::common::IdentityTransform< std::string > t_str;
269 auto input = std::string(
"hello" );
270 auto output = t_str( input );
271 REQUIRE( input == output );
275 TEST_CASE(
"Test split",
"[utils][split]" )
278 auto result = nds_impl::common::split(
"",
"" );
279 REQUIRE( result.size( ) == 0 );
282 auto result = nds_impl::common::split(
283 "",
"", nds_impl::common::split_type::EXCLUDE_EMPTY_STRING );
284 REQUIRE( result.size( ) == 0 );
287 auto result = nds_impl::common::split(
"",
"a" );
288 REQUIRE( result.size( ) == 0 );
291 auto result = nds_impl::common::split(
292 "",
"a", nds_impl::common::split_type::EXCLUDE_EMPTY_STRING );
293 REQUIRE( result.size( ) == 0 );
296 auto result = nds_impl::common::split(
"abc",
"b" );
297 REQUIRE( result.size( ) == 2 );
298 REQUIRE( result[ 0 ] ==
"a" );
299 REQUIRE( result[ 1 ] ==
"c" );
302 auto result = nds_impl::common::split(
303 "abc",
"b", nds_impl::common::split_type::EXCLUDE_EMPTY_STRING );
304 REQUIRE( result.size( ) == 2 );
305 REQUIRE( result[ 0 ] ==
"a" );
306 REQUIRE( result[ 1 ] ==
"c" );
309 auto result = nds_impl::common::split(
"abc",
"d" );
310 REQUIRE( result.size( ) == 1 );
311 REQUIRE( result[ 0 ] ==
"abc" );
314 auto result = nds_impl::common::split(
315 "abc",
"d", nds_impl::common::split_type::EXCLUDE_EMPTY_STRING );
316 REQUIRE( result.size( ) == 1 );
317 REQUIRE( result[ 0 ] ==
"abc" );
320 auto result = nds_impl::common::split(
"babcabbdb",
"b" );
321 REQUIRE( result.size( ) == 6 );
322 std::vector< std::string > expected{
"",
"a",
"ca",
"",
"d",
"" };
323 REQUIRE( result == expected );
326 auto result = nds_impl::common::split(
"catbatdog",
"at" );
327 REQUIRE( result.size( ) == 3 );
328 REQUIRE( result[ 0 ] ==
"c" );
329 REQUIRE( result[ 1 ] ==
"b" );
330 REQUIRE( result[ 2 ] ==
"dog" );
333 auto result = nds_impl::common::split(
336 nds_impl::common::split_type::EXCLUDE_EMPTY_STRING );
337 REQUIRE( result.size( ) == 3 );
338 REQUIRE( result[ 0 ] ==
"c" );
339 REQUIRE( result[ 1 ] ==
"b" );
340 REQUIRE( result[ 2 ] ==
"dog" );
343 auto result = nds_impl::common::split(
"abc",
"" );
344 REQUIRE( result.size( ) == 1 );
345 REQUIRE( result[ 0 ] ==
"abc" );
348 auto result = nds_impl::common::split(
349 "abc",
"", nds_impl::common::split_type::EXCLUDE_EMPTY_STRING );
350 REQUIRE( result.size( ) == 1 );
351 REQUIRE( result[ 0 ] ==
"abc" );
354 auto result = nds_impl::common::split(
"a b\r \tc\nd",
"" );
355 REQUIRE( result.size( ) == 6 );
356 std::vector< std::string > expected{
"a",
"b",
"",
"",
"c",
"d" };
357 REQUIRE( result == expected );
360 auto result = nds_impl::common::split(
363 nds_impl::common::split_type::EXCLUDE_EMPTY_STRING );
364 REQUIRE( result.size( ) == 4 );
365 std::vector< std::string > expected{
"a",
"b",
"c",
"d" };
366 REQUIRE( result == expected );
369 auto result = nds_impl::common::split(
372 nds_impl::common::split_type::EXCLUDE_EMPTY_STRING );
373 REQUIRE( result.size( ) == 4 );
374 std::vector< std::string > expected{
"a",
"b",
"c",
"d" };
375 REQUIRE( result == expected );
379 TEST_CASE(
"TruePredicate",
"[utils][predicates]" )
381 nds_impl::common::TruePredicate< int > p;
382 REQUIRE( p( 10000000 ) );
386 REQUIRE( p( -1000000 ) );
389 TEST_CASE(
"FirstNPredicate",
"[utils][predicates]" )
392 nds_impl::common::FirstNPredicate< int > p( 5 );
393 for (
auto i = 0; i < 5; ++i )
395 REQUIRE( p.accepted( ) == i );
398 REQUIRE( p.accepted( ) == 5 );
400 REQUIRE( p.accepted( ) == 5 );
402 REQUIRE( p.accepted( ) == 5 );
406 auto test_cb = []( nds_impl::common::FirstNPredicate< int > p,
408 REQUIRE( p.accepted( ) == val );
411 nds_impl::common::FirstNPredicate< int > p( 5 );
412 for (
auto i = 0; i < 5; ++i )
416 REQUIRE( p.accepted( ) == 5 );
418 REQUIRE( p.accepted( ) == 5 );
420 REQUIRE( p.accepted( ) == 5 );
424 TEST_CASE(
"Array_view",
"[utils][array_view]" )
426 using namespace nds_impl_cmn_utils;
428 const int ARRAY_SIZE = 20;
429 simple_struct base[ ARRAY_SIZE ];
430 for (
auto i = 0; i < ARRAY_SIZE; ++i )
432 base[ i ].field1 =
static_cast< int >( i );
434 base[ i ].field2,
"a string",
sizeof( base[ i ].field2 ) );
437 nds_impl::common::Span< simple_struct > array( base, ARRAY_SIZE );
438 REQUIRE( array.empty( ) == false );
439 REQUIRE( array.size( ) == ARRAY_SIZE );
440 REQUIRE( array.max_size( ) == array.size( ) );
441 REQUIRE( array.data( ) == base );
442 REQUIRE( array.begin( ) == base );
443 REQUIRE( array.end( ) == base + ARRAY_SIZE );
444 REQUIRE( &array.at( 0 ) == base );
445 REQUIRE( &array[ 0 ] == base );
446 REQUIRE_THROWS_AS( array.at( ARRAY_SIZE + 1 ), std::out_of_range );
447 REQUIRE_THROWS_AS( array.at( -1 ), std::out_of_range );
448 REQUIRE( &array.front( ) == base );
449 REQUIRE( &array.back( ) == base + ( ARRAY_SIZE - 1 ) );
450 for (
auto i = 0; i < ARRAY_SIZE; ++i )
452 REQUIRE( array.at( i ).field1 ==
static_cast< int >( i ) );
453 REQUIRE( std::strncmp( array.at( i ).field2,
455 sizeof( base[ i ].field2 ) ) == 0 );
457 REQUIRE( array[ i ].field1 == static_cast< int >( i ) );
458 REQUIRE( std::strncmp( array[ i ].field2,
460 sizeof( base[ i ].field2 ) ) == 0 );
463 typedef nds_impl::common::Span< simple_struct > sstruct_array;
465 std::is_same< sstruct_array::value_type, simple_struct >::value,
"" );
466 static_assert( std::is_same< sstruct_array::size_type, std::size_t >::value,
469 std::is_same< sstruct_array::pointer, simple_struct* >::value,
"" );
471 std::is_same< sstruct_array::difference_type, std::ptrdiff_t >::value,
474 std::is_same< sstruct_array::reference, simple_struct& >::value,
"" );
476 std::is_same< sstruct_array::iterator, simple_struct* >::value,
"" );
480 TEST_CASE(
"Empty Span",
"[utils][array_view]" )
482 using namespace nds_impl_cmn_utils;
484 const int ARRAY_SIZE = 5;
485 simple_struct base[ 5 ];
487 nds_impl::common::Span< simple_struct > array1(
nullptr, 0 );
488 REQUIRE( array1.empty( ) );
489 REQUIRE( array1.size( ) == 0 );
490 REQUIRE( array1.data( ) == nullptr );
491 REQUIRE( array1.begin( ) == array1.end( ) );
492 REQUIRE( array1.begin( ) == nullptr );
494 nds_impl::common::Span< simple_struct > array2(
nullptr, 5 );
495 REQUIRE( array2.empty( ) );
496 REQUIRE( array2.size( ) == 0 );
497 REQUIRE( array2.data( ) == nullptr );
498 REQUIRE( array2.begin( ) == array2.end( ) );
499 REQUIRE( array2.begin( ) == nullptr );
501 nds_impl::common::Span< simple_struct > array3( base, 0 );
502 REQUIRE( array3.empty( ) );
503 REQUIRE( array3.size( ) == 0 );
504 REQUIRE( array3.data( ) == base );
505 REQUIRE( array3.begin( ) == array3.end( ) );
506 REQUIRE( array3.begin( ) == base );
509 TEST_CASE(
"Copy and assign ArrayViews",
"[utils][array_view]" )
511 using namespace nds_impl_cmn_utils;
513 const int ARRAY_SIZE = 5;
514 simple_struct base[ 5 ];
516 nds_impl::common::Span< simple_struct > array1( base, ARRAY_SIZE );
517 nds_impl::common::Span< simple_struct > array2( base + 1, ARRAY_SIZE - 2 );
518 nds_impl::common::Span< simple_struct > array3( array1 );
519 REQUIRE( array1.size( ) == array3.size( ) );
520 REQUIRE( array1.data( ) == array3.data( ) );
523 REQUIRE( array3.size( ) == array2.size( ) );
524 REQUIRE( array3.data( ) == array2.data( ) );
526 array3.swap( array1 );
527 REQUIRE( array3.data( ) == base );
528 REQUIRE( array3.size( ) == ARRAY_SIZE );
529 REQUIRE( array1.data( ) == base + 1 );
530 REQUIRE( array1.size( ) == ARRAY_SIZE - 2 );
533 TEST_CASE(
"array_view fill",
"[utils][array_view]" )
535 using namespace nds_impl_cmn_utils;
537 const int ARRAY_SIZE = 5;
538 simple_struct base[ 5 ];
540 nds_impl::common::Span< simple_struct > array( base, ARRAY_SIZE );
543 std::strncpy( ref.field2,
"answer",
sizeof( ref.field2 ) );
545 for (
auto entry : array )
547 REQUIRE( entry.field1 == 42 );
548 REQUIRE( std::strncmp(
549 entry.field2,
"answer",
sizeof( entry.field2 ) ) == 0 );
552 std::strncpy( ref.field2,
"nonanswer",
sizeof( ref.field2 ) );
554 for (
auto entry : array )
556 REQUIRE( entry.field1 == 32 );
557 REQUIRE( std::strncmp(
558 entry.field2,
"nonanswer",
sizeof( entry.field2 ) ) == 0 );
562 TEST_CASE(
"adjacent_find finds two entries next to each other that are equal",
563 "[utils][algorithms]" )
565 using namespace nds_impl_cmn_utils;
567 auto eq = [](
int a,
int b ) ->
bool {
return a == b; };
570 std::vector< int > s;
571 REQUIRE( adjacent_find( s.begin( ), s.end( ), eq ) == s.end( ) );
575 std::vector< int > s;
577 REQUIRE( adjacent_find( s.begin( ), s.end( ), eq ) == s.end( ) );
581 std::vector< int > s;
584 REQUIRE( adjacent_find( s.begin( ), s.end( ), eq ) == s.end( ) );
588 std::vector< int > s;
591 REQUIRE( adjacent_find( s.begin( ), s.end( ), eq ) == s.begin( ) );
595 std::vector< int > s{ 1, 0, 5, 5, 6 };
596 auto it = adjacent_find( s.begin( ), s.end( ), eq );
597 REQUIRE( it != s.end( ) );
602 REQUIRE( it != s.end( ) );
607 std::vector< int > s{ 1, 0, 5, 6, 5, 5 };
608 auto it = adjacent_find( s.begin( ), s.end( ), eq );
609 REQUIRE( it != s.end( ) );
614 REQUIRE( it == s.end( ) );
618 #endif // _NDS_IMPL_ENABLE_CATCH_TESTS_
620 #endif // NDS_LITE_UTILS_HH