1 /*
2 *
3 * Copyright 2015 gRPC authors.
4 *
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
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
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.
16 *
17 */
18
19 #include <grpc/support/port_platform.h>
20
21 #include "src/core/lib/slice/slice_internal.h"
22
23 #include <grpc/slice.h>
24 #include <grpc/support/alloc.h>
25 #include <grpc/support/log.h>
26
27 #include <string.h>
28
29 #include "src/core/lib/gprpp/memory.h"
30 #include "src/core/lib/gprpp/ref_counted.h"
31 #include "src/core/lib/iomgr/exec_ctx.h"
32
grpc_slice_to_c_string(grpc_slice slice)33 char* grpc_slice_to_c_string(grpc_slice slice) {
34 char* out = static_cast<char*>(gpr_malloc(GRPC_SLICE_LENGTH(slice) + 1));
35 memcpy(out, GRPC_SLICE_START_PTR(slice), GRPC_SLICE_LENGTH(slice));
36 out[GRPC_SLICE_LENGTH(slice)] = 0;
37 return out;
38 }
39
grpc_empty_slice(void)40 grpc_slice grpc_empty_slice(void) { return grpc_core::UnmanagedMemorySlice(); }
41
grpc_slice_copy(grpc_slice s)42 grpc_slice grpc_slice_copy(grpc_slice s) {
43 grpc_slice out = GRPC_SLICE_MALLOC(GRPC_SLICE_LENGTH(s));
44 memcpy(GRPC_SLICE_START_PTR(out), GRPC_SLICE_START_PTR(s),
45 GRPC_SLICE_LENGTH(s));
46 return out;
47 }
48
49 /* Public API */
grpc_slice_ref(grpc_slice slice)50 grpc_slice grpc_slice_ref(grpc_slice slice) {
51 return grpc_slice_ref_internal(slice);
52 }
53
54 /* Public API */
grpc_slice_unref(grpc_slice slice)55 void grpc_slice_unref(grpc_slice slice) {
56 if (grpc_core::ExecCtx::Get() == nullptr) {
57 grpc_core::ExecCtx exec_ctx;
58 grpc_slice_unref_internal(slice);
59 } else {
60 grpc_slice_unref_internal(slice);
61 }
62 }
63
64 namespace grpc_core {
65
66 /* grpc_slice_from_static_string support structure - a refcount that does
67 nothing */
68 grpc_slice_refcount kNoopRefcount(grpc_slice_refcount::Type::NOP);
69 static_assert(std::is_trivially_destructible<decltype(kNoopRefcount)>::value,
70 "kNoopRefcount must be trivially destructible.");
71
72 /* grpc_slice_new support structures - we create a refcount object extended
73 with the user provided data pointer & destroy function */
74 class NewSliceRefcount {
75 public:
Destroy(void * arg)76 static void Destroy(void* arg) { delete static_cast<NewSliceRefcount*>(arg); }
77
NewSliceRefcount(void (* destroy)(void *),void * user_data)78 NewSliceRefcount(void (*destroy)(void*), void* user_data)
79 : base_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this,
80 &base_),
81 user_destroy_(destroy),
82 user_data_(user_data) {}
~NewSliceRefcount()83 ~NewSliceRefcount() { user_destroy_(user_data_); }
84
base_refcount()85 grpc_slice_refcount* base_refcount() { return &base_; }
86
87 private:
88 grpc_slice_refcount base_;
89 RefCount refs_;
90 void (*user_destroy_)(void*);
91 void* user_data_;
92 };
93
94 } // namespace grpc_core
95
grpc_slice_memory_usage(grpc_slice s)96 size_t grpc_slice_memory_usage(grpc_slice s) {
97 if (s.refcount == nullptr || s.refcount == &grpc_core::kNoopRefcount) {
98 return 0;
99 } else {
100 return s.data.refcounted.length;
101 }
102 }
103
grpc_slice_from_static_buffer(const void * s,size_t len)104 grpc_slice grpc_slice_from_static_buffer(const void* s, size_t len) {
105 return grpc_core::ExternallyManagedSlice(s, len);
106 }
107
grpc_slice_from_static_string(const char * s)108 grpc_slice grpc_slice_from_static_string(const char* s) {
109 return grpc_core::ExternallyManagedSlice(s, strlen(s));
110 }
111
grpc_slice_new_with_user_data(void * p,size_t len,void (* destroy)(void *),void * user_data)112 grpc_slice grpc_slice_new_with_user_data(void* p, size_t len,
113 void (*destroy)(void*),
114 void* user_data) {
115 grpc_slice slice;
116 slice.refcount =
117 (new grpc_core::NewSliceRefcount(destroy, user_data))->base_refcount();
118 slice.data.refcounted.bytes = static_cast<uint8_t*>(p);
119 slice.data.refcounted.length = len;
120 return slice;
121 }
122
grpc_slice_new(void * p,size_t len,void (* destroy)(void *))123 grpc_slice grpc_slice_new(void* p, size_t len, void (*destroy)(void*)) {
124 /* Pass "p" to *destroy when the slice is no longer needed. */
125 return grpc_slice_new_with_user_data(p, len, destroy, p);
126 }
127
128 namespace grpc_core {
129 /* grpc_slice_new_with_len support structures - we create a refcount object
130 extended with the user provided data pointer & destroy function */
131 class NewWithLenSliceRefcount {
132 public:
Destroy(void * arg)133 static void Destroy(void* arg) {
134 delete static_cast<NewWithLenSliceRefcount*>(arg);
135 }
136
NewWithLenSliceRefcount(void (* destroy)(void *,size_t),void * user_data,size_t user_length)137 NewWithLenSliceRefcount(void (*destroy)(void*, size_t), void* user_data,
138 size_t user_length)
139 : base_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this,
140 &base_),
141 user_data_(user_data),
142 user_length_(user_length),
143 user_destroy_(destroy) {}
~NewWithLenSliceRefcount()144 ~NewWithLenSliceRefcount() { user_destroy_(user_data_, user_length_); }
145
base_refcount()146 grpc_slice_refcount* base_refcount() { return &base_; }
147
148 private:
149 grpc_slice_refcount base_;
150 RefCount refs_;
151 void* user_data_;
152 size_t user_length_;
153 void (*user_destroy_)(void*, size_t);
154 };
155
156 /** grpc_slice_from_moved_(string|buffer) ref count .*/
157 class MovedStringSliceRefCount {
158 public:
MovedStringSliceRefCount(grpc_core::UniquePtr<char> && str)159 explicit MovedStringSliceRefCount(grpc_core::UniquePtr<char>&& str)
160 : base_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this,
161 &base_),
162 str_(std::move(str)) {}
163
base_refcount()164 grpc_slice_refcount* base_refcount() { return &base_; }
165
166 private:
Destroy(void * arg)167 static void Destroy(void* arg) {
168 delete static_cast<MovedStringSliceRefCount*>(arg);
169 }
170
171 grpc_slice_refcount base_;
172 grpc_core::RefCount refs_;
173 grpc_core::UniquePtr<char> str_;
174 };
175
176 // grpc_slice_from_cpp_string() ref count.
177 class MovedCppStringSliceRefCount {
178 public:
MovedCppStringSliceRefCount(std::string && str)179 explicit MovedCppStringSliceRefCount(std::string&& str)
180 : base_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this,
181 &base_),
182 str_(std::move(str)) {}
183
base_refcount()184 grpc_slice_refcount* base_refcount() { return &base_; }
185
186 private:
Destroy(void * arg)187 static void Destroy(void* arg) {
188 delete static_cast<MovedCppStringSliceRefCount*>(arg);
189 }
190
191 grpc_slice_refcount base_;
192 grpc_core::RefCount refs_;
193 std::string str_;
194 };
195
196 } // namespace grpc_core
197
grpc_slice_new_with_len(void * p,size_t len,void (* destroy)(void *,size_t))198 grpc_slice grpc_slice_new_with_len(void* p, size_t len,
199 void (*destroy)(void*, size_t)) {
200 grpc_slice slice;
201 slice.refcount = (new grpc_core::NewWithLenSliceRefcount(destroy, p, len))
202 ->base_refcount();
203 slice.data.refcounted.bytes = static_cast<uint8_t*>(p);
204 slice.data.refcounted.length = len;
205 return slice;
206 }
207
UnmanagedMemorySlice(const char * source,size_t length)208 grpc_core::UnmanagedMemorySlice::UnmanagedMemorySlice(const char* source,
209 size_t length) {
210 if (length <= sizeof(data.inlined.bytes)) {
211 refcount = nullptr;
212 data.inlined.length = static_cast<uint8_t>(length);
213 } else {
214 HeapInit(length);
215 }
216 if (length > 0) {
217 memcpy(GRPC_SLICE_START_PTR(*this), source, length);
218 }
219 }
220
UnmanagedMemorySlice(const char * source)221 grpc_core::UnmanagedMemorySlice::UnmanagedMemorySlice(const char* source)
222 : grpc_core::UnmanagedMemorySlice::UnmanagedMemorySlice(source,
223 strlen(source)) {}
224
grpc_slice_from_copied_buffer(const char * source,size_t length)225 grpc_slice grpc_slice_from_copied_buffer(const char* source, size_t length) {
226 return grpc_core::UnmanagedMemorySlice(source, length);
227 }
228
grpc_slice_from_copied_string(const char * source)229 grpc_slice grpc_slice_from_copied_string(const char* source) {
230 return grpc_core::UnmanagedMemorySlice(source, strlen(source));
231 }
232
grpc_slice_from_moved_buffer(grpc_core::UniquePtr<char> p,size_t len)233 grpc_slice grpc_slice_from_moved_buffer(grpc_core::UniquePtr<char> p,
234 size_t len) {
235 uint8_t* ptr = reinterpret_cast<uint8_t*>(p.get());
236 grpc_slice slice;
237 if (len <= sizeof(slice.data.inlined.bytes)) {
238 slice.refcount = nullptr;
239 slice.data.inlined.length = len;
240 memcpy(GRPC_SLICE_START_PTR(slice), ptr, len);
241 } else {
242 slice.refcount = (new grpc_core::MovedStringSliceRefCount(std::move(p)))
243 ->base_refcount();
244 slice.data.refcounted.bytes = ptr;
245 slice.data.refcounted.length = len;
246 }
247 return slice;
248 }
249
grpc_slice_from_moved_string(grpc_core::UniquePtr<char> p)250 grpc_slice grpc_slice_from_moved_string(grpc_core::UniquePtr<char> p) {
251 const size_t len = strlen(p.get());
252 return grpc_slice_from_moved_buffer(std::move(p), len);
253 }
254
grpc_slice_from_cpp_string(std::string str)255 grpc_slice grpc_slice_from_cpp_string(std::string str) {
256 grpc_slice slice;
257 if (str.size() <= sizeof(slice.data.inlined.bytes)) {
258 slice.refcount = nullptr;
259 slice.data.inlined.length = str.size();
260 memcpy(GRPC_SLICE_START_PTR(slice), str.data(), str.size());
261 } else {
262 slice.data.refcounted.bytes =
263 reinterpret_cast<uint8_t*>(const_cast<char*>(str.data()));
264 slice.data.refcounted.length = str.size();
265 slice.refcount =
266 (new grpc_core::MovedCppStringSliceRefCount(std::move(str)))
267 ->base_refcount();
268 }
269 return slice;
270 }
271
272 namespace {
273
274 class MallocRefCount {
275 public:
Destroy(void * arg)276 static void Destroy(void* arg) {
277 MallocRefCount* r = static_cast<MallocRefCount*>(arg);
278 r->~MallocRefCount();
279 gpr_free(r);
280 }
281
MallocRefCount()282 MallocRefCount()
283 : base_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this,
284 &base_) {}
285 ~MallocRefCount() = default;
286
base_refcount()287 grpc_slice_refcount* base_refcount() { return &base_; }
288
289 private:
290 grpc_slice_refcount base_;
291 grpc_core::RefCount refs_;
292 };
293
294 } // namespace
295
grpc_slice_malloc_large(size_t length)296 grpc_slice grpc_slice_malloc_large(size_t length) {
297 return grpc_core::UnmanagedMemorySlice(
298 length, grpc_core::UnmanagedMemorySlice::ForceHeapAllocation());
299 }
300
HeapInit(size_t length)301 void grpc_core::UnmanagedMemorySlice::HeapInit(size_t length) {
302 /* Memory layout used by the slice created here:
303
304 +-----------+----------------------------------------------------------+
305 | refcount | bytes |
306 +-----------+----------------------------------------------------------+
307
308 refcount is a malloc_refcount
309 bytes is an array of bytes of the requested length
310 Both parts are placed in the same allocation returned from gpr_malloc */
311 auto* rc =
312 static_cast<MallocRefCount*>(gpr_malloc(sizeof(MallocRefCount) + length));
313
314 /* Initial refcount on rc is 1 - and it's up to the caller to release
315 this reference. */
316 new (rc) MallocRefCount();
317
318 /* Build up the slice to be returned. */
319 /* The slices refcount points back to the allocated block. */
320 refcount = rc->base_refcount();
321 /* The data bytes are placed immediately after the refcount struct */
322 data.refcounted.bytes = reinterpret_cast<uint8_t*>(rc + 1);
323 /* And the length of the block is set to the requested length */
324 data.refcounted.length = length;
325 }
326
grpc_slice_malloc(size_t length)327 grpc_slice grpc_slice_malloc(size_t length) {
328 return grpc_core::UnmanagedMemorySlice(length);
329 }
330
UnmanagedMemorySlice(size_t length)331 grpc_core::UnmanagedMemorySlice::UnmanagedMemorySlice(size_t length) {
332 if (length > sizeof(data.inlined.bytes)) {
333 HeapInit(length);
334 } else {
335 /* small slice: just inline the data */
336 refcount = nullptr;
337 data.inlined.length = static_cast<uint8_t>(length);
338 }
339 }
340
341 template <typename Slice>
sub_no_ref(const Slice & source,size_t begin,size_t end)342 static Slice sub_no_ref(const Slice& source, size_t begin, size_t end) {
343 Slice subset;
344
345 GPR_ASSERT(end >= begin);
346
347 if (source.refcount) {
348 /* Enforce preconditions */
349 GPR_ASSERT(source.data.refcounted.length >= end);
350
351 /* Build the result */
352 subset.refcount = source.refcount->sub_refcount();
353 /* Point into the source array */
354 subset.data.refcounted.bytes = source.data.refcounted.bytes + begin;
355 subset.data.refcounted.length = end - begin;
356 } else {
357 /* Enforce preconditions */
358 GPR_ASSERT(source.data.inlined.length >= end);
359 subset.refcount = nullptr;
360 subset.data.inlined.length = static_cast<uint8_t>(end - begin);
361 memcpy(subset.data.inlined.bytes, source.data.inlined.bytes + begin,
362 end - begin);
363 }
364 return subset;
365 }
366
grpc_slice_sub_no_ref(grpc_slice source,size_t begin,size_t end)367 grpc_slice grpc_slice_sub_no_ref(grpc_slice source, size_t begin, size_t end) {
368 return sub_no_ref(source, begin, end);
369 }
370
grpc_slice_sub_no_ref(const grpc_core::UnmanagedMemorySlice & source,size_t begin,size_t end)371 grpc_core::UnmanagedMemorySlice grpc_slice_sub_no_ref(
372 const grpc_core::UnmanagedMemorySlice& source, size_t begin, size_t end) {
373 return sub_no_ref(source, begin, end);
374 }
375
grpc_slice_sub(grpc_slice source,size_t begin,size_t end)376 grpc_slice grpc_slice_sub(grpc_slice source, size_t begin, size_t end) {
377 grpc_slice subset;
378
379 if (end - begin <= sizeof(subset.data.inlined.bytes)) {
380 subset.refcount = nullptr;
381 subset.data.inlined.length = static_cast<uint8_t>(end - begin);
382 memcpy(subset.data.inlined.bytes, GRPC_SLICE_START_PTR(source) + begin,
383 end - begin);
384 } else {
385 subset = grpc_slice_sub_no_ref(source, begin, end);
386 /* Bump the refcount */
387 subset.refcount->Ref();
388 }
389 return subset;
390 }
391
grpc_slice_split_tail_maybe_ref(grpc_slice * source,size_t split,grpc_slice_ref_whom ref_whom)392 grpc_slice grpc_slice_split_tail_maybe_ref(grpc_slice* source, size_t split,
393 grpc_slice_ref_whom ref_whom) {
394 grpc_slice tail;
395
396 if (source->refcount == nullptr) {
397 /* inlined data, copy it out */
398 GPR_ASSERT(source->data.inlined.length >= split);
399 tail.refcount = nullptr;
400 tail.data.inlined.length =
401 static_cast<uint8_t>(source->data.inlined.length - split);
402 memcpy(tail.data.inlined.bytes, source->data.inlined.bytes + split,
403 tail.data.inlined.length);
404 source->data.inlined.length = static_cast<uint8_t>(split);
405 } else {
406 size_t tail_length = source->data.refcounted.length - split;
407 GPR_ASSERT(source->data.refcounted.length >= split);
408 if (tail_length < sizeof(tail.data.inlined.bytes) &&
409 ref_whom != GRPC_SLICE_REF_TAIL) {
410 /* Copy out the bytes - it'll be cheaper than refcounting */
411 tail.refcount = nullptr;
412 tail.data.inlined.length = static_cast<uint8_t>(tail_length);
413 memcpy(tail.data.inlined.bytes, source->data.refcounted.bytes + split,
414 tail_length);
415 source->refcount = source->refcount->sub_refcount();
416 } else {
417 /* Build the result */
418 switch (ref_whom) {
419 case GRPC_SLICE_REF_TAIL:
420 tail.refcount = source->refcount->sub_refcount();
421 source->refcount = &grpc_core::kNoopRefcount;
422 break;
423 case GRPC_SLICE_REF_HEAD:
424 tail.refcount = &grpc_core::kNoopRefcount;
425 source->refcount = source->refcount->sub_refcount();
426 break;
427 case GRPC_SLICE_REF_BOTH:
428 tail.refcount = source->refcount->sub_refcount();
429 source->refcount = source->refcount->sub_refcount();
430 /* Bump the refcount */
431 tail.refcount->Ref();
432 break;
433 }
434 /* Point into the source array */
435 tail.data.refcounted.bytes = source->data.refcounted.bytes + split;
436 tail.data.refcounted.length = tail_length;
437 }
438 source->data.refcounted.length = split;
439 }
440
441 return tail;
442 }
443
grpc_slice_split_tail(grpc_slice * source,size_t split)444 grpc_slice grpc_slice_split_tail(grpc_slice* source, size_t split) {
445 return grpc_slice_split_tail_maybe_ref(source, split, GRPC_SLICE_REF_BOTH);
446 }
447
grpc_slice_split_head(grpc_slice * source,size_t split)448 grpc_slice grpc_slice_split_head(grpc_slice* source, size_t split) {
449 grpc_slice head;
450
451 if (source->refcount == nullptr) {
452 GPR_ASSERT(source->data.inlined.length >= split);
453
454 head.refcount = nullptr;
455 head.data.inlined.length = static_cast<uint8_t>(split);
456 memcpy(head.data.inlined.bytes, source->data.inlined.bytes, split);
457 source->data.inlined.length =
458 static_cast<uint8_t>(source->data.inlined.length - split);
459 memmove(source->data.inlined.bytes, source->data.inlined.bytes + split,
460 source->data.inlined.length);
461 } else if (split < sizeof(head.data.inlined.bytes)) {
462 GPR_ASSERT(source->data.refcounted.length >= split);
463
464 head.refcount = nullptr;
465 head.data.inlined.length = static_cast<uint8_t>(split);
466 memcpy(head.data.inlined.bytes, source->data.refcounted.bytes, split);
467 source->refcount = source->refcount->sub_refcount();
468 source->data.refcounted.bytes += split;
469 source->data.refcounted.length -= split;
470 } else {
471 GPR_ASSERT(source->data.refcounted.length >= split);
472
473 /* Build the result */
474 head.refcount = source->refcount->sub_refcount();
475 /* Bump the refcount */
476 head.refcount->Ref();
477 /* Point into the source array */
478 head.data.refcounted.bytes = source->data.refcounted.bytes;
479 head.data.refcounted.length = split;
480 source->refcount = source->refcount->sub_refcount();
481 source->data.refcounted.bytes += split;
482 source->data.refcounted.length -= split;
483 }
484
485 return head;
486 }
487
grpc_slice_default_eq_impl(grpc_slice a,grpc_slice b)488 int grpc_slice_default_eq_impl(grpc_slice a, grpc_slice b) {
489 if (GRPC_SLICE_LENGTH(a) != GRPC_SLICE_LENGTH(b)) return false;
490 if (GRPC_SLICE_LENGTH(a) == 0) return true;
491 return 0 == memcmp(GRPC_SLICE_START_PTR(a), GRPC_SLICE_START_PTR(b),
492 GRPC_SLICE_LENGTH(a));
493 }
494
grpc_slice_eq(grpc_slice a,grpc_slice b)495 int grpc_slice_eq(grpc_slice a, grpc_slice b) {
496 if (a.refcount && b.refcount &&
497 a.refcount->GetType() == b.refcount->GetType()) {
498 return a.refcount->Eq(a, b);
499 }
500 return grpc_slice_default_eq_impl(a, b);
501 }
502
grpc_slice_differs_refcounted(const grpc_slice & a,const grpc_slice & b_not_inline)503 int grpc_slice_differs_refcounted(const grpc_slice& a,
504 const grpc_slice& b_not_inline) {
505 size_t a_len;
506 const uint8_t* a_ptr;
507 if (a.refcount) {
508 a_len = a.data.refcounted.length;
509 a_ptr = a.data.refcounted.bytes;
510 } else {
511 a_len = a.data.inlined.length;
512 a_ptr = &a.data.inlined.bytes[0];
513 }
514 if (a_len != b_not_inline.data.refcounted.length) {
515 return true;
516 }
517 if (a_len == 0) {
518 return false;
519 }
520 // This check *must* occur after the a_len == 0 check
521 // to retain compatibility with grpc_slice_eq.
522 if (a_ptr == nullptr) {
523 return true;
524 }
525 return memcmp(a_ptr, b_not_inline.data.refcounted.bytes, a_len);
526 }
527
grpc_slice_cmp(grpc_slice a,grpc_slice b)528 int grpc_slice_cmp(grpc_slice a, grpc_slice b) {
529 int d = static_cast<int>(GRPC_SLICE_LENGTH(a) - GRPC_SLICE_LENGTH(b));
530 if (d != 0) return d;
531 return memcmp(GRPC_SLICE_START_PTR(a), GRPC_SLICE_START_PTR(b),
532 GRPC_SLICE_LENGTH(a));
533 }
534
grpc_slice_str_cmp(grpc_slice a,const char * b)535 int grpc_slice_str_cmp(grpc_slice a, const char* b) {
536 size_t b_length = strlen(b);
537 int d = static_cast<int>(GRPC_SLICE_LENGTH(a) - b_length);
538 if (d != 0) return d;
539 return memcmp(GRPC_SLICE_START_PTR(a), b, b_length);
540 }
541
grpc_slice_is_equivalent(grpc_slice a,grpc_slice b)542 int grpc_slice_is_equivalent(grpc_slice a, grpc_slice b) {
543 if (a.refcount == nullptr || b.refcount == nullptr) {
544 return grpc_slice_eq(a, b);
545 }
546 return a.data.refcounted.length == b.data.refcounted.length &&
547 a.data.refcounted.bytes == b.data.refcounted.bytes;
548 }
549
grpc_slice_buf_start_eq(grpc_slice a,const void * b,size_t len)550 int grpc_slice_buf_start_eq(grpc_slice a, const void* b, size_t len) {
551 if (GRPC_SLICE_LENGTH(a) < len) return 0;
552 return 0 == memcmp(GRPC_SLICE_START_PTR(a), b, len);
553 }
554
grpc_slice_rchr(grpc_slice s,char c)555 int grpc_slice_rchr(grpc_slice s, char c) {
556 const char* b = reinterpret_cast<const char*> GRPC_SLICE_START_PTR(s);
557 int i;
558 for (i = static_cast<int> GRPC_SLICE_LENGTH(s) - 1; i != -1 && b[i] != c;
559 i--) {
560 }
561 return i;
562 }
563
grpc_slice_chr(grpc_slice s,char c)564 int grpc_slice_chr(grpc_slice s, char c) {
565 const char* b = reinterpret_cast<const char*> GRPC_SLICE_START_PTR(s);
566 const char* p = static_cast<const char*>(memchr(b, c, GRPC_SLICE_LENGTH(s)));
567 return p == nullptr ? -1 : static_cast<int>(p - b);
568 }
569
grpc_slice_slice(grpc_slice haystack,grpc_slice needle)570 int grpc_slice_slice(grpc_slice haystack, grpc_slice needle) {
571 size_t haystack_len = GRPC_SLICE_LENGTH(haystack);
572 const uint8_t* haystack_bytes = GRPC_SLICE_START_PTR(haystack);
573 size_t needle_len = GRPC_SLICE_LENGTH(needle);
574 const uint8_t* needle_bytes = GRPC_SLICE_START_PTR(needle);
575
576 if (haystack_len == 0 || needle_len == 0) return -1;
577 if (haystack_len < needle_len) return -1;
578 if (haystack_len == needle_len) {
579 return grpc_slice_eq(haystack, needle) ? 0 : -1;
580 }
581 if (needle_len == 1) {
582 return grpc_slice_chr(haystack, static_cast<char>(*needle_bytes));
583 }
584
585 const uint8_t* last = haystack_bytes + haystack_len - needle_len;
586 for (const uint8_t* cur = haystack_bytes; cur != last; ++cur) {
587 if (0 == memcmp(cur, needle_bytes, needle_len)) {
588 return static_cast<int>(cur - haystack_bytes);
589 }
590 }
591 return -1;
592 }
593
grpc_slice_dup(grpc_slice a)594 grpc_slice grpc_slice_dup(grpc_slice a) {
595 grpc_slice copy = GRPC_SLICE_MALLOC(GRPC_SLICE_LENGTH(a));
596 memcpy(GRPC_SLICE_START_PTR(copy), GRPC_SLICE_START_PTR(a),
597 GRPC_SLICE_LENGTH(a));
598 return copy;
599 }
600