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