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