1 /* 2 * QEMU generic buffers 3 * 4 * Copyright (c) 2015 Red Hat, Inc. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 18 * 19 */ 20 21 #include "qemu/buffer.h" 22 23 #define BUFFER_MIN_INIT_SIZE 4096 24 #define BUFFER_MIN_SHRINK_SIZE 65536 25 26 void buffer_init(Buffer *buffer, const char *name, ...) 27 { 28 va_list ap; 29 30 va_start(ap, name); 31 buffer->name = g_strdup_vprintf(name, ap); 32 va_end(ap); 33 } 34 35 void buffer_shrink(Buffer *buffer) 36 { 37 /* 38 * Only shrink in case the used size is *much* smaller than the 39 * capacity, to avoid bumping up & down the buffers all the time. 40 * realloc() isn't exactly cheap ... 41 */ 42 if (buffer->offset < (buffer->capacity >> 3) && 43 buffer->capacity > BUFFER_MIN_SHRINK_SIZE) { 44 return; 45 } 46 47 buffer->capacity = pow2ceil(buffer->offset); 48 buffer->capacity = MAX(buffer->capacity, BUFFER_MIN_SHRINK_SIZE); 49 buffer->buffer = g_realloc(buffer->buffer, buffer->capacity); 50 } 51 52 void buffer_reserve(Buffer *buffer, size_t len) 53 { 54 if ((buffer->capacity - buffer->offset) < len) { 55 buffer->capacity = pow2ceil(buffer->offset + len); 56 buffer->capacity = MAX(buffer->capacity, BUFFER_MIN_INIT_SIZE); 57 buffer->buffer = g_realloc(buffer->buffer, buffer->capacity); 58 } 59 } 60 61 gboolean buffer_empty(Buffer *buffer) 62 { 63 return buffer->offset == 0; 64 } 65 66 uint8_t *buffer_end(Buffer *buffer) 67 { 68 return buffer->buffer + buffer->offset; 69 } 70 71 void buffer_reset(Buffer *buffer) 72 { 73 buffer->offset = 0; 74 } 75 76 void buffer_free(Buffer *buffer) 77 { 78 g_free(buffer->buffer); 79 g_free(buffer->name); 80 buffer->offset = 0; 81 buffer->capacity = 0; 82 buffer->buffer = NULL; 83 buffer->name = NULL; 84 } 85 86 void buffer_append(Buffer *buffer, const void *data, size_t len) 87 { 88 memcpy(buffer->buffer + buffer->offset, data, len); 89 buffer->offset += len; 90 } 91 92 void buffer_advance(Buffer *buffer, size_t len) 93 { 94 memmove(buffer->buffer, buffer->buffer + len, 95 (buffer->offset - len)); 96 buffer->offset -= len; 97 } 98 99 void buffer_move_empty(Buffer *to, Buffer *from) 100 { 101 assert(to->offset == 0); 102 103 g_free(to->buffer); 104 to->offset = from->offset; 105 to->capacity = from->capacity; 106 to->buffer = from->buffer; 107 108 from->offset = 0; 109 from->capacity = 0; 110 from->buffer = NULL; 111 } 112 113 void buffer_move(Buffer *to, Buffer *from) 114 { 115 if (to->offset == 0) { 116 buffer_move_empty(to, from); 117 return; 118 } 119 120 buffer_reserve(to, from->offset); 121 buffer_append(to, from->buffer, from->offset); 122 123 g_free(from->buffer); 124 from->offset = 0; 125 from->capacity = 0; 126 from->buffer = NULL; 127 } 128