Program Listing for File input_text_stream.hpp
↰ Return to documentation for file (include/ecl/streams/text_streams/input_text_stream.hpp
)
/*****************************************************************************
** Ifdefs
*****************************************************************************/
#ifndef ECL_STREAMS_INPUT_TEXT_STREAM_HPP_
#define ECL_STREAMS_INPUT_TEXT_STREAM_HPP_
/*****************************************************************************
** Includes
*****************************************************************************/
#include <iostream>
#include <limits>
#include <string>
#include <ecl/config/macros.hpp>
#include <ecl/config/portable_types.hpp>
#include <ecl/exceptions/standard_exception.hpp>
#include <ecl/concepts/devices.hpp>
#include <ecl/type_traits/numeric_limits.hpp>
#include "base_text_stream.hpp"
#include "../macros.hpp"
/*****************************************************************************
** Namespaces
*****************************************************************************/
namespace ecl {
namespace interfaces {
/*****************************************************************************
** Interface [InputTextStream]
*****************************************************************************/
template <typename Device, bool InputDevice = true >
class ECL_PUBLIC InputTextStream {
};
template <typename Device>
class ECL_PUBLIC InputTextStream<Device,true> : public virtual BaseTextStream<Device> {
public:
/*********************
** Constructors
**********************/
InputTextStream();
virtual ~InputTextStream() {}
/*********************
** Streaming Operators
**********************/
InputTextStream<Device>& operator >> ( char &c );
InputTextStream<Device>& operator >> ( std::string &s );
InputTextStream<Device>& operator >> ( short &i );
InputTextStream<Device>& operator >> ( int &i );
InputTextStream<Device>& operator >> ( long &i );
InputTextStream<Device>& operator >> ( unsigned char &c );
InputTextStream<Device>& operator >> ( unsigned short &i );
InputTextStream<Device>& operator >> ( unsigned int &i );
InputTextStream<Device>& operator >> ( unsigned long &i );
InputTextStream<Device>& operator >> ( float &f );
InputTextStream<Device>& operator >> ( double &d );
InputTextStream<Device>& operator >> ( long long &i );
InputTextStream<Device>& operator >> ( unsigned long long &i );
InputTextStream<Device>& operator >> ( bool &b );
/*********************
** Non-Streaming API
**********************/
void enableRawCharReads();
void disableRawCharReads();
private:
bool raw_char_reads;
/*********************
** Private Parsers
**********************/
bool skipLeadingWhiteSpace(char &c);
template <typename Number>
bool getIntegerFromStream(Number &i);
template <typename Number>
bool parseHexInteger(Number &i);
template <typename Number>
bool getFloatFromStream(Number &f);
};
/*****************************************************************************
** Implementation [InputTextStream]
*****************************************************************************/
template <typename Device>
InputTextStream<Device,true>::InputTextStream() : raw_char_reads(false) {
ecl_compile_time_concept_check(ecl::InputCharDeviceConcept<Device>);
}
/*****************************************************************************
** Implementation [InputTextStream][Streaming Operators]
*****************************************************************************/
template <typename Device>
InputTextStream<Device> & InputTextStream<Device,true>::operator >> ( char &c ) {
ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
if ( !raw_char_reads ) {
if( skipLeadingWhiteSpace(c) ) {
this->error = NoError;
} else {
this->error = ReadError;
}
} else {
if ( this->io_device.read(c) == 1 ) {
this->error = NoError;
} else {
this->error = ReadError;
}
}
return *this;
}
template <typename Device>
InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( std::string &s ) {
ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
char c;
if ( skipLeadingWhiteSpace(c) ) {
s.clear();
do {
s.push_back(c);
if( this->io_device.read(c) < 1 ) {
this->error = ReadError;
break;
}
} while ( ( c != ' ' ) && ( c != '\n' ) );
this->error = NoError;
} else {
this->error = ReadError;
}
// Original method - reads a whole line (must be terminated by a \n)
// static char buffer[80];
// this->io_device.read(&buffer[0],80);
// s.assign(buffer);
return *this;
}
template <typename Device>
InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( short &i ) {
ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
if ( getIntegerFromStream(i) ) {
this->error = NoError;
} // Real errors are handled internally in getIntegerFromStreams
return *this;
}
template <typename Device>
InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( int &i ) {
ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
if ( getIntegerFromStream(i) ) {
this->error = NoError;
} // Real errors are handled internally in getIntegerFromStreams
return *this;
}
template <typename Device>
InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( long &i ) {
ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
if ( getIntegerFromStream(i) ) {
this->error = NoError;
} // Real errors are handled internally in getIntegerFromStreams
return *this;
}
template <typename Device>
InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( long long &i ) {
ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
if ( getIntegerFromStream(i) ) {
this->error = NoError;
} // Real errors are handled internally in getIntegerFromStreams
return *this;
}
template <typename Device>
InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( unsigned char &uc ) {
ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
if ( getIntegerFromStream(uc) ) {
this->error = NoError;
} // Real errors are handled internally in getIntegerFromStreams
return *this;
}
template <typename Device>
InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( unsigned short &i ) {
ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
if ( getIntegerFromStream(i) ) {
this->error = NoError;
} // Real errors are handled internally in getIntegerFromStreams
return *this;
}
template <typename Device>
InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( unsigned int &i ) {
ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
if ( getIntegerFromStream(i) ) {
this->error = NoError;
} // Real errors are handled internally in getIntegerFromStreams
return *this;
}
template <typename Device>
InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( unsigned long &i ) {
ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
if ( getIntegerFromStream(i) ) {
this->error = NoError;
} // Real errors are handled internally in getIntegerFromStreams
return *this;
}
template <typename Device>
InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( unsigned long long &i ) {
ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
if ( getIntegerFromStream(i) ) {
this->error = NoError;
} // Real errors are handled internally in getIntegerFromStreams
return *this;
}
template <typename Device>
InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( float &f ) {
ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
if ( getFloatFromStream(f) ) {
this->error = NoError;
} // Real errors are handled internally in getFloatFromStreams
return *this;
}
template <typename Device>
InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( double &d ) {
ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
if ( getFloatFromStream(d) ) {
this->error = NoError;
} // Real errors are handled internally in getFloatFromStreams
return *this;
}
template <typename Device>
InputTextStream<Device>& InputTextStream<Device,true>::operator >> ( bool &b )
{
ecl_assert_throw(this->io_device.open(),ecl::StandardException(LOC,OpenError,"The underlying stream device is not open."));
std::string s;
*this >> s;
if ( this->fail() ) { // string could not be read
return *this; // error already set
}
if ( ( s == "true" ) || ( s == "TRUE" ) || ( s == "True" ) ) {
b = true;
this->error = NoError;
} else if ( ( s == "false" ) || ( s == "FALSE" ) || ( s == "False" ) ) {
b = false;
this->error = NoError;
} else {
this->error = ConversionError;
}
return *this;
}
/*****************************************************************************
** Implementation [InputTextStream][Non-Streaming Interface]
*****************************************************************************/
template <typename Device>
void InputTextStream<Device,true>::enableRawCharReads() { raw_char_reads = true; }
template <typename Device>
void InputTextStream<Device,true>::disableRawCharReads() { raw_char_reads = false; }
/*****************************************************************************
** Implementation [InputTextStream][Private Parsers]
*****************************************************************************/
template <typename Device>
bool InputTextStream<Device,true>::skipLeadingWhiteSpace(char &c)
{
do {
if( this->io_device.read(c) < 1 ) { // Fail if either there is a read error OR there is nothing in the device.
this->error = ReadError;
return false;
}
} while ( ( c == ' ' ) || ( c == '\n' ) );
return true;
}
template <typename Device>
template <typename Number>
bool InputTextStream<Device,true>::parseHexInteger(Number &i)
{
char c;
static int digits[25];
static const short ceiling = numeric_limits<short>::maximum/10;
i = 0;
int j = 0;
while ( j < 25 ) {
long n = this->io_device.read(c);
if ( n < 0 ) {
this->error = ReadError;
return false;
} else if ( n == 0 ) {
break; // nothing more to read.
}
if ( ( c >= '0' ) && ( c <= '9') ) {
digits[j] = c - '0';
} else if ( ( c >= 'a' ) && ( c <= 'f') ) {
digits[j] = 10 + c - 'a';
} else if ( ( c >= 'A' ) && ( c <= 'F') ) {
digits[j] = 10 + c - 'A';
} else {
break; // No more valid characters to read.
}
++j;
}
if ( j == 0 ) {
this->error = ReadError;
return false;
}
short number = 0;
for ( int k = 0; k < j; ++k ) {
if ( number < ceiling ) {
number = 16*number + (digits[k]);
} else {
this->error = OutOfRangeError;
return false;
}
}
i = number;
return true;
}
template <typename Device>
template <typename Number>
bool InputTextStream<Device,true>::getIntegerFromStream(Number &i) {
static char digits[25]; // 20 is the maximum needed on a 64 bit system for a long type
static const Number ceiling = ecl::numeric_limits<Number>::maximum/10;
char c = ' ';
Number sign_multiplier = 1;
Number number;
if ( !skipLeadingWhiteSpace(c) ) { return false; }
if ( c == '-' ) { // Negative
if ( std::numeric_limits<Number>::min() != 0 ) {
sign_multiplier = -1;
if ( this->io_device.read(c) < 1 ) {
this->error = ReadError;
return false;
}
} // else do nothing and continue, an error will be found at the next step.
} else if ( c == '+' ) { // Positive
if ( this->io_device.read(c) < 1 ) {
this->error = ReadError;
return false;
}
} else if ( c == '0' ) {
long n = this->io_device.read(c);
if ( ( n == 0 ) || ( c == ' ' ) || ( c == '\n' ) ) { // It's just a single zero.
i = 0;
return true;
} else if ( n < 0 ) {
this->error = ReadError;
return false;
} else if ( c == 'x' ) {
return parseHexInteger(i);
} else {
// its a regular integer, just continue
}
} else if ( c == 'x' ) {
return parseHexInteger(i);
}
/*********************
** Parse reg. integer
**********************/
int j = 0;
while ( ( c >= '0' ) && ( c <= '9') && ( j < 25 ) ) {
digits[j] = c;
j++;
long n = this->io_device.read(c);
if ( n < 0 ) {
this->error = ReadError;
return false;
} else if ( n == 0 ) {
break;
} else { // n > 1
}
}
if ( j == 0 ) {
this->error = ConversionError;
return false;
}
number = 0;
for ( int k = 0; k < j; ++k )
{
if ( number < ceiling )
{
number = 10*number + (digits[k] - '0');
} else {
this->error = OutOfRangeError;
return false;
}
}
i = sign_multiplier*number;
return true;
}
template <typename Device>
template <typename Number>
bool InputTextStream<Device,true>::getFloatFromStream(Number &f) {
static const int bufferSize = 25;
static char digits[bufferSize]; // 20 is the maximum needed on a 64 bit system for a long type
char c = ' ';
int integral_length = 0;
int decimal_length = 0;
Number sign_multiplier = 1;
Number number;
if ( !skipLeadingWhiteSpace(c) ) { return false; }
if ( c == '-' ) {
sign_multiplier = -1;
if ( this->io_device.read(c) < 1 ) { this->error = ReadError; return false; }
} else if ( c == '+' ) {
if ( this->io_device.read(c) < 1 ) { this->error = ReadError; return false; }
}
number = 0;
/******************************************
** Integral part
*******************************************/
while ( ( c >= '0' ) && ( c <= '9') && ( integral_length < bufferSize ) ) {
digits[integral_length] = c;
long n = this->io_device.read(c);
if ( n < 0 ) {
this->error = ReadError; return false;
} else if ( n == 0 ) {
break;
} else { // n > 1
integral_length++;
}
}
for ( int k = 0; k < integral_length; ++k ) {
number = 10*number + (digits[k] - '0');
}
if ( c == '.' ) {
float frac_multiplier = 1;
if ( this->io_device.read(c) < 1 ) { this->error = ReadError; return false; }
/******************************************
** Decimal part
*******************************************/
while ( ( c >= '0' ) && ( c <= '9') && ( decimal_length < bufferSize ) ) {
digits[decimal_length] = c;
long n = this->io_device.read(c);
if ( n < 0 ) {
this->error = ReadError; return false;
} else if ( n == 0 ) {
break;
} else { // n > 1
decimal_length++;
}
}
for ( int k = 0; k < decimal_length; ++k ) {
frac_multiplier *= 0.1f;
number = number + frac_multiplier*(digits[k] - '0');
}
}
if ( (integral_length+decimal_length) == 0 ) {
this->error = ConversionError;
return false;
}
f = sign_multiplier*number;
return true;
}
} // namespace interfaces
} // namespace ecl
#endif /* ECL_STREAMS_INPUT_TEXT_STREAM_HPP_ */