383 lines
9.6 KiB
C++
383 lines
9.6 KiB
C++
#include <fc/io/iostream.hpp>
|
|
#include <fc/io/sstream.hpp>
|
|
#include <fc/thread/thread.hpp>
|
|
#include <iostream>
|
|
#include <string.h>
|
|
//#include <fc/log.hpp>
|
|
#include <fc/thread/mutex.hpp>
|
|
#include <fc/thread/scoped_lock.hpp>
|
|
#include <string>
|
|
#include <boost/lexical_cast.hpp>
|
|
#include <boost/thread/mutex.hpp>
|
|
#include <fc/io/stdio.hpp>
|
|
#include <fc/log/logger.hpp>
|
|
|
|
namespace fc {
|
|
|
|
struct cin_buffer {
|
|
cin_buffer():eof(false),write_pos(0),read_pos(0),cinthread("cin"){
|
|
|
|
cinthread.async( [=](){read();}, "cin_buffer::read" );
|
|
}
|
|
|
|
void read() {
|
|
char c;
|
|
std::cin.read(&c,1);
|
|
while( !std::cin.eof() ) {
|
|
while( write_pos - read_pos > 0xfffff ) {
|
|
fc::promise<void>::ptr wr( new fc::promise<void>("cin_buffer::write_ready") );
|
|
write_ready = wr;
|
|
if( write_pos - read_pos <= 0xfffff ) {
|
|
wr->wait();
|
|
}
|
|
write_ready.reset();
|
|
}
|
|
buf[write_pos&0xfffff] = c;
|
|
++write_pos;
|
|
|
|
fc::promise<void>::ptr tmp;
|
|
{ // copy read_ready because it is accessed from multiple threads
|
|
fc::scoped_lock<boost::mutex> lock( read_ready_mutex );
|
|
tmp = read_ready;
|
|
}
|
|
|
|
if( tmp && !tmp->ready() ) {
|
|
tmp->set_value();
|
|
}
|
|
std::cin.read(&c,1);
|
|
}
|
|
eof = true;
|
|
fc::promise<void>::ptr tmp;
|
|
{ // copy read_ready because it is accessed from multiple threads
|
|
fc::scoped_lock<boost::mutex> lock( read_ready_mutex );
|
|
tmp = read_ready;
|
|
}
|
|
if( tmp && !tmp->ready() ) {
|
|
tmp->set_exception( exception_ptr( new eof_exception() ));
|
|
}
|
|
}
|
|
boost::mutex read_ready_mutex;
|
|
fc::promise<void>::ptr read_ready;
|
|
fc::promise<void>::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;
|
|
char c;
|
|
i.read( &c, 1 );
|
|
while( true ) {
|
|
if( c == delim ) { s = ss.str(); return i; }
|
|
if( c != '\r' ) ss.write(&c,1);
|
|
i.read( &c, 1 );
|
|
}
|
|
s = ss.str();
|
|
return i;
|
|
}
|
|
|
|
|
|
size_t cout_t::writesome( const char* buf, size_t len ) { std::cout.write(buf,len); return len; }
|
|
size_t cout_t::writesome( const std::shared_ptr<const char>& buf, size_t len, size_t offset ) { return writesome(buf.get() + offset, len); }
|
|
void cout_t::close() {}
|
|
void cout_t::flush() { std::cout.flush(); }
|
|
|
|
size_t cerr_t::writesome( const char* buf, size_t len ) { std::cerr.write(buf,len); return len; }
|
|
size_t cerr_t::writesome( const std::shared_ptr<const char>& buf, size_t len, size_t offset ) { return writesome(buf.get() + offset, len); }
|
|
void cerr_t::close() {};
|
|
void cerr_t::flush() { std::cerr.flush(); }
|
|
|
|
|
|
size_t cin_t::readsome( char* buf, size_t len ) {
|
|
cin_buffer& b = get_cin_buffer();
|
|
int64_t avail = b.write_pos - b.read_pos;
|
|
avail = (fc::min)(int64_t(len),avail);
|
|
int64_t u = 0;
|
|
|
|
if( !((avail>0) && (len>0)) ) {
|
|
read( buf, 1 );
|
|
++buf;
|
|
++u;
|
|
--len;
|
|
}
|
|
|
|
while( (avail>0) && (len>0) ) {
|
|
*buf = b.buf[b.read_pos&0xfffff];
|
|
++b.read_pos;
|
|
++buf;
|
|
--avail;
|
|
--len;
|
|
++u;
|
|
}
|
|
return size_t(u);
|
|
}
|
|
size_t cin_t::readsome( const std::shared_ptr<char>& buf, size_t len, size_t offset ) { return readsome(buf.get() + offset, len); }
|
|
|
|
cin_t::~cin_t() {
|
|
/*
|
|
cin_buffer& b = get_cin_buffer();
|
|
if( b.read_ready ) {
|
|
b.read_ready->wait();
|
|
}
|
|
*/
|
|
}
|
|
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<void>::ptr rr( new fc::promise<void>("cin_buffer::read_ready") );
|
|
{ // copy read_ready because it is accessed from multiple threads
|
|
fc::scoped_lock<boost::mutex> lock( b.read_ready_mutex );
|
|
b.read_ready = rr;
|
|
}
|
|
if( b.write_pos - b.read_pos == 0 ) {
|
|
rr->wait();
|
|
}
|
|
// b.read_ready.reset();
|
|
{ // copy read_ready because it is accessed from multiple threads
|
|
fc::scoped_lock<boost::mutex> lock( b.read_ready_mutex );
|
|
b.read_ready.reset();
|
|
}
|
|
}
|
|
if( b.eof ) FC_THROW_EXCEPTION( eof_exception, "cin" );
|
|
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 );
|
|
if( b.eof ) FC_THROW_EXCEPTION( eof_exception, "cin" );
|
|
return *this;
|
|
}
|
|
|
|
bool cin_t::eof()const { return get_cin_buffer().eof; }
|
|
|
|
|
|
std::shared_ptr<cin_t> cin_ptr = std::make_shared<cin_t>();
|
|
std::shared_ptr<cout_t> cout_ptr = std::make_shared<cout_t>();
|
|
std::shared_ptr<cerr_t> cerr_ptr = std::make_shared<cerr_t>();
|
|
cout_t& cout = *cout_ptr;
|
|
cerr_t& cerr = *cerr_ptr;
|
|
cin_t& cin = *cin_ptr;
|
|
|
|
|
|
ostream& operator<<( ostream& o, const char v )
|
|
{
|
|
o.write( &v, 1 );
|
|
return o;
|
|
}
|
|
ostream& operator<<( ostream& o, const char* v )
|
|
{
|
|
o.write( v, strlen(v) );
|
|
return o;
|
|
}
|
|
|
|
ostream& operator<<( ostream& o, const std::string& v )
|
|
{
|
|
o.write( v.c_str(), v.size() );
|
|
return o;
|
|
}
|
|
#ifdef USE_FC_STRING
|
|
ostream& operator<<( ostream& o, const fc::string& v )
|
|
{
|
|
o.write( v.c_str(), v.size() );
|
|
return o;
|
|
}
|
|
#endif
|
|
|
|
ostream& operator<<( ostream& o, const double& v )
|
|
{
|
|
return o << boost::lexical_cast<std::string>(v).c_str();
|
|
}
|
|
|
|
ostream& operator<<( ostream& o, const float& v )
|
|
{
|
|
return o << boost::lexical_cast<std::string>(v).c_str();
|
|
}
|
|
|
|
ostream& operator<<( ostream& o, const int64_t& v )
|
|
{
|
|
return o << boost::lexical_cast<std::string>(v).c_str();
|
|
}
|
|
|
|
ostream& operator<<( ostream& o, const uint64_t& v )
|
|
{
|
|
return o << boost::lexical_cast<std::string>(v).c_str();
|
|
}
|
|
|
|
ostream& operator<<( ostream& o, const int32_t& v )
|
|
{
|
|
return o << boost::lexical_cast<std::string>(v).c_str();
|
|
}
|
|
|
|
ostream& operator<<( ostream& o, const uint32_t& v )
|
|
{
|
|
return o << boost::lexical_cast<std::string>(v).c_str();
|
|
}
|
|
|
|
ostream& operator<<( ostream& o, const int16_t& v )
|
|
{
|
|
return o << boost::lexical_cast<std::string>(v).c_str();
|
|
}
|
|
|
|
ostream& operator<<( ostream& o, const uint16_t& v )
|
|
{
|
|
return o << boost::lexical_cast<std::string>(v).c_str();
|
|
}
|
|
|
|
ostream& operator<<( ostream& o, const int8_t& v )
|
|
{
|
|
return o << boost::lexical_cast<std::string>(v).c_str();
|
|
}
|
|
|
|
ostream& operator<<( ostream& o, const uint8_t& v )
|
|
{
|
|
return o << boost::lexical_cast<std::string>(v).c_str();
|
|
}
|
|
|
|
#ifdef __APPLE__
|
|
ostream& operator<<( ostream& o, const size_t& v )
|
|
{
|
|
return o << boost::lexical_cast<std::string>(v).c_str();
|
|
}
|
|
|
|
#endif
|
|
|
|
istream& operator>>( istream& o, std::string& v )
|
|
{
|
|
assert(false && "not implemented");
|
|
return o;
|
|
}
|
|
|
|
#ifdef USE_FC_STRING
|
|
istream& operator>>( istream& o, fc::string& v )
|
|
{
|
|
assert(false && "not implemented");
|
|
return o;
|
|
}
|
|
#endif
|
|
|
|
istream& operator>>( istream& o, char& v )
|
|
{
|
|
o.read(&v,1);
|
|
return o;
|
|
}
|
|
|
|
istream& operator>>( istream& o, double& v )
|
|
{
|
|
assert(false && "not implemented");
|
|
return o;
|
|
}
|
|
|
|
istream& operator>>( istream& o, float& v )
|
|
{
|
|
assert(false && "not implemented");
|
|
return o;
|
|
}
|
|
|
|
istream& operator>>( istream& o, int64_t& v )
|
|
{
|
|
assert(false && "not implemented");
|
|
return o;
|
|
}
|
|
|
|
istream& operator>>( istream& o, uint64_t& v )
|
|
{
|
|
assert(false && "not implemented");
|
|
return o;
|
|
}
|
|
|
|
istream& operator>>( istream& o, int32_t& v )
|
|
{
|
|
assert(false && "not implemented");
|
|
return o;
|
|
}
|
|
|
|
istream& operator>>( istream& o, uint32_t& v )
|
|
{
|
|
assert(false && "not implemented");
|
|
return o;
|
|
}
|
|
|
|
istream& operator>>( istream& o, int16_t& v )
|
|
{
|
|
assert(false && "not implemented");
|
|
return o;
|
|
}
|
|
|
|
istream& operator>>( istream& o, uint16_t& v )
|
|
{
|
|
assert(false && "not implemented");
|
|
return o;
|
|
}
|
|
|
|
istream& operator>>( istream& o, int8_t& v )
|
|
{
|
|
assert(false && "not implemented");
|
|
return o;
|
|
}
|
|
|
|
istream& operator>>( istream& o, uint8_t& v )
|
|
{
|
|
assert(false && "not implemented");
|
|
return o;
|
|
}
|
|
|
|
|
|
char istream::get()
|
|
{
|
|
char tmp;
|
|
read(&tmp,1);
|
|
return tmp;
|
|
}
|
|
|
|
istream& istream::read( char* buf, size_t len )
|
|
{
|
|
char* pos = buf;
|
|
while( size_t(pos-buf) < len )
|
|
pos += readsome( pos, len - (pos - buf) );
|
|
return *this;
|
|
}
|
|
|
|
istream& istream::read( const std::shared_ptr<char>& buf, size_t len, size_t offset )
|
|
{
|
|
size_t bytes_read = 0;
|
|
while( bytes_read < len )
|
|
bytes_read += readsome(buf, len - bytes_read, bytes_read + offset);
|
|
return *this;
|
|
}
|
|
|
|
ostream& ostream::write( const char* buf, size_t len )
|
|
{
|
|
const char* pos = buf;
|
|
while( size_t(pos-buf) < len )
|
|
pos += writesome( pos, len - (pos - buf) );
|
|
return *this;
|
|
}
|
|
|
|
ostream& ostream::write( const std::shared_ptr<const char>& buf, size_t len, size_t offset )
|
|
{
|
|
size_t bytes_written = 0;
|
|
while( bytes_written < len )
|
|
bytes_written += writesome(buf, len - bytes_written, bytes_written + offset);
|
|
return *this;
|
|
}
|
|
|
|
} // namespace fc
|