source: mainline/uspace/lib/cpp/include/impl/ostream.hpp@ 9396c52

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

cpp: implemented most of the unformatted and formatted output for ostream and also standard ostream manipulators

  • Property mode set to 100644
File size: 23.8 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_OSTREAM
30#define LIBCPP_OSTREAM
31
32#include <ios>
33#include <iosfwd>
34#include <locale>
35
36namespace std
37{
38 /**
39 * 27.7.3.1, class template basic_ostream:
40 */
41
42 template<class Char, class Traits>
43 class basic_ostream: virtual public basic_ios<Char, Traits>
44 {
45 public:
46 using char_type = Char;
47 using traits_type = Traits;
48 using int_type = typename traits_type::int_type;
49 using pos_type = typename traits_type::pos_type;
50 using off_type = typename traits_type::off_type;
51
52 /**
53 * 27.7.3.2, constructor/destructor:
54 */
55
56 explicit basic_ostream(basic_streambuf<char_type, traits_type>* sb)
57 {
58 basic_ios<Char, Traits>::init(sb);
59 }
60
61 virtual ~basic_ostream()
62 { /* DUMMY BODY */ }
63
64 /**
65 * 27.7.3.4, prefix/suffix:
66 */
67
68 class sentry
69 {
70 public:
71 explicit sentry(basic_ostream<Char, Traits>& os)
72 : os_{os}, ok_{false}
73 {
74 if (os.good())
75 {
76 if (os.tie())
77 os.tie()->flush();
78 }
79
80 ok_ = os.good();
81 }
82
83 ~sentry()
84 {
85 if ((os_.flags() & ios_base::unitbuf) && os_.good())
86 {
87 auto ret = os_.rdbuf()->pubsync();
88 (void)ret;
89 // TODO: if ret == -1, set badbit in rdstate
90 }
91 }
92
93 explicit operator bool() const
94 {
95 return ok_;
96 }
97
98 sentry(const sentry&) = delete;
99 sentry& operator=(const sentry&) = delete;
100
101 private:
102 basic_ostream<Char, Traits>& os_;
103 bool ok_;
104 };
105
106 /**
107 * 27.7.3.6, formatted output:
108 */
109
110 basic_ostream<Char, Traits>& operator<<(
111 basic_ostream<Char, Traits>& (*pf)(basic_ostream<Char, Traits>&)
112 )
113 {
114 return pf(*this);
115 }
116
117 basic_ostream<Char, Traits>& operator<<(
118 basic_ios<Char, Traits>& (*pf)(basic_ios<Char, Traits>&)
119 )
120 {
121 pf(*this);
122
123 return *this;
124 }
125
126 basic_ostream<Char, Traits>& operator<<(
127 ios_base& (*pf)(ios_base&)
128 )
129 {
130 pf(*this);
131
132 return *this;
133 }
134
135 basic_ostream<Char, Traits>& operator<<(bool x)
136 {
137 sentry sen{*this};
138
139 if (sen)
140 {
141 bool failed = use_facet<
142 num_put<char_type, ostreambuf_iterator<char_type, traits_type>>
143 >(this->getloc()).put(*this, *this, this->fill(), x).failed();
144
145 if (failed)
146 this->setstate(ios_base::badbit);
147 }
148
149 return *this;
150 }
151
152 basic_ostream<Char, Traits>& operator<<(short x)
153 {
154 sentry sen{*this};
155
156 if (sen)
157 {
158 auto basefield = (this->flags() & ios_base::basefield);
159 bool failed = use_facet<
160 num_put<char_type, ostreambuf_iterator<char_type, traits_type>>
161 >(this->getloc()).put(*this, *this, this->fill(),
162 (basefield == ios_base::oct || basefield == ios_base::hex)
163 ? static_cast<long>(static_cast<unsigned short>(x))
164 : static_cast<long>(x)).failed();
165
166 if (failed)
167 this->setstate(ios_base::badbit);
168 }
169
170 return *this;
171 }
172
173 basic_ostream<Char, Traits>& operator<<(unsigned short x)
174 {
175 sentry sen{*this};
176
177 if (sen)
178 {
179 bool failed = use_facet<
180 num_put<char_type, ostreambuf_iterator<char_type, traits_type>>
181 >(this->getloc()).put(*this, *this, this->fill(),
182 static_cast<unsigned long>(x)).failed();
183
184 if (failed)
185 this->setstate(ios_base::badbit);
186 }
187
188 return *this;
189 }
190
191 basic_ostream<Char, Traits>& operator<<(int x)
192 {
193 sentry sen{*this};
194
195 if (sen)
196 {
197 auto basefield = (this->flags() & ios_base::basefield);
198 bool failed = use_facet<
199 num_put<char_type, ostreambuf_iterator<char_type, traits_type>>
200 >(this->getloc()).put(*this, *this, this->fill(),
201 (basefield == ios_base::oct || basefield == ios_base::hex)
202 ? static_cast<long>(static_cast<unsigned int>(x))
203 : static_cast<long>(x)).failed();
204
205 if (failed)
206 this->setstate(ios_base::badbit);
207 }
208
209 return *this;
210 }
211
212 basic_ostream<Char, Traits>& operator<<(unsigned int x)
213 {
214 sentry sen{*this};
215
216 if (sen)
217 {
218 bool failed = use_facet<
219 num_put<char_type, ostreambuf_iterator<char_type, traits_type>>
220 >(this->getloc()).put(*this, *this, this->fill(),
221 static_cast<unsigned long>(x)).failed();
222
223 if (failed)
224 this->setstate(ios_base::badbit);
225 }
226
227 return *this;
228 }
229
230 basic_ostream<Char, Traits>& operator<<(long x)
231 {
232 sentry sen{*this};
233
234 if (sen)
235 {
236 bool failed = use_facet<
237 num_put<char_type, ostreambuf_iterator<char_type, traits_type>>
238 >(this->getloc()).put(*this, *this, this->fill(), x).failed();
239
240 if (failed)
241 this->setstate(ios_base::badbit);
242 }
243
244 return *this;
245 }
246
247 basic_ostream<Char, Traits>& operator<<(unsigned long x)
248 {
249 sentry sen{*this};
250
251 if (sen)
252 {
253 bool failed = use_facet<
254 num_put<char_type, ostreambuf_iterator<char_type, traits_type>>
255 >(this->getloc()).put(*this, *this, this->fill(), x).failed();
256
257 if (failed)
258 this->setstate(ios_base::badbit);
259 }
260
261 return *this;
262 }
263
264 basic_ostream<Char, Traits>& operator<<(long long x)
265 {
266 sentry sen{*this};
267
268 if (sen)
269 {
270 bool failed = use_facet<
271 num_put<char_type, ostreambuf_iterator<char_type, traits_type>>
272 >(this->getloc()).put(*this, *this, this->fill(), x).failed();
273
274 if (failed)
275 this->setstate(ios_base::badbit);
276 }
277
278 return *this;
279 }
280
281 basic_ostream<Char, Traits>& operator<<(unsigned long long x)
282 {
283 sentry sen{*this};
284
285 if (sen)
286 {
287 bool failed = use_facet<
288 num_put<char_type, ostreambuf_iterator<char_type, traits_type>>
289 >(this->getloc()).put(*this, *this, this->fill(), x).failed();
290
291 if (failed)
292 this->setstate(ios_base::badbit);
293 }
294
295 return *this;
296 }
297
298 basic_ostream<Char, Traits>& operator<<(float x)
299 {
300 sentry sen{*this};
301
302 if (sen)
303 {
304 bool failed = use_facet<
305 num_put<char_type, ostreambuf_iterator<char_type, traits_type>>
306 >(this->getloc()).put(*this, *this, this->fill(), static_cast<double>(x)).failed();
307
308 if (failed)
309 this->setstate(ios_base::badbit);
310 }
311
312 return *this;
313 }
314
315 basic_ostream<Char, Traits>& operator<<(double x)
316 {
317 sentry sen{*this};
318
319 if (sen)
320 {
321 bool failed = use_facet<
322 num_put<char_type, ostreambuf_iterator<char_type, traits_type>>
323 >(this->getloc()).put(*this, *this, this->fill(), x).failed();
324
325 if (failed)
326 this->setstate(ios_base::badbit);
327 }
328
329 return *this;
330 }
331
332 basic_ostream<Char, Traits>& operator<<(long double x)
333 {
334 sentry sen{*this};
335
336 if (sen)
337 {
338 bool failed = use_facet<
339 num_put<char_type, ostreambuf_iterator<char_type, traits_type>>
340 >(this->getloc()).put(*this, *this, this->fill(), x).failed();
341
342 if (failed)
343 this->setstate(ios_base::badbit);
344 }
345
346 return *this;
347 }
348
349 basic_ostream<Char, Traits>& operator<<(const void* p)
350 {
351 sentry sen{*this};
352
353 if (sen)
354 {
355 bool failed = use_facet<
356 num_put<char_type, ostreambuf_iterator<char_type, traits_type>>
357 >(this->getloc()).put(*this, *this, this->fill(), p).failed();
358
359 if (failed)
360 this->setstate(ios_base::badbit);
361 }
362
363 return *this;
364 }
365
366 basic_ostream<Char, Traits>& operator<<(basic_streambuf<Char, Traits>* sb)
367 {
368 if (!sb)
369 return *this;
370
371 sentry sen{*this};
372
373 if (sen)
374 {
375 size_t count{};
376
377 int_type c = sb->sgetc();
378 while (!traits_type::eq_int_type(c, traits_type::eof()))
379 {
380 this->put(traits_type::to_char_type(c));
381
382 if (!(*this))
383 break;
384
385 ++count;
386 sb->sbumpc();
387 c = sb->sgetc();
388 }
389
390 if (count == 0)
391 this->setstate(ios_base::failbit);
392 }
393
394 return *this;
395 }
396
397 /**
398 * 27.7.3.7, unformatted output:
399 * TODO: when we have exceptions, complete these
400 */
401
402 basic_ostream<Char, Traits>& put(char_type c)
403 {
404 sentry sen{*this};
405
406 if (sen)
407 {
408 auto ret = this->rdbuf()->sputc(c);
409 if (traits_type::eq_int_type(ret, traits_type::eof()))
410 this->setstate(ios_base::badbit);
411 }
412
413 return *this;
414 }
415
416 basic_ostream<Char, Traits>& write(const char_type* s, streamsize n)
417 {
418 sentry sen{*this};
419
420 if (sen)
421 {
422 for (streamsize i = 0; i < n; ++i)
423 {
424 auto ret = this->rdbuf()->sputc(s[i]);
425 if (traits_type::eq_int_type(ret, traits_type::eof()))
426 {
427 this->setstate(ios_base::badbit);
428 break;
429 }
430 }
431 }
432
433 return *this;
434 }
435
436 basic_ostream<Char, Traits>& flush()
437 {
438 if (this->rdbuf())
439 {
440 sentry sen{*this};
441
442 if (sen)
443 {
444 auto ret = this->rdbuf()->pubsync();
445 if (ret == -1)
446 this->setstate(ios_base::badbit);
447 }
448 }
449
450 return *this;
451 }
452
453 /**
454 * 27.7.3.5, seeks:
455 */
456
457 pos_type tellp()
458 {
459 // TODO: implement
460 return pos_type{};
461 }
462
463 basic_ostream<Char, Traits>& seekp(pos_type pos)
464 {
465 // TODO: implement
466 return *this;
467 }
468
469 basic_ostream<Char, Traits>& seekp(off_type off, ios_base::seekdir dir)
470 {
471 // TODO: implement
472 return *this;
473 }
474
475 protected:
476 basic_ostream(const basic_ostream&) = delete;
477
478 basic_ostream(basic_ostream&& other)
479 {
480 basic_ios<Char, Traits>::move(other);
481 }
482
483 /**
484 * 27.7.3.3, assign/swap:
485 */
486
487 basic_ostream& operator=(const basic_ostream&) = delete;
488
489 basic_ostream& operator=(basic_ostream&& other)
490 {
491 swap(other);
492
493 return *this;
494 }
495
496 void swap(basic_ostream& rhs)
497 {
498 basic_ios<Char, Traits>::swap(rhs);
499 }
500 };
501
502 using ostream = basic_ostream<char>;
503 using wostream = basic_ostream<wchar_t>;
504
505 /**
506 * 27.7.6.3.4, character inserter function templates:
507 */
508
509 template<class Char, class Traits>
510 basic_ostream<Char, Traits>& operator<<(basic_ostream<Char, Traits>& os,
511 Char c)
512 {
513 typename basic_ostream<Char, Traits>::sentry sen{os};
514
515 if (sen)
516 {
517 if (os.width() > 0)
518 {
519 if ((os.flags() & ios_base::adjustfield) != ios_base::left)
520 {
521 for (decltype(os.width()) i = 0; i < os.width(); ++i)
522 os.put(os.fill());
523 os.put(c);
524 }
525 else
526 {
527 os.put(c);
528 for (decltype(os.width()) i = 0; i < os.width(); ++i)
529 os.put(os.fill());
530 }
531 }
532 else
533 os.put(c);
534
535 os.width(0);
536 }
537
538 return os;
539 }
540
541 template<class Char, class Traits>
542 basic_ostream<Char, Traits>& operator<<(basic_ostream<Char, Traits>& os,
543 char c)
544 {
545 typename basic_ostream<Char, Traits>::sentry sen{os};
546
547 if (sen)
548 {
549 if (os.width() > 0)
550 {
551 if ((os.flags() & ios_base::adjustfield) != ios_base::left)
552 {
553 for (decltype(os.width()) i = 0; i < os.width(); ++i)
554 os.put(os.fill());
555 os.put(os.widen(c));
556 }
557 else
558 {
559 os.put(os.widen(c));
560 for (decltype(os.width()) i = 0; i < os.width(); ++i)
561 os.put(os.fill());
562 }
563 }
564 else
565 os.put(os.widen(c));
566
567 os.width(0);
568 }
569 return os;
570 }
571
572 template<class Traits>
573 basic_ostream<char, Traits>& operator<<(basic_ostream<char, Traits>& os,
574 char c)
575 {
576 typename basic_ostream<char, Traits>::sentry sen{os};
577
578 if (sen)
579 {
580 if (os.width() > 0)
581 {
582 if ((os.flags() & ios_base::adjustfield) != ios_base::left)
583 {
584 for (decltype(os.width()) i = 0; i < os.width(); ++i)
585 os.put(os.fill());
586 os.put(c);
587 }
588 else
589 {
590 os.put(c);
591 for (decltype(os.width()) i = 0; i < os.width(); ++i)
592 os.put(os.fill());
593 }
594 }
595 else
596 os.put(c);
597
598 os.width(0);
599 }
600
601 return os;
602 }
603
604 template<class Traits>
605 basic_ostream<char, Traits>& operator<<(basic_ostream<char, Traits>& os,
606 signed char c)
607 {
608 typename basic_ostream<char, Traits>::sentry sen{os};
609
610 if (sen)
611 {
612 if (os.width() > 0)
613 {
614 if ((os.flags() & ios_base::adjustfield) != ios_base::left)
615 {
616 for (decltype(os.width()) i = 0; i < os.width(); ++i)
617 os.put(os.fill());
618 os.put(c);
619 }
620 else
621 {
622 os.put(c);
623 for (decltype(os.width()) i = 0; i < os.width(); ++i)
624 os.put(os.fill());
625 }
626 }
627 else
628 os.put(c);
629
630 os.width(0);
631 }
632
633 return os;
634 }
635
636 template<class Traits>
637 basic_ostream<char, Traits>& operator<<(basic_ostream<char, Traits>& os,
638 unsigned char c)
639 {
640 typename basic_ostream<char, Traits>::sentry sen{os};
641
642 if (sen)
643 {
644 if (os.width() > 0)
645 {
646 if ((os.flags() & ios_base::adjustfield) != ios_base::left)
647 {
648 for (decltype(os.width()) i = 0; i < os.width(); ++i)
649 os.put(os.fill());
650 os.put(c);
651 }
652 else
653 {
654 os.put(c);
655 for (decltype(os.width()) i = 0; i < os.width(); ++i)
656 os.put(os.fill());
657 }
658 }
659 else
660 os.put(c);
661
662 os.width(0);
663 }
664
665 return os;
666 }
667
668 namespace aux
669 {
670 template<class Char, class Traits>
671 basic_ostream<Char, Traits>& insert(basic_ostream<Char, Traits>& os,
672 const Char* str, size_t len)
673 {
674 if (os.width() > 0 && static_cast<size_t>(os.width()) > len)
675 {
676 size_t to_pad = (static_cast<size_t>(os.width()) - len);
677
678 if ((os.flags() & ios_base::adjustfield) != ios_base::left)
679 {
680 for (size_t i = 0; i < to_pad; ++i)
681 os.put(os.fill());
682 for (size_t i = 0; i < len; ++i)
683 os.put(os.widen(str[i]));
684 }
685 else
686 {
687 for (size_t i = 0; i < len; ++i)
688 os.put(os.widen(str[i]));
689 for (size_t i = 0; i < to_pad; ++i)
690 os.put(os.fill());
691 }
692 }
693 else
694 {
695 for (size_t i = 0; i < len; ++i)
696 os.put(os.widen(str[i]));
697 }
698
699 os.width(0);
700 return os;
701 }
702 }
703
704 template<class Char, class Traits>
705 basic_ostream<Char, Traits>& operator<<(basic_ostream<Char, Traits>& os,
706 const Char* str)
707 {
708 typename basic_ostream<Char, Traits>::sentry sen{os};
709
710 auto len = Traits::length(str);
711
712 return aux::insert(os, str, len);
713 }
714
715 template<class Char, class Traits>
716 basic_ostream<Char, Traits>& operator<<(basic_ostream<Char, Traits>& os,
717 const char* str)
718 {
719 typename basic_ostream<Char, Traits>::sentry sen{os};
720
721 auto len = std::char_traits<char>::length(str);
722
723 return aux::insert(os, str, len);
724 }
725
726 template<class Traits>
727 basic_ostream<char, Traits>& operator<<(basic_ostream<char, Traits>& os,
728 const char* str)
729 {
730 typename basic_ostream<char, Traits>::sentry sen{os};
731
732 if (sen)
733 {
734 auto len = Traits::length(str);
735
736 return aux::insert(os, str, len);
737 }
738 else
739 return os;
740 }
741
742 template<class Traits>
743 basic_ostream<char, Traits>& operator<<(basic_ostream<char, Traits>& os,
744 const signed char* str)
745 {
746 typename basic_ostream<char, Traits>::sentry sen{os};
747
748 if (sen)
749 {
750 auto len = Traits::length(reinterpret_cast<const char*>(str));
751
752 return aux::insert(os, str, len);
753 }
754 else
755 return os;
756 }
757
758 template<class Traits>
759 basic_ostream<char, Traits>& operator<<(basic_ostream<char, Traits>& os,
760 const unsigned char* str)
761 {
762 typename basic_ostream<char, Traits>::sentry sen{os};
763
764 if (sen)
765 {
766 auto len = Traits::length(reinterpret_cast<const char*>(str));
767
768 return aux::insert(os, str, len);
769 }
770 else
771 return os;
772 }
773
774 /**
775 * 27.7.3.8, standard basic_ostream manipulators:
776 */
777
778 template<class Char, class Traits = char_traits<Char>>
779 basic_ostream<Char, Traits>& endl(basic_ostream<Char, Traits>& os)
780 {
781 os.put(os.widen('\n'));
782 os.flush();
783
784 return os;
785 }
786
787 template<class Char, class Traits = char_traits<Char>>
788 basic_ostream<Char, Traits>& ends(basic_ostream<Char, Traits>& os)
789 {
790 os.put(Char{});
791
792 return os;
793 }
794
795 template<class Char, class Traits = char_traits<Char>>
796 basic_ostream<Char, Traits>& flush(basic_ostream<Char, Traits>& os)
797 {
798 os.flush();
799
800 return os;
801 }
802
803 template<class Char, class Traits = char_traits<Char>, class T>
804 basic_ostream<Char, Traits>& operator<<(basic_ostream<Char, Traits>&& os, const T& x)
805 {
806 os << x;
807
808 return os;
809 }
810}
811
812#endif
813
Note: See TracBrowser for help on using the repository browser.