nds2-client - Developer 0.16.7
Loading...
Searching...
No Matches
utils.hh
Go to the documentation of this file.
1//
2// Created by jonathan.hanks on 4/29/17.
3//
4
5#ifndef NDS_LITE_UTILS_HH
6#define NDS_LITE_UTILS_HH
7
8#include <cstddef>
9#include <stdexcept>
10#include <string>
11#include <vector>
12
13namespace nds_impl
14{
15 namespace common
16 {
17 template < typename T >
19 {
20 public:
21 auto
22 operator( )( const T& input ) -> T
23 {
24 return input;
25 }
26 };
27
33
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 )
38 {
39 std::vector< std::string > results;
40
41 if ( source == "" )
42 return results;
43 std::string::size_type prev = 0;
44 std::string::size_type pos = 0;
45 if ( sep.size( ) > 0 )
46 {
47 std::string::size_type sep_size = sep.size( );
48 while ( pos < source.size( ) && pos != std::string::npos )
49 {
50 pos = source.find( sep, prev );
51 if ( pos != std::string::npos )
52 {
53 auto tmp = source.substr( prev, pos - prev );
54 if ( tmp != "" || filter_mode == INCLUDE_EMPTY_STRING )
55 results.push_back( tmp );
56 pos += sep_size;
57 prev = pos;
58 }
59 }
60 }
61 else
62 {
63 while ( pos < source.size( ) && pos != std::string::npos )
64 {
65 pos = source.find_first_of( " \t\n\r", prev );
66 if ( pos != std::string::npos )
67 {
68 auto tmp = source.substr( prev, pos - prev );
69 if ( tmp != "" || filter_mode == INCLUDE_EMPTY_STRING )
70 results.push_back( tmp );
71 ++pos;
72 prev = pos;
73 }
74 }
75 }
76 auto tmp = source.substr( prev );
77 if ( tmp != "" || filter_mode == INCLUDE_EMPTY_STRING )
78 results.push_back( tmp );
79 return results;
80 }
81
82 template < typename T >
84 {
85 public:
86 bool
87 operator( )( const T& input )
88 {
89 return true;
90 }
91 };
92
93 template < typename T >
95 {
96 public:
97 typedef std::size_t size_type;
98
100 : max_{ max }, local_cur_{ 0 }, ext_cur_{ &local_cur_ }
101 {
102 }
104 : max_{ max }, local_cur_{ 0 }, ext_cur_{ ext_tracker }
105 {
106 }
107 bool
108 operator( )( const T& input )
109 {
110 if ( *ext_cur_ < max_ )
111 {
112 ++( *ext_cur_ );
113 return true;
114 }
115 return false;
116 }
117
119 accepted( ) const
120 {
121 return *ext_cur_;
122 }
123
124 private:
128 };
129
134 template < typename T >
135 class Span
136 {
137 public:
138 typedef T value_type;
139 typedef std::size_t size_type;
140 typedef T* pointer;
141 typedef std::ptrdiff_t difference_type;
142 typedef T& reference;
143 typedef T* iterator;
144
145 Span( const Span< T >& other )
146 : data_{ other.data_ }, size_{ other.size_ }
147 {
148 }
149 Span( T* data, size_type count )
150 : data_{ data }, size_{ ( data ? count : 0 ) }
151 {
152 }
154 size( ) const
155 {
156 return size_;
157 }
159 max_size( ) const
160 {
161 return size( );
162 }
163 bool
164 empty( ) const
165 {
166 return size( ) == 0;
167 }
168 pointer
169 data( ) const
170 {
171 return data_;
172 }
173 pointer
174 begin( ) const
175 {
176 return data_;
177 }
178 pointer
179 end( ) const
180 {
181 return data_ + size_;
182 }
184 at( size_t index ) const
185 {
186 if ( index >= size_ )
187 throw std::out_of_range(
188 "accessing outside of the array range" );
189 return data_[ index ];
190 }
191 reference operator[]( size_t index )
192 {
193 return data_[ index ];
194 }
196 front( ) const
197 {
198 return *data_;
199 }
201 back( ) const
202 {
203 return data_[ size_ - 1 ];
204 }
205 void
206 swap( Span< T >& other )
207 {
208 std::swap( other.data_, data_ );
209 std::swap( other.size_, size_ );
210 }
211 void
212 fill( T& value )
213 {
214 std::fill( begin( ), end( ), value );
215 }
216
217 private:
220 };
221
222 template < typename It, typename BinaryPred >
223 It
224 adjacent_find( It begin, It end, BinaryPred p )
225 {
226 auto cur = begin;
227 if ( cur == end )
228 {
229 return end;
230 }
231 auto prev = cur;
232 ++cur;
233 for ( ; cur != end; ++cur, prev = cur )
234 {
235 if ( p( *prev, *cur ) )
236 {
237 return prev;
238 }
239 }
240 return end;
241 }
242 }
243}
244
246// Tests only after this point.
248
249#ifdef _NDS_IMPL_ENABLE_CATCH_TESTS_
250
251#include <algorithm>
252#include <cstring>
253#include "catch.hpp"
254
255namespace nds_impl_cmn_utils
256{
257 struct simple_struct
258 {
259 int field1;
260 char field2[ 10 ];
261 };
262}
263
264TEST_CASE( "An identity transform transforms an object to itself",
265 "[nds2][utils][transforms]" )
266{
267 {
269 auto input = std::string( "hello" );
270 auto output = t_str( input );
271 REQUIRE( input == output );
272 }
273}
274
275TEST_CASE( "Test split", "[utils][split]" )
276{
277 {
278 auto result = nds_impl::common::split( "", "" );
279 REQUIRE( result.size( ) == 0 );
280 }
281 {
282 auto result = nds_impl::common::split(
284 REQUIRE( result.size( ) == 0 );
285 }
286 {
287 auto result = nds_impl::common::split( "", "a" );
288 REQUIRE( result.size( ) == 0 );
289 }
290 {
291 auto result = nds_impl::common::split(
293 REQUIRE( result.size( ) == 0 );
294 }
295 {
296 auto result = nds_impl::common::split( "abc", "b" );
297 REQUIRE( result.size( ) == 2 );
298 REQUIRE( result[ 0 ] == "a" );
299 REQUIRE( result[ 1 ] == "c" );
300 }
301 {
302 auto result = nds_impl::common::split(
304 REQUIRE( result.size( ) == 2 );
305 REQUIRE( result[ 0 ] == "a" );
306 REQUIRE( result[ 1 ] == "c" );
307 }
308 {
309 auto result = nds_impl::common::split( "abc", "d" );
310 REQUIRE( result.size( ) == 1 );
311 REQUIRE( result[ 0 ] == "abc" );
312 }
313 {
314 auto result = nds_impl::common::split(
316 REQUIRE( result.size( ) == 1 );
317 REQUIRE( result[ 0 ] == "abc" );
318 }
319 {
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 );
324 }
325 {
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" );
331 }
332 {
333 auto result = nds_impl::common::split(
334 "catbatdog",
335 "at",
337 REQUIRE( result.size( ) == 3 );
338 REQUIRE( result[ 0 ] == "c" );
339 REQUIRE( result[ 1 ] == "b" );
340 REQUIRE( result[ 2 ] == "dog" );
341 }
342 {
343 auto result = nds_impl::common::split( "abc", "" );
344 REQUIRE( result.size( ) == 1 );
345 REQUIRE( result[ 0 ] == "abc" );
346 }
347 {
348 auto result = nds_impl::common::split(
350 REQUIRE( result.size( ) == 1 );
351 REQUIRE( result[ 0 ] == "abc" );
352 }
353 {
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 );
358 }
359 {
360 auto result = nds_impl::common::split(
361 "a b\r \tc\nd",
362 "",
364 REQUIRE( result.size( ) == 4 );
365 std::vector< std::string > expected{ "a", "b", "c", "d" };
366 REQUIRE( result == expected );
367 }
368 {
369 auto result = nds_impl::common::split(
370 "a b\r \tc\nd ",
371 "",
373 REQUIRE( result.size( ) == 4 );
374 std::vector< std::string > expected{ "a", "b", "c", "d" };
375 REQUIRE( result == expected );
376 }
377}
378
379TEST_CASE( "TruePredicate", "[utils][predicates]" )
380{
382 REQUIRE( p( 10000000 ) );
383 REQUIRE( p( 1 ) );
384 REQUIRE( p( 0 ) );
385 REQUIRE( p( -1 ) );
386 REQUIRE( p( -1000000 ) );
387}
388
389TEST_CASE( "FirstNPredicate", "[utils][predicates]" )
390{
391 {
393 for ( auto i = 0; i < 5; ++i )
394 {
395 REQUIRE( p.accepted( ) == i );
396 REQUIRE( p( 1 ) );
397 }
398 REQUIRE( p.accepted( ) == 5 );
399 REQUIRE( !p( 1 ) );
400 REQUIRE( p.accepted( ) == 5 );
401 REQUIRE( !p( 1 ) );
402 REQUIRE( p.accepted( ) == 5 );
403 }
404
405 {
406 auto test_cb = []( nds_impl::common::FirstNPredicate< int > p,
407 int val ) {
408 REQUIRE( p.accepted( ) == val );
409 REQUIRE( p( 1 ) );
410 };
412 for ( auto i = 0; i < 5; ++i )
413 {
414 test_cb( p, i );
415 }
416 REQUIRE( p.accepted( ) == 5 );
417 REQUIRE( !p( 1 ) );
418 REQUIRE( p.accepted( ) == 5 );
419 REQUIRE( !p( 1 ) );
420 REQUIRE( p.accepted( ) == 5 );
421 }
422}
423
424TEST_CASE( "Array_view", "[utils][array_view]" )
425{
426 using namespace nds_impl_cmn_utils;
427
428 const int ARRAY_SIZE = 20;
429 simple_struct base[ ARRAY_SIZE ];
430 for ( auto i = 0; i < ARRAY_SIZE; ++i )
431 {
432 base[ i ].field1 = static_cast< int >( i );
433 std::strncpy(
434 base[ i ].field2, "a string", sizeof( base[ i ].field2 ) );
435 }
436
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 )
451 {
452 REQUIRE( array.at( i ).field1 == static_cast< int >( i ) );
453 REQUIRE( std::strncmp( array.at( i ).field2,
454 "a string",
455 sizeof( base[ i ].field2 ) ) == 0 );
456
457 REQUIRE( array[ i ].field1 == static_cast< int >( i ) );
458 REQUIRE( std::strncmp( array[ i ].field2,
459 "a string",
460 sizeof( base[ i ].field2 ) ) == 0 );
461 }
462
463 typedef nds_impl::common::Span< simple_struct > sstruct_array;
464 static_assert(
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,
467 "" );
468 static_assert(
469 std::is_same< sstruct_array::pointer, simple_struct* >::value, "" );
470 static_assert(
471 std::is_same< sstruct_array::difference_type, std::ptrdiff_t >::value,
472 "" );
473 static_assert(
474 std::is_same< sstruct_array::reference, simple_struct& >::value, "" );
475 static_assert(
476 std::is_same< sstruct_array::iterator, simple_struct* >::value, "" );
477 // static_assert(std::is_same<sstruct_array::, >::value, "");
478}
479
480TEST_CASE( "Empty Span", "[utils][array_view]" )
481{
482 using namespace nds_impl_cmn_utils;
483
484 const int ARRAY_SIZE = 5;
485 simple_struct base[ 5 ];
486
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 );
493
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 );
500
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 );
507}
508
509TEST_CASE( "Copy and assign ArrayViews", "[utils][array_view]" )
510{
511 using namespace nds_impl_cmn_utils;
512
513 const int ARRAY_SIZE = 5;
514 simple_struct base[ 5 ];
515
516 nds_impl::common::Span< simple_struct > array1( base, ARRAY_SIZE );
517 nds_impl::common::Span< simple_struct > array2( base + 1, ARRAY_SIZE - 2 );
519 REQUIRE( array1.size( ) == array3.size( ) );
520 REQUIRE( array1.data( ) == array3.data( ) );
521
522 array3 = array2;
523 REQUIRE( array3.size( ) == array2.size( ) );
524 REQUIRE( array3.data( ) == array2.data( ) );
525
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 );
531}
532
533TEST_CASE( "array_view fill", "[utils][array_view]" )
534{
535 using namespace nds_impl_cmn_utils;
536
537 const int ARRAY_SIZE = 5;
538 simple_struct base[ 5 ];
539
540 nds_impl::common::Span< simple_struct > array( base, ARRAY_SIZE );
541 simple_struct ref;
542 ref.field1 = 42;
543 std::strncpy( ref.field2, "answer", sizeof( ref.field2 ) );
544 array.fill( ref );
545 for ( auto entry : array )
546 {
547 REQUIRE( entry.field1 == 42 );
548 REQUIRE( std::strncmp(
549 entry.field2, "answer", sizeof( entry.field2 ) ) == 0 );
550 }
551 ref.field1 = 32;
552 std::strncpy( ref.field2, "nonanswer", sizeof( ref.field2 ) );
553 array.fill( ref );
554 for ( auto entry : array )
555 {
556 REQUIRE( entry.field1 == 32 );
557 REQUIRE( std::strncmp(
558 entry.field2, "nonanswer", sizeof( entry.field2 ) ) == 0 );
559 }
560}
561
562TEST_CASE( "adjacent_find finds two entries next to each other that are equal",
563 "[utils][algorithms]" )
564{
565 using namespace nds_impl_cmn_utils;
566
567 auto eq = []( int a, int b ) -> bool { return a == b; };
568
569 {
570 std::vector< int > s;
571 REQUIRE( adjacent_find( s.begin( ), s.end( ), eq ) == s.end( ) );
572 }
573
574 {
575 std::vector< int > s;
576 s.push_back( 1 );
577 REQUIRE( adjacent_find( s.begin( ), s.end( ), eq ) == s.end( ) );
578 }
579
580 {
581 std::vector< int > s;
582 s.push_back( 1 );
583 s.push_back( 2 );
584 REQUIRE( adjacent_find( s.begin( ), s.end( ), eq ) == s.end( ) );
585 }
586
587 {
588 std::vector< int > s;
589 s.push_back( 1 );
590 s.push_back( 1 );
591 REQUIRE( adjacent_find( s.begin( ), s.end( ), eq ) == s.begin( ) );
592 }
593
594 {
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( ) );
598 REQUIRE( *it == 5 );
599 ++it;
600 REQUIRE( *it == 5 );
601 ++it;
602 REQUIRE( it != s.end( ) );
603 REQUIRE( *it == 6 );
604 }
605
606 {
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( ) );
610 REQUIRE( *it == 5 );
611 ++it;
612 REQUIRE( *it == 5 );
613 ++it;
614 REQUIRE( it == s.end( ) );
615 }
616}
617
618#endif // _NDS_IMPL_ENABLE_CATCH_TESTS_
619
620#endif // NDS_LITE_UTILS_HH
Definition utils.hh:95
size_type * ext_cur_
Definition utils.hh:127
FirstNPredicate(size_type max, size_type *ext_tracker)
Definition utils.hh:103
std::size_t size_type
Definition utils.hh:97
size_type local_cur_
Definition utils.hh:126
size_type max_
Definition utils.hh:125
size_type accepted() const
Definition utils.hh:119
FirstNPredicate(size_type max)
Definition utils.hh:99
Definition utils.hh:136
void swap(Span< T > &other)
Definition utils.hh:206
size_type size_
Definition utils.hh:219
reference operator[](size_t index)
Definition utils.hh:191
T value_type
Definition utils.hh:138
Span(T *data, size_type count)
Definition utils.hh:149
pointer end() const
Definition utils.hh:179
void fill(T &value)
Definition utils.hh:212
value_type * data_
Definition utils.hh:218
T * iterator
Definition utils.hh:143
reference back() const
Definition utils.hh:201
pointer data() const
Definition utils.hh:169
T & reference
Definition utils.hh:142
std::size_t size_type
Definition utils.hh:139
Span(const Span< T > &other)
Definition utils.hh:145
bool empty() const
Definition utils.hh:164
pointer begin() const
Definition utils.hh:174
reference at(size_t index) const
Definition utils.hh:184
reference front() const
Definition utils.hh:196
size_type size() const
Definition utils.hh:154
size_type max_size() const
Definition utils.hh:159
T * pointer
Definition utils.hh:140
std::ptrdiff_t difference_type
Definition utils.hh:141
Definition utils.hh:84
It adjacent_find(It begin, It end, BinaryPred p)
Definition utils.hh:224
static std::vector< std::string > split(const std::string &source, const std::string &sep, split_type filter_mode=INCLUDE_EMPTY_STRING)
Definition utils.hh:35
split_type
Definition utils.hh:29
@ EXCLUDE_EMPTY_STRING
Definition utils.hh:31
@ INCLUDE_EMPTY_STRING
Definition utils.hh:30
Definition span_reader.hh:14
std::unique_ptr< T > pointer
Definition nds_testing.hh:13
TEST_CASE("daq_strlcpy copies strings safely when buffers are sufficiently large")
Definition test_bsd_string.cc:9