src/buffer.c

changeset 544
2e73456e5f84
parent 543
7b9114030ca4
child 567
f90a7cfe2480
equal deleted inserted replaced
543:7b9114030ca4 544:2e73456e5f84
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
149 } 184 }
150 return nitems; 185 return nitems;
151 } 186 }
152 187
153 size_t len; 188 size_t len;
189 size_t nitems_out = nitems;
154 if (cx_szmul(size, nitems, &len)) { 190 if (cx_szmul(size, nitems, &len)) {
155 return 0; 191 return 0;
156 } 192 }
157 size_t required = buffer->pos + len; 193 size_t required = buffer->pos + len;
158 if (buffer->pos > required) { 194 if (buffer->pos > required) {
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

mercurial