1 // Copyright 2021 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_SRC_CORE_LIB_SLICE_SLICE_H
16 #define GRPC_SRC_CORE_LIB_SLICE_SLICE_H
17
18 #include <grpc/support/port_platform.h>
19
20 #include <string.h>
21
22 #include <cstdint>
23 #include <string>
24 #include <utility>
25
26 #include "absl/strings/string_view.h"
27
28 #include <grpc/event_engine/internal/slice_cast.h>
29 #include <grpc/event_engine/slice.h>
30 #include <grpc/slice.h>
31 #include <grpc/support/log.h>
32
33 #include "src/core/lib/gpr/string.h"
34 #include "src/core/lib/gprpp/debug_location.h"
35 #include "src/core/lib/slice/slice_internal.h"
36 #include "src/core/lib/slice/slice_refcount.h"
37
38 // Herein lies grpc_core::Slice and its team of thin wrappers around grpc_slice.
39 // They aim to keep you safe by providing strong guarantees around lifetime and
40 // mutability.
41 //
42 // The team:
43 // Slice - provides a wrapper around an unknown type of slice.
44 // Immutable (since we don't know who else might be referencing
45 // it), and potentially ref counted.
46 // StaticSlice - provides a wrapper around a static slice. Not refcounted,
47 // fast to copy.
48 // MutableSlice - provides a guarantee of unique ownership, meaning the
49 // underlying data can be mutated safely.
50
51 // This slice implementation is an extension of the EventEngine Slice
52 // implementation defined in <grpc/event_engine/slice.h>. Changes to this
53 // implementation might warrant changes to the public EventEngine Slice
54 // type as well.
55
56 namespace grpc_core {
57
58 inline const grpc_slice& CSliceRef(const grpc_slice& slice,
59 DebugLocation loc = {}) {
60 if (reinterpret_cast<uintptr_t>(slice.refcount) > 1) {
61 slice.refcount->Ref(loc);
62 }
63 return slice;
64 }
65
66 inline void CSliceUnref(const grpc_slice& slice, DebugLocation loc = {}) {
67 if (reinterpret_cast<uintptr_t>(slice.refcount) > 1) {
68 slice.refcount->Unref(loc);
69 }
70 }
71
72 namespace slice_detail {
73
74 // Returns an empty slice.
EmptySlice()75 static constexpr grpc_slice EmptySlice() { return {nullptr, {}}; }
76
77 // BaseSlice holds the grpc_slice object, but does not apply refcounting policy.
78 // It does export immutable access into the slice, such that this can be shared
79 // by all storage policies.
80 class BaseSlice {
81 public:
82 BaseSlice(const BaseSlice&) = delete;
83 BaseSlice& operator=(const BaseSlice&) = delete;
84 BaseSlice(BaseSlice&& other) = delete;
85 BaseSlice& operator=(BaseSlice&& other) = delete;
86
87 // Iterator access to the underlying bytes
begin()88 const uint8_t* begin() const { return GRPC_SLICE_START_PTR(c_slice()); }
end()89 const uint8_t* end() const { return GRPC_SLICE_END_PTR(c_slice()); }
cbegin()90 const uint8_t* cbegin() const { return GRPC_SLICE_START_PTR(c_slice()); }
cend()91 const uint8_t* cend() const { return GRPC_SLICE_END_PTR(c_slice()); }
92
93 // Retrieve a borrowed reference to the underlying grpc_slice.
c_slice()94 const grpc_slice& c_slice() const { return slice_; }
95
96 // Retrieve the underlying grpc_slice, and replace the one in this object with
97 // EmptySlice().
TakeCSlice()98 grpc_slice TakeCSlice() {
99 grpc_slice out = slice_;
100 slice_ = EmptySlice();
101 return out;
102 }
103
104 // As other things... borrowed references.
as_string_view()105 absl::string_view as_string_view() const {
106 return absl::string_view(reinterpret_cast<const char*>(data()), size());
107 }
108
109 // Array access
110 uint8_t operator[](size_t i) const {
111 return GRPC_SLICE_START_PTR(c_slice())[i];
112 }
113
114 // Access underlying data
data()115 const uint8_t* data() const { return GRPC_SLICE_START_PTR(c_slice()); }
116
117 // Size of the slice
size()118 size_t size() const { return GRPC_SLICE_LENGTH(c_slice()); }
length()119 size_t length() const { return size(); }
empty()120 bool empty() const { return size() == 0; }
121
122 // For inlined slices - are these two slices equal?
123 // For non-inlined slices - do these two slices refer to the same block of
124 // memory?
is_equivalent(const BaseSlice & other)125 bool is_equivalent(const BaseSlice& other) const {
126 return grpc_slice_is_equivalent(slice_, other.slice_);
127 }
128
Hash()129 uint32_t Hash() const { return grpc_slice_hash(slice_); }
130
131 protected:
BaseSlice()132 BaseSlice() : slice_(EmptySlice()) {}
BaseSlice(const grpc_slice & slice)133 explicit BaseSlice(const grpc_slice& slice) : slice_(slice) {}
134 ~BaseSlice() = default;
135
Swap(BaseSlice * other)136 void Swap(BaseSlice* other) { std::swap(slice_, other->slice_); }
SetCSlice(const grpc_slice & slice)137 void SetCSlice(const grpc_slice& slice) { slice_ = slice; }
138
mutable_data()139 uint8_t* mutable_data() { return GRPC_SLICE_START_PTR(slice_); }
140
c_slice_ptr()141 grpc_slice* c_slice_ptr() { return &slice_; }
142
143 private:
144 grpc_slice slice_;
145 };
146
147 inline bool operator==(const BaseSlice& a, const BaseSlice& b) {
148 return grpc_slice_eq(a.c_slice(), b.c_slice()) != 0;
149 }
150
151 inline bool operator!=(const BaseSlice& a, const BaseSlice& b) {
152 return grpc_slice_eq(a.c_slice(), b.c_slice()) == 0;
153 }
154
155 inline bool operator==(const BaseSlice& a, absl::string_view b) {
156 return a.as_string_view() == b;
157 }
158
159 inline bool operator!=(const BaseSlice& a, absl::string_view b) {
160 return a.as_string_view() != b;
161 }
162
163 inline bool operator==(absl::string_view a, const BaseSlice& b) {
164 return a == b.as_string_view();
165 }
166
167 inline bool operator!=(absl::string_view a, const BaseSlice& b) {
168 return a != b.as_string_view();
169 }
170
171 inline bool operator==(const BaseSlice& a, const grpc_slice& b) {
172 return grpc_slice_eq(a.c_slice(), b) != 0;
173 }
174
175 inline bool operator!=(const BaseSlice& a, const grpc_slice& b) {
176 return grpc_slice_eq(a.c_slice(), b) == 0;
177 }
178
179 inline bool operator==(const grpc_slice& a, const BaseSlice& b) {
180 return grpc_slice_eq(a, b.c_slice()) != 0;
181 }
182
183 inline bool operator!=(const grpc_slice& a, const BaseSlice& b) {
184 return grpc_slice_eq(a, b.c_slice()) == 0;
185 }
186
187 template <typename Out>
188 struct CopyConstructors {
FromCopiedStringCopyConstructors189 static Out FromCopiedString(const char* s) {
190 return FromCopiedBuffer(s, strlen(s));
191 }
FromCopiedStringCopyConstructors192 static Out FromCopiedString(absl::string_view s) {
193 return FromCopiedBuffer(s.data(), s.size());
194 }
FromCopiedStringCopyConstructors195 static Out FromCopiedString(std::string s) {
196 return Out(grpc_slice_from_cpp_string(std::move(s)));
197 }
FromCopiedBufferCopyConstructors198 static Out FromCopiedBuffer(const char* p, size_t len) {
199 return Out(grpc_slice_from_copied_buffer(p, len));
200 }
FromCopiedBufferCopyConstructors201 static Out FromCopiedBuffer(const uint8_t* p, size_t len) {
202 return Out(
203 grpc_slice_from_copied_buffer(reinterpret_cast<const char*>(p), len));
204 }
205
206 template <typename Buffer>
FromCopiedBufferCopyConstructors207 static Out FromCopiedBuffer(const Buffer& buffer) {
208 return FromCopiedBuffer(reinterpret_cast<const char*>(buffer.data()),
209 buffer.size());
210 }
211
FromInt64CopyConstructors212 static Out FromInt64(int64_t i) {
213 char buffer[GPR_LTOA_MIN_BUFSIZE];
214 gpr_ltoa(i, buffer);
215 return FromCopiedString(buffer);
216 }
217 };
218
219 template <typename Out>
220 struct StaticConstructors {
FromStaticStringStaticConstructors221 static Out FromStaticString(const char* s) {
222 return FromStaticBuffer(s, strlen(s));
223 }
224
FromStaticStringStaticConstructors225 static Out FromStaticString(absl::string_view s) {
226 return FromStaticBuffer(s.data(), s.size());
227 }
228
FromStaticBufferStaticConstructors229 static Out FromStaticBuffer(const void* s, size_t len) {
230 grpc_slice slice;
231 slice.refcount = grpc_slice_refcount::NoopRefcount();
232 slice.data.refcounted.bytes =
233 const_cast<uint8_t*>(static_cast<const uint8_t*>(s));
234 slice.data.refcounted.length = len;
235 return Out(slice);
236 }
237 };
238
239 } // namespace slice_detail
240
241 class StaticSlice : public slice_detail::BaseSlice,
242 public slice_detail::StaticConstructors<StaticSlice> {
243 public:
244 StaticSlice() = default;
StaticSlice(const grpc_slice & slice)245 explicit StaticSlice(const grpc_slice& slice)
246 : slice_detail::BaseSlice(slice) {
247 GPR_DEBUG_ASSERT(slice.refcount == grpc_slice_refcount::NoopRefcount());
248 }
249
StaticSlice(const StaticSlice & other)250 StaticSlice(const StaticSlice& other)
251 : slice_detail::BaseSlice(other.c_slice()) {}
252 StaticSlice& operator=(const StaticSlice& other) {
253 SetCSlice(other.c_slice());
254 return *this;
255 }
StaticSlice(StaticSlice && other)256 StaticSlice(StaticSlice&& other) noexcept
257 : slice_detail::BaseSlice(other.TakeCSlice()) {}
258 StaticSlice& operator=(StaticSlice&& other) noexcept {
259 Swap(&other);
260 return *this;
261 }
262 };
263
264 class GPR_MSVC_EMPTY_BASE_CLASS_WORKAROUND MutableSlice
265 : public slice_detail::BaseSlice,
266 public slice_detail::CopyConstructors<MutableSlice> {
267 public:
268 MutableSlice() = default;
MutableSlice(const grpc_slice & slice)269 explicit MutableSlice(const grpc_slice& slice)
270 : slice_detail::BaseSlice(slice) {
271 GPR_DEBUG_ASSERT(slice.refcount == nullptr || slice.refcount->IsUnique());
272 }
~MutableSlice()273 ~MutableSlice() { CSliceUnref(c_slice()); }
274
275 MutableSlice(const MutableSlice&) = delete;
276 MutableSlice& operator=(const MutableSlice&) = delete;
MutableSlice(MutableSlice && other)277 MutableSlice(MutableSlice&& other) noexcept
278 : slice_detail::BaseSlice(other.TakeCSlice()) {}
279 MutableSlice& operator=(MutableSlice&& other) noexcept {
280 Swap(&other);
281 return *this;
282 }
283
CreateUninitialized(size_t length)284 static MutableSlice CreateUninitialized(size_t length) {
285 return MutableSlice(grpc_slice_malloc(length));
286 }
287
288 // Return a sub slice of this one. Leaves this slice in an indeterminate but
289 // valid state.
TakeSubSlice(size_t pos,size_t n)290 MutableSlice TakeSubSlice(size_t pos, size_t n) {
291 return MutableSlice(grpc_slice_sub_no_ref(TakeCSlice(), pos, pos + n));
292 }
293
294 // Split this slice in two, returning the first n bytes and leaving the
295 // remainder.
TakeFirst(size_t n)296 MutableSlice TakeFirst(size_t n) {
297 return MutableSlice(NoCheck{}, grpc_slice_split_head(c_slice_ptr(), n));
298 }
299
300 // Iterator access to the underlying bytes
begin()301 uint8_t* begin() { return mutable_data(); }
end()302 uint8_t* end() { return mutable_data() + size(); }
data()303 uint8_t* data() { return mutable_data(); }
304
305 // Array access
306 uint8_t& operator[](size_t i) { return mutable_data()[i]; }
307
308 using slice_detail::BaseSlice::c_slice_ptr;
309
310 private:
311 struct NoCheck {};
MutableSlice(NoCheck,const grpc_slice & slice)312 MutableSlice(NoCheck, const grpc_slice& slice)
313 : slice_detail::BaseSlice(slice) {}
314 };
315
316 class GPR_MSVC_EMPTY_BASE_CLASS_WORKAROUND Slice
317 : public slice_detail::BaseSlice,
318 public slice_detail::CopyConstructors<Slice>,
319 public slice_detail::StaticConstructors<Slice> {
320 public:
321 Slice() = default;
~Slice()322 ~Slice() { CSliceUnref(c_slice()); }
323
Slice(const grpc_slice & slice)324 explicit Slice(const grpc_slice& slice) : slice_detail::BaseSlice(slice) {}
Slice(slice_detail::BaseSlice && other)325 explicit Slice(slice_detail::BaseSlice&& other)
326 : slice_detail::BaseSlice(other.TakeCSlice()) {}
327
328 Slice(const Slice&) = delete;
329 Slice& operator=(const Slice&) = delete;
Slice(Slice && other)330 Slice(Slice&& other) noexcept : slice_detail::BaseSlice(other.TakeCSlice()) {}
331 Slice& operator=(Slice&& other) noexcept {
332 Swap(&other);
333 return *this;
334 }
335
336 // A slice might refer to some memory that we keep a refcount to (this is
337 // owned), or some memory that's inlined into the slice (also owned), or some
338 // other block of memory that we know will be available for the lifetime of
339 // some operation in the common case (not owned). In the *less common* case
340 // that we need to keep that slice text for longer than our API's guarantee us
341 // access, we need to take a copy and turn this into something that we do own.
342
343 // TakeOwned returns an owned slice regardless of current ownership, and
344 // leaves the current slice in a valid but externally unpredictable state - in
345 // doing so it can avoid adding a ref to the underlying slice.
TakeOwned()346 Slice TakeOwned() {
347 if (c_slice().refcount == nullptr) {
348 return Slice(c_slice());
349 }
350 if (c_slice().refcount == grpc_slice_refcount::NoopRefcount()) {
351 return Slice(grpc_slice_copy(c_slice()));
352 }
353 return Slice(TakeCSlice());
354 }
355
356 // As per TakeOwned, but if the slice is refcounted and there are other refs
357 // then it will copy instead of ref-counting, to ensure the returned slice is
358 // not shared.
TakeUniquelyOwned()359 Slice TakeUniquelyOwned() {
360 if (c_slice().refcount == nullptr) {
361 return Slice(c_slice());
362 }
363 if (c_slice().refcount == grpc_slice_refcount::NoopRefcount()) {
364 return Slice(grpc_slice_copy(c_slice()));
365 }
366 if (c_slice().refcount->IsUnique()) {
367 return Slice(TakeCSlice());
368 }
369 return Slice(grpc_slice_copy(c_slice()));
370 }
371
372 // AsOwned returns an owned slice but does not mutate the current slice,
373 // meaning that it may add a reference to the underlying slice.
AsOwned()374 Slice AsOwned() const {
375 if (c_slice().refcount == nullptr) {
376 return Slice(c_slice());
377 }
378 if (c_slice().refcount == grpc_slice_refcount::NoopRefcount()) {
379 return Slice(grpc_slice_copy(c_slice()));
380 }
381 return Ref();
382 }
383
384 // TakeMutable returns a MutableSlice, and leaves the current slice in an
385 // indeterminate but valid state.
386 // A mutable slice requires only one reference to the bytes of the slice -
387 // this can be achieved either with inlined storage or with a single
388 // reference.
389 // If the current slice is refcounted and there are more than one references
390 // to that slice, then the slice is copied in order to achieve a mutable
391 // version.
TakeMutable()392 MutableSlice TakeMutable() {
393 if (c_slice().refcount == nullptr) {
394 return MutableSlice(c_slice());
395 }
396 if (c_slice().refcount != grpc_slice_refcount::NoopRefcount() &&
397 c_slice().refcount->IsUnique()) {
398 return MutableSlice(TakeCSlice());
399 }
400 return MutableSlice(grpc_slice_copy(c_slice()));
401 }
402
403 // Return a sub slice of this one. Leaves this slice in an indeterminate but
404 // valid state.
TakeSubSlice(size_t pos,size_t n)405 Slice TakeSubSlice(size_t pos, size_t n) {
406 return Slice(grpc_slice_sub_no_ref(TakeCSlice(), pos, pos + n));
407 }
408
409 // Return a sub slice of this one. Adds a reference to the underlying slice.
RefSubSlice(size_t pos,size_t n)410 Slice RefSubSlice(size_t pos, size_t n) const {
411 return Slice(grpc_slice_sub(c_slice(), pos, pos + n));
412 }
413
414 // Split this slice, returning a new slice containing (split:end] and
415 // leaving this slice with [begin:split).
Split(size_t split)416 Slice Split(size_t split) {
417 return Slice(grpc_slice_split_tail(c_slice_ptr(), split));
418 }
419
Ref()420 Slice Ref() const { return Slice(CSliceRef(c_slice())); }
421
Copy()422 Slice Copy() const { return Slice(grpc_slice_copy(c_slice())); }
423
424 static Slice FromRefcountAndBytes(grpc_slice_refcount* r,
425 const uint8_t* begin, const uint8_t* end,
426 DebugLocation location = {}) {
427 grpc_slice out;
428 out.refcount = r;
429 if (r != grpc_slice_refcount::NoopRefcount()) r->Ref(location);
430 out.data.refcounted.bytes = const_cast<uint8_t*>(begin);
431 out.data.refcounted.length = end - begin;
432 return Slice(out);
433 }
434
FromExternalString(absl::string_view str)435 static Slice FromExternalString(absl::string_view str) {
436 return FromStaticString(str);
437 }
438 };
439
440 } // namespace grpc_core
441
442 namespace grpc_event_engine {
443 namespace experimental {
444 namespace internal {
445 template <>
446 struct SliceCastable<grpc_core::Slice, grpc_slice> {};
447 template <>
448 struct SliceCastable<grpc_slice, grpc_core::Slice> {};
449 template <>
450 struct SliceCastable<grpc_core::Slice, Slice> {};
451 template <>
452 struct SliceCastable<Slice, grpc_core::Slice> {};
453 } // namespace internal
454 } // namespace experimental
455 } // namespace grpc_event_engine
456
457 #endif // GRPC_SRC_CORE_LIB_SLICE_SLICE_H
458