• 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/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