Line data Source code
1 : /*
2 : *
3 : * Copyright 2015, Google Inc.
4 : * All rights reserved.
5 : *
6 : * Redistribution and use in source and binary forms, with or without
7 : * modification, are permitted provided that the following conditions are
8 : * met:
9 : *
10 : * * Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : * * Redistributions in binary form must reproduce the above
13 : * copyright notice, this list of conditions and the following disclaimer
14 : * in the documentation and/or other materials provided with the
15 : * distribution.
16 : * * Neither the name of Google Inc. nor the names of its
17 : * contributors may be used to endorse or promote products derived from
18 : * this software without specific prior written permission.
19 : *
20 : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 : * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 : * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 : * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 : * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 : * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 : * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 : * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 : *
32 : */
33 :
34 : #include <grpc/support/port_platform.h>
35 : #include <grpc/support/slice_buffer.h>
36 :
37 : #include <string.h>
38 :
39 : #include <grpc/support/alloc.h>
40 : #include <grpc/support/log.h>
41 : #include <grpc/support/useful.h>
42 :
43 : /* grow a buffer; requires GRPC_SLICE_BUFFER_INLINE_ELEMENTS > 1 */
44 : #define GROW(x) (3 * (x) / 2)
45 :
46 67251399 : static void maybe_embiggen(gpr_slice_buffer *sb) {
47 67251399 : if (sb->count == sb->capacity) {
48 25666 : sb->capacity = GROW(sb->capacity);
49 25666 : GPR_ASSERT(sb->capacity > sb->count);
50 25666 : if (sb->slices == sb->inlined) {
51 6495 : sb->slices = gpr_malloc(sb->capacity * sizeof(gpr_slice));
52 6495 : memcpy(sb->slices, sb->inlined, sb->count * sizeof(gpr_slice));
53 : } else {
54 19171 : sb->slices = gpr_realloc(sb->slices, sb->capacity * sizeof(gpr_slice));
55 : }
56 : }
57 67251399 : }
58 :
59 24143371 : void gpr_slice_buffer_init(gpr_slice_buffer *sb) {
60 24143371 : sb->count = 0;
61 24143371 : sb->length = 0;
62 24143371 : sb->capacity = GRPC_SLICE_BUFFER_INLINE_ELEMENTS;
63 24143371 : sb->slices = sb->inlined;
64 24143371 : }
65 :
66 20437293 : void gpr_slice_buffer_destroy(gpr_slice_buffer *sb) {
67 20437293 : gpr_slice_buffer_reset_and_unref(sb);
68 20440421 : if (sb->slices != sb->inlined) {
69 6426 : gpr_free(sb->slices);
70 : }
71 20440421 : }
72 :
73 42211813 : gpr_uint8 *gpr_slice_buffer_tiny_add(gpr_slice_buffer *sb, size_t n) {
74 : gpr_slice *back;
75 : gpr_uint8 *out;
76 :
77 42211813 : sb->length += n;
78 :
79 42211813 : if (sb->count == 0) goto add_new;
80 42211813 : back = &sb->slices[sb->count - 1];
81 42211813 : if (back->refcount) goto add_new;
82 36166249 : if ((back->data.inlined.length + n) > sizeof(back->data.inlined.bytes))
83 2154066 : goto add_new;
84 34012154 : out = back->data.inlined.bytes + back->data.inlined.length;
85 34012154 : back->data.inlined.length = (gpr_uint8)(back->data.inlined.length + n);
86 34012154 : return out;
87 :
88 : add_new:
89 8199659 : maybe_embiggen(sb);
90 8200101 : back = &sb->slices[sb->count];
91 8200101 : sb->count++;
92 8200101 : back->refcount = NULL;
93 8200101 : back->data.inlined.length = (gpr_uint8)n;
94 8200101 : return back->data.inlined.bytes;
95 : }
96 :
97 54853247 : size_t gpr_slice_buffer_add_indexed(gpr_slice_buffer *sb, gpr_slice s) {
98 54853247 : size_t out = sb->count;
99 54853247 : maybe_embiggen(sb);
100 54876271 : sb->slices[out] = s;
101 54876271 : sb->length += GPR_SLICE_LENGTH(s);
102 54876271 : sb->count = out + 1;
103 54876271 : return out;
104 : }
105 :
106 39654691 : void gpr_slice_buffer_add(gpr_slice_buffer *sb, gpr_slice s) {
107 39654691 : size_t n = sb->count;
108 : /* if both the last slice in the slice buffer and the slice being added
109 : are inlined (that is, that they carry their data inside the slice data
110 : structure), and the back slice is not full, then concatenate directly
111 : into the back slice, preventing many small slices being passed into
112 : writes */
113 39654691 : if (!s.refcount && n) {
114 18381557 : gpr_slice *back = &sb->slices[n - 1];
115 18381557 : if (!back->refcount && back->data.inlined.length < GPR_SLICE_INLINED_SIZE) {
116 18037018 : if (s.data.inlined.length + back->data.inlined.length <=
117 : GPR_SLICE_INLINED_SIZE) {
118 13791451 : memcpy(back->data.inlined.bytes + back->data.inlined.length,
119 13791183 : s.data.inlined.bytes, s.data.inlined.length);
120 13791451 : back->data.inlined.length =
121 13791451 : (gpr_uint8)(back->data.inlined.length + s.data.inlined.length);
122 : } else {
123 4245567 : size_t cp1 = GPR_SLICE_INLINED_SIZE - back->data.inlined.length;
124 4245567 : memcpy(back->data.inlined.bytes + back->data.inlined.length,
125 : s.data.inlined.bytes, cp1);
126 4245567 : back->data.inlined.length = GPR_SLICE_INLINED_SIZE;
127 4245567 : maybe_embiggen(sb);
128 4244797 : back = &sb->slices[n];
129 4244797 : sb->count = n + 1;
130 4244797 : back->refcount = NULL;
131 4244797 : back->data.inlined.length = (gpr_uint8)(s.data.inlined.length - cp1);
132 4244797 : memcpy(back->data.inlined.bytes, s.data.inlined.bytes + cp1,
133 4244652 : s.data.inlined.length - cp1);
134 : }
135 18036248 : sb->length += s.data.inlined.length;
136 57755738 : return; /* early out */
137 : }
138 : }
139 21617673 : gpr_slice_buffer_add_indexed(sb, s);
140 : }
141 :
142 4361009 : void gpr_slice_buffer_addn(gpr_slice_buffer *sb, gpr_slice *s, size_t n) {
143 : size_t i;
144 8996607 : for (i = 0; i < n; i++) {
145 4633082 : gpr_slice_buffer_add(sb, s[i]);
146 : }
147 4363525 : }
148 :
149 26 : void gpr_slice_buffer_pop(gpr_slice_buffer *sb) {
150 26 : if (sb->count != 0) {
151 20 : size_t count = --sb->count;
152 20 : sb->length -= GPR_SLICE_LENGTH(sb->slices[count]);
153 : }
154 26 : }
155 :
156 41131557 : void gpr_slice_buffer_reset_and_unref(gpr_slice_buffer *sb) {
157 : size_t i;
158 :
159 99017351 : for (i = 0; i < sb->count; i++) {
160 57867882 : gpr_slice_unref(sb->slices[i]);
161 : }
162 :
163 41149469 : sb->count = 0;
164 41149469 : sb->length = 0;
165 41149469 : }
166 :
167 42469065 : void gpr_slice_buffer_swap(gpr_slice_buffer *a, gpr_slice_buffer *b) {
168 42469065 : GPR_SWAP(size_t, a->count, b->count);
169 42469065 : GPR_SWAP(size_t, a->capacity, b->capacity);
170 42469065 : GPR_SWAP(size_t, a->length, b->length);
171 :
172 42469065 : if (a->slices == a->inlined) {
173 19411748 : if (b->slices == b->inlined) {
174 : /* swap contents of inlined buffer */
175 : gpr_slice temp[GRPC_SLICE_BUFFER_INLINE_ELEMENTS];
176 8719446 : memcpy(temp, a->slices, b->count * sizeof(gpr_slice));
177 8719446 : memcpy(a->slices, b->slices, a->count * sizeof(gpr_slice));
178 8719446 : memcpy(b->slices, temp, b->count * sizeof(gpr_slice));
179 : } else {
180 : /* a is inlined, b is not - copy a inlined into b, fix pointers */
181 10692302 : a->slices = b->slices;
182 10692302 : b->slices = b->inlined;
183 10692302 : memcpy(b->slices, a->inlined, b->count * sizeof(gpr_slice));
184 : }
185 23057317 : } else if (b->slices == b->inlined) {
186 : /* b is inlined, a is not - copy b inlined int a, fix pointers */
187 10685116 : b->slices = a->slices;
188 10685116 : a->slices = a->inlined;
189 10685116 : memcpy(a->slices, b->inlined, a->count * sizeof(gpr_slice));
190 : } else {
191 : /* no inlining: easy swap */
192 12372201 : GPR_SWAP(gpr_slice *, a->slices, b->slices);
193 : }
194 42469065 : }
195 :
196 11002858 : void gpr_slice_buffer_move_into(gpr_slice_buffer *src, gpr_slice_buffer *dst) {
197 : /* anything to move? */
198 11002858 : if (src->count == 0) {
199 7033190 : return;
200 : }
201 : /* anything in dst? */
202 3968998 : if (dst->count == 0) {
203 5556 : gpr_slice_buffer_swap(src, dst);
204 5557 : return;
205 : }
206 : /* both buffers have data - copy, and reset src */
207 3963442 : gpr_slice_buffer_addn(dst, src->slices, src->count);
208 3962996 : src->count = 0;
209 3962996 : src->length = 0;
210 : }
211 :
212 4489531 : void gpr_slice_buffer_move_first(gpr_slice_buffer *src, size_t n,
213 : gpr_slice_buffer *dst) {
214 : size_t src_idx;
215 4489531 : size_t output_len = dst->length + n;
216 4489531 : size_t new_input_len = src->length - n;
217 4489531 : GPR_ASSERT(src->length >= n);
218 4489531 : if (src->length == n) {
219 4485706 : gpr_slice_buffer_move_into(src, dst);
220 4485339 : return;
221 : }
222 3717 : src_idx = 0;
223 8896 : while (src_idx < src->capacity) {
224 5179 : gpr_slice slice = src->slices[src_idx];
225 5179 : size_t slice_len = GPR_SLICE_LENGTH(slice);
226 5179 : if (n > slice_len) {
227 1354 : gpr_slice_buffer_add(dst, slice);
228 1354 : n -= slice_len;
229 1354 : src_idx++;
230 3825 : } else if (n == slice_len) {
231 1 : gpr_slice_buffer_add(dst, slice);
232 1 : src_idx++;
233 3826 : break;
234 : } else { /* n < slice_len */
235 3824 : src->slices[src_idx] = gpr_slice_split_tail(&slice, n);
236 3824 : GPR_ASSERT(GPR_SLICE_LENGTH(slice) == n);
237 3824 : GPR_ASSERT(GPR_SLICE_LENGTH(src->slices[src_idx]) == slice_len - n);
238 3824 : gpr_slice_buffer_add(dst, slice);
239 3824 : break;
240 : }
241 : }
242 3825 : GPR_ASSERT(dst->length == output_len);
243 3825 : memmove(src->slices, src->slices + src_idx,
244 3825 : sizeof(gpr_slice) * (src->count - src_idx));
245 3825 : src->count -= src_idx;
246 3825 : src->length = new_input_len;
247 3825 : GPR_ASSERT(src->count > 0);
248 : }
249 :
250 2456567 : void gpr_slice_buffer_trim_end(gpr_slice_buffer *sb, size_t n,
251 : gpr_slice_buffer *garbage) {
252 2456567 : GPR_ASSERT(n <= sb->length);
253 2456567 : sb->length -= n;
254 : for (;;) {
255 4554623 : size_t idx = sb->count - 1;
256 4554623 : gpr_slice slice = sb->slices[idx];
257 4554623 : size_t slice_len = GPR_SLICE_LENGTH(slice);
258 4554623 : if (slice_len > n) {
259 2294889 : sb->slices[idx] = gpr_slice_split_head(&slice, slice_len - n);
260 2294904 : gpr_slice_buffer_add_indexed(garbage, slice);
261 2294904 : return;
262 2259734 : } else if (slice_len == n) {
263 161672 : gpr_slice_buffer_add_indexed(garbage, slice);
264 161672 : sb->count = idx;
265 161672 : return;
266 : } else {
267 2098062 : gpr_slice_buffer_add_indexed(garbage, slice);
268 2098056 : n -= slice_len;
269 2098056 : sb->count = idx;
270 : }
271 2098056 : }
272 : }
273 :
274 3192058 : gpr_slice gpr_slice_buffer_take_first(gpr_slice_buffer *sb) {
275 : gpr_slice slice;
276 3192058 : GPR_ASSERT(sb->count > 0);
277 3192058 : slice = sb->slices[0];
278 3192058 : memmove(&sb->slices[0], &sb->slices[1], (sb->count - 1) * sizeof(gpr_slice));
279 3192058 : sb->count--;
280 3192058 : sb->length -= GPR_SLICE_LENGTH(slice);
281 3192058 : return slice;
282 : }
|