xref: /openbmc/qemu/util/buffer.c (revision fd952433)
188c5f205SDaniel P. Berrange /*
288c5f205SDaniel P. Berrange  * QEMU generic buffers
388c5f205SDaniel P. Berrange  *
488c5f205SDaniel P. Berrange  * Copyright (c) 2015 Red Hat, Inc.
588c5f205SDaniel P. Berrange  *
688c5f205SDaniel P. Berrange  * This library is free software; you can redistribute it and/or
788c5f205SDaniel P. Berrange  * modify it under the terms of the GNU Lesser General Public
888c5f205SDaniel P. Berrange  * License as published by the Free Software Foundation; either
988c5f205SDaniel P. Berrange  * version 2 of the License, or (at your option) any later version.
1088c5f205SDaniel P. Berrange  *
1188c5f205SDaniel P. Berrange  * This library is distributed in the hope that it will be useful,
1288c5f205SDaniel P. Berrange  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1388c5f205SDaniel P. Berrange  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1488c5f205SDaniel P. Berrange  * Lesser General Public License for more details.
1588c5f205SDaniel P. Berrange  *
1688c5f205SDaniel P. Berrange  * You should have received a copy of the GNU Lesser General Public
1788c5f205SDaniel P. Berrange  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
1888c5f205SDaniel P. Berrange  *
1988c5f205SDaniel P. Berrange  */
2088c5f205SDaniel P. Berrange 
2188c5f205SDaniel P. Berrange #include "qemu/buffer.h"
22d2b90718SGerd Hoffmann #include "trace.h"
2388c5f205SDaniel P. Berrange 
245c10dbb7SPeter Lieven #define BUFFER_MIN_INIT_SIZE     4096
251ff36b5dSGerd Hoffmann #define BUFFER_MIN_SHRINK_SIZE  65536
265c10dbb7SPeter Lieven 
27*fd952433SPeter Lieven static size_t buffer_req_size(Buffer *buffer, size_t len)
28*fd952433SPeter Lieven {
29*fd952433SPeter Lieven     return MAX(BUFFER_MIN_INIT_SIZE,
30*fd952433SPeter Lieven                pow2ceil(buffer->offset + len));
31*fd952433SPeter Lieven }
32*fd952433SPeter Lieven 
33*fd952433SPeter Lieven 
34810082d1SGerd Hoffmann void buffer_init(Buffer *buffer, const char *name, ...)
35810082d1SGerd Hoffmann {
36810082d1SGerd Hoffmann     va_list ap;
37810082d1SGerd Hoffmann 
38810082d1SGerd Hoffmann     va_start(ap, name);
39810082d1SGerd Hoffmann     buffer->name = g_strdup_vprintf(name, ap);
40810082d1SGerd Hoffmann     va_end(ap);
41810082d1SGerd Hoffmann }
42810082d1SGerd Hoffmann 
431ff36b5dSGerd Hoffmann void buffer_shrink(Buffer *buffer)
441ff36b5dSGerd Hoffmann {
45d2b90718SGerd Hoffmann     size_t old;
46d2b90718SGerd Hoffmann 
471ff36b5dSGerd Hoffmann     /*
481ff36b5dSGerd Hoffmann      * Only shrink in case the used size is *much* smaller than the
491ff36b5dSGerd Hoffmann      * capacity, to avoid bumping up & down the buffers all the time.
501ff36b5dSGerd Hoffmann      * realloc() isn't exactly cheap ...
511ff36b5dSGerd Hoffmann      */
521ff36b5dSGerd Hoffmann     if (buffer->offset < (buffer->capacity >> 3) &&
531ff36b5dSGerd Hoffmann         buffer->capacity > BUFFER_MIN_SHRINK_SIZE) {
541ff36b5dSGerd Hoffmann         return;
551ff36b5dSGerd Hoffmann     }
561ff36b5dSGerd Hoffmann 
57d2b90718SGerd Hoffmann     old = buffer->capacity;
581ff36b5dSGerd Hoffmann     buffer->capacity = pow2ceil(buffer->offset);
591ff36b5dSGerd Hoffmann     buffer->capacity = MAX(buffer->capacity, BUFFER_MIN_SHRINK_SIZE);
601ff36b5dSGerd Hoffmann     buffer->buffer = g_realloc(buffer->buffer, buffer->capacity);
61d2b90718SGerd Hoffmann     trace_buffer_resize(buffer->name ?: "unnamed",
62d2b90718SGerd Hoffmann                         old, buffer->capacity);
631ff36b5dSGerd Hoffmann }
641ff36b5dSGerd Hoffmann 
6588c5f205SDaniel P. Berrange void buffer_reserve(Buffer *buffer, size_t len)
6688c5f205SDaniel P. Berrange {
67d2b90718SGerd Hoffmann     size_t old;
68d2b90718SGerd Hoffmann 
6988c5f205SDaniel P. Berrange     if ((buffer->capacity - buffer->offset) < len) {
70d2b90718SGerd Hoffmann         old = buffer->capacity;
71*fd952433SPeter Lieven         buffer->capacity = buffer_req_size(buffer, len);
7288c5f205SDaniel P. Berrange         buffer->buffer = g_realloc(buffer->buffer, buffer->capacity);
73d2b90718SGerd Hoffmann         trace_buffer_resize(buffer->name ?: "unnamed",
74d2b90718SGerd Hoffmann                             old, buffer->capacity);
7588c5f205SDaniel P. Berrange     }
7688c5f205SDaniel P. Berrange }
7788c5f205SDaniel P. Berrange 
7888c5f205SDaniel P. Berrange gboolean buffer_empty(Buffer *buffer)
7988c5f205SDaniel P. Berrange {
8088c5f205SDaniel P. Berrange     return buffer->offset == 0;
8188c5f205SDaniel P. Berrange }
8288c5f205SDaniel P. Berrange 
8388c5f205SDaniel P. Berrange uint8_t *buffer_end(Buffer *buffer)
8488c5f205SDaniel P. Berrange {
8588c5f205SDaniel P. Berrange     return buffer->buffer + buffer->offset;
8688c5f205SDaniel P. Berrange }
8788c5f205SDaniel P. Berrange 
8888c5f205SDaniel P. Berrange void buffer_reset(Buffer *buffer)
8988c5f205SDaniel P. Berrange {
9088c5f205SDaniel P. Berrange     buffer->offset = 0;
9188c5f205SDaniel P. Berrange }
9288c5f205SDaniel P. Berrange 
9388c5f205SDaniel P. Berrange void buffer_free(Buffer *buffer)
9488c5f205SDaniel P. Berrange {
95d2b90718SGerd Hoffmann     trace_buffer_free(buffer->name ?: "unnamed", buffer->capacity);
9688c5f205SDaniel P. Berrange     g_free(buffer->buffer);
97810082d1SGerd Hoffmann     g_free(buffer->name);
9888c5f205SDaniel P. Berrange     buffer->offset = 0;
9988c5f205SDaniel P. Berrange     buffer->capacity = 0;
10088c5f205SDaniel P. Berrange     buffer->buffer = NULL;
101810082d1SGerd Hoffmann     buffer->name = NULL;
10288c5f205SDaniel P. Berrange }
10388c5f205SDaniel P. Berrange 
10488c5f205SDaniel P. Berrange void buffer_append(Buffer *buffer, const void *data, size_t len)
10588c5f205SDaniel P. Berrange {
10688c5f205SDaniel P. Berrange     memcpy(buffer->buffer + buffer->offset, data, len);
10788c5f205SDaniel P. Berrange     buffer->offset += len;
10888c5f205SDaniel P. Berrange }
10988c5f205SDaniel P. Berrange 
11088c5f205SDaniel P. Berrange void buffer_advance(Buffer *buffer, size_t len)
11188c5f205SDaniel P. Berrange {
11288c5f205SDaniel P. Berrange     memmove(buffer->buffer, buffer->buffer + len,
11388c5f205SDaniel P. Berrange             (buffer->offset - len));
11488c5f205SDaniel P. Berrange     buffer->offset -= len;
11588c5f205SDaniel P. Berrange }
1164d1eb5fdSGerd Hoffmann 
1174d1eb5fdSGerd Hoffmann void buffer_move_empty(Buffer *to, Buffer *from)
1184d1eb5fdSGerd Hoffmann {
119d2b90718SGerd Hoffmann     trace_buffer_move_empty(to->name ?: "unnamed",
120d2b90718SGerd Hoffmann                             from->offset,
121d2b90718SGerd Hoffmann                             from->name ?: "unnamed");
1224d1eb5fdSGerd Hoffmann     assert(to->offset == 0);
1234d1eb5fdSGerd Hoffmann 
1244d1eb5fdSGerd Hoffmann     g_free(to->buffer);
1254d1eb5fdSGerd Hoffmann     to->offset = from->offset;
1264d1eb5fdSGerd Hoffmann     to->capacity = from->capacity;
1274d1eb5fdSGerd Hoffmann     to->buffer = from->buffer;
1284d1eb5fdSGerd Hoffmann 
1294d1eb5fdSGerd Hoffmann     from->offset = 0;
1304d1eb5fdSGerd Hoffmann     from->capacity = 0;
1314d1eb5fdSGerd Hoffmann     from->buffer = NULL;
1324d1eb5fdSGerd Hoffmann }
133830a9583SGerd Hoffmann 
134830a9583SGerd Hoffmann void buffer_move(Buffer *to, Buffer *from)
135830a9583SGerd Hoffmann {
136830a9583SGerd Hoffmann     if (to->offset == 0) {
137830a9583SGerd Hoffmann         buffer_move_empty(to, from);
138830a9583SGerd Hoffmann         return;
139830a9583SGerd Hoffmann     }
140830a9583SGerd Hoffmann 
141d2b90718SGerd Hoffmann     trace_buffer_move(to->name ?: "unnamed",
142d2b90718SGerd Hoffmann                       from->offset,
143d2b90718SGerd Hoffmann                       from->name ?: "unnamed");
144830a9583SGerd Hoffmann     buffer_reserve(to, from->offset);
145830a9583SGerd Hoffmann     buffer_append(to, from->buffer, from->offset);
146830a9583SGerd Hoffmann 
147830a9583SGerd Hoffmann     g_free(from->buffer);
148830a9583SGerd Hoffmann     from->offset = 0;
149830a9583SGerd Hoffmann     from->capacity = 0;
150830a9583SGerd Hoffmann     from->buffer = NULL;
151830a9583SGerd Hoffmann }
152