FastLED 3.9.15
Loading...
Searching...
No Matches
istream.cpp
Go to the documentation of this file.
1#include "istream.h"
2#include "fl/math.h"
4//#include <stddef.h>
5// <cstdlib> not available on AVR platforms like Arduino UNO
6// We implement custom integer parsing functions instead
7
8#include "fl/math_macros.h"
9
10namespace fl {
11
12namespace {
13 // Helper function to check if a character is a digit
14 inline bool isDigit(char c) {
15 return c >= '0' && c <= '9';
16 }
17
18 // Helper function to check if a character is whitespace
19 inline bool isSpace(char c) {
20 return c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == '\f' || c == '\v';
21 }
22
23 // Custom integer parsing function for signed 32-bit integers
24 bool parse_i32(const char* str, fl::i32& result) {
25 if (!str) return false;
26
27 // Skip leading whitespace
28 while (*str && isSpace(*str)) {
29 str++;
30 }
31
32 if (*str == '\0') return false;
33
34 bool negative = false;
35 if (*str == '-') {
36 negative = true;
37 str++;
38 } else if (*str == '+') {
39 str++;
40 }
41
42 if (*str == '\0' || !isDigit(*str)) return false;
43
44 fl::u32 value = 0;
45 const fl::u32 max_div_10 = 214748364U; // INT32_MAX / 10
46 const fl::u32 max_mod_10 = 7U; // INT32_MAX % 10
47 const fl::u32 max_neg_div_10 = 214748364U; // -INT32_MIN / 10
48 const fl::u32 max_neg_mod_10 = 8U; // -INT32_MIN % 10
49
50 while (*str && isDigit(*str)) {
51 fl::u32 digit = *str - '0';
52
53 // Check for overflow
54 if (negative) {
55 if (value > max_neg_div_10 || (value == max_neg_div_10 && digit > max_neg_mod_10)) {
56 return false; // Overflow
57 }
58 } else {
59 if (value > max_div_10 || (value == max_div_10 && digit > max_mod_10)) {
60 return false; // Overflow
61 }
62 }
63
64 value = value * 10 + digit;
65 str++;
66 }
67
68 // Check if we stopped at a non-digit character (should be end of string for valid parse)
69 if (*str != '\0') return false;
70
71 if (negative) {
72 result = -static_cast<fl::i32>(value);
73 } else {
74 result = static_cast<fl::i32>(value);
75 }
76
77 return true;
78 }
79
80 // Custom integer parsing function for unsigned 32-bit integers
81 bool parse_u32(const char* str, fl::u32& result) {
82 if (!str) return false;
83
84 // Skip leading whitespace
85 while (*str && isSpace(*str)) {
86 str++;
87 }
88
89 if (*str == '\0') return false;
90
91 // Optional '+' sign (no '-' for unsigned)
92 if (*str == '+') {
93 str++;
94 } else if (*str == '-') {
95 return false; // Negative not allowed for unsigned
96 }
97
98 if (*str == '\0' || !isDigit(*str)) return false;
99
100 fl::u32 value = 0;
101 const fl::u32 max_div_10 = 429496729U; // UINT32_MAX / 10
102 const fl::u32 max_mod_10 = 5U; // UINT32_MAX % 10
103
104 while (*str && isDigit(*str)) {
105 fl::u32 digit = *str - '0';
106
107 // Check for overflow
108 if (value > max_div_10 || (value == max_div_10 && digit > max_mod_10)) {
109 return false; // Overflow
110 }
111
112 value = value * 10 + digit;
113 str++;
114 }
115
116 // Check if we stopped at a non-digit character (should be end of string for valid parse)
117 if (*str != '\0') return false;
118
119 result = value;
120 return true;
121 }
122}
123
125// Global cin instance (stub that conditionally delegates)
127
128// Function to get singleton instance of istream_real (for better linker elimination)
130 // Local static instance - only constructed when first called
131 // This allows the linker to eliminate it if never referenced
132 static istream_real instance;
133 return instance;
134}
135
137 // If we have no more data available and no buffered data, we're at EOF
138 if (pos_ >= buffer_len_ && fl::available() == 0) {
139 return false;
140 }
141
142 // Read characters until newline or no more data
143 buffer_len_ = 0;
144 while (fl::available() > 0 && buffer_len_ < BUFFER_SIZE - 1) {
145 int c = fl::read();
146 if (c == -1) break;
147 if (c == '\n') break;
148 if (c == '\r') continue; // Skip carriage return
149 buffer_[buffer_len_++] = static_cast<char>(c);
150 }
151
152 // Null terminate the buffer
153 buffer_[buffer_len_] = '\0';
154 pos_ = 0;
155 return true;
156}
157
159 while (pos_ < buffer_len_ &&
160 (buffer_[pos_] == ' ' || buffer_[pos_] == '\t' ||
161 buffer_[pos_] == '\n' || buffer_[pos_] == '\r')) {
162 pos_++;
163 }
164
165 // If we've consumed all buffer and there's more input, read more
166 if (pos_ >= buffer_len_ && fl::available() > 0) {
167 if (readLine()) {
169 }
170 }
171}
172
173bool istream_real::readToken(string& token) {
175
176 if (pos_ >= buffer_len_ && fl::available() == 0) {
177 failed_ = true;
178 return false;
179 }
180
181 // If buffer is empty but data is available, read a line
182 if (pos_ >= buffer_len_ && fl::available() > 0) {
183 if (!readLine()) {
184 failed_ = true;
185 return false;
186 }
188 }
189
190 // Read until whitespace or end of buffer
191 token.clear();
192 while (pos_ < buffer_len_ &&
193 buffer_[pos_] != ' ' && buffer_[pos_] != '\t' &&
194 buffer_[pos_] != '\n' && buffer_[pos_] != '\r') {
195 // Explicitly append as a character string to avoid fl::u8->number conversion
196 char ch[2] = {buffer_[pos_], '\0'};
197 token.append(ch, 1);
198 pos_++;
199 }
200
201 return !token.empty();
202}
203
205 if (!readToken(str)) {
206 failed_ = true;
207 }
208 return *this;
209}
210
213
214 if (pos_ >= buffer_len_ && fl::available() > 0) {
215 if (!readLine()) {
216 failed_ = true;
217 return *this;
218 }
220 }
221
222 if (pos_ < buffer_len_) {
223 c = buffer_[pos_];
224 pos_++;
225 } else {
226 failed_ = true;
227 }
228 return *this;
229}
230
232 string token;
233 if (readToken(token)) {
234 fl::i32 temp;
235 if (parse_i32(token.c_str(), temp) && temp >= -128 && temp <= 127) {
236 n = static_cast<fl::i8>(temp);
237 } else {
238 failed_ = true;
239 }
240 } else {
241 failed_ = true;
242 }
243 return *this;
244}
245
247 string token;
248 if (readToken(token)) {
249 fl::u32 temp;
250 if (parse_u32(token.c_str(), temp) && temp <= 255) {
251 n = static_cast<fl::u8>(temp);
252 } else {
253 failed_ = true;
254 }
255 } else {
256 failed_ = true;
257 }
258 return *this;
259}
260
262 string token;
263 if (readToken(token)) {
264 fl::i32 temp;
265 if (parse_i32(token.c_str(), temp) && temp >= -32768 && temp <= 32767) {
266 n = static_cast<fl::i16>(temp);
267 } else {
268 failed_ = true;
269 }
270 } else {
271 failed_ = true;
272 }
273 return *this;
274}
275
276// u16 operator>> removed - now handled by template in header
277
279 string token;
280 if (readToken(token)) {
281 if (!parse_i32(token.c_str(), n)) {
282 failed_ = true;
283 }
284 } else {
285 failed_ = true;
286 }
287 return *this;
288}
289
291 string token;
292 if (readToken(token)) {
293 if (!parse_u32(token.c_str(), n)) {
294 failed_ = true;
295 }
296 } else {
297 failed_ = true;
298 }
299 return *this;
300}
301
303 string token;
304 if (readToken(token)) {
305 // Use the existing toFloat() method
306 f = token.toFloat();
307 // Check if parsing was successful by checking for valid float
308 // toFloat() returns 0.0f for invalid input, but we need to distinguish
309 // between actual 0.0f and parse failure
310 if (ALMOST_EQUAL_FLOAT(f, 0.0f) && token != "0" && token != "0.0" && token != "0." && token.find("0") != 0) {
311 failed_ = true;
312 }
313 } else {
314 failed_ = true;
315 }
316 return *this;
317}
318
320 string token;
321 if (readToken(token)) {
322 // Use the existing toFloat() method
323 float f = token.toFloat();
324 d = static_cast<double>(f);
325 // Check if parsing was successful (same logic as float)
326 if (ALMOST_EQUAL_FLOAT(f, 0.0f) && token != "0" && token != "0.0" && token != "0." && token.find("0") != 0) {
327 failed_ = true;
328 }
329 } else {
330 failed_ = true;
331 }
332 return *this;
333}
334
335// fl::size operator>> removed - now handled by template in header
336
338 str.clear();
339
340 // Read from current buffer position to end
341 while (pos_ < buffer_len_) {
342 if (buffer_[pos_] == '\n') {
343 pos_++; // Consume the newline
344 return *this;
345 }
346 // Explicitly append as a character string to avoid fl::u8->number conversion
347 char ch[2] = {buffer_[pos_], '\0'};
348 str.append(ch, 1);
349 pos_++;
350 }
351
352 // If we need more data, read a new line
353 if (fl::available() > 0) {
354 // Read more characters until newline
355 while (fl::available() > 0) {
356 int c = fl::read();
357 if (c == -1) break;
358 if (c == '\n') break;
359 if (c == '\r') continue; // Skip carriage return
360 // Explicitly append as a character string to avoid fl::u8->number conversion
361 char ch[2] = {static_cast<char>(c), '\0'};
362 str.append(ch, 1);
363 }
364 }
365
366 return *this;
367}
368
370 if (pos_ >= buffer_len_ && fl::available() > 0) {
371 if (!readLine()) {
372 return -1;
373 }
374 }
375
376 if (pos_ < buffer_len_) {
377 return static_cast<int>(static_cast<unsigned char>(buffer_[pos_++]));
378 }
379
380 // Try to read directly from input if buffer is empty
381 return fl::read();
382}
383
385 if (pos_ > 0) {
386 pos_--;
387 buffer_[pos_] = c;
388 } else {
389 // Insert at beginning of buffer - shift existing data
390 if (buffer_len_ < BUFFER_SIZE - 1) {
391 for (fl::size i = buffer_len_; i > 0; --i) {
392 buffer_[i] = buffer_[i-1];
393 }
394 buffer_[0] = c;
395 buffer_len_++;
396 buffer_[buffer_len_] = '\0';
397 }
398 }
399 return *this;
400}
401
403 if (pos_ >= buffer_len_ && fl::available() > 0) {
404 if (!readLine()) {
405 return -1;
406 }
407 }
408
409 if (pos_ < buffer_len_) {
410 return static_cast<int>(static_cast<unsigned char>(buffer_[pos_]));
411 }
412
413 return -1;
414}
415
416} // namespace fl
bool empty() const
Definition str.h:350
fl::size find(const char &value) const
Definition str.h:408
const char * c_str() const
Definition str.h:326
void clear(bool freeMemory=false)
Definition str.h:398
float toFloat() const
Definition str.h:586
void skipWhitespace()
Definition istream.cpp:158
fl::size buffer_len_
Definition istream.h:31
istream_real & putback(char c)
Definition istream.cpp:384
char buffer_[BUFFER_SIZE]
Definition istream.h:30
fl::size pos_
Definition istream.h:32
static const fl::size BUFFER_SIZE
Definition istream.h:29
istream_real & operator>>(string &str)
Definition istream.cpp:204
istream_real()=default
bool readToken(string &token)
Definition istream.cpp:173
istream_real & getline(string &str)
Definition istream.cpp:337
Result type for promise operations.
string & append(const BitsetFixed< N > &bs)
Definition str.h:675
#define FL_DISABLE_WARNING_GLOBAL_CONSTRUCTORS
#define ALMOST_EQUAL_FLOAT(a, b)
Definition math_macros.h:63
bool parse_u32(const char *str, fl::u32 &result)
Definition istream.cpp:81
bool parse_i32(const char *str, fl::i32 &result)
Definition istream.cpp:24
int available()
Definition io.cpp:117
unsigned char u8
Definition int.h:17
int read()
Definition io.cpp:148
FL_DISABLE_WARNING_GLOBAL_CONSTRUCTORS istream cin
Definition istream.cpp:126
istream_real & cin_real()
Definition istream.cpp:129
signed char i8
Definition int.h:16
IMPORTANT!
Definition crgb.h:20