input_text_stream.hpp
Go to the documentation of this file.
1 
11 /*****************************************************************************
12 ** Ifdefs
13 *****************************************************************************/
14 
15 #ifndef ECL_STREAMS_INPUT_TEXT_STREAM_HPP_
16 #define ECL_STREAMS_INPUT_TEXT_STREAM_HPP_
17 
18 /*****************************************************************************
19 ** Includes
20 *****************************************************************************/
21 
22 #include <iostream>
23 #include <limits>
24 #include <string>
25 #include <ecl/config/macros.hpp>
28 #include <ecl/concepts/devices.hpp>
30 #include "base_text_stream.hpp"
31 #include "../macros.hpp"
32 
33 /*****************************************************************************
34 ** Namespaces
35 *****************************************************************************/
36 
37 namespace ecl {
38 namespace interfaces {
39 
40 /*****************************************************************************
41 ** Interface [InputTextStream]
42 *****************************************************************************/
43 
56 template <typename Device, bool InputDevice = true >
57 class ECL_PUBLIC InputTextStream {
58 };
59 
86 template <typename Device>
87 class ECL_PUBLIC InputTextStream<Device,true> : public virtual BaseTextStream<Device> {
88 public:
89  /*********************
90  ** Constructors
91  **********************/
92  InputTextStream();
93  virtual ~InputTextStream() {}
94 
95  /*********************
96  ** Streaming Operators
97  **********************/
98  InputTextStream<Device>& operator >> ( char &c );
99  InputTextStream<Device>& operator >> ( std::string &s );
100  InputTextStream<Device>& operator >> ( short &i );
101  InputTextStream<Device>& operator >> ( int &i );
102  InputTextStream<Device>& operator >> ( long &i );
103  InputTextStream<Device>& operator >> ( unsigned char &c );
104  InputTextStream<Device>& operator >> ( unsigned short &i );
105  InputTextStream<Device>& operator >> ( unsigned int &i );
106  InputTextStream<Device>& operator >> ( unsigned long &i );
107  InputTextStream<Device>& operator >> ( float &f );
108  InputTextStream<Device>& operator >> ( double &d );
109  InputTextStream<Device>& operator >> ( long long &i );
110  InputTextStream<Device>& operator >> ( unsigned long long &i );
111  InputTextStream<Device>& operator >> ( bool &b );
112 
113  /*********************
114  ** Non-Streaming API
115  **********************/
116  void enableRawCharReads();
117  void disableRawCharReads();
118 
119 private:
120  bool raw_char_reads;
121 
122  /*********************
123  ** Private Parsers
124  **********************/
125  bool skipLeadingWhiteSpace(char &c);
126  template <typename Number>
127  bool getIntegerFromStream(Number &i);
128  template <typename Number>
129  bool parseHexInteger(Number &i);
130  template <typename Number>
131  bool getFloatFromStream(Number &f);
132 };
133 
134 /*****************************************************************************
135 ** Implementation [InputTextStream]
136 *****************************************************************************/
147 template <typename Device>
148 InputTextStream<Device,true>::InputTextStream() : raw_char_reads(false) {
150 }
151 
152 /*****************************************************************************
153 ** Implementation [InputTextStream][Streaming Operators]
154 *****************************************************************************/
165 template <typename Device>
166 InputTextStream<Device> & InputTextStream<Device,true>::operator >> ( char &c ) {
167 
168  ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
169 
170  if ( !raw_char_reads ) {
171  if( skipLeadingWhiteSpace(c) ) {
172  this->error = NoError;
173  } else {
174  this->error = ReadError;
175  }
176  } else {
177  if ( this->io_device.read(c) == 1 ) {
178  this->error = NoError;
179  } else {
180  this->error = ReadError;
181  }
182  }
183  return *this;
184 }
185 
197 template <typename Device>
198 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( std::string &s ) {
199 
200  ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
201 
202  char c;
203  if ( skipLeadingWhiteSpace(c) ) {
204  s.clear();
205  do {
206  s.push_back(c);
207  if( this->io_device.read(c) < 1 ) {
208  this->error = ReadError;
209  break;
210  }
211  } while ( ( c != ' ' ) && ( c != '\n' ) );
212  this->error = NoError;
213  } else {
214  this->error = ReadError;
215  }
216 
217  // Original method - reads a whole line (must be terminated by a \n)
218 // static char buffer[80];
219 // this->io_device.read(&buffer[0],80);
220 // s.assign(buffer);
221  return *this;
222 }
223 
232 template <typename Device>
233 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( short &i ) {
234 
235  ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
236 
237  if ( getIntegerFromStream(i) ) {
238  this->error = NoError;
239  } // Real errors are handled internally in getIntegerFromStreams
240 
241  return *this;
242 }
243 
252 template <typename Device>
253 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( int &i ) {
254 
255  ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
256  if ( getIntegerFromStream(i) ) {
257  this->error = NoError;
258  } // Real errors are handled internally in getIntegerFromStreams
259  return *this;
260 }
261 
270 template <typename Device>
271 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( long &i ) {
272 
273  ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
274  if ( getIntegerFromStream(i) ) {
275  this->error = NoError;
276  } // Real errors are handled internally in getIntegerFromStreams
277  return *this;
278 }
287 template <typename Device>
288 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( long long &i ) {
289 
290  ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
291  if ( getIntegerFromStream(i) ) {
292  this->error = NoError;
293  } // Real errors are handled internally in getIntegerFromStreams
294  return *this;
295 }
306 template <typename Device>
307 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( unsigned char &uc ) {
308 
309  ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
310  if ( getIntegerFromStream(uc) ) {
311  this->error = NoError;
312  } // Real errors are handled internally in getIntegerFromStreams
313  return *this;
314 }
315 
324 template <typename Device>
325 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( unsigned short &i ) {
326 
327  ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
328  if ( getIntegerFromStream(i) ) {
329  this->error = NoError;
330  } // Real errors are handled internally in getIntegerFromStreams
331  return *this;
332 }
333 
342 template <typename Device>
343 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( unsigned int &i ) {
344 
345  ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
346  if ( getIntegerFromStream(i) ) {
347  this->error = NoError;
348  } // Real errors are handled internally in getIntegerFromStreams
349  return *this;
350 }
351 
360 template <typename Device>
361 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( unsigned long &i ) {
362 
363  ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
364  if ( getIntegerFromStream(i) ) {
365  this->error = NoError;
366  } // Real errors are handled internally in getIntegerFromStreams
367  return *this;
368 }
369 
378 template <typename Device>
379 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( unsigned long long &i ) {
380 
381  ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
382  if ( getIntegerFromStream(i) ) {
383  this->error = NoError;
384  } // Real errors are handled internally in getIntegerFromStreams
385  return *this;
386 }
387 
388 
397 template <typename Device>
398 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( float &f ) {
399 
400  ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
401  if ( getFloatFromStream(f) ) {
402  this->error = NoError;
403  } // Real errors are handled internally in getFloatFromStreams
404  return *this;
405 }
406 
415 template <typename Device>
416 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( double &d ) {
417 
418  ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
419  if ( getFloatFromStream(d) ) {
420  this->error = NoError;
421  } // Real errors are handled internally in getFloatFromStreams
422  return *this;
423 }
424 
435 template <typename Device>
436 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( bool &b )
437 {
438  ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
439  std::string s;
440  *this >> s;
441 
442  if ( this->fail() ) { // string could not be read
443  return *this; // error already set
444  }
445 
446  if ( ( s == "true" ) || ( s == "TRUE" ) || ( s == "True" ) ) {
447  b = true;
448  this->error = NoError;
449  } else if ( ( s == "false" ) || ( s == "FALSE" ) || ( s == "False" ) ) {
450  b = false;
451  this->error = NoError;
452  } else {
453  this->error = ConversionError;
454  }
455  return *this;
456 }
457 
458 /*****************************************************************************
459 ** Implementation [InputTextStream][Non-Streaming Interface]
460 *****************************************************************************/
461 
474 template <typename Device>
475 void InputTextStream<Device,true>::enableRawCharReads() { raw_char_reads = true; }
476 
485 template <typename Device>
486 void InputTextStream<Device,true>::disableRawCharReads() { raw_char_reads = false; }
487 
488 
489 /*****************************************************************************
490 ** Implementation [InputTextStream][Private Parsers]
491 *****************************************************************************/
492 
502 template <typename Device>
504 {
505  do {
506  if( this->io_device.read(c) < 1 ) { // Fail if either there is a read error OR there is nothing in the device.
507  this->error = ReadError;
508  return false;
509  }
510  } while ( ( c == ' ' ) || ( c == '\n' ) );
511  return true;
512 }
513 
518 template <typename Device>
519 template <typename Number>
521 {
522  char c;
523  static int digits[25];
524  static const short ceiling = numeric_limits<short>::maximum/10;
525 
526  i = 0;
527  int j = 0;
528  while ( j < 25 ) {
529  long n = this->io_device.read(c);
530  if ( n < 0 ) {
531  this->error = ReadError;
532  return false;
533  } else if ( n == 0 ) {
534  break; // nothing more to read.
535  }
536  if ( ( c >= '0' ) && ( c <= '9') ) {
537  digits[j] = c - '0';
538  } else if ( ( c >= 'a' ) && ( c <= 'f') ) {
539  digits[j] = 10 + c - 'a';
540  } else if ( ( c >= 'A' ) && ( c <= 'F') ) {
541  digits[j] = 10 + c - 'A';
542  } else {
543  break; // No more valid characters to read.
544  }
545  ++j;
546  }
547  if ( j == 0 ) {
548  this->error = ReadError;
549  return false;
550  }
551 
552  short number = 0;
553  for ( int k = 0; k < j; ++k ) {
554  if ( number < ceiling ) {
555  number = 16*number + (digits[k]);
556  } else {
557  this->error = OutOfRangeError;
558  return false;
559  }
560  }
561  i = number;
562  return true;
563 }
564 
570 template <typename Device>
571 template <typename Number>
573 
574  static char digits[25]; // 20 is the maximum needed on a 64 bit system for a long type
575  static const Number ceiling = ecl::numeric_limits<Number>::maximum/10;
576  char c = ' ';
577  Number sign_multiplier = 1;
578  Number number;
579 
580  if ( !skipLeadingWhiteSpace(c) ) { return false; }
581 
582  if ( c == '-' ) { // Negative
583  if ( std::numeric_limits<Number>::min() != 0 ) {
584  sign_multiplier = -1;
585  if ( this->io_device.read(c) < 1 ) {
586  this->error = ReadError;
587  return false;
588  }
589  } // else do nothing and continue, an error will be found at the next step.
590  } else if ( c == '+' ) { // Positive
591  if ( this->io_device.read(c) < 1 ) {
592  this->error = ReadError;
593  return false;
594  }
595  } else if ( c == '0' ) {
596  long n = this->io_device.read(c);
597  if ( ( n == 0 ) || ( c == ' ' ) || ( c == '\n' ) ) { // It's just a single zero.
598  i = 0;
599  return true;
600  } else if ( n < 0 ) {
601  this->error = ReadError;
602  return false;
603  } else if ( c == 'x' ) {
604  return parseHexInteger(i);
605  } else {
606  // its a regular integer, just continue
607  }
608  } else if ( c == 'x' ) {
609  return parseHexInteger(i);
610  }
611 
612  /*********************
613  ** Parse reg. integer
614  **********************/
615  int j = 0;
616  while ( ( c >= '0' ) && ( c <= '9') && ( j < 25 ) ) {
617  digits[j] = c;
618  j++;
619  long n = this->io_device.read(c);
620  if ( n < 0 ) {
621  this->error = ReadError;
622  return false;
623  } else if ( n == 0 ) {
624  break;
625  } else { // n > 1
626  }
627  }
628  if ( j == 0 ) {
629  this->error = ConversionError;
630  return false;
631  }
632  number = 0;
633  for ( int k = 0; k < j; ++k )
634  {
635  if ( number < ceiling )
636  {
637  number = 10*number + (digits[k] - '0');
638  } else {
639  this->error = OutOfRangeError;
640  return false;
641  }
642  }
643  i = sign_multiplier*number;
644 
645  return true;
646 }
647 
648 template <typename Device>
649 template <typename Number>
651  static const int bufferSize = 25;
652  static char digits[bufferSize]; // 20 is the maximum needed on a 64 bit system for a long type
653  char c = ' ';
654  int integral_length = 0;
655  int decimal_length = 0;
656  Number sign_multiplier = 1;
657  Number number;
658 
659  if ( !skipLeadingWhiteSpace(c) ) { return false; }
660 
661  if ( c == '-' ) {
662  sign_multiplier = -1;
663  if ( this->io_device.read(c) < 1 ) { this->error = ReadError; return false; }
664  } else if ( c == '+' ) {
665  if ( this->io_device.read(c) < 1 ) { this->error = ReadError; return false; }
666  }
667  number = 0;
668  /******************************************
669  ** Integral part
670  *******************************************/
671  while ( ( c >= '0' ) && ( c <= '9') && ( integral_length < bufferSize ) ) {
672  digits[integral_length] = c;
673  long n = this->io_device.read(c);
674  if ( n < 0 ) {
675  this->error = ReadError; return false;
676  } else if ( n == 0 ) {
677  break;
678  } else { // n > 1
679  integral_length++;
680  }
681  }
682  for ( int k = 0; k < integral_length; ++k ) {
683  number = 10*number + (digits[k] - '0');
684  }
685 
686  if ( c == '.' ) {
687  float frac_multiplier = 1;
688  if ( this->io_device.read(c) < 1 ) { this->error = ReadError; return false; }
689  /******************************************
690  ** Decimal part
691  *******************************************/
692  while ( ( c >= '0' ) && ( c <= '9') && ( decimal_length < bufferSize ) ) {
693  digits[decimal_length] = c;
694  long n = this->io_device.read(c);
695  if ( n < 0 ) {
696  this->error = ReadError; return false;
697  } else if ( n == 0 ) {
698  break;
699  } else { // n > 1
700  decimal_length++;
701  }
702  }
703  for ( int k = 0; k < decimal_length; ++k ) {
704  frac_multiplier *= 0.1f;
705  number = number + frac_multiplier*(digits[k] - '0');
706  }
707  }
708 
709  if ( (integral_length+decimal_length) == 0 ) {
710  this->error = ConversionError;
711  return false;
712  }
713 
714  f = sign_multiplier*number;
715 
716  return true;
717 }
718 
719 } // namespace interfaces
720 } // namespace ecl
721 
722 #endif /* ECL_STREAMS_INPUT_TEXT_STREAM_HPP_ */
ecl::OpenError
OpenError
ecl::InputCharDeviceConcept
ecl::interfaces::InputTextStream< Device, true >::getIntegerFromStream
bool getIntegerFromStream(Number &i)
Definition: input_text_stream.hpp:584
ecl::interfaces::InputTextStream< Device, true >::getFloatFromStream
bool getFloatFromStream(Number &f)
Definition: input_text_stream.hpp:662
ecl::interfaces::InputTextStream< Device, true >::enableRawCharReads
void enableRawCharReads()
This permits true char by char reads (including space and newline chars).
Definition: input_text_stream.hpp:487
ecl_compile_time_concept_check
#define ecl_compile_time_concept_check(Model)
portable_types.hpp
ecl::interfaces::InputTextStream
Parent template for input text streams.
Definition: input_text_stream.hpp:69
numeric_limits.hpp
ecl::demos::f
void f()
Definition: log_streams.cpp:55
ecl::interfaces::InputTextStream< Device, true >::disableRawCharReads
void disableRawCharReads()
This ensures char reads are read element by element (not byte by byte).
Definition: input_text_stream.hpp:498
base_text_stream.hpp
Base interface for text streams.
ecl::interfaces::InputTextStream< Device, true >::operator>>
InputTextStream< Device > & operator>>(char &c)
Reads an unformatted char to the stream.
Definition: input_text_stream.hpp:178
ecl::StandardException
ecl::NoError
NoError
ecl::numeric_limits
ecl_assert_throw
#define ecl_assert_throw(expression, exception)
standard_exception.hpp
ecl::ConversionError
ConversionError
devices.hpp
macros.hpp
ecl::ReadError
ReadError
ecl::OutOfRangeError
OutOfRangeError
ecl
ECL_PUBLIC
#define ECL_PUBLIC


ecl_streams
Author(s): Daniel Stonier
autogenerated on Wed Mar 2 2022 00:16:48