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 #include "trace.h" 23 24 #define BUFFER_MIN_INIT_SIZE 4096 25 #define BUFFER_MIN_SHRINK_SIZE 65536 26 27 void buffer_init(Buffer *buffer, const char *name, ...) 28 { 29 va_list ap; 30 31 va_start(ap, name); 32 buffer->name = g_strdup_vprintf(name, ap); 33 va_end(ap); 34 } 35 36 void buffer_shrink(Buffer *buffer) 37 { 38 size_t old; 39 40 /* 41 * Only shrink in case the used size is *much* smaller than the 42 * capacity, to avoid bumping up & down the buffers all the time. 43 * realloc() isn't exactly cheap ... 44 */ 45 if (buffer->offset < (buffer->capacity >> 3) && 46 buffer->capacity > BUFFER_MIN_SHRINK_SIZE) { 47 return; 48 } 49 50 old = buffer->capacity; 51 buffer->capacity = pow2ceil(buffer->offset); 52 buffer->capacity = MAX(buffer->capacity, BUFFER_MIN_SHRINK_SIZE); 53 buffer->buffer = g_realloc(buffer->buffer, buffer->capacity); 54 trace_buffer_resize(buffer->name ?: "unnamed", 55 old, buffer->capacity); 56 } 57 58 void buffer_reserve(Buffer *buffer, size_t len) 59 { 60 size_t old; 61 62 if ((buffer->capacity - buffer->offset) < len) { 63 old = buffer->capacity; 64 buffer->capacity = pow2ceil(buffer->offset + len); 65 buffer->capacity = MAX(buffer->capacity, BUFFER_MIN_INIT_SIZE); 66 buffer->buffer = g_realloc(buffer->buffer, buffer->capacity); 67 trace_buffer_resize(buffer->name ?: "unnamed", 68 old, buffer->capacity); 69 } 70 } 71 72 gboolean buffer_empty(Buffer *buffer) 73 { 74 return buffer->offset == 0; 75 } 76 77 uint8_t *buffer_end(Buffer *buffer) 78 { 79 return buffer->buffer + buffer->offset; 80 } 81 82 void buffer_reset(Buffer *buffer) 83 { 84 buffer->offset = 0; 85 } 86 87 void buffer_free(Buffer *buffer) 88 { 89 trace_buffer_free(buffer->name ?: "unnamed", buffer->capacity); 90 g_free(buffer->buffer); 91 g_free(buffer->name); 92 buffer->offset = 0; 93 buffer->capacity = 0; 94 buffer->buffer = NULL; 95 buffer->name = NULL; 96 } 97 98 void buffer_append(Buffer *buffer, const void *data, size_t len) 99 { 100 memcpy(buffer->buffer + buffer->offset, data, len); 101 buffer->offset += len; 102 } 103 104 void buffer_advance(Buffer *buffer, size_t len) 105 { 106 memmove(buffer->buffer, buffer->buffer + len, 107 (buffer->offset - len)); 108 buffer->offset -= len; 109 } 110 111 void buffer_move_empty(Buffer *to, Buffer *from) 112 { 113 trace_buffer_move_empty(to->name ?: "unnamed", 114 from->offset, 115 from->name ?: "unnamed"); 116 assert(to->offset == 0); 117 118 g_free(to->buffer); 119 to->offset = from->offset; 120 to->capacity = from->capacity; 121 to->buffer = from->buffer; 122 123 from->offset = 0; 124 from->capacity = 0; 125 from->buffer = NULL; 126 } 127 128 void buffer_move(Buffer *to, Buffer *from) 129 { 130 if (to->offset == 0) { 131 buffer_move_empty(to, from); 132 return; 133 } 134 135 trace_buffer_move(to->name ?: "unnamed", 136 from->offset, 137 from->name ?: "unnamed"); 138 buffer_reserve(to, from->offset); 139 buffer_append(to, from->buffer, from->offset); 140 141 g_free(from->buffer); 142 from->offset = 0; 143 from->capacity = 0; 144 from->buffer = NULL; 145 } 146