diff --git a/include/grpc++/support/slice.h b/include/grpc++/support/slice.h index 0b4ba7cecb4..bbf97f280ef 100644 --- a/include/grpc++/support/slice.h +++ b/include/grpc++/support/slice.h @@ -67,6 +67,20 @@ class Slice final { return *this; } + /// Create a slice pointing at some data. Calls malloc to allocate a refcount + /// for the object, and arranges that destroy will be called with the + /// user data pointer passed in at destruction. Can be the same as buf or + /// different (e.g., if data is part of a larger structure that must be + /// destroyed when the data is no longer needed) + Slice(void* buf, size_t len, void (*destroy)(void*), void* user_data); + + /// Specialization of above for common case where buf == user_data + Slice(void* buf, size_t len, void (*destroy)(void*)) + : Slice(buf, len, destroy, buf) {} + + /// Similar to the above but has a destroy that also takes slice length + Slice(void* buf, size_t len, void (*destroy)(void*, size_t)); + /// Byte size. size_t size() const { return GRPC_SLICE_LENGTH(slice_); } diff --git a/src/cpp/util/slice_cc.cc b/src/cpp/util/slice_cc.cc index 56e0328b949..486d0cdf0ec 100644 --- a/src/cpp/util/slice_cc.cc +++ b/src/cpp/util/slice_cc.cc @@ -17,6 +17,7 @@ */ #include +#include namespace grpc { @@ -43,4 +44,10 @@ Slice::Slice(const void* buf, size_t len, StaticSlice) Slice::Slice(const Slice& other) : slice_(grpc_slice_ref(other.slice_)) {} +Slice::Slice(void* buf, size_t len, void (*destroy)(void*), void* user_data) + : slice_(grpc_slice_new_with_user_data(buf, len, destroy, user_data)) {} + +Slice::Slice(void* buf, size_t len, void (*destroy)(void*, size_t)) + : slice_(grpc_slice_new_with_len(buf, len, destroy)) {} + } // namespace grpc diff --git a/test/cpp/util/slice_test.cc b/test/cpp/util/slice_test.cc index 9e3329fab02..8a8962d7ee0 100644 --- a/test/cpp/util/slice_test.cc +++ b/test/cpp/util/slice_test.cc @@ -63,6 +63,42 @@ TEST_F(SliceTest, StaticBuf) { CheckSlice(spp, kContent); } +TEST_F(SliceTest, SliceNew) { + char* x = new char[strlen(kContent) + 1]; + strcpy(x, kContent); + Slice spp(x, strlen(x), [](void* p) { delete[] reinterpret_cast(p); }); + CheckSlice(spp, kContent); +} + +TEST_F(SliceTest, SliceNewDoNothing) { + Slice spp(const_cast(kContent), strlen(kContent), [](void* p) {}); + CheckSlice(spp, kContent); +} + +TEST_F(SliceTest, SliceNewWithUserData) { + struct stest { + char* x; + int y; + }; + auto* t = new stest; + t->x = new char[strlen(kContent) + 1]; + strcpy(t->x, kContent); + Slice spp(t->x, strlen(t->x), + [](void* p) { + auto* t = reinterpret_cast(p); + delete[] t->x; + delete t; + }, + t); + CheckSlice(spp, kContent); +} + +TEST_F(SliceTest, SliceNewLen) { + Slice spp(const_cast(kContent), strlen(kContent), + [](void* p, size_t l) { EXPECT_EQ(l, strlen(kContent)); }); + CheckSlice(spp, kContent); +} + TEST_F(SliceTest, Steal) { grpc_slice s = grpc_slice_from_copied_string(kContent); Slice spp(s, Slice::STEAL_REF);