]> git.tdb.fi Git - libs/core.git/blob - source/buffered.cpp
Drop copyright and license notices from files
[libs/core.git] / source / buffered.cpp
1 #include <cstring>
2 #include "buffered.h"
3 #include "except.h"
4
5 using namespace std;
6
7 namespace Msp {
8 namespace IO {
9
10 Buffered::Buffered(Base &b, unsigned s):
11         below(b),
12         buf_size(s),
13         buf(new char[buf_size]),
14         begin(buf),
15         end(buf),
16         cur_op(M_NONE)
17 {
18         mode = below.get_mode();
19         below.signal_flush_required.connect(sigc::mem_fun(this, &Buffered::flush));
20 }
21
22 unsigned Buffered::put(char c)
23 {
24         set_op(M_WRITE);
25
26         if(end<buf+buf_size)
27         {
28                 *end++ = c;
29                 return 1;
30         }
31         else
32                 return do_write(&c, 1);
33 }
34
35 void Buffered::flush()
36 {
37         if(cur_op==M_WRITE)
38         {
39                 unsigned used = end-begin;
40                 if(used)
41                 {
42                         unsigned len = below.write(begin, used);
43
44                         begin=end = buf;
45
46                         if(len<used)
47                                 throw Exception("Couldn't flush all data");
48                 }
49         }
50         else if(cur_op==M_READ)
51                 begin=end = buf;
52 }
53
54 bool Buffered::getline(std::string &line)
55 {
56         set_op(M_READ);
57
58         for(char *i=begin; i!=end; ++i)
59                 if(*i=='\n')
60                 {
61                         line.assign(begin, i-begin);
62                         begin = i+1;
63                         return true;
64                 }
65
66         return Base::getline(line);
67 }
68
69 int Buffered::get()
70 {
71         set_op(M_READ);
72
73         if(begin<end)
74                 return static_cast<unsigned char>(*begin++);
75
76         char c;
77         if(do_read(&c, 1)==0)
78                 return -1;
79         return static_cast<unsigned char>(c);
80 }
81
82 Handle Buffered::get_event_handle()
83 {
84         throw Exception("Buffered doesn't support events");
85 }
86
87 unsigned Buffered::get_current_size() const
88 {
89         return end-begin;
90 }
91
92 Buffered::~Buffered()
93 {
94         try
95         {
96                 flush();
97         }
98         catch(...)
99         { }
100
101         delete[] buf;
102 }
103
104 void Buffered::set_op(Mode op)
105 {
106         if(op!=cur_op)
107                 flush();
108         cur_op = op;
109 }
110
111 unsigned Buffered::do_write(const char *data, unsigned size)
112 {
113         set_op(M_WRITE);
114
115         if(end+size<buf+buf_size)
116         {
117                 // All data fits in buffer with whatever is already there
118                 memcpy(end, data, size);
119                 end += size;
120
121                 return size;
122         }
123         else
124         {
125                 // Clear the buffer to make more room
126                 flush();
127
128                 if(size<buf_size)
129                 {
130                         // Put new data in the buffer to wait for more
131                         memcpy(end, data, size);
132                         end += size;
133
134                         return size;
135                 }
136                 else
137                         // New data still doesn't fit in the buffer, so write it directly
138                         return below.write(data, size);
139         }
140 }
141
142 unsigned Buffered::do_read(char *data, unsigned size)
143 {
144         set_op(M_READ);
145
146         if(begin+size<=end)
147         {
148                 // The request can be served from the buffer
149                 memcpy(data, begin, size);
150                 begin += size;
151
152                 eof_flag = (below.eof() && begin==end);
153
154                 return size;
155         }
156         else
157         {
158                 // Give out whatever is in the buffer already
159                 memcpy(data, begin, end-begin);
160                 unsigned ret = end-begin;
161                 begin=end = buf;
162
163                 data += ret;
164                 size -= ret;
165
166                 if(size<buf_size)
167                 {
168                         // Fill the buffer and serve the rest of the request from it
169                         unsigned len = below.read(end, buf+buf_size-end);
170                         end += len;
171
172                         len = min(static_cast<unsigned>(end-begin), size);
173                         memcpy(data, begin, len);
174                         begin += len;
175                         ret += len;
176                 }
177                 else
178                         // Read the rest directly from the underlying object
179                         ret += below.read(data, size);
180
181                 eof_flag = (below.eof() && begin==end);
182
183                 return ret;
184         }
185 }
186
187 } // namespace IO
188 } // namespace Msp