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_SRC_CORE_LIB_SLICE_SLICE_BUFFER_H
16 #define GRPC_SRC_CORE_LIB_SLICE_SLICE_BUFFER_H
17 
18 #include <grpc/support/port_platform.h>
19 
20 #include <stdint.h>
21 #include <string.h>
22 
23 #include <memory>
24 #include <string>
25 
26 #include <grpc/slice.h>
27 #include <grpc/slice_buffer.h>
28 
29 #include "src/core/lib/slice/slice.h"
30 
31 namespace grpc_core {
32 
33 /// A slice buffer holds the memory for a collection of slices.
34 /// The SliceBuffer object itself is meant to only hide the C-style API,
35 /// and won't hold the data itself. In terms of lifespan, the
36 /// grpc_slice_buffer ought to be kept somewhere inside the caller's objects,
37 /// like a transport or an endpoint.
38 ///
39 /// This lifespan rule is likely to change in the future, as we may
40 /// collapse the grpc_slice_buffer structure straight into this class.
41 ///
42 /// The SliceBuffer API is basically a replica of the grpc_slice_buffer's,
43 /// and its documentation will move here once we remove the C structure,
44 /// which should happen before the EventEngine's API is no longer
45 /// an experimental API.
46 class SliceBuffer {
47  public:
SliceBuffer()48   explicit SliceBuffer() { grpc_slice_buffer_init(&slice_buffer_); }
49   SliceBuffer(const SliceBuffer& other) = delete;
SliceBuffer(SliceBuffer && other)50   SliceBuffer(SliceBuffer&& other) noexcept {
51     grpc_slice_buffer_init(&slice_buffer_);
52     grpc_slice_buffer_swap(&slice_buffer_, &other.slice_buffer_);
53   }
54   /// Upon destruction, the underlying raw slice buffer is cleaned out and all
55   /// slices are unreffed.
~SliceBuffer()56   ~SliceBuffer() { grpc_slice_buffer_destroy(&slice_buffer_); }
57 
58   SliceBuffer& operator=(const SliceBuffer&) = delete;
59   SliceBuffer& operator=(SliceBuffer&& other) noexcept {
60     grpc_slice_buffer_swap(&slice_buffer_, &other.slice_buffer_);
61     return *this;
62   }
63 
64   /// Appends a new slice into the SliceBuffer and makes an attempt to merge
65   /// this slice with the last slice in the SliceBuffer.
66   void Append(Slice slice);
67   /// Appends a SliceBuffer into the SliceBuffer and makes an attempt to merge
68   /// this slice with the last slice in the SliceBuffer.
69   void Append(const SliceBuffer& other);
70 
71   /// Adds a new slice into the SliceBuffer at the next available index.
72   /// Returns the index at which the new slice is added.
73   size_t AppendIndexed(Slice slice);
74 
75   /// Returns the number of slices held by the SliceBuffer.
Count()76   size_t Count() const { return slice_buffer_.count; }
77 
78   /// Removes/deletes the last n bytes in the SliceBuffer.
RemoveLastNBytes(size_t n)79   void RemoveLastNBytes(size_t n) {
80     grpc_slice_buffer_trim_end(&slice_buffer_, n, nullptr);
81   }
82 
83   /// Move the first n bytes of the SliceBuffer into a memory pointed to by dst.
MoveFirstNBytesIntoBuffer(size_t n,void * dst)84   void MoveFirstNBytesIntoBuffer(size_t n, void* dst) {
85     grpc_slice_buffer_move_first_into_buffer(&slice_buffer_, n, dst);
86   }
87 
88   /// Removes/deletes the last n bytes in the SliceBuffer and add it to the
89   /// other SliceBuffer
MoveLastNBytesIntoSliceBuffer(size_t n,SliceBuffer & other)90   void MoveLastNBytesIntoSliceBuffer(size_t n, SliceBuffer& other) {
91     grpc_slice_buffer_trim_end(&slice_buffer_, n, &other.slice_buffer_);
92   }
93 
94   /// Move the first n bytes of the SliceBuffer into the other SliceBuffer
MoveFirstNBytesIntoSliceBuffer(size_t n,SliceBuffer & other)95   void MoveFirstNBytesIntoSliceBuffer(size_t n, SliceBuffer& other) {
96     grpc_slice_buffer_move_first(&slice_buffer_, n, &other.slice_buffer_);
97   }
98 
99   /// Removes and unrefs all slices in the SliceBuffer.
Clear()100   void Clear() { grpc_slice_buffer_reset_and_unref(&slice_buffer_); }
101 
102   /// Removes the first slice in the SliceBuffer and returns it.
103   Slice TakeFirst();
104 
105   /// Prepends the slice to the the front of the SliceBuffer.
106   void Prepend(Slice slice);
107 
108   /// Increased the ref-count of slice at the specified index and returns the
109   /// associated slice.
110   Slice RefSlice(size_t index) const;
111 
112   const Slice& operator[](size_t index) const {
113     return grpc_event_engine::experimental::internal::SliceCast<Slice>(
114         slice_buffer_.slices[index]);
115   }
116 
117   /// The total number of bytes held by the SliceBuffer
Length()118   size_t Length() const { return slice_buffer_.length; }
119 
120   /// Swap with another slice buffer
Swap(SliceBuffer * other)121   void Swap(SliceBuffer* other) {
122     grpc_slice_buffer_swap(c_slice_buffer(), other->c_slice_buffer());
123   }
124 
125   /// Concatenate all slices and return the resulting string.
126   std::string JoinIntoString() const;
127 
128   // Return a copy of the slice buffer
Copy()129   SliceBuffer Copy() const {
130     SliceBuffer copy;
131     for (size_t i = 0; i < Count(); i++) {
132       copy.Append(RefSlice(i));
133     }
134     return copy;
135   }
136 
137   /// Add a small amount to the end of the slice buffer.
AddTiny(size_t n)138   uint8_t* AddTiny(size_t n) {
139     return grpc_slice_buffer_tiny_add(&slice_buffer_, n);
140   }
141 
142   /// Return a pointer to the back raw grpc_slice_buffer
c_slice_buffer()143   grpc_slice_buffer* c_slice_buffer() { return &slice_buffer_; }
144 
145   /// Return a pointer to the back raw grpc_slice_buffer
c_slice_buffer()146   const grpc_slice_buffer* c_slice_buffer() const { return &slice_buffer_; }
147 
c_slice_at(size_t index)148   const grpc_slice& c_slice_at(size_t index) {
149     return slice_buffer_.slices[index];
150   }
151 
152  private:
153   /// The backing raw slice buffer.
154   grpc_slice_buffer slice_buffer_;
155 
156 // Make failure to destruct show up in ASAN builds.
157 #ifndef NDEBUG
158   std::unique_ptr<int> asan_canary_ = std::make_unique<int>(0);
159 #endif
160 };
161 
162 }  // namespace grpc_core
163 
164 // Copy the first n bytes of src into memory pointed to by dst.
165 void grpc_slice_buffer_copy_first_into_buffer(grpc_slice_buffer* src, size_t n,
166                                               void* dst);
167 
168 #endif  // GRPC_SRC_CORE_LIB_SLICE_SLICE_BUFFER_H
169