Rename signal_closing to signal_flush_required
sigc::signal<void> signal_end_of_file;
/**
sigc::signal<void> signal_end_of_file;
/**
- Emitted when the I/O object is about to close. Mainly intended for
- buffering objects that need to flush their buffers at closing.
+ Emitted when there is a nonlinearity in I/O (such as a file being seeked)
+ and any data buffered by upper layers needs to be flushed.
- sigc::signal<void> signal_closing;
+ sigc::signal<void> signal_flush_required;
/**
Emitted when the I/O object has closed.
/**
Emitted when the I/O object has closed.
Buffered::Buffered(Base &b, unsigned s):
below(b),
buf_size(s),
Buffered::Buffered(Base &b, unsigned s):
below(b),
buf_size(s),
- in_buf(new char[buf_size]),
- in_ptr(in_buf),
- in_avail(0),
- out_buf(new char[buf_size]),
- out_used(0)
+ buf(new char[buf_size]),
+ begin(buf),
+ end(buf),
+ cur_op(M_NONE)
- below.signal_closing.connect(sigc::mem_fun(this, &Buffered::below_closing));
+ below.signal_flush_required.connect(sigc::mem_fun(this, &Buffered::flush));
}
unsigned Buffered::put(char c)
{
}
unsigned Buffered::put(char c)
{
+ set_op(M_WRITE);
+
+ if(end<buf+buf_size)
- if(out_used==0)
- return;
-
- unsigned len=below.write(out_buf, out_used);
- if(len<out_used)
- memmove(out_buf, out_buf+len, out_used-len);
- out_used-=len;
- throw Exception("Couldn't flush all data");
+ unsigned used=end-begin;
+ if(used)
+ {
+ unsigned len=below.write(begin, used);
+
+ begin=end=buf;
+
+ if(len<used)
+ throw Exception("Couldn't flush all data");
+ }
+ else if(cur_op==M_READ)
+ begin=end=buf;
}
bool Buffered::getline(std::string &line)
{
}
bool Buffered::getline(std::string &line)
{
- for(unsigned i=0; i<in_avail; ++i)
- if(in_ptr[i]=='\n')
+ set_op(M_READ);
+
+ for(char *i=begin; i!=end; ++i)
+ if(*i=='\n')
- line.assign(in_ptr, i);
- in_ptr+=i+1;
- in_avail-=i+1;
+ line.assign(begin, i-begin);
+ begin=i+1;
- if(in_avail>0)
- {
- --in_avail;
- return *in_ptr++;
- }
+ set_op(M_READ);
+
+ if(begin<end)
+ return static_cast<unsigned char>(*begin++);
char c;
if(do_read(&c, 1)==0)
char c;
if(do_read(&c, 1)==0)
throw Exception("Buffered doesn't support events");
}
throw Exception("Buffered doesn't support events");
}
+unsigned Buffered::get_current_size() const
+{
+ return end-begin;
+}
+
Buffered::~Buffered()
{
try
Buffered::~Buffered()
{
try
- delete[] in_buf;
- delete[] out_buf;
-void Buffered::below_closing()
+void Buffered::set_op(Mode op)
+ if(op!=cur_op)
+ flush();
+ cur_op=op;
-unsigned Buffered::do_write(const char *buf, unsigned size)
+unsigned Buffered::do_write(const char *data, unsigned size)
- if(out_used+size<buf_size)
+ set_op(M_WRITE);
+
+ if(end+size<buf+buf_size)
- // All data fits in the buffer
- memcpy(out_buf+out_used, buf, size);
- out_used+=size;
+ // All data fits in buffer with whatever is already there
+ memcpy(end, data, size);
+ end+=size;
- int ret=0;
- bool ok=true;
+ // Clear the buffer to make more room
+ flush();
- // XXX sub-obtimal - should try to write directly from input first
- // Fill the buffer and pass it on
- unsigned head=min(buf_size-out_used, size);
-
- memcpy(out_buf+out_used, buf, head);
- out_used+=head;
-
- buf+=head;
- size-=head;
- ret+=head;
-
- if(!ok) break;
+ // Put new data in the buffer to wait for more
+ memcpy(end, data, size);
+ end+=size;
- unsigned len=below.write(out_buf, out_used);
-
- ok=(len==out_used);
- if(ok)
- out_used=0;
- else
- {
- memmove(out_buf, out_buf+len, buf_size-len);
- out_used=buf_size-len;
- }
+ else
+ // New data still doesn't fit in the buffer, so write it directly
+ return below.write(data, size);
-unsigned Buffered::do_read(char *buf, unsigned size)
+unsigned Buffered::do_read(char *data, unsigned size)
+ set_op(M_READ);
+
+ if(begin+size<=end)
{
// The request can be served from the buffer
{
// The request can be served from the buffer
- memcpy(buf, in_ptr, size);
- in_ptr+=size;
- in_avail-=size;
+ memcpy(data, begin, size);
+ begin+=size;
+
+ eof_flag=(below.eof() && begin==end);
- // Use whatever is left in the buffer
- memcpy(buf, in_ptr, in_avail);
-
- buf+=in_avail;
- size-=in_avail;
- int ret=in_avail;
+ // Give out whatever is in the buffer already
+ memcpy(data, begin, end-begin);
+ unsigned ret=end-begin;
+ begin=end=buf;
- in_ptr=in_buf;
- in_avail=0;
+ data+=ret;
+ size-=ret;
- if(size>=buf_size)
- ret+=below.read(buf, size);
- else
- // Read more data into the buffer
- while(size>0)
- {
- in_avail=below.read(in_buf, buf_size);
- if(in_avail==0)
- {
- eof_flag=true;
- break;
- }
-
- unsigned head=min(size, in_avail);
- memcpy(buf, in_buf, head);
- buf+=head;
- size-=head;
-
- in_ptr=in_buf+head;
- in_avail-=head;
- ret+=head;
- }
+ // Fill the buffer and serve the rest of the request from it
+ unsigned len=below.read(end, buf+buf_size-end);
+ end+=len;
+
+ len=min(static_cast<unsigned>(end-begin), size);
+ memcpy(data, begin, len);
+ begin+=len;
+ ret+=len;
+ else
+ // Read the rest directly from the underlying object
+ ret+=below.read(data, size);
+
+ eof_flag=(below.eof() && begin==end);
class Buffered: public Base
{
class Buffered: public Base
{
+private:
+ Base &below;
+ unsigned buf_size;
+ char *buf;
+ char *begin;
+ char *end;
+ Mode cur_op;
+
public:
Buffered(Base &, unsigned =8192);
public:
Buffered(Base &, unsigned =8192);
unsigned put(char);
void flush();
bool getline(std::string &);
int get();
unsigned put(char);
void flush();
bool getline(std::string &);
int get();
Handle get_event_handle();
Handle get_event_handle();
+ Mode get_current_op() const { return cur_op; }
+ unsigned get_current_size() const;
- Base &below;
- unsigned buf_size;
- char *in_buf;
- char *in_ptr;
- unsigned in_avail;
- char *out_buf;
- unsigned out_used;
-
- void below_closing();
unsigned do_write(const char *, unsigned);
unsigned do_read(char *, unsigned);
};
unsigned do_write(const char *, unsigned);
unsigned do_read(char *, unsigned);
};
+ signal_flush_required.emit();
#ifdef WIN32
CloseHandle(handle);
#ifdef WIN32
CloseHandle(handle);
+void File::sync()
+{
+#ifndef WIN32
+ signal_flush_required.emit();
+
+ fsync(handle);
+#endif
+}
+
/**
Seeks the file to the given byte offset.
/**
Seeks the file to the given byte offset.
+ signal_flush_required.emit();
+
int type=sys_seek_type(st);
#ifdef WIN32
DWORD ret=SetFilePointer(handle, off, 0, type);
int type=sys_seek_type(st);
#ifdef WIN32
DWORD ret=SetFilePointer(handle, off, 0, type);
-void File::sync()
-{
-#ifndef WIN32
- fsync(handle);
-#endif
-}
-
/**
Reads data from the file.
/**
Reads data from the file.
void close();
void set_block(bool);
void close();
void set_block(bool);
- int seek(int, SeekType);
- int tell() const;
+ virtual int seek(int, SeekType);
+ virtual int tell() const;
- Handle get_event_handle() { return handle; }
+ virtual Handle get_event_handle() { return handle; }
- void check_access(Mode) const;
- unsigned do_write(const char *, unsigned);
- unsigned do_read(char *, unsigned);
+ void check_access(Mode) const;
+ virtual unsigned do_write(const char *, unsigned);
+ virtual unsigned do_read(char *, unsigned);
};
inline File::CreateMode operator|(File::CreateMode m, File::CreateMode n)
};
inline File::CreateMode operator|(File::CreateMode m, File::CreateMode n)
+ signal_flush_required.emit();
#ifdef WIN32
CloseHandle(handle[0]);
CloseHandle(handle[1]);
#ifdef WIN32
CloseHandle(handle[0]);
CloseHandle(handle[1]);