132 } else { |
132 } else { |
133 return -1; |
133 return -1; |
134 } |
134 } |
135 } |
135 } |
136 |
136 |
|
137 /** |
|
138 * Helps flushing data to the flush target of a buffer. |
|
139 * |
|
140 * @param buffer the buffer containing the config |
|
141 * @param space the data to flush |
|
142 * @param size the element size |
|
143 * @param nitems the number of items |
|
144 * @return the number of items flushed |
|
145 */ |
|
146 static size_t cx_buffer_write_flush_helper( |
|
147 CxBuffer *buffer, |
|
148 unsigned char const *space, |
|
149 size_t size, |
|
150 size_t nitems |
|
151 ) { |
|
152 size_t pos = 0; |
|
153 size_t remaining = nitems; |
|
154 size_t max_items = buffer->flush_blksize / size; |
|
155 while (remaining > 0) { |
|
156 size_t items = remaining > max_items ? max_items : remaining; |
|
157 size_t flushed = buffer->flush_func( |
|
158 space + pos, |
|
159 size, items, |
|
160 buffer->flush_target); |
|
161 if (flushed > 0) { |
|
162 pos += (flushed * size); |
|
163 remaining -= flushed; |
|
164 } else { |
|
165 // if no bytes can be flushed out anymore, we give up |
|
166 break; |
|
167 } |
|
168 } |
|
169 return nitems - remaining; |
|
170 } |
|
171 |
137 size_t cxBufferWrite( |
172 size_t cxBufferWrite( |
138 void const *ptr, |
173 void const *ptr, |
139 size_t size, |
174 size_t size, |
140 size_t nitems, |
175 size_t nitems, |
141 CxBuffer *buffer |
176 CxBuffer *buffer |
176 // truncate data to be written, if we can neither extend nor flush |
212 // truncate data to be written, if we can neither extend nor flush |
177 len = buffer->capacity - buffer->pos; |
213 len = buffer->capacity - buffer->pos; |
178 if (size > 1) { |
214 if (size > 1) { |
179 len -= len % size; |
215 len -= len % size; |
180 } |
216 } |
181 nitems = len / size; |
217 nitems_out = len / size; |
182 } |
218 } |
183 } |
219 } |
184 } |
220 } |
185 |
221 |
186 if (len == 0) { |
222 if (len == 0) { |
187 return len; |
223 return len; |
188 } |
224 } |
189 |
225 |
190 if (perform_flush) { |
226 if (perform_flush) { |
191 // TODO: implement flushing |
227 size_t flush_max; |
192 // (1) determine how many bytes to flush (use flushmax = blkmax * blksize) |
228 if (cx_szmul(buffer->flush_blkmax, buffer->flush_blksize, &flush_max)) { |
193 // (2) if len is larger than the number computed in (1) we need more flush cycles, compute how many |
229 return 0; |
194 // (3) determine how many bytes from the buffer shall be flushed |
230 } |
195 // (4) if something remains in the buffer, shift the buffer to the left |
231 size_t flush_pos = buffer->flush_func == NULL || buffer->flush_target == NULL |
196 // (4a) if buffer was shifted, append the new data to the buffer |
232 ? buffer->pos |
197 // (4b) if the buffer was flushed entirely AND the new data also fits into flushmax, |
233 : cx_buffer_write_flush_helper(buffer, buffer->bytes, 1, buffer->pos); |
198 // directly write the new data to the flush sink |
234 if (flush_pos == buffer->pos) { |
199 return 0; // remove this after implementation |
235 // entire buffer has been flushed, we can reset |
|
236 buffer->size = buffer->pos = 0; |
|
237 |
|
238 size_t items_flush; // how many items can also be directly flushed |
|
239 size_t items_keep; // how many items have to be written to the buffer |
|
240 |
|
241 items_flush = flush_max >= required ? nitems : (flush_max - flush_pos) / size; |
|
242 if (items_flush > 0) { |
|
243 items_flush = cx_buffer_write_flush_helper(buffer, ptr, size, items_flush / size); |
|
244 // in case we could not flush everything, keep the rest |
|
245 } |
|
246 items_keep = nitems - items_flush; |
|
247 if (items_keep > 0) { |
|
248 // try again with the remaining stuff |
|
249 unsigned char const *new_ptr = ptr; |
|
250 new_ptr += items_flush * size; |
|
251 return cxBufferWrite(new_ptr, size, items_keep, buffer); |
|
252 } else { |
|
253 // all items have been flushed - report them as written |
|
254 return nitems; |
|
255 } |
|
256 } else if (flush_pos == 0) { |
|
257 // nothing could be flushed at all, we immediately give up without writing any data |
|
258 return 0; |
|
259 } else { |
|
260 // we were partially successful, we have shift left and try again |
|
261 cxBufferShiftLeft(buffer, flush_pos); |
|
262 return cxBufferWrite(ptr, size, nitems, buffer); |
|
263 } |
200 } else { |
264 } else { |
201 memcpy(buffer->bytes + buffer->pos, ptr, len); |
265 memcpy(buffer->bytes + buffer->pos, ptr, len); |
202 buffer->pos += len; |
266 buffer->pos += len; |
203 if (buffer->pos > buffer->size) { |
267 if (buffer->pos > buffer->size) { |
204 buffer->size = buffer->pos; |
268 buffer->size = buffer->pos; |
205 } |
269 } |
206 } |
270 return nitems_out; |
207 |
271 } |
208 return nitems; |
272 |
209 } |
273 } |
210 |
274 |
211 int cxBufferPut( |
275 int cxBufferPut( |
212 CxBuffer *buffer, |
276 CxBuffer *buffer, |
213 int c |
277 int c |