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) { |
34 static int buffer_copy_on_write(CxBuffer* buffer) { |
35 if (0 == (buffer->flags & CX_BUFFER_COPY_ON_WRITE)) return 0; |
35 if (0 == (buffer->flags & CX_BUFFER_COPY_ON_WRITE)) return 0; |
36 if (newcap == 0) newcap = buffer->capacity; |
36 void *newspace = cxMalloc(buffer->allocator, buffer->capacity); |
37 void *newspace = cxMalloc(buffer->allocator, newcap); |
|
38 if (NULL == newspace) return -1; |
37 if (NULL == newspace) return -1; |
39 memcpy(newspace, buffer->space, buffer->size); |
38 memcpy(newspace, buffer->space, buffer->size); |
40 buffer->space = newspace; |
39 buffer->space = newspace; |
41 buffer->capacity = newcap; |
|
42 buffer->flags &= ~CX_BUFFER_COPY_ON_WRITE; |
40 buffer->flags &= ~CX_BUFFER_COPY_ON_WRITE; |
43 buffer->flags |= CX_BUFFER_FREE_CONTENTS; |
41 buffer->flags |= CX_BUFFER_FREE_CONTENTS; |
44 return 0; |
42 return 0; |
45 } |
43 } |
46 |
44 |
51 const CxAllocator *allocator, |
49 const CxAllocator *allocator, |
52 int flags |
50 int flags |
53 ) { |
51 ) { |
54 if (allocator == NULL) { |
52 if (allocator == NULL) { |
55 allocator = cxDefaultAllocator; |
53 allocator = cxDefaultAllocator; |
|
54 } |
|
55 if (flags & CX_BUFFER_COPY_ON_EXTEND) { |
|
56 flags |= CX_BUFFER_AUTO_EXTEND; |
56 } |
57 } |
57 buffer->allocator = allocator; |
58 buffer->allocator = allocator; |
58 buffer->flags = flags; |
59 buffer->flags = flags; |
59 if (!space) { |
60 if (!space) { |
60 buffer->bytes = cxMalloc(allocator, capacity); |
61 buffer->bytes = cxMalloc(allocator, capacity); |
168 ) { |
169 ) { |
169 if (newcap <= buffer->capacity) { |
170 if (newcap <= buffer->capacity) { |
170 return 0; |
171 return 0; |
171 } |
172 } |
172 |
173 |
173 if (buffer->flags & CX_BUFFER_COPY_ON_WRITE) { |
174 const int force_copy_flags = CX_BUFFER_COPY_ON_WRITE | CX_BUFFER_COPY_ON_EXTEND; |
174 return buffer_copy_on_write(buffer, newcap); |
175 if (buffer->flags & force_copy_flags) { |
|
176 void *newspace = cxMalloc(buffer->allocator, newcap); |
|
177 if (NULL == newspace) return -1; |
|
178 memcpy(newspace, buffer->space, buffer->size); |
|
179 buffer->space = newspace; |
|
180 buffer->capacity = newcap; |
|
181 buffer->flags &= ~force_copy_flags; |
|
182 buffer->flags |= CX_BUFFER_FREE_CONTENTS; |
|
183 return 0; |
175 } else if (cxReallocate(buffer->allocator, |
184 } else if (cxReallocate(buffer->allocator, |
176 (void **) &buffer->bytes, newcap) == 0) { |
185 (void **) &buffer->bytes, newcap) == 0) { |
177 buffer->capacity = newcap; |
186 buffer->capacity = newcap; |
178 return 0; |
187 return 0; |
179 } else { |
188 } else { |
222 size_t nitems, |
231 size_t nitems, |
223 CxBuffer *buffer |
232 CxBuffer *buffer |
224 ) { |
233 ) { |
225 // optimize for easy case |
234 // optimize for easy case |
226 if (size == 1 && (buffer->capacity - buffer->pos) >= nitems) { |
235 if (size == 1 && (buffer->capacity - buffer->pos) >= nitems) { |
227 if (buffer_copy_on_write(buffer, 0)) return 0; |
236 if (buffer_copy_on_write(buffer)) return 0; |
228 memcpy(buffer->bytes + buffer->pos, ptr, nitems); |
237 memcpy(buffer->bytes + buffer->pos, ptr, nitems); |
229 buffer->pos += nitems; |
238 buffer->pos += nitems; |
230 if (buffer->pos > buffer->size) { |
239 if (buffer->pos > buffer->size) { |
231 buffer->size = buffer->pos; |
240 buffer->size = buffer->pos; |
232 } |
241 } |
309 // we were partially successful, we shift left and try again |
318 // we were partially successful, we shift left and try again |
310 cxBufferShiftLeft(buffer, flush_pos); |
319 cxBufferShiftLeft(buffer, flush_pos); |
311 return cxBufferWrite(ptr, size, nitems, buffer); |
320 return cxBufferWrite(ptr, size, nitems, buffer); |
312 } |
321 } |
313 } else { |
322 } else { |
314 if (buffer_copy_on_write(buffer, 0)) return 0; |
323 if (buffer_copy_on_write(buffer)) return 0; |
315 memcpy(buffer->bytes + buffer->pos, ptr, len); |
324 memcpy(buffer->bytes + buffer->pos, ptr, len); |
316 buffer->pos += len; |
325 buffer->pos += len; |
317 if (buffer->pos > buffer->size) { |
326 if (buffer->pos > buffer->size) { |
318 buffer->size = buffer->pos; |
327 buffer->size = buffer->pos; |
319 } |
328 } |
393 size_t shift |
402 size_t shift |
394 ) { |
403 ) { |
395 if (shift >= buffer->size) { |
404 if (shift >= buffer->size) { |
396 buffer->pos = buffer->size = 0; |
405 buffer->pos = buffer->size = 0; |
397 } else { |
406 } else { |
398 if (buffer_copy_on_write(buffer, 0)) return -1; |
407 if (buffer_copy_on_write(buffer)) return -1; |
399 memmove(buffer->bytes, buffer->bytes + shift, buffer->size - shift); |
408 memmove(buffer->bytes, buffer->bytes + shift, buffer->size - shift); |
400 buffer->size -= shift; |
409 buffer->size -= shift; |
401 |
410 |
402 if (buffer->pos >= shift) { |
411 if (buffer->pos >= shift) { |
403 buffer->pos -= shift; |
412 buffer->pos -= shift; |
428 } else { |
437 } else { |
429 movebytes = buffer->size; |
438 movebytes = buffer->size; |
430 } |
439 } |
431 |
440 |
432 if (movebytes > 0) { |
441 if (movebytes > 0) { |
433 if (buffer_copy_on_write(buffer, 0)) return -1; |
442 if (buffer_copy_on_write(buffer)) return -1; |
434 memmove(buffer->bytes + shift, buffer->bytes, movebytes); |
443 memmove(buffer->bytes + shift, buffer->bytes, movebytes); |
435 buffer->size = shift + movebytes; |
444 buffer->size = shift + movebytes; |
436 } |
445 } |
437 |
446 |
438 buffer->pos += shift; |
447 buffer->pos += shift; |