source: mainline/uspace/lib/cpp/include/impl/sstream.hpp@ eaabd7d

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

cpp: fixed bugs found by the tests

  • Property mode set to 100644
File size: 18.0 KB
RevLine 
[6c242c3]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_SSTREAM
30#define LIBCPP_SSTREAM
31
32#include <ios>
33#include <iosfwd>
[eaabd7d]34#include <iostream>
[6c242c3]35#include <streambuf>
36#include <string>
37
38namespace std
39{
40 /**
41 * 27.8.2, class template basic_stringbuf:
42 */
43
44 template<class Char, class Traits, class Allocator>
45 class basic_stringbuf: public basic_streambuf<Char, Traits>
46 {
47 public:
48 using char_type = Char;
49 using traits_type = Traits;
50 using allocator_type = Allocator;
51 using int_type = typename traits_type::int_type;
52 using pos_type = typename traits_type::pos_type;
53 using off_type = typename traits_type::off_type;
54
55 /**
56 * 27.8.2.1, constructors:
57 */
58
59 explicit basic_stringbuf(ios_base::openmode mode = ios_base::in | ios_base::out)
60 : basic_streambuf<char_type, traits_type>(), mode_{mode}, str_{}
61 {
62 init_();
63 }
64
65 explicit basic_stringbuf(const basic_string<char_type, traits_type, allocator_type> str,
66 ios_base::openmode mode = ios_base::in | ios_base::out)
67 : basic_streambuf<char_type, traits_type>(), mode_{mode}, str_{str}
68 {
69 init_();
70 }
71
72 basic_stringbuf(const basic_stringbuf&) = delete;
73
74 basic_stringbuf(basic_stringbuf&& other)
75 : mode_{move(other.mode_)}, str_{move(other.str_)}
76 {
77 basic_streambuf<char_type, traits_type>::swap(other);
78 }
79
80 /**
81 * 27.8.2.2, assign and swap:
82 */
83
84 basic_stringbuf& operator=(const basic_stringbuf&) = delete;
85
86 basic_stringbuf& operator=(basic_stringbuf&& other)
87 {
88 swap(other);
89 }
90
91 void swap(basic_stringbuf& rhs)
92 {
93 std::swap(mode_, rhs.mode_);
94 std::swap(str_, rhs.str_);
95
96 basic_streambuf<char_type, traits_type>::swap(rhs);
97 }
98
99 /**
100 * 27.8.2.3, get and set:
101 */
102
103 basic_string<char_type, traits_type, allocator_type> str() const
104 {
105 if (mode_ & ios_base::out)
106 return basic_string<char_type, traits_type, allocator_type>{
[eaabd7d]107 this->output_begin_, this->output_next_ - 1, str_.get_allocator()
[6c242c3]108 };
109 else if (mode_ == ios_base::in)
110 return basic_string<char_type, traits_type, allocator_type>{
111 this->eback(), this->egptr(), str_.get_allocator()
112 };
113 else
114 return basic_string<char_type, traits_type, allocator_type>{};
115 }
116
117 void str(const basic_string<char_type, traits_type, allocator_type>& str)
118 {
119 str_ = str;
120 init_();
121 }
122
123 protected:
124 /**
125 * 27.8.2.4, overriden virtual functions:
126 */
127
128 int_type underflow() override
129 {
130 if (this->read_avail_())
131 return traits_type::to_int_type(*this->gptr());
132 else
133 return traits_type::eof();
134 }
135
136 int_type pbackfail(int_type c = traits_type::eof()) override
137 {
138 if (!traits_type::eq_int_type(c, traits_type::eof()) &&
139 this->putback_avail_() &&
140 traits_type::eq(traits_type::to_char_type(c), this->gptr()[-1]))
141 {
142 --this->input_next_;
143
144 return c;
145 }
146 else if (!traits_type::eq_int_type(c, traits_type::eof()) &&
147 this->putback_avail_() && (mode_ & ios_base::out) != 0)
148 {
149 *--this->input_next_ = c;
150
151 return c;
152 }
153 else if (traits_type::eq_int_type(c, traits_type::eof()) &&
154 this->putback_avail_())
155 {
156 --this->input_next_;
157
158 return traits_type::not_eof(c);
159 }
160
161 return traits_type::eof();
162 }
163
164 int_type overflow(int_type c = traits_type::eof()) override
165 {
166 if ((mode_ & ios_base::out) == 0)
167 return traits_type::eof();
168
169 if (!traits_type::eq_int_type(c, traits_type::eof()))
170 {
171 if (this->output_next_ < this->output_end_)
172 return c;
173
174 auto size = static_cast<size_t>(this->output_next_ - this->output_begin_);
175 str_.size_ = size;
176
177 str_.push_back(traits_type::to_char_type(c));
178 init_();
179
180 return c;
181 }
182 else if (traits_type::eq_int_type(c, traits_type::eof()))
183 return traits_type::not_eof(c);
184
185 return traits_type::eof();
186 }
187
188 basic_streambuf<char_type, traits_type>* setbuf(char_type* str, streamsize n) override
189 {
190 if (!str && n == 0)
191 return this;
192
193 str_.assign(str, str + static_cast<size_t>(n));
194
195 return this;
196 }
197
198 pos_type seekoff(off_type off, ios_base::seekdir dir,
199 ios_base::openmode mode = ios_base::in | ios_base::out)
200 {
201 if ((mode & ios_base::in) == ios_base::in)
202 {
203 if (!this->input_next_)
204 return pos_type(off_type(-1));
205
206 return seekoff_(off, this->input_begin_, this->input_next_, this->input_end_, dir);
207 }
208 else if ((mode & ios_base::out) == ios_base::out)
209 {
210 if (!this->output_next_)
211 return pos_type(off_type(-1));
212
213 return seekoff_(off, this->output_begin_, this->output_next_, this->output_end_, dir);
214 }
215 else if ((mode & (ios_base::in | ios_base::out)) == (ios_base::in | ios_base::out) &&
216 (dir == ios_base::beg || dir == ios_base::end))
217 {
218 if (!this->input_next_ || !this->output_next_)
219 return pos_type(off_type(-1));
220
221 seekoff_(off, this->input_begin_, this->input_next_, this->input_end_, dir);
222 return seekoff_(off, this->output_begin_, this->output_next_, this->output_end_, dir);
223 }
224
225 return pos_type(off_type(-1));
226 }
227
228 pos_type seekpos(pos_type pos, ios_base::openmode mode = ios_base::in | ios_base::out)
229 {
230 return seekoff(off_type(pos), ios_base::beg, mode);
231 }
232
233 private:
234 ios_base::openmode mode_;
235 basic_string<char_type, traits_type, allocator_type> str_;
236
237 void init_()
238 {
239 if ((mode_ & ios_base::in) != 0)
240 {
241 this->input_begin_ = this->input_next_ = str_.begin();
242 this->input_end_ = str_.end();
243 }
244
245 if ((mode_ & ios_base::out) != 0)
246 {
247 this->output_begin_ = str_.begin();
248 this->output_next_ = str_.end();
249 this->output_end_ = str_.begin() + str_.size() + 1;
250 }
251 }
252
253 bool ensure_free_space_(size_t n = 1)
254 {
255 str_.ensure_free_space_(n);
256 this->output_end_ = str_.begin() + str_.capacity();
257
258 return true;
259 }
260
261 pos_type seekoff_(off_type off, char_type* begin, char_type*& next, char_type* end,
262 ios_base::seekdir dir)
263 {
264 off_type new_off{};
265
266 if (dir == ios_base::beg)
267 new_off = 0;
268 else if (dir == ios_base::cur)
269 new_off = static_cast<off_type>(next - begin);
270 else if (dir == ios_base::end)
271 new_off = static_cast<off_type>(end - begin);
272
273 if (new_off + off < 0 || begin + new_off + off >= end)
274 return pos_type(off_type(-1));
275 else
276 next = begin + new_off + off;
277
278 return pos_type(new_off);
279 }
280 };
281
282 template<class Char, class Traits, class Allocator>
283 void swap(basic_stringbuf<Char, Traits, Allocator>& lhs,
284 basic_stringbuf<Char, Traits, Allocator>& rhs)
285 {
286 lhs.swap(rhs);
287 }
288
289 /**
290 * 27.8.3, class template basic_istringstream:
291 */
292
293 template<class Char, class Traits, class Allocator>
294 class basic_istringstream: public basic_istream<Char, Traits>
295 {
296 public:
297 using char_type = Char;
298 using traits_type = Traits;
299 using allocator_type = Allocator;
300 using int_type = typename traits_type::int_type;
301 using pos_type = typename traits_type::pos_type;
302 using off_type = typename traits_type::off_type;
303
304 /**
305 * 27.8.3.1, constructors:
306 */
307
308 explicit basic_istringstream(ios_base::openmode mode = ios_base::in)
309 : basic_istream<char_type, traits_type>(&sb_),
310 sb_(mode | ios_base::in)
311 { /* DUMMY BODY */ }
312
313 explicit basic_istringstream(const basic_string<char_type, traits_type, allocator_type> str,
314 ios_base::openmode mode = ios_base::in)
315 : basic_istream<char_type, traits_type>{&sb_},
316 sb_(str, mode | ios_base::in)
317 { /* DUMMY BODY */ }
318
319 basic_istringstream(const basic_istringstream&) = delete;
320
321 basic_istringstream(basic_istringstream&& other)
322 : basic_istream<char_type, traits_type>{move(other)},
323 sb_{move(other.sb_)}
324 {
325 basic_istream<char_type, traits_type>::set_rdbuf(&sb_);
326 }
327
328 /**
329 * 27.8.3.2, assign and swap:
330 */
331
332 basic_istringstream& operator=(const basic_istringstream&) = delete;
333
334 basic_istringstream& operator=(basic_istringstream&& other)
335 {
336 swap(other);
337 }
338
339 void swap(basic_istringstream& rhs)
340 {
341 basic_istream<char_type, traits_type>::swap(rhs);
342 sb_.swap(rhs.sb_);
343 }
344
345 /**
346 * 27.8.3.3, members:
347 */
348
349 basic_stringbuf<char_type, traits_type, allocator_type>* rdbuf() const
350 {
351 return const_cast<basic_stringbuf<char_type, traits_type, allocator_type>*>(&sb_);
352 }
353
354 basic_string<char_type, traits_type, allocator_type> str() const
355 {
356 return sb_.str();
357 }
358
359 void str(const basic_string<char_type, traits_type, allocator_type>& str)
360 {
361 sb_.str(str);
362 }
363
364 private:
365 basic_stringbuf<char_type, traits_type, allocator_type> sb_;
366 };
367
368 template<class Char, class Traits, class Allocator>
369 void swap(basic_istringstream<Char, Traits, Allocator>& lhs,
370 basic_istringstream<Char, Traits, Allocator>& rhs)
371 {
372 lhs.swap(rhs);
373 }
374
375 template<class Char, class Traits, class Allocator>
376 class basic_ostringstream: public basic_ostream<Char, Traits>
377 {
378 public:
379 using char_type = Char;
380 using traits_type = Traits;
381 using allocator_type = Allocator;
382 using int_type = typename traits_type::int_type;
383 using pos_type = typename traits_type::pos_type;
384 using off_type = typename traits_type::off_type;
385
386 /**
387 * 27.8.4.1, constructors:
388 */
389
390 explicit basic_ostringstream(ios_base::openmode mode = ios_base::out)
391 : basic_ostream<char_type, traits_type>(&sb_),
392 sb_(mode | ios_base::out)
393 { /* DUMMY BODY */ }
394
395 explicit basic_ostringstream(const basic_string<char_type, traits_type, allocator_type> str,
396 ios_base::openmode mode = ios_base::out)
397 : basic_ostream<char_type, traits_type>{&sb_},
398 sb_(str, mode | ios_base::out)
399 { /* DUMMY BODY */ }
400
401 basic_ostringstream(const basic_ostringstream&) = delete;
402
403 basic_ostringstream(basic_ostringstream&& other)
404 : basic_ostream<char_type, traits_type>{move(other)},
405 sb_{move(other.sb_)}
406 {
407 basic_ostream<char_type, traits_type>::set_rdbuf(&sb_);
408 }
409
410 /**
411 * 27.8.4.2, assign and swap:
412 */
413
414 basic_ostringstream& operator=(const basic_ostringstream&) = delete;
415
416 basic_ostringstream& operator=(basic_ostringstream&& other)
417 {
418 swap(other);
419 }
420
421 void swap(basic_ostringstream& rhs)
422 {
423 basic_ostream<char_type, traits_type>::swap(rhs);
424 sb_.swap(rhs.sb_);
425 }
426
427 /**
428 * 27.8.3.3, members:
429 */
430
431 basic_stringbuf<char_type, traits_type, allocator_type>* rdbuf() const
432 {
433 return const_cast<basic_stringbuf<char_type, traits_type, allocator_type>*>(&sb_);
434 }
435
436 basic_string<char_type, traits_type, allocator_type> str() const
437 {
438 return sb_.str();
439 }
440
441 void str(const basic_string<char_type, traits_type, allocator_type>& str)
442 {
443 sb_.str(str);
444 }
445
446 private:
447 basic_stringbuf<char_type, traits_type, allocator_type> sb_;
448 };
449
450 /**
451 * 27.8.5, class template basic_stringstream:
452 */
453
454 template<class Char, class Traits, class Allocator>
455 class basic_stringstream: public basic_iostream<Char, Traits>
456 {
457 public:
458 using char_type = Char;
459 using traits_type = Traits;
460 using allocator_type = Allocator;
461 using int_type = typename traits_type::int_type;
462 using pos_type = typename traits_type::pos_type;
463 using off_type = typename traits_type::off_type;
464
465 /**
466 * 27.8.5.1, constructors:
467 */
468
469 explicit basic_stringstream(ios_base::openmode mode = ios_base::in | ios_base::out)
470 : basic_iostream<char_type, traits_type>(&sb_),
471 sb_(mode | ios_base::out)
472 { /* DUMMY BODY */ }
473
474 explicit basic_stringstream(const basic_string<char_type, traits_type, allocator_type> str,
475 ios_base::openmode mode = ios_base::in | ios_base::out)
476 : basic_iostream<char_type, traits_type>{&sb_},
477 sb_(str, mode | ios_base::out)
478 { /* DUMMY BODY */ }
479
480 basic_stringstream(const basic_stringstream&) = delete;
481
482 basic_stringstream(basic_stringstream&& other)
483 : basic_iostream<char_type, traits_type>{move(other)},
484 sb_{move(other.sb_)}
485 {
486 basic_iostream<char_type, traits_type>::set_rdbuf(&sb_);
487 }
488
489 /**
490 * 27.8.5.2, assign and swap:
491 */
492
493 basic_stringstream& operator=(const basic_stringstream&) = delete;
494
495 basic_stringstream& operator=(basic_stringstream&& other)
496 {
497 swap(other);
498 }
499
500 void swap(basic_stringstream& rhs)
501 {
502 basic_iostream<char_type, traits_type>::swap(rhs);
503 sb_.swap(rhs.sb_);
504 }
505
506 /**
507 * 27.8.5.3, members:
508 */
509
510 basic_stringbuf<char_type, traits_type, allocator_type>* rdbuf() const
511 {
512 return const_cast<basic_stringbuf<char_type, traits_type, allocator_type>*>(&sb_);
513 }
514
515 basic_string<char_type, traits_type, allocator_type> str() const
516 {
517 return sb_.str();
518 }
519
520 void str(const basic_string<char_type, traits_type, allocator_type>& str)
521 {
522 sb_.str(str);
523 }
524
525 private:
526 basic_stringbuf<char_type, traits_type, allocator_type> sb_;
527 };
528}
529
530#endif
Note: See TracBrowser for help on using the repository browser.