input_text_stream.hpp
Go to the documentation of this file.
00001 
00011 /*****************************************************************************
00012 ** Ifdefs
00013 *****************************************************************************/
00014 
00015 #ifndef ECL_STREAMS_INPUT_TEXT_STREAM_HPP_
00016 #define ECL_STREAMS_INPUT_TEXT_STREAM_HPP_
00017 
00018 /*****************************************************************************
00019 ** Includes
00020 *****************************************************************************/
00021 
00022 #include <iostream>
00023 #include <limits>
00024 #include <string>
00025 #include <ecl/config/macros.hpp>
00026 #include <ecl/config/portable_types.hpp>
00027 #include <ecl/exceptions/standard_exception.hpp>
00028 #include <ecl/concepts/devices.hpp>
00029 #include <ecl/type_traits/numeric_limits.hpp>
00030 #include "base_text_stream.hpp"
00031 
00032 /*****************************************************************************
00033 ** Namespaces
00034 *****************************************************************************/
00035 
00036 namespace ecl {
00037 namespace interfaces {
00038 
00039 /*****************************************************************************
00040 ** Interface [InputTextStream]
00041 *****************************************************************************/
00042 
00055 template <typename Device, bool InputDevice = true >
00056 class ECL_PUBLIC InputTextStream {
00057 };
00058 
00085 template <typename Device>
00086 class ECL_PUBLIC InputTextStream<Device,true> : public virtual BaseTextStream<Device> {
00087 public:
00088         /*********************
00089         ** Constructors
00090         **********************/
00091         InputTextStream();
00092         virtual ~InputTextStream() {}
00093 
00094         /*********************
00095         ** Streaming Operators
00096         **********************/
00097     InputTextStream<Device>& operator >> ( char &c ) ecl_assert_throw_decl(ecl::StandardException);
00098     InputTextStream<Device>& operator >> ( std::string &s ) ecl_assert_throw_decl(ecl::StandardException);
00099     InputTextStream<Device>& operator >> ( short &i ) ecl_assert_throw_decl(ecl::StandardException);
00100     InputTextStream<Device>& operator >> ( int &i ) ecl_assert_throw_decl(ecl::StandardException);
00101     InputTextStream<Device>& operator >> ( long &i ) ecl_assert_throw_decl(ecl::StandardException);
00102     InputTextStream<Device>& operator >> ( unsigned char &c ) ecl_assert_throw_decl(ecl::StandardException);
00103     InputTextStream<Device>& operator >> ( unsigned short &i ) ecl_assert_throw_decl(ecl::StandardException);
00104     InputTextStream<Device>& operator >> ( unsigned int &i ) ecl_assert_throw_decl(ecl::StandardException);
00105     InputTextStream<Device>& operator >> ( unsigned long &i ) ecl_assert_throw_decl(ecl::StandardException);
00106     InputTextStream<Device>& operator >> ( float &f ) ecl_assert_throw_decl(ecl::StandardException);
00107     InputTextStream<Device>& operator >> ( double &d ) ecl_assert_throw_decl(ecl::StandardException);
00108     InputTextStream<Device>& operator >> ( long long &i ) ecl_assert_throw_decl(ecl::StandardException);
00109     InputTextStream<Device>& operator >> ( unsigned long long &i ) ecl_assert_throw_decl(ecl::StandardException);
00110     InputTextStream<Device>& operator >> ( bool &b ) ecl_assert_throw_decl(ecl::StandardException);
00111 
00112     /*********************
00113         ** Non-Streaming API
00114         **********************/
00115     void enableRawCharReads();
00116     void disableRawCharReads();
00117 
00118 private:
00119     bool raw_char_reads;
00120 
00121     /*********************
00122         ** Private Parsers
00123         **********************/
00124     bool skipLeadingWhiteSpace(char &c);
00125     template <typename Number>
00126     bool getIntegerFromStream(Number &i);
00127     template <typename Number>
00128     bool parseHexInteger(Number &i);
00129     template <typename Number>
00130     bool getFloatFromStream(Number &f);
00131 };
00132 
00133 /*****************************************************************************
00134 ** Implementation [InputTextStream]
00135 *****************************************************************************/
00146 template <typename Device>
00147 InputTextStream<Device,true>::InputTextStream() : raw_char_reads(false) {
00148         ecl_compile_time_concept_check(ecl::InputCharDeviceConcept<Device>);
00149 }
00150 
00151 /*****************************************************************************
00152 ** Implementation [InputTextStream][Streaming Operators]
00153 *****************************************************************************/
00164 template <typename Device>
00165 InputTextStream<Device> & InputTextStream<Device,true>::operator >> ( char &c ) ecl_assert_throw_decl(ecl::StandardException) {
00166 
00167         ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
00168 
00169     if ( !raw_char_reads ) {
00170         if( skipLeadingWhiteSpace(c) ) {
00171                 this->error = NoError;
00172         } else {
00173                 this->error = ReadError;
00174         }
00175     } else {
00176                 if ( this->io_device.read(c) == 1 ) {
00177                         this->error = NoError;
00178                 } else {
00179                         this->error = ReadError;
00180                 }
00181     }
00182     return *this;
00183 }
00184 
00196 template <typename Device>
00197 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( std::string &s ) ecl_assert_throw_decl(ecl::StandardException) {
00198 
00199         ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
00200 
00201     char c;
00202         if ( skipLeadingWhiteSpace(c) ) {
00203             s.clear();
00204             do {
00205                 s.push_back(c);
00206                 if( this->io_device.read(c) < 1 ) {
00207                         this->error = ReadError;
00208                         break;
00209                         }
00210             } while ( ( c != ' ' ) && ( c != '\n' ) );
00211             this->error = NoError;
00212         } else {
00213                 this->error = ReadError;
00214         }
00215 
00216     // Original method - reads a whole line (must be terminated by a \n)
00217 //    static char buffer[80];
00218 //    this->io_device.read(&buffer[0],80);
00219 //    s.assign(buffer);
00220     return *this;
00221 }
00222 
00231 template <typename Device>
00232 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( short &i ) ecl_assert_throw_decl(ecl::StandardException) {
00233 
00234         ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
00235 
00236     if ( getIntegerFromStream(i) ) {
00237         this->error = NoError;
00238     } // Real errors are handled internally in getIntegerFromStreams
00239 
00240     return *this;
00241 }
00242 
00251 template <typename Device>
00252 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( int &i ) ecl_assert_throw_decl(ecl::StandardException) {
00253 
00254         ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
00255     if ( getIntegerFromStream(i) ) {
00256         this->error = NoError;
00257     } // Real errors are handled internally in getIntegerFromStreams
00258     return *this;
00259 }
00260 
00269 template <typename Device>
00270 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( long &i ) ecl_assert_throw_decl(ecl::StandardException) {
00271 
00272         ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
00273     if ( getIntegerFromStream(i) ) {
00274         this->error = NoError;
00275     } // Real errors are handled internally in getIntegerFromStreams
00276     return *this;
00277 }
00286 template <typename Device>
00287 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( long long &i ) ecl_assert_throw_decl(ecl::StandardException) {
00288 
00289         ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
00290     if ( getIntegerFromStream(i) ) {
00291         this->error = NoError;
00292     } // Real errors are handled internally in getIntegerFromStreams
00293     return *this;
00294 }
00305 template <typename Device>
00306 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( unsigned char &uc ) ecl_assert_throw_decl(ecl::StandardException) {
00307 
00308         ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
00309     if ( getIntegerFromStream(uc) ) {
00310         this->error = NoError;
00311     } // Real errors are handled internally in getIntegerFromStreams
00312     return *this;
00313 }
00314 
00323 template <typename Device>
00324 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( unsigned short &i ) ecl_assert_throw_decl(ecl::StandardException) {
00325 
00326         ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
00327     if ( getIntegerFromStream(i) ) {
00328         this->error = NoError;
00329     } // Real errors are handled internally in getIntegerFromStreams
00330     return *this;
00331 }
00332 
00341 template <typename Device>
00342 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( unsigned int &i ) ecl_assert_throw_decl(ecl::StandardException) {
00343 
00344         ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
00345     if ( getIntegerFromStream(i) ) {
00346         this->error = NoError;
00347     } // Real errors are handled internally in getIntegerFromStreams
00348     return *this;
00349 }
00350 
00359 template <typename Device>
00360 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( unsigned long &i ) ecl_assert_throw_decl(ecl::StandardException) {
00361 
00362         ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
00363     if ( getIntegerFromStream(i) ) {
00364         this->error = NoError;
00365     } // Real errors are handled internally in getIntegerFromStreams
00366     return *this;
00367 }
00368 
00377 template <typename Device>
00378 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( unsigned long long &i ) ecl_assert_throw_decl(ecl::StandardException) {
00379 
00380         ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
00381     if ( getIntegerFromStream(i) ) {
00382         this->error = NoError;
00383     } // Real errors are handled internally in getIntegerFromStreams
00384     return *this;
00385 }
00386 
00387 
00396 template <typename Device>
00397 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( float &f ) ecl_assert_throw_decl(ecl::StandardException) {
00398 
00399         ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
00400     if ( getFloatFromStream(f) ) {
00401         this->error = NoError;
00402     } // Real errors are handled internally in getFloatFromStreams
00403     return *this;
00404 }
00405 
00414 template <typename Device>
00415 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( double &d ) ecl_assert_throw_decl(ecl::StandardException) {
00416 
00417         ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
00418     if ( getFloatFromStream(d) ) {
00419         this->error = NoError;
00420     } // Real errors are handled internally in getFloatFromStreams
00421     return *this;
00422 }
00423 
00434 template <typename Device>
00435 InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( bool &b ) ecl_assert_throw_decl(ecl::StandardException)
00436 {
00437         ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
00438     std::string s;
00439     *this >> s;
00440 
00441     if ( this->fail() ) { // string could not be read
00442         return *this; // error already set
00443         }
00444 
00445     if ( ( s == "true" ) || ( s == "TRUE" ) || ( s == "True" ) ) {
00446         b = true;
00447         this->error = NoError;
00448     } else if ( ( s == "false" ) || ( s == "FALSE" ) || ( s == "False" ) ) {
00449         b = false;
00450         this->error = NoError;
00451     } else {
00452         this->error = ConversionError;
00453     }
00454     return *this;
00455 }
00456 
00457 /*****************************************************************************
00458 ** Implementation [InputTextStream][Non-Streaming Interface]
00459 *****************************************************************************/
00460 
00473 template <typename Device>
00474 void InputTextStream<Device,true>::enableRawCharReads() { raw_char_reads = true; }
00475 
00484 template <typename Device>
00485 void InputTextStream<Device,true>::disableRawCharReads() { raw_char_reads = false; }
00486 
00487 
00488 /*****************************************************************************
00489 ** Implementation [InputTextStream][Private Parsers]
00490 *****************************************************************************/
00491 
00501 template <typename Device>
00502 bool InputTextStream<Device,true>::skipLeadingWhiteSpace(char &c)
00503 {
00504         do {
00505         if( this->io_device.read(c) < 1 ) { // Fail if either there is a read error OR there is nothing in the device.
00506                 this->error = ReadError;
00507                 return false;
00508         }
00509         } while ( ( c == ' ' ) || ( c == '\n' ) );
00510         return true;
00511 }
00512 
00517 template <typename Device>
00518 template <typename Number>
00519 bool InputTextStream<Device,true>::parseHexInteger(Number &i)
00520 {
00521     char c;
00522     static int digits[25];
00523     static const short ceiling = numeric_limits<short>::maximum/10;
00524 
00525     i = 0;
00526     int j = 0;
00527     while ( j < 25 ) {
00528         long n = this->io_device.read(c);
00529         if ( n < 0 ) {
00530                 this->error = ReadError;
00531                 return false;
00532                 } else if ( n == 0 ) {
00533                         break; // nothing more to read.
00534                 }
00535         if ( ( c >= '0' ) && ( c <= '9') ) {
00536             digits[j] = c - '0';
00537         } else if ( ( c >= 'a' ) && ( c <= 'f') ) {
00538             digits[j] = 10 + c - 'a';
00539         } else if ( ( c >= 'A' ) && ( c <= 'F') ) {
00540             digits[j] = 10 + c - 'A';
00541         } else {
00542             break; // No more valid characters to read.
00543         }
00544         ++j;
00545     }
00546     if ( j == 0 ) {
00547         this->error = ReadError;
00548         return false;
00549         }
00550 
00551     short number = 0;
00552     for ( int k = 0; k < j; ++k ) {
00553         if ( number < ceiling ) {
00554             number = 16*number + (digits[k]);
00555         } else {
00556                 this->error = OutOfRangeError;
00557             return false;
00558         }
00559     }
00560     i = number;
00561     return true;
00562 }
00563 
00569 template <typename Device>
00570 template <typename Number>
00571 bool InputTextStream<Device,true>::getIntegerFromStream(Number &i) {
00572 
00573     static char digits[25]; // 20 is the maximum needed on a 64 bit system for a long type
00574     static const Number ceiling = ecl::numeric_limits<Number>::maximum/10;
00575     char c = ' ';
00576     Number sign_multiplier = 1;
00577     Number number;
00578 
00579         if ( !skipLeadingWhiteSpace(c) ) { return false; }
00580 
00581     if ( c == '-' ) { // Negative
00582                 if ( std::numeric_limits<Number>::min() != 0 ) {
00583             sign_multiplier = -1;
00584             if ( this->io_device.read(c) < 1 ) {
00585                 this->error = ReadError;
00586                 return false;
00587                         }
00588         } // else do nothing and continue, an error will be found at the next step.
00589     } else if ( c == '+' ) { // Positive
00590         if ( this->io_device.read(c) < 1 ) {
00591                 this->error = ReadError;
00592                 return false;
00593                 }
00594     } else if ( c == '0' ) {
00595         long n = this->io_device.read(c);
00596         if ( ( n == 0 ) || ( c == ' ' ) || ( c == '\n' ) ) { // It's just a single zero.
00597                 i = 0;
00598                 return true;
00599         } else if ( n < 0 ) {
00600                 this->error = ReadError;
00601                 return false;
00602                 } else if ( c == 'x' ) {
00603             return parseHexInteger(i);
00604         } else {
00605                 // its a regular integer, just continue
00606         }
00607     } else if ( c == 'x' ) {
00608         return parseHexInteger(i);
00609     }
00610 
00611     /*********************
00612     ** Parse reg. integer
00613     **********************/
00614     int j = 0;
00615     while ( ( c >= '0' ) && ( c <= '9') && ( j < 25 ) ) {
00616         digits[j] = c;
00617         j++;
00618         long n = this->io_device.read(c);
00619                 if ( n < 0 ) {
00620                         this->error = ReadError;
00621                         return false;
00622                 } else if ( n == 0 ) {
00623                         break;
00624                 } else { // n > 1
00625         }
00626     }
00627     if ( j == 0 ) {
00628         this->error = ConversionError;
00629         return false;
00630         }
00631     number = 0;
00632     for ( int k = 0; k < j; ++k )
00633     {
00634         if ( number < ceiling )
00635         {
00636             number = 10*number + (digits[k] - '0');
00637         } else {
00638                 this->error = OutOfRangeError;
00639             return false;
00640         }
00641     }
00642     i = sign_multiplier*number;
00643 
00644     return true;
00645 }
00646 
00647 template <typename Device>
00648 template <typename Number>
00649 bool InputTextStream<Device,true>::getFloatFromStream(Number &f) {
00650     static const int bufferSize = 25;
00651     static char digits[bufferSize]; // 20 is the maximum needed on a 64 bit system for a long type
00652     char c = ' ';
00653     int integral_length = 0;
00654     int decimal_length = 0;
00655     Number sign_multiplier = 1;
00656     Number number;
00657 
00658         if ( !skipLeadingWhiteSpace(c) ) { return false; }
00659 
00660     if ( c == '-' ) {
00661         sign_multiplier = -1;
00662         if ( this->io_device.read(c) < 1 ) { this->error = ReadError; return false; }
00663     } else if ( c == '+' ) {
00664         if ( this->io_device.read(c) < 1 ) { this->error = ReadError; return false; }
00665     }
00666     number = 0;
00667     /******************************************
00668     ** Integral part
00669     *******************************************/
00670     while ( ( c >= '0' ) && ( c <= '9') && ( integral_length < bufferSize ) ) {
00671         digits[integral_length] = c;
00672         long n = this->io_device.read(c);
00673                 if ( n < 0 ) {
00674                         this->error = ReadError; return false;
00675                 } else if ( n == 0 ) {
00676                         break;
00677                 } else { // n > 1
00678                         integral_length++;
00679         }
00680     }
00681     for ( int k = 0; k < integral_length; ++k ) {
00682         number = 10*number + (digits[k] - '0');
00683     }
00684 
00685     if ( c == '.' ) {
00686         float frac_multiplier = 1;
00687         if ( this->io_device.read(c) < 1 ) { this->error = ReadError; return false; }
00688         /******************************************
00689         ** Decimal part
00690         *******************************************/
00691         while ( ( c >= '0' ) && ( c <= '9') && ( decimal_length < bufferSize ) ) {
00692             digits[decimal_length] = c;
00693             long n = this->io_device.read(c);
00694                 if ( n < 0 ) {
00695                         this->error = ReadError; return false;
00696                 } else if ( n == 0 ) {
00697                         break;
00698                 } else { // n > 1
00699                 decimal_length++;
00700             }
00701         }
00702         for ( int k = 0; k < decimal_length; ++k ) {
00703             frac_multiplier *= 0.1f;
00704             number = number + frac_multiplier*(digits[k] - '0');
00705         }
00706     }
00707 
00708     if ( (integral_length+decimal_length) == 0 ) {
00709         this->error = ConversionError;
00710         return false;
00711         }
00712 
00713     f = sign_multiplier*number;
00714 
00715     return true;
00716 }
00717 
00718 } // namespace interfaces
00719 } // namespace ecl
00720 
00721 #endif /* ECL_STREAMS_INPUT_TEXT_STREAM_HPP_ */


ecl_streams
Author(s): Daniel Stonier (d.stonier@gmail.com)
autogenerated on Thu Jan 2 2014 11:12:54