xref: /openbmc/qemu/util/buffer.c (revision d2b90718)
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