Line data Source code
1 : /***************************************************************************\
2 : * Name : input stream *
3 : * Description : char stream used for parsing proto files *
4 : * Author : antonin.kriz@gmail.com *
5 : * ------------------------------------------------------------------------- *
6 : * This is free software; you can redistribute it and/or modify it under the *
7 : * terms of the MIT license. A copy of the license can be found in the file *
8 : * "LICENSE" at the root of this distribution. *
9 : \***************************************************************************/
10 :
11 : #pragma once
12 : #include <algorithm>
13 : #include <cassert>
14 : #include <cctype>
15 : #include <stdexcept>
16 : #include <string>
17 : #include <string_view>
18 :
19 : namespace spb
20 : {
21 :
22 : struct char_stream
23 : {
24 : private:
25 : //- start of the stream
26 : const char * p_start = nullptr;
27 : //- current position in the stream
28 : const char * p_begin = nullptr;
29 : //- end of the stream
30 : const char * p_end = nullptr;
31 : //- current char
32 : char m_current = { };
33 :
34 : /**
35 : * @brief gets the next char from the stream
36 : *
37 : * @param skip_white_space if true, skip white spaces
38 : */
39 63413 : void update_current( bool skip_white_space ) noexcept
40 : {
41 90582 : while( p_begin < p_end )
42 : {
43 90568 : m_current = *p_begin;
44 90568 : if( !skip_white_space || isspace( m_current ) == 0 )
45 : {
46 63399 : return;
47 : }
48 27169 : p_begin += 1;
49 : }
50 14 : m_current = { };
51 : }
52 :
53 : public:
54 14 : explicit char_stream( std::string_view content ) noexcept
55 14 : : p_start( content.data( ) )
56 14 : , p_begin( p_start )
57 14 : , p_end( p_begin + content.size( ) )
58 : {
59 14 : update_current( true );
60 14 : }
61 :
62 95790 : [[nodiscard]] auto begin( ) const noexcept -> const char *
63 : {
64 95790 : return p_begin;
65 : }
66 :
67 70464 : [[nodiscard]] auto end( ) const noexcept -> const char *
68 : {
69 70464 : return p_end;
70 : }
71 :
72 420 : [[nodiscard]] auto empty( ) const noexcept -> bool
73 : {
74 420 : return p_end <= p_begin;
75 : }
76 :
77 75318 : [[nodiscard]] auto current_char( ) const noexcept -> char
78 : {
79 75318 : return m_current;
80 : }
81 :
82 : /**
83 : * @brief consumes `current char` if its equal to c
84 : *
85 : * @param c consumed char
86 : * @return true if char was consumed
87 : */
88 13778 : [[nodiscard]] auto consume( char c ) noexcept -> bool
89 : {
90 13778 : if( auto current = current_char( ); current == c )
91 : {
92 3798 : consume_current_char( true );
93 3798 : return true;
94 : }
95 9980 : return false;
96 : }
97 :
98 : /**
99 : * @brief consumes an `token`
100 : *
101 : * @param token consumed `token` (whole word)
102 : * @return true if `token` was consumed
103 : */
104 13384 : auto consume( std::string_view token ) noexcept -> bool
105 : {
106 13384 : const auto state = *this;
107 :
108 13384 : if( content( ).starts_with( token ) )
109 : {
110 2739 : p_begin += token.size( );
111 2739 : update_current( false );
112 2739 : auto next = current_char( );
113 2739 : if( isspace( next ) || !isalnum( next ) )
114 : {
115 2038 : update_current( true );
116 2038 : return true;
117 : }
118 701 : *this = state;
119 : }
120 11346 : return false;
121 : }
122 :
123 48349 : void consume_current_char( bool skip_white_space ) noexcept
124 : {
125 48349 : if( begin( ) < end( ) )
126 : {
127 48349 : p_begin += 1;
128 48349 : update_current( skip_white_space );
129 : }
130 48349 : }
131 :
132 : /**
133 : * @brief trim current spaces
134 : *
135 : */
136 5839 : void consume_space( ) noexcept
137 : {
138 5839 : update_current( true );
139 5839 : }
140 :
141 4434 : void skip_to( const char * ptr ) noexcept
142 : {
143 4434 : assert( ptr >= p_start && ptr <= end( ) );
144 4434 : p_begin = ptr;
145 4434 : update_current( true );
146 4434 : }
147 :
148 15983 : [[nodiscard]] auto content( ) const noexcept -> std::string_view
149 : {
150 15983 : return { begin( ), size_t( end( ) - begin( ) ) };
151 : }
152 :
153 0 : [[nodiscard]] auto current_line( ) const noexcept -> size_t
154 : {
155 0 : return std::count( p_start, p_begin, '\n' ) + 1;
156 : }
157 0 : [[nodiscard]] auto current_column( ) const noexcept -> size_t
158 : {
159 0 : auto parsed = std::string_view( p_start, p_begin - p_start );
160 :
161 0 : if( auto p = parsed.rfind( '\n' ); p != std::string_view::npos )
162 : {
163 0 : parsed.remove_prefix( p );
164 : }
165 0 : return std::max< size_t >( parsed.size( ), 1 );
166 : }
167 0 : [[noreturn]] void throw_parse_error( std::string_view message )
168 : {
169 0 : throw std::runtime_error( std::to_string( current_line( ) ) + ":" +
170 0 : std::to_string( current_column( ) ) + ": " +
171 0 : std::string( message ) );
172 : }
173 : };
174 : }// namespace spb
|