nds2-client - Developer 0.16.7
Loading...
Searching...
No Matches
span_reader.hh
Go to the documentation of this file.
1//
2// Created by jonathan.hanks on 5/4/18.
3//
4
5#ifndef NDS2_CLIENT_COMMONSPAN_READER_HH
6#define NDS2_CLIENT_COMMONSPAN_READER_HH
7
8#include <algorithm>
9#include <stdexcept>
10
11#include "common/utils.hh"
12
13namespace nds_impl
14{
15 namespace common
16 {
17
19 {
20 public:
22
23 SpanReader( span_type& s ) : s_{ s }, cur_{ 0 }
24 {
25 }
26
27 char*
28 write_all( const char* begin, const char* end )
29 {
30 throw std::runtime_error(
31 "Write operations not supported on the spanreader" );
32 }
33
41 char*
42 read_available( char* start, char* end )
43 {
44 span_type::size_type len_requested = end - start;
45
46 if ( remaining( ) == 0 )
47 {
48 throw std::range_error( "No more data to read" );
49 }
50
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;
56 }
57
64 char*
65 read_exactly( char* start, const char* end )
66 {
67 span_type::size_type len_requested = end - start;
68
69 auto result = peek( start, end );
70 consume( len_requested );
71 return result;
72 }
73
84 char*
85 peek( char* start, const char* end )
86 {
87 span_type::size_type len_requested = end - start;
88
89 while ( remaining( ) < len_requested )
90 {
91 throw std::range_error( "Insufficient data for request" );
92 }
93 std::copy( cur_data( ), cur_data( ) + len_requested, start );
94 return start + len_requested;
95 }
96
108 template < typename It >
109 std::vector< char >
110 read_until( It begin_set, It end_set )
111 {
112 std::vector< char > result;
113
114 span_type::size_type cur = 0;
115 auto rem = remaining( );
116 for ( bool match = false; !match; ++cur, --rem )
117 {
118 if ( rem == 0 )
119 {
120 throw std::range_error(
121 "Insufficient data for request" );
122 }
123
124 if ( std::find( begin_set, end_set, cur_data( )[ cur ] ) !=
125 end_set )
126 {
127 match = true;
128 }
129 }
130 result.resize( cur );
131 std::copy( cur_data( ), cur_data( ) + cur, result.begin( ) );
132 consume( cur );
133 return result;
134 }
135
148 template < typename It, typename OutIt >
149 OutIt
150 read_until( It begin_set,
151 It end_set,
152 OutIt dest_start,
153 OutIt dest_end )
154 {
155 span_type::size_type cur = 0;
156 auto rem = remaining( );
157 OutIt dest_cur = dest_start;
158 bool match = false;
159 for ( ; !match && dest_cur != dest_end;
160 ++cur, --rem, ++dest_cur )
161 {
162 if ( rem == 0 )
163 {
164 throw std::range_error(
165 "Insufficient data for request" );
166 }
167
168 if ( std::find( begin_set, end_set, cur_data( )[ cur ] ) !=
169 end_set )
170 {
171 match = true;
172 }
173 }
174 if ( match )
175 {
176 std::copy( cur_data( ), cur_data( ) + cur, dest_start );
177 }
178 else
179 {
180 throw std::range_error(
181 "Unable to find matching sequence" );
182 }
183 consume( cur );
184 return dest_cur;
185 }
186
187 private:
188 void
190 {
191 if ( count > remaining( ) )
192 {
193 count = remaining( );
194 }
195 cur_ += count;
196 }
197
200 {
201 return s_.size( ) - cur_;
202 }
203
204 char*
206 {
207 return s_.data( ) + cur_;
208 }
209
212 };
213 }
214}
215
217// Tests only after this point.
219
220#ifdef _NDS_IMPL_ENABLE_CATCH_TESTS_
221
222#include <string>
223#include "catch.hpp"
224
225TEST_CASE( "You can create a span reader class", "[common,span_reader]" )
226{
227 std::string tmp{ "abc" };
228 nds_impl::common::Span< char > s{ const_cast< char* >( tmp.data( ) ),
229 tmp.size( ) };
231}
232
233TEST_CASE( "You can cannot write to a span_reader", "[common,span_reader]" )
234{
235 std::string tmp{ "abc" };
236 nds_impl::common::Span< char > s{ const_cast< char* >( tmp.data( ) ),
237 tmp.size( ) };
239 std::string tmp2{ "ABC" };
240 REQUIRE_THROWS( r.write_all( tmp2.data( ), tmp2.data( ) + tmp2.size( ) ) );
241}
242
243TEST_CASE( "You can read from a span reader", "[span_reader,read]" )
244{
245 std::vector< char > dest( 20 );
246
247 auto hello = std::string{ "hello world!" };
248 nds_impl::common::Span< char > s{ const_cast< char* >( hello.data( ) ),
249 hello.size( ) };
251
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 );
257}
258
259TEST_CASE( "You can read the data in small segments from a span reader",
260 "[span_reader,read]" )
261{
262 std::vector< char > dest( 5 );
263
264 auto hello = std::string{ "hello world!" };
265 nds_impl::common::Span< char > s{ const_cast< char* >( hello.data( ) ),
266 hello.size( ) };
267
269
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( ) ) );
275
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( ) ) );
281}
282
283TEST_CASE( "You can ask for an exact amount of bytes to be returned from a "
284 "span_reader",
285 "[span_reader,read]" )
286{
287 std::vector< char > dest( 10 );
288
289 auto input = std::string{ "0123456789" };
290 nds_impl::common::Span< char > s{ const_cast< char* >( input.data( ) ),
291 input.size( ) };
293
294 auto stride = 4;
295 auto end = r.read_exactly( dest.data( ), dest.data( ) + stride );
296 REQUIRE( end == dest.data( ) + stride );
297
298 REQUIRE_THROWS(
299 r.read_exactly( dest.data( ), dest.data( ) + dest.size( ) ) );
300}
301
302TEST_CASE( "You can peek at an exact amount of data without consuming it from "
303 "a span reader",
304 "[span_reader,read]" )
305{
306 std::vector< char > dest( 10 );
307 auto input = std::string{ "0123456789" };
308
309 nds_impl::common::Span< char > s{ const_cast< char* >( input.data( ) ),
310 input.size( ) };
312
313 auto stride = 4;
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( ) ) );
317
318 // clear the buffer
319 std::fill( dest.begin( ), dest.end( ), 0 );
320 REQUIRE(
321 !std::equal( dest.data( ), dest.data( ) + stride, input.data( ) ) );
322
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( ) ) );
326}
327
328TEST_CASE( "You can ask a span reader to read until a sequence is found",
329 "[buffered,read_until]" )
330{
331 auto input = std::string{ "0123456789" };
332 nds_impl::common::Span< char > s{ const_cast< char* >( input.data( ) ),
333 input.size( ) };
335
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" ) );
340}
341
342TEST_CASE( "You can ask a span reader to read until a sequence is found, "
343 "with a bound",
344 "[span_reader,read_until]" )
345{
346 std::vector< char > dest( 5 );
347 auto input = std::string{ "0123456789abcdef" };
348 nds_impl::common::Span< char > s{ const_cast< char* >( input.data( ) ),
349 input.size( ) };
351
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" ) );
359}
360
362 "A bounded span_reader read_until will throw an exception if it cannot "
363 "find a sequence",
364 "[span_reader,read_until]" )
365{
366 std::vector< char > dest( 5 );
367 auto input = std::string{ "0123456789abcdef" };
368 nds_impl::common::Span< char > s{ const_cast< char* >( input.data( ) ),
369 input.size( ) };
371
372 auto terminators = std::string( "Z" );
373 REQUIRE_THROWS_AS( r.read_until( terminators.begin( ),
374 terminators.end( ),
375 dest.begin( ),
376 dest.end( ) ),
377 std::range_error );
378}
379
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]" )
384{
385 std::vector< char > dest( 5 );
386 auto input = std::string{ "" };
387 nds_impl::common::Span< char > s{ const_cast< char* >( input.data( ) ),
388 input.size( ) };
390
391 auto terminators = std::string( "Z" );
392 REQUIRE_THROWS_AS( r.read_until( terminators.begin( ),
393 terminators.end( ),
394 dest.begin( ),
395 dest.end( ) ),
396 std::runtime_error );
397}
398
399#endif // _NDS_IMPL_ENABLE_CATCH_TESTS_
400
401#endif // NDS2_CLIENT_COMMON_SPAN_READER_HH
Definition span_reader.hh:19
span_type::size_type cur_
Definition span_reader.hh:211
char * read_exactly(char *start, const char *end)
Definition span_reader.hh:65
nds_impl::common::Span< char > span_type
Definition span_reader.hh:21
OutIt read_until(It begin_set, It end_set, OutIt dest_start, OutIt dest_end)
Definition span_reader.hh:150
std::vector< char > read_until(It begin_set, It end_set)
Definition span_reader.hh:110
char * read_available(char *start, char *end)
Definition span_reader.hh:42
char * write_all(const char *begin, const char *end)
Definition span_reader.hh:28
char * cur_data()
Definition span_reader.hh:205
span_type s_
Definition span_reader.hh:210
span_type::size_type remaining()
Definition span_reader.hh:199
void consume(span_type::size_type count)
Definition span_reader.hh:189
char * peek(char *start, const char *end)
Definition span_reader.hh:85
SpanReader(span_type &s)
Definition span_reader.hh:23
pointer data() const
Definition utils.hh:169
std::size_t size_type
Definition utils.hh:139
size_type size() const
Definition utils.hh:154
Definition span_reader.hh:14
TEST_CASE("daq_strlcpy copies strings safely when buffers are sufficiently large")
Definition test_bsd_string.cc:9