├── test.c ├── buffer.h └── buffer.c /test.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "buffer.h" 4 | 5 | static void tests(int num) { 6 | printf("1..%d\n", num); 7 | } 8 | 9 | static void ok(int ok, const char* msg) { 10 | static int testnum = 0; 11 | printf("%s %d - %s\n", ok ? "ok" : "not ok", ++testnum, msg); 12 | } 13 | 14 | int main(void) { 15 | buffer* b; 16 | int i; 17 | 18 | tests(18); 19 | 20 | b = buffer_init(); 21 | ok(NULL == b->ptr, "ptr is NULL by default"); 22 | ok(0 == b->used, "used 0"); 23 | ok(0 == b->size, "size 0"); 24 | 25 | buffer_append_string(b, "Hello"); 26 | ok(NULL != b->ptr, "ptr is allocated"); 27 | ok(5 == b->used, "used ok"); 28 | ok(64 == b->size, "size ok"); 29 | ok('\0' == b->ptr[b->used], "null terminated ok"); 30 | ok(0 == strcmp(b->ptr, "Hello"), "data ok"); 31 | 32 | buffer_append_string(b, " "); 33 | buffer_append_string(b, "World"); 34 | 35 | ok(0 == strcmp(b->ptr, "Hello World"), "data ok 2"); 36 | ok(11 == b->used, "used ok"); 37 | 38 | buffer_spin(b, 6); 39 | ok(0 == strcmp(b->ptr, "World"), "spin ok"); 40 | ok(5 == b->used, "used ok"); 41 | 42 | buffer_spin(b, 5); 43 | ok(NULL != b->ptr, "reset buf reuse mem ok"); 44 | ok(0 == b->used, "used ok"); 45 | 46 | for (i = 0; i < 1024; ++i) { 47 | buffer_append_string(b, "Hello"); 48 | } 49 | 50 | ok(b->used == 5 * 1024, "used ok"); 51 | 52 | buffer_reset(b); 53 | ok(0 == b->used, "used ok"); 54 | ok(0 == b->size, "size ok"); 55 | ok(NULL == b->ptr, "reset mem when data > BUFFER_MAX_REUSE_SIZE ok"); 56 | 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /buffer.h: -------------------------------------------------------------------------------- 1 | #ifndef buffer_h 2 | #define buffer_h 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | /* 8 | Copyright (c) 2004, Jan Kneschke, incremental 9 | All rights reserved. 10 | 11 | Redistribution and use in source and binary forms, with or without 12 | modification, are permitted provided that the following conditions are met: 13 | 14 | - Redistributions of source code must retain the above copyright notice, this 15 | list of conditions and the following disclaimer. 16 | 17 | - Redistributions in binary form must reproduce the above copyright notice, 18 | this list of conditions and the following disclaimer in the documentation 19 | and/or other materials provided with the distribution. 20 | 21 | - Neither the name of the 'incremental' nor the names of its contributors may 22 | be used to endorse or promote products derived from this software without 23 | specific prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 29 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 35 | THE POSSIBILITY OF SUCH DAMAGE. */ 36 | 37 | #include 38 | 39 | typedef struct buffer_s buffer; 40 | 41 | struct buffer_s { 42 | char* ptr; 43 | 44 | size_t used; 45 | size_t size; 46 | }; 47 | 48 | buffer* buffer_init(void); 49 | void buffer_free(buffer* b); 50 | void buffer_reset(buffer* b); 51 | 52 | int buffer_prepare_append(buffer* b, size_t size); 53 | 54 | int buffer_append_string(buffer* b, const char* s); 55 | int buffer_append_string_len(buffer* b, const char* s, size_t len); 56 | 57 | int buffer_spin(buffer* b, size_t len); 58 | 59 | #ifdef __cplusplus 60 | } 61 | #endif 62 | #endif /* buffer_h */ 63 | -------------------------------------------------------------------------------- /buffer.c: -------------------------------------------------------------------------------- 1 | #include "buffer.h" 2 | 3 | /* 4 | Copyright (c) 2004, Jan Kneschke, incremental 5 | All rights reserved. 6 | 7 | Redistribution and use in source and binary forms, with or without 8 | modification, are permitted provided that the following conditions are met: 9 | 10 | - Redistributions of source code must retain the above copyright notice, this 11 | list of conditions and the following disclaimer. 12 | 13 | - Redistributions in binary form must reproduce the above copyright notice, 14 | this list of conditions and the following disclaimer in the documentation 15 | and/or other materials provided with the distribution. 16 | 17 | - Neither the name of the 'incremental' nor the names of its contributors may 18 | be used to endorse or promote products derived from this software without 19 | specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 25 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 31 | THE POSSIBILITY OF SUCH DAMAGE. */ 32 | 33 | #include 34 | #include 35 | #include 36 | 37 | #define BUFFER_PIECE_SIZE 64 38 | #define BUFFER_MAX_REUSE_SIZE (4 * 1024) 39 | 40 | buffer* buffer_init(void) { 41 | buffer* b; 42 | 43 | b = malloc(sizeof(buffer)); 44 | assert(b); 45 | 46 | b->ptr = NULL; 47 | b->used = 0; 48 | b->size = 0; 49 | 50 | return b; 51 | } 52 | 53 | void buffer_free(buffer* b) { 54 | if (!b) return; 55 | 56 | free(b->ptr); 57 | free(b); 58 | } 59 | 60 | void buffer_reset(buffer* b) { 61 | if (!b) return; 62 | 63 | if (b->size > BUFFER_MAX_REUSE_SIZE) { 64 | free(b->ptr); 65 | b->ptr = NULL; 66 | b->size = 0; 67 | } 68 | 69 | b->used = 0; 70 | } 71 | 72 | int buffer_prepare_append(buffer* b, size_t size) { 73 | if (!b) return -1; 74 | if (0 == size) return 0; 75 | 76 | /* for '\0' terminate char. its useful for debugging */ 77 | size += 1; 78 | 79 | if (0 == b->size) { 80 | b->size = size; 81 | b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE); 82 | 83 | b->ptr = malloc(b->size); 84 | assert(b->ptr); 85 | } 86 | else if (b->used + size > b->size) { 87 | b->size += size; 88 | b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE); 89 | 90 | b->ptr = realloc(b->ptr, b->size); 91 | assert(b->ptr); 92 | } 93 | 94 | return 0; 95 | } 96 | 97 | int buffer_append_string(buffer* b, const char* s) { 98 | size_t len; 99 | 100 | if (!b || !s) return -1; 101 | 102 | len = strlen(s); 103 | return buffer_append_string_len(b, s, len); 104 | } 105 | 106 | int buffer_append_string_len(buffer* b, const char* s, size_t len) { 107 | if (!b || !s) return -1; 108 | if (0 == len) return 0; 109 | 110 | buffer_prepare_append(b, len); 111 | 112 | memcpy(b->ptr + b->used, s, len); 113 | b->used += len; 114 | 115 | b->ptr[b->used] = '\0'; 116 | 117 | return 0; 118 | } 119 | 120 | int buffer_spin(buffer* b, size_t len) { 121 | size_t rest; 122 | 123 | if (!b) return -1; 124 | if (0 == b->used) return 0; 125 | 126 | rest = b->used - len; 127 | if (rest > 0) { 128 | memmove(b->ptr, b->ptr + len, rest); 129 | b->used -= len; 130 | b->ptr[b->used] = '\0'; 131 | } 132 | else { 133 | buffer_reset(b); 134 | } 135 | 136 | return 0; 137 | } 138 | --------------------------------------------------------------------------------