xref: /openbmc/qemu/util/buffer.c (revision fd95243372f7657c2d24aed269e3be01bed1b87c)
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 static 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 
34 void 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 
43 void buffer_shrink(Buffer *buffer)
44 {
45     size_t old;
46 
47     /*
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 
57     old = buffer->capacity;
58     buffer->capacity = pow2ceil(buffer->offset);
59     buffer->capacity = MAX(buffer->capacity, BUFFER_MIN_SHRINK_SIZE);
60     buffer->buffer = g_realloc(buffer->buffer, buffer->capacity);
61     trace_buffer_resize(buffer->name ?: "unnamed",
62                         old, buffer->capacity);
63 }
64 
65 void buffer_reserve(Buffer *buffer, size_t len)
66 {
67     size_t old;
68 
69     if ((buffer->capacity - buffer->offset) < len) {
70         old = buffer->capacity;
71         buffer->capacity = buffer_req_size(buffer, len);
72         buffer->buffer = g_realloc(buffer->buffer, buffer->capacity);
73         trace_buffer_resize(buffer->name ?: "unnamed",
74                             old, buffer->capacity);
75     }
76 }
77 
78 gboolean buffer_empty(Buffer *buffer)
79 {
80     return buffer->offset == 0;
81 }
82 
83 uint8_t *buffer_end(Buffer *buffer)
84 {
85     return buffer->buffer + buffer->offset;
86 }
87 
88 void buffer_reset(Buffer *buffer)
89 {
90     buffer->offset = 0;
91 }
92 
93 void buffer_free(Buffer *buffer)
94 {
95     trace_buffer_free(buffer->name ?: "unnamed", buffer->capacity);
96     g_free(buffer->buffer);
97     g_free(buffer->name);
98     buffer->offset = 0;
99     buffer->capacity = 0;
100     buffer->buffer = NULL;
101     buffer->name = NULL;
102 }
103 
104 void 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 
110 void buffer_advance(Buffer *buffer, size_t len)
111 {
112     memmove(buffer->buffer, buffer->buffer + len,
113             (buffer->offset - len));
114     buffer->offset -= len;
115 }
116 
117 void buffer_move_empty(Buffer *to, Buffer *from)
118 {
119     trace_buffer_move_empty(to->name ?: "unnamed",
120                             from->offset,
121                             from->name ?: "unnamed");
122     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 }
133 
134 void buffer_move(Buffer *to, Buffer *from)
135 {
136     if (to->offset == 0) {
137         buffer_move_empty(to, from);
138         return;
139     }
140 
141     trace_buffer_move(to->name ?: "unnamed",
142                       from->offset,
143                       from->name ?: "unnamed");
144     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 }
152