The C based gRPC (C++, Python, Ruby, Objective-C, PHP, C#)
https://grpc.io/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
384 lines
13 KiB
384 lines
13 KiB
// Copyright 2021 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_CORE_LIB_SLICE_SLICE_H |
|
#define GRPC_CORE_LIB_SLICE_SLICE_H |
|
|
|
#include <grpc/support/port_platform.h> |
|
|
|
#include <cstdint> |
|
|
|
#include "absl/strings/string_view.h" |
|
|
|
#include <grpc/slice.h> |
|
|
|
#include "src/core/lib/gpr/string.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" |
|
|
|
// Herein lies grpc_core::Slice and its team of thin wrappers around grpc_slice. |
|
// They aim to keep you safe by providing strong guarantees around lifetime and |
|
// mutability. |
|
// |
|
// The team: |
|
// Slice - provides a wrapper around an unknown type of slice. |
|
// Immutable (since we don't know who else might be referencing |
|
// it), and potentially ref counted. |
|
// StaticSlice - provides a wrapper around a static slice. Not refcounted, |
|
// fast to copy. |
|
// MutableSlice - provides a guarantee of unique ownership, meaning the |
|
// underlying data can be mutated safely. |
|
|
|
namespace grpc_core { |
|
|
|
// Forward declarations |
|
class Slice; |
|
class StaticSlice; |
|
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 { return grpc_slice_hash_internal(slice_); } |
|
|
|
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) { |
|
return Out(grpc_slice_from_cpp_string(std::move(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()); |
|
} |
|
|
|
static Out FromInt64(int64_t i) { |
|
char buffer[GPR_LTOA_MIN_BUFSIZE]; |
|
gpr_ltoa(i, buffer); |
|
return FromCopiedString(buffer); |
|
} |
|
}; |
|
|
|
template <typename Out> |
|
struct StaticConstructors { |
|
static Out FromStaticString(const char* s) { |
|
return FromStaticBuffer(s, strlen(s)); |
|
} |
|
|
|
static Out FromStaticString(absl::string_view s) { |
|
return FromStaticBuffer(s.data(), s.size()); |
|
} |
|
|
|
static Out FromStaticBuffer(const void* s, size_t len) { |
|
grpc_slice slice; |
|
slice.refcount = grpc_slice_refcount::NoopRefcount(); |
|
slice.data.refcounted.bytes = |
|
const_cast<uint8_t*>(static_cast<const uint8_t*>(s)); |
|
slice.data.refcounted.length = len; |
|
return Out(slice); |
|
} |
|
}; |
|
|
|
} // namespace slice_detail |
|
|
|
class StaticSlice : public slice_detail::BaseSlice, |
|
public slice_detail::StaticConstructors<StaticSlice> { |
|
public: |
|
StaticSlice() = default; |
|
explicit StaticSlice(const grpc_slice& slice) |
|
: slice_detail::BaseSlice(slice) { |
|
GPR_DEBUG_ASSERT(slice.refcount == grpc_slice_refcount::NoopRefcount()); |
|
} |
|
|
|
StaticSlice(const StaticSlice& other) |
|
: slice_detail::BaseSlice(other.c_slice()) {} |
|
StaticSlice& operator=(const StaticSlice& other) { |
|
SetCSlice(other.c_slice()); |
|
return *this; |
|
} |
|
StaticSlice(StaticSlice&& other) noexcept |
|
: slice_detail::BaseSlice(other.TakeCSlice()) {} |
|
StaticSlice& operator=(StaticSlice&& other) noexcept { |
|
Swap(&other); |
|
return *this; |
|
} |
|
}; |
|
|
|
class MutableSlice : public slice_detail::BaseSlice, |
|
public slice_detail::CopyConstructors<MutableSlice> { |
|
public: |
|
MutableSlice() = default; |
|
explicit MutableSlice(const grpc_slice& slice) |
|
: slice_detail::BaseSlice(slice) { |
|
GPR_DEBUG_ASSERT(slice.refcount == nullptr || slice.refcount->IsUnique()); |
|
} |
|
~MutableSlice() { grpc_slice_unref_internal(c_slice()); } |
|
|
|
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_detail::StaticConstructors<Slice> { |
|
public: |
|
Slice() = default; |
|
~Slice() { grpc_slice_unref_internal(c_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() { |
|
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()); |
|
} |
|
|
|
// 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 { |
|
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())); |
|
} |
|
|
|
// 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() { |
|
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())); |
|
} |
|
|
|
// 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 { return Slice(grpc_slice_ref_internal(c_slice())); } |
|
|
|
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) { |
|
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); |
|
} |
|
|
|
static Slice FromExternalString(absl::string_view str) { |
|
return FromStaticString(str); |
|
} |
|
}; |
|
|
|
} // namespace grpc_core |
|
|
|
#endif // GRPC_CORE_LIB_SLICE_SLICE_H
|
|
|