29 #include "cx/buffer.h" |
29 #include "cx/buffer.h" |
30 |
30 |
31 #include <stdio.h> |
31 #include <stdio.h> |
32 #include <string.h> |
32 #include <string.h> |
33 |
33 |
|
34 static int buffer_copy_on_write(CxBuffer* buffer, size_t newcap) { |
|
35 if (0 == (buffer->flags & CX_BUFFER_COPY_ON_WRITE)) return 0; |
|
36 if (newcap == 0) newcap = buffer->capacity; |
|
37 void *newspace = cxMalloc(buffer->allocator, newcap); |
|
38 if (NULL == newspace) return -1; |
|
39 memcpy(newspace, buffer->space, buffer->size); |
|
40 buffer->space = newspace; |
|
41 buffer->capacity = newcap; |
|
42 buffer->flags &= ~CX_BUFFER_COPY_ON_WRITE; |
|
43 buffer->flags |= CX_BUFFER_FREE_CONTENTS; |
|
44 return 0; |
|
45 } |
|
46 |
34 int cxBufferInit( |
47 int cxBufferInit( |
35 CxBuffer *buffer, |
48 CxBuffer *buffer, |
36 void *space, |
49 void *space, |
37 size_t capacity, |
50 size_t capacity, |
38 const CxAllocator *allocator, |
51 const CxAllocator *allocator, |
44 buffer->allocator = allocator; |
57 buffer->allocator = allocator; |
45 buffer->flags = flags; |
58 buffer->flags = flags; |
46 if (!space) { |
59 if (!space) { |
47 buffer->bytes = cxMalloc(allocator, capacity); |
60 buffer->bytes = cxMalloc(allocator, capacity); |
48 if (buffer->bytes == NULL) { |
61 if (buffer->bytes == NULL) { |
49 return 1; |
62 return -1; |
50 } |
63 } |
51 buffer->flags |= CX_BUFFER_FREE_CONTENTS; |
64 buffer->flags |= CX_BUFFER_FREE_CONTENTS; |
52 } else { |
65 } else { |
53 buffer->bytes = space; |
66 buffer->bytes = space; |
54 } |
67 } |
153 ) { |
168 ) { |
154 if (newcap <= buffer->capacity) { |
169 if (newcap <= buffer->capacity) { |
155 return 0; |
170 return 0; |
156 } |
171 } |
157 |
172 |
158 if (cxReallocate(buffer->allocator, |
173 if (buffer->flags & CX_BUFFER_COPY_ON_WRITE) { |
|
174 return buffer_copy_on_write(buffer, newcap); |
|
175 } else if (cxReallocate(buffer->allocator, |
159 (void **) &buffer->bytes, newcap) == 0) { |
176 (void **) &buffer->bytes, newcap) == 0) { |
160 buffer->capacity = newcap; |
177 buffer->capacity = newcap; |
161 return 0; |
178 return 0; |
162 } else { |
179 } else { |
163 return -1; |
180 return -1; |
205 size_t nitems, |
222 size_t nitems, |
206 CxBuffer *buffer |
223 CxBuffer *buffer |
207 ) { |
224 ) { |
208 // optimize for easy case |
225 // optimize for easy case |
209 if (size == 1 && (buffer->capacity - buffer->pos) >= nitems) { |
226 if (size == 1 && (buffer->capacity - buffer->pos) >= nitems) { |
|
227 if (buffer_copy_on_write(buffer, 0)) return 0; |
210 memcpy(buffer->bytes + buffer->pos, ptr, nitems); |
228 memcpy(buffer->bytes + buffer->pos, ptr, nitems); |
211 buffer->pos += nitems; |
229 buffer->pos += nitems; |
212 if (buffer->pos > buffer->size) { |
230 if (buffer->pos > buffer->size) { |
213 buffer->size = buffer->pos; |
231 buffer->size = buffer->pos; |
214 } |
232 } |
225 return 0; |
243 return 0; |
226 } |
244 } |
227 |
245 |
228 bool perform_flush = false; |
246 bool perform_flush = false; |
229 if (required > buffer->capacity) { |
247 if (required > buffer->capacity) { |
230 if ((buffer->flags & CX_BUFFER_AUTO_EXTEND) == CX_BUFFER_AUTO_EXTEND && required) { |
248 if (buffer->flags & CX_BUFFER_AUTO_EXTEND) { |
231 if (buffer->flush_blkmax > 0 && required > buffer->flush_threshold) { |
249 if (buffer->flush_blkmax > 0 && required > buffer->flush_threshold) { |
232 perform_flush = true; |
250 perform_flush = true; |
233 } else { |
251 } else { |
234 if (cxBufferMinimumCapacity(buffer, required)) { |
252 if (cxBufferMinimumCapacity(buffer, required)) { |
235 return 0; |
253 return 0; |
291 // we were partially successful, we shift left and try again |
309 // we were partially successful, we shift left and try again |
292 cxBufferShiftLeft(buffer, flush_pos); |
310 cxBufferShiftLeft(buffer, flush_pos); |
293 return cxBufferWrite(ptr, size, nitems, buffer); |
311 return cxBufferWrite(ptr, size, nitems, buffer); |
294 } |
312 } |
295 } else { |
313 } else { |
|
314 if (buffer_copy_on_write(buffer, 0)) return 0; |
296 memcpy(buffer->bytes + buffer->pos, ptr, len); |
315 memcpy(buffer->bytes + buffer->pos, ptr, len); |
297 buffer->pos += len; |
316 buffer->pos += len; |
298 if (buffer->pos > buffer->size) { |
317 if (buffer->pos > buffer->size) { |
299 buffer->size = buffer->pos; |
318 buffer->size = buffer->pos; |
300 } |
319 } |
374 size_t shift |
393 size_t shift |
375 ) { |
394 ) { |
376 if (shift >= buffer->size) { |
395 if (shift >= buffer->size) { |
377 buffer->pos = buffer->size = 0; |
396 buffer->pos = buffer->size = 0; |
378 } else { |
397 } else { |
|
398 if (buffer_copy_on_write(buffer, 0)) return -1; |
379 memmove(buffer->bytes, buffer->bytes + shift, buffer->size - shift); |
399 memmove(buffer->bytes, buffer->bytes + shift, buffer->size - shift); |
380 buffer->size -= shift; |
400 buffer->size -= shift; |
381 |
401 |
382 if (buffer->pos >= shift) { |
402 if (buffer->pos >= shift) { |
383 buffer->pos -= shift; |
403 buffer->pos -= shift; |
395 size_t req_capacity = buffer->size + shift; |
415 size_t req_capacity = buffer->size + shift; |
396 size_t movebytes; |
416 size_t movebytes; |
397 |
417 |
398 // auto extend buffer, if required and enabled |
418 // auto extend buffer, if required and enabled |
399 if (buffer->capacity < req_capacity) { |
419 if (buffer->capacity < req_capacity) { |
400 if ((buffer->flags & CX_BUFFER_AUTO_EXTEND) == CX_BUFFER_AUTO_EXTEND) { |
420 if (buffer->flags & CX_BUFFER_AUTO_EXTEND) { |
401 if (cxBufferMinimumCapacity(buffer, req_capacity)) { |
421 if (cxBufferMinimumCapacity(buffer, req_capacity)) { |
402 return 1; |
422 return -1; |
403 } |
423 } |
404 movebytes = buffer->size; |
424 movebytes = buffer->size; |
405 } else { |
425 } else { |
406 movebytes = buffer->capacity - shift; |
426 movebytes = buffer->capacity - shift; |
407 } |
427 } |
408 } else { |
428 } else { |
409 movebytes = buffer->size; |
429 movebytes = buffer->size; |
410 } |
430 } |
411 |
431 |
412 memmove(buffer->bytes + shift, buffer->bytes, movebytes); |
432 if (movebytes > 0) { |
413 buffer->size = shift + movebytes; |
433 if (buffer_copy_on_write(buffer, 0)) return -1; |
|
434 memmove(buffer->bytes + shift, buffer->bytes, movebytes); |
|
435 buffer->size = shift + movebytes; |
|
436 } |
414 |
437 |
415 buffer->pos += shift; |
438 buffer->pos += shift; |
416 if (buffer->pos > buffer->size) { |
439 if (buffer->pos > buffer->size) { |
417 buffer->pos = buffer->size; |
440 buffer->pos = buffer->size; |
418 } |
441 } |