diff --git a/include/grpc/slice_buffer.h b/include/grpc/slice_buffer.h index f1de653af41..ebd0db7620a 100644 --- a/include/grpc/slice_buffer.h +++ b/include/grpc/slice_buffer.h @@ -77,8 +77,14 @@ GPRAPI void grpc_slice_buffer_trim_end(grpc_slice_buffer *src, size_t n, /* move the first n bytes of src into dst */ GPRAPI void grpc_slice_buffer_move_first(grpc_slice_buffer *src, size_t n, grpc_slice_buffer *dst); +/* move the first n bytes of src into dst (copying them) */ +GPRAPI void grpc_slice_buffer_move_first_into_buffer(grpc_slice_buffer *src, + size_t n, void *dst); /* take the first slice in the slice buffer */ GPRAPI grpc_slice grpc_slice_buffer_take_first(grpc_slice_buffer *src); +/* undo the above with (a possibly different) \a slice */ +GPRAPI void grpc_slice_buffer_undo_take_first(grpc_slice_buffer *src, + grpc_slice slice); #ifdef __cplusplus } diff --git a/src/core/lib/slice/slice_buffer.c b/src/core/lib/slice/slice_buffer.c index a76b86f1d51..84fa89684f0 100644 --- a/src/core/lib/slice/slice_buffer.c +++ b/src/core/lib/slice/slice_buffer.c @@ -254,7 +254,6 @@ void grpc_slice_buffer_move_into(grpc_slice_buffer *src, void grpc_slice_buffer_move_first(grpc_slice_buffer *src, size_t n, grpc_slice_buffer *dst) { - size_t src_idx; size_t output_len = dst->length + n; size_t new_input_len = src->length - n; GPR_ASSERT(src->length >= n); @@ -263,34 +262,53 @@ void grpc_slice_buffer_move_first(grpc_slice_buffer *src, size_t n, return; } - src_idx = 0; - while (src_idx < src->count) { - grpc_slice slice = src->slices[src_idx]; + while (src->count > 0) { + grpc_slice slice = grpc_slice_buffer_take_first(src); size_t slice_len = GRPC_SLICE_LENGTH(slice); if (n > slice_len) { grpc_slice_buffer_add(dst, slice); n -= slice_len; - src_idx++; } else if (n == slice_len) { grpc_slice_buffer_add(dst, slice); - src_idx++; break; } else { /* n < slice_len */ - src->slices[src_idx] = grpc_slice_split_tail(&slice, n); + grpc_slice_buffer_undo_take_first(src, grpc_slice_split_tail(&slice, n)); GPR_ASSERT(GRPC_SLICE_LENGTH(slice) == n); - GPR_ASSERT(GRPC_SLICE_LENGTH(src->slices[src_idx]) == slice_len - n); grpc_slice_buffer_add(dst, slice); break; } } GPR_ASSERT(dst->length == output_len); - memmove(src->slices, src->slices + src_idx, - sizeof(grpc_slice) * (src->count - src_idx)); - src->count -= src_idx; - src->length = new_input_len; + GPR_ASSERT(src->length == new_input_len); GPR_ASSERT(src->count > 0); } +void grpc_slice_buffer_move_first_into_buffer(grpc_slice_buffer *src, size_t n, + void *dst) { + char *dstp = dst; + GPR_ASSERT(src->length >= n); + + while (n > 0) { + grpc_slice slice = grpc_slice_buffer_take_first(src); + size_t slice_len = GRPC_SLICE_LENGTH(slice); + if (slice_len > n) { + memcpy(dstp, GRPC_SLICE_START_PTR(slice), n); + grpc_slice_buffer_undo_take_first( + src, grpc_slice_sub_no_ref(slice, n, slice_len)); + n = 0; + } else if (slice_len == n) { + memcpy(dstp, GRPC_SLICE_START_PTR(slice), n); + grpc_slice_unref(slice); + n = 0; + } else { + memcpy(dstp, GRPC_SLICE_START_PTR(slice), slice_len); + dstp += slice_len; + n -= slice_len; + grpc_slice_unref(slice); + } + } +} + void grpc_slice_buffer_trim_end(grpc_slice_buffer *sb, size_t n, grpc_slice_buffer *garbage) { GPR_ASSERT(n <= sb->length); @@ -325,3 +343,11 @@ grpc_slice grpc_slice_buffer_take_first(grpc_slice_buffer *sb) { return slice; } + +void grpc_slice_buffer_undo_take_first(grpc_slice_buffer *sb, + grpc_slice slice) { + sb->slices--; + sb->slices[0] = slice; + sb->count++; + sb->length += GRPC_SLICE_LENGTH(slice); +}