From c123fb39c22ca6ef268d46f100f389993fdb1261 Mon Sep 17 00:00:00 2001 From: Daniel Larimer Date: Fri, 26 Oct 2012 00:58:29 -0400 Subject: [PATCH] updated io stream, simplified interface, faster cin --- include/fc/iostream.hpp | 78 ++++++++----------- include/fc/iostream_wrapper.hpp | 109 ++++++++++++++++++++++++++ include/fc/lexical_cast.hpp | 2 + src/iostream.cpp | 134 ++++++++++++++++++++++---------- 4 files changed, 239 insertions(+), 84 deletions(-) create mode 100644 include/fc/iostream_wrapper.hpp diff --git a/include/fc/iostream.hpp b/include/fc/iostream.hpp index 0a4165f..f0650d8 100644 --- a/include/fc/iostream.hpp +++ b/include/fc/iostream.hpp @@ -12,25 +12,7 @@ namespace fc { virtual size_t readsome( char* buf, size_t len ) = 0; virtual istream& read( char* buf, size_t len ) = 0; - template - friend istream& operator>>( istream& i, T& v ){ return i.read(v); } - virtual bool eof()const = 0; - - protected: - virtual istream& read( int64_t& ) = 0; - virtual istream& read( uint64_t& ) = 0; - virtual istream& read( int32_t& ) = 0; - virtual istream& read( uint32_t& ) = 0; - virtual istream& read( int16_t& ) = 0; - virtual istream& read( uint16_t& ) = 0; - virtual istream& read( int8_t& ) = 0; - virtual istream& read( uint8_t& ) = 0; - virtual istream& read( float& ) = 0; - virtual istream& read( double& ) = 0; - virtual istream& read( bool& ) = 0; - virtual istream& read( char& ) = 0; - virtual istream& read( fc::string& ) = 0; }; class ostream { @@ -38,18 +20,10 @@ namespace fc { virtual ~ostream(){}; virtual ostream& write( const char* buf, size_t len ) = 0; - virtual void close() = 0; - virtual void flush() = 0; - - template - friend ostream& operator<<( ostream& o, const T& v ) { return o.write(fc::lexical_cast(v)); } - friend ostream& operator<<( ostream& o, char* v ) { return o.write(v); } - friend ostream& operator<<( ostream& o, const char* v ) { return o.write(v); } - friend ostream& operator<<( ostream& o, const fc::string& v ){ return o.write(v); } - - protected: - virtual ostream& write( const fc::string& ) = 0; + virtual void close(){} + virtual void flush(){} }; + class iostream : public virtual ostream, public virtual istream {}; @@ -73,26 +47,42 @@ namespace fc { virtual size_t readsome( char* buf, size_t len ); virtual istream& read( char* buf, size_t len ); virtual bool eof()const; - - virtual istream& read( int64_t& ); - virtual istream& read( uint64_t& ); - virtual istream& read( int32_t& ); - virtual istream& read( uint32_t& ); - virtual istream& read( int16_t& ); - virtual istream& read( uint16_t& ); - virtual istream& read( int8_t& ); - virtual istream& read( uint8_t& ); - virtual istream& read( float& ); - virtual istream& read( double& ); - virtual istream& read( bool& ); - virtual istream& read( char& ); - virtual istream& read( fc::string& ); }; fc::istream& getline( fc::istream&, fc::string&, char delim = '\n' ); - fc::cin_t& getline( fc::cin_t&, fc::string&, char delim = '\n' ); extern cout_t cout; extern cerr_t cerr; extern cin_t cin; + + + template + ostream& operator<<( ostream& o, const T& v ) { + auto str = fc::lexical_cast(v); + o.write( str.c_str(), str.size() ); + return o; + } + ostream& operator<<( ostream& o, const char* v ); + + template + ostream& operator<<( ostream& o, const fc::string& str ) { + o.write( str.c_str(), str.size() ); + return o; + } + template + istream& operator>>( istream& o, T& v ) { + fc::string str; + getline( o, str, ' ' ); + v = fc::lexical_cast(str); + return o; + } + + fc::cin_t& getline( fc::cin_t&, fc::string&, char delim = '\n' ); + template + cin_t& operator>>( cin_t& o, T& v ) { + fc::string str; + getline( o, str, ' ' ); + v = fc::lexical_cast(str); + return o; + } } diff --git a/include/fc/iostream_wrapper.hpp b/include/fc/iostream_wrapper.hpp new file mode 100644 index 0000000..7524f9d --- /dev/null +++ b/include/fc/iostream_wrapper.hpp @@ -0,0 +1,109 @@ +#pragma once +#include +#include + +namespace fc { + /** + * Used to wrap references to other streams + */ + class ostream_wrapper : public ostream { + public: + template + ostream_wrapper( Stream& s ) + :my( new impl(s) ){} + + virtual ~ostream_wrapper(){}; + + virtual ostream& write( const char* buf, size_t len ) { + my->write(buf,len); + return *this; + } + virtual void close() { + my->close(); + } + virtual void flush() { + my->flush(); + } + + protected: + virtual ostream& write( const fc::string& s ) { + return write( s.c_str(), s.size() ); + } + + struct impl_base : public fc::retainable { + virtual void write( const char* buf, size_t len ) = 0; + virtual void close() = 0; + virtual void flush() = 0; + }; + + template + struct impl : public impl_base { + impl(T& i):st(i){} + + virtual void write( const char* buf, size_t len ) { + st.write(buf,len); + } + virtual void close() { st.close(); } + virtual void flush() { st.flush(); } + T& st; + }; + + fc::shared_ptr my; + }; + /** + * Used to wrap references to other streams + */ + class istream_wrapper : public istream { + public: + template + istream_wrapper( Stream& s ) + :my( new impl(s) ){} + + virtual ~istream_wrapper(){}; + + virtual size_t readsome( char* buf, size_t len ) { return my->readsome(buf,len); } + virtual istream& read( char* buf, size_t len ) { + my->read(buf,len); + return *this; + } + virtual void close() { } + virtual bool eof()const{ return my->eof(); } + + virtual istream& read( int64_t& ) { return *this; } + virtual istream& read( uint64_t& ) { return *this; } + virtual istream& read( int32_t& ) { return *this; } + virtual istream& read( uint32_t& ) { return *this; } + virtual istream& read( int16_t& ) { return *this; } + virtual istream& read( uint16_t& ) { return *this; } + virtual istream& read( int8_t& ) { return *this; } + virtual istream& read( uint8_t& ) { return *this; } + virtual istream& read( float& ) { return *this; } + virtual istream& read( double& ) { return *this; } + virtual istream& read( bool& ) { return *this; } + virtual istream& read( char& ) { return *this; } + virtual istream& read( fc::string& ) { return *this; } + + protected: + struct impl_base : public fc::retainable { + virtual void read( char* buf, size_t len ) = 0; + virtual size_t readsome( char* buf, size_t len ) = 0; + virtual bool eof()const; + }; + + template + struct impl : public impl_base { + impl(T& i):st(i){} + + virtual size_t readsome( char* buf, size_t len ) { return st.readsome(buf,len); } + virtual void read( char* buf, size_t len ) { + st.read(buf,len); + } + virtual bool eof()const { return st.eof(); } + T& st; + }; + + fc::shared_ptr my; + }; + +} // namespace fc + diff --git a/include/fc/lexical_cast.hpp b/include/fc/lexical_cast.hpp index fe8153e..e0f491e 100644 --- a/include/fc/lexical_cast.hpp +++ b/include/fc/lexical_cast.hpp @@ -28,6 +28,8 @@ namespace fc { fc::string to_string( int16_t d ); fc::string to_string( int8_t d ); fc::string to_string( char d ); + fc::string to_string( const char* d ); + inline fc::string to_string( fc::string s ) { return s; } template struct lexical_cast { diff --git a/src/iostream.cpp b/src/iostream.cpp index 6494efb..d4c0332 100644 --- a/src/iostream.cpp +++ b/src/iostream.cpp @@ -2,28 +2,65 @@ #include #include #include - +#include #include namespace fc { - fc::thread& cin_thread() { static fc::thread i("cin"); return i; } - - fc::cin_t& getline( fc::cin_t& i, fc::string& s, char delim ) { - if( !cin_thread().is_current() ) { - cin_thread().async([&](){ getline(i,s,delim); } ).wait(); - return i; - } - fc::stringstream ss; - char c; - i.read( &c, 1 ); - while( !i.eof() ) { - if( c == delim ) { s = ss.str(); return i; } - ss.write(&c,1); - i.read( &c, 1 ); - } - s = ss.str(); - return i; + ostream& operator<<( ostream& o, const char* v ) { + o.write( v, strlen(v) ); + return o; } + + struct cin_buffer { + cin_buffer():eof(false),write_pos(0),read_pos(0),cinthread("cin"){ + cinthread.async( [=](){read();} ); + } + + void read() { + char c; + std::cin.read(&c,1); + while( !std::cin.eof() ) { + while( write_pos - read_pos > 0xfffff ) { + fc::promise::ptr wr( new fc::promise() ); + write_ready = wr; + if( write_pos - read_pos <= 0xfffff ) { + wr->wait(); + } + write_ready.reset(); + } + buf[write_pos&0xfffff] = c; + ++write_pos; + + auto tmp = read_ready; // copy read_ready because it is accessed from multiple threads + if( tmp && !tmp->ready() ) { + tmp->set_value(); + } + std::cin.read(&c,1); + } + eof = true; + auto tmp = read_ready; // copy read_ready because it is accessed from multiple threads + if( tmp && !tmp->ready() ) { + tmp->set_value(); + } + } + fc::promise::ptr read_ready; + fc::promise::ptr write_ready; + + volatile bool eof; + + volatile uint64_t write_pos; + char buf[0xfffff+1]; // 1 mb buffer + volatile uint64_t read_pos; + fc::thread cinthread; + }; + + cin_buffer& get_cin_buffer() { + static cin_buffer* b = new cin_buffer(); + return *b; + } + + + fc::thread& cin_thread() { static fc::thread i("cin"); return i; } fc::istream& getline( fc::istream& i, fc::string& s, char delim ) { fc::stringstream ss; @@ -52,32 +89,49 @@ namespace fc { ostream& cerr_t::write( const fc::string& s ) { std::cerr<< *reinterpret_cast(&s); return *this; } size_t cin_t::readsome( char* buf, size_t len ) { - return std::cin.readsome(buf,len); - } - istream& cin_t::read( char* buf, size_t len ) { - if( !cin_thread().is_current() ) { - cin_thread().async( [=](){ this->read(buf,len); } ).wait(); - return *this; + cin_buffer& b = get_cin_buffer(); + size_t avail = b.write_pos - b.read_pos; + avail = (fc::min)(len,avail); + size_t u = 0; + while( avail && len ) { + *buf = b.buf[b.read_pos&0xfffff]; + ++b.read_pos; + ++buf; + --avail; + --len; + ++u; } - std::cin.read(buf,len); + return u; + } + + istream& cin_t::read( char* buf, size_t len ) { + cin_buffer& b = get_cin_buffer(); + do { + while( !b.eof && (b.write_pos - b.read_pos)==0 ){ + // wait for more... + fc::promise::ptr rr( new fc::promise() ); + b.read_ready = rr; + if( b.write_pos - b.read_pos == 0 ) { + rr->wait(); + } + b.read_ready.reset(); + } + if( b.eof ) return *this; + size_t r = readsome( buf, len ); + buf += r; + len -= r; + + auto tmp = b.write_ready; // copy write_writey because it is accessed from multiple thwrites + if( tmp && !tmp->ready() ) { + tmp->set_value(); + } + + + } while( len > 0 && !b.eof ); return *this; } - bool cin_t::eof()const { return std::cin.eof(); } - - istream& cin_t::read( int64_t& v) { slog(""); std::cin >> v; return *this; } - istream& cin_t::read( uint64_t& v) { slog(""); std::cin >> v; return *this; } - istream& cin_t::read( int32_t& v) { slog(""); std::cin >> v; return *this; } - istream& cin_t::read( uint32_t& v) { slog(""); std::cin >> v; return *this; } - istream& cin_t::read( int16_t& v) { slog(""); std::cin >> v; return *this; } - istream& cin_t::read( uint16_t& v) { slog(""); std::cin >> v; return *this; } - istream& cin_t::read( int8_t& v) { slog(""); std::cin >> v; return *this; } - istream& cin_t::read( uint8_t& v) { slog(""); std::cin >> v; return *this; } - istream& cin_t::read( float& v) { slog(""); std::cin >> v; return *this; } - istream& cin_t::read( double& v) { slog(""); std::cin >> v; return *this; } - istream& cin_t::read( bool& v) { slog(""); std::cin >> v; return *this; } - istream& cin_t::read( char& v) { slog(""); std::cin >> v; return *this; } - istream& cin_t::read( fc::string& v) { slog(""); std::cin >> *reinterpret_cast(&v); return *this; } + bool cin_t::eof()const { return get_cin_buffer().eof; } cout_t cout; cerr_t cerr;