]> git.tdb.fi Git - libs/core.git/blobdiff - source/buffered.cpp
Move class members and comments around
[libs/core.git] / source / buffered.cpp
index 4cd5cb4d0eed742c81357cedd634895793dae7f2..f53d2fc23fa49e38ede87da0188b40d3cfeadb50 100644 (file)
@@ -1,11 +1,6 @@
-/* $Id$
-
-This file is part of libmspio
-Copyright © 2007 Mikko Rasa, Mikkosoft Productions
-Distributed under the LGPL
-*/
+#include <cstring>
 #include "buffered.h"
-#include "error.h"
+#include "except.h"
 
 using namespace std;
 
@@ -15,189 +10,178 @@ namespace IO {
 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)
 {
-       mode=below.get_mode();
-       below.signal_closing.connect(sigc::mem_fun(this, &Buffered::below_closing));
+       mode = below.get_mode();
+       below.signal_flush_required.connect(sigc::mem_fun(this, &Buffered::flush));
 }
 
-unsigned Buffered::put(char c)
+Buffered::~Buffered()
 {
-       if(out_used<buf_size)
+       try
        {
-               out_buf[out_used++]=c;
-               return 1;
+               flush();
        }
-       else
-               return do_write(&c, 1);
+       catch(...)
+       { }
+
+       delete[] buf;
 }
 
 void Buffered::flush()
 {
-       if(out_used==0)
-               return;
-
-       unsigned len=below.write(out_buf, out_used);
-       if(len<out_used)
+       if(cur_op==M_WRITE)
        {
-               memmove(out_buf, out_buf+len, out_used-len);
-               out_used-=len;
-               throw Exception("Couldn't flush all data");
-       }
-       out_used=0;
-}
-
-bool Buffered::getline(std::string &line)
-{
-       for(unsigned i=0; i<in_avail; ++i)
-               if(in_ptr[i]=='\n')
+               unsigned used = end-begin;
+               if(used)
                {
-                       line.assign(in_ptr, i);
-                       in_ptr+=i+1;
-                       in_avail-=i+1;
-                       return true;
-               }
+                       unsigned len = below.write(begin, used);
 
-       return Base::getline(line);
-}
+                       begin=end = buf;
 
-int Buffered::get()
-{
-       if(in_avail>0)
-       {
-               --in_avail;
-               return *in_ptr++;
+                       if(len<used)
+                               throw Exception("Couldn't flush all data");
+               }
        }
-
-       char c;
-       if(do_read(&c, 1)==0)
-               return -1;
-       return static_cast<unsigned char>(c);
+       else if(cur_op==M_READ)
+               begin=end = buf;
 }
 
-Handle Buffered::get_event_handle()
+unsigned Buffered::do_write(const char *data, unsigned size)
 {
-       throw Exception("Buffered doesn't support events");
-}
+       set_op(M_WRITE);
 
-Buffered::~Buffered()
-{
-       try
+       if(end+size<buf+buf_size)
        {
-               flush();
+               // All data fits in buffer with whatever is already there
+               memcpy(end, data, size);
+               end += size;
+
+               return size;
        }
-       catch(...)
-       { }
+       else
+       {
+               // Clear the buffer to make more room
+               flush();
 
-       delete[] in_buf;
-       delete[] out_buf;
-}
+               if(size<buf_size)
+               {
+                       // Put new data in the buffer to wait for more
+                       memcpy(end, data, size);
+                       end += size;
 
-void Buffered::below_closing()
-{
-       flush();
+                       return size;
+               }
+               else
+                       // New data still doesn't fit in the buffer, so write it directly
+                       return below.write(data, size);
+       }
 }
 
-unsigned Buffered::do_write(const char *buf, unsigned size)
+unsigned Buffered::do_read(char *data, unsigned size)
 {
-       if(out_used+size<buf_size)
+       set_op(M_READ);
+
+       if(begin+size<=end)
        {
-               // All data fits in the buffer
-               memcpy(out_buf+out_used, buf, size);
-               out_used+=size;
+               // The request can be served from the buffer
+               memcpy(data, begin, size);
+               begin += size;
+
+               eof_flag = (below.eof() && begin==end);
 
                return size;
        }
        else
        {
-               int ret=0;
-               bool ok=true;
-
-               while(size>0)
-               {
-                       // 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;
+               // Give out whatever is in the buffer already
+               memcpy(data, begin, end-begin);
+               unsigned ret = end-begin;
+               begin=end = buf;
 
-                       if(!ok) break;
+               data += ret;
+               size -= ret;
 
-                       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;
-                       }
+               if(size<buf_size)
+               {
+                       // 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);
 
                return ret;
        }
 }
 
-unsigned Buffered::do_read(char *buf, unsigned size)
+unsigned Buffered::put(char c)
 {
-       if(size<=in_avail)
-       {
-               // The request can be served from the buffer
-               memcpy(buf, in_ptr, size);
-               in_ptr+=size;
-               in_avail-=size;
+       set_op(M_WRITE);
 
-               return size;
+       if(end<buf+buf_size)
+       {
+               *end++ = c;
+               return 1;
        }
        else
-       {
-               // Use whatever is left in the buffer
-               memcpy(buf, in_ptr, in_avail);
-
-               buf+=in_avail;
-               size-=in_avail;
-               int ret=in_avail;
+               return do_write(&c, 1);
+}
 
-               in_ptr=in_buf;
-               in_avail=0;
+bool Buffered::getline(std::string &line)
+{
+       set_op(M_READ);
 
-               if(size>=buf_size)
-                       ret+=below.read(buf, size);
-               else
+       for(char *i=begin; i!=end; ++i)
+               if(*i=='\n')
                {
-                       // 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;
-                       }
+                       line.assign(begin, i-begin);
+                       begin = i+1;
+                       return true;
                }
 
-               return ret;
-       }
+       return Base::getline(line);
+}
+
+int Buffered::get()
+{
+       set_op(M_READ);
+
+       if(begin<end)
+               return static_cast<unsigned char>(*begin++);
+
+       char c;
+       if(do_read(&c, 1)==0)
+               return -1;
+       return static_cast<unsigned char>(c);
+}
+
+void Buffered::set_op(Mode op)
+{
+       if(op!=cur_op)
+               flush();
+       cur_op = op;
+}
+
+unsigned Buffered::get_current_size() const
+{
+       return end-begin;
+}
+
+Handle Buffered::get_event_handle()
+{
+       throw Exception("Buffered doesn't support events");
 }
 
 } // namespace IO