source: mainline/uspace/lib/cpp/include/impl/istream.hpp@ 25cc4a5

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 25cc4a5 was 25cc4a5, checked in by Dzejrou <dzejrou@…>, 7 years ago

cpp: fixed whitespace testing in std::basic_istream::sentry

  • Property mode set to 100644
File size: 20.9 KB
Line 
1/*
2 * Copyright (c) 2017 Jaroslav Jindrak
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#ifndef LIBCPP_ISTREAM
30#define LIBCPP_ISTREAM
31
32#include <ios>
33#include <iosfwd>
34#include <limits>
35#include <locale>
36#include <ostream>
37#include <utility>
38
39namespace std
40{
41
42 /**
43 * 27.7.2.1, class template basic_stream:
44 */
45
46 template<class Char, class Traits>
47 class basic_istream: virtual public basic_ios<Char, Traits>
48 {
49 public:
50 using traits_type = Traits;
51 using char_type = Char;
52 using int_type = typename traits_type::int_type;
53 using pos_type = typename traits_type::pos_type;
54 using off_type = typename traits_type::off_type;
55
56 /**
57 * 27.7.2.1.1, constructor/destructor:
58 */
59
60 explicit basic_istream(basic_streambuf<Char, Traits>* sb)
61 : gcount_{0}
62 {
63 basic_ios<Char, Traits>::init(sb);
64 }
65
66 virtual ~basic_istream()
67 { /* DUMMY BODY */ }
68
69 /**
70 * 27.7.2.1.3, prefix/suffix:
71 */
72
73 class sentry
74 {
75 public:
76 explicit sentry(basic_istream<Char, Traits>& is, bool noskipws = false)
77 : ok_{false}
78 {
79 if (!is.good())
80 is.setstate(ios_base::failbit);
81 else
82 {
83 if (is.tie())
84 is.tie()->flush();
85
86 if (!noskipws && ((is.flags() & ios_base::skipws) != 0))
87 {
88 const auto& ct = use_facet<ctype<Char>>(is.getloc());
89 while (true)
90 {
91 auto i = is.rdbuf()->sgetc();
92 if (Traits::eq_int_type(i, Traits::eof()))
93 {
94 is.setstate(ios_base::failbit | ios_base::eofbit);
95 break;
96 }
97
98 auto c = Traits::to_char_type(i);
99 if (!ct.is(ctype_base::space, c))
100 break;
101 else
102 is.rdbuf()->sbumpc();
103 }
104 }
105 }
106
107 if (is.good())
108 ok_ = true;
109 }
110
111 ~sentry() = default;
112
113 explicit operator bool() const
114 {
115 return ok_;
116 }
117
118 sentry(const sentry&) = delete;
119 sentry& operator=(const sentry&) = delete;
120
121 private:
122 using traits_type = Traits;
123 bool ok_;
124 };
125
126 /**
127 * 27.7.2.2, formatted input:
128 */
129
130 basic_istream<Char, Traits>& operator>>(
131 basic_istream<Char, Traits>& (*pf)(basic_istream<Char, Traits>&)
132 )
133 {
134 return pf(*this);
135 }
136
137 basic_istream<Char, Traits>& operator>>(
138 basic_ios<Char, Traits>& (*pf)(basic_ios<Char, Traits>&)
139 )
140 {
141 pf(*this);
142
143 return *this;
144 }
145
146 basic_istream<Char, Traits>& operator>>(
147 ios_base& (*pf)(ios_base&)
148 )
149 {
150 pf(*this);
151
152 return *this;
153 }
154
155 basic_istream<Char, Traits>& operator>>(bool& x)
156 {
157 // TODO: implement
158 }
159
160 basic_istream<Char, Traits>& operator>>(short& x)
161 {
162 // TODO: implement
163 }
164
165 basic_istream<Char, Traits>& operator>>(unsigned short& x)
166 {
167 // TODO: implement
168 }
169
170 basic_istream<Char, Traits>& operator>>(int& x)
171 {
172 // TODO: implement
173 }
174
175 basic_istream<Char, Traits>& operator>>(unsigned int& x)
176 {
177 // TODO: implement
178 }
179
180 basic_istream<Char, Traits>& operator>>(long& x)
181 {
182 // TODO: implement
183 }
184
185 basic_istream<Char, Traits>& operator>>(unsigned long& x)
186 {
187 // TODO: implement
188 }
189
190 basic_istream<Char, Traits>& operator>>(long long& x)
191 {
192 // TODO: implement
193 }
194
195 basic_istream<Char, Traits>& operator>>(unsigned long long& x)
196 {
197 // TODO: implement
198 }
199
200 basic_istream<Char, Traits>& operator>>(float& x)
201 {
202 // TODO: implement
203 }
204
205 basic_istream<Char, Traits>& operator>>(double& x)
206 {
207 // TODO: implement
208 }
209
210 basic_istream<Char, Traits>& operator>>(long double& x)
211 {
212 // TODO: implement
213 }
214
215 basic_istream<Char, Traits>& operator>>(void*& p)
216 {
217 // TODO: implement
218 }
219
220 basic_istream<Char, Traits>& operator>>(basic_streambuf<Char, Traits>* sb)
221 {
222 // TODO: implement
223 }
224
225 /**
226 * 27.7.2.3, unformatted input:
227 * TODO: Once we have exceptions, implement
228 * 27.7.2.3 paragraph 1.
229 */
230
231 streamsize gcount() const
232 {
233 return gcount_;
234 }
235
236 int_type get()
237 {
238 gcount_ = 0;
239 sentry sen{*this, true};
240
241 if (sen)
242 {
243 auto res = this->rdbuf()->sbumpc();
244 if (!traits_type::eq_int_type(res, traits_type::eof()))
245 {
246 gcount_ = 1;
247 return res;
248 }
249
250 this->setstate(ios_base::failbit | ios_base::eofbit);
251 }
252
253 return traits_type::eof();
254 }
255
256 basic_istream<Char, Traits>& get(char_type& c)
257 {
258 auto res = get();
259 if (res != traits_type::eof())
260 c = traits_type::to_char_type(res);
261
262 return this;
263 }
264
265 basic_istream<Char, Traits>& get(char_type* s, streamsize n, char_type delim)
266 {
267 gcount_ = 0;
268 sentry sen{*this, true};
269
270 if (sen && n > 0)
271 {
272 while(gcount_ < n - 1)
273 {
274 auto c = this->rdbuf()->sbumpc();
275
276 if (traits_type::eq_int_type(c, traits_type::eof()))
277 {
278 this->setstate(ios_base::eofbit);
279 break;
280 }
281
282 s[gcount_++] = traits_type::to_char_type(c);
283
284 auto peek = traits_type::to_char_type(this->rdbuf()->sgetc());
285 if (traits_type::eq(peek, delim))
286 break;
287 }
288
289 if (gcount_ == 0)
290 this->setstate(ios_base::failbit);
291 s[n] = char_type{};
292 }
293
294 return *this;
295 }
296
297 basic_istream<Char, Traits>& get(char_type* s, streamsize n)
298 {
299 return get(s, n, this->widen('\n'));
300 }
301
302 basic_istream<Char, Traits>& get(basic_streambuf<Char, Traits>& sb)
303 {
304 get(sb, this->widen('\n'));
305 }
306
307 basic_istream<Char, Traits>& get(basic_streambuf<Char, Traits>& sb, char_type delim)
308 {
309 gcount_ = 0;
310 sentry sen{*this, true};
311
312 if (sen)
313 {
314 while (true)
315 {
316 auto i = this->rdbuf()->sgetc();
317 if (traits_type::eq_int_type(i, traits_type::eof()))
318 {
319 this->setstate(ios_base::eofbit);
320 break;
321 }
322
323 auto c = traits_type::to_char_type(i);
324 if (traits_type::eq(c, delim))
325 break;
326
327 auto insert_ret = sb.sputc(c);
328 if (traits_type::eq_int_type(insert_ret, traits_type::eof()))
329 break;
330
331 this->rdbuf()->sbumpc();
332 ++gcount_;
333 }
334
335 if (gcount_ == 0)
336 this->setstate(ios_base::failbit);
337 }
338
339 return *this;
340 }
341
342 basic_istream<Char, Traits>& getline(char_type* s, streamsize n)
343 {
344 return getline(s, n, this->widen('\n'));
345 }
346
347 basic_istream<Char, Traits>& getline(char_type* s, streamsize n, char_type delim)
348 {
349 gcount_ = 0;
350 sentry sen{*this, true};
351
352 if (sen)
353 {
354 while (true)
355 { // We have exactly specified order of checks, easier to do them in the body.
356 auto c = this->rdbuf()->sbumpc();
357
358 if (traits_type::eq_int_type(c, traits_type::eof()))
359 {
360 this->setstate(ios_base::eofbit);
361 break;
362 }
363
364 if (traits_type::eq_int_type(c, traits_type::to_int_type(delim)))
365 break;
366
367 if (n < 1 || gcount_ >= n - 1)
368 {
369 this->setstate(ios_base::failbit);
370 break;
371 }
372
373 s[gcount_++] = traits_type::to_char_type(c);
374 }
375
376 if (gcount_ == 0)
377 this->setstate(ios_base::failbit);
378 if (n > 0)
379 s[gcount_] = char_type{};
380 }
381
382 return *this;
383 }
384
385 basic_istream<Char, Traits>& ignore(streamsize n = 1, int_type delim = traits_type::eof())
386 {
387 sentry sen{*this, true};
388
389 if (sen)
390 {
391 streamsize i{};
392 while (n == numeric_limits<streamsize>::max() || i < n)
393 {
394 auto c = this->rdbuf()->sbumpc();
395
396 if (traits_type::eq_int_type(c, traits_type::eof()))
397 {
398 this->setstate(ios_base::eofbit);
399 break;
400 }
401
402 if (traits_type::eq_int_type(c, delim))
403 break;
404 }
405 }
406 }
407
408 int_type peek()
409 {
410 sentry sen{*this, true};
411
412 if (!this->good())
413 return traits_type::eof();
414 else
415 return this->rdbuf()->sgetc();
416 }
417
418 basic_istream<Char, Traits>& read(char_type* s, streamsize n)
419 {
420 gcount_ = 0;
421 sentry sen{*this, true};
422
423 if (!this->good())
424 {
425 this->setstate(ios_base::failbit);
426 return *this;
427 }
428
429 while (gcount_ < n)
430 {
431 auto c = this->rdbuf()->sbumpc();
432 if (traits_type::eq_int_type(c, traits_type::eof()))
433 {
434 this->setstate(ios_base::failbit | ios_base::eofbit);
435 break;
436 }
437
438 s[gcount_++] = traits_type::to_char_type(c);
439 }
440 }
441
442 streamsize readsome(char_type* s, streamsize n)
443 {
444 gcount_ = 0;
445 sentry sen{*this, true};
446
447 if (!this->good())
448 {
449 this->setstate(ios_base::failbit);
450 return streamsize{};
451 }
452
453 auto avail = this->rdbuf()->in_avail();
454 if (avail == -1)
455 {
456 this->setstate(ios_base::eofbit);
457 return streamsize{};
458 } else if (avail > 0)
459 {
460 auto count = (avail < n ? avail : n);
461 while (gcount_ < count)
462 s[gcount_++] = traits_type::to_char_type(this->rdbuf()->sbumpc());
463 }
464
465 return gcount_;
466 }
467
468 basic_istream<Char, Traits>& putback(char_type c)
469 {
470 clear(this->rdstate() & (~ios_base::eofbit));
471
472 gcount_ = 0;
473 sentry sen{*this, true};
474
475 if (!this->good())
476 {
477 this->setstate(ios_base::failbit);
478 return *this;
479 }
480
481 if (this->rdbuf())
482 {
483 auto ret = this->rdbuf()->sputbackc(c);
484 if (traits_type::eq_int_type(ret, traits_type::eof()))
485 this->setstate(ios_base::badbit);
486 }
487 else
488 this->setstate(ios_base::badbit);
489
490 return *this;
491 }
492
493 basic_istream<Char, Traits>& unget()
494 {
495 clear(this->rdstate() & (~ios_base::eofbit));
496
497 gcount_ = 0;
498 sentry sen{*this, true};
499
500 if (!this->good())
501 {
502 this->setstate(ios_base::failbit);
503 return *this;
504 }
505
506 if (this->rdbuf())
507 {
508 auto ret = this->rdbuf()->sungetc();
509 if (traits_type::eq_int_type(ret, traits_type::eof()))
510 this->setstate(ios_base::badbit);
511 }
512 else
513 this->setstate(ios_base::badbit);
514
515 return *this;
516 }
517
518 int sync()
519 {
520 sentry s{*this, true};
521
522 if (this->rdbuf())
523 {
524 auto ret = this->rdbuf()->pubsync();
525 if (ret == -1)
526 {
527 this->setstate(ios_base::badbit);
528 return -1;
529 }
530 else
531 return 0;
532 }
533 else
534 return -1;
535 }
536
537 pos_type tellg()
538 {
539 sentry s{*this, true};
540
541 if (this->fail())
542 return pos_type(-1);
543 else
544 return this->rdbuf()->pubseekoff(0, ios_base::cur, ios_base::in);
545 }
546
547 basic_istream<Char, Traits>& seekg(pos_type pos)
548 {
549 this->clear(this->rdstate() & (~ios_base::eofbit));
550
551 sentry sen{*this, true};
552
553 if (!this->fail())
554 this->rdbuf()->pubseekoff(pos, ios_base::in);
555 else
556 this->setstate(ios_base::failbit);
557
558 return *this;
559 }
560
561 basic_istream<Char, Traits>& seekg(off_type off, ios_base::seekdir dir)
562 {
563 sentry sen{*this, true};
564
565 if (!this->fail())
566 this->rdbuf()->pubseekoff(off, dir, ios_base::in);
567 else
568 this->setstate(ios_base::failbit);
569
570 return *this;
571 }
572
573 protected:
574 streamsize gcount_;
575
576 basic_istream(const basic_istream&) = delete;
577
578 basic_istream(basic_istream&& rhs)
579 {
580 gcount_ = rhs.gcout_;
581
582 basic_ios<Char, Traits>::move(rhs);
583
584 rhs.gcount_ = 0;
585 }
586
587 /**
588 * 27.7.2.1.2, assign/swap:
589 */
590
591 basic_istream& operator=(const basic_istream& rhs) = delete;
592
593 basic_istream& operator=(basic_istream&& rhs)
594 {
595 swap(rhs);
596
597 return *this;
598 }
599
600 void swap(basic_istream& rhs)
601 {
602 basic_ios<Char, Traits>::swap(rhs);
603 swap(gcount_, rhs.gcount_);
604 }
605 };
606
607 /**
608 * 27.7.2.2.3, character extraction templates:
609 */
610
611 template<class Char, class Traits>
612 basic_istream<Char, Traits>& operator>>(basic_istream<Char, Traits>& is,
613 Char& c)
614 {
615 // TODO: implement
616 }
617
618 template<class Char, class Traits>
619 basic_istream<Char, Traits>& operator>>(basic_istream<Char, Traits>& is,
620 unsigned char& c)
621 {
622 // TODO: implement
623 }
624
625 template<class Char, class Traits>
626 basic_istream<Char, Traits>& operator>>(basic_istream<Char, Traits>& is,
627 signed char& c)
628 {
629 // TODO: implement
630 }
631
632 template<class Char, class Traits>
633 basic_istream<Char, Traits>& operator>>(basic_istream<Char, Traits>& is,
634 Char* c)
635 {
636 // TODO: implement
637 }
638
639 template<class Char, class Traits>
640 basic_istream<Char, Traits>& operator>>(basic_istream<Char, Traits>& is,
641 unsigned char* c)
642 {
643 // TODO: implement
644 }
645
646 template<class Char, class Traits>
647 basic_istream<Char, Traits>& operator>>(basic_istream<Char, Traits>& is,
648 signed char* c)
649 {
650 // TODO: implement
651 }
652
653 /**
654 * 27.7.2.4, standard basic_istream manipulators:
655 */
656
657 template<class Char, class Traits = char_traits<Char>>
658 basic_istream<Char, Traits>& ws(basic_istream<Char, Traits>& is)
659 {
660 using sentry = typename basic_istream<Char, Traits>::sentry;
661 sentry sen{is, true};
662
663 if (sen)
664 {
665 const auto& ct = use_facet<ctype<Char>>(is.getloc());
666 while (true)
667 {
668 auto i = is.rdbuf()->sgetc();
669 if (Traits::eq_int_type(i, Traits::eof()))
670 {
671 is.setstate(ios_base::eofbit);
672 break;
673 }
674
675 auto c = Traits::to_char_type(i);
676 if (!ct.is(c, ct.space))
677 break;
678 else
679 is.rdbuf()->sbumpc();
680 }
681 }
682
683 return is;
684 }
685
686 using istream = basic_istream<char>;
687 using wistream = basic_istream<wchar_t>;
688
689 /**
690 * 27.7.2.5, class template basic_iostream:
691 */
692
693 template<class Char, class Traits>
694 class basic_iostream;
695
696 using iostream = basic_iostream<char>;
697 using wiostream = basic_iostream<wchar_t>;
698
699 /**
700 * 27.7.2.6, rvalue stream extraction:
701 */
702
703 template<class Char, class Traits, class T>
704 basic_istream<Char, Traits>& operator>>(basic_istream<Char, Traits>&& is, T& x)
705 {
706 is >> x;
707
708 return is;
709 }
710}
711
712#endif
Note: See TracBrowser for help on using the repository browser.