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