mirror of https://github.com/grpc/grpc.git
A starter slice buffer implementation to unblock event engine endpoints (#29367)
* A starter SliceBuffer implementation * Add comments and fix sanity checks * Minor fixes * more minor fixes * Addressing review comments and adding a slice_buffer_test * fix sanity checks * regenerate projects * fixing undefined function error * reverting changes from memory_allocator.cc and adding them to src/core/lib/slice/slice_buffer.cc to allow memory allocator lib to build correctly * fix sanity checks * adding an open source slice definition * regnerate projects * fix asan error * Automated change: Fix sanity tests * addressing review comments * fix sanity checks * regenerate projects * update * fix sanity checks * Converting slice buffer to retarin ownership of the underlying ctype * fix nits Co-authored-by: Vignesh2208 <Vignesh2208@users.noreply.github.com>pull/29647/head
parent
4ab3103293
commit
1494b1ef26
26 changed files with 841 additions and 77 deletions
@ -0,0 +1,286 @@ |
|||||||
|
// Copyright 2022 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.
|
||||||
|
|
||||||
|
#ifndef GRPC_EVENT_ENGINE_SLICE_H |
||||||
|
#define GRPC_EVENT_ENGINE_SLICE_H |
||||||
|
|
||||||
|
#include <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#include <string.h> |
||||||
|
|
||||||
|
#include <cstdint> |
||||||
|
#include <string> |
||||||
|
#include <utility> |
||||||
|
|
||||||
|
#include "absl/strings/string_view.h" |
||||||
|
|
||||||
|
#include <grpc/slice.h> |
||||||
|
#include <grpc/support/log.h> |
||||||
|
|
||||||
|
// This public slice definition largely based of the internal grpc_core::Slice
|
||||||
|
// implementation. Changes to this implementation might warrant changes to the
|
||||||
|
// internal grpc_core::Slice type as well.
|
||||||
|
|
||||||
|
namespace grpc_event_engine { |
||||||
|
namespace experimental { |
||||||
|
|
||||||
|
// Forward declarations
|
||||||
|
class Slice; |
||||||
|
class MutableSlice; |
||||||
|
|
||||||
|
namespace slice_detail { |
||||||
|
|
||||||
|
// Returns an empty slice.
|
||||||
|
static constexpr grpc_slice EmptySlice() { return {nullptr, {}}; } |
||||||
|
|
||||||
|
// BaseSlice holds the grpc_slice object, but does not apply refcounting policy.
|
||||||
|
// It does export immutable access into the slice, such that this can be shared
|
||||||
|
// by all storage policies.
|
||||||
|
class BaseSlice { |
||||||
|
public: |
||||||
|
BaseSlice(const BaseSlice&) = delete; |
||||||
|
BaseSlice& operator=(const BaseSlice&) = delete; |
||||||
|
BaseSlice(BaseSlice&& other) = delete; |
||||||
|
BaseSlice& operator=(BaseSlice&& other) = delete; |
||||||
|
|
||||||
|
// Iterator access to the underlying bytes
|
||||||
|
const uint8_t* begin() const { return GRPC_SLICE_START_PTR(c_slice()); } |
||||||
|
const uint8_t* end() const { return GRPC_SLICE_END_PTR(c_slice()); } |
||||||
|
const uint8_t* cbegin() const { return GRPC_SLICE_START_PTR(c_slice()); } |
||||||
|
const uint8_t* cend() const { return GRPC_SLICE_END_PTR(c_slice()); } |
||||||
|
|
||||||
|
// Retrieve a borrowed reference to the underlying grpc_slice.
|
||||||
|
const grpc_slice& c_slice() const { return slice_; } |
||||||
|
|
||||||
|
// Retrieve the underlying grpc_slice, and replace the one in this object with
|
||||||
|
// EmptySlice().
|
||||||
|
grpc_slice TakeCSlice() { |
||||||
|
grpc_slice out = slice_; |
||||||
|
slice_ = EmptySlice(); |
||||||
|
return out; |
||||||
|
} |
||||||
|
|
||||||
|
// As other things... borrowed references.
|
||||||
|
absl::string_view as_string_view() const { |
||||||
|
return absl::string_view(reinterpret_cast<const char*>(data()), size()); |
||||||
|
} |
||||||
|
|
||||||
|
// Array access
|
||||||
|
uint8_t operator[](size_t i) const { |
||||||
|
return GRPC_SLICE_START_PTR(c_slice())[i]; |
||||||
|
} |
||||||
|
|
||||||
|
// Access underlying data
|
||||||
|
const uint8_t* data() const { return GRPC_SLICE_START_PTR(c_slice()); } |
||||||
|
|
||||||
|
// Size of the slice
|
||||||
|
size_t size() const { return GRPC_SLICE_LENGTH(c_slice()); } |
||||||
|
size_t length() const { return size(); } |
||||||
|
bool empty() const { return size() == 0; } |
||||||
|
|
||||||
|
// For inlined slices - are these two slices equal?
|
||||||
|
// For non-inlined slices - do these two slices refer to the same block of
|
||||||
|
// memory?
|
||||||
|
bool is_equivalent(const BaseSlice& other) const { |
||||||
|
return grpc_slice_is_equivalent(slice_, other.slice_); |
||||||
|
} |
||||||
|
|
||||||
|
uint32_t Hash() const; |
||||||
|
|
||||||
|
protected: |
||||||
|
BaseSlice() : slice_(EmptySlice()) {} |
||||||
|
explicit BaseSlice(const grpc_slice& slice) : slice_(slice) {} |
||||||
|
~BaseSlice() = default; |
||||||
|
|
||||||
|
void Swap(BaseSlice* other) { std::swap(slice_, other->slice_); } |
||||||
|
void SetCSlice(const grpc_slice& slice) { slice_ = slice; } |
||||||
|
|
||||||
|
uint8_t* mutable_data() { return GRPC_SLICE_START_PTR(slice_); } |
||||||
|
|
||||||
|
grpc_slice* c_slice_ptr() { return &slice_; } |
||||||
|
|
||||||
|
private: |
||||||
|
grpc_slice slice_; |
||||||
|
}; |
||||||
|
|
||||||
|
inline bool operator==(const BaseSlice& a, const BaseSlice& b) { |
||||||
|
return grpc_slice_eq(a.c_slice(), b.c_slice()) != 0; |
||||||
|
} |
||||||
|
|
||||||
|
inline bool operator!=(const BaseSlice& a, const BaseSlice& b) { |
||||||
|
return grpc_slice_eq(a.c_slice(), b.c_slice()) == 0; |
||||||
|
} |
||||||
|
|
||||||
|
inline bool operator==(const BaseSlice& a, absl::string_view b) { |
||||||
|
return a.as_string_view() == b; |
||||||
|
} |
||||||
|
|
||||||
|
inline bool operator!=(const BaseSlice& a, absl::string_view b) { |
||||||
|
return a.as_string_view() != b; |
||||||
|
} |
||||||
|
|
||||||
|
inline bool operator==(absl::string_view a, const BaseSlice& b) { |
||||||
|
return a == b.as_string_view(); |
||||||
|
} |
||||||
|
|
||||||
|
inline bool operator!=(absl::string_view a, const BaseSlice& b) { |
||||||
|
return a != b.as_string_view(); |
||||||
|
} |
||||||
|
|
||||||
|
inline bool operator==(const BaseSlice& a, const grpc_slice& b) { |
||||||
|
return grpc_slice_eq(a.c_slice(), b) != 0; |
||||||
|
} |
||||||
|
|
||||||
|
inline bool operator!=(const BaseSlice& a, const grpc_slice& b) { |
||||||
|
return grpc_slice_eq(a.c_slice(), b) == 0; |
||||||
|
} |
||||||
|
|
||||||
|
inline bool operator==(const grpc_slice& a, const BaseSlice& b) { |
||||||
|
return grpc_slice_eq(a, b.c_slice()) != 0; |
||||||
|
} |
||||||
|
|
||||||
|
inline bool operator!=(const grpc_slice& a, const BaseSlice& b) { |
||||||
|
return grpc_slice_eq(a, b.c_slice()) == 0; |
||||||
|
} |
||||||
|
|
||||||
|
template <typename Out> |
||||||
|
struct CopyConstructors { |
||||||
|
static Out FromCopiedString(const char* s) { |
||||||
|
return FromCopiedBuffer(s, strlen(s)); |
||||||
|
} |
||||||
|
static Out FromCopiedString(absl::string_view s) { |
||||||
|
return FromCopiedBuffer(s.data(), s.size()); |
||||||
|
} |
||||||
|
static Out FromCopiedString(std::string s); |
||||||
|
|
||||||
|
static Out FromCopiedBuffer(const char* p, size_t len) { |
||||||
|
return Out(grpc_slice_from_copied_buffer(p, len)); |
||||||
|
} |
||||||
|
|
||||||
|
template <typename Buffer> |
||||||
|
static Out FromCopiedBuffer(const Buffer& buffer) { |
||||||
|
return FromCopiedBuffer(reinterpret_cast<const char*>(buffer.data()), |
||||||
|
buffer.size()); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace slice_detail
|
||||||
|
|
||||||
|
class MutableSlice : public slice_detail::BaseSlice, |
||||||
|
public slice_detail::CopyConstructors<MutableSlice> { |
||||||
|
public: |
||||||
|
MutableSlice() = default; |
||||||
|
explicit MutableSlice(const grpc_slice& slice); |
||||||
|
~MutableSlice(); |
||||||
|
|
||||||
|
MutableSlice(const MutableSlice&) = delete; |
||||||
|
MutableSlice& operator=(const MutableSlice&) = delete; |
||||||
|
MutableSlice(MutableSlice&& other) noexcept |
||||||
|
: slice_detail::BaseSlice(other.TakeCSlice()) {} |
||||||
|
MutableSlice& operator=(MutableSlice&& other) noexcept { |
||||||
|
Swap(&other); |
||||||
|
return *this; |
||||||
|
} |
||||||
|
|
||||||
|
static MutableSlice CreateUninitialized(size_t length) { |
||||||
|
return MutableSlice(grpc_slice_malloc(length)); |
||||||
|
} |
||||||
|
|
||||||
|
// Return a sub slice of this one. Leaves this slice in an indeterminate but
|
||||||
|
// valid state.
|
||||||
|
MutableSlice TakeSubSlice(size_t pos, size_t n) { |
||||||
|
return MutableSlice(grpc_slice_sub_no_ref(TakeCSlice(), pos, pos + n)); |
||||||
|
} |
||||||
|
|
||||||
|
// Iterator access to the underlying bytes
|
||||||
|
uint8_t* begin() { return mutable_data(); } |
||||||
|
uint8_t* end() { return mutable_data() + size(); } |
||||||
|
uint8_t* data() { return mutable_data(); } |
||||||
|
|
||||||
|
// Array access
|
||||||
|
uint8_t& operator[](size_t i) { return mutable_data()[i]; } |
||||||
|
}; |
||||||
|
|
||||||
|
class Slice : public slice_detail::BaseSlice, |
||||||
|
public slice_detail::CopyConstructors<Slice> { |
||||||
|
public: |
||||||
|
Slice() = default; |
||||||
|
~Slice(); |
||||||
|
explicit Slice(const grpc_slice& slice) : slice_detail::BaseSlice(slice) {} |
||||||
|
explicit Slice(slice_detail::BaseSlice&& other) |
||||||
|
: slice_detail::BaseSlice(other.TakeCSlice()) {} |
||||||
|
|
||||||
|
Slice(const Slice&) = delete; |
||||||
|
Slice& operator=(const Slice&) = delete; |
||||||
|
Slice(Slice&& other) noexcept : slice_detail::BaseSlice(other.TakeCSlice()) {} |
||||||
|
Slice& operator=(Slice&& other) noexcept { |
||||||
|
Swap(&other); |
||||||
|
return *this; |
||||||
|
} |
||||||
|
|
||||||
|
// A slice might refer to some memory that we keep a refcount to (this is
|
||||||
|
// owned), or some memory that's inlined into the slice (also owned), or some
|
||||||
|
// other block of memory that we know will be available for the lifetime of
|
||||||
|
// some operation in the common case (not owned). In the *less common* case
|
||||||
|
// that we need to keep that slice text for longer than our API's guarantee us
|
||||||
|
// access, we need to take a copy and turn this into something that we do own.
|
||||||
|
|
||||||
|
// TakeOwned returns an owned slice regardless of current ownership, and
|
||||||
|
// leaves the current slice in a valid but externally unpredictable state - in
|
||||||
|
// doing so it can avoid adding a ref to the underlying slice.
|
||||||
|
Slice TakeOwned(); |
||||||
|
|
||||||
|
// AsOwned returns an owned slice but does not mutate the current slice,
|
||||||
|
// meaning that it may add a reference to the underlying slice.
|
||||||
|
Slice AsOwned() const; |
||||||
|
|
||||||
|
// TakeMutable returns a MutableSlice, and leaves the current slice in an
|
||||||
|
// indeterminate but valid state.
|
||||||
|
// A mutable slice requires only one reference to the bytes of the slice -
|
||||||
|
// this can be achieved either with inlined storage or with a single
|
||||||
|
// reference.
|
||||||
|
// If the current slice is refcounted and there are more than one references
|
||||||
|
// to that slice, then the slice is copied in order to achieve a mutable
|
||||||
|
// version.
|
||||||
|
MutableSlice TakeMutable(); |
||||||
|
|
||||||
|
// Return a sub slice of this one. Leaves this slice in an indeterminate but
|
||||||
|
// valid state.
|
||||||
|
Slice TakeSubSlice(size_t pos, size_t n) { |
||||||
|
return Slice(grpc_slice_sub_no_ref(TakeCSlice(), pos, pos + n)); |
||||||
|
} |
||||||
|
|
||||||
|
// Return a sub slice of this one. Adds a reference to the underlying slice.
|
||||||
|
Slice RefSubSlice(size_t pos, size_t n) const { |
||||||
|
return Slice(grpc_slice_sub(c_slice(), pos, pos + n)); |
||||||
|
} |
||||||
|
|
||||||
|
// Split this slice, returning a new slice containing (split:end] and
|
||||||
|
// leaving this slice with [begin:split).
|
||||||
|
Slice Split(size_t split) { |
||||||
|
return Slice(grpc_slice_split_tail(c_slice_ptr(), split)); |
||||||
|
} |
||||||
|
|
||||||
|
Slice Ref() const; |
||||||
|
|
||||||
|
Slice Copy() const { return Slice(grpc_slice_copy(c_slice())); } |
||||||
|
|
||||||
|
static Slice FromRefcountAndBytes(grpc_slice_refcount* r, |
||||||
|
const uint8_t* begin, const uint8_t* end); |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace experimental
|
||||||
|
} // namespace grpc_event_engine
|
||||||
|
|
||||||
|
#endif // GRPC_EVENT_ENGINE_SLICE_H
|
@ -0,0 +1,112 @@ |
|||||||
|
// Copyright 2022 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.
|
||||||
|
|
||||||
|
#ifndef GRPC_EVENT_ENGINE_SLICE_BUFFER_H |
||||||
|
#define GRPC_EVENT_ENGINE_SLICE_BUFFER_H |
||||||
|
|
||||||
|
#include <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#include <string.h> |
||||||
|
|
||||||
|
#include <cstdint> |
||||||
|
#include <string> |
||||||
|
|
||||||
|
#include "absl/strings/string_view.h" |
||||||
|
#include "absl/utility/utility.h" |
||||||
|
|
||||||
|
#include <grpc/event_engine/slice.h> |
||||||
|
#include <grpc/slice.h> |
||||||
|
#include <grpc/slice_buffer.h> |
||||||
|
#include <grpc/support/log.h> |
||||||
|
|
||||||
|
namespace grpc_event_engine { |
||||||
|
namespace experimental { |
||||||
|
|
||||||
|
/// A Wrapper around \a grpc_slice_buffer pointer.
|
||||||
|
///
|
||||||
|
/// A slice buffer holds the memory for a collection of slices.
|
||||||
|
/// The SliceBuffer object itself is meant to only hide the C-style API,
|
||||||
|
/// and won't hold the data itself. In terms of lifespan, the
|
||||||
|
/// grpc_slice_buffer ought to be kept somewhere inside the caller's objects,
|
||||||
|
/// like a transport or an endpoint.
|
||||||
|
///
|
||||||
|
/// This lifespan rule is likely to change in the future, as we may
|
||||||
|
/// collapse the grpc_slice_buffer structure straight into this class.
|
||||||
|
///
|
||||||
|
/// The SliceBuffer API is basically a replica of the grpc_slice_buffer's,
|
||||||
|
/// and its documentation will move here once we remove the C structure,
|
||||||
|
/// which should happen before the Event Engine's API is no longer
|
||||||
|
/// an experimental API.
|
||||||
|
class SliceBuffer { |
||||||
|
public: |
||||||
|
explicit SliceBuffer() { grpc_slice_buffer_init(&slice_buffer_); } |
||||||
|
SliceBuffer(const SliceBuffer& other) = delete; |
||||||
|
SliceBuffer(SliceBuffer&& other) noexcept |
||||||
|
: slice_buffer_(other.slice_buffer_) { |
||||||
|
grpc_slice_buffer_reset_and_unref(&slice_buffer_); |
||||||
|
grpc_slice_buffer_swap(&slice_buffer_, &other.slice_buffer_); |
||||||
|
} |
||||||
|
/// Upon destruction, the underlying raw slice buffer is cleaned out and all
|
||||||
|
/// slices are unreffed.
|
||||||
|
~SliceBuffer() { grpc_slice_buffer_destroy(&slice_buffer_); } |
||||||
|
|
||||||
|
/// Appends a new slice into the SliceBuffer and makes an attempt to merge
|
||||||
|
/// this slice with the last slice in the SliceBuffer.
|
||||||
|
void Append(Slice slice); |
||||||
|
|
||||||
|
/// Adds a new slice into the SliceBuffer at the next available index.
|
||||||
|
/// Returns the index at which the new slice is added.
|
||||||
|
size_t AppendIndexed(Slice slice); |
||||||
|
|
||||||
|
/// Returns the number of slices held by the SliceBuffer.
|
||||||
|
size_t Count() { return slice_buffer_.count; } |
||||||
|
|
||||||
|
/// Removes/deletes the last n bytes in the SliceBuffer.
|
||||||
|
void RemoveLastNBytes(size_t n) { |
||||||
|
grpc_slice_buffer_trim_end(&slice_buffer_, n, nullptr); |
||||||
|
} |
||||||
|
|
||||||
|
/// Move the first n bytes of the SliceBuffer into a memory pointed to by dst.
|
||||||
|
void MoveFirstNBytesIntoBuffer(size_t n, void* dst) { |
||||||
|
grpc_slice_buffer_move_first_into_buffer(&slice_buffer_, n, dst); |
||||||
|
} |
||||||
|
|
||||||
|
/// Removes and unrefs all slices in the SliceBuffer.
|
||||||
|
void Clear() { grpc_slice_buffer_reset_and_unref(&slice_buffer_); } |
||||||
|
|
||||||
|
/// Removes the first slice in the SliceBuffer and returns it.
|
||||||
|
Slice TakeFirst(); |
||||||
|
|
||||||
|
/// Prepends the slice to the the front of the SliceBuffer.
|
||||||
|
void Prepend(Slice slice); |
||||||
|
|
||||||
|
/// Increased the ref-count of slice at the specified index and returns the
|
||||||
|
/// associated slice.
|
||||||
|
Slice RefSlice(size_t index); |
||||||
|
|
||||||
|
/// The total number of bytes held by the SliceBuffer
|
||||||
|
size_t Length() { return slice_buffer_.length; } |
||||||
|
|
||||||
|
/// Return a pointer to the back raw grpc_slice_buffer
|
||||||
|
grpc_slice_buffer* RawSliceBuffer() { return &slice_buffer_; } |
||||||
|
|
||||||
|
private: |
||||||
|
/// The backing raw slice buffer.
|
||||||
|
grpc_slice_buffer slice_buffer_; |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace experimental
|
||||||
|
} // namespace grpc_event_engine
|
||||||
|
|
||||||
|
#endif // GRPC_EVENT_ENGINE_SLICE_BUFFER_H
|
@ -0,0 +1,102 @@ |
|||||||
|
// Copyright 2022 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 <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#include <stddef.h> |
||||||
|
#include <stdint.h> |
||||||
|
|
||||||
|
#include <string> |
||||||
|
#include <utility> |
||||||
|
|
||||||
|
#include <grpc/event_engine/slice.h> |
||||||
|
#include <grpc/slice.h> |
||||||
|
|
||||||
|
#include "src/core/lib/slice/slice_internal.h" |
||||||
|
#include "src/core/lib/slice/slice_refcount.h" |
||||||
|
#include "src/core/lib/slice/slice_refcount_base.h" |
||||||
|
|
||||||
|
namespace grpc_event_engine { |
||||||
|
namespace experimental { |
||||||
|
|
||||||
|
namespace slice_detail { |
||||||
|
|
||||||
|
uint32_t BaseSlice::Hash() const { return grpc_slice_hash_internal(slice_); } |
||||||
|
|
||||||
|
template <> |
||||||
|
MutableSlice CopyConstructors<MutableSlice>::FromCopiedString(std::string s) { |
||||||
|
return MutableSlice(grpc_slice_from_cpp_string(std::move(s))); |
||||||
|
} |
||||||
|
|
||||||
|
template <> |
||||||
|
Slice CopyConstructors<Slice>::FromCopiedString(std::string s) { |
||||||
|
return Slice(grpc_slice_from_cpp_string(std::move(s))); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace slice_detail
|
||||||
|
|
||||||
|
MutableSlice::MutableSlice(const grpc_slice& slice) |
||||||
|
: slice_detail::BaseSlice(slice) { |
||||||
|
GPR_DEBUG_ASSERT(slice.refcount == nullptr || slice.refcount->IsUnique()); |
||||||
|
} |
||||||
|
|
||||||
|
MutableSlice::~MutableSlice() { grpc_slice_unref_internal(c_slice()); } |
||||||
|
|
||||||
|
Slice Slice::TakeOwned() { |
||||||
|
if (c_slice().refcount == nullptr) { |
||||||
|
return Slice(c_slice()); |
||||||
|
} |
||||||
|
if (c_slice().refcount == grpc_slice_refcount::NoopRefcount()) { |
||||||
|
return Slice(grpc_slice_copy(c_slice())); |
||||||
|
} |
||||||
|
return Slice(TakeCSlice()); |
||||||
|
} |
||||||
|
|
||||||
|
Slice Slice::AsOwned() const { |
||||||
|
if (c_slice().refcount == nullptr) { |
||||||
|
return Slice(c_slice()); |
||||||
|
} |
||||||
|
if (c_slice().refcount == grpc_slice_refcount::NoopRefcount()) { |
||||||
|
return Slice(grpc_slice_copy(c_slice())); |
||||||
|
} |
||||||
|
return Slice(grpc_slice_ref_internal(c_slice())); |
||||||
|
} |
||||||
|
|
||||||
|
MutableSlice Slice::TakeMutable() { |
||||||
|
if (c_slice().refcount == nullptr) { |
||||||
|
return MutableSlice(c_slice()); |
||||||
|
} |
||||||
|
if (c_slice().refcount != grpc_slice_refcount::NoopRefcount() && |
||||||
|
c_slice().refcount->IsUnique()) { |
||||||
|
return MutableSlice(TakeCSlice()); |
||||||
|
} |
||||||
|
return MutableSlice(grpc_slice_copy(c_slice())); |
||||||
|
} |
||||||
|
|
||||||
|
Slice::~Slice() { grpc_slice_unref_internal(c_slice()); } |
||||||
|
|
||||||
|
Slice Slice::Ref() const { return Slice(grpc_slice_ref_internal(c_slice())); } |
||||||
|
|
||||||
|
Slice Slice::FromRefcountAndBytes(grpc_slice_refcount* r, const uint8_t* begin, |
||||||
|
const uint8_t* end) { |
||||||
|
grpc_slice out; |
||||||
|
out.refcount = r; |
||||||
|
if (r != grpc_slice_refcount::NoopRefcount()) r->Ref(); |
||||||
|
out.data.refcounted.bytes = const_cast<uint8_t*>(begin); |
||||||
|
out.data.refcounted.length = end - begin; |
||||||
|
return Slice(out); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace experimental
|
||||||
|
} // namespace grpc_event_engine
|
@ -0,0 +1,49 @@ |
|||||||
|
// Copyright 2022 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 <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#include <grpc/event_engine/slice_buffer.h> |
||||||
|
#include <grpc/slice.h> |
||||||
|
#include <grpc/slice_buffer.h> |
||||||
|
|
||||||
|
#include "src/core/lib/slice/slice.h" |
||||||
|
#include "src/core/lib/slice/slice_internal.h" |
||||||
|
#include "src/core/lib/slice/slice_refcount.h" |
||||||
|
|
||||||
|
namespace grpc_event_engine { |
||||||
|
namespace experimental { |
||||||
|
|
||||||
|
void SliceBuffer::Append(Slice slice) { |
||||||
|
grpc_slice_buffer_add(&slice_buffer_, slice.TakeCSlice()); |
||||||
|
} |
||||||
|
|
||||||
|
size_t SliceBuffer::AppendIndexed(Slice slice) { |
||||||
|
return grpc_slice_buffer_add_indexed(&slice_buffer_, slice.TakeCSlice()); |
||||||
|
} |
||||||
|
|
||||||
|
Slice SliceBuffer::TakeFirst() { |
||||||
|
return Slice(grpc_slice_buffer_take_first(&slice_buffer_)); |
||||||
|
} |
||||||
|
|
||||||
|
void SliceBuffer::Prepend(Slice slice) { |
||||||
|
grpc_slice_buffer_undo_take_first(&slice_buffer_, slice.TakeCSlice()); |
||||||
|
} |
||||||
|
|
||||||
|
Slice SliceBuffer::RefSlice(size_t index) { |
||||||
|
return Slice(grpc_slice_ref_internal(slice_buffer_.slices[index])); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace experimental
|
||||||
|
} // namespace grpc_event_engine
|
@ -0,0 +1,79 @@ |
|||||||
|
// Copyright 2022 The 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 <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#include <gmock/gmock.h> |
||||||
|
#include <gtest/gtest.h> |
||||||
|
|
||||||
|
#include <grpc/event_engine/slice_buffer.h> |
||||||
|
#include <grpc/grpc.h> |
||||||
|
|
||||||
|
#include "src/core/lib/slice/slice.h" |
||||||
|
#include "test/core/util/test_config.h" |
||||||
|
|
||||||
|
using ::grpc_event_engine::experimental::Slice; |
||||||
|
using ::grpc_event_engine::experimental::SliceBuffer; |
||||||
|
|
||||||
|
static constexpr int kNewSliceLength = 100; |
||||||
|
|
||||||
|
Slice MakeSlice(size_t len) { |
||||||
|
GPR_ASSERT(len > 0); |
||||||
|
unsigned char* contents = reinterpret_cast<unsigned char*>(new char[len]); |
||||||
|
memset(contents, 'a', len); |
||||||
|
return Slice(grpc_slice_new(contents, len, gpr_free)); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(SliceBufferTest, AddAndRemoveTest) { |
||||||
|
SliceBuffer sb; |
||||||
|
Slice first_slice = MakeSlice(kNewSliceLength); |
||||||
|
Slice second_slice = MakeSlice(kNewSliceLength); |
||||||
|
Slice first_slice_copy = first_slice.Copy(); |
||||||
|
sb.Append(std::move(first_slice)); |
||||||
|
sb.Append(std::move(second_slice)); |
||||||
|
ASSERT_EQ(sb.Count(), 2); |
||||||
|
ASSERT_EQ(sb.Length(), 2 * kNewSliceLength); |
||||||
|
Slice popped = sb.TakeFirst(); |
||||||
|
ASSERT_EQ(popped, first_slice_copy); |
||||||
|
ASSERT_EQ(sb.Count(), 1); |
||||||
|
ASSERT_EQ(sb.Length(), kNewSliceLength); |
||||||
|
sb.Prepend(std::move(popped)); |
||||||
|
ASSERT_EQ(sb.Count(), 2); |
||||||
|
ASSERT_EQ(sb.Length(), 2 * kNewSliceLength); |
||||||
|
sb.Clear(); |
||||||
|
ASSERT_EQ(sb.Count(), 0); |
||||||
|
ASSERT_EQ(sb.Length(), 0); |
||||||
|
} |
||||||
|
|
||||||
|
TEST(SliceBufferTest, SliceRefTest) { |
||||||
|
SliceBuffer sb; |
||||||
|
Slice first_slice = MakeSlice(kNewSliceLength); |
||||||
|
Slice second_slice = MakeSlice(kNewSliceLength + 1); |
||||||
|
Slice first_slice_copy = first_slice.Copy(); |
||||||
|
Slice second_slice_copy = second_slice.Copy(); |
||||||
|
ASSERT_EQ(sb.AppendIndexed(std::move(first_slice)), 0); |
||||||
|
ASSERT_EQ(sb.AppendIndexed(std::move(second_slice)), 1); |
||||||
|
Slice first_reffed = sb.RefSlice(0); |
||||||
|
Slice second_reffed = sb.RefSlice(1); |
||||||
|
ASSERT_EQ(first_reffed, first_slice_copy); |
||||||
|
ASSERT_EQ(second_reffed, second_slice_copy); |
||||||
|
ASSERT_EQ(sb.Count(), 2); |
||||||
|
ASSERT_EQ(sb.Length(), 2 * kNewSliceLength + 1); |
||||||
|
sb.Clear(); |
||||||
|
} |
||||||
|
|
||||||
|
int main(int argc, char** argv) { |
||||||
|
testing::InitGoogleTest(&argc, argv); |
||||||
|
return RUN_ALL_TESTS(); |
||||||
|
} |
Loading…
Reference in new issue