source: mainline/uspace/lib/cpp/include/__bits/io/istream.hpp@ 8fd0675f

Last change on this file since 8fd0675f was b57ba05, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 3 years ago

Update headers in C++ files

  • Property mode set to 100644
File size: 27.9 KB
Line 
1/*
2 * SPDX-FileCopyrightText: 2019 Jaroslav Jindrak
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#ifndef LIBCPP_BITS_IO_ISTREAM
8#define LIBCPP_BITS_IO_ISTREAM
9
10#include <cassert>
11#include <ios>
12#include <iosfwd>
13#include <limits>
14#include <locale>
15#include <ostream>
16#include <utility>
17
18namespace std
19{
20
21 /**
22 * 27.7.2.1, class template basic_stream:
23 */
24
25 template<class Char, class Traits>
26 class basic_istream: virtual public basic_ios<Char, Traits>
27 {
28 public:
29 using traits_type = Traits;
30 using char_type = Char;
31 using int_type = typename traits_type::int_type;
32 using pos_type = typename traits_type::pos_type;
33 using off_type = typename traits_type::off_type;
34
35 /**
36 * 27.7.2.1.1, constructor/destructor:
37 */
38
39 explicit basic_istream(basic_streambuf<Char, Traits>* sb)
40 : gcount_{0}
41 {
42 basic_ios<Char, Traits>::init(sb);
43 }
44
45 virtual ~basic_istream()
46 { /* DUMMY BODY */ }
47
48 /**
49 * 27.7.2.1.3, prefix/suffix:
50 */
51
52 class sentry
53 {
54 public:
55 explicit sentry(basic_istream<Char, Traits>& is, bool noskipws = false)
56 : ok_{false}
57 {
58 if (!is.good())
59 is.setstate(ios_base::failbit);
60 else
61 {
62 if (is.tie())
63 is.tie()->flush();
64
65 if (!noskipws && ((is.flags() & ios_base::skipws) != 0))
66 {
67 const auto& ct = use_facet<ctype<Char>>(is.getloc());
68 while (true)
69 {
70 auto i = is.rdbuf()->sgetc();
71 if (Traits::eq_int_type(i, Traits::eof()))
72 {
73 is.setstate(ios_base::failbit | ios_base::eofbit);
74 break;
75 }
76
77 auto c = Traits::to_char_type(i);
78 if (!ct.is(ctype_base::space, c))
79 break;
80 else
81 is.rdbuf()->sbumpc();
82 }
83 }
84 }
85
86 if (is.good())
87 ok_ = true;
88 }
89
90 ~sentry() = default;
91
92 explicit operator bool() const
93 {
94 return ok_;
95 }
96
97 sentry(const sentry&) = delete;
98 sentry& operator=(const sentry&) = delete;
99
100 private:
101 using traits_type = Traits;
102 bool ok_;
103 };
104
105 /**
106 * 27.7.2.2, formatted input:
107 */
108
109 basic_istream<Char, Traits>& operator>>(
110 basic_istream<Char, Traits>& (*pf)(basic_istream<Char, Traits>&)
111 )
112 {
113 return pf(*this);
114 }
115
116 basic_istream<Char, Traits>& operator>>(
117 basic_ios<Char, Traits>& (*pf)(basic_ios<Char, Traits>&)
118 )
119 {
120 pf(*this);
121
122 return *this;
123 }
124
125 basic_istream<Char, Traits>& operator>>(
126 ios_base& (*pf)(ios_base&)
127 )
128 {
129 pf(*this);
130
131 return *this;
132 }
133
134 basic_istream<Char, Traits>& operator>>(bool& x)
135 {
136 sentry sen{*this, false};
137
138 if (sen)
139 {
140 using num_get = num_get<Char, istreambuf_iterator<Char, Traits>>;
141 auto err = ios_base::goodbit;
142
143 auto loc = this->getloc();
144 use_facet<num_get>(loc).get(*this, 0, *this, err, x);
145 this->setstate(err);
146 }
147
148 return *this;
149 }
150
151 basic_istream<Char, Traits>& operator>>(short& x)
152 {
153 sentry sen{*this, false};
154
155 if (sen)
156 {
157 using num_get = num_get<Char, istreambuf_iterator<Char, Traits>>;
158 auto err = ios_base::goodbit;
159
160 long tmp{};
161 auto loc = this->getloc();
162 use_facet<num_get>(loc).get(*this, 0, *this, err, tmp);
163
164 if (tmp < numeric_limits<short>::min())
165 {
166 err |= ios_base::failbit;
167 x = numeric_limits<short>::min();
168 }
169 else if (numeric_limits<short>::max() < tmp)
170 {
171 err |= ios_base::failbit;
172 x = numeric_limits<short>::max();
173 }
174 else
175 x = static_cast<short>(tmp);
176
177 this->setstate(err);
178 }
179
180 return *this;
181 }
182
183 basic_istream<Char, Traits>& operator>>(unsigned short& x)
184 {
185 sentry sen{*this, false};
186
187 if (sen)
188 {
189 using num_get = num_get<Char, istreambuf_iterator<Char, Traits>>;
190 auto err = ios_base::goodbit;
191
192 auto loc = this->getloc();
193 use_facet<num_get>(loc).get(*this, 0, *this, err, x);
194 this->setstate(err);
195 }
196
197 return *this;
198 }
199
200 basic_istream<Char, Traits>& operator>>(int& x)
201 {
202 sentry sen{*this, false};
203
204 if (sen)
205 {
206 using num_get = num_get<Char, istreambuf_iterator<Char, Traits>>;
207 auto err = ios_base::goodbit;
208
209 long tmp{};
210 auto loc = this->getloc();
211 use_facet<num_get>(loc).get(*this, 0, *this, err, tmp);
212
213 if (tmp < numeric_limits<int>::min())
214 {
215 err |= ios_base::failbit;
216 x = numeric_limits<int>::min();
217 }
218 else if (numeric_limits<int>::max() < tmp)
219 {
220 err |= ios_base::failbit;
221 x = numeric_limits<int>::max();
222 }
223 else
224 x = static_cast<int>(tmp);
225
226 this->setstate(err);
227 }
228
229 return *this;
230 }
231
232 basic_istream<Char, Traits>& operator>>(unsigned int& x)
233 {
234 sentry sen{*this, false};
235
236 if (sen)
237 {
238 using num_get = num_get<Char, istreambuf_iterator<Char, Traits>>;
239 auto err = ios_base::goodbit;
240
241 auto loc = this->getloc();
242 use_facet<num_get>(loc).get(*this, 0, *this, err, x);
243 this->setstate(err);
244 }
245
246 return *this;
247 }
248
249 basic_istream<Char, Traits>& operator>>(long& x)
250 {
251 sentry sen{*this, false};
252
253 if (sen)
254 {
255 using num_get = num_get<Char, istreambuf_iterator<Char, Traits>>;
256 auto err = ios_base::goodbit;
257
258 auto loc = this->getloc();
259 use_facet<num_get>(loc).get(*this, 0, *this, err, x);
260 this->setstate(err);
261 }
262
263 return *this;
264 }
265
266 basic_istream<Char, Traits>& operator>>(unsigned long& x)
267 {
268 sentry sen{*this, false};
269
270 if (sen)
271 {
272 using num_get = num_get<Char, istreambuf_iterator<Char, Traits>>;
273 auto err = ios_base::goodbit;
274
275 auto loc = this->getloc();
276 use_facet<num_get>(loc).get(*this, 0, *this, err, x);
277 this->setstate(err);
278 }
279
280 return *this;
281 }
282
283 basic_istream<Char, Traits>& operator>>(long long& x)
284 {
285 sentry sen{*this, false};
286
287 if (sen)
288 {
289 using num_get = num_get<Char, istreambuf_iterator<Char, Traits>>;
290 auto err = ios_base::goodbit;
291
292 auto loc = this->getloc();
293 use_facet<num_get>(loc).get(*this, 0, *this, err, x);
294 this->setstate(err);
295 }
296
297 return *this;
298 }
299
300 basic_istream<Char, Traits>& operator>>(unsigned long long& x)
301 {
302 sentry sen{*this, false};
303
304 if (sen)
305 {
306 using num_get = num_get<Char, istreambuf_iterator<Char, Traits>>;
307 auto err = ios_base::goodbit;
308
309 auto loc = this->getloc();
310 use_facet<num_get>(loc).get(*this, 0, *this, err, x);
311 this->setstate(err);
312 }
313
314 return *this;
315 }
316
317 basic_istream<Char, Traits>& operator>>(float& x)
318 {
319 // TODO: implement
320 __unimplemented();
321 return *this;
322 }
323
324 basic_istream<Char, Traits>& operator>>(double& x)
325 {
326 // TODO: implement
327 __unimplemented();
328 return *this;
329 }
330
331 basic_istream<Char, Traits>& operator>>(long double& x)
332 {
333 // TODO: implement
334 __unimplemented();
335 return *this;
336 }
337
338 basic_istream<Char, Traits>& operator>>(void*& p)
339 {
340 // TODO: implement
341 __unimplemented();
342 return *this;
343 }
344
345 basic_istream<Char, Traits>& operator>>(basic_streambuf<Char, Traits>* sb)
346 {
347 if (!sb)
348 {
349 this->setstate(ios_base::failbit);
350 return *this;
351 }
352
353 gcount_ = 0;
354 sentry sen{*this, false};
355
356 if (sen)
357 {
358 while (true)
359 {
360 auto ic = this->rdbuf()->sgetc();
361 if (traits_type::eq_int_type(ic, traits_type::eof()))
362 {
363 this->setstate(ios_base::eofbit);
364 break;
365 }
366
367 auto res = sb->sputc(traits_type::to_char_type(ic));
368 if (traits_type::eq_int_type(res, traits_type::eof()))
369 break;
370
371 ++gcount_;
372 this->rdbuf()->sbumpc();
373 }
374 }
375
376 return *this;
377 }
378
379 /**
380 * 27.7.2.3, unformatted input:
381 * TODO: Once we have exceptions, implement
382 * 27.7.2.3 paragraph 1.
383 */
384
385 streamsize gcount() const
386 {
387 return gcount_;
388 }
389
390 int_type get()
391 {
392 gcount_ = 0;
393 sentry sen{*this, true};
394
395 if (sen)
396 {
397 auto res = this->rdbuf()->sbumpc();
398 if (!traits_type::eq_int_type(res, traits_type::eof()))
399 {
400 gcount_ = 1;
401 return res;
402 }
403
404 this->setstate(ios_base::failbit | ios_base::eofbit);
405 }
406
407 return traits_type::eof();
408 }
409
410 basic_istream<Char, Traits>& get(char_type& c)
411 {
412 auto res = get();
413 if (res != traits_type::eof())
414 c = traits_type::to_char_type(res);
415
416 return *this;
417 }
418
419 basic_istream<Char, Traits>& get(char_type* s, streamsize n, char_type delim)
420 {
421 gcount_ = 0;
422 sentry sen{*this, true};
423
424 if (sen && n > 0)
425 {
426 while(gcount_ < n - 1)
427 {
428 auto c = this->rdbuf()->sbumpc();
429
430 if (traits_type::eq_int_type(c, traits_type::eof()))
431 {
432 this->setstate(ios_base::eofbit);
433 break;
434 }
435
436 s[gcount_++] = traits_type::to_char_type(c);
437
438 auto peek = traits_type::to_char_type(this->rdbuf()->sgetc());
439 if (traits_type::eq(peek, delim))
440 break;
441 }
442
443 if (gcount_ == 0)
444 this->setstate(ios_base::failbit);
445 s[n] = char_type{};
446 }
447
448 return *this;
449 }
450
451 basic_istream<Char, Traits>& get(char_type* s, streamsize n)
452 {
453 return get(s, n, this->widen('\n'));
454 }
455
456 basic_istream<Char, Traits>& get(basic_streambuf<Char, Traits>& sb)
457 {
458 get(sb, this->widen('\n'));
459 }
460
461 basic_istream<Char, Traits>& get(basic_streambuf<Char, Traits>& sb, char_type delim)
462 {
463 gcount_ = 0;
464 sentry sen{*this, true};
465
466 if (sen)
467 {
468 while (true)
469 {
470 auto i = this->rdbuf()->sgetc();
471 if (traits_type::eq_int_type(i, traits_type::eof()))
472 {
473 this->setstate(ios_base::eofbit);
474 break;
475 }
476
477 auto c = traits_type::to_char_type(i);
478 if (traits_type::eq(c, delim))
479 break;
480
481 auto insert_ret = sb.sputc(c);
482 if (traits_type::eq_int_type(insert_ret, traits_type::eof()))
483 break;
484
485 this->rdbuf()->sbumpc();
486 ++gcount_;
487 }
488
489 if (gcount_ == 0)
490 this->setstate(ios_base::failbit);
491 }
492
493 return *this;
494 }
495
496 basic_istream<Char, Traits>& getline(char_type* s, streamsize n)
497 {
498 return getline(s, n, this->widen('\n'));
499 }
500
501 basic_istream<Char, Traits>& getline(char_type* s, streamsize n, char_type delim)
502 {
503 gcount_ = 0;
504 sentry sen{*this, true};
505
506 if (sen)
507 {
508 while (true)
509 { // We have exactly specified order of checks, easier to do them in the body.
510 auto c = this->rdbuf()->sbumpc();
511
512 if (traits_type::eq_int_type(c, traits_type::eof()))
513 {
514 this->setstate(ios_base::eofbit);
515 break;
516 }
517
518 if (traits_type::eq_int_type(c, traits_type::to_int_type(delim)))
519 break;
520
521 if (n < 1 || gcount_ >= n - 1)
522 {
523 this->setstate(ios_base::failbit);
524 break;
525 }
526
527 s[gcount_++] = traits_type::to_char_type(c);
528 }
529
530 if (gcount_ == 0)
531 this->setstate(ios_base::failbit);
532 if (n > 0)
533 s[gcount_] = char_type{};
534 }
535
536 return *this;
537 }
538
539 basic_istream<Char, Traits>& ignore(streamsize n = 1, int_type delim = traits_type::eof())
540 {
541 sentry sen{*this, true};
542
543 if (sen)
544 {
545 streamsize i{};
546 while (n == numeric_limits<streamsize>::max() || i < n)
547 {
548 auto c = this->rdbuf()->sbumpc();
549
550 if (traits_type::eq_int_type(c, traits_type::eof()))
551 {
552 this->setstate(ios_base::eofbit);
553 break;
554 }
555
556 if (traits_type::eq_int_type(c, delim))
557 break;
558 }
559 }
560
561 return *this;
562 }
563
564 int_type peek()
565 {
566 sentry sen{*this, true};
567
568 if (!this->good())
569 return traits_type::eof();
570 else
571 return this->rdbuf()->sgetc();
572 }
573
574 basic_istream<Char, Traits>& read(char_type* s, streamsize n)
575 {
576 gcount_ = 0;
577 sentry sen{*this, true};
578
579 if (!this->good())
580 {
581 this->setstate(ios_base::failbit);
582 return *this;
583 }
584
585 while (gcount_ < n)
586 {
587 auto c = this->rdbuf()->sbumpc();
588 if (traits_type::eq_int_type(c, traits_type::eof()))
589 {
590 this->setstate(ios_base::failbit | ios_base::eofbit);
591 break;
592 }
593
594 s[gcount_++] = traits_type::to_char_type(c);
595 }
596
597 return *this;
598 }
599
600 streamsize readsome(char_type* s, streamsize n)
601 {
602 gcount_ = 0;
603 sentry sen{*this, true};
604
605 if (!this->good())
606 {
607 this->setstate(ios_base::failbit);
608 return streamsize{};
609 }
610
611 auto avail = this->rdbuf()->in_avail();
612 if (avail == -1)
613 {
614 this->setstate(ios_base::eofbit);
615 return streamsize{};
616 } else if (avail > 0)
617 {
618 auto count = (avail < n ? avail : n);
619 while (gcount_ < count)
620 s[gcount_++] = traits_type::to_char_type(this->rdbuf()->sbumpc());
621 }
622
623 return gcount_;
624 }
625
626 basic_istream<Char, Traits>& putback(char_type c)
627 {
628 this->clear(this->rdstate() & (~ios_base::eofbit));
629
630 gcount_ = 0;
631 sentry sen{*this, true};
632
633 if (!this->good())
634 {
635 this->setstate(ios_base::failbit);
636 return *this;
637 }
638
639 if (this->rdbuf())
640 {
641 auto ret = this->rdbuf()->sputbackc(c);
642 if (traits_type::eq_int_type(ret, traits_type::eof()))
643 this->setstate(ios_base::badbit);
644 }
645 else
646 this->setstate(ios_base::badbit);
647
648 return *this;
649 }
650
651 basic_istream<Char, Traits>& unget()
652 {
653 this->clear(this->rdstate() & (~ios_base::eofbit));
654
655 gcount_ = 0;
656 sentry sen{*this, true};
657
658 if (!this->good())
659 {
660 this->setstate(ios_base::failbit);
661 return *this;
662 }
663
664 if (this->rdbuf())
665 {
666 auto ret = this->rdbuf()->sungetc();
667 if (traits_type::eq_int_type(ret, traits_type::eof()))
668 this->setstate(ios_base::badbit);
669 }
670 else
671 this->setstate(ios_base::badbit);
672
673 return *this;
674 }
675
676 int sync()
677 {
678 sentry s{*this, true};
679
680 if (this->rdbuf())
681 {
682 auto ret = this->rdbuf()->pubsync();
683 if (ret == -1)
684 {
685 this->setstate(ios_base::badbit);
686 return -1;
687 }
688 else
689 return 0;
690 }
691 else
692 return -1;
693 }
694
695 pos_type tellg()
696 {
697 sentry s{*this, true};
698
699 if (this->fail())
700 return pos_type(-1);
701 else
702 return this->rdbuf()->pubseekoff(0, ios_base::cur, ios_base::in);
703 }
704
705 basic_istream<Char, Traits>& seekg(pos_type pos)
706 {
707 this->clear(this->rdstate() & (~ios_base::eofbit));
708
709 sentry sen{*this, true};
710
711 if (!this->fail())
712 this->rdbuf()->pubseekoff(pos, ios_base::in);
713 else
714 this->setstate(ios_base::failbit);
715
716 return *this;
717 }
718
719 basic_istream<Char, Traits>& seekg(off_type off, ios_base::seekdir dir)
720 {
721 sentry sen{*this, true};
722
723 if (!this->fail())
724 this->rdbuf()->pubseekoff(off, dir, ios_base::in);
725 else
726 this->setstate(ios_base::failbit);
727
728 return *this;
729 }
730
731 protected:
732 streamsize gcount_;
733
734 basic_istream(const basic_istream&) = delete;
735
736 basic_istream(basic_istream&& rhs)
737 {
738 gcount_ = rhs.gcout_;
739
740 basic_ios<Char, Traits>::move(rhs);
741
742 rhs.gcount_ = 0;
743 }
744
745 /**
746 * 27.7.2.1.2, assign/swap:
747 */
748
749 basic_istream& operator=(const basic_istream& rhs) = delete;
750
751 basic_istream& operator=(basic_istream&& rhs)
752 {
753 swap(rhs);
754
755 return *this;
756 }
757
758 void swap(basic_istream& rhs)
759 {
760 basic_ios<Char, Traits>::swap(rhs);
761 swap(gcount_, rhs.gcount_);
762 }
763 };
764
765 /**
766 * 27.7.2.2.3, character extraction templates:
767 */
768
769 template<class Char, class Traits>
770 basic_istream<Char, Traits>& operator>>(basic_istream<Char, Traits>& is,
771 Char& c)
772 {
773 typename basic_istream<Char, Traits>::sentry sen{is, false};
774
775 if (sen)
776 {
777 auto ic = is.rdbuf()->sgetc();
778 if (Traits::eq_int_type(ic, Traits::eof()))
779 {
780 is.setstate(ios_base::failbit | ios_base::eofbit);
781 return is;
782 }
783
784 c = Traits::to_char_type(is.rdbuf()->sbumpc());
785 }
786
787 return is;
788 }
789
790 template<class Char, class Traits>
791 basic_istream<Char, Traits>& operator>>(basic_istream<Char, Traits>& is,
792 unsigned char& c)
793 {
794 return is >> reinterpret_cast<char&>(c);
795 }
796
797 template<class Char, class Traits>
798 basic_istream<Char, Traits>& operator>>(basic_istream<Char, Traits>& is,
799 signed char& c)
800 {
801 return is >> reinterpret_cast<char&>(c);
802 }
803
804 template<class Char, class Traits>
805 basic_istream<Char, Traits>& operator>>(basic_istream<Char, Traits>& is,
806 Char* str)
807 {
808 typename basic_istream<Char, Traits>::sentry sen{is, false};
809
810 if (sen)
811 {
812 const auto& ct = use_facet<ctype<Char>>(is.getloc());
813
814 size_t n{};
815 if (is.width() > 0)
816 n = static_cast<size_t>(is.width());
817 else
818 n = (numeric_limits<size_t>::max() / sizeof(Char)) - sizeof(Char);
819
820 size_t i{};
821 for (; i < n - 1; ++i)
822 {
823 auto ic = is.rdbuf()->sgetc();
824 if (Traits::eq_int_type(ic, Traits::eof()))
825 break;
826
827 auto c = Traits::to_char_type(ic);
828 if (ct.is(ctype_base::space, c))
829 break;
830
831 str[i] = c;
832 is.rdbuf()->sbumpc();
833 }
834
835 str[i] = Char{};
836 if (i == 0)
837 is.setstate(ios_base::failbit);
838 }
839
840 return is;
841 }
842
843 template<class Char, class Traits>
844 basic_istream<Char, Traits>& operator>>(basic_istream<Char, Traits>& is,
845 unsigned char* str)
846 {
847 return is >> reinterpret_cast<char*>(str);
848 }
849
850 template<class Char, class Traits>
851 basic_istream<Char, Traits>& operator>>(basic_istream<Char, Traits>& is,
852 signed char* str)
853 {
854 return is >> reinterpret_cast<char*>(str);
855 }
856
857 /**
858 * 27.7.2.4, standard basic_istream manipulators:
859 */
860
861 template<class Char, class Traits = char_traits<Char>>
862 basic_istream<Char, Traits>& ws(basic_istream<Char, Traits>& is)
863 {
864 using sentry = typename basic_istream<Char, Traits>::sentry;
865 sentry sen{is, true};
866
867 if (sen)
868 {
869 const auto& ct = use_facet<ctype<Char>>(is.getloc());
870 while (true)
871 {
872 auto i = is.rdbuf()->sgetc();
873 if (Traits::eq_int_type(i, Traits::eof()))
874 {
875 is.setstate(ios_base::eofbit);
876 break;
877 }
878
879 auto c = Traits::to_char_type(i);
880 if (!ct.is(c, ct.space))
881 break;
882 else
883 is.rdbuf()->sbumpc();
884 }
885 }
886
887 return is;
888 }
889
890 using istream = basic_istream<char>;
891 using wistream = basic_istream<wchar_t>;
892
893 /**
894 * 27.7.2.5, class template basic_iostream:
895 */
896
897 template<class Char, class Traits>
898 class basic_iostream
899 : public basic_istream<Char, Traits>,
900 public basic_ostream<Char, Traits>
901 {
902 public:
903 using char_type = Char;
904 using traits_type = Traits;
905 using int_type = typename traits_type::int_type;
906 using pos_type = typename traits_type::pos_type;
907 using off_type = typename traits_type::off_type;
908
909 explicit basic_iostream(basic_streambuf<char_type, traits_type>* sb)
910 : basic_istream<char_type, traits_type>(sb),
911 basic_ostream<char_type, traits_type>(sb)
912 { /* DUMMY BODY */ }
913
914 virtual ~basic_iostream()
915 { /* DUMMY BODY */ }
916
917 protected:
918 basic_iostream(const basic_iostream&) = delete;
919 basic_iostream& operator=(const basic_iostream&) = delete;
920
921 basic_iostream(basic_iostream&& other)
922 : basic_istream<char_type, traits_type>(move(other))
923 { /* DUMMY BODY */ }
924
925 basic_iostream& operator=(basic_iostream&& other)
926 {
927 swap(other);
928 }
929
930 void swap(basic_iostream& other)
931 {
932 basic_istream<char_type, traits_type>::swap(other);
933 }
934 };
935
936 using iostream = basic_iostream<char>;
937 using wiostream = basic_iostream<wchar_t>;
938
939 /**
940 * 27.7.2.6, rvalue stream extraction:
941 */
942
943 template<class Char, class Traits, class T>
944 basic_istream<Char, Traits>& operator>>(basic_istream<Char, Traits>&& is, T& x)
945 {
946 is >> x;
947
948 return is;
949 }
950}
951
952#endif
Note: See TracBrowser for help on using the repository browser.