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 "src/core/lib/slice/slice_internal.h"
23 #include <grpc/slice.h>
24 #include <grpc/support/alloc.h>
25 #include <grpc/support/log.h>
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"
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;
40 grpc_slice grpc_empty_slice(void) { return grpc_core::UnmanagedMemorySlice(); }
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));
50 grpc_slice grpc_slice_ref(grpc_slice slice) {
51 return grpc_slice_ref_internal(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);
60 grpc_slice_unref_internal(slice);
66 /* grpc_slice_from_static_string support structure - a refcount that does
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.");
72 /* grpc_slice_new support structures - we create a refcount object extended
73 with the user provided data pointer & destroy function */
74 class NewSliceRefcount {
76 static void Destroy(void* arg) {
77 Delete(static_cast<NewSliceRefcount*>(arg));
80 NewSliceRefcount(void (*destroy)(void*), void* user_data)
81 : base_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this,
83 user_destroy_(destroy),
84 user_data_(user_data) {}
86 GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
88 grpc_slice_refcount* base_refcount() { return &base_; }
91 ~NewSliceRefcount() { user_destroy_(user_data_); }
93 grpc_slice_refcount base_;
95 void (*user_destroy_)(void*);
99 } // namespace grpc_core
101 size_t grpc_slice_memory_usage(grpc_slice s) {
102 if (s.refcount == nullptr || s.refcount == &grpc_core::kNoopRefcount) {
105 return s.data.refcounted.length;
109 grpc_slice grpc_slice_from_static_buffer(const void* s, size_t len) {
110 return grpc_core::ExternallyManagedSlice(s, len);
113 grpc_slice grpc_slice_from_static_string(const char* s) {
114 return grpc_core::ExternallyManagedSlice(s, strlen(s));
117 grpc_slice grpc_slice_new_with_user_data(void* p, size_t len,
118 void (*destroy)(void*),
122 grpc_core::New<grpc_core::NewSliceRefcount>(destroy, user_data)
124 slice.data.refcounted.bytes = static_cast<uint8_t*>(p);
125 slice.data.refcounted.length = len;
129 grpc_slice grpc_slice_new(void* p, size_t len, void (*destroy)(void*)) {
130 /* Pass "p" to *destroy when the slice is no longer needed. */
131 return grpc_slice_new_with_user_data(p, len, destroy, p);
134 namespace grpc_core {
135 /* grpc_slice_new_with_len support structures - we create a refcount object
136 extended with the user provided data pointer & destroy function */
137 class NewWithLenSliceRefcount {
139 static void Destroy(void* arg) {
140 Delete(static_cast<NewWithLenSliceRefcount*>(arg));
143 NewWithLenSliceRefcount(void (*destroy)(void*, size_t), void* user_data,
145 : base_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this,
147 user_data_(user_data),
148 user_length_(user_length),
149 user_destroy_(destroy) {}
151 GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
153 grpc_slice_refcount* base_refcount() { return &base_; }
156 ~NewWithLenSliceRefcount() { user_destroy_(user_data_, user_length_); }
158 grpc_slice_refcount base_;
162 void (*user_destroy_)(void*, size_t);
165 /** grpc_slice_from_moved_(string|buffer) ref count .*/
166 class MovedStringSliceRefCount {
168 MovedStringSliceRefCount(grpc_core::UniquePtr<char>&& str)
169 : base_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this,
171 str_(std::move(str)) {}
173 GRPC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
175 grpc_slice_refcount* base_refcount() { return &base_; }
178 static void Destroy(void* arg) {
179 Delete(static_cast<MovedStringSliceRefCount*>(arg));
182 grpc_slice_refcount base_;
183 grpc_core::RefCount refs_;
184 grpc_core::UniquePtr<char> str_;
187 } // namespace grpc_core
189 grpc_slice grpc_slice_new_with_len(void* p, size_t len,
190 void (*destroy)(void*, size_t)) {
193 grpc_core::New<grpc_core::NewWithLenSliceRefcount>(destroy, p, len)
195 slice.data.refcounted.bytes = static_cast<uint8_t*>(p);
196 slice.data.refcounted.length = len;
200 grpc_core::UnmanagedMemorySlice::UnmanagedMemorySlice(const char* source,
202 if (length <= sizeof(data.inlined.bytes)) {
204 data.inlined.length = static_cast<uint8_t>(length);
209 memcpy(GRPC_SLICE_START_PTR(*this), source, length);
213 grpc_core::UnmanagedMemorySlice::UnmanagedMemorySlice(const char* source)
214 : grpc_core::UnmanagedMemorySlice::UnmanagedMemorySlice(source,
217 grpc_slice grpc_slice_from_copied_buffer(const char* source, size_t length) {
218 return grpc_core::UnmanagedMemorySlice(source, length);
221 grpc_slice grpc_slice_from_copied_string(const char* source) {
222 return grpc_core::UnmanagedMemorySlice(source, strlen(source));
225 grpc_slice grpc_slice_from_moved_buffer(grpc_core::UniquePtr<char> p,
227 uint8_t* ptr = reinterpret_cast<uint8_t*>(p.get());
229 if (len <= sizeof(slice.data.inlined.bytes)) {
230 slice.refcount = nullptr;
231 slice.data.inlined.length = len;
232 memcpy(GRPC_SLICE_START_PTR(slice), ptr, len);
235 grpc_core::New<grpc_core::MovedStringSliceRefCount>(std::move(p))
237 slice.data.refcounted.bytes = ptr;
238 slice.data.refcounted.length = len;
243 grpc_slice grpc_slice_from_moved_string(grpc_core::UniquePtr<char> p) {
244 const size_t len = strlen(p.get());
245 return grpc_slice_from_moved_buffer(std::move(p), len);
250 class MallocRefCount {
252 static void Destroy(void* arg) {
253 MallocRefCount* r = static_cast<MallocRefCount*>(arg);
254 r->~MallocRefCount();
259 : base_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this,
261 ~MallocRefCount() = default;
263 grpc_slice_refcount* base_refcount() { return &base_; }
266 grpc_slice_refcount base_;
267 grpc_core::RefCount refs_;
272 grpc_slice grpc_slice_malloc_large(size_t length) {
273 return grpc_core::UnmanagedMemorySlice(
274 length, grpc_core::UnmanagedMemorySlice::ForceHeapAllocation());
277 void grpc_core::UnmanagedMemorySlice::HeapInit(size_t length) {
278 /* Memory layout used by the slice created here:
280 +-----------+----------------------------------------------------------+
282 +-----------+----------------------------------------------------------+
284 refcount is a malloc_refcount
285 bytes is an array of bytes of the requested length
286 Both parts are placed in the same allocation returned from gpr_malloc */
288 static_cast<MallocRefCount*>(gpr_malloc(sizeof(MallocRefCount) + length));
290 /* Initial refcount on rc is 1 - and it's up to the caller to release
292 new (rc) MallocRefCount();
294 /* Build up the slice to be returned. */
295 /* The slices refcount points back to the allocated block. */
296 refcount = rc->base_refcount();
297 /* The data bytes are placed immediately after the refcount struct */
298 data.refcounted.bytes = reinterpret_cast<uint8_t*>(rc + 1);
299 /* And the length of the block is set to the requested length */
300 data.refcounted.length = length;
303 grpc_slice grpc_slice_malloc(size_t length) {
304 return grpc_core::UnmanagedMemorySlice(length);
307 grpc_core::UnmanagedMemorySlice::UnmanagedMemorySlice(size_t length) {
308 if (length > sizeof(data.inlined.bytes)) {
311 /* small slice: just inline the data */
313 data.inlined.length = static_cast<uint8_t>(length);
317 template <typename Slice>
318 static Slice sub_no_ref(const Slice& source, size_t begin, size_t end) {
321 GPR_ASSERT(end >= begin);
323 if (source.refcount) {
324 /* Enforce preconditions */
325 GPR_ASSERT(source.data.refcounted.length >= end);
327 /* Build the result */
328 subset.refcount = source.refcount->sub_refcount();
329 /* Point into the source array */
330 subset.data.refcounted.bytes = source.data.refcounted.bytes + begin;
331 subset.data.refcounted.length = end - begin;
333 /* Enforce preconditions */
334 GPR_ASSERT(source.data.inlined.length >= end);
335 subset.refcount = nullptr;
336 subset.data.inlined.length = static_cast<uint8_t>(end - begin);
337 memcpy(subset.data.inlined.bytes, source.data.inlined.bytes + begin,
343 grpc_slice grpc_slice_sub_no_ref(grpc_slice source, size_t begin, size_t end) {
344 return sub_no_ref(source, begin, end);
347 grpc_core::UnmanagedMemorySlice grpc_slice_sub_no_ref(
348 const grpc_core::UnmanagedMemorySlice& source, size_t begin, size_t end) {
349 return sub_no_ref(source, begin, end);
352 grpc_slice grpc_slice_sub(grpc_slice source, size_t begin, size_t end) {
355 if (end - begin <= sizeof(subset.data.inlined.bytes)) {
356 subset.refcount = nullptr;
357 subset.data.inlined.length = static_cast<uint8_t>(end - begin);
358 memcpy(subset.data.inlined.bytes, GRPC_SLICE_START_PTR(source) + begin,
361 subset = grpc_slice_sub_no_ref(source, begin, end);
362 /* Bump the refcount */
363 subset.refcount->Ref();
368 grpc_slice grpc_slice_split_tail_maybe_ref(grpc_slice* source, size_t split,
369 grpc_slice_ref_whom ref_whom) {
372 if (source->refcount == nullptr) {
373 /* inlined data, copy it out */
374 GPR_ASSERT(source->data.inlined.length >= split);
375 tail.refcount = nullptr;
376 tail.data.inlined.length =
377 static_cast<uint8_t>(source->data.inlined.length - split);
378 memcpy(tail.data.inlined.bytes, source->data.inlined.bytes + split,
379 tail.data.inlined.length);
380 source->data.inlined.length = static_cast<uint8_t>(split);
382 size_t tail_length = source->data.refcounted.length - split;
383 GPR_ASSERT(source->data.refcounted.length >= split);
384 if (tail_length < sizeof(tail.data.inlined.bytes) &&
385 ref_whom != GRPC_SLICE_REF_TAIL) {
386 /* Copy out the bytes - it'll be cheaper than refcounting */
387 tail.refcount = nullptr;
388 tail.data.inlined.length = static_cast<uint8_t>(tail_length);
389 memcpy(tail.data.inlined.bytes, source->data.refcounted.bytes + split,
391 source->refcount = source->refcount->sub_refcount();
393 /* Build the result */
395 case GRPC_SLICE_REF_TAIL:
396 tail.refcount = source->refcount->sub_refcount();
397 source->refcount = &grpc_core::kNoopRefcount;
399 case GRPC_SLICE_REF_HEAD:
400 tail.refcount = &grpc_core::kNoopRefcount;
401 source->refcount = source->refcount->sub_refcount();
403 case GRPC_SLICE_REF_BOTH:
404 tail.refcount = source->refcount->sub_refcount();
405 source->refcount = source->refcount->sub_refcount();
406 /* Bump the refcount */
407 tail.refcount->Ref();
410 /* Point into the source array */
411 tail.data.refcounted.bytes = source->data.refcounted.bytes + split;
412 tail.data.refcounted.length = tail_length;
414 source->data.refcounted.length = split;
420 grpc_slice grpc_slice_split_tail(grpc_slice* source, size_t split) {
421 return grpc_slice_split_tail_maybe_ref(source, split, GRPC_SLICE_REF_BOTH);
424 grpc_slice grpc_slice_split_head(grpc_slice* source, size_t split) {
427 if (source->refcount == nullptr) {
428 GPR_ASSERT(source->data.inlined.length >= split);
430 head.refcount = nullptr;
431 head.data.inlined.length = static_cast<uint8_t>(split);
432 memcpy(head.data.inlined.bytes, source->data.inlined.bytes, split);
433 source->data.inlined.length =
434 static_cast<uint8_t>(source->data.inlined.length - split);
435 memmove(source->data.inlined.bytes, source->data.inlined.bytes + split,
436 source->data.inlined.length);
437 } else if (split < sizeof(head.data.inlined.bytes)) {
438 GPR_ASSERT(source->data.refcounted.length >= split);
440 head.refcount = nullptr;
441 head.data.inlined.length = static_cast<uint8_t>(split);
442 memcpy(head.data.inlined.bytes, source->data.refcounted.bytes, split);
443 source->refcount = source->refcount->sub_refcount();
444 source->data.refcounted.bytes += split;
445 source->data.refcounted.length -= split;
447 GPR_ASSERT(source->data.refcounted.length >= split);
449 /* Build the result */
450 head.refcount = source->refcount->sub_refcount();
451 /* Bump the refcount */
452 head.refcount->Ref();
453 /* Point into the source array */
454 head.data.refcounted.bytes = source->data.refcounted.bytes;
455 head.data.refcounted.length = split;
456 source->refcount = source->refcount->sub_refcount();
457 source->data.refcounted.bytes += split;
458 source->data.refcounted.length -= split;
464 int grpc_slice_default_eq_impl(grpc_slice a, grpc_slice b) {
465 if (GRPC_SLICE_LENGTH(a) != GRPC_SLICE_LENGTH(b)) return false;
466 if (GRPC_SLICE_LENGTH(a) == 0) return true;
467 return 0 == memcmp(GRPC_SLICE_START_PTR(a), GRPC_SLICE_START_PTR(b),
468 GRPC_SLICE_LENGTH(a));
471 int grpc_slice_eq(grpc_slice a, grpc_slice b) {
472 if (a.refcount && b.refcount &&
473 a.refcount->GetType() == b.refcount->GetType()) {
474 return a.refcount->Eq(a, b);
476 return grpc_slice_default_eq_impl(a, b);
479 int grpc_slice_differs_refcounted(const grpc_slice& a,
480 const grpc_slice& b_not_inline) {
482 const uint8_t* a_ptr;
484 a_len = a.data.refcounted.length;
485 a_ptr = a.data.refcounted.bytes;
487 a_len = a.data.inlined.length;
488 a_ptr = &a.data.inlined.bytes[0];
490 if (a_len != b_not_inline.data.refcounted.length) {
496 // This check *must* occur after the a_len == 0 check
497 // to retain compatibility with grpc_slice_eq.
498 if (a_ptr == nullptr) {
501 return memcmp(a_ptr, b_not_inline.data.refcounted.bytes, a_len);
504 int grpc_slice_cmp(grpc_slice a, grpc_slice b) {
505 int d = static_cast<int>(GRPC_SLICE_LENGTH(a) - GRPC_SLICE_LENGTH(b));
506 if (d != 0) return d;
507 return memcmp(GRPC_SLICE_START_PTR(a), GRPC_SLICE_START_PTR(b),
508 GRPC_SLICE_LENGTH(a));
511 int grpc_slice_str_cmp(grpc_slice a, const char* b) {
512 size_t b_length = strlen(b);
513 int d = static_cast<int>(GRPC_SLICE_LENGTH(a) - b_length);
514 if (d != 0) return d;
515 return memcmp(GRPC_SLICE_START_PTR(a), b, b_length);
518 int grpc_slice_is_equivalent(grpc_slice a, grpc_slice b) {
519 if (a.refcount == nullptr || b.refcount == nullptr) {
520 return grpc_slice_eq(a, b);
522 return a.data.refcounted.length == b.data.refcounted.length &&
523 a.data.refcounted.bytes == b.data.refcounted.bytes;
526 int grpc_slice_buf_start_eq(grpc_slice a, const void* b, size_t len) {
527 if (GRPC_SLICE_LENGTH(a) < len) return 0;
528 return 0 == memcmp(GRPC_SLICE_START_PTR(a), b, len);
531 int grpc_slice_rchr(grpc_slice s, char c) {
532 const char* b = reinterpret_cast<const char*> GRPC_SLICE_START_PTR(s);
534 for (i = static_cast<int> GRPC_SLICE_LENGTH(s) - 1; i != -1 && b[i] != c; i--)
539 int grpc_slice_chr(grpc_slice s, char c) {
540 const char* b = reinterpret_cast<const char*> GRPC_SLICE_START_PTR(s);
541 const char* p = static_cast<const char*>(memchr(b, c, GRPC_SLICE_LENGTH(s)));
542 return p == nullptr ? -1 : static_cast<int>(p - b);
545 int grpc_slice_slice(grpc_slice haystack, grpc_slice needle) {
546 size_t haystack_len = GRPC_SLICE_LENGTH(haystack);
547 const uint8_t* haystack_bytes = GRPC_SLICE_START_PTR(haystack);
548 size_t needle_len = GRPC_SLICE_LENGTH(needle);
549 const uint8_t* needle_bytes = GRPC_SLICE_START_PTR(needle);
551 if (haystack_len == 0 || needle_len == 0) return -1;
552 if (haystack_len < needle_len) return -1;
553 if (haystack_len == needle_len)
554 return grpc_slice_eq(haystack, needle) ? 0 : -1;
556 return grpc_slice_chr(haystack, static_cast<char>(*needle_bytes));
558 const uint8_t* last = haystack_bytes + haystack_len - needle_len;
559 for (const uint8_t* cur = haystack_bytes; cur != last; ++cur) {
560 if (0 == memcmp(cur, needle_bytes, needle_len)) {
561 return static_cast<int>(cur - haystack_bytes);
567 grpc_slice grpc_slice_dup(grpc_slice a) {
568 grpc_slice copy = GRPC_SLICE_MALLOC(GRPC_SLICE_LENGTH(a));
569 memcpy(GRPC_SLICE_START_PTR(copy), GRPC_SLICE_START_PTR(a),
570 GRPC_SLICE_LENGTH(a));