• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef GRPC_EVENT_ENGINE_SLICE_H
16 #define GRPC_EVENT_ENGINE_SLICE_H
17 
18 #include <grpc/event_engine/internal/slice_cast.h>
19 #include <grpc/slice.h>
20 #include <grpc/support/port_platform.h>
21 #include <string.h>
22 
23 #include <cstdint>
24 #include <string>
25 #include <utility>
26 
27 #include "absl/strings/string_view.h"
28 
29 // This public slice definition largely based of the internal grpc_core::Slice
30 // implementation. Changes to this implementation might warrant changes to the
31 // internal grpc_core::Slice type as well.
32 
33 namespace grpc_event_engine {
34 namespace experimental {
35 
36 // Forward declarations
37 class Slice;
38 class MutableSlice;
39 
40 namespace slice_detail {
41 
42 // Returns an empty slice.
EmptySlice()43 static constexpr grpc_slice EmptySlice() { return {nullptr, {}}; }
44 
45 // BaseSlice holds the grpc_slice object, but does not apply refcounting policy.
46 // It does export immutable access into the slice, such that this can be shared
47 // by all storage policies.
48 class BaseSlice {
49  public:
50   BaseSlice(const BaseSlice&) = delete;
51   BaseSlice& operator=(const BaseSlice&) = delete;
52   BaseSlice(BaseSlice&& other) = delete;
53   BaseSlice& operator=(BaseSlice&& other) = delete;
54 
55   // Iterator access to the underlying bytes
begin()56   const uint8_t* begin() const { return GRPC_SLICE_START_PTR(c_slice()); }
end()57   const uint8_t* end() const { return GRPC_SLICE_END_PTR(c_slice()); }
cbegin()58   const uint8_t* cbegin() const { return GRPC_SLICE_START_PTR(c_slice()); }
cend()59   const uint8_t* cend() const { return GRPC_SLICE_END_PTR(c_slice()); }
60 
61   // Retrieve a borrowed reference to the underlying grpc_slice.
c_slice()62   const grpc_slice& c_slice() const { return slice_; }
63 
64   // Retrieve the underlying grpc_slice, and replace the one in this object with
65   // EmptySlice().
TakeCSlice()66   grpc_slice TakeCSlice() {
67     grpc_slice out = slice_;
68     slice_ = EmptySlice();
69     return out;
70   }
71 
72   // As other things... borrowed references.
as_string_view()73   absl::string_view as_string_view() const {
74     return absl::string_view(reinterpret_cast<const char*>(data()), size());
75   }
76 
77   // Array access
78   uint8_t operator[](size_t i) const {
79     return GRPC_SLICE_START_PTR(c_slice())[i];
80   }
81 
82   // Access underlying data
data()83   const uint8_t* data() const { return GRPC_SLICE_START_PTR(c_slice()); }
84 
85   // Size of the slice
size()86   size_t size() const { return GRPC_SLICE_LENGTH(c_slice()); }
length()87   size_t length() const { return size(); }
empty()88   bool empty() const { return size() == 0; }
89 
90   // For inlined slices - are these two slices equal?
91   // For non-inlined slices - do these two slices refer to the same block of
92   // memory?
is_equivalent(const BaseSlice & other)93   bool is_equivalent(const BaseSlice& other) const {
94     return grpc_slice_is_equivalent(slice_, other.slice_);
95   }
96 
97   uint32_t Hash() const;
98 
99  protected:
BaseSlice()100   BaseSlice() : slice_(EmptySlice()) {}
BaseSlice(const grpc_slice & slice)101   explicit BaseSlice(const grpc_slice& slice) : slice_(slice) {}
102   ~BaseSlice() = default;
103 
Swap(BaseSlice * other)104   void Swap(BaseSlice* other) { std::swap(slice_, other->slice_); }
SetCSlice(const grpc_slice & slice)105   void SetCSlice(const grpc_slice& slice) { slice_ = slice; }
106 
mutable_data()107   uint8_t* mutable_data() { return GRPC_SLICE_START_PTR(slice_); }
108 
c_slice_ptr()109   grpc_slice* c_slice_ptr() { return &slice_; }
110 
111  private:
112   grpc_slice slice_;
113 };
114 
115 inline bool operator==(const BaseSlice& a, const BaseSlice& b) {
116   return grpc_slice_eq(a.c_slice(), b.c_slice()) != 0;
117 }
118 
119 inline bool operator!=(const BaseSlice& a, const BaseSlice& b) {
120   return grpc_slice_eq(a.c_slice(), b.c_slice()) == 0;
121 }
122 
123 inline bool operator==(const BaseSlice& a, absl::string_view b) {
124   return a.as_string_view() == b;
125 }
126 
127 inline bool operator!=(const BaseSlice& a, absl::string_view b) {
128   return a.as_string_view() != b;
129 }
130 
131 inline bool operator==(absl::string_view a, const BaseSlice& b) {
132   return a == b.as_string_view();
133 }
134 
135 inline bool operator!=(absl::string_view a, const BaseSlice& b) {
136   return a != b.as_string_view();
137 }
138 
139 inline bool operator==(const BaseSlice& a, const grpc_slice& b) {
140   return grpc_slice_eq(a.c_slice(), b) != 0;
141 }
142 
143 inline bool operator!=(const BaseSlice& a, const grpc_slice& b) {
144   return grpc_slice_eq(a.c_slice(), b) == 0;
145 }
146 
147 inline bool operator==(const grpc_slice& a, const BaseSlice& b) {
148   return grpc_slice_eq(a, b.c_slice()) != 0;
149 }
150 
151 inline bool operator!=(const grpc_slice& a, const BaseSlice& b) {
152   return grpc_slice_eq(a, b.c_slice()) == 0;
153 }
154 
155 template <typename Out>
156 struct CopyConstructors {
FromCopiedStringCopyConstructors157   static Out FromCopiedString(const char* s) {
158     return FromCopiedBuffer(s, strlen(s));
159   }
FromCopiedStringCopyConstructors160   static Out FromCopiedString(absl::string_view s) {
161     return FromCopiedBuffer(s.data(), s.size());
162   }
163   static Out FromCopiedString(std::string s);
164 
FromCopiedBufferCopyConstructors165   static Out FromCopiedBuffer(const char* p, size_t len) {
166     return Out(grpc_slice_from_copied_buffer(p, len));
167   }
168 
FromCopiedBufferCopyConstructors169   static Out FromCopiedBuffer(const uint8_t* p, size_t len) {
170     return Out(
171         grpc_slice_from_copied_buffer(reinterpret_cast<const char*>(p), len));
172   }
173 
174   template <typename Buffer>
FromCopiedBufferCopyConstructors175   static Out FromCopiedBuffer(const Buffer& buffer) {
176     return FromCopiedBuffer(reinterpret_cast<const char*>(buffer.data()),
177                             buffer.size());
178   }
179 };
180 
181 }  // namespace slice_detail
182 
183 class GPR_MSVC_EMPTY_BASE_CLASS_WORKAROUND MutableSlice
184     : public slice_detail::BaseSlice,
185       public slice_detail::CopyConstructors<MutableSlice> {
186  public:
187   MutableSlice() = default;
188   explicit MutableSlice(const grpc_slice& slice);
189   ~MutableSlice();
190 
191   MutableSlice(const MutableSlice&) = delete;
192   MutableSlice& operator=(const MutableSlice&) = delete;
MutableSlice(MutableSlice && other)193   MutableSlice(MutableSlice&& other) noexcept
194       : slice_detail::BaseSlice(other.TakeCSlice()) {}
195   MutableSlice& operator=(MutableSlice&& other) noexcept {
196     Swap(&other);
197     return *this;
198   }
199 
CreateUninitialized(size_t length)200   static MutableSlice CreateUninitialized(size_t length) {
201     return MutableSlice(grpc_slice_malloc(length));
202   }
203 
204   // Return a sub slice of this one. Leaves this slice in an indeterminate but
205   // valid state.
TakeSubSlice(size_t pos,size_t n)206   MutableSlice TakeSubSlice(size_t pos, size_t n) {
207     return MutableSlice(grpc_slice_sub_no_ref(TakeCSlice(), pos, pos + n));
208   }
209 
210   // Iterator access to the underlying bytes
begin()211   uint8_t* begin() { return mutable_data(); }
end()212   uint8_t* end() { return mutable_data() + size(); }
data()213   uint8_t* data() { return mutable_data(); }
214 
215   // Array access
216   uint8_t& operator[](size_t i) { return mutable_data()[i]; }
217 };
218 
219 class GPR_MSVC_EMPTY_BASE_CLASS_WORKAROUND Slice
220     : public slice_detail::BaseSlice,
221       public slice_detail::CopyConstructors<Slice> {
222  public:
223   Slice() = default;
224   ~Slice();
Slice(const grpc_slice & slice)225   explicit Slice(const grpc_slice& slice) : slice_detail::BaseSlice(slice) {}
Slice(slice_detail::BaseSlice && other)226   explicit Slice(slice_detail::BaseSlice&& other)
227       : slice_detail::BaseSlice(other.TakeCSlice()) {}
228 
229   Slice(const Slice&) = delete;
230   Slice& operator=(const Slice&) = delete;
Slice(Slice && other)231   Slice(Slice&& other) noexcept : slice_detail::BaseSlice(other.TakeCSlice()) {}
232   Slice& operator=(Slice&& other) noexcept {
233     Swap(&other);
234     return *this;
235   }
236 
237   // A slice might refer to some memory that we keep a refcount to (this is
238   // owned), or some memory that's inlined into the slice (also owned), or some
239   // other block of memory that we know will be available for the lifetime of
240   // some operation in the common case (not owned). In the *less common* case
241   // that we need to keep that slice text for longer than our API's guarantee us
242   // access, we need to take a copy and turn this into something that we do own.
243 
244   // TakeOwned returns an owned slice regardless of current ownership, and
245   // leaves the current slice in a valid but externally unpredictable state - in
246   // doing so it can avoid adding a ref to the underlying slice.
247   Slice TakeOwned();
248 
249   // AsOwned returns an owned slice but does not mutate the current slice,
250   // meaning that it may add a reference to the underlying slice.
251   Slice AsOwned() const;
252 
253   // TakeMutable returns a MutableSlice, and leaves the current slice in an
254   // indeterminate but valid state.
255   // A mutable slice requires only one reference to the bytes of the slice -
256   // this can be achieved either with inlined storage or with a single
257   // reference.
258   // If the current slice is refcounted and there are more than one references
259   // to that slice, then the slice is copied in order to achieve a mutable
260   // version.
261   MutableSlice TakeMutable();
262 
263   // Return a sub slice of this one. Leaves this slice in an indeterminate but
264   // valid state.
TakeSubSlice(size_t pos,size_t n)265   Slice TakeSubSlice(size_t pos, size_t n) {
266     return Slice(grpc_slice_sub_no_ref(TakeCSlice(), pos, pos + n));
267   }
268 
269   // Return a sub slice of this one. Adds a reference to the underlying slice.
RefSubSlice(size_t pos,size_t n)270   Slice RefSubSlice(size_t pos, size_t n) const {
271     return Slice(grpc_slice_sub(c_slice(), pos, pos + n));
272   }
273 
274   // Split this slice, returning a new slice containing (split:end] and
275   // leaving this slice with [begin:split).
Split(size_t split)276   Slice Split(size_t split) {
277     return Slice(grpc_slice_split_tail(c_slice_ptr(), split));
278   }
279 
280   Slice Ref() const;
281 
Copy()282   Slice Copy() const { return Slice(grpc_slice_copy(c_slice())); }
283 
284   static Slice FromRefcountAndBytes(grpc_slice_refcount* r,
285                                     const uint8_t* begin, const uint8_t* end);
286 };
287 
288 namespace internal {
289 template <>
290 struct SliceCastable<Slice, grpc_slice> {};
291 template <>
292 struct SliceCastable<grpc_slice, Slice> {};
293 
294 template <>
295 struct SliceCastable<MutableSlice, grpc_slice> {};
296 template <>
297 struct SliceCastable<grpc_slice, MutableSlice> {};
298 
299 template <>
300 struct SliceCastable<MutableSlice, Slice> {};
301 template <>
302 struct SliceCastable<Slice, MutableSlice> {};
303 }  // namespace internal
304 
305 }  // namespace experimental
306 }  // namespace grpc_event_engine
307 
308 #endif  // GRPC_EVENT_ENGINE_SLICE_H
309