Add lttng_dynamic_buffer_append_view util
[lttng-tools.git] / src / common / dynamic-buffer.c
CommitLineData
0b83088a
MJ
1/*
2 * Copyright (C) 2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License, version 2.1 only,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
11 * for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, write to the Free Software Foundation,
15 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17
18#include <common/dynamic-buffer.h>
b7bce764 19#include <common/buffer-view.h>
0b83088a
MJ
20#include <common/utils.h>
21#include <assert.h>
22
23/*
24 * Round to (upper) power of two, val is returned if it already is a power of
25 * two.
26 */
27static
28size_t round_to_power_of_2(size_t val)
29{
30 int order;
31 size_t rounded;
32
33 order = utils_get_count_order_u64(val);
34 assert(order >= 0);
35 rounded = (1ULL << order);
36 assert(rounded >= val);
37
38 return rounded;
39}
40
41LTTNG_HIDDEN
42void lttng_dynamic_buffer_init(struct lttng_dynamic_buffer *buffer)
43{
44 assert(buffer);
45 memset(buffer, 0, sizeof(*buffer));
46}
47
48LTTNG_HIDDEN
49int lttng_dynamic_buffer_append(struct lttng_dynamic_buffer *buffer,
50 const void *buf, size_t len)
51{
52 int ret = 0;
53
54 if (!buffer || (!buf && len)) {
55 ret = -1;
56 goto end;
57 }
58
59 if (len == 0) {
60 /* Not an error, no-op. */
61 goto end;
62 }
63
64 assert(buffer->_capacity >= buffer->size);
65 if (buffer->_capacity < (len + buffer->size)) {
66 ret = lttng_dynamic_buffer_set_capacity(buffer,
67 buffer->_capacity +
68 (len - (buffer->_capacity - buffer->size)));
69 if (ret) {
70 goto end;
71 }
72 }
73
74 memcpy(buffer->data + buffer->size, buf, len);
75 buffer->size += len;
76end:
77 return ret;
78}
79
80LTTNG_HIDDEN
81int lttng_dynamic_buffer_append_buffer(struct lttng_dynamic_buffer *dst_buffer,
82 struct lttng_dynamic_buffer *src_buffer)
83{
84 int ret;
85
86 if (!dst_buffer || !src_buffer) {
87 ret = -1;
88 goto end;
89 }
90
91 ret = lttng_dynamic_buffer_append(dst_buffer, src_buffer->data,
92 src_buffer->size);
93end:
94 return ret;
95}
96
b7bce764
JG
97LTTNG_HIDDEN
98int lttng_dynamic_buffer_append_view(struct lttng_dynamic_buffer *buffer,
99 const struct lttng_buffer_view *src)
100{
101 int ret;
102
103 if (!buffer || !src) {
104 ret = -1;
105 goto end;
106 }
107
108 ret = lttng_dynamic_buffer_append(buffer, src->data,
109 src->size);
110end:
111 return ret;
112}
113
0b83088a
MJ
114LTTNG_HIDDEN
115int lttng_dynamic_buffer_set_size(struct lttng_dynamic_buffer *buffer,
116 size_t new_size)
117{
118 int ret = 0;
119
120 if (!buffer) {
121 goto end;
122 }
123
124 if (new_size == buffer->size) {
125 goto end;
126 }
127
128 if (new_size > buffer->_capacity) {
129 size_t original_size = buffer->size;
130 size_t original_capacity = buffer->_capacity;
131
132 ret = lttng_dynamic_buffer_set_capacity(buffer, new_size);
133 if (ret) {
134 goto end;
135 }
136
137 /*
138 * Zero-initialize the space that was left in the buffer at the
139 * before we increased its capacity (original capacity - original size).
140 * The newly acquired capacity (new capacity - original capacity)
141 * is zeroed by lttng_dynamic_buffer_set_capacity().
142 */
143 memset(buffer->data + original_size, 0,
144 original_capacity - original_size);
145 } else if (new_size > buffer->size) {
146 memset(buffer->data + buffer->size, 0, new_size - buffer->size);
147 } else {
148 /*
149 * Shrinking size. There is no need to zero-out the newly
150 * released memory as it will either be:
151 * - overwritten by lttng_dynamic_buffer_append,
152 * - expanded later, which will zero-out the memory
153 *
154 * Users of external APIs are encouraged to set the buffer's
155 * size _before_ making such calls.
156 */
157 }
158 buffer->size = new_size;
159end:
160 return ret;
161}
162
163LTTNG_HIDDEN
164int lttng_dynamic_buffer_set_capacity(struct lttng_dynamic_buffer *buffer,
165 size_t demanded_capacity)
166{
167 int ret = 0;
168 void *new_buf;
169 size_t new_capacity = round_to_power_of_2(demanded_capacity);
170
171 if (!buffer || demanded_capacity < buffer->size) {
172 /*
173 * Shrinking a buffer's size by changing its capacity is
174 * unsupported.
175 */
176 ret = -1;
177 goto end;
178 }
179
180 if (new_capacity == buffer->_capacity) {
181 goto end;
182 }
183
184 /* Memory is initialized by the size increases. */
185 new_buf = realloc(buffer->data, new_capacity);
186 if (!new_buf) {
187 ret = -1;
188 goto end;
189 }
190 buffer->data = new_buf;
191 buffer->_capacity = new_capacity;
192end:
193 return ret;
194}
195
196/* Release any memory used by the dynamic buffer. */
197LTTNG_HIDDEN
198void lttng_dynamic_buffer_reset(struct lttng_dynamic_buffer *buffer)
199{
200 if (!buffer) {
201 return;
202 }
203 buffer->size = 0;
204 buffer->_capacity = 0;
205 free(buffer->data);
206}
This page took 0.033961 seconds and 5 git commands to generate.