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

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

cpp: added sstream implementation

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