5 #ifndef NDS2_CLIENT_COMMONSPAN_READER_HH
6 #define NDS2_CLIENT_COMMONSPAN_READER_HH
11 #include "common/utils.hh"
21 typedef nds_impl::common::Span< char > span_type;
23 SpanReader( span_type& s ) : s_{ s }, cur_{ 0 }
28 write_all(
const char* begin,
const char* end )
30 throw std::runtime_error(
31 "Write operations not supported on the spanreader" );
42 read_available(
char* start,
char* end )
44 span_type::size_type len_requested = end - start;
46 if ( remaining( ) == 0 )
48 throw std::range_error(
"No more data to read" );
51 if ( remaining( ) < len_requested )
52 len_requested = remaining( );
53 std::copy( cur_data( ), cur_data( ) + len_requested, start );
54 consume( len_requested );
55 return start + len_requested;
65 read_exactly(
char* start,
const char* end )
67 span_type::size_type len_requested = end - start;
69 auto result = peek( start, end );
70 consume( len_requested );
85 peek(
char* start,
const char* end )
87 span_type::size_type len_requested = end - start;
89 while ( remaining( ) < len_requested )
91 throw std::range_error(
"Insufficient data for request" );
93 std::copy( cur_data( ), cur_data( ) + len_requested, start );
94 return start + len_requested;
108 template <
typename It >
110 read_until( It begin_set, It end_set )
112 std::vector< char > result;
114 span_type::size_type cur = 0;
115 auto rem = remaining( );
116 for (
bool match =
false; !match; ++cur, --rem )
120 throw std::range_error(
121 "Insufficient data for request" );
124 if ( std::find( begin_set, end_set, cur_data( )[ cur ] ) !=
130 result.resize( cur );
131 std::copy( cur_data( ), cur_data( ) + cur, result.begin( ) );
148 template <
typename It,
typename OutIt >
150 read_until( It begin_set,
155 span_type::size_type cur = 0;
156 auto rem = remaining( );
157 OutIt dest_cur = dest_start;
159 for ( ; !match && dest_cur != dest_end;
160 ++cur, --rem, ++dest_cur )
164 throw std::range_error(
165 "Insufficient data for request" );
168 if ( std::find( begin_set, end_set, cur_data( )[ cur ] ) !=
176 std::copy( cur_data( ), cur_data( ) + cur, dest_start );
180 throw std::range_error(
181 "Unable to find matching sequence" );
189 consume( span_type::size_type count )
191 if ( count > remaining( ) )
193 count = remaining( );
201 return s_.size( ) - cur_;
207 return s_.data( ) + cur_;
211 span_type::size_type cur_ = 0;
220 #ifdef _NDS_IMPL_ENABLE_CATCH_TESTS_
225 TEST_CASE(
"You can create a span reader class",
"[common,span_reader]" )
227 std::string tmp{
"abc" };
228 nds_impl::common::Span< char > s{
const_cast< char*
>( tmp.data( ) ),
230 nds_impl::common::SpanReader r{ s };
233 TEST_CASE(
"You can cannot write to a span_reader",
"[common,span_reader]" )
235 std::string tmp{
"abc" };
236 nds_impl::common::Span< char > s{
const_cast< char*
>( tmp.data( ) ),
238 nds_impl::common::SpanReader r{ s };
239 std::string tmp2{
"ABC" };
240 REQUIRE_THROWS( r.write_all( tmp2.data( ), tmp2.data( ) + tmp2.size( ) ) );
243 TEST_CASE(
"You can read from a span reader",
"[span_reader,read]" )
245 std::vector< char > dest( 20 );
247 auto hello = std::string{
"hello world!" };
248 nds_impl::common::Span< char > s{
const_cast< char*
>( hello.data( ) ),
250 nds_impl::common::SpanReader r{ s };
252 auto end = r.read_available( dest.data( ), dest.data( ) + dest.size( ) );
253 REQUIRE( end != dest.data( ) );
254 REQUIRE( end == dest.data( ) + hello.size( ) );
255 auto output = std::string( dest.data( ), end );
256 REQUIRE( output == hello );
259 TEST_CASE(
"You can read the data in small segments from a span reader",
260 "[span_reader,read]" )
262 std::vector< char > dest( 5 );
264 auto hello = std::string{
"hello world!" };
265 nds_impl::common::Span< char > s{
const_cast< char*
>( hello.data( ) ),
268 nds_impl::common::SpanReader r{ s };
270 auto end = r.read_available( dest.data( ), dest.data( ) + dest.size( ) );
271 REQUIRE( end != dest.data( ) );
272 REQUIRE( end == dest.data( ) + dest.size( ) );
273 auto output = std::string( dest.data( ), end );
274 REQUIRE( output == hello.substr( 0, dest.size( ) ) );
276 end = r.read_available( dest.data( ), dest.data( ) + dest.size( ) );
277 REQUIRE( end != dest.data( ) );
278 REQUIRE( end == dest.data( ) + dest.size( ) );
279 output = std::string( dest.data( ), end );
280 REQUIRE( output == hello.substr( dest.size( ), dest.size( ) ) );
283 TEST_CASE(
"You can ask for an exact amount of bytes to be returned from a "
285 "[span_reader,read]" )
287 std::vector< char > dest( 10 );
289 auto input = std::string{
"0123456789" };
290 nds_impl::common::Span< char > s{
const_cast< char*
>( input.data( ) ),
292 nds_impl::common::SpanReader r{ s };
295 auto end = r.read_exactly( dest.data( ), dest.data( ) + stride );
296 REQUIRE( end == dest.data( ) + stride );
299 r.read_exactly( dest.data( ), dest.data( ) + dest.size( ) ) );
302 TEST_CASE(
"You can peek at an exact amount of data without consuming it from "
304 "[span_reader,read]" )
306 std::vector< char > dest( 10 );
307 auto input = std::string{
"0123456789" };
309 nds_impl::common::Span< char > s{
const_cast< char*
>( input.data( ) ),
311 nds_impl::common::SpanReader r{ s };
314 auto end = r.peek( dest.data( ), dest.data( ) + stride );
315 REQUIRE( end == dest.data( ) + stride );
316 REQUIRE( std::equal( dest.data( ), dest.data( ) + stride, input.data( ) ) );
319 std::fill( dest.begin( ), dest.end( ), 0 );
321 !std::equal( dest.data( ), dest.data( ) + stride, input.data( ) ) );
323 end = r.read_exactly( dest.data( ), dest.data( ) + stride );
324 REQUIRE( end == dest.data( ) + stride );
325 REQUIRE( std::equal( dest.data( ), dest.data( ) + stride, input.data( ) ) );
328 TEST_CASE(
"You can ask a span reader to read until a sequence is found",
329 "[buffered,read_until]" )
331 auto input = std::string{
"0123456789" };
332 nds_impl::common::Span< char > s{
const_cast< char*
>( input.data( ) ),
334 nds_impl::common::SpanReader r{ s };
336 auto terminators = std::string(
"59" );
337 auto result = r.read_until( terminators.begin( ), terminators.end( ) );
338 REQUIRE( std::string( result.begin( ), result.end( ) ) ==
339 std::string(
"012345" ) );
342 TEST_CASE(
"You can ask a span reader to read until a sequence is found, "
344 "[span_reader,read_until]" )
346 std::vector< char > dest( 5 );
347 auto input = std::string{
"0123456789abcdef" };
348 nds_impl::common::Span< char > s{
const_cast< char*
>( input.data( ) ),
350 nds_impl::common::SpanReader r{ s };
352 std::fill( dest.begin( ), dest.end( ), 0 );
353 auto terminators = std::string(
"29" );
354 auto end = r.read_until(
355 terminators.begin( ), terminators.end( ), dest.begin( ), dest.end( ) );
356 auto length = std::distance( dest.begin( ), end );
357 REQUIRE( length == 3 );
358 REQUIRE( std::string( dest.data( ), length ) == std::string(
"012" ) );
362 "A bounded span_reader read_until will throw an exception if it cannot "
364 "[span_reader,read_until]" )
366 std::vector< char > dest( 5 );
367 auto input = std::string{
"0123456789abcdef" };
368 nds_impl::common::Span< char > s{
const_cast< char*
>( input.data( ) ),
370 nds_impl::common::SpanReader r{ s };
372 auto terminators = std::string(
"Z" );
373 REQUIRE_THROWS_AS( r.read_until( terminators.begin( ),
381 "A bounded span_reader read_until will throw an exception if it cannot "
382 "find a sequence when input is empty",
383 "[span_reader,read_until]" )
385 std::vector< char > dest( 5 );
386 auto input = std::string{
"" };
387 nds_impl::common::Span< char > s{
const_cast< char*
>( input.data( ) ),
389 nds_impl::common::SpanReader r{ s };
391 auto terminators = std::string(
"Z" );
392 REQUIRE_THROWS_AS( r.read_until( terminators.begin( ),
396 std::runtime_error );
399 #endif // _NDS_IMPL_ENABLE_CATCH_TESTS_
401 #endif // NDS2_CLIENT_COMMON_SPAN_READER_HH