source: mainline/uspace/lib/cpp/include/impl/istream.hpp@ 6371c5bf

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

cpp: added basic unformatted input to std::istream

  • 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 printf("ISTREAM\n");
64 basic_ios<Char, Traits>::init(sb);
65 }
66
67 virtual ~basic_istream()
68 { /* DUMMY BODY */ }
69
70 /**
71 * 27.7.2.1.3, prefix/suffix:
72 */
73
74 class sentry
75 {
76 public:
77 explicit sentry(basic_istream<Char, Traits>& is, bool noskipws = false)
78 : ok_{false}
79 {
80 if (!is.good())
81 is.setstate(ios_base::failbit);
82 else
83 {
84 if (is.tie())
85 is.tie()->flush();
86
87 if (!noskipws && ((is.flags() & ios_base::skipws) != 0))
88 {
89 const auto& ct = use_facet<ctype<Char>>(is.getloc());
90 while (true)
91 {
92 auto i = is.rdbuf()->sgetc();
93 if (Traits::eq_int_type(i, Traits::eof()))
94 {
95 is.setstate(ios_base::failbit | ios_base::eofbit);
96 break;
97 }
98
99 auto c = Traits::to_char_type(i);
100 if (!ct.is(c, ct.space))
101 break;
102 else
103 is.rdbuf()->sbumpc();
104 }
105 }
106 }
107
108 if (is.good())
109 ok_ = true;
110 }
111
112 ~sentry() = default;
113
114 explicit operator bool() const
115 {
116 return ok_;
117 }
118
119 sentry(const sentry&) = delete;
120 sentry& operator=(const sentry&) = delete;
121
122 private:
123 using traits_type = Traits;
124 bool ok_;
125 };
126
127 /**
128 * 27.7.2.2, formatted input:
129 */
130
131 basic_istream<Char, Traits>& operator>>(
132 basic_istream<Char, Traits>& (*pf)(basic_istream<Char, Traits>&)
133 )
134 {
135 return pf(*this);
136 }
137
138 basic_istream<Char, Traits>& operator>>(
139 basic_ios<Char, Traits>& (*pf)(basic_ios<Char, Traits>&)
140 )
141 {
142 pf(*this);
143
144 return *this;
145 }
146
147 basic_istream<Char, Traits>& operator>>(
148 ios_base& (*pf)(ios_base&)
149 )
150 {
151 pf(*this);
152
153 return *this;
154 }
155
156 basic_istream<Char, Traits>& operator>>(bool& x)
157 {
158 // TODO: implement
159 }
160
161 basic_istream<Char, Traits>& operator>>(short& x)
162 {
163 // TODO: implement
164 }
165
166 basic_istream<Char, Traits>& operator>>(unsigned short& x)
167 {
168 // TODO: implement
169 }
170
171 basic_istream<Char, Traits>& operator>>(int& x)
172 {
173 // TODO: implement
174 }
175
176 basic_istream<Char, Traits>& operator>>(unsigned int& x)
177 {
178 // TODO: implement
179 }
180
181 basic_istream<Char, Traits>& operator>>(long& x)
182 {
183 // TODO: implement
184 }
185
186 basic_istream<Char, Traits>& operator>>(unsigned long& x)
187 {
188 // TODO: implement
189 }
190
191 basic_istream<Char, Traits>& operator>>(long long& x)
192 {
193 // TODO: implement
194 }
195
196 basic_istream<Char, Traits>& operator>>(unsigned long long& x)
197 {
198 // TODO: implement
199 }
200
201 basic_istream<Char, Traits>& operator>>(float& x)
202 {
203 // TODO: implement
204 }
205
206 basic_istream<Char, Traits>& operator>>(double& x)
207 {
208 // TODO: implement
209 }
210
211 basic_istream<Char, Traits>& operator>>(long double& x)
212 {
213 // TODO: implement
214 }
215
216 basic_istream<Char, Traits>& operator>>(void*& p)
217 {
218 // TODO: implement
219 }
220
221 basic_istream<Char, Traits>& operator>>(basic_streambuf<Char, Traits>* sb)
222 {
223 // TODO: implement
224 }
225
226 /**
227 * 27.7.2.3, unformatted input:
228 * TODO: Once we have exceptions, implement
229 * 27.7.2.3 paragraph 1.
230 */
231
232 streamsize gcount() const
233 {
234 return gcount_;
235 }
236
237 int_type get()
238 {
239 gcount_ = 0;
240 sentry sen{*this, true};
241
242 if (sen)
243 {
244 auto res = this->rdbuf()->sbumpc();
245 if (!traits_type::eq_int_type(res, traits_type::eof()))
246 {
247 gcount_ = 1;
248 return res;
249 }
250
251 this->setstate(ios_base::failbit | ios_base::eofbit);
252 }
253
254 return traits_type::eof();
255 }
256
257 basic_istream<Char, Traits>& get(char_type& c)
258 {
259 auto res = get();
260 if (res != traits_type::eof())
261 c = traits_type::to_char_type(res);
262
263 return this;
264 }
265
266 basic_istream<Char, Traits>& get(char_type* s, streamsize n, char_type delim)
267 {
268 gcount_ = 0;
269 sentry sen{*this, true};
270
271 if (sen && n > 0)
272 {
273 while(gcount_ < n - 1)
274 {
275 auto c = this->rdbuf()->sbumpc();
276
277 if (traits_type::eq_int_type(c, traits_type::eof()))
278 {
279 this->setstate(ios_base::eofbit);
280 break;
281 }
282
283 s[gcount_++] = traits_type::to_char_type(c);
284
285 auto peek = traits_type::to_char_type(this->rdbuf()->sgetc());
286 if (traits_type::eq(peek, delim))
287 break;
288 }
289
290 if (gcount_ == 0)
291 this->setstate(ios_base::failbit);
292 s[n] = char_type{};
293 }
294
295 return *this;
296 }
297
298 basic_istream<Char, Traits>& get(char_type* s, streamsize n)
299 {
300 return get(s, n, this->widen('\n'));
301 }
302
303 basic_istream<Char, Traits>& get(basic_streambuf<Char, Traits>& sb)
304 {
305 get(sb, this->widen('\n'));
306 }
307
308 basic_istream<Char, Traits>& get(basic_streambuf<Char, Traits>& sb, char_type delim)
309 {
310 gcount_ = 0;
311 sentry sen{*this, true};
312
313 if (sen)
314 {
315 while (true)
316 {
317 auto i = this->rdbuf()->sgetc();
318 if (traits_type::eq_int_type(i, traits_type::eof()))
319 {
320 this->setstate(ios_base::eofbit);
321 break;
322 }
323
324 auto c = traits_type::to_char_type(i);
325 if (traits_type::eq(c, delim))
326 break;
327
328 auto insert_ret = sb.sputc(c);
329 if (traits_type::eq_int_type(insert_ret, traits_type::eof()))
330 break;
331
332 this->rdbuf()->sbumpc();
333 ++gcount_;
334 }
335
336 if (gcount_ == 0)
337 this->setstate(ios_base::failbit);
338 }
339
340 return *this;
341 }
342
343 basic_istream<Char, Traits>& getline(char_type* s, streamsize n)
344 {
345 return getline(s, n, this->widen('\n'));
346 }
347
348 basic_istream<Char, Traits>& getline(char_type* s, streamsize n, char_type delim)
349 {
350 gcount_ = 0;
351 sentry sen{*this, true};
352
353 if (sen)
354 {
355 while (true)
356 { // We have exactly specified order of checks, easier to do them in the body.
357 auto c = this->rdbuf()->sbumpc();
358
359 if (traits_type::eq_int_type(c, traits_type::eof()))
360 {
361 this->setstate(ios_base::eofbit);
362 break;
363 }
364
365 if (traits_type::eq_int_type(c, traits_type::to_int_type(delim)))
366 break;
367
368 if (n < 1 || gcount_ >= n - 1)
369 {
370 this->setstate(ios_base::failbit);
371 break;
372 }
373
374 s[gcount_++] = traits_type::to_char_type(c);
375 }
376
377 if (gcount_ == 0)
378 this->setstate(ios_base::failbit);
379 if (n > 0)
380 s[gcount_] = char_type{};
381 }
382
383 return *this;
384 }
385
386 basic_istream<Char, Traits>& ignore(streamsize n = 1, int_type delim = traits_type::eof())
387 {
388 sentry sen{*this, true};
389
390 if (sen)
391 {
392 streamsize i{};
393 while (n == numeric_limits<streamsize>::max() || i < n)
394 {
395 auto c = this->rdbuf()->sbumpc();
396
397 if (traits_type::eq_int_type(c, traits_type::eof()))
398 {
399 this->setstate(ios_base::eofbit);
400 break;
401 }
402
403 if (traits_type::eq_int_type(c, delim))
404 break;
405 }
406 }
407 }
408
409 int_type peek()
410 {
411 sentry sen{*this, true};
412
413 if (!this->good())
414 return traits_type::eof();
415 else
416 return this->rdbuf()->sgetc();
417 }
418
419 basic_istream<Char, Traits>& read(char_type* s, streamsize n)
420 {
421 gcount_ = 0;
422 sentry sen{*this, true};
423
424 if (!this->good())
425 {
426 this->setstate(ios_base::failbit);
427 return *this;
428 }
429
430 while (gcount_ < n)
431 {
432 auto c = this->rdbuf()->sbumpc();
433 if (traits_type::eq_int_type(c, traits_type::eof()))
434 {
435 this->setstate(ios_base::failbit | ios_base::eofbit);
436 break;
437 }
438
439 s[gcount_++] = traits_type::to_char_type(c);
440 }
441 }
442
443 streamsize readsome(char_type* s, streamsize n)
444 {
445 gcount_ = 0;
446 sentry sen{*this, true};
447
448 if (!this->good())
449 {
450 this->setstate(ios_base::failbit);
451 return streamsize{};
452 }
453
454 auto avail = this->rdbuf()->in_avail();
455 if (avail == -1)
456 {
457 this->setstate(ios_base::eofbit);
458 return streamsize{};
459 } else if (avail > 0)
460 {
461 auto count = (avail < n ? avail : n);
462 while (gcount_ < count)
463 s[gcount_++] = traits_type::to_char_type(this->rdbuf()->sbumpc());
464 }
465
466 return gcount_;
467 }
468
469 basic_istream<Char, Traits>& putback(char_type c)
470 {
471 clear(this->rdstate() & (~ios_base::eofbit));
472
473 gcount_ = 0;
474 sentry sen{*this, true};
475
476 if (!this->good())
477 {
478 this->setstate(ios_base::failbit);
479 return *this;
480 }
481
482 if (this->rdbuf())
483 {
484 auto ret = this->rdbuf()->sputbackc(c);
485 if (traits_type::eq_int_type(ret, traits_type::eof()))
486 this->setstate(ios_base::badbit);
487 }
488 else
489 this->setstate(ios_base::badbit);
490
491 return *this;
492 }
493
494 basic_istream<Char, Traits>& unget()
495 {
496 clear(this->rdstate() & (~ios_base::eofbit));
497
498 gcount_ = 0;
499 sentry sen{*this, true};
500
501 if (!this->good())
502 {
503 this->setstate(ios_base::failbit);
504 return *this;
505 }
506
507 if (this->rdbuf())
508 {
509 auto ret = this->rdbuf()->sungetc();
510 if (traits_type::eq_int_type(ret, traits_type::eof()))
511 this->setstate(ios_base::badbit);
512 }
513 else
514 this->setstate(ios_base::badbit);
515
516 return *this;
517 }
518
519 int sync()
520 {
521 sentry s{*this, true};
522
523 if (this->rdbuf())
524 {
525 auto ret = this->rdbuf()->pubsync();
526 if (ret == -1)
527 {
528 this->setstate(ios_base::badbit);
529 return -1;
530 }
531 else
532 return 0;
533 }
534 else
535 return -1;
536 }
537
538 pos_type tellg()
539 {
540 sentry s{*this, true};
541
542 if (this->fail())
543 return pos_type(-1);
544 else
545 return this->rdbuf()->pubseekoff(0, ios_base::cur, ios_base::in);
546 }
547
548 basic_istream<Char, Traits>& seekg(pos_type pos)
549 {
550 this->clear(this->rdstate() & (~ios_base::eofbit));
551
552 sentry sen{*this, true};
553
554 if (!this->fail())
555 this->rdbuf()->pubseekoff(pos, ios_base::in);
556 else
557 this->setstate(ios_base::failbit);
558
559 return *this;
560 }
561
562 basic_istream<Char, Traits>& seekg(off_type off, ios_base::seekdir dir)
563 {
564 sentry sen{*this, true};
565
566 if (!this->fail())
567 this->rdbuf()->pubseekoff(off, dir, ios_base::in);
568 else
569 this->setstate(ios_base::failbit);
570
571 return *this;
572 }
573
574 protected:
575 streamsize gcount_;
576
577 basic_istream(const basic_istream&) = delete;
578
579 basic_istream(basic_istream&& rhs)
580 {
581 gcount_ = rhs.gcout_;
582
583 basic_ios<Char, Traits>::move(rhs);
584
585 rhs.gcount_ = 0;
586 }
587
588 /**
589 * 27.7.2.1.2, assign/swap:
590 */
591
592 basic_istream& operator=(const basic_istream& rhs) = delete;
593
594 basic_istream& operator=(basic_istream&& rhs)
595 {
596 swap(rhs);
597
598 return *this;
599 }
600
601 void swap(basic_istream& rhs)
602 {
603 basic_ios<Char, Traits>::swap(rhs);
604 swap(gcount_, rhs.gcount_);
605 }
606 };
607
608 /**
609 * 27.7.2.2.3, character extraction templates:
610 */
611
612 template<class Char, class Traits>
613 basic_istream<Char, Traits>& operator>>(basic_istream<Char, Traits>& is,
614 Char& c)
615 {
616 // TODO: implement
617 }
618
619 template<class Char, class Traits>
620 basic_istream<Char, Traits>& operator>>(basic_istream<Char, Traits>& is,
621 unsigned char& c)
622 {
623 // TODO: implement
624 }
625
626 template<class Char, class Traits>
627 basic_istream<Char, Traits>& operator>>(basic_istream<Char, Traits>& is,
628 signed char& c)
629 {
630 // TODO: implement
631 }
632
633 template<class Char, class Traits>
634 basic_istream<Char, Traits>& operator>>(basic_istream<Char, Traits>& is,
635 Char* c)
636 {
637 // TODO: implement
638 }
639
640 template<class Char, class Traits>
641 basic_istream<Char, Traits>& operator>>(basic_istream<Char, Traits>& is,
642 unsigned char* c)
643 {
644 // TODO: implement
645 }
646
647 template<class Char, class Traits>
648 basic_istream<Char, Traits>& operator>>(basic_istream<Char, Traits>& is,
649 signed char* c)
650 {
651 // TODO: implement
652 }
653
654 /**
655 * 27.7.2.4, standard basic_istream manipulators:
656 */
657
658 template<class Char, class Traits = char_traits<Char>>
659 basic_istream<Char, Traits>& ws(basic_istream<Char, Traits>& is)
660 {
661 using sentry = typename basic_istream<Char, Traits>::sentry;
662 sentry sen{is, true};
663
664 if (sen)
665 {
666 const auto& ct = use_facet<ctype<Char>>(is.getloc());
667 while (true)
668 {
669 auto i = is.rdbuf()->sgetc();
670 if (Traits::eq_int_type(i, Traits::eof()))
671 {
672 is.setstate(ios_base::eofbit);
673 break;
674 }
675
676 auto c = Traits::to_char_type(i);
677 if (!ct.is(c, ct.space))
678 break;
679 else
680 is.rdbuf()->sbumpc();
681 }
682 }
683
684 return is;
685 }
686
687 using istream = basic_istream<char>;
688 using wistream = basic_istream<wchar_t>;
689
690 /**
691 * 27.7.2.5, class template basic_iostream:
692 */
693
694 template<class Char, class Traits>
695 class basic_iostream;
696
697 using iostream = basic_iostream<char>;
698 using wiostream = basic_iostream<wchar_t>;
699
700 /**
701 * 27.7.2.6, rvalue stream extraction:
702 */
703
704 template<class Char, class Traits, class T>
705 basic_istream<Char, Traits>& operator>>(basic_istream<Char, Traits>&& is, T& x)
706 {
707 is >> x;
708
709 return is;
710 }
711}
712
713#endif
Note: See TracBrowser for help on using the repository browser.