blob: 31f1d9f286a728aa7e0f1102028c8961d817699b [file] [log] [blame]
Daniel P. Berrange88c5f202015-03-03 17:13:42 +00001/*
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"
Gerd Hoffmannd2b90712015-10-30 12:10:01 +010022#include "trace.h"
Daniel P. Berrange88c5f202015-03-03 17:13:42 +000023
Gerd Hoffmann1ff36b52015-10-30 12:10:00 +010024#define BUFFER_MIN_INIT_SIZE 4096
25#define BUFFER_MIN_SHRINK_SIZE 65536
Peter Lieven5c10dbb2015-10-30 12:09:56 +010026
Peter Lievenfd952432015-10-30 12:10:12 +010027static size_t buffer_req_size(Buffer *buffer, size_t len)
28{
29 return MAX(BUFFER_MIN_INIT_SIZE,
30 pow2ceil(buffer->offset + len));
31}
32
33
Gerd Hoffmann810082d2015-10-30 12:09:57 +010034void buffer_init(Buffer *buffer, const char *name, ...)
35{
36 va_list ap;
37
38 va_start(ap, name);
39 buffer->name = g_strdup_vprintf(name, ap);
40 va_end(ap);
41}
42
Gerd Hoffmann1ff36b52015-10-30 12:10:00 +010043void buffer_shrink(Buffer *buffer)
44{
Gerd Hoffmannd2b90712015-10-30 12:10:01 +010045 size_t old;
46
Gerd Hoffmann1ff36b52015-10-30 12:10:00 +010047 /*
48 * Only shrink in case the used size is *much* smaller than the
49 * capacity, to avoid bumping up & down the buffers all the time.
50 * realloc() isn't exactly cheap ...
51 */
52 if (buffer->offset < (buffer->capacity >> 3) &&
53 buffer->capacity > BUFFER_MIN_SHRINK_SIZE) {
54 return;
55 }
56
Gerd Hoffmannd2b90712015-10-30 12:10:01 +010057 old = buffer->capacity;
Gerd Hoffmann1ff36b52015-10-30 12:10:00 +010058 buffer->capacity = pow2ceil(buffer->offset);
59 buffer->capacity = MAX(buffer->capacity, BUFFER_MIN_SHRINK_SIZE);
60 buffer->buffer = g_realloc(buffer->buffer, buffer->capacity);
Gerd Hoffmannd2b90712015-10-30 12:10:01 +010061 trace_buffer_resize(buffer->name ?: "unnamed",
62 old, buffer->capacity);
Gerd Hoffmann1ff36b52015-10-30 12:10:00 +010063}
64
Daniel P. Berrange88c5f202015-03-03 17:13:42 +000065void buffer_reserve(Buffer *buffer, size_t len)
66{
Gerd Hoffmannd2b90712015-10-30 12:10:01 +010067 size_t old;
68
Daniel P. Berrange88c5f202015-03-03 17:13:42 +000069 if ((buffer->capacity - buffer->offset) < len) {
Gerd Hoffmannd2b90712015-10-30 12:10:01 +010070 old = buffer->capacity;
Peter Lievenfd952432015-10-30 12:10:12 +010071 buffer->capacity = buffer_req_size(buffer, len);
Daniel P. Berrange88c5f202015-03-03 17:13:42 +000072 buffer->buffer = g_realloc(buffer->buffer, buffer->capacity);
Gerd Hoffmannd2b90712015-10-30 12:10:01 +010073 trace_buffer_resize(buffer->name ?: "unnamed",
74 old, buffer->capacity);
Daniel P. Berrange88c5f202015-03-03 17:13:42 +000075 }
76}
77
78gboolean buffer_empty(Buffer *buffer)
79{
80 return buffer->offset == 0;
81}
82
83uint8_t *buffer_end(Buffer *buffer)
84{
85 return buffer->buffer + buffer->offset;
86}
87
88void buffer_reset(Buffer *buffer)
89{
90 buffer->offset = 0;
91}
92
93void buffer_free(Buffer *buffer)
94{
Gerd Hoffmannd2b90712015-10-30 12:10:01 +010095 trace_buffer_free(buffer->name ?: "unnamed", buffer->capacity);
Daniel P. Berrange88c5f202015-03-03 17:13:42 +000096 g_free(buffer->buffer);
Gerd Hoffmann810082d2015-10-30 12:09:57 +010097 g_free(buffer->name);
Daniel P. Berrange88c5f202015-03-03 17:13:42 +000098 buffer->offset = 0;
99 buffer->capacity = 0;
100 buffer->buffer = NULL;
Gerd Hoffmann810082d2015-10-30 12:09:57 +0100101 buffer->name = NULL;
Daniel P. Berrange88c5f202015-03-03 17:13:42 +0000102}
103
104void buffer_append(Buffer *buffer, const void *data, size_t len)
105{
106 memcpy(buffer->buffer + buffer->offset, data, len);
107 buffer->offset += len;
108}
109
110void buffer_advance(Buffer *buffer, size_t len)
111{
112 memmove(buffer->buffer, buffer->buffer + len,
113 (buffer->offset - len));
114 buffer->offset -= len;
115}
Gerd Hoffmann4d1eb5f2015-10-30 12:09:58 +0100116
117void buffer_move_empty(Buffer *to, Buffer *from)
118{
Gerd Hoffmannd2b90712015-10-30 12:10:01 +0100119 trace_buffer_move_empty(to->name ?: "unnamed",
120 from->offset,
121 from->name ?: "unnamed");
Gerd Hoffmann4d1eb5f2015-10-30 12:09:58 +0100122 assert(to->offset == 0);
123
124 g_free(to->buffer);
125 to->offset = from->offset;
126 to->capacity = from->capacity;
127 to->buffer = from->buffer;
128
129 from->offset = 0;
130 from->capacity = 0;
131 from->buffer = NULL;
132}
Gerd Hoffmann830a9582015-10-30 12:09:59 +0100133
134void buffer_move(Buffer *to, Buffer *from)
135{
136 if (to->offset == 0) {
137 buffer_move_empty(to, from);
138 return;
139 }
140
Gerd Hoffmannd2b90712015-10-30 12:10:01 +0100141 trace_buffer_move(to->name ?: "unnamed",
142 from->offset,
143 from->name ?: "unnamed");
Gerd Hoffmann830a9582015-10-30 12:09:59 +0100144 buffer_reserve(to, from->offset);
145 buffer_append(to, from->buffer, from->offset);
146
147 g_free(from->buffer);
148 from->offset = 0;
149 from->capacity = 0;
150 from->buffer = NULL;
151}