NovaSVG 0.10.0
A header-only SVG library
Loading...
Searching...
No Matches
svgparserutils.h
Go to the documentation of this file.
1#ifndef NOVASVG_SVGPARSERUTILS_H
2#define NOVASVG_SVGPARSERUTILS_H
3
4#include <cmath>
5#include <string_view>
6#include <limits>
7
8namespace novasvg {
9
10constexpr bool IS_NUM(int cc) { return cc >= '0' && cc <= '9'; }
11constexpr bool IS_ALPHA(int cc) { return (cc >= 'a' && cc <= 'z') || (cc >= 'A' && cc <= 'Z'); }
12constexpr bool IS_WS(int cc) { return cc == ' ' || cc == '\t' || cc == '\n' || cc == '\r'; }
13
14constexpr void stripLeadingSpaces(std::string_view& input)
15{
16 while(!input.empty() && IS_WS(input.front())) {
17 input.remove_prefix(1);
18 }
19}
20
21constexpr void stripTrailingSpaces(std::string_view& input)
22{
23 while(!input.empty() && IS_WS(input.back())) {
24 input.remove_suffix(1);
25 }
26}
27
28constexpr void stripLeadingAndTrailingSpaces(std::string_view& input)
29{
30 stripLeadingSpaces(input);
32}
33
34constexpr bool skipOptionalSpaces(std::string_view& input)
35{
36 while(!input.empty() && IS_WS(input.front()))
37 input.remove_prefix(1);
38 return !input.empty();
39}
40
41constexpr bool skipOptionalSpacesOrDelimiter(std::string_view& input, char delimiter)
42{
43 if(!input.empty() && !IS_WS(input.front()) && delimiter != input.front())
44 return false;
45 if(skipOptionalSpaces(input)) {
46 if(delimiter == input.front()) {
47 input.remove_prefix(1);
48 skipOptionalSpaces(input);
49 }
50 }
51
52 return !input.empty();
53}
54
55constexpr bool skipOptionalSpacesOrComma(std::string_view& input)
56{
57 return skipOptionalSpacesOrDelimiter(input, ',');
58}
59
60constexpr bool skipDelimiterAndOptionalSpaces(std::string_view& input, char delimiter)
61{
62 if(!input.empty() && input.front() == delimiter) {
63 input.remove_prefix(1);
64 skipOptionalSpaces(input);
65 return true;
66 }
67
68 return false;
69}
70
71constexpr bool skipDelimiter(std::string_view& input, char delimiter)
72{
73 if(!input.empty() && input.front() == delimiter) {
74 input.remove_prefix(1);
75 return true;
76 }
77
78 return false;
79}
80
81constexpr bool skipString(std::string_view& input, std::string_view value)
82{
83 if(input.size() >= value.size() && value == input.substr(0, value.size())) {
84 input.remove_prefix(value.size());
85 return true;
86 }
87
88 return false;
89}
90
91constexpr bool isIntegralDigit(char ch, int base)
92{
93 if(IS_NUM(ch))
94 return ch - '0' < base;
95 if(IS_ALPHA(ch))
96 return (ch >= 'a' && ch < 'a' + base - 10) || (ch >= 'A' && ch < 'A' + base - 10);
97 return false;
98}
99
100constexpr int toIntegralDigit(char ch)
101{
102 if(IS_NUM(ch))
103 return ch - '0';
104 if(ch >= 'a')
105 return ch - 'a' + 10;
106 return ch - 'A' + 10;
107}
108
109template<typename T>
110inline bool parseInteger(std::string_view& input, T& integer, int base = 10)
111{
112 constexpr bool isSigned = std::numeric_limits<T>::is_signed;
113 constexpr T intMax = std::numeric_limits<T>::max();
114 const T maxMultiplier = intMax / static_cast<T>(base);
115
116 T value = 0;
117 bool isNegative = false;
118
119 if(!input.empty() && input.front() == '+') {
120 input.remove_prefix(1);
121 } else if(!input.empty() && isSigned && input.front() == '-') {
122 input.remove_prefix(1);
123 isNegative = true;
124 }
125
126 if(input.empty() || !isIntegralDigit(input.front(), base))
127 return false;
128 do {
129 const int digitValue = toIntegralDigit(input.front());
130 if(value > maxMultiplier || (value == maxMultiplier && static_cast<T>(digitValue) > (intMax % static_cast<T>(base)) + isNegative))
131 return false;
132 value = static_cast<T>(base) * value + static_cast<T>(digitValue);
133 input.remove_prefix(1);
134 } while(!input.empty() && isIntegralDigit(input.front(), base));
135
136 using SignedType = typename std::make_signed<T>::type;
137 if(isNegative)
138 integer = -static_cast<SignedType>(value);
139 else
140 integer = value;
141 return true;
142}
143
144template<typename T>
145inline bool parseNumber(std::string_view& input, T& number)
146{
147 constexpr T maxValue = std::numeric_limits<T>::max();
148 T integer = 0;
149 T fraction = 0;
150 int exponent = 0;
151 int sign = 1;
152 int expsign = 1;
153
154 if(!input.empty() && input.front() == '+') {
155 input.remove_prefix(1);
156 } else if(!input.empty() && input.front() == '-') {
157 input.remove_prefix(1);
158 sign = -1;
159 }
160
161 if(input.empty() || (!IS_NUM(input.front()) && input.front() != '.'))
162 return false;
163 if(IS_NUM(input.front())) {
164 do {
165 integer = static_cast<T>(10) * integer + (input.front() - '0');
166 input.remove_prefix(1);
167 } while(!input.empty() && IS_NUM(input.front()));
168 }
169
170 if(!input.empty() && input.front() == '.') {
171 input.remove_prefix(1);
172 if(input.empty() || !IS_NUM(input.front()))
173 return false;
174 T divisor = static_cast<T>(1);
175 do {
176 fraction = static_cast<T>(10) * fraction + (input.front() - '0');
177 divisor *= static_cast<T>(10);
178 input.remove_prefix(1);
179 } while(!input.empty() && IS_NUM(input.front()));
180 fraction /= divisor;
181 }
182
183 if(input.size() > 1 && (input[0] == 'e' || input[0] == 'E')
184 && (input[1] != 'x' && input[1] != 'm'))
185 {
186 input.remove_prefix(1);
187 if(!input.empty() && input.front() == '+')
188 input.remove_prefix(1);
189 else if(!input.empty() && input.front() == '-') {
190 input.remove_prefix(1);
191 expsign = -1;
192 }
193
194 if(input.empty() || !IS_NUM(input.front()))
195 return false;
196 do {
197 exponent = 10 * exponent + (input.front() - '0');
198 input.remove_prefix(1);
199 } while(!input.empty() && IS_NUM(input.front()));
200 }
201
202 number = sign * (integer + fraction);
203 if(exponent)
204 number *= static_cast<T>(std::pow(10.0, expsign * exponent));
205 return number >= -maxValue && number <= maxValue;
206}
207
208} // namespace novasvg
209
210#endif // NOVASVG_SVGPARSERUTILS_H
Main namespace for the NovaSVG library.
Definition bitmap.h:23
constexpr bool IS_WS(int cc)
constexpr int toIntegralDigit(char ch)
bool parseNumber(std::string_view &input, T &number)
bool parseInteger(std::string_view &input, T &integer, int base=10)
constexpr bool skipDelimiter(std::string_view &input, char delimiter)
constexpr bool skipString(std::string_view &input, std::string_view value)
constexpr bool skipDelimiterAndOptionalSpaces(std::string_view &input, char delimiter)
constexpr bool skipOptionalSpacesOrComma(std::string_view &input)
constexpr bool IS_NUM(int cc)
constexpr void stripLeadingAndTrailingSpaces(std::string_view &input)
constexpr bool IS_ALPHA(int cc)
constexpr bool isIntegralDigit(char ch, int base)
constexpr void stripLeadingSpaces(std::string_view &input)
constexpr bool skipOptionalSpaces(std::string_view &input)
constexpr bool skipOptionalSpacesOrDelimiter(std::string_view &input, char delimiter)
constexpr void stripTrailingSpaces(std::string_view &input)