aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/lib/slice/slice.cc
diff options
context:
space:
mode:
authorGravatar Michael Darakananda <pongad@google.com>2017-10-10 15:07:28 +1100
committerGravatar Michael Darakananda <pongad@google.com>2017-10-10 15:07:28 +1100
commitdf6e3750b24a584daa823e01b2a69ac65f59af83 (patch)
tree659cbc6c0021d03564b516110abd4b09bd17ce82 /src/core/lib/slice/slice.cc
parentb268629245788bee994e96cb585a3ab2c78bafa8 (diff)
parentb6142ef1a6dc70565f468346c7935f43dbcb55fa (diff)
Merge branch 'master' into fix-php
Diffstat (limited to 'src/core/lib/slice/slice.cc')
-rw-r--r--src/core/lib/slice/slice.cc486
1 files changed, 486 insertions, 0 deletions
diff --git a/src/core/lib/slice/slice.cc b/src/core/lib/slice/slice.cc
new file mode 100644
index 0000000000..0764eda052
--- /dev/null
+++ b/src/core/lib/slice/slice.cc
@@ -0,0 +1,486 @@
+/*
+ *
+ * Copyright 2015 gRPC authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "src/core/lib/slice/slice_internal.h"
+
+#include <grpc/slice.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
+
+#include <string.h>
+
+#include "src/core/lib/iomgr/exec_ctx.h"
+
+char *grpc_slice_to_c_string(grpc_slice slice) {
+ char *out = (char *)gpr_malloc(GRPC_SLICE_LENGTH(slice) + 1);
+ memcpy(out, GRPC_SLICE_START_PTR(slice), GRPC_SLICE_LENGTH(slice));
+ out[GRPC_SLICE_LENGTH(slice)] = 0;
+ return out;
+}
+
+grpc_slice grpc_empty_slice(void) {
+ grpc_slice out;
+ out.refcount = NULL;
+ out.data.inlined.length = 0;
+ return out;
+}
+
+grpc_slice grpc_slice_copy(grpc_slice s) {
+ grpc_slice out = GRPC_SLICE_MALLOC(GRPC_SLICE_LENGTH(s));
+ memcpy(GRPC_SLICE_START_PTR(out), GRPC_SLICE_START_PTR(s),
+ GRPC_SLICE_LENGTH(s));
+ return out;
+}
+
+grpc_slice grpc_slice_ref_internal(grpc_slice slice) {
+ if (slice.refcount) {
+ slice.refcount->vtable->ref(slice.refcount);
+ }
+ return slice;
+}
+
+void grpc_slice_unref_internal(grpc_exec_ctx *exec_ctx, grpc_slice slice) {
+ if (slice.refcount) {
+ slice.refcount->vtable->unref(exec_ctx, slice.refcount);
+ }
+}
+
+/* Public API */
+grpc_slice grpc_slice_ref(grpc_slice slice) {
+ return grpc_slice_ref_internal(slice);
+}
+
+/* Public API */
+void grpc_slice_unref(grpc_slice slice) {
+ grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
+ grpc_slice_unref_internal(&exec_ctx, slice);
+ grpc_exec_ctx_finish(&exec_ctx);
+}
+
+/* grpc_slice_from_static_string support structure - a refcount that does
+ nothing */
+static void noop_ref(void *unused) {}
+static void noop_unref(grpc_exec_ctx *exec_ctx, void *unused) {}
+
+static const grpc_slice_refcount_vtable noop_refcount_vtable = {
+ noop_ref, noop_unref, grpc_slice_default_eq_impl,
+ grpc_slice_default_hash_impl};
+static grpc_slice_refcount noop_refcount = {&noop_refcount_vtable,
+ &noop_refcount};
+
+grpc_slice grpc_slice_from_static_buffer(const void *s, size_t len) {
+ grpc_slice slice;
+ slice.refcount = &noop_refcount;
+ slice.data.refcounted.bytes = (uint8_t *)s;
+ slice.data.refcounted.length = len;
+ return slice;
+}
+
+grpc_slice grpc_slice_from_static_string(const char *s) {
+ return grpc_slice_from_static_buffer(s, strlen(s));
+}
+
+/* grpc_slice_new support structures - we create a refcount object extended
+ with the user provided data pointer & destroy function */
+typedef struct new_slice_refcount {
+ grpc_slice_refcount rc;
+ gpr_refcount refs;
+ void (*user_destroy)(void *);
+ void *user_data;
+} new_slice_refcount;
+
+static void new_slice_ref(void *p) {
+ new_slice_refcount *r = (new_slice_refcount *)p;
+ gpr_ref(&r->refs);
+}
+
+static void new_slice_unref(grpc_exec_ctx *exec_ctx, void *p) {
+ new_slice_refcount *r = (new_slice_refcount *)p;
+ if (gpr_unref(&r->refs)) {
+ r->user_destroy(r->user_data);
+ gpr_free(r);
+ }
+}
+
+static const grpc_slice_refcount_vtable new_slice_vtable = {
+ new_slice_ref, new_slice_unref, grpc_slice_default_eq_impl,
+ grpc_slice_default_hash_impl};
+
+grpc_slice grpc_slice_new_with_user_data(void *p, size_t len,
+ void (*destroy)(void *),
+ void *user_data) {
+ grpc_slice slice;
+ new_slice_refcount *rc =
+ (new_slice_refcount *)gpr_malloc(sizeof(new_slice_refcount));
+ gpr_ref_init(&rc->refs, 1);
+ rc->rc.vtable = &new_slice_vtable;
+ rc->rc.sub_refcount = &rc->rc;
+ rc->user_destroy = destroy;
+ rc->user_data = user_data;
+
+ slice.refcount = &rc->rc;
+ slice.data.refcounted.bytes = (uint8_t *)p;
+ slice.data.refcounted.length = len;
+ return slice;
+}
+
+grpc_slice grpc_slice_new(void *p, size_t len, void (*destroy)(void *)) {
+ /* Pass "p" to *destroy when the slice is no longer needed. */
+ return grpc_slice_new_with_user_data(p, len, destroy, p);
+}
+
+/* grpc_slice_new_with_len support structures - we create a refcount object
+ extended with the user provided data pointer & destroy function */
+typedef struct new_with_len_slice_refcount {
+ grpc_slice_refcount rc;
+ gpr_refcount refs;
+ void *user_data;
+ size_t user_length;
+ void (*user_destroy)(void *, size_t);
+} new_with_len_slice_refcount;
+
+static void new_with_len_ref(void *p) {
+ new_with_len_slice_refcount *r = (new_with_len_slice_refcount *)p;
+ gpr_ref(&r->refs);
+}
+
+static void new_with_len_unref(grpc_exec_ctx *exec_ctx, void *p) {
+ new_with_len_slice_refcount *r = (new_with_len_slice_refcount *)p;
+ if (gpr_unref(&r->refs)) {
+ r->user_destroy(r->user_data, r->user_length);
+ gpr_free(r);
+ }
+}
+
+static const grpc_slice_refcount_vtable new_with_len_vtable = {
+ new_with_len_ref, new_with_len_unref, grpc_slice_default_eq_impl,
+ grpc_slice_default_hash_impl};
+
+grpc_slice grpc_slice_new_with_len(void *p, size_t len,
+ void (*destroy)(void *, size_t)) {
+ grpc_slice slice;
+ new_with_len_slice_refcount *rc = (new_with_len_slice_refcount *)gpr_malloc(
+ sizeof(new_with_len_slice_refcount));
+ gpr_ref_init(&rc->refs, 1);
+ rc->rc.vtable = &new_with_len_vtable;
+ rc->rc.sub_refcount = &rc->rc;
+ rc->user_destroy = destroy;
+ rc->user_data = p;
+ rc->user_length = len;
+
+ slice.refcount = &rc->rc;
+ slice.data.refcounted.bytes = (uint8_t *)p;
+ slice.data.refcounted.length = len;
+ return slice;
+}
+
+grpc_slice grpc_slice_from_copied_buffer(const char *source, size_t length) {
+ if (length == 0) return grpc_empty_slice();
+ grpc_slice slice = GRPC_SLICE_MALLOC(length);
+ memcpy(GRPC_SLICE_START_PTR(slice), source, length);
+ return slice;
+}
+
+grpc_slice grpc_slice_from_copied_string(const char *source) {
+ return grpc_slice_from_copied_buffer(source, strlen(source));
+}
+
+typedef struct {
+ grpc_slice_refcount base;
+ gpr_refcount refs;
+} malloc_refcount;
+
+static void malloc_ref(void *p) {
+ malloc_refcount *r = (malloc_refcount *)p;
+ gpr_ref(&r->refs);
+}
+
+static void malloc_unref(grpc_exec_ctx *exec_ctx, void *p) {
+ malloc_refcount *r = (malloc_refcount *)p;
+ if (gpr_unref(&r->refs)) {
+ gpr_free(r);
+ }
+}
+
+static const grpc_slice_refcount_vtable malloc_vtable = {
+ malloc_ref, malloc_unref, grpc_slice_default_eq_impl,
+ grpc_slice_default_hash_impl};
+
+grpc_slice grpc_slice_malloc_large(size_t length) {
+ grpc_slice slice;
+
+ /* Memory layout used by the slice created here:
+
+ +-----------+----------------------------------------------------------+
+ | refcount | bytes |
+ +-----------+----------------------------------------------------------+
+
+ refcount is a malloc_refcount
+ bytes is an array of bytes of the requested length
+ Both parts are placed in the same allocation returned from gpr_malloc */
+ malloc_refcount *rc =
+ (malloc_refcount *)gpr_malloc(sizeof(malloc_refcount) + length);
+
+ /* Initial refcount on rc is 1 - and it's up to the caller to release
+ this reference. */
+ gpr_ref_init(&rc->refs, 1);
+
+ rc->base.vtable = &malloc_vtable;
+ rc->base.sub_refcount = &rc->base;
+
+ /* Build up the slice to be returned. */
+ /* The slices refcount points back to the allocated block. */
+ slice.refcount = &rc->base;
+ /* The data bytes are placed immediately after the refcount struct */
+ slice.data.refcounted.bytes = (uint8_t *)(rc + 1);
+ /* And the length of the block is set to the requested length */
+ slice.data.refcounted.length = length;
+ return slice;
+}
+
+grpc_slice grpc_slice_malloc(size_t length) {
+ grpc_slice slice;
+
+ if (length > sizeof(slice.data.inlined.bytes)) {
+ return grpc_slice_malloc_large(length);
+ } else {
+ /* small slice: just inline the data */
+ slice.refcount = NULL;
+ slice.data.inlined.length = (uint8_t)length;
+ }
+ return slice;
+}
+
+grpc_slice grpc_slice_sub_no_ref(grpc_slice source, size_t begin, size_t end) {
+ grpc_slice subset;
+
+ GPR_ASSERT(end >= begin);
+
+ if (source.refcount) {
+ /* Enforce preconditions */
+ GPR_ASSERT(source.data.refcounted.length >= end);
+
+ /* Build the result */
+ subset.refcount = source.refcount->sub_refcount;
+ /* Point into the source array */
+ subset.data.refcounted.bytes = source.data.refcounted.bytes + begin;
+ subset.data.refcounted.length = end - begin;
+ } else {
+ /* Enforce preconditions */
+ GPR_ASSERT(source.data.inlined.length >= end);
+ subset.refcount = NULL;
+ subset.data.inlined.length = (uint8_t)(end - begin);
+ memcpy(subset.data.inlined.bytes, source.data.inlined.bytes + begin,
+ end - begin);
+ }
+ return subset;
+}
+
+grpc_slice grpc_slice_sub(grpc_slice source, size_t begin, size_t end) {
+ grpc_slice subset;
+
+ if (end - begin <= sizeof(subset.data.inlined.bytes)) {
+ subset.refcount = NULL;
+ subset.data.inlined.length = (uint8_t)(end - begin);
+ memcpy(subset.data.inlined.bytes, GRPC_SLICE_START_PTR(source) + begin,
+ end - begin);
+ } else {
+ subset = grpc_slice_sub_no_ref(source, begin, end);
+ /* Bump the refcount */
+ subset.refcount->vtable->ref(subset.refcount);
+ }
+ return subset;
+}
+
+grpc_slice grpc_slice_split_tail_maybe_ref(grpc_slice *source, size_t split,
+ grpc_slice_ref_whom ref_whom) {
+ grpc_slice tail;
+
+ if (source->refcount == NULL) {
+ /* inlined data, copy it out */
+ GPR_ASSERT(source->data.inlined.length >= split);
+ tail.refcount = NULL;
+ tail.data.inlined.length = (uint8_t)(source->data.inlined.length - split);
+ memcpy(tail.data.inlined.bytes, source->data.inlined.bytes + split,
+ tail.data.inlined.length);
+ source->data.inlined.length = (uint8_t)split;
+ } else {
+ size_t tail_length = source->data.refcounted.length - split;
+ GPR_ASSERT(source->data.refcounted.length >= split);
+ if (tail_length < sizeof(tail.data.inlined.bytes) &&
+ ref_whom != GRPC_SLICE_REF_TAIL) {
+ /* Copy out the bytes - it'll be cheaper than refcounting */
+ tail.refcount = NULL;
+ tail.data.inlined.length = (uint8_t)tail_length;
+ memcpy(tail.data.inlined.bytes, source->data.refcounted.bytes + split,
+ tail_length);
+ source->refcount = source->refcount->sub_refcount;
+ } else {
+ /* Build the result */
+ switch (ref_whom) {
+ case GRPC_SLICE_REF_TAIL:
+ tail.refcount = source->refcount->sub_refcount;
+ source->refcount = &noop_refcount;
+ break;
+ case GRPC_SLICE_REF_HEAD:
+ tail.refcount = &noop_refcount;
+ source->refcount = source->refcount->sub_refcount;
+ break;
+ case GRPC_SLICE_REF_BOTH:
+ tail.refcount = source->refcount->sub_refcount;
+ source->refcount = source->refcount->sub_refcount;
+ /* Bump the refcount */
+ tail.refcount->vtable->ref(tail.refcount);
+ break;
+ }
+ /* Point into the source array */
+ tail.data.refcounted.bytes = source->data.refcounted.bytes + split;
+ tail.data.refcounted.length = tail_length;
+ }
+ source->data.refcounted.length = split;
+ }
+
+ return tail;
+}
+
+grpc_slice grpc_slice_split_tail(grpc_slice *source, size_t split) {
+ return grpc_slice_split_tail_maybe_ref(source, split, GRPC_SLICE_REF_BOTH);
+}
+
+grpc_slice grpc_slice_split_head(grpc_slice *source, size_t split) {
+ grpc_slice head;
+
+ if (source->refcount == NULL) {
+ GPR_ASSERT(source->data.inlined.length >= split);
+
+ head.refcount = NULL;
+ head.data.inlined.length = (uint8_t)split;
+ memcpy(head.data.inlined.bytes, source->data.inlined.bytes, split);
+ source->data.inlined.length =
+ (uint8_t)(source->data.inlined.length - split);
+ memmove(source->data.inlined.bytes, source->data.inlined.bytes + split,
+ source->data.inlined.length);
+ } else if (split < sizeof(head.data.inlined.bytes)) {
+ GPR_ASSERT(source->data.refcounted.length >= split);
+
+ head.refcount = NULL;
+ head.data.inlined.length = (uint8_t)split;
+ memcpy(head.data.inlined.bytes, source->data.refcounted.bytes, split);
+ source->refcount = source->refcount->sub_refcount;
+ source->data.refcounted.bytes += split;
+ source->data.refcounted.length -= split;
+ } else {
+ GPR_ASSERT(source->data.refcounted.length >= split);
+
+ /* Build the result */
+ head.refcount = source->refcount->sub_refcount;
+ /* Bump the refcount */
+ head.refcount->vtable->ref(head.refcount);
+ /* Point into the source array */
+ head.data.refcounted.bytes = source->data.refcounted.bytes;
+ head.data.refcounted.length = split;
+ source->refcount = source->refcount->sub_refcount;
+ source->data.refcounted.bytes += split;
+ source->data.refcounted.length -= split;
+ }
+
+ return head;
+}
+
+int grpc_slice_default_eq_impl(grpc_slice a, grpc_slice b) {
+ if (GRPC_SLICE_LENGTH(a) != GRPC_SLICE_LENGTH(b)) return false;
+ if (GRPC_SLICE_LENGTH(a) == 0) return true;
+ return 0 == memcmp(GRPC_SLICE_START_PTR(a), GRPC_SLICE_START_PTR(b),
+ GRPC_SLICE_LENGTH(a));
+}
+
+int grpc_slice_eq(grpc_slice a, grpc_slice b) {
+ if (a.refcount && b.refcount && a.refcount->vtable == b.refcount->vtable) {
+ return a.refcount->vtable->eq(a, b);
+ }
+ return grpc_slice_default_eq_impl(a, b);
+}
+
+int grpc_slice_cmp(grpc_slice a, grpc_slice b) {
+ int d = (int)(GRPC_SLICE_LENGTH(a) - GRPC_SLICE_LENGTH(b));
+ if (d != 0) return d;
+ return memcmp(GRPC_SLICE_START_PTR(a), GRPC_SLICE_START_PTR(b),
+ GRPC_SLICE_LENGTH(a));
+}
+
+int grpc_slice_str_cmp(grpc_slice a, const char *b) {
+ size_t b_length = strlen(b);
+ int d = (int)(GRPC_SLICE_LENGTH(a) - b_length);
+ if (d != 0) return d;
+ return memcmp(GRPC_SLICE_START_PTR(a), b, b_length);
+}
+
+int grpc_slice_is_equivalent(grpc_slice a, grpc_slice b) {
+ if (a.refcount == NULL || b.refcount == NULL) {
+ return grpc_slice_eq(a, b);
+ }
+ return a.data.refcounted.length == b.data.refcounted.length &&
+ a.data.refcounted.bytes == b.data.refcounted.bytes;
+}
+
+int grpc_slice_buf_start_eq(grpc_slice a, const void *b, size_t len) {
+ if (GRPC_SLICE_LENGTH(a) < len) return 0;
+ return 0 == memcmp(GRPC_SLICE_START_PTR(a), b, len);
+}
+
+int grpc_slice_rchr(grpc_slice s, char c) {
+ const char *b = (const char *)GRPC_SLICE_START_PTR(s);
+ int i;
+ for (i = (int)GRPC_SLICE_LENGTH(s) - 1; i != -1 && b[i] != c; i--)
+ ;
+ return i;
+}
+
+int grpc_slice_chr(grpc_slice s, char c) {
+ const char *b = (const char *)GRPC_SLICE_START_PTR(s);
+ const char *p = (const char *)memchr(b, c, GRPC_SLICE_LENGTH(s));
+ return p == NULL ? -1 : (int)(p - b);
+}
+
+int grpc_slice_slice(grpc_slice haystack, grpc_slice needle) {
+ size_t haystack_len = GRPC_SLICE_LENGTH(haystack);
+ const uint8_t *haystack_bytes = GRPC_SLICE_START_PTR(haystack);
+ size_t needle_len = GRPC_SLICE_LENGTH(needle);
+ const uint8_t *needle_bytes = GRPC_SLICE_START_PTR(needle);
+
+ if (haystack_len == 0 || needle_len == 0) return -1;
+ if (haystack_len < needle_len) return -1;
+ if (haystack_len == needle_len)
+ return grpc_slice_eq(haystack, needle) ? 0 : -1;
+ if (needle_len == 1) return grpc_slice_chr(haystack, (char)*needle_bytes);
+
+ const uint8_t *last = haystack_bytes + haystack_len - needle_len;
+ for (const uint8_t *cur = haystack_bytes; cur != last; ++cur) {
+ if (0 == memcmp(cur, needle_bytes, needle_len)) {
+ return (int)(cur - haystack_bytes);
+ }
+ }
+ return -1;
+}
+
+grpc_slice grpc_slice_dup(grpc_slice a) {
+ grpc_slice copy = GRPC_SLICE_MALLOC(GRPC_SLICE_LENGTH(a));
+ memcpy(GRPC_SLICE_START_PTR(copy), GRPC_SLICE_START_PTR(a),
+ GRPC_SLICE_LENGTH(a));
+ return copy;
+}