DCCL v3
dccl_native_protobuf.h
1 // Copyright 2009-2017 Toby Schneider (http://gobysoft.org/index.wt/people/toby)
2 // GobySoft, LLC (for 2013-)
3 // Massachusetts Institute of Technology (for 2007-2014)
4 // Community contributors (see AUTHORS file)
5 //
6 //
7 // This file is part of the Dynamic Compact Control Language Library
8 // ("DCCL").
9 //
10 // DCCL is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 2.1 of the License, or
13 // (at your option) any later version.
14 //
15 // DCCL is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with DCCL. If not, see <http://www.gnu.org/licenses/>.
22 #ifndef DCCL_NATIVE_PROTOBUF_20190218H
23 #define DCCL_NATIVE_PROTOBUF_20190218H
24 
25 #include <google/protobuf/unknown_field_set.h>
26 #include <google/protobuf/io/coded_stream.h>
27 #include <google/protobuf/io/zero_copy_stream_impl_lite.h>
28 #include <google/protobuf/wire_format_lite.h>
29 #include <google/protobuf/wire_format_lite_inl.h>
30 
31 #include "dccl/field_codec_fixed.h"
32 #include "dccl/field_codec_typed.h"
33 
34 namespace dccl
35 {
37 namespace native_protobuf
38 {
39 
40 template<typename WireType, google::protobuf::internal::WireFormatLite::FieldType DeclaredType>
42 {
43  WireType decode(google::protobuf::io::CodedInputStream* input_stream)
44  {
45  WireType value;
46  google::protobuf::internal::WireFormatLite::ReadPrimitive<WireType, DeclaredType>(input_stream, &value);
47  return value;
48  }
49 };
50 
51 
52 template<typename WireType, google::protobuf::FieldDescriptor::Type DeclaredType>
54 {
55 };
56 
57 template<typename WireType>
58 struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_INT64> : public PrimitiveTypeHelperBase<WireType, google::protobuf::internal::WireFormatLite::TYPE_INT64>
59 {
60  unsigned byte_size(const WireType& wire_value)
61  { return google::protobuf::internal::WireFormatLite::Int64Size(wire_value); }
62  void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
63  { google::protobuf::internal::WireFormatLite::WriteInt64NoTagToArray(wire_value, &(*bytes)[0]); }
64  bool is_varint() { return true; }
65 };
66 
67 template<typename WireType>
68 struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_INT32> : public PrimitiveTypeHelperBase<WireType, google::protobuf::internal::WireFormatLite::TYPE_INT32>
69 {
70  unsigned byte_size(const WireType& wire_value)
71  { return google::protobuf::internal::WireFormatLite::Int32Size(wire_value); }
72  void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
73  { google::protobuf::internal::WireFormatLite::WriteInt32NoTagToArray(wire_value, &(*bytes)[0]); }
74  bool is_varint() { return true; }
75 };
76 
77 
78 template<typename WireType>
79 struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_UINT64> : public PrimitiveTypeHelperBase<WireType, google::protobuf::internal::WireFormatLite::TYPE_UINT64>
80 {
81  unsigned byte_size(const WireType& wire_value)
82  { return google::protobuf::internal::WireFormatLite::UInt64Size(wire_value); }
83  void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
84  { google::protobuf::internal::WireFormatLite::WriteUInt64NoTagToArray(wire_value, &(*bytes)[0]); }
85  bool is_varint() { return true; }
86 };
87 
88 template<typename WireType>
89 struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_UINT32> : public PrimitiveTypeHelperBase<WireType, google::protobuf::internal::WireFormatLite::TYPE_UINT32>
90 {
91  unsigned byte_size(const WireType& wire_value)
92  { return google::protobuf::internal::WireFormatLite::UInt32Size(wire_value); }
93  void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
94  { google::protobuf::internal::WireFormatLite::WriteUInt32NoTagToArray(wire_value, &(*bytes)[0]); }
95  bool is_varint() { return true; }
96 };
97 
98 template<typename WireType>
99 struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_SINT64> : public PrimitiveTypeHelperBase<WireType, google::protobuf::internal::WireFormatLite::TYPE_SINT64>
100 {
101  unsigned byte_size(const WireType& wire_value)
102  { return google::protobuf::internal::WireFormatLite::SInt64Size(wire_value); }
103  void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
104  { google::protobuf::internal::WireFormatLite::WriteSInt64NoTagToArray(wire_value, &(*bytes)[0]); }
105  bool is_varint() { return true; }
106 };
107 
108 template<typename WireType>
109 struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_SINT32> : public PrimitiveTypeHelperBase<WireType, google::protobuf::internal::WireFormatLite::TYPE_SINT32>
110 {
111  unsigned byte_size(const WireType& wire_value)
112  { return google::protobuf::internal::WireFormatLite::SInt32Size(wire_value); }
113  void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
114  { google::protobuf::internal::WireFormatLite::WriteSInt32NoTagToArray(wire_value, &(*bytes)[0]); }
115  bool is_varint() { return true; }
116 };
117 
118 
119 
120 template<typename WireType>
121 struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_ENUM> : public PrimitiveTypeHelperBase<WireType, google::protobuf::internal::WireFormatLite::TYPE_ENUM>
122 {
123  unsigned byte_size(const WireType& wire_value)
124  { return google::protobuf::internal::WireFormatLite::EnumSize(wire_value); }
125  void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
126  { google::protobuf::internal::WireFormatLite::WriteEnumNoTagToArray(wire_value, &(*bytes)[0]); }
127  bool is_varint() { return true; }
128 };
129 
130 
131 template<typename WireType>
132 struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_DOUBLE> : public PrimitiveTypeHelperBase<WireType, google::protobuf::internal::WireFormatLite::TYPE_DOUBLE>
133 {
134  unsigned byte_size(const WireType& wire_value)
135  { return google::protobuf::internal::WireFormatLite::kDoubleSize; }
136  void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
137  { google::protobuf::internal::WireFormatLite::WriteDoubleNoTagToArray(wire_value, &(*bytes)[0]); }
138  bool is_varint() { return false; }
139 };
140 
141 template<typename WireType>
142 struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_FLOAT> : public PrimitiveTypeHelperBase<WireType, google::protobuf::internal::WireFormatLite::TYPE_FLOAT>
143 {
144  unsigned byte_size(const WireType& wire_value)
145  { return google::protobuf::internal::WireFormatLite::kFloatSize; }
146  void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
147  { google::protobuf::internal::WireFormatLite::WriteFloatNoTagToArray(wire_value, &(*bytes)[0]); }
148  bool is_varint() { return false; }
149 };
150 
151 template<typename WireType>
152 struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_BOOL> : public PrimitiveTypeHelperBase<WireType, google::protobuf::internal::WireFormatLite::TYPE_BOOL>
153 {
154  unsigned byte_size(const WireType& wire_value)
155  { return google::protobuf::internal::WireFormatLite::kBoolSize; }
156  void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
157  { google::protobuf::internal::WireFormatLite::WriteBoolNoTagToArray(wire_value, &(*bytes)[0]); }
158  bool is_varint() { return false; }
159 };
160 
161 
162 template<typename WireType>
163 struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_FIXED64> : public PrimitiveTypeHelperBase<WireType, google::protobuf::internal::WireFormatLite::TYPE_FIXED64>
164 {
165  unsigned byte_size(const WireType& wire_value)
166  { return google::protobuf::internal::WireFormatLite::kFixed64Size; }
167  void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
168  { google::protobuf::internal::WireFormatLite::WriteFixed64NoTagToArray(wire_value, &(*bytes)[0]); }
169  bool is_varint() { return false; }
170 };
171 
172 template<typename WireType>
173 struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_FIXED32> : public PrimitiveTypeHelperBase<WireType, google::protobuf::internal::WireFormatLite::TYPE_FIXED32>
174 {
175  unsigned byte_size(const WireType& wire_value)
176  { return google::protobuf::internal::WireFormatLite::kFixed32Size; }
177  void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
178  { google::protobuf::internal::WireFormatLite::WriteFixed32NoTagToArray(wire_value, &(*bytes)[0]); }
179  bool is_varint() { return false; }
180 };
181 
182 template<typename WireType>
183 struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_SFIXED64> : public PrimitiveTypeHelperBase<WireType, google::protobuf::internal::WireFormatLite::TYPE_SFIXED64>
184 {
185  unsigned byte_size(const WireType& wire_value)
186  { return google::protobuf::internal::WireFormatLite::kSFixed64Size; }
187  void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
188  { google::protobuf::internal::WireFormatLite::WriteSFixed64NoTagToArray(wire_value, &(*bytes)[0]); }
189  bool is_varint() { return false; }
190 };
191 
192 template<typename WireType>
193 struct PrimitiveTypeHelper<WireType, google::protobuf::FieldDescriptor::TYPE_SFIXED32> : public PrimitiveTypeHelperBase<WireType, google::protobuf::internal::WireFormatLite::TYPE_SFIXED32>
194 {
195  unsigned byte_size(const WireType& wire_value)
196  { return google::protobuf::internal::WireFormatLite::kSFixed32Size; }
197  void encode(WireType wire_value, std::vector<google::protobuf::uint8>* bytes)
198  { google::protobuf::internal::WireFormatLite::WriteSFixed32NoTagToArray(wire_value, &(*bytes)[0]); }
199  bool is_varint() { return false; }
200 };
201 
202 template<typename WireType, google::protobuf::FieldDescriptor::Type DeclaredType, typename FieldType = WireType>
203 class PrimitiveTypeFieldCodec : public TypedFieldCodec<WireType, FieldType>
204 {
205 private:
206  unsigned presence_bit_size()
207  {
208  return this->use_required() ? 0 : 1;
209  }
210 
211  unsigned min_size()
212  {
213  // if required, minimum size is 1-byte (for varint) or full size (for non-varint)
214  if(this->use_required())
215  {
216  if(helper_.is_varint())
217  return BITS_IN_BYTE;
218  else
219  return BITS_IN_BYTE*helper_.byte_size(WireType());
220  }
221  // if not required, presence bit
222  else
223  {
224  return presence_bit_size();
225  }
226 
227  }
228 
229  unsigned max_size()
230  {
231  // Int32 and Int64 use more space for large negative numbers
232  return std::max<unsigned>(size(std::numeric_limits<WireType>::min()),
233  size(std::numeric_limits<WireType>::max()));
234  }
235 
236  unsigned size()
237  {
238  return min_size();
239  }
240 
241  unsigned size(const WireType& wire_value)
242  {
243  unsigned data_bytes = helper_.byte_size(wire_value);
244  unsigned size = presence_bit_size() + BITS_IN_BYTE*data_bytes;
245  return size;
246  }
247 
248  Bitset encode()
249  {
250  // presence bit, not set
251  return Bitset(min_size(), 0);
252  }
253 
254  Bitset encode(const WireType& wire_value)
255  {
256  std::vector<google::protobuf::uint8> bytes(size(wire_value) / BITS_IN_BYTE, 0);
257 
258  helper_.encode(wire_value, &bytes);
259 
260  Bitset data_bits;
261  data_bits.from_byte_stream(bytes.begin(), bytes.end());
262  if(!this->use_required())
263  {
264  data_bits.resize(data_bits.size() + presence_bit_size());
265  data_bits <<= 1;
266  data_bits.set(0, true); // presence bit
267  }
268  return data_bits;
269  }
270 
271 
272  WireType decode(Bitset* bits)
273  {
274  if(!this->use_required())
275  {
276  dccl::uint64 uint_value = (bits->template to<dccl::uint64>)();
277  if(!uint_value) throw NullValueException();
278  bits->resize(0);
279 
280  if(helper_.is_varint())
281  bits->get_more_bits(BITS_IN_BYTE);
282  else
283  bits->get_more_bits(BITS_IN_BYTE*helper_.byte_size(WireType()));
284  }
285 
286  if(helper_.is_varint())
287  {
288  // most significant bit indicates if more bytes are needed
289  while(bits->test(bits->size()-1))
290  bits->get_more_bits(BITS_IN_BYTE);
291  }
292 
293  std::string bytes = bits->to_byte_string();
294  google::protobuf::io::CodedInputStream input_stream(reinterpret_cast<const google::protobuf::uint8*>(bytes.data()), bytes.size());
295 
296  return helper_.decode(&input_stream);
297  }
298 
299 private:
301 
302 };
303 
304 class EnumFieldCodec : public PrimitiveTypeFieldCodec<int, google::protobuf::FieldDescriptor::TYPE_ENUM, const google::protobuf::EnumValueDescriptor*>
305 {
306 public:
307  int pre_encode(const google::protobuf::EnumValueDescriptor* const& field_value);
308  const google::protobuf::EnumValueDescriptor* post_decode(const int& wire_value);
309 };
310 
311 
312 }
313 }
314 
315 
316 
317 #endif
bool test(size_type n) const
Test a bit (return its value)
Definition: bitset.h:230
Exception used to signal null (non-existent) value within field codecs during decode.
Definition: exception.h:40
Bitset & set(size_type n, bool val=true)
Set a bit to a given value.
Definition: bitset.h:176
void from_byte_stream(CharIterator begin, CharIterator end)
Sets the value of the Bitset to the contents of a byte string, where each character represents 8 bits...
Definition: bitset.h:358
google::protobuf::uint64 uint64
an unsigned 64 bit integer
Definition: common.h:59
Base class for static-typed (no boost::any) field encoders/decoders. Most single-valued user defined ...
void get_more_bits(size_type num_bits)
Retrieve more bits from the parent Bitset.
Definition: bitset.h:447
Dynamic Compact Control Language namespace.
std::string to_byte_string()
Returns the value of the Bitset to a byte string, where each character represents 8 bits of the Bitse...
Definition: bitset.h:310
A variable size container of bits (subclassed from std::deque<bool>) with an optional hierarchy...
Definition: bitset.h:38