source: mainline/uspace/lib/cpp/include/impl/istream.hpp@ 7c84fce

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

cpp: added most of the integral extractors

  • Property mode set to 100644
File size: 25.4 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 sentry sen{*this, false};
158
159 if (sen)
160 {
161 using num_get = num_get<Char, istreambuf_iterator<Char, Traits>>;
162 auto err = ios_base::goodbit;
163
164 auto loc = this->getloc();
165 use_facet<num_get>(loc).get(*this, 0, *this, err, x);
166 this->setstate(err);
167 }
168
169 return *this;
170 }
171
172 basic_istream<Char, Traits>& operator>>(short& x)
173 {
174 sentry sen{*this, false};
175
176 if (sen)
177 {
178 using num_get = num_get<Char, istreambuf_iterator<Char, Traits>>;
179 auto err = ios_base::goodbit;
180
181 long tmp{};
182 auto loc = this->getloc();
183 use_facet<num_get>(loc).get(*this, 0, *this, err, tmp);
184
185 if (tmp < numeric_limits<short>::min())
186 {
187 err |= ios_base::failbit;
188 x = numeric_limits<short>::min();
189 }
190 else if (numeric_limits<short>::max() < tmp)
191 {
192 err |= ios_base::failbit;
193 x = numeric_limits<short>::max();
194 }
195 else
196 x = static_cast<short>(tmp);
197
198 this->setstate(err);
199 }
200
201 return *this;
202 }
203
204 basic_istream<Char, Traits>& operator>>(unsigned short& x)
205 {
206 sentry sen{*this, false};
207
208 if (sen)
209 {
210 using num_get = num_get<Char, istreambuf_iterator<Char, Traits>>;
211 auto err = ios_base::goodbit;
212
213 auto loc = this->getloc();
214 use_facet<num_get>(loc).get(*this, 0, *this, err, x);
215 this->setstate(err);
216 }
217
218 return *this;
219 }
220
221 basic_istream<Char, Traits>& operator>>(int& x)
222 {
223 sentry sen{*this, false};
224
225 if (sen)
226 {
227 using num_get = num_get<Char, istreambuf_iterator<Char, Traits>>;
228 auto err = ios_base::goodbit;
229
230 long tmp{};
231 auto loc = this->getloc();
232 use_facet<num_get>(loc).get(*this, 0, *this, err, tmp);
233
234 if (tmp < numeric_limits<int>::min())
235 {
236 err |= ios_base::failbit;
237 x = numeric_limits<int>::min();
238 }
239 else if (numeric_limits<int>::max() < tmp)
240 {
241 err |= ios_base::failbit;
242 x = numeric_limits<int>::max();
243 }
244 else
245 x = static_cast<int>(tmp);
246
247 this->setstate(err);
248 }
249
250 return *this;
251 }
252
253 basic_istream<Char, Traits>& operator>>(unsigned int& x)
254 {
255 sentry sen{*this, false};
256
257 if (sen)
258 {
259 using num_get = num_get<Char, istreambuf_iterator<Char, Traits>>;
260 auto err = ios_base::goodbit;
261
262 auto loc = this->getloc();
263 use_facet<num_get>(loc).get(*this, 0, *this, err, x);
264 this->setstate(err);
265 }
266
267 return *this;
268 }
269
270 basic_istream<Char, Traits>& operator>>(long& x)
271 {
272 sentry sen{*this, false};
273
274 if (sen)
275 {
276 using num_get = num_get<Char, istreambuf_iterator<Char, Traits>>;
277 auto err = ios_base::goodbit;
278
279 auto loc = this->getloc();
280 use_facet<num_get>(loc).get(*this, 0, *this, err, x);
281 this->setstate(err);
282 }
283
284 return *this;
285 }
286
287 basic_istream<Char, Traits>& operator>>(unsigned long& x)
288 {
289 sentry sen{*this, false};
290
291 if (sen)
292 {
293 using num_get = num_get<Char, istreambuf_iterator<Char, Traits>>;
294 auto err = ios_base::goodbit;
295
296 auto loc = this->getloc();
297 use_facet<num_get>(loc).get(*this, 0, *this, err, x);
298 this->setstate(err);
299 }
300
301 return *this;
302 }
303
304 basic_istream<Char, Traits>& operator>>(long long& x)
305 {
306 sentry sen{*this, false};
307
308 if (sen)
309 {
310 using num_get = num_get<Char, istreambuf_iterator<Char, Traits>>;
311 auto err = ios_base::goodbit;
312
313 auto loc = this->getloc();
314 use_facet<num_get>(loc).get(*this, 0, *this, err, x);
315 this->setstate(err);
316 }
317
318 return *this;
319 }
320
321 basic_istream<Char, Traits>& operator>>(unsigned long long& x)
322 {
323 sentry sen{*this, false};
324
325 if (sen)
326 {
327 using num_get = num_get<Char, istreambuf_iterator<Char, Traits>>;
328 auto err = ios_base::goodbit;
329
330 auto loc = this->getloc();
331 use_facet<num_get>(loc).get(*this, 0, *this, err, x);
332 this->setstate(err);
333 }
334
335 return *this;
336 }
337
338 basic_istream<Char, Traits>& operator>>(float& x)
339 {
340 // TODO: implement
341 }
342
343 basic_istream<Char, Traits>& operator>>(double& x)
344 {
345 // TODO: implement
346 }
347
348 basic_istream<Char, Traits>& operator>>(long double& x)
349 {
350 // TODO: implement
351 }
352
353 basic_istream<Char, Traits>& operator>>(void*& p)
354 {
355 // TODO: implement
356 }
357
358 basic_istream<Char, Traits>& operator>>(basic_streambuf<Char, Traits>* sb)
359 {
360 // TODO: implement
361 }
362
363 /**
364 * 27.7.2.3, unformatted input:
365 * TODO: Once we have exceptions, implement
366 * 27.7.2.3 paragraph 1.
367 */
368
369 streamsize gcount() const
370 {
371 return gcount_;
372 }
373
374 int_type get()
375 {
376 gcount_ = 0;
377 sentry sen{*this, true};
378
379 if (sen)
380 {
381 auto res = this->rdbuf()->sbumpc();
382 if (!traits_type::eq_int_type(res, traits_type::eof()))
383 {
384 gcount_ = 1;
385 return res;
386 }
387
388 this->setstate(ios_base::failbit | ios_base::eofbit);
389 }
390
391 return traits_type::eof();
392 }
393
394 basic_istream<Char, Traits>& get(char_type& c)
395 {
396 auto res = get();
397 if (res != traits_type::eof())
398 c = traits_type::to_char_type(res);
399
400 return this;
401 }
402
403 basic_istream<Char, Traits>& get(char_type* s, streamsize n, char_type delim)
404 {
405 gcount_ = 0;
406 sentry sen{*this, true};
407
408 if (sen && n > 0)
409 {
410 while(gcount_ < n - 1)
411 {
412 auto c = this->rdbuf()->sbumpc();
413
414 if (traits_type::eq_int_type(c, traits_type::eof()))
415 {
416 this->setstate(ios_base::eofbit);
417 break;
418 }
419
420 s[gcount_++] = traits_type::to_char_type(c);
421
422 auto peek = traits_type::to_char_type(this->rdbuf()->sgetc());
423 if (traits_type::eq(peek, delim))
424 break;
425 }
426
427 if (gcount_ == 0)
428 this->setstate(ios_base::failbit);
429 s[n] = char_type{};
430 }
431
432 return *this;
433 }
434
435 basic_istream<Char, Traits>& get(char_type* s, streamsize n)
436 {
437 return get(s, n, this->widen('\n'));
438 }
439
440 basic_istream<Char, Traits>& get(basic_streambuf<Char, Traits>& sb)
441 {
442 get(sb, this->widen('\n'));
443 }
444
445 basic_istream<Char, Traits>& get(basic_streambuf<Char, Traits>& sb, char_type delim)
446 {
447 gcount_ = 0;
448 sentry sen{*this, true};
449
450 if (sen)
451 {
452 while (true)
453 {
454 auto i = this->rdbuf()->sgetc();
455 if (traits_type::eq_int_type(i, traits_type::eof()))
456 {
457 this->setstate(ios_base::eofbit);
458 break;
459 }
460
461 auto c = traits_type::to_char_type(i);
462 if (traits_type::eq(c, delim))
463 break;
464
465 auto insert_ret = sb.sputc(c);
466 if (traits_type::eq_int_type(insert_ret, traits_type::eof()))
467 break;
468
469 this->rdbuf()->sbumpc();
470 ++gcount_;
471 }
472
473 if (gcount_ == 0)
474 this->setstate(ios_base::failbit);
475 }
476
477 return *this;
478 }
479
480 basic_istream<Char, Traits>& getline(char_type* s, streamsize n)
481 {
482 return getline(s, n, this->widen('\n'));
483 }
484
485 basic_istream<Char, Traits>& getline(char_type* s, streamsize n, char_type delim)
486 {
487 gcount_ = 0;
488 sentry sen{*this, true};
489
490 if (sen)
491 {
492 while (true)
493 { // We have exactly specified order of checks, easier to do them in the body.
494 auto c = this->rdbuf()->sbumpc();
495
496 if (traits_type::eq_int_type(c, traits_type::eof()))
497 {
498 this->setstate(ios_base::eofbit);
499 break;
500 }
501
502 if (traits_type::eq_int_type(c, traits_type::to_int_type(delim)))
503 break;
504
505 if (n < 1 || gcount_ >= n - 1)
506 {
507 this->setstate(ios_base::failbit);
508 break;
509 }
510
511 s[gcount_++] = traits_type::to_char_type(c);
512 }
513
514 if (gcount_ == 0)
515 this->setstate(ios_base::failbit);
516 if (n > 0)
517 s[gcount_] = char_type{};
518 }
519
520 return *this;
521 }
522
523 basic_istream<Char, Traits>& ignore(streamsize n = 1, int_type delim = traits_type::eof())
524 {
525 sentry sen{*this, true};
526
527 if (sen)
528 {
529 streamsize i{};
530 while (n == numeric_limits<streamsize>::max() || i < n)
531 {
532 auto c = this->rdbuf()->sbumpc();
533
534 if (traits_type::eq_int_type(c, traits_type::eof()))
535 {
536 this->setstate(ios_base::eofbit);
537 break;
538 }
539
540 if (traits_type::eq_int_type(c, delim))
541 break;
542 }
543 }
544 }
545
546 int_type peek()
547 {
548 sentry sen{*this, true};
549
550 if (!this->good())
551 return traits_type::eof();
552 else
553 return this->rdbuf()->sgetc();
554 }
555
556 basic_istream<Char, Traits>& read(char_type* s, streamsize n)
557 {
558 gcount_ = 0;
559 sentry sen{*this, true};
560
561 if (!this->good())
562 {
563 this->setstate(ios_base::failbit);
564 return *this;
565 }
566
567 while (gcount_ < n)
568 {
569 auto c = this->rdbuf()->sbumpc();
570 if (traits_type::eq_int_type(c, traits_type::eof()))
571 {
572 this->setstate(ios_base::failbit | ios_base::eofbit);
573 break;
574 }
575
576 s[gcount_++] = traits_type::to_char_type(c);
577 }
578 }
579
580 streamsize readsome(char_type* s, streamsize n)
581 {
582 gcount_ = 0;
583 sentry sen{*this, true};
584
585 if (!this->good())
586 {
587 this->setstate(ios_base::failbit);
588 return streamsize{};
589 }
590
591 auto avail = this->rdbuf()->in_avail();
592 if (avail == -1)
593 {
594 this->setstate(ios_base::eofbit);
595 return streamsize{};
596 } else if (avail > 0)
597 {
598 auto count = (avail < n ? avail : n);
599 while (gcount_ < count)
600 s[gcount_++] = traits_type::to_char_type(this->rdbuf()->sbumpc());
601 }
602
603 return gcount_;
604 }
605
606 basic_istream<Char, Traits>& putback(char_type c)
607 {
608 clear(this->rdstate() & (~ios_base::eofbit));
609
610 gcount_ = 0;
611 sentry sen{*this, true};
612
613 if (!this->good())
614 {
615 this->setstate(ios_base::failbit);
616 return *this;
617 }
618
619 if (this->rdbuf())
620 {
621 auto ret = this->rdbuf()->sputbackc(c);
622 if (traits_type::eq_int_type(ret, traits_type::eof()))
623 this->setstate(ios_base::badbit);
624 }
625 else
626 this->setstate(ios_base::badbit);
627
628 return *this;
629 }
630
631 basic_istream<Char, Traits>& unget()
632 {
633 clear(this->rdstate() & (~ios_base::eofbit));
634
635 gcount_ = 0;
636 sentry sen{*this, true};
637
638 if (!this->good())
639 {
640 this->setstate(ios_base::failbit);
641 return *this;
642 }
643
644 if (this->rdbuf())
645 {
646 auto ret = this->rdbuf()->sungetc();
647 if (traits_type::eq_int_type(ret, traits_type::eof()))
648 this->setstate(ios_base::badbit);
649 }
650 else
651 this->setstate(ios_base::badbit);
652
653 return *this;
654 }
655
656 int sync()
657 {
658 sentry s{*this, true};
659
660 if (this->rdbuf())
661 {
662 auto ret = this->rdbuf()->pubsync();
663 if (ret == -1)
664 {
665 this->setstate(ios_base::badbit);
666 return -1;
667 }
668 else
669 return 0;
670 }
671 else
672 return -1;
673 }
674
675 pos_type tellg()
676 {
677 sentry s{*this, true};
678
679 if (this->fail())
680 return pos_type(-1);
681 else
682 return this->rdbuf()->pubseekoff(0, ios_base::cur, ios_base::in);
683 }
684
685 basic_istream<Char, Traits>& seekg(pos_type pos)
686 {
687 this->clear(this->rdstate() & (~ios_base::eofbit));
688
689 sentry sen{*this, true};
690
691 if (!this->fail())
692 this->rdbuf()->pubseekoff(pos, ios_base::in);
693 else
694 this->setstate(ios_base::failbit);
695
696 return *this;
697 }
698
699 basic_istream<Char, Traits>& seekg(off_type off, ios_base::seekdir dir)
700 {
701 sentry sen{*this, true};
702
703 if (!this->fail())
704 this->rdbuf()->pubseekoff(off, dir, ios_base::in);
705 else
706 this->setstate(ios_base::failbit);
707
708 return *this;
709 }
710
711 protected:
712 streamsize gcount_;
713
714 basic_istream(const basic_istream&) = delete;
715
716 basic_istream(basic_istream&& rhs)
717 {
718 gcount_ = rhs.gcout_;
719
720 basic_ios<Char, Traits>::move(rhs);
721
722 rhs.gcount_ = 0;
723 }
724
725 /**
726 * 27.7.2.1.2, assign/swap:
727 */
728
729 basic_istream& operator=(const basic_istream& rhs) = delete;
730
731 basic_istream& operator=(basic_istream&& rhs)
732 {
733 swap(rhs);
734
735 return *this;
736 }
737
738 void swap(basic_istream& rhs)
739 {
740 basic_ios<Char, Traits>::swap(rhs);
741 swap(gcount_, rhs.gcount_);
742 }
743 };
744
745 /**
746 * 27.7.2.2.3, character extraction templates:
747 */
748
749 template<class Char, class Traits>
750 basic_istream<Char, Traits>& operator>>(basic_istream<Char, Traits>& is,
751 Char& c)
752 {
753 // TODO: implement
754 }
755
756 template<class Char, class Traits>
757 basic_istream<Char, Traits>& operator>>(basic_istream<Char, Traits>& is,
758 unsigned char& c)
759 {
760 // TODO: implement
761 }
762
763 template<class Char, class Traits>
764 basic_istream<Char, Traits>& operator>>(basic_istream<Char, Traits>& is,
765 signed char& c)
766 {
767 // TODO: implement
768 }
769
770 template<class Char, class Traits>
771 basic_istream<Char, Traits>& operator>>(basic_istream<Char, Traits>& is,
772 Char* c)
773 {
774 // TODO: implement
775 }
776
777 template<class Char, class Traits>
778 basic_istream<Char, Traits>& operator>>(basic_istream<Char, Traits>& is,
779 unsigned char* c)
780 {
781 // TODO: implement
782 }
783
784 template<class Char, class Traits>
785 basic_istream<Char, Traits>& operator>>(basic_istream<Char, Traits>& is,
786 signed char* c)
787 {
788 // TODO: implement
789 }
790
791 /**
792 * 27.7.2.4, standard basic_istream manipulators:
793 */
794
795 template<class Char, class Traits = char_traits<Char>>
796 basic_istream<Char, Traits>& ws(basic_istream<Char, Traits>& is)
797 {
798 using sentry = typename basic_istream<Char, Traits>::sentry;
799 sentry sen{is, true};
800
801 if (sen)
802 {
803 const auto& ct = use_facet<ctype<Char>>(is.getloc());
804 while (true)
805 {
806 auto i = is.rdbuf()->sgetc();
807 if (Traits::eq_int_type(i, Traits::eof()))
808 {
809 is.setstate(ios_base::eofbit);
810 break;
811 }
812
813 auto c = Traits::to_char_type(i);
814 if (!ct.is(c, ct.space))
815 break;
816 else
817 is.rdbuf()->sbumpc();
818 }
819 }
820
821 return is;
822 }
823
824 using istream = basic_istream<char>;
825 using wistream = basic_istream<wchar_t>;
826
827 /**
828 * 27.7.2.5, class template basic_iostream:
829 */
830
831 template<class Char, class Traits>
832 class basic_iostream;
833
834 using iostream = basic_iostream<char>;
835 using wiostream = basic_iostream<wchar_t>;
836
837 /**
838 * 27.7.2.6, rvalue stream extraction:
839 */
840
841 template<class Char, class Traits, class T>
842 basic_istream<Char, Traits>& operator>>(basic_istream<Char, Traits>&& is, T& x)
843 {
844 is >> x;
845
846 return is;
847 }
848}
849
850#endif
Note: See TracBrowser for help on using the repository browser.