1 // Copyright (c) 1997-2020
2 //
3 // Utrecht University (The Netherlands),
4 // ETH Zurich (Switzerland),
5 // INRIA Sophia-Antipolis (France),
6 // Max-Planck-Institute Saarbruecken (Germany),
7 // and Tel-Aviv University (Israel). All rights reserved.
8 //
9 // This file is part of CGAL (www.cgal.org)
10 //
11 // $URL: https://github.com/CGAL/cgal/blob/v5.3/Stream_support/include/CGAL/IO/io.h $
12 // $Id: io.h 4e519a3 2021-05-05T13:15:37+02:00 Sébastien Loriot
13 // SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
14 //
15 //
16 // Author(s) : Andreas Fabri
17
18 #ifndef CGAL_IO_H
19 #define CGAL_IO_H
20
21 #include <CGAL/disable_warnings.h>
22
23 #include <CGAL/IO/io_tags.h>
24 #include <CGAL/IO/Color.h>
25
26 #include <CGAL/assertions.h>
27 #include <CGAL/Fraction_traits.h>
28 #include <CGAL/tags.h>
29
30 #include <cstdio>
31 #include <cctype>
32 #include <string>
33 #include <locale>
34 #include <iostream>
35
36 namespace CGAL {
37
38 namespace IO {
39
40 class Static
41 {
42 public:
get_mode()43 static int get_mode()
44 {
45 static const int mode = std::ios::xalloc();
46 return mode;
47 }
48 };
49
50 /*!
51 \ingroup PkgStreamSupportEnumRef
52
53 All classes in the \cgal `Kernel` provide input and output operators for
54 IOStreams. The basic task of such an operator is to produce a
55 representation of an object that can be written as a sequence of
56 characters on devices as a console, a file, or a pipe. The enum `Mode` distinguish between three different printing formats.
57
58 In `ASCII` mode, numbers
59 e.g. the coordinates of a point or
60 the coefficients of a line, are written
61 in a machine independent format.
62 In <span class="textsc">BINARY</span> mode, data are written
63 in a binary format, e.g. a double is represented
64 as a sequence of four byte. The format depends on the machine.
65 The mode <span class="textsc">PRETTY</span>
66 serves mainly for debugging as the type of the geometric
67 object is written, as well as the data defining the object. For example
68 for a point at the origin with %Cartesian double coordinates, the output
69 would be `PointC2(0.0, 0.0)`. At the moment \cgal does not
70 provide input operations for pretty printed data. By default a stream
71 is in <span class="textsc">Ascii</span> mode.
72
73 \sa `CGAL::IO::set_mode()`
74 \sa `CGAL::IO::set_ascii_mode()`
75 \sa `CGAL::IO::set_binary_mode()`
76 \sa `CGAL::IO::set_pretty_mode()`
77 \sa `CGAL::IO::get_mode()`
78 \sa `CGAL::IO::is_ascii()`
79 \sa `CGAL::IO::is_binary()`
80 \sa `CGAL::IO::is_pretty()`
81 */
82 enum Mode {ASCII = 0, PRETTY, BINARY};
83
84 } // namespace IO
85
86 #ifdef DOXYGEN_RUNNING
87 /*!
88 \ingroup IOstreamOperators
89
90 \brief Inserts object `c` in the stream `os`. Returns `os`.
91 \cgal defines output operators for classes that are derived
92 from the class `ostream`. This allows to write to ostreams
93 as `cout` or `cerr`, as well as to `std::ostringstream`
94 and `std::ofstream`.
95 The output operator is defined for all classes in the \cgal `Kernel` and for the class `Color` as well.
96
97 \sa `CGAL::IO::set_mode()`
98 \sa `CGAL::IO::set_ascii_mode()`
99 \sa `CGAL::IO::set_binary_mode()`
100 \sa `CGAL::IO::set_pretty_mode()`
101 \sa `CGAL::IO::get_mode()`
102 \sa `CGAL::IO::is_ascii()`
103 \sa `CGAL::IO::is_binary()`
104 \sa `CGAL::IO::is_pretty()`
105 */
106 ostream& operator<<(ostream& os, Class c);
107
108 /*!
109 \ingroup IOstreamOperators
110
111 \brief \cgal defines input operators for classes that are derived
112 from the class `istream`. This allows to read from istreams
113 as `std::cin`, as well as from `std::istringstream` and `std::ifstream`.
114 The input operator is defined for all classes in the \cgal `Kernel`.
115
116 \sa `CGAL::IO::set_mode()`
117 \sa `CGAL::IO::set_ascii_mode()`
118 \sa `CGAL::IO::set_binary_mode()`
119 \sa `CGAL::IO::set_pretty_mode()`
120 \sa `CGAL::IO::get_mode()`
121 \sa `CGAL::IO::is_ascii()`
122 \sa `CGAL::IO::is_binary()`
123 \sa `CGAL::IO::is_pretty()`
124 */
125 istream& operator>>(istream& is, Class c);
126 #endif
127
128 template <typename Dummy>
129 struct IO_rep_is_specialized_aux
130 {
131 static const bool is_specialized = true;
132 };
133
134 template< class Dummy >
135 const bool IO_rep_is_specialized_aux<Dummy>::is_specialized;
136
137 template <typename Dummy>
138 struct IO_rep_is_not_specialized_aux
139 {
140 static const bool is_specialized = false;
141 };
142
143 template< class Dummy >
144 const bool IO_rep_is_not_specialized_aux<Dummy>::is_specialized;
145
146 typedef IO_rep_is_specialized_aux<void> IO_rep_is_specialized;
147 typedef IO_rep_is_not_specialized_aux<void> IO_rep_is_not_specialized;
148
149 /*!
150 \ingroup PkgStreamSupportRef
151
152 The purpose of `Output_rep` is to provide a way to control output formatting that works independently of the object's stream output operator.
153
154 If you dont specialize `Output_rep` for `T`, `T`'s stream output operator is called from within `Output_rep`, by default. If you want another behaviour for your type `T`, you have to provide a specialization for that type. Furthermore, you can provide specializations with a second template parameter (a formatting tag). The second template parameter defaults to `Null_tag` and means *default behaviour*.
155
156 Specializations of `Output_rep` should provide the following features:
157
158 \code{.cpp}
159
160 template< class F >
161 struct Output_rep< Some_type, F > {
162 static const bool is_specialized = true;
163 Output_rep( const Some_type& t );
164 std::ostream& operator()( std::ostream& out ) const;
165 };
166
167 \endcode
168
169 You can also specialize for a formatting tag `F`.
170
171 The constant `is_specialized` can be tested by meta-programming tools to
172 verify that a given type can be used with `oformat()`. Its value has to be
173 `true` in a specialization of `Output_rep`. When there is no specialization
174 for a type, the class template `Output_rep` defines `is_specialized` to the
175 default value `false`.
176 */
177 template <class T, class F = ::CGAL::Null_tag >
178 class Output_rep
179 : public IO_rep_is_not_specialized
180 {
181 const T& t;
182
183 public:
184 //! initialize with a const reference to \a t.
Output_rep(const T & tt)185 Output_rep( const T& tt) : t(tt) {}
186 //! perform the output, calls \c operator\<\< by default.
operator()187 std::ostream& operator()( std::ostream& out) const { return (out << t); }
188 };
189
190 /*!
191 \relates Output_rep
192 \brief stream output of the \c Output_rep calls its \c operator().
193
194 \cgal defines output operators for classes that are derived from the class `ostream`.
195 This enables to write to ostreams as `cout` or `cerr`, as well as to `std::ostringstream`
196 and `std::ofstream`.
197 The output operator is defined for all classes in the \cgal `Kernel` and for the class `Color` as well.
198 */
199 template <class T, class F>
200 std::ostream& operator<<( std::ostream& out, Output_rep<T,F> rep) { return rep( out); }
201
202 namespace IO {
203
204 /*!
205 \ingroup PkgStreamSupportRef
206
207 Convenience function to construct an output representation (`Output_rep`) for type `T`.
208
209 Generic IO for type `T`.
210 */
211 template <class T>
oformat(const T & t)212 Output_rep<T> oformat(const T& t) { return Output_rep<T>(t); }
213
214 /*!
215 \ingroup PkgStreamSupportRef
216
217 Convenience function to construct an output representation (`Output_rep`) for type `T`.
218
219 Generic IO for type `T` with formatting tag.
220 */
221 template <class T, class F>
oformat(const T & t,F)222 Output_rep<T,F> oformat( const T& t, F) { return Output_rep<T,F>(t); }
223
224 } // namespace IO
225
226 /*!
227 \ingroup PkgStreamSupportRef
228
229 The definition of `Input_rep` is completely symmetric to `Output_rep`.
230 */
231 template <class T>
232 class Input_rep
233 : public IO_rep_is_not_specialized
234 {
235 T& t;
236
237 public:
238 //! initialize with a reference to \a t.
Input_rep(T & tt)239 Input_rep( T& tt) : t(tt) {}
240
241 //! perform the input, calls \c operator\>\> by default.
operator()242 std::istream& operator()( std::istream& in) const { return (in >> t); }
243 };
244
245 #if CGAL_FORCE_IFORMAT_DOUBLE || \
246 ( ( _MSC_VER > 1600 ) && ( _MSC_VER < 1910 ) && (! defined( CGAL_NO_IFORMAT_DOUBLE )) )
247
248 template <>
249 class Input_rep<double>
250 : public IO_rep_is_specialized
251 {
252 double& t;
253
254 public:
255 //! initialize with a reference to \a t.
Input_rep(double & tt)256 Input_rep( double& tt) : t(tt) {}
257
operator()258 std::istream& operator()( std::istream& is) const
259 {
260 typedef std::istream istream;
261 typedef istream::char_type char_type;
262 typedef istream::int_type int_type;
263 typedef istream::traits_type traits_type;
264
265 std::string buffer;
266 buffer.reserve(32);
267
268 char_type c;
269 do
270 {
271 const int_type i = is.get();
272 if(i == traits_type::eof())
273 return is;
274
275 c = static_cast<char_type>(i);
276 }
277 while (std::isspace(c));
278
279 if(c == '-')
280 {
281 buffer += '-';
282 }
283 else if(c != '+')
284 {
285 is.unget();
286 }
287
288 for(;;)
289 {
290 const int_type i = is.get();
291 if(i == traits_type::eof())
292 {
293 is.clear(is.rdstate() & ~std::ios_base::failbit);
294 break;
295 }
296
297 c = static_cast<char_type>(i);
298 if(std::isdigit(c) || (c =='.') || (c =='E') || (c =='e') || (c =='+') || (c =='-'))
299 {
300 buffer += c;
301 }
302 else
303 {
304 is.unget();
305 break;
306 }
307 }
308
309 if(sscanf_s(buffer.c_str(), "%lf", &t) != 1)
310 {
311 // if a 'buffer' does not contain a double, set the fail bit.
312 is.setstate(std::ios_base::failbit);
313 }
314
315 return is;
316 }
317 };
318
319 template <>
320 class Input_rep<float>
321 {
322 float& t;
323
324 public:
325 //! initialize with a reference to \a t.
Input_rep(float & tt)326 Input_rep( float& tt) : t(tt) {}
327
operator()328 std::istream& operator()( std::istream& is) const
329 {
330 typedef std::istream istream;
331 typedef istream::char_type char_type;
332 typedef istream::int_type int_type;
333 typedef istream::traits_type traits_type;
334
335 std::string buffer;
336 buffer.reserve(32);
337
338 char_type c;
339 do
340 {
341 const int_type i = is.get();
342 if(i == traits_type::eof())
343 return is;
344
345 c = static_cast<char_type>(i);
346 }
347 while (std::isspace(c));
348
349 if(c == '-')
350 {
351 buffer += '-';
352 }
353 else if(c != '+')
354 {
355 is.unget();
356 }
357
358 for(;;)
359 {
360 const int_type i = is.get();
361 if(i == traits_type::eof())
362 {
363 is.clear(is.rdstate() & ~std::ios_base::failbit);
364 break;
365 }
366
367 c = static_cast<char_type>(i);
368 if(std::isdigit(c) || (c =='.') || (c =='E') || (c =='e') || (c =='+') || (c =='-'))
369 {
370 buffer += c;
371 }
372 else
373 {
374 is.unget();
375 break;
376 }
377 }
378
379 if(sscanf_s(buffer.c_str(), "%f", &t) != 1)
380 {
381 // if a 'buffer' does not contain a double, set the fail bit.
382 is.setstate(std::ios_base::failbit);
383 }
384
385 return is;
386 }
387 };
388 #endif
389
390 /*! \relates Input_rep
391 \brief stream input to the \c Input_rep calls its \c operator().
392
393 \brief \cgal defines input operators for classes that are derived
394 from the class `istream`. This allows to read from istreams
395 as `std::cin`, as well as from `std::istringstream` and `std::ifstream`.
396 The input operator is defined for all classes in the \cgal `Kernel`.
397 */
398 template <class T>
399 std::istream& operator>>( std::istream& in, Input_rep<T> rep) { return rep(in); }
400
401 namespace IO {
402
403 /*!
404 \ingroup PkgStreamSupportRef
405
406 The definition of this function is completely symmetric to `oformat()`.
407 */
408 template <class T>
iformat(T & t)409 Input_rep<T> iformat( T& t) { return Input_rep<T>(t); }
410
411 } // namespace IO
412
413 template <class T, class F = Null_tag >
414 class Benchmark_rep
415 {
416 const T& t;
417
418 public:
419 //! initialize with a const reference to \a t.
Benchmark_rep(const T & tt)420 Benchmark_rep( const T& tt) : t(tt) {}
421 //! perform the output, calls \c operator\<\< by default.
operator()422 std::ostream& operator()( std::ostream& out) const { return out << t; }
423
424 // static function to get the benchmark name
get_benchmark_name()425 static std::string get_benchmark_name() { return ""; }
426 };
427
428 template <class T, class F>
429 std::ostream& operator<<( std::ostream& out, Benchmark_rep<T,F> rep) { return rep( out); }
430
431 namespace IO {
432
433 template <class T>
bmformat(const T & t)434 Benchmark_rep<T> bmformat( const T& t) { return Benchmark_rep<T>(t); }
435
436 template <class T, class F>
bmformat(const T & t,F)437 Benchmark_rep<T,F> bmformat( const T& t, F) { return Benchmark_rep<T,F>(t); }
438
439 /*!
440 \ingroup PkgStreamSupportRef
441
442 returns the printing mode of the %IO stream `s`.
443
444 \link PkgStreamSupportEnumRef `CGAL::IO::Mode`\endlink
445 \sa `CGAL::IO::set_mode()`
446 \sa `CGAL::IO::set_ascii_mode()`
447 \sa `CGAL::IO::set_binary_mode()`
448 \sa `CGAL::IO::set_pretty_mode()`
449 \sa `CGAL::IO::is_ascii()`
450 \sa `CGAL::IO::is_binary()`
451 \sa `CGAL::IO::is_pretty()`
452 */
get_mode(std::ios & i)453 inline Mode get_mode(std::ios& i)
454 {
455 return static_cast<Mode>(i.iword(Static::get_mode()));
456 }
457
458 /*!
459 \ingroup PkgStreamSupportRef
460
461 sets the mode of the %IO stream `s` to be the `ASCII` mode.
462 Returns the previous mode of `s`.
463
464 \link PkgStreamSupportEnumRef `CGAL::IO::Mode`\endlink
465 \sa `CGAL::IO::set_mode()`
466 \sa `CGAL::IO::set_binary_mode()`
467 \sa `CGAL::IO::set_pretty_mode()`
468 \sa `CGAL::IO::get_mode()`
469 \sa `CGAL::IO::is_ascii()`
470 \sa `CGAL::IO::is_binary()`
471 \sa `CGAL::IO::is_pretty()`
472 */
set_ascii_mode(std::ios & i)473 inline Mode set_ascii_mode(std::ios& i)
474 {
475 Mode m = get_mode(i);
476 i.iword(Static::get_mode()) = ASCII;
477 return m;
478 }
479
480 /*!
481 \ingroup PkgStreamSupportRef
482
483 sets the mode of the %IO stream `s` to be the `BINARY` mode.
484 Returns the previous mode of `s`.
485
486 \link PkgStreamSupportEnumRef `CGAL::IO::Mode`\endlink
487 \sa `CGAL::IO::set_mode()`
488 \sa `CGAL::IO::set_ascii_mode()`
489 \sa `CGAL::IO::set_pretty_mode()`
490 \sa `CGAL::IO::get_mode()`
491 \sa `CGAL::IO::is_ascii()`
492 \sa `CGAL::IO::is_binary()`
493 \sa `CGAL::IO::is_pretty()`
494 */
set_binary_mode(std::ios & i)495 inline Mode set_binary_mode(std::ios& i)
496 {
497 Mode m = get_mode(i);
498 i.iword(Static::get_mode()) = BINARY;
499 return m;
500 }
501
502 /*!
503 \ingroup PkgStreamSupportRef
504
505 sets the mode of the %IO stream `s` to be the `PRETTY` mode.
506 Returns the previous mode of `s`.
507
508 \link PkgStreamSupportEnumRef `CGAL::IO::Mode`\endlink
509 \sa `CGAL::IO::set_mode()`
510 \sa `CGAL::IO::set_ascii_mode()`
511 \sa `CGAL::IO::set_binary_mode()`
512 \sa `CGAL::IO::get_mode()`
513 \sa `CGAL::IO::is_ascii()`
514 \sa `CGAL::IO::is_binary()`
515 \sa `CGAL::IO::is_pretty()`
516 */
set_pretty_mode(std::ios & i)517 inline Mode set_pretty_mode(std::ios& i)
518 {
519 Mode m = get_mode(i);
520 i.iword(Static::get_mode()) = PRETTY;
521 return m;
522 }
523
524 /*!
525 \ingroup PkgStreamSupportRef
526
527 sets the printing mode of the %IO stream `s`.
528
529 \link PkgStreamSupportEnumRef `CGAL::IO::Mode`\endlink
530 \sa `CGAL::IO::set_ascii_mode()`
531 \sa `CGAL::IO::set_binary_mode()`
532 \sa `CGAL::IO::set_pretty_mode()`
533 \sa `CGAL::IO::get_mode()`
534 \sa `CGAL::IO::is_ascii()`
535 \sa `CGAL::IO::is_binary()`
536 \sa `CGAL::IO::is_pretty()`
537 */
set_mode(std::ios & i,Mode m)538 inline Mode set_mode(std::ios& i, Mode m)
539 {
540 Mode old = get_mode(i);
541 i.iword(Static::get_mode()) = m;
542 return old;
543 }
544
545 /*!
546 \ingroup PkgStreamSupportRef
547
548 checks if the %IO stream `s` is in `PRETTY` mode.
549
550 \link PkgStreamSupportEnumRef `CGAL::IO::Mode`\endlink
551 \sa `CGAL::IO::set_mode()`
552 \sa `CGAL::IO::set_ascii_mode()`
553 \sa `CGAL::IO::set_binary_mode()`
554 \sa `CGAL::IO::set_pretty_mode()`
555 \sa `CGAL::IO::get_mode()`
556 \sa `CGAL::IO::is_ascii()`
557 \sa `CGAL::IO::is_binary()`
558 */
is_pretty(std::ios & i)559 inline bool is_pretty(std::ios& i) { return i.iword(Static::get_mode()) == PRETTY; }
560
561 /*!
562 \ingroup PkgStreamSupportRef
563
564 checks if the %IO stream `s` is in `ASCII` mode.
565
566 \link PkgStreamSupportEnumRef `CGAL::IO::Mode`\endlink
567 \sa `CGAL::IO::set_mode()`
568 \sa `CGAL::IO::set_ascii_mode()`
569 \sa `CGAL::IO::set_binary_mode()`
570 \sa `CGAL::IO::set_pretty_mode()`
571 \sa `CGAL::IO::get_mode()`
572 \sa `CGAL::IO::is_binary()`
573 \sa `CGAL::IO::is_pretty()`
574 */
is_ascii(std::ios & i)575 inline bool is_ascii(std::ios& i) { return i.iword(Static::get_mode()) == ASCII; }
576
577 /*!
578 \ingroup PkgStreamSupportRef
579
580 checks if the %IO stream `s` is in `BINARY` mode.
581
582 \link PkgStreamSupportEnumRef `CGAL::IO::Mode`\endlink
583 \sa `CGAL::IO::set_mode()`
584 \sa `CGAL::IO::set_ascii_mode()`
585 \sa `CGAL::IO::set_binary_mode()`
586 \sa `CGAL::IO::set_pretty_mode()`
587 \sa `CGAL::IO::get_mode()`
588 \sa `CGAL::IO::is_ascii()`
589 \sa `CGAL::IO::is_pretty()`
590 */
is_binary(std::ios & i)591 inline bool is_binary(std::ios& i) { return i.iword(Static::get_mode()) == BINARY; }
592
593 } // namespace IO
594
595 template < class T >
write(std::ostream & os,const T & t,const io_Read_write &)596 inline void write(std::ostream& os, const T& t, const io_Read_write&)
597 {
598 os.write(reinterpret_cast<const char*>(&t), sizeof(t));
599 }
600
601 template < class T >
write(std::ostream & os,const T & t,const io_Operator &)602 inline void write(std::ostream& os, const T& t, const io_Operator&)
603 {
604 os << IO::oformat(t);
605 }
606
607 template < class T >
write(std::ostream & os,const T & t,const io_Extract_insert &)608 inline void write(std::ostream& os, const T& t, const io_Extract_insert&)
609 {
610 insert(os, t);
611 }
612
613 template < class T >
write(std::ostream & os,const T & t)614 inline void write(std::ostream& os, const T& t)
615 {
616 write(os, t, typename Io_traits<T>::Io_tag());
617 }
618
619 template < class T >
read(std::istream & is,T & t,const io_Read_write &)620 inline void read(std::istream& is, T& t, const io_Read_write&)
621 {
622 is.read(reinterpret_cast<char*>(&t), sizeof(t));
623 }
624
625 template < class T >
read(std::istream & is,T & t,const io_Operator &)626 inline void read(std::istream& is, T& t, const io_Operator&)
627 {
628 is >> IO::iformat(t);
629 }
630
631 template < class T >
read(std::istream & is,T & t,const io_Extract_insert &)632 inline void read(std::istream& is, T& t, const io_Extract_insert&)
633 {
634 extract(is, t);
635 }
636
637 template < class T >
read(std::istream & is,T & t)638 inline void read(std::istream& is, T& t)
639 {
640 read(is, t, typename Io_traits<T>::Io_tag());
641 }
642
643 namespace IO {
644
645 inline std::ostream& operator<<( std::ostream& out, const Color& col)
646 {
647 switch(get_mode(out))
648 {
649 case ASCII :
650 return out << static_cast<int>(col.red()) << ' '
651 << static_cast<int>(col.green()) << ' '
652 << static_cast<int>(col.blue()) << ' '
653 << static_cast<int>(col.alpha());
654 case BINARY :
655 out.write(reinterpret_cast<const char*>(col.to_rgba().data()), 4);
656 return out;
657 default:
658 return out << "Color(" << static_cast<int>(col.red()) << ", "
659 << static_cast<int>(col.green()) << ", "
660 << static_cast<int>(col.blue()) << ", "
661 << static_cast<int>(col.alpha()) << ")";
662 }
663 }
664
665 inline std::istream &operator>>(std::istream &is, Color& col)
666 {
667 unsigned char r = 0, g = 0, b = 0, a = 0;
668 int ir = 0, ig = 0, ib = 0, ia = 0;
669
670 switch(get_mode(is))
671 {
672 case ASCII :
673 is >> ir >> ig >> ib >> ia;
674 r = (unsigned char)ir;
675 g = (unsigned char)ig;
676 b = (unsigned char)ib;
677 a = (unsigned char)ia;
678 break;
679 case BINARY :
680 read(is, r);
681 read(is, g);
682 read(is, b);
683 read(is, a);
684 break;
685 default:
686 std::cerr << "" << std::endl;
687 std::cerr << "Stream must be in ascii or binary mode" << std::endl;
688 break;
689 }
690
691 col = Color(r,g,b,a);
692 return is;
693 }
694
mode_name(IO::Mode m)695 inline const char* mode_name( IO::Mode m )
696 {
697 static const char* const names[] = {"ASCII", "PRETTY", "BINARY" };
698 CGAL_assertion( IO::ASCII <= m && m <= IO::BINARY );
699 return names[m];
700 }
701
702 } // IO namespace
703
704 #ifndef CGAL_NO_DEPRECATED_CODE
705 using IO::oformat;
706 using IO::iformat;
707 using IO::bmformat;
708 using IO::get_mode;
709 using IO::set_ascii_mode;
710 using IO::set_binary_mode;
711 using IO::set_pretty_mode;
712 using IO::set_mode;
713 using IO::is_pretty;
714 using IO::is_ascii;
715 using IO::is_binary;
716 using IO::mode_name;
717 #endif
718
719 // From polynomial.h TODO: Where to put this?
swallow(std::istream & is,char d)720 inline void swallow(std::istream &is, char d)
721 {
722 char c;
723 do { is.get(c); } while(isspace(c));
724 if(c != d)
725 {
726 std::stringstream msg;
727 msg << "input error: expected '" << d << "' but got '" << c << "'";
728 CGAL_error_msg( msg.str().c_str() );
729 }
730 }
731
swallow(std::istream & is,const std::string & s)732 inline void swallow(std::istream &is, const std::string& s)
733 {
734 std::string t;
735 is >> t;
736 if(s != t)
737 {
738 std::stringstream msg;
739 msg << "input error: expected '" << s << "' but got '" << t << "'";
740 CGAL_error_msg( msg.str().c_str() );
741 }
742 }
743
744 namespace internal {
745
eat_white_space(std::istream & is)746 inline void eat_white_space(std::istream &is)
747 {
748 std::istream::int_type c;
749 do
750 {
751 c = is.peek();
752 if(c == std::istream::traits_type::eof())
753 {
754 return;
755 }
756 else
757 {
758 std::istream::char_type cc= static_cast<std::istream::char_type>(c);
759 if(std::isspace(cc, std::locale::classic()))
760 {
761 is.get();
762 // since peek succeeded, this should too
763 CGAL_assertion(!is.fail());
764 }
765 else
766 {
767 return;
768 }
769 }
770 }
771 while (true);
772 }
773
is_space(const std::istream &,std::istream::int_type c)774 inline bool is_space(const std::istream& /*is*/, std::istream::int_type c)
775 {
776 return (c == std::istream::traits_type::eof()) ||
777 std::isspace(static_cast<std::istream::char_type>(c),
778 std::locale::classic() );
779 }
780
is_eof(const std::istream &,std::istream::int_type c)781 inline bool is_eof(const std::istream& /*is*/, std::istream::int_type c)
782 {
783 return c == std::istream::traits_type::eof();
784 }
785
is_digit(const std::istream &,std::istream::int_type c)786 inline bool is_digit(const std::istream& /*is*/, std::istream::int_type c)
787 {
788 CGAL_assertion(c != std::istream::traits_type::eof());
789 return std::isdigit(static_cast<std::istream::char_type>(c),
790 std::locale::classic());
791 }
792
peek(std::istream & is)793 inline std::istream::int_type peek(std::istream& is)
794 {
795 // Workaround for a bug in the version of libc++ that is shipped with
796 // Apple-clang-3.2. See the long comment in the function
797 // gmpz_new_read() in <CGAL/GMP/Gmpz_type.h>.
798
799 if(is.eof())
800 return std::istream::traits_type::eof();
801 else
802 return is.peek();
803 }
804
805 template <typename ET>
read_float_or_quotient(std::istream & is,ET & et)806 inline void read_float_or_quotient(std::istream & is, ET& et)
807 {
808 is >> et;
809 }
810
811 template <typename Int, typename Rat>
read_float_or_quotient(std::istream & is,Rat & z)812 inline void read_float_or_quotient(std::istream& is, Rat &z)
813 {
814 // To build a rational from numerator and denominator. Hope that `Int`
815 // and `Fraction_traits::(Numerator|Denominator)_type` are consistent...
816 typename Fraction_traits<Rat>::Compose compose;
817
818 // reads rational and floating point literals.
819 const std::istream::char_type zero = '0';
820 std::istream::int_type c;
821 std::ios::fmtflags old_flags = is.flags();
822
823 is.unsetf(std::ios::skipws);
824 internal::eat_white_space(is);
825
826 Int n(0); // unsigned number before '/' or '.'
827 Int d(1); // number after '/', or denominator (fp-case)
828 bool negative = false; // do we have a leading '-'?
829 bool digits = false; // for fp-case: are there any digits at all?
830
831 c = internal::peek(is);
832 if(c != '.')
833 {
834 // is there a sign?
835 if(c == '-' || c == '+')
836 {
837 is.get();
838 negative = (c == '-');
839 internal::eat_white_space(is);
840 c = internal::peek(is);
841 }
842
843 // read n (could be empty)
844 while (!internal::is_eof(is, c) && internal::is_digit(is, c))
845 {
846 digits = true;
847 n = n*10 + (c-zero);
848 is.get();
849 c = internal::peek(is);
850 }
851
852 // are we done?
853 if(internal::is_eof(is, c) || internal::is_space(is, c))
854 {
855 is.flags(old_flags);
856 if(digits && !is.fail())
857 z = negative? compose(-n,1): compose(n,1);
858 return;
859 }
860 }
861 else
862 {
863 n = 0;
864 }
865
866 // now we have read n, we are not done, and c is the next character
867 // in the stream
868 if(c == '/' || c == '.')
869 {
870 is.get();
871 if(c == '/')
872 {
873 // rational case
874 is >> d;
875 is.flags(old_flags);
876 if(!is.fail())
877 z = negative? compose(-n,d) : compose(n,d);
878 return;
879 }
880
881 // floating point case; read number after '.' (may be empty)
882 for(;;)
883 {
884 c = internal::peek(is);
885 if(internal::is_eof(is, c) || !internal::is_digit(is, c))
886 break;
887 // now we have a digit
888 is.get();
889 digits = true;
890 d *= 10;
891 n = n*10 + (c-zero);
892 }
893 }
894
895 // now we have read all digits after '.', and c is the next character;
896 // read the exponential part (optional)
897 int e = 0;
898 if(c == 'e' || c == 'E')
899 {
900 is.get();
901 is >> e;
902 }
903
904 // now construct the Gmpq
905 if(!digits)
906 {
907 // illegal floating-point number
908 is.setstate(std::ios_base::failbit);
909 is.flags(old_flags);
910 return;
911 }
912
913 // handle e
914 if(e > 0)
915 while (e--) n *= 10;
916 else
917 while (e++) d *= 10;
918
919 is.flags(old_flags);
920 if(!is.fail())
921 z = (negative ? compose(-n,d) : compose(n,d));
922 }
923
924 } // namespace internal
925
926 } // namespace CGAL
927
928 #include <CGAL/enable_warnings.h>
929
930 #endif // CGAL_IO_H
931