DCCL v3
field_codec.cpp
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 #include <boost/algorithm/string.hpp> // for replace_all
23 
24 #include "field_codec.h"
25 #include "exception.h"
26 #include "dccl/codec.h"
27 
28 dccl::MessagePart dccl::FieldCodecBase::part_ =
29  dccl::UNKNOWN;
30 
31 bool dccl::FieldCodecBase::strict_ = false;
32 
33 const google::protobuf::Message* dccl::FieldCodecBase::root_message_ = 0;
34 const google::protobuf::Descriptor* dccl::FieldCodecBase::root_descriptor_ = 0;
35 
36 using dccl::dlog;
37 using namespace dccl::logger;
38 
39 //
40 // FieldCodecBase public
41 //
42 dccl::FieldCodecBase::FieldCodecBase() : force_required_(false) { }
43 
45  const google::protobuf::Message& field_value,
46  MessagePart part,
47  bool strict)
48 {
49  BaseRAII scoped_globals(part, &field_value, strict);
50 
51  // we pass this through the FromProtoCppTypeBase to do dynamic_cast (RTTI) for
52  // custom message codecs so that these codecs can be written in the derived class (not google::protobuf::Message)
53  field_encode(bits,
54  internal::TypeHelper::find(field_value.GetDescriptor())->get_value(field_value),
55  0);
56 
57 }
58 
60  const boost::any& field_value,
61  const google::protobuf::FieldDescriptor* field)
62 {
63  internal::MessageStack msg_handler(field);
64 
65  if(field)
66  dlog.is(DEBUG2, ENCODE) && dlog << "Starting encode for field: " << field->DebugString() << std::flush;
67 
68  boost::any wire_value;
69  field_pre_encode(&wire_value, field_value);
70 
71  Bitset new_bits;
72  any_encode(&new_bits, wire_value);
73  disp_size(field, new_bits, msg_handler.field_.size());
74  bits->append(new_bits);
75 }
76 
78  const std::vector<boost::any>& field_values,
79  const google::protobuf::FieldDescriptor* field)
80 {
81  internal::MessageStack msg_handler(field);
82 
83  std::vector<boost::any> wire_values;
84  field_pre_encode_repeated(&wire_values, field_values);
85 
86  Bitset new_bits;
87  any_encode_repeated(&new_bits, wire_values);
88  disp_size(field, new_bits, msg_handler.field_.size(), wire_values.size());
89  bits->append(new_bits);
90 }
91 
92 
93 void dccl::FieldCodecBase::base_size(unsigned* bit_size,
94  const google::protobuf::Message& msg,
95  MessagePart part)
96 {
97  BaseRAII scoped_globals(part, &msg);
98 
99  *bit_size = 0;
100 
101  field_size(bit_size, &msg, 0);
102 
103 }
104 
105 void dccl::FieldCodecBase::field_size(unsigned* bit_size,
106  const boost::any& field_value,
107  const google::protobuf::FieldDescriptor* field)
108 {
109  internal::MessageStack msg_handler(field);
110 
111  boost::any wire_value;
112  field_pre_encode(&wire_value, field_value);
113 
114  *bit_size += any_size(wire_value);
115 }
116 
118  const std::vector<boost::any>& field_values,
119  const google::protobuf::FieldDescriptor* field)
120 {
121  internal::MessageStack msg_handler(field);
122 
123  std::vector<boost::any> wire_values;
124  field_pre_encode_repeated(&wire_values, field_values);
125 
126  *bit_size += any_size_repeated(wire_values);
127 }
128 
129 
130 
131 
133  google::protobuf::Message* field_value,
134  MessagePart part)
135 {
136  BaseRAII scoped_globals(part, field_value);
137  boost::any value(field_value);
138  field_decode(bits, &value, 0);
139 }
140 
141 
143  boost::any* field_value,
144  const google::protobuf::FieldDescriptor* field)
145 {
146  internal::MessageStack msg_handler(field);
147 
148  if(!field_value)
149  throw(Exception("Decode called with NULL boost::any"));
150  else if(!bits)
151  throw(Exception("Decode called with NULL Bitset"));
152 
153  if(field)
154  dlog.is(DEBUG2, DECODE) && dlog << "Starting decode for field: " << field->DebugString() << std::flush;
155 
156  if(root_message())
157  dlog.is(DEBUG3, DECODE) && dlog << "Message thus far is: " << root_message()->DebugString() << std::flush;
158 
159  Bitset these_bits(bits);
160 
161  unsigned bits_to_transfer = 0;
162  field_min_size(&bits_to_transfer, field);
163  these_bits.get_more_bits(bits_to_transfer);
164 
165  dlog.is(DEBUG2, DECODE) && dlog << "... using these bits: " << these_bits << std::endl;
166 
167  boost::any wire_value = *field_value;
168 
169  any_decode(&these_bits, &wire_value);
170 
171  field_post_decode(wire_value, field_value);
172 }
173 
175  std::vector<boost::any>* field_values,
176  const google::protobuf::FieldDescriptor* field)
177 {
178  internal::MessageStack msg_handler(field);
179 
180  if(!field_values)
181  throw(Exception("Decode called with NULL field_values"));
182  else if(!bits)
183  throw(Exception("Decode called with NULL Bitset"));
184 
185  if(field)
186  dlog.is(DEBUG2, DECODE) && dlog << "Starting repeated decode for field: " << field->DebugString();
187 
188  Bitset these_bits(bits);
189 
190  unsigned bits_to_transfer = 0;
191  field_min_size(&bits_to_transfer, field);
192  these_bits.get_more_bits(bits_to_transfer);
193 
194  dlog.is(DEBUG2, DECODE) && dlog << "using these " <<
195  these_bits.size() << " bits: " << these_bits << std::endl;
196 
197  std::vector<boost::any> wire_values = *field_values;
198  any_decode_repeated(&these_bits, &wire_values);
199 
200  field_values->clear();
201  field_post_decode_repeated(wire_values, field_values);
202 }
203 
204 
205 void dccl::FieldCodecBase::base_max_size(unsigned* bit_size,
206  const google::protobuf::Descriptor* desc,
207  MessagePart part)
208 {
209  BaseRAII scoped_globals(part, desc);
210  *bit_size = 0;
211 
212  internal::MessageStack msg_handler;
213  if(desc)
214  msg_handler.push(desc);
215  else
216  throw(Exception("Max Size called with NULL Descriptor"));
217 
218  field_max_size(bit_size, static_cast<google::protobuf::FieldDescriptor*>(0));
219 }
220 
221 void dccl::FieldCodecBase::field_max_size(unsigned* bit_size,
222  const google::protobuf::FieldDescriptor* field)
223 {
224  internal::MessageStack msg_handler(field);
225 
226  if(this_field())
227  *bit_size += this_field()->is_repeated() ? max_size_repeated() : max_size();
228  else
229  *bit_size += max_size();
230 }
231 
232 
233 
234 void dccl::FieldCodecBase::base_min_size(unsigned* bit_size,
235  const google::protobuf::Descriptor* desc,
236  MessagePart part)
237 {
238  BaseRAII scoped_globals(part, desc);
239 
240  *bit_size = 0;
241 
242  internal::MessageStack msg_handler;
243  if(desc)
244  msg_handler.push(desc);
245  else
246  throw(Exception("Min Size called with NULL Descriptor"));
247 
248  field_min_size(bit_size, static_cast<google::protobuf::FieldDescriptor*>(0));
249 }
250 
251 void dccl::FieldCodecBase::field_min_size(unsigned* bit_size,
252  const google::protobuf::FieldDescriptor* field)
253 
254 {
255  internal::MessageStack msg_handler(field);
256 
257  if(this_field())
258  *bit_size += this_field()->is_repeated() ? min_size_repeated() : min_size();
259  else
260  *bit_size += min_size();
261 }
262 
263 
264 void dccl::FieldCodecBase::base_validate(const google::protobuf::Descriptor* desc,
265  MessagePart part)
266 {
267  BaseRAII scoped_globals(part, desc);
268 
269  internal::MessageStack msg_handler;
270  if(desc)
271  msg_handler.push(desc);
272  else
273  throw(Exception("Validate called with NULL Descriptor"));
274 
275  bool b = false;
276  field_validate(&b, static_cast<google::protobuf::FieldDescriptor*>(0));
277 }
278 
279 
281  const google::protobuf::FieldDescriptor* field)
282 {
283  internal::MessageStack msg_handler(field);
284 
285  if(field && dccl_field_options().in_head() && variable_size())
286  throw(Exception("Variable size codec used in header - header fields must be encoded with fixed size codec."));
287 
288  validate();
289 }
290 
291 void dccl::FieldCodecBase::base_info(std::ostream* os, const google::protobuf::Descriptor* desc, MessagePart part)
292 {
293  BaseRAII scoped_globals(part, desc);
294 
295  internal::MessageStack msg_handler;
296  if(desc)
297  msg_handler.push(desc);
298  else
299  throw(Exception("info called with NULL Descriptor"));
300 
301  field_info(os, static_cast<google::protobuf::FieldDescriptor*>(0));
302 }
303 
304 
305 void dccl::FieldCodecBase::field_info(std::ostream* os,
306  const google::protobuf::FieldDescriptor* field)
307 {
308  internal::MessageStack msg_handler(field);
309 
310 
311  std::stringstream ss;
312  int depth = msg_handler.count();
313 
314  std::string name = ((this_field()) ? boost::lexical_cast<std::string>(this_field()->number()) + ". " + this_field()->name() : this_descriptor()->full_name());
315  if(this_field() && this_field()->is_repeated())
316  name += "[" + boost::lexical_cast<std::string>(dccl_field_options().max_repeat()) + "]";
317 
318 
319  if(!this_field() || this_field()->type() == google::protobuf::FieldDescriptor::TYPE_MESSAGE)
320  depth -= 1;
321 
322  const int spaces = 8;
323  std::string indent = std::string(spaces*(depth),' ');
324 
325  const int full_width = 40;
326 
327  bool is_zero_size = false;
328 
329  std::stringstream range;
330  if(variable_size())
331  {
332  unsigned max_sz = 0, min_sz = 0;
333  field_max_size(&max_sz, field);
334  field_min_size(&min_sz, field);
335  if(!max_sz) is_zero_size = true;
336  range << min_sz << "-" << max_sz;
337  }
338  else
339  {
340  unsigned sz = 0;
341  field_max_size(&sz, field);
342  if(!sz) is_zero_size = true;
343  range << sz;
344  }
345 
346  int width = this_field() ? full_width-name.size() : full_width-name.size()+spaces;
347  ss << indent << name <<
348  std::setfill('.') << std::setw(std::max(1, width)) << range.str()
349  << " {" << (this_field() ? FieldCodecManager::find(this_field(), has_codec_group(), codec_group())->name() : FieldCodecManager::find(root_descriptor_)->name()) << "}";
350 
351 
352 
353 // std::string s = ss.str();
354 // boost::replace_all(s, "\n", "\n" + indent);
355 // s = indent + s;
356 
357 
358  if(!is_zero_size)
359  *os << ss.str() << "\n";
360 
361  std::string specific_info = info();
362  if(!specific_info.empty())
363  *os << specific_info;
364 
365 }
366 
367 std::string dccl::FieldCodecBase::codec_group(const google::protobuf::Descriptor* desc)
368 {
369  if(desc->options().GetExtension(dccl::msg).has_codec_group())
370  return desc->options().GetExtension(dccl::msg).codec_group();
371  else
372  return Codec::default_codec_name(desc->options().GetExtension(dccl::msg).codec_version());
373 }
374 
375 
376 //
377 // FieldCodecBase protected
378 //
379 
381 {
382  return std::string();
383 }
384 
385 void dccl::FieldCodecBase::any_encode_repeated(dccl::Bitset* bits, const std::vector<boost::any>& wire_values)
386 {
387  // out_bits = [field_values[2]][field_values[1]][field_values[0]]
388 
389  unsigned wire_vector_size = dccl_field_options().max_repeat();
390 
391  if(wire_values.size() > wire_vector_size)
392  throw(dccl::OutOfRangeException(std::string("Repeated size exceeds max_repeat for field: ") + FieldCodecBase::this_field()->DebugString(), this->this_field()));
393 
394  // for DCCL3 and beyond, add a prefix numeric field giving the vector size (rather than always going to max_repeat)
395  if(codec_version() > 2)
396  {
397  wire_vector_size = std::min((int)dccl_field_options().max_repeat(), (int)wire_values.size());
398  Bitset size_bits(repeated_vector_field_size(dccl_field_options().max_repeat()), wire_values.size());
399  bits->append(size_bits);
400  }
401 
402  for(unsigned i = 0, n = wire_vector_size; i < n; ++i)
403  {
404  Bitset new_bits;
405  if(i < wire_values.size())
406  any_encode(&new_bits, wire_values[i]);
407  else
408  any_encode(&new_bits, boost::any());
409  bits->append(new_bits);
410 
411  }
412 }
413 
414 
415 
416 void dccl::FieldCodecBase::any_decode_repeated(Bitset* repeated_bits, std::vector<boost::any>* wire_values)
417 {
418 
419  unsigned wire_vector_size = dccl_field_options().max_repeat();
420  if(codec_version() > 2)
421  {
422  Bitset size_bits(repeated_bits);
423  size_bits.get_more_bits(repeated_vector_field_size(dccl_field_options().max_repeat()));
424 
425  wire_vector_size = size_bits.to_ulong();
426  }
427 
428  wire_values->resize(wire_vector_size);
429 
430  for(unsigned i = 0, n = wire_vector_size; i < n; ++i)
431  {
432  Bitset these_bits(repeated_bits);
433  these_bits.get_more_bits(min_size());
434  any_decode(&these_bits, &(*wire_values)[i]);
435  }
436 }
437 
438 unsigned dccl::FieldCodecBase::any_size_repeated(const std::vector<boost::any>& wire_values)
439 {
440  unsigned out = 0;
441  unsigned wire_vector_size = dccl_field_options().max_repeat();
442 
443  if(codec_version() > 2)
444  {
445  wire_vector_size = std::min((int)dccl_field_options().max_repeat(), (int)wire_values.size());
446  out += repeated_vector_field_size(dccl_field_options().max_repeat());
447  }
448 
449  for(unsigned i = 0, n = wire_vector_size; i < n; ++i)
450  {
451  if(i < wire_values.size())
452  out += any_size(wire_values[i]);
453  else
454  out += any_size(boost::any());
455  }
456  return out;
457 }
458 
459 unsigned dccl::FieldCodecBase::max_size_repeated()
460 {
461  if(!dccl_field_options().has_max_repeat())
462  throw(Exception("Missing (dccl.field).max_repeat option on `repeated` field: " + this_field()->DebugString()));
463  else if(codec_version() > 2)
464  return repeated_vector_field_size(dccl_field_options().max_repeat()) + max_size() * dccl_field_options().max_repeat();
465  else
466  return max_size() * dccl_field_options().max_repeat();
467 }
468 
469 unsigned dccl::FieldCodecBase::min_size_repeated()
470 {
471  if(!dccl_field_options().has_max_repeat())
472  throw(Exception("Missing (dccl.field).max_repeat option on `repeated` field " + this_field()->DebugString()));
473  else if(codec_version() > 2)
474  return repeated_vector_field_size(dccl_field_options().max_repeat());
475  else
476  return min_size() * dccl_field_options().max_repeat();
477 }
478 
479 void dccl::FieldCodecBase::any_pre_encode_repeated(std::vector<boost::any>* wire_values, const std::vector<boost::any>& field_values)
480 {
481  for(std::vector<boost::any>::const_iterator it = field_values.begin(),
482  end = field_values.end(); it != end; ++it)
483  {
484  boost::any wire_value;
485  any_pre_encode(&wire_value, *it);
486  wire_values->push_back(wire_value);
487  }
488 
489 }
490 void dccl::FieldCodecBase::any_post_decode_repeated(
491  const std::vector<boost::any>& wire_values, std::vector<boost::any>* field_values)
492 {
493  for(std::vector<boost::any>::const_iterator it = wire_values.begin(),
494  end = wire_values.end(); it != end; ++it)
495  {
496  boost::any field_value;
497  any_post_decode(*it, &field_value);
498  field_values->push_back(field_value);
499  }
500 }
501 
502 
503 //
504 // FieldCodecBase private
505 //
506 
507 void dccl::FieldCodecBase::disp_size(const google::protobuf::FieldDescriptor* field, const Bitset& new_bits, int depth, int vector_size /* = -1 */)
508 {
509  if(!root_descriptor_)
510  return;
511 
512  if(dlog.is(INFO, SIZE))
513  {
514  std::string name = ((field) ? field->name() : root_descriptor_->full_name());
515  if(vector_size >= 0)
516  name += "[" + boost::lexical_cast<std::string>(vector_size) + "]";
517 
518 
519  dlog << std::string(depth, '|') << name << std::setfill('.') << std::setw(40-name.size()-depth) << new_bits.size() << std::endl;
520 
521  if(!field)
522  dlog << std::endl;
523 
524  }
525 }
Bitset & append(const Bitset &bits)
Adds the bitset to the big end.
Definition: bitset.h:381
void base_decode(Bitset *bits, google::protobuf::Message *msg, MessagePart part)
Decode part of a message.
unsigned long to_ulong() const
Returns the value of the Bitset as an unsigned long integer. Equivalent to to<unsigned long>()...
Definition: bitset.h:284
void field_validate(bool *b, const google::protobuf::FieldDescriptor *field)
Validate this field, checking that all required option extensions are set (e.g. (dccl.field).max and (dccl.field).min for arithmetic codecs)
void field_decode_repeated(Bitset *bits, std::vector< boost::any > *field_values, const google::protobuf::FieldDescriptor *field)
Decode a repeated field.
void field_min_size(unsigned *bit_size, const google::protobuf::FieldDescriptor *field)
Calculate the lower bound on this field&#39;s size (in bits)
void base_encode(Bitset *bits, const google::protobuf::Message &msg, MessagePart part, bool strict)
Encode this part (body or head) of the base message.
Definition: field_codec.cpp:44
void base_size(unsigned *bit_size, const google::protobuf::Message &msg, MessagePart part)
Calculate the size (in bits) of a part of the base message when it is encoded.
Definition: field_codec.cpp:93
const google::protobuf::FieldDescriptor * this_field() const
Returns the FieldDescriptor (field schema meta-data) for this field.
Definition: field_codec.h:75
void base_min_size(unsigned *bit_size, const google::protobuf::Descriptor *desc, MessagePart part)
Calculate the minimum size of a message given its Descriptor alone (no data)
void field_decode(Bitset *bits, boost::any *field_value, const google::protobuf::FieldDescriptor *field)
Decode a non-repeated field.
static boost::shared_ptr< FieldCodecBase > find(const google::protobuf::FieldDescriptor *field, bool has_codec_group, const std::string &codec_group)
Find the codec for a given field. For embedded messages, prefers (dccl.field).codec (inside field) ov...
void field_size(unsigned *bit_size, const boost::any &field_value, const google::protobuf::FieldDescriptor *field)
Calculate the size of a field.
void field_encode_repeated(Bitset *bits, const std::vector< boost::any > &field_values, const google::protobuf::FieldDescriptor *field)
Encode a repeated field.
Definition: field_codec.cpp:77
void base_max_size(unsigned *bit_size, const google::protobuf::Descriptor *desc, MessagePart part)
Calculate the maximum size of a message given its Descriptor alone (no data)
void get_more_bits(size_type num_bits)
Retrieve more bits from the parent Bitset.
Definition: bitset.h:447
virtual std::string info()
Write field specific information (in addition to general information such as sizes that are automatic...
void field_info(std::ostream *os, const google::protobuf::FieldDescriptor *field)
Write human readable information about the field and its bounds to the provided stream.
void base_info(std::ostream *os, const google::protobuf::Descriptor *desc, MessagePart part)
Get human readable information (size of fields, etc.) about this part of the DCCL message...
void base_validate(const google::protobuf::Descriptor *desc, MessagePart part)
Validate this part of the message to make sure all required extensions are set.
bool is(logger::Verbosity verbosity, logger::Group group=logger::GENERAL)
Indicates the verbosity of the Logger until the next std::flush or std::endl. The boolean return is u...
Definition: logger.h:145
Exception class for DCCL.
Definition: exception.h:31
void field_size_repeated(unsigned *bit_size, const std::vector< boost::any > &field_values, const google::protobuf::FieldDescriptor *field)
Calculate the size of a repeated field.
void field_encode(Bitset *bits, const boost::any &field_value, const google::protobuf::FieldDescriptor *field)
Encode a non-repeated field.
Definition: field_codec.cpp:59
A variable size container of bits (subclassed from std::deque<bool>) with an optional hierarchy...
Definition: bitset.h:38
void field_max_size(unsigned *bit_size, const google::protobuf::FieldDescriptor *field)
Calculate the upper bound on this field&#39;s size (in bits)