source: mainline/uspace/lib/cpp/include/impl/ios.hpp@ 2e0256b

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

cpp: added an internal buffer to ios objects for conversions to avoid unnecessary allocations

  • Property mode set to 100644
File size: 17.0 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_IOS
30#define LIBCPP_IOS
31
32#include <cstdlib>
33#include <internal/locale.hpp>
34#include <internal/locale/ctype.hpp>
35#include <iosfwd>
36#include <system_error>
37#include <utility>
38#include <vector>
39
40namespace std
41{
42 using streamoff = long long;
43 using streamsize = ssize_t;
44
45 /**
46 * 27.5.3, ios_base:
47 */
48
49 class ios_base
50 {
51 public:
52 virtual ~ios_base();
53
54 ios_base(const ios_base&) = delete;
55 ios_base& operator=(const ios_base&) = delete;
56
57 /**
58 * 27.5.3.1.1, failure:
59 */
60
61 class failure: public system_error
62 {
63 // TODO: implement
64 };
65
66 /**
67 * 27.5.3.1.2, fmtflags:
68 */
69
70 using fmtflags = uint16_t;
71 static constexpr fmtflags boolalpha = 0b0000'0000'0000'0001;
72 static constexpr fmtflags dec = 0b0000'0000'0000'0010;
73 static constexpr fmtflags fixed = 0b0000'0000'0000'0100;
74 static constexpr fmtflags hex = 0b0000'0000'0000'1000;
75 static constexpr fmtflags internal = 0b0000'0000'0001'0000;
76 static constexpr fmtflags left = 0b0000'0000'0010'0000;
77 static constexpr fmtflags oct = 0b0000'0000'0100'0000;
78 static constexpr fmtflags right = 0b0000'0000'1000'0000;
79 static constexpr fmtflags scientific = 0b0000'0001'0000'0000;
80 static constexpr fmtflags showbase = 0b0000'0010'0000'0000;
81 static constexpr fmtflags showpoint = 0b0000'0100'0000'0000;
82 static constexpr fmtflags showpos = 0b0000'1000'0000'0000;
83 static constexpr fmtflags skipws = 0b0001'0000'0000'0000;
84 static constexpr fmtflags unitbuf = 0b0010'0000'0000'0000;
85 static constexpr fmtflags uppercase = 0b0100'0000'0000'0000;
86 static constexpr fmtflags adjustfield = left | right | internal;
87 static constexpr fmtflags basefield = dec | oct | hex;
88 static constexpr fmtflags floatfield = scientific | fixed;
89
90 /**
91 * 27.5.3.1.3, iostate:
92 */
93
94 using iostate = uint8_t;
95 static constexpr iostate badbit = 0b0001;
96 static constexpr iostate eofbit = 0b0010;
97 static constexpr iostate failbit = 0b0100;
98 static constexpr iostate goodbit = 0b0000;
99
100 /**
101 * 27.5.3.1.4, openmode:
102 */
103
104 using openmode = uint8_t;
105 static constexpr openmode app = 0b00'0001;
106 static constexpr openmode ate = 0b00'0010;
107 static constexpr openmode binary = 0b00'0100;
108 static constexpr openmode in = 0b00'1000;
109 static constexpr openmode out = 0b01'0000;
110 static constexpr openmode trunc = 0b10'0000;
111
112 /**
113 * 27.5.3.1.5, seekdir:
114 */
115
116 using seekdir = uint8_t;
117 static constexpr seekdir beg = 0b001;
118 static constexpr seekdir cur = 0b010;
119 static constexpr seekdir end = 0b100;
120
121 /**
122 * 27.5.3.1.6, class Init:
123 */
124
125 class Init
126 {
127 public:
128 Init();
129 ~Init();
130
131 private:
132 static int init_cnt_;
133 };
134
135 /**
136 * 27.5.3.2, fmtflags state:
137 */
138
139 fmtflags flags() const;
140 fmtflags flags(fmtflags fmtfl);
141 fmtflags setf(fmtflags fmtfl);
142 fmtflags setf(fmtflags fmtfl, fmtflags mask);
143 void unsetf(fmtflags mask);
144
145 streamsize precision() const;
146 streamsize precision(streamsize prec);
147 streamsize width() const;
148 streamsize width(streamsize wide);
149
150 /**
151 * 27.5.3.3, locales:
152 */
153
154 locale imbue(const locale& loc);
155 locale getloc() const;
156
157 /**
158 * 27.5.3.5, storage:
159 */
160
161 static int xalloc()
162 {
163 // TODO: Concurrent access to this function
164 // by multiple threads shall not result
165 // in a data race.
166 return index_++;
167 }
168
169 long& iword(int index);
170 void*& pword(int index);
171
172 /**
173 * 27.5.3.6, callbacks:
174 */
175
176 enum event
177 {
178 erase_event,
179 imbue_event,
180 copyfmt_event
181 };
182
183 using event_callback = void (*)(event, ios_base&, int);
184 void register_callback(event_callback fn, int index);
185
186 static bool sync_with_stdio(bool sync = true)
187 {
188 auto old = sync_;
189 sync_ = sync;
190
191 return old;
192 }
193
194 protected:
195 ios_base();
196
197 static int index_;
198 static bool sync_;
199
200 static long ierror_;
201 static void* perror_;
202 static constexpr size_t initial_size_{10};
203
204 long* iarray_;
205 void** parray_;
206 size_t iarray_size_;
207 size_t parray_size_;
208
209 fmtflags flags_;
210 streamsize precision_;
211 streamsize width_;
212
213 locale locale_;
214
215 vector<pair<event_callback, int>> callbacks_;
216
217 private:
218 static constexpr size_t buffer_size_{64};
219 char buffer_[buffer_size_];
220
221 template<class Char, class Iterator>
222 friend class num_put;
223 };
224
225 /**
226 * 27.5.4, fpos:
227 */
228
229 template<class State>
230 class fpos
231 {
232 public:
233 State state() const
234 {
235 return state_;
236 }
237
238 void state(State st)
239 {
240 state_ = st;
241 }
242
243 private:
244 State state_;
245 };
246
247 /**
248 * 27.5.4.2, fpos requirements:
249 */
250
251 // TODO: implement
252
253 /**
254 * 27.5.5, basic_ios:
255 */
256
257 template<class Char, class Traits>
258 class basic_ios: public ios_base
259 {
260 public:
261 using traits_type = Traits;
262 using char_type = Char;
263 using int_type = typename traits_type::int_type;
264 using pos_type = typename traits_type::pos_type;
265 using off_type = typename traits_type::off_type;
266
267 basic_ios(const basic_ios&) = delete;
268 basic_ios& operator=(const basic_ios&) = delete;
269
270 explicit operator bool() const
271 {
272 return !fail();
273 }
274
275 bool operator!() const
276 {
277 return fail();
278 }
279
280 iostate rdstate() const
281 {
282 return rdstate_;
283 }
284
285 void clear(iostate state = goodbit)
286 {
287 if (rdbuf_)
288 rdstate_ = state;
289 else
290 rdstate_ = state | badbit;
291
292 if (((state | (rdbuf_ ? goodbit : badbit)) & exceptions_) == 0)
293 return;
294 // TODO: Else throw failure.
295 return;
296 }
297
298 void setstate(iostate state)
299 {
300 clear(rdstate_ | state);
301 }
302
303 bool good() const
304 {
305 return rdstate_ == 0;
306 }
307
308 bool eof() const
309 {
310 return (rdstate_ & eofbit) != 0;
311 }
312
313 bool fail() const
314 {
315 return (rdstate_ & (failbit | badbit)) != 0;
316 }
317
318 bool bad() const
319 {
320 return (rdstate_ & badbit) != 0;
321 }
322
323 iostate exceptions() const
324 {
325 return exceptions_;
326 }
327
328 void exceptions(iostate except)
329 {
330 exceptions_ = except;
331 clear(rdstate_);
332 }
333
334 /**
335 * 27.5.5.2, constructor/destructor:
336 */
337
338 explicit basic_ios(basic_streambuf<Char, Traits>* sb)
339 {
340 init(sb);
341 }
342
343 virtual ~basic_ios()
344 { /* DUMMY BODY */ }
345
346 /**
347 * 27.5.5.3, members:
348 */
349
350 basic_ostream<Char, Traits>* tie() const
351 {
352 return tie_;
353 }
354
355 basic_ostream<Char, Traits>* tie(basic_ostream<Char, Traits>* tiestr)
356 {
357 auto old = tie_;
358 tie_ = tiestr;
359
360 return old;
361 }
362
363 basic_streambuf<Char, Traits>* rdbuf() const
364 {
365 return rdbuf_;
366 }
367
368 basic_streambuf<Char, Traits>* rdbuf(basic_streambuf<Char, Traits>* sb)
369 {
370 auto old = rdbuf_;
371 rdbuf_ = sb;
372
373 clear();
374
375 return old;
376 }
377
378 basic_ios& copyfmt(const basic_ios& rhs)
379 {
380 if (this == &rhs)
381 return *this;
382
383 for (auto& callback: callbacks_)
384 callback.first(erase_event, *this, index_);
385
386 tie_ = rhs.tie_;
387 flags_ = rhs.flags_;
388 width_ = rhs.width_;
389 precision_ = rhs.precision_;
390 fill_ = rhs.fill_;
391 locale_ = rhs.locale_;
392
393 delete[] iarray_;
394 iarray_size_ = rhs.iarray_size_;
395 iarray_ = new long[iarray_size_];
396
397 for (size_t i = 0; i < iarray_size_; ++i)
398 iarray_[i] = rhs.iarray_[i];
399
400 delete[] parray_;
401 parray_size_ = rhs.parray_size_;
402 parray_ = new long[parray_size_];
403
404 for (size_t i = 0; i < parray_size_; ++i)
405 parray_[i] = rhs.parray_[i];
406
407 for (auto& callback: callbacks_)
408 callback.first(copyfmt_event, *this, index_);
409
410 exceptions(rhs.exceptions());
411 }
412
413 char_type fill() const
414 {
415 return fill_;
416 }
417
418 char_type fill(char_type c)
419 {
420 char_type old;
421 traits_type::assign(old, fill_);
422 traits_type::assign(fill_, c);
423
424 return old;
425 }
426
427 locale imbue(const locale& loc)
428 {
429 auto res = ios_base::imbue(loc);
430
431 if (rdbuf_)
432 rdbuf_->pubimbue(loc);
433
434 return res;
435 }
436
437 char narrow(char_type c, char def) const
438 {
439 return use_facet<ctype<char_type>>(locale_).narrow(c, def);
440 }
441
442 char_type widen(char c) const
443 {
444 return use_facet<ctype<char_type>>(locale_).widen(c);
445 }
446
447 protected:
448 basic_ios()
449 { /* DUMMY BODY */ }
450
451 void init(basic_streambuf<Char, Traits>* sb)
452 {
453 // Initialized according to Table 128.
454 rdbuf_ = sb;
455 tie_ = nullptr;
456 rdstate_ = sb ? goodbit : badbit;
457 exceptions_ = goodbit;
458 flags(skipws | dec);
459
460 width(0);
461 precision(6);
462
463 fill_ = widen(' ');
464 locale_ = locale();
465
466 iarray_ = nullptr;
467 parray_ = nullptr;
468 }
469
470 void move(basic_ios& rhs)
471 {
472 rdbuf_ = nullptr; // rhs keeps it!
473 tie_ = rhs.tie_;
474 exceptions_ = rhs.exceptions_;
475 flags_ = rhs.flags_;
476 width_ = rhs.width_;
477 precision_ = rhs.precision_;
478 fill_ = rhs.fill_;
479 locale_ = move(rhs.locale_);
480 rdstate_ = rhs.rdstate_;
481 callbacks_ = move(rhs.callbacks_);
482
483 delete[] iarray_;
484 iarray_ = rhs.iarray_;
485 iarray_size_ = rhs.iarray_size_;
486
487 delete[] parray_;
488 parray_ = rhs.parray_;
489 parray_size_ = rhs.parray_size_;
490
491 rhs.tie_ = nullptr;
492 rhs.iarray_ = nullptr;
493 rhs.parray_ = nullptr;
494 }
495
496 void move(basic_ios&& rhs)
497 {
498 rdbuf_ = nullptr; // rhs keeps it!
499 tie_ = rhs.tie_;
500 exceptions_ = rhs.exceptions_;
501 flags_ = rhs.flags_;
502 width_ = rhs.width_;
503 precision_ = rhs.precision_;
504 fill_ = rhs.fill_;
505 locale_ = move(rhs.locale_);
506 rdstate_ = rhs.rdstate_;
507 callbacks_.swap(rhs.callbacks_);
508
509 delete[] iarray_;
510 iarray_ = rhs.iarray_;
511 iarray_size_ = rhs.iarray_size_;
512
513 delete[] parray_;
514 parray_ = rhs.parray_;
515 parray_size_ = rhs.parray_size_;
516
517 rhs.tie_ = nullptr;
518 rhs.iarray_ = nullptr;
519 rhs.parray_ = nullptr;
520 }
521
522 void swap(basic_ios& rhs) noexcept
523 {
524 // Swap everything but rdbuf_.
525 swap(tie_, rhs.tie_);
526 swap(exceptions_, rhs.exceptions_);
527 swap(flags_, rhs.flags_);
528 swap(width_, rhs.width_);
529 swap(precision_, rhs.precision_);
530 swap(fill_, rhs.fill_);
531 swap(locale_, rhs.locale_);
532 swap(rdstate_, rhs.rdstate_);
533 swap(callbacks_, rhs.callbacks_);
534 swap(iarray_);
535 swap(iarray_size_);
536 swap(parray_);
537 swap(parray_size_);
538 }
539
540 void set_rdbuf(basic_streambuf<Char, Traits>* sb)
541 {
542 // No call to clear is intentional.
543 rdbuf_ = sb;
544 }
545
546 private:
547 basic_streambuf<Char, Traits>* rdbuf_;
548 basic_ostream<Char, Traits>* tie_;
549 iostate rdstate_;
550 iostate exceptions_;
551 char_type fill_;
552 };
553
554 /**
555 * 27.5.6, ios_base manipulators:
556 */
557
558 /**
559 * 27.5.6.1, fmtflags manipulators:
560 */
561
562 ios_base& boolalpha(ios_base& str);
563 ios_base& noboolalpha(ios_base& str);
564 ios_base& showbase(ios_base& str);
565 ios_base& noshowbase(ios_base& str);
566 ios_base& showpoint(ios_base& str);
567 ios_base& noshowpoint(ios_base& str);
568 ios_base& showpos(ios_base& str);
569 ios_base& noshowpos(ios_base& str);
570 ios_base& skipws(ios_base& str);
571 ios_base& noskipws(ios_base& str);
572 ios_base& uppercase(ios_base& str);
573 ios_base& nouppercase(ios_base& str);
574 ios_base& unitbuf(ios_base& str);
575 ios_base& nounitbuf(ios_base& str);
576
577 /**
578 * 27.5.6.2, adjustfield manipulators:
579 */
580
581 ios_base& internal(ios_base& str);
582 ios_base& left(ios_base& str);
583 ios_base& right(ios_base& str);
584
585 /**
586 * 27.5.6.3, basefield manupulators:
587 */
588
589 ios_base& dec(ios_base& str);
590 ios_base& hex(ios_base& str);
591 ios_base& oct(ios_base& str);
592
593 /**
594 * 27.5.6.4, floatfield manupulators:
595 */
596
597 ios_base& fixed(ios_base& str);
598 ios_base& scientific(ios_base& str);
599 ios_base& hexfloat(ios_base& str);
600 ios_base& defaultfloat(ios_base& str);
601
602 /**
603 * 27.5.6.5, error reporting:
604 */
605
606 // TODO: implement
607}
608
609#endif
Note: See TracBrowser for help on using the repository browser.