src/buffer.c

changeset 1024
8f99f6c28bd3
parent 1007
81b2986d2b04
equal deleted inserted replaced
1017:b0098854071f 1024:8f99f6c28bd3
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 }
64 77
65 return 0; 78 return 0;
66 } 79 }
67 80
68 void cxBufferDestroy(CxBuffer *buffer) { 81 void cxBufferDestroy(CxBuffer *buffer) {
69 if ((buffer->flags & CX_BUFFER_FREE_CONTENTS) == CX_BUFFER_FREE_CONTENTS) { 82 if (buffer->flags & CX_BUFFER_FREE_CONTENTS) {
70 cxFree(buffer->allocator, buffer->bytes); 83 cxFree(buffer->allocator, buffer->bytes);
71 } 84 }
72 } 85 }
73 86
74 CxBuffer *cxBufferCreate( 87 CxBuffer *cxBufferCreate(
131 } 144 }
132 145
133 } 146 }
134 147
135 void cxBufferClear(CxBuffer *buffer) { 148 void cxBufferClear(CxBuffer *buffer) {
136 memset(buffer->bytes, 0, buffer->size); 149 if (0 == (buffer->flags & CX_BUFFER_COPY_ON_WRITE)) {
150 memset(buffer->bytes, 0, buffer->size);
151 }
137 buffer->size = 0; 152 buffer->size = 0;
138 buffer->pos = 0; 153 buffer->pos = 0;
139 } 154 }
140 155
141 void cxBufferReset(CxBuffer *buffer) { 156 void cxBufferReset(CxBuffer *buffer) {
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 }
321 if (success) { 340 if (success) {
322 buffer->pos--; 341 buffer->pos--;
323 buffer->size--; 342 buffer->size--;
324 return 0; 343 return 0;
325 } else { 344 } else {
326 return 1; 345 return -1;
327 } 346 }
328 } 347 }
329 348
330 size_t cxBufferPutString( 349 size_t cxBufferPutString(
331 CxBuffer *buffer, 350 CxBuffer *buffer,
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 }

mercurial