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


ecl_streams
Author(s): Daniel Stonier
autogenerated on Sun Oct 5 2014 23:36:00