• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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