3 * Copyright 2015 gRPC authors.
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
19 #include <grpc/support/port_platform.h>
21 #include <grpc/slice_buffer.h>
25 #include <grpc/support/alloc.h>
26 #include <grpc/support/log.h>
28 #include "src/core/lib/gpr/useful.h"
29 #include "src/core/lib/iomgr/exec_ctx.h"
30 #include "src/core/lib/slice/slice_internal.h"
32 /* grow a buffer; requires GRPC_SLICE_BUFFER_INLINE_ELEMENTS > 1 */
33 #define GROW(x) (3 * (x) / 2)
35 static void maybe_embiggen(grpc_slice_buffer* sb) {
37 sb->slices = sb->base_slices;
40 /* How far away from sb->base_slices is sb->slices pointer */
41 size_t slice_offset = static_cast<size_t>(sb->slices - sb->base_slices);
42 size_t slice_count = sb->count + slice_offset;
44 if (slice_count == sb->capacity) {
45 if (sb->base_slices != sb->slices) {
46 /* Make room by moving elements if there's still space unused */
47 memmove(sb->base_slices, sb->slices, sb->count * sizeof(grpc_slice));
48 sb->slices = sb->base_slices;
50 /* Allocate more memory if no more space is available */
51 sb->capacity = GROW(sb->capacity);
52 GPR_ASSERT(sb->capacity > slice_count);
53 if (sb->base_slices == sb->inlined) {
54 sb->base_slices = static_cast<grpc_slice*>(
55 gpr_malloc(sb->capacity * sizeof(grpc_slice)));
56 memcpy(sb->base_slices, sb->inlined, slice_count * sizeof(grpc_slice));
58 sb->base_slices = static_cast<grpc_slice*>(
59 gpr_realloc(sb->base_slices, sb->capacity * sizeof(grpc_slice)));
62 sb->slices = sb->base_slices + slice_offset;
67 void grpc_slice_buffer_init(grpc_slice_buffer* sb) {
70 sb->capacity = GRPC_SLICE_BUFFER_INLINE_ELEMENTS;
71 sb->base_slices = sb->slices = sb->inlined;
74 void grpc_slice_buffer_destroy_internal(grpc_slice_buffer* sb) {
75 grpc_slice_buffer_reset_and_unref_internal(sb);
76 if (sb->base_slices != sb->inlined) {
77 gpr_free(sb->base_slices);
81 void grpc_slice_buffer_destroy(grpc_slice_buffer* sb) {
82 if (grpc_core::ExecCtx::Get() == nullptr) {
83 grpc_core::ExecCtx exec_ctx;
84 grpc_slice_buffer_destroy_internal(sb);
86 grpc_slice_buffer_destroy_internal(sb);
90 uint8_t* grpc_slice_buffer_tiny_add(grpc_slice_buffer* sb, size_t n) {
96 if (sb->count == 0) goto add_new;
97 back = &sb->slices[sb->count - 1];
98 if (back->refcount) goto add_new;
99 if ((back->data.inlined.length + n) > sizeof(back->data.inlined.bytes))
101 out = back->data.inlined.bytes + back->data.inlined.length;
102 back->data.inlined.length =
103 static_cast<uint8_t>(back->data.inlined.length + n);
108 back = &sb->slices[sb->count];
110 back->refcount = nullptr;
111 back->data.inlined.length = static_cast<uint8_t>(n);
112 return back->data.inlined.bytes;
115 size_t grpc_slice_buffer_add_indexed(grpc_slice_buffer* sb, grpc_slice s) {
116 size_t out = sb->count;
119 sb->length += GRPC_SLICE_LENGTH(s);
124 void grpc_slice_buffer_add(grpc_slice_buffer* sb, grpc_slice s) {
125 size_t n = sb->count;
126 /* if both the last slice in the slice buffer and the slice being added
127 are inlined (that is, that they carry their data inside the slice data
128 structure), and the back slice is not full, then concatenate directly
129 into the back slice, preventing many small slices being passed into
131 if (!s.refcount && n) {
132 grpc_slice* back = &sb->slices[n - 1];
133 if (!back->refcount &&
134 back->data.inlined.length < GRPC_SLICE_INLINED_SIZE) {
135 if (s.data.inlined.length + back->data.inlined.length <=
136 GRPC_SLICE_INLINED_SIZE) {
137 memcpy(back->data.inlined.bytes + back->data.inlined.length,
138 s.data.inlined.bytes, s.data.inlined.length);
139 back->data.inlined.length = static_cast<uint8_t>(
140 back->data.inlined.length + s.data.inlined.length);
142 size_t cp1 = GRPC_SLICE_INLINED_SIZE - back->data.inlined.length;
143 memcpy(back->data.inlined.bytes + back->data.inlined.length,
144 s.data.inlined.bytes, cp1);
145 back->data.inlined.length = GRPC_SLICE_INLINED_SIZE;
147 back = &sb->slices[n];
149 back->refcount = nullptr;
150 back->data.inlined.length =
151 static_cast<uint8_t>(s.data.inlined.length - cp1);
152 memcpy(back->data.inlined.bytes, s.data.inlined.bytes + cp1,
153 s.data.inlined.length - cp1);
155 sb->length += s.data.inlined.length;
156 return; /* early out */
159 grpc_slice_buffer_add_indexed(sb, s);
162 void grpc_slice_buffer_addn(grpc_slice_buffer* sb, grpc_slice* s, size_t n) {
164 for (i = 0; i < n; i++) {
165 grpc_slice_buffer_add(sb, s[i]);
169 void grpc_slice_buffer_pop(grpc_slice_buffer* sb) {
170 if (sb->count != 0) {
171 size_t count = --sb->count;
172 sb->length -= GRPC_SLICE_LENGTH(sb->slices[count]);
176 void grpc_slice_buffer_reset_and_unref_internal(grpc_slice_buffer* sb) {
178 for (i = 0; i < sb->count; i++) {
179 grpc_slice_unref_internal(sb->slices[i]);
184 sb->slices = sb->base_slices;
187 void grpc_slice_buffer_reset_and_unref(grpc_slice_buffer* sb) {
188 if (grpc_core::ExecCtx::Get() == nullptr) {
189 grpc_core::ExecCtx exec_ctx;
190 grpc_slice_buffer_reset_and_unref_internal(sb);
192 grpc_slice_buffer_reset_and_unref_internal(sb);
196 void grpc_slice_buffer_swap(grpc_slice_buffer* a, grpc_slice_buffer* b) {
197 size_t a_offset = static_cast<size_t>(a->slices - a->base_slices);
198 size_t b_offset = static_cast<size_t>(b->slices - b->base_slices);
200 size_t a_count = a->count + a_offset;
201 size_t b_count = b->count + b_offset;
203 if (a->base_slices == a->inlined) {
204 if (b->base_slices == b->inlined) {
205 /* swap contents of inlined buffer */
206 grpc_slice temp[GRPC_SLICE_BUFFER_INLINE_ELEMENTS];
207 memcpy(temp, a->base_slices, a_count * sizeof(grpc_slice));
208 memcpy(a->base_slices, b->base_slices, b_count * sizeof(grpc_slice));
209 memcpy(b->base_slices, temp, a_count * sizeof(grpc_slice));
211 /* a is inlined, b is not - copy a inlined into b, fix pointers */
212 a->base_slices = b->base_slices;
213 b->base_slices = b->inlined;
214 memcpy(b->base_slices, a->inlined, a_count * sizeof(grpc_slice));
216 } else if (b->base_slices == b->inlined) {
217 /* b is inlined, a is not - copy b inlined int a, fix pointers */
218 b->base_slices = a->base_slices;
219 a->base_slices = a->inlined;
220 memcpy(a->base_slices, b->inlined, b_count * sizeof(grpc_slice));
222 /* no inlining: easy swap */
223 GPR_SWAP(grpc_slice*, a->base_slices, b->base_slices);
226 /* Update the slices pointers (cannot do a GPR_SWAP on slices fields here).
227 * Also note that since the base_slices pointers are already swapped we need
228 * use 'b_offset' for 'a->base_slices' and vice versa */
229 a->slices = a->base_slices + b_offset;
230 b->slices = b->base_slices + a_offset;
232 /* base_slices and slices fields are correctly set. Swap all other fields */
233 GPR_SWAP(size_t, a->count, b->count);
234 GPR_SWAP(size_t, a->capacity, b->capacity);
235 GPR_SWAP(size_t, a->length, b->length);
238 void grpc_slice_buffer_move_into(grpc_slice_buffer* src,
239 grpc_slice_buffer* dst) {
240 /* anything to move? */
241 if (src->count == 0) {
244 /* anything in dst? */
245 if (dst->count == 0) {
246 grpc_slice_buffer_swap(src, dst);
249 /* both buffers have data - copy, and reset src */
250 grpc_slice_buffer_addn(dst, src->slices, src->count);
255 static void slice_buffer_move_first_maybe_ref(grpc_slice_buffer* src, size_t n,
256 grpc_slice_buffer* dst,
258 GPR_ASSERT(src->length >= n);
259 if (src->length == n) {
260 grpc_slice_buffer_move_into(src, dst);
264 size_t output_len = dst->length + n;
265 size_t new_input_len = src->length - n;
267 while (src->count > 0) {
268 grpc_slice slice = grpc_slice_buffer_take_first(src);
269 size_t slice_len = GRPC_SLICE_LENGTH(slice);
271 grpc_slice_buffer_add(dst, slice);
273 } else if (n == slice_len) {
274 grpc_slice_buffer_add(dst, slice);
276 } else if (incref) { /* n < slice_len */
277 grpc_slice_buffer_undo_take_first(
278 src, grpc_slice_split_tail_maybe_ref(&slice, n, GRPC_SLICE_REF_BOTH));
279 GPR_ASSERT(GRPC_SLICE_LENGTH(slice) == n);
280 grpc_slice_buffer_add(dst, slice);
282 } else { /* n < slice_len */
283 grpc_slice_buffer_undo_take_first(
284 src, grpc_slice_split_tail_maybe_ref(&slice, n, GRPC_SLICE_REF_TAIL));
285 GPR_ASSERT(GRPC_SLICE_LENGTH(slice) == n);
286 grpc_slice_buffer_add_indexed(dst, slice);
290 GPR_ASSERT(dst->length == output_len);
291 GPR_ASSERT(src->length == new_input_len);
292 GPR_ASSERT(src->count > 0);
295 void grpc_slice_buffer_move_first(grpc_slice_buffer* src, size_t n,
296 grpc_slice_buffer* dst) {
297 slice_buffer_move_first_maybe_ref(src, n, dst, true);
300 void grpc_slice_buffer_move_first_no_ref(grpc_slice_buffer* src, size_t n,
301 grpc_slice_buffer* dst) {
302 slice_buffer_move_first_maybe_ref(src, n, dst, false);
305 void grpc_slice_buffer_move_first_into_buffer(grpc_slice_buffer* src, size_t n,
307 char* dstp = static_cast<char*>(dst);
308 GPR_ASSERT(src->length >= n);
311 grpc_slice slice = grpc_slice_buffer_take_first(src);
312 size_t slice_len = GRPC_SLICE_LENGTH(slice);
314 memcpy(dstp, GRPC_SLICE_START_PTR(slice), n);
315 grpc_slice_buffer_undo_take_first(
316 src, grpc_slice_sub_no_ref(slice, n, slice_len));
318 } else if (slice_len == n) {
319 memcpy(dstp, GRPC_SLICE_START_PTR(slice), n);
320 grpc_slice_unref_internal(slice);
323 memcpy(dstp, GRPC_SLICE_START_PTR(slice), slice_len);
326 grpc_slice_unref_internal(slice);
331 void grpc_slice_buffer_trim_end(grpc_slice_buffer* sb, size_t n,
332 grpc_slice_buffer* garbage) {
333 GPR_ASSERT(n <= sb->length);
336 size_t idx = sb->count - 1;
337 grpc_slice slice = sb->slices[idx];
338 size_t slice_len = GRPC_SLICE_LENGTH(slice);
340 sb->slices[idx] = grpc_slice_split_head(&slice, slice_len - n);
342 grpc_slice_buffer_add_indexed(garbage, slice);
344 grpc_slice_unref_internal(slice);
347 } else if (slice_len == n) {
349 grpc_slice_buffer_add_indexed(garbage, slice);
351 grpc_slice_unref_internal(slice);
357 grpc_slice_buffer_add_indexed(garbage, slice);
359 grpc_slice_unref_internal(slice);
367 grpc_slice grpc_slice_buffer_take_first(grpc_slice_buffer* sb) {
369 GPR_ASSERT(sb->count > 0);
370 slice = sb->slices[0];
373 sb->length -= GRPC_SLICE_LENGTH(slice);
378 void grpc_slice_buffer_undo_take_first(grpc_slice_buffer* sb,
381 sb->slices[0] = slice;
383 sb->length += GRPC_SLICE_LENGTH(slice);