join 1.0
lightweight network framework library
Loading...
Searching...
No Matches
view.hpp
Go to the documentation of this file.
1
25#ifndef __JOIN_VIEW_HPP__
26#define __JOIN_VIEW_HPP__
27
28// libjoin.
29#include <join/utils.hpp>
30
31// C++.
32#include <istream>
33#include <string>
34#include <vector>
35
36// C.
37#include <cstring>
38#include <cstddef>
39
40namespace join
41{
42 namespace details
43 {
44 struct alignas(64) EscapedTable
45 {
46 uint8_t data[256];
47
48 constexpr EscapedTable () : data {}
49 {
50 for (unsigned i = 0; i < 0x20; ++i) { data[i] = 1; }
51 data['"'] = 1;
52 data['\\'] = 1;
53 }
54 };
55
57
58 struct alignas(64) WhitespaceTable
59 {
60 uint8_t data[256];
61
62 constexpr WhitespaceTable () : data {}
63 {
64 data['\t'] = 1;
65 data['\n'] = 1;
66 data['\r'] = 1;
67 data[' '] = 1;
68 }
69 };
70
72 }
73
78 {
79 public:
80 using ViewPos = const char*;
81
87 constexpr StringView (const char * in, size_t count)
88 : _cur (in)
89 , _beg (in)
90 , _end (in ? in + count : in)
91 {
92 }
93
99 constexpr StringView (const char * first, const char * last)
100 : _cur (first)
101 , _beg (first)
102 , _end (last)
103 {
104 }
105
110 StringView (const char * in)
111 : _cur (in)
112 , _beg (in)
113 , _end (in ? in + std::char_traits <char>::length (in) : in)
114 {
115 }
116
121 StringView (const StringView& other) = default;
122
128 StringView& operator= (const StringView& other) = default;
129
134 StringView (StringView&& other) = default;
135
141 StringView& operator=(StringView&& other) = default;
142
146 ~StringView () = default;
147
152 inline int peek () const noexcept
153 {
154 if (JOIN_LIKELY (_cur < _end))
155 {
156 return static_cast <unsigned char> (*_cur);
157 }
158 return std::char_traits <char>::eof ();
159 }
160
165 inline int get () noexcept
166 {
167 if (JOIN_LIKELY (_cur < _end))
168 {
169 return static_cast <unsigned char> (*_cur++);
170 }
171 return std::char_traits <char>::eof ();
172 }
173
179 inline bool getIf (char expected) noexcept
180 {
181 if (JOIN_LIKELY (_cur < _end) && (*_cur == expected))
182 {
183 ++_cur;
184 return true;
185 }
186 return false;
187 }
188
194 inline bool getIfNoCase (char expected) noexcept
195 {
196 if (JOIN_LIKELY (_cur < _end))
197 {
198 const char c = *_cur;
199 if ((c | 32) == (expected | 32))
200 {
201 ++_cur;
202 return true;
203 }
204 }
205 return false;
206 }
207
214 inline size_t read (char* buf, size_t count) noexcept
215 {
216 const size_t available = _end - _cur;
217 const size_t nread = (count < available) ? count : available;
218 std::memcpy (buf, _cur, nread);
219 _cur += nread;
220 return nread;
221 }
222
227 inline void readUntilEscaped (std::string& out) noexcept
228 {
229 const char* beg = _cur;
230 const char* cur = _cur;
231 const char* end = _end;
232
233 while (cur < end && !details::escapedLookup.data[static_cast <unsigned char> (*cur)])
234 {
235 ++cur;
236 }
237
238 out.append (beg, static_cast <size_t> (cur - beg));
239 _cur = cur;
240 }
241
246 inline int skipWhitespaces () noexcept
247 {
248 const char* cur = _cur;
249 const char* end = _end;
250
251 while (cur < end && details::whitespaceLookup.data[static_cast <unsigned char> (*cur)])
252 {
253 ++cur;
254 }
255
256 _cur = cur;
257
258 return 0;
259 }
260
265 inline int skipWhitespacesAndComments () noexcept
266 {
267 const char* cur = _cur;
268 const char* end = _end;
269
270 while (cur < end)
271 {
272 while (cur < end && details::whitespaceLookup.data[static_cast <unsigned char> (*cur)])
273 {
274 ++cur;
275 }
276
277 if (cur >= end || *cur != '/')
278 {
279 break;
280 }
281
282 if (++cur >= end)
283 {
284 return -1;
285 }
286
287 if (*cur == '*')
288 {
289 ++cur;
290 bool closed = false;
291 while (cur < end)
292 {
293 if (*cur == '*' && (cur + 1 < end) && *(cur + 1) == '/')
294 {
295 cur += 2;
296 closed = true;
297 break;
298 }
299 ++cur;
300 }
301 if (!closed)
302 {
303 return -1;
304 }
305 }
306 else if (*cur == '/')
307 {
308 ++cur;
309 const char* p = static_cast <const char*> (memchr (cur, '\n', end - cur));
310 cur = p ? p : end;
311 }
312 else
313 {
314 return -1;
315 }
316 }
317
318 _cur = cur;
319
320 return 0;
321 }
322
327 inline ViewPos tell () const noexcept
328 {
329 return _cur;
330 }
331
336 inline void seek (ViewPos pos) noexcept
337 {
338 if (JOIN_LIKELY (pos >= _beg && pos <= _end))
339 {
340 _cur = pos;
341 }
342 else if (pos < _beg)
343 {
344 _cur = _beg;
345 }
346 else
347 {
348 _cur = _end;
349 }
350 }
351
352 private:
354 const char * _cur = nullptr;
355
357 const char * _beg = nullptr;
358
360 const char * _end = nullptr;
361 };
362
366 template <bool Seekable = true>
368 {
369 public:
370 using ViewPos = std::streampos;
371
376 BasicStreamView (std::istream& in)
377 : _in (in.rdbuf ())
378 {
379 }
380
385 BasicStreamView (const BasicStreamView& other) = delete;
386
393
399
406
410 ~BasicStreamView () = default;
411
416 inline int peek () const noexcept
417 {
418 return _in->sgetc ();
419 }
420
425 inline int get () noexcept
426 {
427 return _in->sbumpc ();
428 }
429
435 inline bool getIf (char expected) noexcept
436 {
437 if (_in->sgetc () == static_cast <int> (static_cast <unsigned char> (expected)))
438 {
439 _in->sbumpc ();
440 return true;
441 }
442 return false;
443 }
444
450 inline bool getIfNoCase (char expected) noexcept
451 {
452 const int c = _in->sgetc ();
453 if (JOIN_LIKELY (c != std::char_traits <char>::eof ()))
454 {
455 if ((static_cast <char> (c) | 32) == (expected | 32))
456 {
457 _in->sbumpc ();
458 return true;
459 }
460 }
461 return false;
462 }
463
470 inline size_t read (char* buf, size_t count) noexcept
471 {
472 return _in->sgetn (buf, count);
473 }
474
479 inline void readUntilEscaped (std::string& out) noexcept
480 {
481 int c;
482 while ((c = _in->sgetc ()) != std::char_traits <char>::eof () && !details::escapedLookup.data[static_cast <unsigned char> (c)])
483 {
484 out.push_back (static_cast <char> (c));
485 _in->sbumpc ();
486 }
487 }
488
493 inline int skipWhitespaces () noexcept
494 {
495 int c;
496 while ((c = _in->sgetc ()) != std::char_traits <char>::eof () && details::whitespaceLookup.data[static_cast <unsigned char> (c)])
497 {
498 _in->sbumpc ();
499 }
500
501 return 0;
502 }
503
508 inline int skipWhitespacesAndComments () noexcept
509 {
510 int c;
511
512 while ((c = _in->sgetc ()) != std::char_traits <char>::eof ())
513 {
514 while ((c = _in->sgetc ()) != std::char_traits <char>::eof () && details::whitespaceLookup.data[static_cast <unsigned char> (c)])
515 {
516 _in->sbumpc ();
517 }
518
519 if (c != '/')
520 {
521 break;
522 }
523
524 _in->sbumpc ();
525 c = _in->sgetc ();
526
527 if (c == std::char_traits <char>::eof ())
528 {
529 return -1;
530 }
531
532 if (c == '*')
533 {
534 _in->sbumpc ();
535 bool closed = false;
536
537 while ((c = _in->sbumpc ()) != std::char_traits <char>::eof ())
538 {
539 if (c == '*' && _in->sgetc () == '/')
540 {
541 _in->sbumpc ();
542 closed = true;
543 break;
544 }
545 }
546
547 if (!closed)
548 {
549 return -1;
550 }
551 }
552 else if (c == '/')
553 {
554 _in->sbumpc ();
555
556 while ((c = _in->sbumpc ()) != std::char_traits <char>::eof () && c != '\n')
557 {
558 }
559 }
560 else
561 {
562 return -1;
563 }
564 }
565
566 return 0;
567 }
568
573 template <bool S = Seekable>
574 inline typename std::enable_if <S, ViewPos>::type tell () const noexcept
575 {
576 return _in->pubseekoff (0, std::ios::cur, std::ios::in);
577 }
578
583 template <bool S = Seekable>
584 inline typename std::enable_if <S, void>::type seek (ViewPos pos) noexcept
585 {
586 _in->pubseekpos (pos, std::ios::in);
587 }
588
589 private:
591 std::streambuf* _in;
592 };
593
597 using StringStreamView = BasicStreamView <true>;
598
602 using FileStreamView = BasicStreamView <true>;
603
607 using StreamView = BasicStreamView <false>;
608
613 template <typename ViewType>
614 struct is_seekable : std::false_type {};
615
619 template <>
620 struct is_seekable <StringView> : std::true_type {};
621
625 template <>
626 struct is_seekable <BasicStreamView <true>> : std::true_type {};
627
631 template <typename ViewType, bool Seekable = is_seekable <ViewType>::value>
633
637 template <typename ViewType>
638 class BufferingView <ViewType, true>
639 {
640 public:
645 explicit BufferingView (ViewType& view)
646 : _view (view)
647 , _beg (view.tell ())
648 {
649 }
650
655 inline int peek () const noexcept
656 {
657 return _view.peek ();
658 }
659
664 inline int get () noexcept
665 {
666 return _view.get ();
667 }
668
674 inline bool getIf (char expected) noexcept
675 {
676 return _view.getIf (expected);
677 }
678
684 inline bool getIfNoCase (char expected) noexcept
685 {
686 return _view.getIfNoCase (expected);
687 }
688
693 inline void snapshot (std::string& out)
694 {
695 size_t len = _view.tell () - _beg;
696 out.resize (len);
697
698 _view.seek (_beg);
699 _view.read (&out[0], len);
700 }
701
706 inline void consume (std::string& out)
707 {
708 snapshot (out);
709 _beg = _view.tell ();
710 }
711
712 private:
714 ViewType& _view;
715
717 typename ViewType::ViewPos _beg;
718 };
719
723 template <typename ViewType>
724 class BufferingView <ViewType, false>
725 {
726 public:
731 explicit BufferingView (ViewType& view)
732 : _view (view)
733 {
734 static thread_local std::vector <char> buffer;
735 buffer.clear ();
736 buffer.reserve (32);
737 _buf = &buffer;
738 }
739
744 inline int peek () const noexcept
745 {
746 return _view.peek ();
747 }
748
753 inline int get () noexcept
754 {
755 const int c = _view.get ();
756 if (JOIN_LIKELY (c != std::char_traits <char>::eof ()))
757 {
758 _buf->push_back (static_cast <char> (c));
759 }
760 return c;
761 }
762
768 inline bool getIf (char expected) noexcept
769 {
770 if (_view.peek () == static_cast <int> (static_cast <unsigned char> (expected)))
771 {
772 _buf->push_back (static_cast <char> (_view.get ()));
773 return true;
774 }
775 return false;
776 }
777
783 inline bool getIfNoCase (char expected) noexcept
784 {
785 const int c = _view.peek ();
786 if (JOIN_LIKELY (c != std::char_traits <char>::eof ()))
787 {
788 if ((static_cast <char> (c) | 32) == (expected | 32))
789 {
790 _buf->push_back (static_cast <char> (_view.get ()));
791 return true;
792 }
793 }
794 return false;
795 }
796
801 inline void snapshot (std::string& out)
802 {
803 out.assign (_buf->data (), _buf->size ());
804 }
805
810 inline void consume (std::string& out)
811 {
812 snapshot (out);
813 _buf->clear ();
814 }
815
816 private:
818 ViewType& _view;
819
821 std::vector <char>* _buf = nullptr;
822 };
823}
824
825#endif
basic stream view.
Definition view.hpp:368
int get() noexcept
extracts character.
Definition view.hpp:425
std::enable_if< S, void >::type seek(ViewPos pos) noexcept
seek to the specified position.
Definition view.hpp:584
BasicStreamView(const BasicStreamView &other)=delete
copy constructor.
BasicStreamView & operator=(BasicStreamView &&other)=delete
move assignment.
size_t read(char *buf, size_t count) noexcept
read characters.
Definition view.hpp:470
BasicStreamView(BasicStreamView &&other)=delete
move constructor.
void readUntilEscaped(std::string &out) noexcept
read characters until escaped.
Definition view.hpp:479
std::enable_if< S, ViewPos >::type tell() const noexcept
get input position indicator.
Definition view.hpp:574
std::streampos ViewPos
Definition view.hpp:370
~BasicStreamView()=default
destroy instance.
int skipWhitespaces() noexcept
skip whitespaces.
Definition view.hpp:493
int skipWhitespacesAndComments() noexcept
skip whitespaces and comments.
Definition view.hpp:508
int peek() const noexcept
get character without extracting it.
Definition view.hpp:416
bool getIf(char expected) noexcept
extracts expected character.
Definition view.hpp:435
BasicStreamView & operator=(const BasicStreamView &other)=delete
copy assignment.
BasicStreamView(std::istream &in)
default constructor.
Definition view.hpp:376
bool getIfNoCase(char expected) noexcept
extracts expected character (case insensitive, ASCII-only).
Definition view.hpp:450
BufferingView(ViewType &view)
default constructor.
Definition view.hpp:731
bool getIfNoCase(char expected) noexcept
extracts expected character (case insensitive, ASCII-only).
Definition view.hpp:783
void consume(std::string &out)
consume buffered data.
Definition view.hpp:810
void snapshot(std::string &out)
get snapshot.
Definition view.hpp:801
int peek() const noexcept
get character without extracting it.
Definition view.hpp:744
bool getIf(char expected) noexcept
extracts expected character.
Definition view.hpp:768
int get() noexcept
extracts character.
Definition view.hpp:753
int get() noexcept
extracts character.
Definition view.hpp:664
void consume(std::string &out)
consume buffered data.
Definition view.hpp:706
int peek() const noexcept
get character without extracting it.
Definition view.hpp:655
void snapshot(std::string &out)
get snapshot.
Definition view.hpp:693
bool getIfNoCase(char expected) noexcept
extracts expected character (case insensitive, ASCII-only).
Definition view.hpp:684
BufferingView(ViewType &view)
default constructor.
Definition view.hpp:645
bool getIf(char expected) noexcept
extracts expected character.
Definition view.hpp:674
buffering view adapter
Definition view.hpp:632
string view.
Definition view.hpp:78
bool getIfNoCase(char expected) noexcept
extracts expected character (case insensitive, ASCII-only).
Definition view.hpp:194
void readUntilEscaped(std::string &out) noexcept
read characters until escaped.
Definition view.hpp:227
StringView & operator=(const StringView &other)=default
copy assignment.
StringView(const StringView &other)=default
copy constructor.
StringView(const char *in)
default constructor.
Definition view.hpp:110
const char * ViewPos
Definition view.hpp:80
constexpr StringView(const char *in, size_t count)
default constructor.
Definition view.hpp:87
StringView(StringView &&other)=default
move constructor.
int peek() const noexcept
get character without extracting it.
Definition view.hpp:152
ViewPos tell() const noexcept
get input position indicator.
Definition view.hpp:327
~StringView()=default
destroy instance.
void seek(ViewPos pos) noexcept
seek to the specified position.
Definition view.hpp:336
size_t read(char *buf, size_t count) noexcept
read characters.
Definition view.hpp:214
int skipWhitespaces() noexcept
skip whitespaces.
Definition view.hpp:246
StringView & operator=(StringView &&other)=default
move assignment.
int skipWhitespacesAndComments() noexcept
skip whitespaces and comments.
Definition view.hpp:265
int get() noexcept
extracts character.
Definition view.hpp:165
bool getIf(char expected) noexcept
extracts expected character.
Definition view.hpp:179
constexpr StringView(const char *first, const char *last)
default constructor.
Definition view.hpp:99
constexpr WhitespaceTable whitespaceLookup
Definition view.hpp:71
constexpr EscapedTable escapedLookup
Definition view.hpp:56
Definition acceptor.hpp:32
Definition error.hpp:106
Definition view.hpp:45
uint8_t data[256]
Definition view.hpp:46
constexpr EscapedTable()
Definition view.hpp:48
Definition view.hpp:59
constexpr WhitespaceTable()
Definition view.hpp:62
uint8_t data[256]
Definition view.hpp:60
trait to determine if a view type is seekable.
Definition view.hpp:614
#define JOIN_LIKELY(x)
Definition utils.hpp:46