Add gpr_slice_new_with_user_data.

gpr_slice_new_with_user_data is like gpr_slice_new, but allows the
caller to specify a distinct pointer to pass to the destroy function.
This is useful when the data is part of a larger data structure that
should be destroyed when the data is no longer needed.
pull/7488/head
Sanjay Ghemawat 8 years ago
parent 76692bb283
commit fca59fb2aa
  1. 8
      include/grpc/impl/codegen/slice.h
  2. 11
      src/core/lib/support/slice.c
  3. 22
      test/core/support/slice_test.c

@ -120,6 +120,14 @@ GPRAPI void gpr_slice_unref(gpr_slice s);
passed in at destruction. */ passed in at destruction. */
GPRAPI gpr_slice gpr_slice_new(void *p, size_t len, void (*destroy)(void *)); GPRAPI gpr_slice gpr_slice_new(void *p, size_t len, void (*destroy)(void *));
/* Equivalent to gpr_slice_new, but with a separate pointer that is
passed to the destroy function. This function can be useful when
the data is part of a larger structure that must be destroyed when
the data is no longer needed. */
GPRAPI gpr_slice gpr_slice_new_with_user_data(void *p, size_t len,
void (*destroy)(void *),
void *user_data);
/* Equivalent to gpr_slice_new, but with a two argument destroy function that /* Equivalent to gpr_slice_new, but with a two argument destroy function that
also takes the slice length. */ also takes the slice length. */
GPRAPI gpr_slice gpr_slice_new_with_len(void *p, size_t len, GPRAPI gpr_slice gpr_slice_new_with_len(void *p, size_t len,

@ -94,14 +94,16 @@ static void new_slice_unref(void *p) {
} }
} }
gpr_slice gpr_slice_new(void *p, size_t len, void (*destroy)(void *)) { gpr_slice gpr_slice_new_with_user_data(void *p, size_t len,
void (*destroy)(void *),
void *user_data) {
gpr_slice slice; gpr_slice slice;
new_slice_refcount *rc = gpr_malloc(sizeof(new_slice_refcount)); new_slice_refcount *rc = gpr_malloc(sizeof(new_slice_refcount));
gpr_ref_init(&rc->refs, 1); gpr_ref_init(&rc->refs, 1);
rc->rc.ref = new_slice_ref; rc->rc.ref = new_slice_ref;
rc->rc.unref = new_slice_unref; rc->rc.unref = new_slice_unref;
rc->user_destroy = destroy; rc->user_destroy = destroy;
rc->user_data = p; rc->user_data = user_data;
slice.refcount = &rc->rc; slice.refcount = &rc->rc;
slice.data.refcounted.bytes = p; slice.data.refcounted.bytes = p;
@ -109,6 +111,11 @@ gpr_slice gpr_slice_new(void *p, size_t len, void (*destroy)(void *)) {
return slice; return slice;
} }
gpr_slice gpr_slice_new(void *p, size_t len, void (*destroy)(void *)) {
/* Pass "p" to *destroy when the slice is no longer needed. */
return gpr_slice_new_with_user_data(p, len, destroy, p);
}
/* gpr_slice_new_with_len support structures - we create a refcount object /* gpr_slice_new_with_len support structures - we create a refcount object
extended with the user provided data pointer & destroy function */ extended with the user provided data pointer & destroy function */
typedef struct new_with_len_slice_refcount { typedef struct new_with_len_slice_refcount {

@ -85,6 +85,27 @@ static void test_slice_new_returns_something_sensible(void) {
gpr_slice_unref(slice); gpr_slice_unref(slice);
} }
/* destroy function that sets a mark to indicate it was called. */
static void set_mark(void *p) { *((int *)p) = 1; }
static void test_slice_new_with_user_data(void) {
int marker = 0;
uint8_t buf[2];
gpr_slice slice;
buf[0] = 0;
buf[1] = 1;
slice = gpr_slice_new_with_user_data(buf, 2, set_mark, &marker);
GPR_ASSERT(marker == 0);
GPR_ASSERT(GPR_SLICE_LENGTH(slice) == 2);
GPR_ASSERT(GPR_SLICE_START_PTR(slice)[0] == 0);
GPR_ASSERT(GPR_SLICE_START_PTR(slice)[1] == 1);
/* unref should cause destroy function to run. */
gpr_slice_unref(slice);
GPR_ASSERT(marker == 1);
}
static int do_nothing_with_len_1_calls = 0; static int do_nothing_with_len_1_calls = 0;
static void do_nothing_with_len_1(void *ignored, size_t len) { static void do_nothing_with_len_1(void *ignored, size_t len) {
@ -232,6 +253,7 @@ int main(int argc, char **argv) {
grpc_test_init(argc, argv); grpc_test_init(argc, argv);
test_slice_malloc_returns_something_sensible(); test_slice_malloc_returns_something_sensible();
test_slice_new_returns_something_sensible(); test_slice_new_returns_something_sensible();
test_slice_new_with_user_data();
test_slice_new_with_len_returns_something_sensible(); test_slice_new_with_len_returns_something_sensible();
for (length = 0; length < 128; length++) { for (length = 0; length < 128; length++) {
test_slice_sub_works(length); test_slice_sub_works(length);

Loading…
Cancel
Save