Add basic exception types and throwing facilities
[lttng-tools.git] / src / common / dynamic-buffer.cpp
1 /*
2 * Copyright (C) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 *
6 */
7
8 #include <common/dynamic-buffer.hpp>
9 #include <common/buffer-view.hpp>
10 #include <common/utils.hpp>
11
12 /*
13 * Round to (upper) power of two, val is returned if it already is a power of
14 * two.
15 */
16 static
17 size_t round_to_power_of_2(size_t val)
18 {
19 size_t rounded;
20 const int order = utils_get_count_order_u64(val);
21
22 LTTNG_ASSERT(order >= 0);
23 rounded = (1ULL << order);
24 LTTNG_ASSERT(rounded >= val);
25
26 return rounded;
27 }
28
29 void lttng_dynamic_buffer_init(struct lttng_dynamic_buffer *buffer)
30 {
31 LTTNG_ASSERT(buffer);
32 memset(buffer, 0, sizeof(*buffer));
33 }
34
35 int lttng_dynamic_buffer_append(struct lttng_dynamic_buffer *buffer,
36 const void *buf, size_t len)
37 {
38 int ret = 0;
39
40 if (!buffer || (!buf && len)) {
41 ret = -1;
42 goto end;
43 }
44
45 if (len == 0) {
46 /* Not an error, no-op. */
47 goto end;
48 }
49
50 LTTNG_ASSERT(buffer->_capacity >= buffer->size);
51 if (buffer->_capacity < (len + buffer->size)) {
52 ret = lttng_dynamic_buffer_set_capacity(buffer,
53 buffer->_capacity +
54 (len - (buffer->_capacity - buffer->size)));
55 if (ret) {
56 goto end;
57 }
58 }
59
60 memcpy(buffer->data + buffer->size, buf, len);
61 buffer->size += len;
62 end:
63 return ret;
64 }
65
66 int lttng_dynamic_buffer_append_buffer(struct lttng_dynamic_buffer *dst_buffer,
67 const struct lttng_dynamic_buffer *src_buffer)
68 {
69 int ret;
70
71 if (!dst_buffer || !src_buffer) {
72 ret = -1;
73 goto end;
74 }
75
76 ret = lttng_dynamic_buffer_append(dst_buffer, src_buffer->data,
77 src_buffer->size);
78 end:
79 return ret;
80 }
81
82 int lttng_dynamic_buffer_append_view(struct lttng_dynamic_buffer *buffer,
83 const struct lttng_buffer_view *src)
84 {
85 int ret;
86
87 if (!buffer || !src) {
88 ret = -1;
89 goto end;
90 }
91
92 ret = lttng_dynamic_buffer_append(buffer, src->data,
93 src->size);
94 end:
95 return ret;
96 }
97
98 int lttng_dynamic_buffer_set_size(struct lttng_dynamic_buffer *buffer,
99 size_t new_size)
100 {
101 int ret = 0;
102
103 if (!buffer) {
104 goto end;
105 }
106
107 if (new_size == buffer->size) {
108 goto end;
109 }
110
111 if (new_size > buffer->_capacity) {
112 ret = lttng_dynamic_buffer_set_capacity(buffer, new_size);
113 if (ret) {
114 goto end;
115 }
116
117 memset(buffer->data + buffer->size, 0, new_size - buffer->size);
118 } else if (new_size > buffer->size) {
119 memset(buffer->data + buffer->size, 0, new_size - buffer->size);
120 } else {
121 /*
122 * Shrinking size. There is no need to zero-out the newly
123 * released memory as it will either be:
124 * - overwritten by lttng_dynamic_buffer_append,
125 * - expanded later, which will zero-out the memory
126 *
127 * Users of external APIs are encouraged to set the buffer's
128 * size _before_ making such calls.
129 */
130 }
131
132 buffer->size = new_size;
133 end:
134 return ret;
135 }
136
137 int lttng_dynamic_buffer_set_capacity(struct lttng_dynamic_buffer *buffer,
138 size_t demanded_capacity)
139 {
140 int ret = 0;
141 void *new_buf;
142 size_t new_capacity = demanded_capacity ?
143 round_to_power_of_2(demanded_capacity) : 0;
144
145 if (!buffer || demanded_capacity < buffer->size) {
146 /*
147 * Shrinking a buffer's size by changing its capacity is
148 * unsupported.
149 */
150 ret = -1;
151 goto end;
152 }
153
154 if (new_capacity == buffer->_capacity) {
155 goto end;
156 }
157
158 /* Memory is initialized by the size increases. */
159 new_buf = realloc(buffer->data, new_capacity);
160 if (!new_buf) {
161 ret = -1;
162 goto end;
163 }
164
165 buffer->data = (char *) new_buf;
166 buffer->_capacity = new_capacity;
167 end:
168 return ret;
169 }
170
171 /* Release any memory used by the dynamic buffer. */
172 void lttng_dynamic_buffer_reset(struct lttng_dynamic_buffer *buffer)
173 {
174 if (!buffer) {
175 return;
176 }
177
178 buffer->size = 0;
179 buffer->_capacity = 0;
180 free(buffer->data);
181 buffer->data = NULL;
182 }
183
184 size_t lttng_dynamic_buffer_get_capacity_left(
185 struct lttng_dynamic_buffer *buffer)
186 {
187 if (!buffer) {
188 return 0;
189 }
190
191 return buffer->_capacity - buffer->size;
192 }
This page took 0.033957 seconds and 4 git commands to generate.