blob: ae2907ebd41d84a383ccc89c5b3f76cfd128e281 [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
Gerd Hoffmann810082d2015-10-30 12:09:57 +010027void 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
Gerd Hoffmann1ff36b52015-10-30 12:10:00 +010036void buffer_shrink(Buffer *buffer)
37{
Gerd Hoffmannd2b90712015-10-30 12:10:01 +010038 size_t old;
39
Gerd Hoffmann1ff36b52015-10-30 12:10:00 +010040 /*
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
Gerd Hoffmannd2b90712015-10-30 12:10:01 +010050 old = buffer->capacity;
Gerd Hoffmann1ff36b52015-10-30 12:10:00 +010051 buffer->capacity = pow2ceil(buffer->offset);
52 buffer->capacity = MAX(buffer->capacity, BUFFER_MIN_SHRINK_SIZE);
53 buffer->buffer = g_realloc(buffer->buffer, buffer->capacity);
Gerd Hoffmannd2b90712015-10-30 12:10:01 +010054 trace_buffer_resize(buffer->name ?: "unnamed",
55 old, buffer->capacity);
Gerd Hoffmann1ff36b52015-10-30 12:10:00 +010056}
57
Daniel P. Berrange88c5f202015-03-03 17:13:42 +000058void buffer_reserve(Buffer *buffer, size_t len)
59{
Gerd Hoffmannd2b90712015-10-30 12:10:01 +010060 size_t old;
61
Daniel P. Berrange88c5f202015-03-03 17:13:42 +000062 if ((buffer->capacity - buffer->offset) < len) {
Gerd Hoffmannd2b90712015-10-30 12:10:01 +010063 old = buffer->capacity;
Peter Lieven5c10dbb2015-10-30 12:09:56 +010064 buffer->capacity = pow2ceil(buffer->offset + len);
65 buffer->capacity = MAX(buffer->capacity, BUFFER_MIN_INIT_SIZE);
Daniel P. Berrange88c5f202015-03-03 17:13:42 +000066 buffer->buffer = g_realloc(buffer->buffer, buffer->capacity);
Gerd Hoffmannd2b90712015-10-30 12:10:01 +010067 trace_buffer_resize(buffer->name ?: "unnamed",
68 old, buffer->capacity);
Daniel P. Berrange88c5f202015-03-03 17:13:42 +000069 }
70}
71
72gboolean buffer_empty(Buffer *buffer)
73{
74 return buffer->offset == 0;
75}
76
77uint8_t *buffer_end(Buffer *buffer)
78{
79 return buffer->buffer + buffer->offset;
80}
81
82void buffer_reset(Buffer *buffer)
83{
84 buffer->offset = 0;
85}
86
87void buffer_free(Buffer *buffer)
88{
Gerd Hoffmannd2b90712015-10-30 12:10:01 +010089 trace_buffer_free(buffer->name ?: "unnamed", buffer->capacity);
Daniel P. Berrange88c5f202015-03-03 17:13:42 +000090 g_free(buffer->buffer);
Gerd Hoffmann810082d2015-10-30 12:09:57 +010091 g_free(buffer->name);
Daniel P. Berrange88c5f202015-03-03 17:13:42 +000092 buffer->offset = 0;
93 buffer->capacity = 0;
94 buffer->buffer = NULL;
Gerd Hoffmann810082d2015-10-30 12:09:57 +010095 buffer->name = NULL;
Daniel P. Berrange88c5f202015-03-03 17:13:42 +000096}
97
98void 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
104void buffer_advance(Buffer *buffer, size_t len)
105{
106 memmove(buffer->buffer, buffer->buffer + len,
107 (buffer->offset - len));
108 buffer->offset -= len;
109}
Gerd Hoffmann4d1eb5f2015-10-30 12:09:58 +0100110
111void buffer_move_empty(Buffer *to, Buffer *from)
112{
Gerd Hoffmannd2b90712015-10-30 12:10:01 +0100113 trace_buffer_move_empty(to->name ?: "unnamed",
114 from->offset,
115 from->name ?: "unnamed");
Gerd Hoffmann4d1eb5f2015-10-30 12:09:58 +0100116 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}
Gerd Hoffmann830a9582015-10-30 12:09:59 +0100127
128void buffer_move(Buffer *to, Buffer *from)
129{
130 if (to->offset == 0) {
131 buffer_move_empty(to, from);
132 return;
133 }
134
Gerd Hoffmannd2b90712015-10-30 12:10:01 +0100135 trace_buffer_move(to->name ?: "unnamed",
136 from->offset,
137 from->name ?: "unnamed");
Gerd Hoffmann830a9582015-10-30 12:09:59 +0100138 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}