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