nds2-client - ClientDeveloper  0.16.8
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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 
13 namespace 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 
29  {
32  };
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  }
103  FirstNPredicate( size_type max, size_type* ext_tracker )
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 
118  size_type
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  }
153  size_type
154  size( ) const
155  {
156  return size_;
157  }
158  size_type
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  }
183  reference
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  }
195  reference
196  front( ) const
197  {
198  return *data_;
199  }
200  reference
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 
255 namespace nds_impl_cmn_utils
256 {
257  struct simple_struct
258  {
259  int field1;
260  char field2[ 10 ];
261  };
262 }
263 
264 TEST_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 
275 TEST_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 
379 TEST_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 
389 TEST_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 
424 TEST_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 
480 TEST_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 
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 );
507 }
508 
509 TEST_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 
533 TEST_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 
562 TEST_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
size_type max_
Definition: utils.hh:125
Definition: utils.hh:135
Definition: utils.hh:83
split_type
Definition: utils.hh:28
std::unique_ptr< T > pointer
Definition: nds_testing.hh:13
pointer begin() const
Definition: utils.hh:174
std::size_t size_type
Definition: utils.hh:97
It adjacent_find(It begin, It end, BinaryPred p)
Definition: utils.hh:224
TEST_CASE("daq_strlcpy copies strings safely when buffers are sufficiently large")
Definition: test_bsd_string.cc:9
reference operator[](size_t index)
Definition: utils.hh:191
T value_type
Definition: utils.hh:138
pointer end() const
Definition: utils.hh:179
Span(T *data, size_type count)
Definition: utils.hh:149
Span(const Span< T > &other)
Definition: utils.hh:145
size_type * ext_cur_
Definition: utils.hh:127
FirstNPredicate(size_type max)
Definition: utils.hh:99
Definition: utils.hh:94
T & reference
Definition: utils.hh:142
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
T * pointer
Definition: utils.hh:140
void fill(T &value)
Definition: utils.hh:212
std::size_t size_type
Definition: utils.hh:139
reference at(size_t index) const
Definition: utils.hh:184
bool empty() const
Definition: utils.hh:164
T * iterator
Definition: utils.hh:143
FirstNPredicate(size_type max, size_type *ext_tracker)
Definition: utils.hh:103
value_type * data_
Definition: utils.hh:218
reference front() const
Definition: utils.hh:196
size_type max_size() const
Definition: utils.hh:159
size_type local_cur_
Definition: utils.hh:126
void swap(Span< T > &other)
Definition: utils.hh:206
reference back() const
Definition: utils.hh:201
size_type size_
Definition: utils.hh:219
pointer data() const
Definition: utils.hh:169
size_type accepted() const
Definition: utils.hh:119
size_type size() const
Definition: utils.hh:154
std::ptrdiff_t difference_type
Definition: utils.hh:141