source: mainline/uspace/lib/cpp/include/__bits/io/ostream.hpp@ 7dcce0a

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

cpp: abort and report when an unimplemented function is called

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