• 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 "src/core/lib/slice/slice.h"
20 
21 #include <grpc/slice.h>
22 #include <grpc/support/alloc.h>
23 #include <grpc/support/port_platform.h>
24 #include <string.h>
25 
26 #include <new>
27 
28 #include "absl/log/check.h"
29 #include "src/core/lib/slice/slice_internal.h"
30 #include "src/core/lib/slice/slice_refcount.h"
31 #include "src/core/util/memory.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) {
41   return grpc_core::slice_detail::EmptySlice();
42 }
43 
grpc_slice_copy(grpc_slice s)44 grpc_slice grpc_slice_copy(grpc_slice s) {
45   grpc_slice out = GRPC_SLICE_MALLOC(GRPC_SLICE_LENGTH(s));
46   memcpy(GRPC_SLICE_START_PTR(out), GRPC_SLICE_START_PTR(s),
47          GRPC_SLICE_LENGTH(s));
48   return out;
49 }
50 
51 namespace grpc_core {
52 
53 // grpc_slice_new support structures - we create a refcount object extended
54 // with the user provided data pointer & destroy function
55 class NewSliceRefcount : public grpc_slice_refcount {
56  public:
NewSliceRefcount(void (* destroy)(void *),void * user_data)57   NewSliceRefcount(void (*destroy)(void*), void* user_data)
58       : grpc_slice_refcount(Destroy),
59         user_destroy_(destroy),
60         user_data_(user_data) {}
~NewSliceRefcount()61   ~NewSliceRefcount() { user_destroy_(user_data_); }
62 
63  private:
Destroy(grpc_slice_refcount * arg)64   static void Destroy(grpc_slice_refcount* arg) {
65     delete static_cast<NewSliceRefcount*>(arg);
66   }
67 
68   void (*user_destroy_)(void*);
69   void* user_data_;
70 };
71 
72 }  // namespace grpc_core
73 
grpc_slice_memory_usage(grpc_slice s)74 size_t grpc_slice_memory_usage(grpc_slice s) {
75   if (s.refcount == nullptr ||
76       s.refcount == grpc_slice_refcount::NoopRefcount()) {
77     return 0;
78   } else {
79     return s.data.refcounted.length;
80   }
81 }
82 
grpc_slice_from_static_buffer(const void * s,size_t len)83 grpc_slice grpc_slice_from_static_buffer(const void* s, size_t len) {
84   return grpc_core::StaticSlice::FromStaticBuffer(s, len).TakeCSlice();
85 }
86 
grpc_slice_from_static_string(const char * s)87 grpc_slice grpc_slice_from_static_string(const char* s) {
88   return grpc_core::StaticSlice::FromStaticString(s).TakeCSlice();
89 }
90 
grpc_slice_new_with_user_data(void * p,size_t len,void (* destroy)(void *),void * user_data)91 grpc_slice grpc_slice_new_with_user_data(void* p, size_t len,
92                                          void (*destroy)(void*),
93                                          void* user_data) {
94   grpc_slice slice;
95   slice.refcount = new grpc_core::NewSliceRefcount(destroy, user_data);
96   slice.data.refcounted.bytes = static_cast<uint8_t*>(p);
97   slice.data.refcounted.length = len;
98   return slice;
99 }
100 
grpc_slice_new(void * p,size_t len,void (* destroy)(void *))101 grpc_slice grpc_slice_new(void* p, size_t len, void (*destroy)(void*)) {
102   // Pass "p" to *destroy when the slice is no longer needed.
103   return grpc_slice_new_with_user_data(p, len, destroy, p);
104 }
105 
106 namespace grpc_core {
107 // grpc_slice_new_with_len support structures - we create a refcount object
108 // extended with the user provided data pointer & destroy function
109 class NewWithLenSliceRefcount : public grpc_slice_refcount {
110  public:
NewWithLenSliceRefcount(void (* destroy)(void *,size_t),void * user_data,size_t user_length)111   NewWithLenSliceRefcount(void (*destroy)(void*, size_t), void* user_data,
112                           size_t user_length)
113       : grpc_slice_refcount(Destroy),
114         user_data_(user_data),
115         user_length_(user_length),
116         user_destroy_(destroy) {}
~NewWithLenSliceRefcount()117   ~NewWithLenSliceRefcount() { user_destroy_(user_data_, user_length_); }
118 
119  private:
Destroy(grpc_slice_refcount * arg)120   static void Destroy(grpc_slice_refcount* arg) {
121     delete static_cast<NewWithLenSliceRefcount*>(arg);
122   }
123 
124   void* user_data_;
125   size_t user_length_;
126   void (*user_destroy_)(void*, size_t);
127 };
128 
129 /// grpc_slice_from_moved_(string|buffer) ref count .
130 class MovedStringSliceRefCount : public grpc_slice_refcount {
131  public:
MovedStringSliceRefCount(UniquePtr<char> && str)132   explicit MovedStringSliceRefCount(UniquePtr<char>&& str)
133       : grpc_slice_refcount(Destroy), str_(std::move(str)) {}
134 
135  private:
Destroy(grpc_slice_refcount * arg)136   static void Destroy(grpc_slice_refcount* arg) {
137     delete static_cast<MovedStringSliceRefCount*>(arg);
138   }
139 
140   UniquePtr<char> str_;
141 };
142 
143 // grpc_slice_from_cpp_string() ref count.
144 class MovedCppStringSliceRefCount : public grpc_slice_refcount {
145  public:
MovedCppStringSliceRefCount(std::string && str)146   explicit MovedCppStringSliceRefCount(std::string&& str)
147       : grpc_slice_refcount(Destroy), str_(std::move(str)) {}
148 
data()149   uint8_t* data() {
150     return reinterpret_cast<uint8_t*>(const_cast<char*>(str_.data()));
151   }
152 
size() const153   size_t size() const { return str_.size(); }
154 
155  private:
Destroy(grpc_slice_refcount * arg)156   static void Destroy(grpc_slice_refcount* arg) {
157     delete static_cast<MovedCppStringSliceRefCount*>(arg);
158   }
159 
160   std::string str_;
161 };
162 
163 }  // namespace grpc_core
164 
grpc_slice_new_with_len(void * p,size_t len,void (* destroy)(void *,size_t))165 grpc_slice grpc_slice_new_with_len(void* p, size_t len,
166                                    void (*destroy)(void*, size_t)) {
167   grpc_slice slice;
168   slice.refcount = new grpc_core::NewWithLenSliceRefcount(destroy, p, len);
169   slice.data.refcounted.bytes = static_cast<uint8_t*>(p);
170   slice.data.refcounted.length = len;
171   return slice;
172 }
173 
grpc_slice_from_copied_buffer(const char * source,size_t len)174 grpc_slice grpc_slice_from_copied_buffer(const char* source, size_t len) {
175   if (len == 0) return grpc_empty_slice();
176   grpc_slice out = grpc_slice_malloc(len);
177   memcpy(GRPC_SLICE_START_PTR(out), source, len);
178   return out;
179 }
180 
grpc_slice_from_copied_string(const char * source)181 grpc_slice grpc_slice_from_copied_string(const char* source) {
182   return grpc_slice_from_copied_buffer(source, strlen(source));
183 }
184 
grpc_slice_from_moved_buffer(grpc_core::UniquePtr<char> p,size_t len)185 grpc_slice grpc_slice_from_moved_buffer(grpc_core::UniquePtr<char> p,
186                                         size_t len) {
187   uint8_t* ptr = reinterpret_cast<uint8_t*>(p.get());
188   grpc_slice slice;
189   if (len <= sizeof(slice.data.inlined.bytes)) {
190     slice.refcount = nullptr;
191     slice.data.inlined.length = len;
192     memcpy(GRPC_SLICE_START_PTR(slice), ptr, len);
193   } else {
194     slice.refcount = new grpc_core::MovedStringSliceRefCount(std::move(p));
195     slice.data.refcounted.bytes = ptr;
196     slice.data.refcounted.length = len;
197   }
198   return slice;
199 }
200 
grpc_slice_from_moved_string(grpc_core::UniquePtr<char> p)201 grpc_slice grpc_slice_from_moved_string(grpc_core::UniquePtr<char> p) {
202   const size_t len = strlen(p.get());
203   return grpc_slice_from_moved_buffer(std::move(p), len);
204 }
205 
grpc_slice_from_cpp_string(std::string str)206 grpc_slice grpc_slice_from_cpp_string(std::string str) {
207   grpc_slice slice;
208   if (str.size() <= sizeof(slice.data.inlined.bytes)) {
209     slice.refcount = nullptr;
210     slice.data.inlined.length = str.size();
211     memcpy(GRPC_SLICE_START_PTR(slice), str.data(), str.size());
212   } else {
213     auto* refcount = new grpc_core::MovedCppStringSliceRefCount(std::move(str));
214     slice.data.refcounted.bytes = refcount->data();
215     slice.data.refcounted.length = refcount->size();
216     slice.refcount = refcount;
217   }
218   return slice;
219 }
220 
grpc_slice_malloc_large(size_t length)221 grpc_slice grpc_slice_malloc_large(size_t length) {
222   grpc_slice slice;
223   uint8_t* memory = new uint8_t[sizeof(grpc_slice_refcount) + length];
224   slice.refcount = new (memory) grpc_slice_refcount(
225       [](grpc_slice_refcount* p) { delete[] reinterpret_cast<uint8_t*>(p); });
226   slice.data.refcounted.bytes = memory + sizeof(grpc_slice_refcount);
227   slice.data.refcounted.length = length;
228   return slice;
229 }
230 
grpc_slice_malloc(size_t length)231 grpc_slice grpc_slice_malloc(size_t length) {
232   if (length <= GRPC_SLICE_INLINED_SIZE) {
233     grpc_slice slice;
234     slice.refcount = nullptr;
235     slice.data.inlined.length = length;
236     return slice;
237   } else {
238     return grpc_slice_malloc_large(length);
239   }
240 }
241 
sub_no_ref(const grpc_slice & source,size_t begin,size_t end)242 static grpc_slice sub_no_ref(const grpc_slice& source, size_t begin,
243                              size_t end) {
244   grpc_slice subset;
245 
246   CHECK(end >= begin);
247 
248   if (source.refcount != nullptr) {
249     // Enforce preconditions
250     CHECK(source.data.refcounted.length >= end);
251 
252     // Build the result
253     subset.refcount = source.refcount;
254     // Point into the source array
255     subset.data.refcounted.bytes = source.data.refcounted.bytes + begin;
256     subset.data.refcounted.length = end - begin;
257   } else {
258     // Enforce preconditions
259     CHECK(source.data.inlined.length >= end);
260     subset.refcount = nullptr;
261     subset.data.inlined.length = static_cast<uint8_t>(end - begin);
262     memcpy(subset.data.inlined.bytes, source.data.inlined.bytes + begin,
263            end - begin);
264   }
265   return subset;
266 }
267 
grpc_slice_sub_no_ref(grpc_slice source,size_t begin,size_t end)268 grpc_slice grpc_slice_sub_no_ref(grpc_slice source, size_t begin, size_t end) {
269   return sub_no_ref(source, begin, end);
270 }
271 
grpc_slice_sub(grpc_slice source,size_t begin,size_t end)272 grpc_slice grpc_slice_sub(grpc_slice source, size_t begin, size_t end) {
273   grpc_slice subset;
274 
275   if (end - begin <= sizeof(subset.data.inlined.bytes)) {
276     subset.refcount = nullptr;
277     subset.data.inlined.length = static_cast<uint8_t>(end - begin);
278     memcpy(subset.data.inlined.bytes, GRPC_SLICE_START_PTR(source) + begin,
279            end - begin);
280   } else {
281     subset = grpc_slice_sub_no_ref(source, begin, end);
282     // Bump the refcount
283     if (subset.refcount != grpc_slice_refcount::NoopRefcount()) {
284       subset.refcount->Ref({});
285     }
286   }
287   return subset;
288 }
289 
290 template <bool allow_inline>
grpc_slice_split_tail_maybe_ref_impl(grpc_slice * source,size_t split,grpc_slice_ref_whom ref_whom)291 grpc_slice grpc_slice_split_tail_maybe_ref_impl(grpc_slice* source,
292                                                 size_t split,
293                                                 grpc_slice_ref_whom ref_whom) {
294   grpc_slice tail;
295 
296   if (source->refcount == nullptr) {
297     // inlined data, copy it out
298     CHECK(source->data.inlined.length >= split);
299     tail.refcount = nullptr;
300     tail.data.inlined.length =
301         static_cast<uint8_t>(source->data.inlined.length - split);
302     memcpy(tail.data.inlined.bytes, source->data.inlined.bytes + split,
303            tail.data.inlined.length);
304     source->data.inlined.length = static_cast<uint8_t>(split);
305   } else if (source->refcount == grpc_slice_refcount::NoopRefcount()) {
306     // refcount == NoopRefcount(), so we can just split in-place
307     tail.refcount = grpc_slice_refcount::NoopRefcount();
308     tail.data.refcounted.bytes = source->data.refcounted.bytes + split;
309     tail.data.refcounted.length = source->data.refcounted.length - split;
310     source->data.refcounted.length = split;
311   } else {
312     size_t tail_length = source->data.refcounted.length - split;
313     CHECK(source->data.refcounted.length >= split);
314     if (allow_inline && tail_length < sizeof(tail.data.inlined.bytes) &&
315         ref_whom != GRPC_SLICE_REF_TAIL) {
316       // Copy out the bytes - it'll be cheaper than refcounting
317       tail.refcount = nullptr;
318       tail.data.inlined.length = static_cast<uint8_t>(tail_length);
319       memcpy(tail.data.inlined.bytes, source->data.refcounted.bytes + split,
320              tail_length);
321     } else {
322       // Build the result
323       switch (ref_whom) {
324         case GRPC_SLICE_REF_TAIL:
325           tail.refcount = source->refcount;
326           source->refcount = grpc_slice_refcount::NoopRefcount();
327           break;
328         case GRPC_SLICE_REF_HEAD:
329           tail.refcount = grpc_slice_refcount::NoopRefcount();
330           break;
331         case GRPC_SLICE_REF_BOTH:
332           tail.refcount = source->refcount;
333           // Bump the refcount
334           if (tail.refcount != grpc_slice_refcount::NoopRefcount()) {
335             tail.refcount->Ref({});
336           }
337           break;
338       }
339       // Point into the source array
340       tail.data.refcounted.bytes = source->data.refcounted.bytes + split;
341       tail.data.refcounted.length = tail_length;
342     }
343     source->data.refcounted.length = split;
344   }
345 
346   return tail;
347 }
348 
grpc_slice_split_tail_maybe_ref(grpc_slice * source,size_t split,grpc_slice_ref_whom ref_whom)349 grpc_slice grpc_slice_split_tail_maybe_ref(grpc_slice* source, size_t split,
350                                            grpc_slice_ref_whom ref_whom) {
351   return grpc_slice_split_tail_maybe_ref_impl<true>(source, split, ref_whom);
352 }
353 
grpc_slice_split_tail_maybe_ref_no_inline(grpc_slice * source,size_t split,grpc_slice_ref_whom ref_whom)354 grpc_slice grpc_slice_split_tail_maybe_ref_no_inline(
355     grpc_slice* source, size_t split, grpc_slice_ref_whom ref_whom) {
356   return grpc_slice_split_tail_maybe_ref_impl<false>(source, split, ref_whom);
357 }
358 
grpc_slice_split_tail(grpc_slice * source,size_t split)359 grpc_slice grpc_slice_split_tail(grpc_slice* source, size_t split) {
360   return grpc_slice_split_tail_maybe_ref(source, split, GRPC_SLICE_REF_BOTH);
361 }
362 
grpc_slice_split_tail_no_inline(grpc_slice * source,size_t split)363 grpc_slice grpc_slice_split_tail_no_inline(grpc_slice* source, size_t split) {
364   return grpc_slice_split_tail_maybe_ref_no_inline(source, split,
365                                                    GRPC_SLICE_REF_BOTH);
366 }
367 
368 template <bool allow_inline>
grpc_slice_split_head_impl(grpc_slice * source,size_t split)369 grpc_slice grpc_slice_split_head_impl(grpc_slice* source, size_t split) {
370   grpc_slice head;
371 
372   if (source->refcount == nullptr) {
373     CHECK(source->data.inlined.length >= split);
374 
375     head.refcount = nullptr;
376     head.data.inlined.length = static_cast<uint8_t>(split);
377     memcpy(head.data.inlined.bytes, source->data.inlined.bytes, split);
378     source->data.inlined.length =
379         static_cast<uint8_t>(source->data.inlined.length - split);
380     memmove(source->data.inlined.bytes, source->data.inlined.bytes + split,
381             source->data.inlined.length);
382   } else if (allow_inline && split < sizeof(head.data.inlined.bytes)) {
383     CHECK(source->data.refcounted.length >= split);
384 
385     head.refcount = nullptr;
386     head.data.inlined.length = static_cast<uint8_t>(split);
387     memcpy(head.data.inlined.bytes, source->data.refcounted.bytes, split);
388     source->data.refcounted.bytes += split;
389     source->data.refcounted.length -= split;
390   } else {
391     CHECK(source->data.refcounted.length >= split);
392 
393     // Build the result
394     head.refcount = source->refcount;
395     // Bump the refcount
396     if (head.refcount != grpc_slice_refcount::NoopRefcount()) {
397       head.refcount->Ref({});
398     }
399     // Point into the source array
400     head.data.refcounted.bytes = source->data.refcounted.bytes;
401     head.data.refcounted.length = split;
402     source->data.refcounted.bytes += split;
403     source->data.refcounted.length -= split;
404   }
405 
406   return head;
407 }
408 
grpc_slice_split_head(grpc_slice * source,size_t split)409 grpc_slice grpc_slice_split_head(grpc_slice* source, size_t split) {
410   return grpc_slice_split_head_impl<true>(source, split);
411 }
412 
grpc_slice_split_head_no_inline(grpc_slice * source,size_t split)413 grpc_slice grpc_slice_split_head_no_inline(grpc_slice* source, size_t split) {
414   return grpc_slice_split_head_impl<false>(source, split);
415 }
416 
grpc_slice_eq(grpc_slice a,grpc_slice b)417 int grpc_slice_eq(grpc_slice a, grpc_slice b) {
418   if (GRPC_SLICE_LENGTH(a) != GRPC_SLICE_LENGTH(b)) return false;
419   if (GRPC_SLICE_LENGTH(a) == 0) return true;
420   return 0 == memcmp(GRPC_SLICE_START_PTR(a), GRPC_SLICE_START_PTR(b),
421                      GRPC_SLICE_LENGTH(a));
422 }
423 
grpc_slice_differs_refcounted(const grpc_slice & a,const grpc_slice & b_not_inline)424 int grpc_slice_differs_refcounted(const grpc_slice& a,
425                                   const grpc_slice& b_not_inline) {
426   size_t a_len;
427   const uint8_t* a_ptr;
428   if (a.refcount) {
429     a_len = a.data.refcounted.length;
430     a_ptr = a.data.refcounted.bytes;
431   } else {
432     a_len = a.data.inlined.length;
433     a_ptr = &a.data.inlined.bytes[0];
434   }
435   if (a_len != b_not_inline.data.refcounted.length) {
436     return true;
437   }
438   if (a_len == 0) {
439     return false;
440   }
441   // This check *must* occur after the a_len == 0 check
442   // to retain compatibility with grpc_slice_eq.
443   if (a_ptr == nullptr) {
444     return true;
445   }
446   return memcmp(a_ptr, b_not_inline.data.refcounted.bytes, a_len);
447 }
448 
grpc_slice_cmp(grpc_slice a,grpc_slice b)449 int grpc_slice_cmp(grpc_slice a, grpc_slice b) {
450   int d = static_cast<int>(GRPC_SLICE_LENGTH(a) - GRPC_SLICE_LENGTH(b));
451   if (d != 0) return d;
452   return memcmp(GRPC_SLICE_START_PTR(a), GRPC_SLICE_START_PTR(b),
453                 GRPC_SLICE_LENGTH(a));
454 }
455 
grpc_slice_str_cmp(grpc_slice a,const char * b)456 int grpc_slice_str_cmp(grpc_slice a, const char* b) {
457   size_t b_length = strlen(b);
458   int d = static_cast<int>(GRPC_SLICE_LENGTH(a) - b_length);
459   if (d != 0) return d;
460   return memcmp(GRPC_SLICE_START_PTR(a), b, b_length);
461 }
462 
grpc_slice_is_equivalent(grpc_slice a,grpc_slice b)463 int grpc_slice_is_equivalent(grpc_slice a, grpc_slice b) {
464   if (a.refcount == nullptr || b.refcount == nullptr) {
465     return grpc_slice_eq(a, b);
466   }
467   return a.data.refcounted.length == b.data.refcounted.length &&
468          a.data.refcounted.bytes == b.data.refcounted.bytes;
469 }
470 
grpc_slice_buf_start_eq(grpc_slice a,const void * b,size_t len)471 int grpc_slice_buf_start_eq(grpc_slice a, const void* b, size_t len) {
472   if (GRPC_SLICE_LENGTH(a) < len) return 0;
473   return 0 == memcmp(GRPC_SLICE_START_PTR(a), b, len);
474 }
475 
grpc_slice_rchr(grpc_slice s,char c)476 int grpc_slice_rchr(grpc_slice s, char c) {
477   const char* b = reinterpret_cast<const char*> GRPC_SLICE_START_PTR(s);
478   int i;
479   for (i = static_cast<int> GRPC_SLICE_LENGTH(s) - 1; i != -1 && b[i] != c;
480        i--) {
481   }
482   return i;
483 }
484 
grpc_slice_chr(grpc_slice s,char c)485 int grpc_slice_chr(grpc_slice s, char c) {
486   const char* b = reinterpret_cast<const char*> GRPC_SLICE_START_PTR(s);
487   const char* p = static_cast<const char*>(memchr(b, c, GRPC_SLICE_LENGTH(s)));
488   return p == nullptr ? -1 : static_cast<int>(p - b);
489 }
490 
grpc_slice_slice(grpc_slice haystack,grpc_slice needle)491 int grpc_slice_slice(grpc_slice haystack, grpc_slice needle) {
492   size_t haystack_len = GRPC_SLICE_LENGTH(haystack);
493   const uint8_t* haystack_bytes = GRPC_SLICE_START_PTR(haystack);
494   size_t needle_len = GRPC_SLICE_LENGTH(needle);
495   const uint8_t* needle_bytes = GRPC_SLICE_START_PTR(needle);
496 
497   if (haystack_len == 0 || needle_len == 0) return -1;
498   if (haystack_len < needle_len) return -1;
499   if (haystack_len == needle_len) {
500     return grpc_slice_eq(haystack, needle) ? 0 : -1;
501   }
502   if (needle_len == 1) {
503     return grpc_slice_chr(haystack, static_cast<char>(*needle_bytes));
504   }
505 
506   const uint8_t* last = haystack_bytes + haystack_len - needle_len;
507   for (const uint8_t* cur = haystack_bytes; cur <= last; ++cur) {
508     if (0 == memcmp(cur, needle_bytes, needle_len)) {
509       return static_cast<int>(cur - haystack_bytes);
510     }
511   }
512   return -1;
513 }
514 
grpc_slice_dup(grpc_slice a)515 grpc_slice grpc_slice_dup(grpc_slice a) {
516   grpc_slice copy = GRPC_SLICE_MALLOC(GRPC_SLICE_LENGTH(a));
517   memcpy(GRPC_SLICE_START_PTR(copy), GRPC_SLICE_START_PTR(a),
518          GRPC_SLICE_LENGTH(a));
519   return copy;
520 }
521 
grpc_slice_ref(grpc_slice slice)522 grpc_slice grpc_slice_ref(grpc_slice slice) {
523   return grpc_core::CSliceRef(slice);
524 }
525 
grpc_slice_unref(grpc_slice slice)526 void grpc_slice_unref(grpc_slice slice) { grpc_core::CSliceUnref(slice); }
527