Add lttng_dynamic_buffer_append_view util
[lttng-tools.git] / src / common / dynamic-buffer.c
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>
19 #include <common/buffer-view.h>
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 */
27 static
28 size_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
41 LTTNG_HIDDEN
42 void lttng_dynamic_buffer_init(struct lttng_dynamic_buffer *buffer)
43 {
44 assert(buffer);
45 memset(buffer, 0, sizeof(*buffer));
46 }
47
48 LTTNG_HIDDEN
49 int 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;
76 end:
77 return ret;
78 }
79
80 LTTNG_HIDDEN
81 int 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);
93 end:
94 return ret;
95 }
96
97 LTTNG_HIDDEN
98 int 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);
110 end:
111 return ret;
112 }
113
114 LTTNG_HIDDEN
115 int 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 ret = lttng_dynamic_buffer_set_capacity(buffer, new_size);
130 if (ret) {
131 goto end;
132 }
133
134 memset(buffer->data + buffer->size, 0, new_size - buffer->size);
135 } else if (new_size > buffer->size) {
136 memset(buffer->data + buffer->size, 0, new_size - buffer->size);
137 } else {
138 /*
139 * Shrinking size. There is no need to zero-out the newly
140 * released memory as it will either be:
141 * - overwritten by lttng_dynamic_buffer_append,
142 * - expanded later, which will zero-out the memory
143 *
144 * Users of external APIs are encouraged to set the buffer's
145 * size _before_ making such calls.
146 */
147 }
148 buffer->size = new_size;
149 end:
150 return ret;
151 }
152
153 LTTNG_HIDDEN
154 int lttng_dynamic_buffer_set_capacity(struct lttng_dynamic_buffer *buffer,
155 size_t demanded_capacity)
156 {
157 int ret = 0;
158 void *new_buf;
159 size_t new_capacity = demanded_capacity ?
160 round_to_power_of_2(demanded_capacity) : 0;
161
162 if (!buffer || demanded_capacity < buffer->size) {
163 /*
164 * Shrinking a buffer's size by changing its capacity is
165 * unsupported.
166 */
167 ret = -1;
168 goto end;
169 }
170
171 if (new_capacity == buffer->_capacity) {
172 goto end;
173 }
174
175 /* Memory is initialized by the size increases. */
176 new_buf = realloc(buffer->data, new_capacity);
177 if (!new_buf) {
178 ret = -1;
179 goto end;
180 }
181 buffer->data = new_buf;
182 buffer->_capacity = new_capacity;
183 end:
184 return ret;
185 }
186
187 /* Release any memory used by the dynamic buffer. */
188 LTTNG_HIDDEN
189 void lttng_dynamic_buffer_reset(struct lttng_dynamic_buffer *buffer)
190 {
191 if (!buffer) {
192 return;
193 }
194 buffer->size = 0;
195 buffer->_capacity = 0;
196 free(buffer->data);
197 }
198
199 LTTNG_HIDDEN
200 size_t lttng_dynamic_buffer_get_capacity_left(
201 struct lttng_dynamic_buffer *buffer)
202 {
203 if (!buffer) {
204 return 0;
205 }
206 return buffer->_capacity - buffer->size;
207 }
This page took 0.035457 seconds and 4 git commands to generate.