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>
23 #include <grpc/slice.h>
24 #include <grpc/support/alloc.h>
25 #include <grpc/support/log.h>
27 #include "src/core/lib/gprpp/memory.h"
28 #include "src/core/lib/gprpp/ref_counted.h"
29 #include "src/core/lib/iomgr/exec_ctx.h"
30 #include "src/core/lib/slice/slice_internal.h"
32 char* grpc_slice_to_c_string(grpc_slice slice) {
33 char* out = static_cast<char*>(gpr_malloc(GRPC_SLICE_LENGTH(slice) + 1));
34 memcpy(out, GRPC_SLICE_START_PTR(slice), GRPC_SLICE_LENGTH(slice));
35 out[GRPC_SLICE_LENGTH(slice)] = 0;
39 grpc_slice grpc_empty_slice(void) { return grpc_core::UnmanagedMemorySlice(); }
41 grpc_slice grpc_slice_copy(grpc_slice s) {
42 grpc_slice out = GRPC_SLICE_MALLOC(GRPC_SLICE_LENGTH(s));
43 memcpy(GRPC_SLICE_START_PTR(out), GRPC_SLICE_START_PTR(s),
44 GRPC_SLICE_LENGTH(s));
49 grpc_slice grpc_slice_ref(grpc_slice slice) {
50 return grpc_slice_ref_internal(slice);
54 void grpc_slice_unref(grpc_slice slice) {
55 if (grpc_core::ExecCtx::Get() == nullptr) {
56 grpc_core::ExecCtx exec_ctx;
57 grpc_slice_unref_internal(slice);
59 grpc_slice_unref_internal(slice);
65 /* grpc_slice_from_static_string support structure - a refcount that does
67 grpc_slice_refcount kNoopRefcount(grpc_slice_refcount::Type::NOP);
68 static_assert(std::is_trivially_destructible<decltype(kNoopRefcount)>::value,
69 "kNoopRefcount must be trivially destructible.");
71 /* grpc_slice_new support structures - we create a refcount object extended
72 with the user provided data pointer & destroy function */
73 class NewSliceRefcount {
75 static void Destroy(void* arg) { delete static_cast<NewSliceRefcount*>(arg); }
77 NewSliceRefcount(void (*destroy)(void*), void* user_data)
78 : base_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this,
80 user_destroy_(destroy),
81 user_data_(user_data) {}
82 ~NewSliceRefcount() { user_destroy_(user_data_); }
84 grpc_slice_refcount* base_refcount() { return &base_; }
87 grpc_slice_refcount base_;
89 void (*user_destroy_)(void*);
93 } // namespace grpc_core
95 size_t grpc_slice_memory_usage(grpc_slice s) {
96 if (s.refcount == nullptr || s.refcount == &grpc_core::kNoopRefcount) {
99 return s.data.refcounted.length;
103 grpc_slice grpc_slice_from_static_buffer(const void* s, size_t len) {
104 return grpc_core::ExternallyManagedSlice(s, len);
107 grpc_slice grpc_slice_from_static_string(const char* s) {
108 return grpc_core::ExternallyManagedSlice(s, strlen(s));
111 grpc_slice grpc_slice_new_with_user_data(void* p, size_t len,
112 void (*destroy)(void*),
116 (new grpc_core::NewSliceRefcount(destroy, user_data))->base_refcount();
117 slice.data.refcounted.bytes = static_cast<uint8_t*>(p);
118 slice.data.refcounted.length = len;
122 grpc_slice grpc_slice_new(void* p, size_t len, void (*destroy)(void*)) {
123 /* Pass "p" to *destroy when the slice is no longer needed. */
124 return grpc_slice_new_with_user_data(p, len, destroy, p);
127 namespace grpc_core {
128 /* grpc_slice_new_with_len support structures - we create a refcount object
129 extended with the user provided data pointer & destroy function */
130 class NewWithLenSliceRefcount {
132 static void Destroy(void* arg) {
133 delete static_cast<NewWithLenSliceRefcount*>(arg);
136 NewWithLenSliceRefcount(void (*destroy)(void*, size_t), void* user_data,
138 : base_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this,
140 user_data_(user_data),
141 user_length_(user_length),
142 user_destroy_(destroy) {}
143 ~NewWithLenSliceRefcount() { user_destroy_(user_data_, user_length_); }
145 grpc_slice_refcount* base_refcount() { return &base_; }
148 grpc_slice_refcount base_;
152 void (*user_destroy_)(void*, size_t);
155 /** grpc_slice_from_moved_(string|buffer) ref count .*/
156 class MovedStringSliceRefCount {
158 explicit MovedStringSliceRefCount(grpc_core::UniquePtr<char>&& str)
159 : base_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this,
161 str_(std::move(str)) {}
163 grpc_slice_refcount* base_refcount() { return &base_; }
166 static void Destroy(void* arg) {
167 delete static_cast<MovedStringSliceRefCount*>(arg);
170 grpc_slice_refcount base_;
171 grpc_core::RefCount refs_;
172 grpc_core::UniquePtr<char> str_;
175 // grpc_slice_from_cpp_string() ref count.
176 class MovedCppStringSliceRefCount {
178 explicit MovedCppStringSliceRefCount(std::string&& str)
179 : base_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this,
181 str_(std::move(str)) {}
183 grpc_slice_refcount* base_refcount() { return &base_; }
186 static void Destroy(void* arg) {
187 delete static_cast<MovedCppStringSliceRefCount*>(arg);
190 grpc_slice_refcount base_;
191 grpc_core::RefCount refs_;
195 } // namespace grpc_core
197 grpc_slice grpc_slice_new_with_len(void* p, size_t len,
198 void (*destroy)(void*, size_t)) {
200 slice.refcount = (new grpc_core::NewWithLenSliceRefcount(destroy, p, len))
202 slice.data.refcounted.bytes = static_cast<uint8_t*>(p);
203 slice.data.refcounted.length = len;
207 grpc_core::UnmanagedMemorySlice::UnmanagedMemorySlice(const char* source,
209 if (length <= sizeof(data.inlined.bytes)) {
211 data.inlined.length = static_cast<uint8_t>(length);
216 memcpy(GRPC_SLICE_START_PTR(*this), source, length);
220 grpc_core::UnmanagedMemorySlice::UnmanagedMemorySlice(const char* source)
221 : grpc_core::UnmanagedMemorySlice::UnmanagedMemorySlice(source,
224 grpc_slice grpc_slice_from_copied_buffer(const char* source, size_t length) {
226 if (length <= sizeof(slice.data.inlined.bytes)) {
227 slice.refcount = nullptr;
228 slice.data.inlined.length = length;
230 // Create a ref-counted slice.
231 slice = grpc_core::UnmanagedMemorySlice(
232 length, grpc_core::UnmanagedMemorySlice::ForceHeapAllocation());
234 memcpy(GRPC_SLICE_START_PTR(slice), source, length);
238 grpc_slice grpc_slice_from_copied_string(const char* source) {
239 return grpc_slice_from_copied_buffer(source, strlen(source));
242 grpc_slice grpc_slice_from_moved_buffer(grpc_core::UniquePtr<char> p,
244 uint8_t* ptr = reinterpret_cast<uint8_t*>(p.get());
246 if (len <= sizeof(slice.data.inlined.bytes)) {
247 slice.refcount = nullptr;
248 slice.data.inlined.length = len;
249 memcpy(GRPC_SLICE_START_PTR(slice), ptr, len);
251 slice.refcount = (new grpc_core::MovedStringSliceRefCount(std::move(p)))
253 slice.data.refcounted.bytes = ptr;
254 slice.data.refcounted.length = len;
259 grpc_slice grpc_slice_from_moved_string(grpc_core::UniquePtr<char> p) {
260 const size_t len = strlen(p.get());
261 return grpc_slice_from_moved_buffer(std::move(p), len);
264 grpc_slice grpc_slice_from_cpp_string(std::string str) {
266 if (str.size() <= sizeof(slice.data.inlined.bytes)) {
267 slice.refcount = nullptr;
268 slice.data.inlined.length = str.size();
269 memcpy(GRPC_SLICE_START_PTR(slice), str.data(), str.size());
271 slice.data.refcounted.bytes =
272 reinterpret_cast<uint8_t*>(const_cast<char*>(str.data()));
273 slice.data.refcounted.length = str.size();
275 (new grpc_core::MovedCppStringSliceRefCount(std::move(str)))
283 class MallocRefCount {
285 static void Destroy(void* arg) {
286 MallocRefCount* r = static_cast<MallocRefCount*>(arg);
287 r->~MallocRefCount();
292 : base_(grpc_slice_refcount::Type::REGULAR, &refs_, Destroy, this,
294 ~MallocRefCount() = default;
296 grpc_slice_refcount* base_refcount() { return &base_; }
299 grpc_slice_refcount base_;
300 grpc_core::RefCount refs_;
305 grpc_slice grpc_slice_malloc_large(size_t length) {
306 return grpc_core::UnmanagedMemorySlice(
307 length, grpc_core::UnmanagedMemorySlice::ForceHeapAllocation());
310 void grpc_core::UnmanagedMemorySlice::HeapInit(size_t length) {
311 /* Memory layout used by the slice created here:
313 +-----------+----------------------------------------------------------+
315 +-----------+----------------------------------------------------------+
317 refcount is a malloc_refcount
318 bytes is an array of bytes of the requested length
319 Both parts are placed in the same allocation returned from gpr_malloc */
321 static_cast<MallocRefCount*>(gpr_malloc(sizeof(MallocRefCount) + length));
323 /* Initial refcount on rc is 1 - and it's up to the caller to release
325 new (rc) MallocRefCount();
327 /* Build up the slice to be returned. */
328 /* The slices refcount points back to the allocated block. */
329 refcount = rc->base_refcount();
330 /* The data bytes are placed immediately after the refcount struct */
331 data.refcounted.bytes = reinterpret_cast<uint8_t*>(rc + 1);
332 /* And the length of the block is set to the requested length */
333 data.refcounted.length = length;
336 grpc_slice grpc_slice_malloc(size_t length) {
337 return grpc_core::UnmanagedMemorySlice(length);
340 grpc_core::UnmanagedMemorySlice::UnmanagedMemorySlice(size_t length) {
341 if (length > sizeof(data.inlined.bytes)) {
344 /* small slice: just inline the data */
346 data.inlined.length = static_cast<uint8_t>(length);
350 template <typename Slice>
351 static Slice sub_no_ref(const Slice& source, size_t begin, size_t end) {
354 GPR_ASSERT(end >= begin);
356 if (source.refcount) {
357 /* Enforce preconditions */
358 GPR_ASSERT(source.data.refcounted.length >= end);
360 /* Build the result */
361 subset.refcount = source.refcount->sub_refcount();
362 /* Point into the source array */
363 subset.data.refcounted.bytes = source.data.refcounted.bytes + begin;
364 subset.data.refcounted.length = end - begin;
366 /* Enforce preconditions */
367 GPR_ASSERT(source.data.inlined.length >= end);
368 subset.refcount = nullptr;
369 subset.data.inlined.length = static_cast<uint8_t>(end - begin);
370 memcpy(subset.data.inlined.bytes, source.data.inlined.bytes + begin,
376 grpc_slice grpc_slice_sub_no_ref(grpc_slice source, size_t begin, size_t end) {
377 return sub_no_ref(source, begin, end);
380 grpc_core::UnmanagedMemorySlice grpc_slice_sub_no_ref(
381 const grpc_core::UnmanagedMemorySlice& source, size_t begin, size_t end) {
382 return sub_no_ref(source, begin, end);
385 grpc_slice grpc_slice_sub(grpc_slice source, size_t begin, size_t end) {
388 if (end - begin <= sizeof(subset.data.inlined.bytes)) {
389 subset.refcount = nullptr;
390 subset.data.inlined.length = static_cast<uint8_t>(end - begin);
391 memcpy(subset.data.inlined.bytes, GRPC_SLICE_START_PTR(source) + begin,
394 subset = grpc_slice_sub_no_ref(source, begin, end);
395 /* Bump the refcount */
396 subset.refcount->Ref();
401 grpc_slice grpc_slice_split_tail_maybe_ref(grpc_slice* source, size_t split,
402 grpc_slice_ref_whom ref_whom) {
405 if (source->refcount == nullptr) {
406 /* inlined data, copy it out */
407 GPR_ASSERT(source->data.inlined.length >= split);
408 tail.refcount = nullptr;
409 tail.data.inlined.length =
410 static_cast<uint8_t>(source->data.inlined.length - split);
411 memcpy(tail.data.inlined.bytes, source->data.inlined.bytes + split,
412 tail.data.inlined.length);
413 source->data.inlined.length = static_cast<uint8_t>(split);
415 size_t tail_length = source->data.refcounted.length - split;
416 GPR_ASSERT(source->data.refcounted.length >= split);
417 if (tail_length < sizeof(tail.data.inlined.bytes) &&
418 ref_whom != GRPC_SLICE_REF_TAIL) {
419 /* Copy out the bytes - it'll be cheaper than refcounting */
420 tail.refcount = nullptr;
421 tail.data.inlined.length = static_cast<uint8_t>(tail_length);
422 memcpy(tail.data.inlined.bytes, source->data.refcounted.bytes + split,
424 source->refcount = source->refcount->sub_refcount();
426 /* Build the result */
428 case GRPC_SLICE_REF_TAIL:
429 tail.refcount = source->refcount->sub_refcount();
430 source->refcount = &grpc_core::kNoopRefcount;
432 case GRPC_SLICE_REF_HEAD:
433 tail.refcount = &grpc_core::kNoopRefcount;
434 source->refcount = source->refcount->sub_refcount();
436 case GRPC_SLICE_REF_BOTH:
437 tail.refcount = source->refcount->sub_refcount();
438 source->refcount = source->refcount->sub_refcount();
439 /* Bump the refcount */
440 tail.refcount->Ref();
443 /* Point into the source array */
444 tail.data.refcounted.bytes = source->data.refcounted.bytes + split;
445 tail.data.refcounted.length = tail_length;
447 source->data.refcounted.length = split;
453 grpc_slice grpc_slice_split_tail(grpc_slice* source, size_t split) {
454 return grpc_slice_split_tail_maybe_ref(source, split, GRPC_SLICE_REF_BOTH);
457 grpc_slice grpc_slice_split_head(grpc_slice* source, size_t split) {
460 if (source->refcount == nullptr) {
461 GPR_ASSERT(source->data.inlined.length >= split);
463 head.refcount = nullptr;
464 head.data.inlined.length = static_cast<uint8_t>(split);
465 memcpy(head.data.inlined.bytes, source->data.inlined.bytes, split);
466 source->data.inlined.length =
467 static_cast<uint8_t>(source->data.inlined.length - split);
468 memmove(source->data.inlined.bytes, source->data.inlined.bytes + split,
469 source->data.inlined.length);
470 } else if (split < sizeof(head.data.inlined.bytes)) {
471 GPR_ASSERT(source->data.refcounted.length >= split);
473 head.refcount = nullptr;
474 head.data.inlined.length = static_cast<uint8_t>(split);
475 memcpy(head.data.inlined.bytes, source->data.refcounted.bytes, split);
476 source->refcount = source->refcount->sub_refcount();
477 source->data.refcounted.bytes += split;
478 source->data.refcounted.length -= split;
480 GPR_ASSERT(source->data.refcounted.length >= split);
482 /* Build the result */
483 head.refcount = source->refcount->sub_refcount();
484 /* Bump the refcount */
485 head.refcount->Ref();
486 /* Point into the source array */
487 head.data.refcounted.bytes = source->data.refcounted.bytes;
488 head.data.refcounted.length = split;
489 source->refcount = source->refcount->sub_refcount();
490 source->data.refcounted.bytes += split;
491 source->data.refcounted.length -= split;
497 int grpc_slice_default_eq_impl(grpc_slice a, grpc_slice b) {
498 if (GRPC_SLICE_LENGTH(a) != GRPC_SLICE_LENGTH(b)) return false;
499 if (GRPC_SLICE_LENGTH(a) == 0) return true;
500 return 0 == memcmp(GRPC_SLICE_START_PTR(a), GRPC_SLICE_START_PTR(b),
501 GRPC_SLICE_LENGTH(a));
504 int grpc_slice_eq(grpc_slice a, grpc_slice b) {
505 if (a.refcount && b.refcount &&
506 a.refcount->GetType() == b.refcount->GetType()) {
507 return a.refcount->Eq(a, b);
509 return grpc_slice_default_eq_impl(a, b);
512 int grpc_slice_differs_refcounted(const grpc_slice& a,
513 const grpc_slice& b_not_inline) {
515 const uint8_t* a_ptr;
517 a_len = a.data.refcounted.length;
518 a_ptr = a.data.refcounted.bytes;
520 a_len = a.data.inlined.length;
521 a_ptr = &a.data.inlined.bytes[0];
523 if (a_len != b_not_inline.data.refcounted.length) {
529 // This check *must* occur after the a_len == 0 check
530 // to retain compatibility with grpc_slice_eq.
531 if (a_ptr == nullptr) {
534 return memcmp(a_ptr, b_not_inline.data.refcounted.bytes, a_len);
537 int grpc_slice_cmp(grpc_slice a, grpc_slice b) {
538 int d = static_cast<int>(GRPC_SLICE_LENGTH(a) - GRPC_SLICE_LENGTH(b));
539 if (d != 0) return d;
540 return memcmp(GRPC_SLICE_START_PTR(a), GRPC_SLICE_START_PTR(b),
541 GRPC_SLICE_LENGTH(a));
544 int grpc_slice_str_cmp(grpc_slice a, const char* b) {
545 size_t b_length = strlen(b);
546 int d = static_cast<int>(GRPC_SLICE_LENGTH(a) - b_length);
547 if (d != 0) return d;
548 return memcmp(GRPC_SLICE_START_PTR(a), b, b_length);
551 int grpc_slice_is_equivalent(grpc_slice a, grpc_slice b) {
552 if (a.refcount == nullptr || b.refcount == nullptr) {
553 return grpc_slice_eq(a, b);
555 return a.data.refcounted.length == b.data.refcounted.length &&
556 a.data.refcounted.bytes == b.data.refcounted.bytes;
559 int grpc_slice_buf_start_eq(grpc_slice a, const void* b, size_t len) {
560 if (GRPC_SLICE_LENGTH(a) < len) return 0;
561 return 0 == memcmp(GRPC_SLICE_START_PTR(a), b, len);
564 int grpc_slice_rchr(grpc_slice s, char c) {
565 const char* b = reinterpret_cast<const char*> GRPC_SLICE_START_PTR(s);
567 for (i = static_cast<int> GRPC_SLICE_LENGTH(s) - 1; i != -1 && b[i] != c;
573 int grpc_slice_chr(grpc_slice s, char c) {
574 const char* b = reinterpret_cast<const char*> GRPC_SLICE_START_PTR(s);
575 const char* p = static_cast<const char*>(memchr(b, c, GRPC_SLICE_LENGTH(s)));
576 return p == nullptr ? -1 : static_cast<int>(p - b);
579 int grpc_slice_slice(grpc_slice haystack, grpc_slice needle) {
580 size_t haystack_len = GRPC_SLICE_LENGTH(haystack);
581 const uint8_t* haystack_bytes = GRPC_SLICE_START_PTR(haystack);
582 size_t needle_len = GRPC_SLICE_LENGTH(needle);
583 const uint8_t* needle_bytes = GRPC_SLICE_START_PTR(needle);
585 if (haystack_len == 0 || needle_len == 0) return -1;
586 if (haystack_len < needle_len) return -1;
587 if (haystack_len == needle_len) {
588 return grpc_slice_eq(haystack, needle) ? 0 : -1;
590 if (needle_len == 1) {
591 return grpc_slice_chr(haystack, static_cast<char>(*needle_bytes));
594 const uint8_t* last = haystack_bytes + haystack_len - needle_len;
595 for (const uint8_t* cur = haystack_bytes; cur != last; ++cur) {
596 if (0 == memcmp(cur, needle_bytes, needle_len)) {
597 return static_cast<int>(cur - haystack_bytes);
603 grpc_slice grpc_slice_dup(grpc_slice a) {
604 grpc_slice copy = GRPC_SLICE_MALLOC(GRPC_SLICE_LENGTH(a));
605 memcpy(GRPC_SLICE_START_PTR(copy), GRPC_SLICE_START_PTR(a),
606 GRPC_SLICE_LENGTH(a));