diff --git a/include/grpc/event_engine/slice.h b/include/grpc/event_engine/slice.h index bb109230303..8d49f391600 100644 --- a/include/grpc/event_engine/slice.h +++ b/include/grpc/event_engine/slice.h @@ -178,8 +178,9 @@ struct CopyConstructors { } // namespace slice_detail -class MutableSlice : public slice_detail::BaseSlice, - public slice_detail::CopyConstructors { +class GPR_MSVC_EMPTY_BASE_CLASS_WORKAROUND MutableSlice + : public slice_detail::BaseSlice, + public slice_detail::CopyConstructors { public: MutableSlice() = default; explicit MutableSlice(const grpc_slice& slice); @@ -287,6 +288,16 @@ template <> struct SliceCastable {}; template <> struct SliceCastable {}; + +template <> +struct SliceCastable {}; +template <> +struct SliceCastable {}; + +template <> +struct SliceCastable {}; +template <> +struct SliceCastable {}; } // namespace internal } // namespace experimental diff --git a/include/grpc/event_engine/slice_buffer.h b/include/grpc/event_engine/slice_buffer.h index d2a8ecd81a3..6d0862e35b6 100644 --- a/include/grpc/event_engine/slice_buffer.h +++ b/include/grpc/event_engine/slice_buffer.h @@ -119,10 +119,17 @@ class SliceBuffer { /// associated slice. Slice RefSlice(size_t index); + /// Array access into the SliceBuffer. It returns a non mutable reference to + /// the slice at the specified index const Slice& operator[](size_t index) const { return internal::SliceCast(slice_buffer_.slices[index]); } + /// Return mutable reference to the slice at the specified index + Slice& MutableSliceAt(size_t index) const { + return internal::SliceCast(slice_buffer_.slices[index]); + } + /// The total number of bytes held by the SliceBuffer size_t Length() { return slice_buffer_.length; } diff --git a/src/core/lib/slice/slice.h b/src/core/lib/slice/slice.h index 9742d878c9f..0f85308a6e5 100644 --- a/src/core/lib/slice/slice.h +++ b/src/core/lib/slice/slice.h @@ -259,8 +259,9 @@ class StaticSlice : public slice_detail::BaseSlice, } }; -class MutableSlice : public slice_detail::BaseSlice, - public slice_detail::CopyConstructors { +class GPR_MSVC_EMPTY_BASE_CLASS_WORKAROUND MutableSlice + : public slice_detail::BaseSlice, + public slice_detail::CopyConstructors { public: MutableSlice() = default; explicit MutableSlice(const grpc_slice& slice) @@ -417,6 +418,16 @@ template <> struct SliceCastable {}; template <> struct SliceCastable {}; + +template <> +struct SliceCastable {}; +template <> +struct SliceCastable {}; + +template <> +struct SliceCastable {}; +template <> +struct SliceCastable {}; } // namespace internal } // namespace experimental } // namespace grpc_event_engine diff --git a/test/core/slice/slice_test.cc b/test/core/slice/slice_test.cc index b4abce706f8..346498f10d3 100644 --- a/test/core/slice/slice_test.cc +++ b/test/core/slice/slice_test.cc @@ -448,6 +448,19 @@ TEST(SliceTest, MutableSliceCastWorks) { EXPECT_EQ(&slice, &test.c_slice()); slice = grpc_slice_from_static_string("goodbye world!"); EXPECT_EQ(test.as_string_view(), "goodbye world!"); + + MutableSlice& m_cpp_slice = SliceCast(test); + EXPECT_EQ(&m_cpp_slice.c_slice(), &test.c_slice()); + m_cpp_slice = MutableSlice::FromCopiedString("hello world again!"); + // Change the first byte. + m_cpp_slice[0] = 'e'; + EXPECT_EQ(test.as_string_view(), "eello world again!"); + + MutableSlice& m_c_slice = SliceCast(slice); + EXPECT_EQ(&m_c_slice.c_slice(), &slice); + // Restore the first byte. + GRPC_SLICE_START_PTR(slice)[0] = 'h'; + EXPECT_EQ(m_c_slice.as_string_view(), "hello world again!"); } } // namespace