Imported Upstream version 1.25.0
[platform/core/ml/nnfw.git] / onert-micro / externals / flatbuffers / grpc.h
1 /*
2  * Copyright (c) 2023 Samsung Electronics Co., Ltd. All Rights Reserved
3  * Copyright 2014 Google Inc. All rights reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #ifndef FLATBUFFERS_GRPC_H_
19 #define FLATBUFFERS_GRPC_H_
20
21 // Helper functionality to glue FlatBuffers and GRPC.
22
23 #include "flatbuffers/flatbuffers.h"
24 #include "grpc/byte_buffer_reader.h"
25 #include "grpcpp/support/byte_buffer.h"
26
27 namespace flatbuffers
28 {
29 namespace grpc
30 {
31
32 // Message is a typed wrapper around a buffer that manages the underlying
33 // `grpc_slice` and also provides flatbuffers-specific helpers such as `Verify`
34 // and `GetRoot`. Since it is backed by a `grpc_slice`, the underlying buffer
35 // is refcounted and ownership is be managed automatically.
36 template <class T> class Message
37 {
38 public:
39   Message() : slice_(grpc_empty_slice()) {}
40
41   Message(grpc_slice slice, bool add_ref) : slice_(add_ref ? grpc_slice_ref(slice) : slice) {}
42
43   Message &operator=(const Message &other) = delete;
44
45   Message(Message &&other) : slice_(other.slice_) { other.slice_ = grpc_empty_slice(); }
46
47   Message(const Message &other) = delete;
48
49   Message &operator=(Message &&other)
50   {
51     grpc_slice_unref(slice_);
52     slice_ = other.slice_;
53     other.slice_ = grpc_empty_slice();
54     return *this;
55   }
56
57   ~Message() { grpc_slice_unref(slice_); }
58
59   const uint8_t *mutable_data() const { return GRPC_SLICE_START_PTR(slice_); }
60
61   const uint8_t *data() const { return GRPC_SLICE_START_PTR(slice_); }
62
63   size_t size() const { return GRPC_SLICE_LENGTH(slice_); }
64
65   bool Verify() const
66   {
67     Verifier verifier(data(), size());
68     return verifier.VerifyBuffer<T>(nullptr);
69   }
70
71   T *GetMutableRoot() { return flatbuffers::GetMutableRoot<T>(mutable_data()); }
72
73   const T *GetRoot() const { return flatbuffers::GetRoot<T>(data()); }
74
75   // This is only intended for serializer use, or if you know what you're doing
76   const grpc_slice &BorrowSlice() const { return slice_; }
77
78 private:
79   grpc_slice slice_;
80 };
81
82 class MessageBuilder;
83
84 // SliceAllocator is a gRPC-specific allocator that uses the `grpc_slice`
85 // refcounted slices to manage memory ownership. This makes it easy and
86 // efficient to transfer buffers to gRPC.
87 class SliceAllocator : public Allocator
88 {
89 public:
90   SliceAllocator() : slice_(grpc_empty_slice()) {}
91
92   SliceAllocator(const SliceAllocator &other) = delete;
93   SliceAllocator &operator=(const SliceAllocator &other) = delete;
94
95   SliceAllocator(SliceAllocator &&other) : slice_(grpc_empty_slice())
96   {
97     // default-construct and swap idiom
98     swap(other);
99   }
100
101   SliceAllocator &operator=(SliceAllocator &&other)
102   {
103     // move-construct and swap idiom
104     SliceAllocator temp(std::move(other));
105     swap(temp);
106     return *this;
107   }
108
109   void swap(SliceAllocator &other)
110   {
111     using std::swap;
112     swap(slice_, other.slice_);
113   }
114
115   virtual ~SliceAllocator() { grpc_slice_unref(slice_); }
116
117   virtual uint8_t *allocate(size_t size) override
118   {
119     FLATBUFFERS_ASSERT(GRPC_SLICE_IS_EMPTY(slice_));
120     slice_ = grpc_slice_malloc(size);
121     return GRPC_SLICE_START_PTR(slice_);
122   }
123
124   virtual void deallocate(uint8_t *p, size_t size) override
125   {
126     FLATBUFFERS_ASSERT(p == GRPC_SLICE_START_PTR(slice_));
127     FLATBUFFERS_ASSERT(size == GRPC_SLICE_LENGTH(slice_));
128     grpc_slice_unref(slice_);
129     slice_ = grpc_empty_slice();
130   }
131
132   virtual uint8_t *reallocate_downward(uint8_t *old_p, size_t old_size, size_t new_size,
133                                        size_t in_use_back, size_t in_use_front) override
134   {
135     FLATBUFFERS_ASSERT(old_p == GRPC_SLICE_START_PTR(slice_));
136     FLATBUFFERS_ASSERT(old_size == GRPC_SLICE_LENGTH(slice_));
137     FLATBUFFERS_ASSERT(new_size > old_size);
138     grpc_slice old_slice = slice_;
139     grpc_slice new_slice = grpc_slice_malloc(new_size);
140     uint8_t *new_p = GRPC_SLICE_START_PTR(new_slice);
141     memcpy_downward(old_p, old_size, new_p, new_size, in_use_back, in_use_front);
142     slice_ = new_slice;
143     grpc_slice_unref(old_slice);
144     return new_p;
145   }
146
147 private:
148   grpc_slice &get_slice(uint8_t *p, size_t size)
149   {
150     FLATBUFFERS_ASSERT(p == GRPC_SLICE_START_PTR(slice_));
151     FLATBUFFERS_ASSERT(size == GRPC_SLICE_LENGTH(slice_));
152     return slice_;
153   }
154
155   grpc_slice slice_;
156
157   friend class MessageBuilder;
158 };
159
160 // SliceAllocatorMember is a hack to ensure that the MessageBuilder's
161 // slice_allocator_ member is constructed before the FlatBufferBuilder, since
162 // the allocator is used in the FlatBufferBuilder ctor.
163 namespace detail
164 {
165 struct SliceAllocatorMember
166 {
167   SliceAllocator slice_allocator_;
168 };
169 } // namespace detail
170
171 // MessageBuilder is a gRPC-specific FlatBufferBuilder that uses SliceAllocator
172 // to allocate gRPC buffers.
173 class MessageBuilder : private detail::SliceAllocatorMember, public FlatBufferBuilder
174 {
175 public:
176   explicit MessageBuilder(uoffset_t initial_size = 1024)
177     : FlatBufferBuilder(initial_size, &slice_allocator_, false)
178   {
179   }
180
181   MessageBuilder(const MessageBuilder &other) = delete;
182   MessageBuilder &operator=(const MessageBuilder &other) = delete;
183
184   MessageBuilder(MessageBuilder &&other) : FlatBufferBuilder(1024, &slice_allocator_, false)
185   {
186     // Default construct and swap idiom.
187     Swap(other);
188   }
189
190   /// Create a MessageBuilder from a FlatBufferBuilder.
191   explicit MessageBuilder(FlatBufferBuilder &&src,
192                           void (*dealloc)(void *, size_t) = &DefaultAllocator::dealloc)
193     : FlatBufferBuilder(1024, &slice_allocator_, false)
194   {
195     src.Swap(*this);
196     src.SwapBufAllocator(*this);
197     if (buf_.capacity())
198     {
199       uint8_t *buf = buf_.scratch_data(); // pointer to memory
200       size_t capacity = buf_.capacity();  // size of memory
201       slice_allocator_.slice_ = grpc_slice_new_with_len(buf, capacity, dealloc);
202     }
203     else
204     {
205       slice_allocator_.slice_ = grpc_empty_slice();
206     }
207   }
208
209   /// Move-assign a FlatBufferBuilder to a MessageBuilder.
210   /// Only FlatBufferBuilder with default allocator (basically, nullptr) is
211   /// supported.
212   MessageBuilder &operator=(FlatBufferBuilder &&src)
213   {
214     // Move construct a temporary and swap
215     MessageBuilder temp(std::move(src));
216     Swap(temp);
217     return *this;
218   }
219
220   MessageBuilder &operator=(MessageBuilder &&other)
221   {
222     // Move construct a temporary and swap
223     MessageBuilder temp(std::move(other));
224     Swap(temp);
225     return *this;
226   }
227
228   void Swap(MessageBuilder &other)
229   {
230     slice_allocator_.swap(other.slice_allocator_);
231     FlatBufferBuilder::Swap(other);
232     // After swapping the FlatBufferBuilder, we swap back the allocator, which
233     // restores the original allocator back in place. This is necessary because
234     // MessageBuilder's allocator is its own member (SliceAllocatorMember). The
235     // allocator passed to FlatBufferBuilder::vector_downward must point to this
236     // member.
237     buf_.swap_allocator(other.buf_);
238   }
239
240   // Releases the ownership of the buffer pointer.
241   // Returns the size, offset, and the original grpc_slice that
242   // allocated the buffer. Also see grpc_slice_unref().
243   uint8_t *ReleaseRaw(size_t &size, size_t &offset, grpc_slice &slice)
244   {
245     uint8_t *buf = FlatBufferBuilder::ReleaseRaw(size, offset);
246     slice = slice_allocator_.slice_;
247     slice_allocator_.slice_ = grpc_empty_slice();
248     return buf;
249   }
250
251   ~MessageBuilder() {}
252
253   // GetMessage extracts the subslice of the buffer corresponding to the
254   // flatbuffers-encoded region and wraps it in a `Message<T>` to handle buffer
255   // ownership.
256   template <class T> Message<T> GetMessage()
257   {
258     auto buf_data = buf_.scratch_data(); // pointer to memory
259     auto buf_size = buf_.capacity();     // size of memory
260     auto msg_data = buf_.data();         // pointer to msg
261     auto msg_size = buf_.size();         // size of msg
262     // Do some sanity checks on data/size
263     FLATBUFFERS_ASSERT(msg_data);
264     FLATBUFFERS_ASSERT(msg_size);
265     FLATBUFFERS_ASSERT(msg_data >= buf_data);
266     FLATBUFFERS_ASSERT(msg_data + msg_size <= buf_data + buf_size);
267     // Calculate offsets from the buffer start
268     auto begin = msg_data - buf_data;
269     auto end = begin + msg_size;
270     // Get the slice we are working with (no refcount change)
271     grpc_slice slice = slice_allocator_.get_slice(buf_data, buf_size);
272     // Extract a subslice of the existing slice (increment refcount)
273     grpc_slice subslice = grpc_slice_sub(slice, begin, end);
274     // Wrap the subslice in a `Message<T>`, but don't increment refcount
275     Message<T> msg(subslice, false);
276     return msg;
277   }
278
279   template <class T> Message<T> ReleaseMessage()
280   {
281     Message<T> msg = GetMessage<T>();
282     Reset();
283     return msg;
284   }
285
286 private:
287   // SliceAllocator slice_allocator_;  // part of SliceAllocatorMember
288 };
289
290 } // namespace grpc
291 } // namespace flatbuffers
292
293 namespace grpc
294 {
295
296 template <class T> class SerializationTraits<flatbuffers::grpc::Message<T>>
297 {
298 public:
299   static grpc::Status Serialize(const flatbuffers::grpc::Message<T> &msg, grpc_byte_buffer **buffer,
300                                 bool *own_buffer)
301   {
302     // We are passed in a `Message<T>`, which is a wrapper around a
303     // `grpc_slice`. We extract it here using `BorrowSlice()`. The const cast
304     // is necessary because the `grpc_raw_byte_buffer_create` func expects
305     // non-const slices in order to increment their refcounts.
306     grpc_slice *slice = const_cast<grpc_slice *>(&msg.BorrowSlice());
307     // Now use `grpc_raw_byte_buffer_create` to package the single slice into a
308     // `grpc_byte_buffer`, incrementing the refcount in the process.
309     *buffer = grpc_raw_byte_buffer_create(slice, 1);
310     *own_buffer = true;
311     return grpc::Status::OK;
312   }
313
314   // Deserialize by pulling the
315   static grpc::Status Deserialize(ByteBuffer *buf, flatbuffers::grpc::Message<T> *msg)
316   {
317     grpc_byte_buffer *buffer = *reinterpret_cast<grpc_byte_buffer **>(buf);
318     if (!buffer)
319     {
320       return ::grpc::Status(::grpc::StatusCode::INTERNAL, "No payload");
321     }
322     // Check if this is a single uncompressed slice.
323     if ((buffer->type == GRPC_BB_RAW) && (buffer->data.raw.compression == GRPC_COMPRESS_NONE) &&
324         (buffer->data.raw.slice_buffer.count == 1))
325     {
326       // If it is, then we can reference the `grpc_slice` directly.
327       grpc_slice slice = buffer->data.raw.slice_buffer.slices[0];
328       // We wrap a `Message<T>` around the slice, incrementing the refcount.
329       *msg = flatbuffers::grpc::Message<T>(slice, true);
330     }
331     else
332     {
333       // Otherwise, we need to use `grpc_byte_buffer_reader_readall` to read
334       // `buffer` into a single contiguous `grpc_slice`. The gRPC reader gives
335       // us back a new slice with the refcount already incremented.
336       grpc_byte_buffer_reader reader;
337       grpc_byte_buffer_reader_init(&reader, buffer);
338       grpc_slice slice = grpc_byte_buffer_reader_readall(&reader);
339       grpc_byte_buffer_reader_destroy(&reader);
340       // We wrap a `Message<T>` around the slice, but don't increment refcount
341       *msg = flatbuffers::grpc::Message<T>(slice, false);
342     }
343     grpc_byte_buffer_destroy(buffer);
344 #if FLATBUFFERS_GRPC_DISABLE_AUTO_VERIFICATION
345     return ::grpc::Status::OK;
346 #else
347     if (msg->Verify())
348     {
349       return ::grpc::Status::OK;
350     }
351     else
352     {
353       return ::grpc::Status(::grpc::StatusCode::INTERNAL, "Message verification failed");
354     }
355 #endif
356   }
357 };
358
359 } // namespace grpc
360
361 #endif // FLATBUFFERS_GRPC_H_