Library of Assembled Shared Sources
extended_io.inl
Go to the documentation of this file.
1/** @file
2 * @author Bram de Greve (bram@cocamware.com)
3 * @author Tom De Muer (tom@cocamware.com)
4 *
5 * *** BEGIN LICENSE INFORMATION ***
6 *
7 * The contents of this file are subject to the Common Public Attribution License
8 * Version 1.0 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://lass.sourceforge.net/cpal-license. The License is based on the
11 * Mozilla Public License Version 1.1 but Sections 14 and 15 have been added to cover
12 * use of software over a computer network and provide for limited attribution for
13 * the Original Developer. In addition, Exhibit A has been modified to be consistent
14 * with Exhibit B.
15 *
16 * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
17 * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
18 * language governing rights and limitations under the License.
19 *
20 * The Original Code is LASS - Library of Assembled Shared Sources.
21 *
22 * The Initial Developer of the Original Code is Bram de Greve and Tom De Muer.
23 * The Original Developer is the Initial Developer.
24 *
25 * All portions of the code written by the Initial Developer are:
26 * Copyright (C) 2004-2011 the Initial Developer.
27 * All Rights Reserved.
28 *
29 * Contributor(s):
30 *
31 * Alternatively, the contents of this file may be used under the terms of the
32 * GNU General Public License Version 2 or later (the GPL), in which case the
33 * provisions of GPL are applicable instead of those above. If you wish to allow use
34 * of your version of this file only under the terms of the GPL and not to allow
35 * others to use your version of this file under the CPAL, indicate your decision by
36 * deleting the provisions above and replace them with the notice and other
37 * provisions required by the GPL License. If you do not delete the provisions above,
38 * a recipient may use your version of this file under either the CPAL or the GPL.
39 *
40 * *** END LICENSE INFORMATION ***
41 */
42
43#include <cctype>
44#include <limits>
45#include "extended_string.h"
46
47// --- implemenation details -----------------------------------------------------------------------
48
49namespace lass
50{
51namespace stde
52{
53namespace impl
54{
55
56/** @ingroup extended_io
57 * @internal
58 */
59template <typename Char, typename Traits>
60void eat_whitespace(std::basic_istream<Char, Traits>& stream)
61{
62 Char c = 0;
63 while (stream.get(c))
64 {
65 if (!std::isspace(c))
66 {
67 stream.putback(c);
68 break;
69 }
70 }
71}
72
73/** @ingroup extended_io
74 * @internal
75 */
76struct sequence_traits
77{
78 template <typename Container, typename T>
79 static void push(Container& container, const T& value)
80 {
81 container.push_back(value);
82 }
83 template <typename Container>
84 static void temp_to_output(Container& temp, Container& output)
85 {
86 temp.swap(output);
87 }
88};
89
90/** @ingroup extended_io
91 * @internal
92 */
93struct set_traits
94{
95 template <typename Container, typename T>
96 static void push(Container& container, const T& value)
97 {
98 container.insert(value);
99 }
100 template <typename Container>
101 static void temp_to_output(Container& temp, Container& output)
102 {
103 temp.swap(output);
104 }
105};
106
107/** @ingroup extended_io
108 * @internal
109 * @note may change value on failure, but that's ok since it's a temp of the caller.
110 */
111struct value_traits
112{
113 template <typename Char, typename Traits, typename T>
114 static bool read(
115 std::basic_istream<Char, Traits>& stream, T& value,
116 Char inter_seperator, Char /*intra_seperator*/, Char closer)
117 {
118 eat_whitespace(stream);
119
120 // read till next seperator
121 //
122 std::basic_string<Char, Traits> buffer;
123 Char c = 0;
124 while (stream.get(c))
125 {
126 if (c == inter_seperator || c == closer)
127 {
128 stream.putback(c);
129 break;
130 }
131 buffer += c;
132 }
133
134 // convert
135 //
136 return cast(buffer, value);
137
138 }
139private:
140 static bool cast(const std::string& buffer, std::string& value)
141 {
142 value = rstrip(buffer);
143 return true;
144 }
145 template <typename T>
146 static bool cast(const std::string& buffer, T& value)
147 {
148 std::stringstream buffer_stream(buffer);
149 if (std::numeric_limits<T>::is_specialized)
150 {
151 buffer_stream.precision(std::numeric_limits<T>::digits10 + 1);
152 }
153 return buffer_stream >> value && (buffer_stream >> std::ws).eof();
154 }
155};
156
157/** @ingroup extended_io
158 * @internal
159 * @note may change value on failure, but that's ok since it's a temp of the caller.
160 */
161struct pair_traits
162{
163 template <typename Char, typename Traits, typename T, typename U>
164 static bool read(
165 std::basic_istream<Char, Traits>& stream, std::pair<T, U>& value,
166 Char inter_seperator, Char intra_seperator, Char closer)
167 {
168 if (!value_traits::read<Char>(stream, value.first, intra_seperator, 0, intra_seperator))
169 {
170 return false;
171 }
172 Char dummy;
173 stream >> dummy;
174 if (!value_traits::read<Char>(stream, value.second, inter_seperator, 0, closer))
175 {
176 return false;
177 }
178 return true;
179 }
180};
181
182/** @ingroup extended_io
183 * @internal
184 */
185template <typename Iterator, typename Char, typename Traits>
186std::basic_ostream<Char, Traits>& print_sequence(
187 std::basic_ostream<Char, Traits>& stream, Iterator begin, Iterator end,
188 const Char* opener, const Char* seperator, const Char* closer)
189{
190 std::basic_ostringstream<Char, Traits> buffer;
191 buffer.copyfmt(stream);
192 buffer.width(0);
193
194 buffer << opener;
195 for (Iterator i = begin; i != end; ++i)
196 {
197 if (i != begin)
198 {
199 buffer << seperator;
200 }
201 buffer << *i;
202 }
203 buffer << closer;
204
205 LASS_ENFORCE_STREAM(stream) << buffer.str();
206 return stream;
207}
208
209/** @ingroup extended_io
210 * @internal
211 */
212template <typename Char, typename Traits, typename Iterator>
213std::basic_ostream<Char, Traits>& print_map(
214 std::basic_ostream<Char, Traits>& stream, Iterator begin, Iterator end,
215 const Char* opener, const Char* seperator_1, const Char* seperator_2, const Char* closer)
216{
217 std::basic_ostringstream<Char, Traits> buffer;
218 buffer.copyfmt(stream);
219 buffer.width(0);
220
221 buffer << opener;
222 for (Iterator i = begin; i != end; ++i)
223 {
224 if (i != begin)
225 {
226 buffer << seperator_1;
227 }
228 buffer << i->first << seperator_2 << i->second;
229 }
230 buffer << closer;
231
232 LASS_ENFORCE_STREAM(stream) << buffer.str();
233 return stream;
234}
235
236/** @ingroup extended_io
237 * @internal
238 */
239template
240<
241 typename ContainerTraits, typename DataTraits, typename T,
242 typename Char, typename Traits,
243 typename Container
244>
245std::basic_istream<Char, Traits>& read_container(
246 std::basic_istream<Char, Traits>& stream, Container& container,
247 Char opener, Char inter_seperator, Char intra_seperator, Char closer)
248{
249 Container result;
250
251 bool good = true;
252 Char c = 0;
253 eat_whitespace(stream);
254 if (stream.get(c))
255 {
256 if (c == opener)
257 {
258 T temp;
259 good = DataTraits::read(stream, temp, inter_seperator, intra_seperator, closer);
260 if (good)
261 {
262 ContainerTraits::push(result, temp);
263 }
264 }
265 else
266 {
267 stream.putback(c);
268 good = false;
269 }
270 }
271 else
272 {
273 good = false;
274 }
275
276 while (good && stream.get(c) && c != closer)
277 {
278 if (c == inter_seperator)
279 {
280 T temp;
281 good = DataTraits::read(stream, temp, inter_seperator, intra_seperator, closer);
282 if (good)
283 {
284 ContainerTraits::push(result, temp);
285 }
286 }
287 else
288 {
289 stream.putback(c);
290 good = false;
291 }
292 }
293
294 if (good)
295 {
296 ContainerTraits::temp_to_output(result, container);
297 }
298 else
299 {
300 stream.clear(std::ios::failbit);
301 }
302
303 return stream;
304}
305
306}
307
308}
309
310}
311
312// --- free ----------------------------------------------------------------------------------------
313
314namespace std
315{
316
317// output
318
319/** @ingroup extended_io
320 */
321template <typename T1, typename T2, typename Char, typename Traits>
322std::basic_ostream<Char, Traits>& operator<<(
323 std::basic_ostream<Char, Traits>& stream, const std::pair<T1, T2>& x)
324{
325 std::basic_ostringstream<Char, Traits> buffer;
326 buffer.copyfmt(stream);
327 buffer.width(0);
328 buffer << "(" << x.first << ", " << x.second << ")";
329 LASS_ENFORCE_STREAM(stream) << buffer.str();
330 return stream;
331}
332
333/** @ingroup extended_io
334 */
335template <typename T, typename Alloc, typename Char, typename Traits>
336std::basic_ostream<Char, Traits>& operator<<(
337 std::basic_ostream<Char, Traits>& stream, const std::vector<T, Alloc>& container)
338{
339 return lass::stde::impl::print_sequence(
340 stream, container.begin(), container.end(), "[", ", ", "]");
341}
342
343/** @ingroup extended_io
344 */
345template <typename T, typename Alloc, typename Char, typename Traits>
346std::basic_ostream<Char, Traits>& operator<<(
347 std::basic_ostream<Char, Traits>& stream, const std::list<T, Alloc>& container)
348{
349 return lass::stde::impl::print_sequence(
350 stream, container.begin(), container.end(), "[", ", ", "]");
351}
352
353/** @ingroup extended_io
354 */
355template <typename T, typename Alloc, typename Char, typename Traits>
356std::basic_ostream<Char, Traits>& operator<<(
357 std::basic_ostream<Char, Traits>& stream, const std::deque<T, Alloc>& container)
358{
359 return lass::stde::impl::print_sequence(
360 stream, container.begin(), container.end(), "[", ", ", "]");
361}
362
363/** @ingroup extended_io
364 */
365template <typename Key, typename Data, typename Comp, typename Alloc, typename Char, typename Traits>
366std::basic_ostream<Char, Traits>& operator<<(
367 std::basic_ostream<Char, Traits>& stream,
368 const std::map<Key, Data, Comp, Alloc>& container)
369{
370 return lass::stde::impl::print_map<Char>(
371 stream, container.begin(), container.end(), "{", ", ", ": ", "}");
372}
373
374/** @ingroup extended_io
375 */
376template <typename Key, typename Data, typename Comp, typename Alloc, typename Char, typename Traits>
377std::basic_ostream<Char, Traits>& operator<<(
378 std::basic_ostream<Char, Traits>& stream,
379 const std::multimap<Key, Data, Comp, Alloc>& container)
380{
381 return lass::stde::impl::print_map<Char>(
382 stream, container.begin(), container.end(), "{", ", ", ": ", "}");
383}
384
385/** @ingroup extended_io
386 */
387template <typename Key, typename Comp, typename Alloc, typename Char, typename Traits>
388std::basic_ostream<Char, Traits>& operator<<(
389 std::basic_ostream<Char, Traits>& stream,
390 const std::set<Key, Comp, Alloc>& container)
391{
392 return lass::stde::impl::print_sequence(
393 stream, container.begin(), container.end(), "{", ", ", "}");
394}
395
396/** @ingroup extended_io
397 */
398template <typename Key, typename Comp, typename Alloc, typename Char, typename Traits>
399std::basic_ostream<Char, Traits>& operator<<(
400 std::basic_ostream<Char, Traits>& stream,
401 const std::multiset<Key, Comp, Alloc>& container)
402{
403 return lass::stde::impl::print_sequence(
404 stream, container.begin(), container.end(), "{", ", ", "}");
405}
406
407
408
409// input
410
411/** @ingroup extended_io
412 */
413template <typename Char, typename Traits, typename T1, typename T2>
414std::basic_istream<Char, Traits>& operator>>(
415 std::basic_istream<Char, Traits>& stream, std::pair<T1, T2>& x)
416{
417 using namespace lass::stde;
418
419 Char c = 0;
420 if (stream.get(c))
421 {
422 if (c == '(')
423 {
424 std::pair<T1, T2> temp;
425 if (impl::pair_traits::read<Char>(stream, temp, ')', ',', ')'))
426 {
427 x = temp;
428 Char dummy;
429 stream >> dummy;
430 }
431 }
432 else
433 {
434 stream.putback(c);
435 stream.clear(std::ios::failbit);
436 }
437 }
438 else
439 {
440 stream.clear(std::ios::failbit);
441 }
442
443 return stream;
444}
445
446
447
448/** @ingroup extended_io
449 */
450template <typename Char, typename Traits, typename T, typename Alloc>
451std::basic_istream<Char, Traits>& operator>>(
452 std::basic_istream<Char, Traits>& stream, std::vector<T, Alloc>& container)
453{
454 return ::lass::stde::impl::read_container<
455 ::lass::stde::impl::sequence_traits,
456 ::lass::stde::impl::value_traits,
457 T, Char>(
458 stream, container, '[', ',', 0, ']');
459}
460
461
462
463/** @ingroup extended_io
464 */
465template <typename Char, typename Traits, typename T, typename Alloc>
466std::basic_istream<Char, Traits>& operator>>(
467 std::basic_istream<Char, Traits>& stream, std::list<T, Alloc>& container)
468{
469 return ::lass::stde::impl::read_container<
470 ::lass::stde::impl::sequence_traits,
471 ::lass::stde::impl::value_traits,
472 T, Char>(
473 stream, container, '[', ',', 0, ']');
474}
475
476
477
478/** @ingroup extended_io
479 */
480template <typename Char, typename Traits, typename T, typename Alloc>
481std::basic_istream<Char, Traits>& operator>>(
482 std::basic_istream<Char, Traits>& stream, std::deque<T, Alloc>& container)
483{
484 return ::lass::stde::impl::read_container<
485 ::lass::stde::impl::sequence_traits,
486 ::lass::stde::impl::value_traits,
487 T, Char>(
488 stream, container, '[', ',', 0, ']');
489}
490
491
492
493/** @ingroup extended_io
494 */
495template <typename Char, typename Traits, typename Key, typename Data, typename Comp, typename Alloc>
496std::basic_istream<Char, Traits>& operator>>(
497 std::basic_istream<Char, Traits>& stream, std::map<Key, Data, Comp, Alloc>& container)
498{
499 return ::lass::stde::impl::read_container<
500 ::lass::stde::impl::set_traits,
501 ::lass::stde::impl::pair_traits,
502 std::pair<Key, Data>, Char>(
503 stream, container, '{', ',', ':', '}');
504}
505
506
507
508/** @ingroup extended_io
509 */
510template <typename Char, typename Traits, typename Key, typename Data, typename Comp, typename Alloc>
511std::basic_istream<Char, Traits>& operator>>(
512 std::basic_istream<Char, Traits>& stream,
513 std::multimap<Key, Data, Comp, Alloc>& container)
514{
515 return ::lass::stde::impl::read_container<
516 ::lass::stde::impl::set_traits,
517 ::lass::stde::impl::pair_traits,
518 std::pair<Key, Data>, Char>(
519 stream, container, '{', ',', ':', '}');
520}
521
522
523
524/** @ingroup extended_io
525 */
526template <typename Char, typename Traits, typename Key, typename Comp, typename Alloc>
527std::basic_istream<Char, Traits>& operator>>(
528 std::basic_istream<Char, Traits>& stream, std::set<Key, Comp, Alloc>& container)
529{
530 return ::lass::stde::impl::read_container<
531 ::lass::stde::impl::set_traits,
532 ::lass::stde::impl::value_traits,
533 Key, Char>(
534 stream, container, '{', ',', 0, '}');
535}
536
537
538
539/** @ingroup extended_io
540 */
541template <typename Char, typename Traits, typename Key, typename Comp, typename Alloc>
542std::basic_istream<Char, Traits>& operator>>(
543 std::basic_istream<Char, Traits>& stream, std::multiset<Key, Comp, Alloc>& container)
544{
545 return ::lass::stde::impl::read_container<
546 ::lass::stde::impl::set_traits,
547 ::lass::stde::impl::value_traits,
548 Key, Char>(
549 stream, container, '{', ',', 0, '}');
550}
551
552
553
554}
555
556// EOF
std::basic_string< Char, Traits, Alloc > rstrip(const std::basic_string< Char, Traits, Alloc > &to_be_stripped, const std::basic_string< Char, Traits, Alloc > &to_be_removed)
Return a copy of the string to_be_stripped with trailing characters removed.
lass extensions to the standard library
Library for Assembled Shared Sources.
Definition config.h:53