24#include "field_codec.h"
28using namespace dccl::logger;
33dccl::FieldCodecBase::FieldCodecBase() =
default;
36 MessagePart part,
bool strict)
38 BaseRAII scoped_globals(
this,
part, &field_value, strict);
39 manager().codec_data().root_bits_ = bits;
44 manager().type_helper().find(field_value.GetDescriptor())->get_value(field_value),
49 const google::protobuf::FieldDescriptor* field)
54 dlog.
is(DEBUG2, ENCODE) && dlog <<
"Starting encode for field: " << field->DebugString()
60 Bitset* prev_root_bits = manager().codec_data().root_bits_;
61 manager().codec_data().root_bits_ = bits;
64 field_pre_encode(&wire_value, field_value);
67 any_encode(&new_bits, wire_value);
69 manager().codec_data().root_bits_ = prev_root_bits;
71 disp_size(field, new_bits, msg_handler.field_size());
75 dlog.
is(DEBUG2, ENCODE) && dlog <<
"... produced these " << new_bits.size()
76 <<
" bits: " << new_bits << std::endl;
80 const std::vector<dccl::any>& field_values,
81 const google::protobuf::FieldDescriptor* field)
85 std::vector<dccl::any> wire_values;
86 field_pre_encode_repeated(&wire_values, field_values);
89 any_encode_repeated(&new_bits, wire_values);
90 disp_size(field, new_bits, msg_handler.field_size(), wire_values.size());
97 BaseRAII scoped_globals(
this, part, &msg);
101 field_size(bit_size, &msg,
nullptr);
105 const google::protobuf::FieldDescriptor* field)
109 dccl::any wire_value;
110 field_pre_encode(&wire_value, field_value);
112 *bit_size += any_size(wire_value);
116 const std::vector<dccl::any>& field_values,
117 const google::protobuf::FieldDescriptor* field)
121 std::vector<dccl::any> wire_values;
122 field_pre_encode_repeated(&wire_values, field_values);
124 *bit_size += any_size_repeated(wire_values);
130 BaseRAII scoped_globals(
this, part, field_value);
134 manager().codec_data().decoded_bits_.clear();
135 manager().codec_data().root_bits_ = &manager().codec_data().decoded_bits_;
136 dccl::any value(field_value);
137 field_decode(bits, &value,
nullptr);
141 const google::protobuf::FieldDescriptor* field)
146 throw(
Exception(
"Decode called with NULL dccl::any"));
148 throw(
Exception(
"Decode called with NULL Bitset"));
151 dlog.
is(DEBUG2, DECODE) && dlog <<
"Starting decode for field: " << field->DebugString()
155 dlog.
is(DEBUG3, DECODE) && dlog <<
"Message thus far is: " << root_message()->DebugString()
160 unsigned bits_to_transfer = 0;
161 field_min_size(&bits_to_transfer, field);
165 dlog.
is(DEBUG2, DECODE) && dlog <<
"... using these bits: " << these_bits << std::endl;
167 dccl::any wire_value = *field_value;
174 Bitset* prev_root_bits = manager().codec_data().root_bits_;
175 manager().codec_data().root_bits_ = &manager().codec_data().decoded_bits_;
177 any_decode(&these_bits, &wire_value);
178 field_post_decode(wire_value, field_value);
181 manager().codec_data().decoded_bits_.append(these_bits);
183 manager().codec_data().root_bits_ = prev_root_bits;
188 any_decode(&these_bits, &wire_value);
189 field_post_decode(wire_value, field_value);
194 const google::protobuf::FieldDescriptor* field)
199 throw(
Exception(
"Decode called with NULL field_values"));
201 throw(
Exception(
"Decode called with NULL Bitset"));
204 dlog.
is(DEBUG2, DECODE) &&
205 dlog <<
"Starting repeated decode for field: " << field->DebugString() << std::endl;
209 unsigned bits_to_transfer = 0;
210 field_min_size(&bits_to_transfer, field);
213 dlog.
is(DEBUG2, DECODE) && dlog <<
"using these " << these_bits.size()
214 <<
" bits: " << these_bits << std::endl;
216 std::vector<dccl::any> wire_values = *field_values;
217 any_decode_repeated(&these_bits, &wire_values);
219 field_values->clear();
220 field_post_decode_repeated(wire_values, field_values);
224 const google::protobuf::Descriptor* desc, MessagePart part)
226 BaseRAII scoped_globals(
this, part, desc);
231 msg_handler.push(desc);
233 throw(
Exception(
"Max Size called with NULL Descriptor"));
235 field_max_size(bit_size,
static_cast<google::protobuf::FieldDescriptor*
>(
nullptr));
239 const google::protobuf::FieldDescriptor* field)
244 *bit_size += this_field()->is_repeated() ? max_size_repeated() : max_size();
246 *bit_size += max_size();
250 const google::protobuf::Descriptor* desc, MessagePart part)
252 BaseRAII scoped_globals(
this, part, desc);
258 msg_handler.push(desc);
260 throw(
Exception(
"Min Size called with NULL Descriptor"));
262 field_min_size(bit_size,
static_cast<google::protobuf::FieldDescriptor*
>(
nullptr));
266 const google::protobuf::FieldDescriptor* field)
272 *bit_size += this_field()->is_repeated() ? min_size_repeated() : min_size();
274 *bit_size += min_size();
279 BaseRAII scoped_globals(
this, part, desc);
283 msg_handler.push(desc);
285 throw(
Exception(
"Validate called with NULL Descriptor"));
288 field_validate(&b,
static_cast<google::protobuf::FieldDescriptor*
>(
nullptr));
292 const google::protobuf::FieldDescriptor* field)
296 if (field && dccl_field_options().in_head() && variable_size())
297 throw(
Exception(
"Variable size codec used in header - header fields must be encoded with "
298 "fixed size codec."));
302 "Oneof field used in header - oneof fields cannot be encoded in the header."));
310 BaseRAII scoped_globals(
this, part, desc);
314 msg_handler.push(desc);
316 throw(
Exception(
"info called with NULL Descriptor"));
318 field_info(os,
static_cast<google::protobuf::FieldDescriptor*
>(
nullptr));
322 const google::protobuf::FieldDescriptor* field)
326 std::stringstream ss;
327 int depth = msg_handler.count();
329 std::string name = ((this_field()) ? std::to_string(this_field()->number()) +
". " +
330 std::string(this_field()->name())
331 : std::string(this_descriptor()->full_name()));
332 if (this_field() && this_field()->is_repeated())
334 (dccl_field_options().has_min_repeat()
335 ? (std::to_string(dccl_field_options().min_repeat()) +
"-")
337 std::to_string(dccl_field_options().max_repeat()) +
"]";
339 if (!this_field() || this_field()->type() == google::protobuf::FieldDescriptor::TYPE_MESSAGE)
342 const int spaces = 8;
344 std::string(spaces * (depth) + spaces / 2 * (field &&
is_part_of_oneof(field)),
347 const int full_width = 40;
349 bool is_zero_size =
false;
351 std::stringstream range;
354 unsigned max_sz = 0, min_sz = 0;
355 field_max_size(&max_sz, field);
356 field_min_size(&min_sz, field);
359 range << min_sz <<
"-" << max_sz;
364 field_max_size(&sz, field);
370 int width = this_field() ? full_width - name.size() : full_width - name.size() + spaces;
371 ss << indent << name << std::setfill(
'.') << std::setw(std::max(1, width)) << range.str()
373 << (this_field() ? manager()
374 .find(this_field(), codec_version(), has_codec_group(), codec_group())
376 : manager().find(manager().codec_data().root_descriptor_)->name())
380 *os << ss.str() <<
"\n";
382 std::string specific_info = info();
383 if (!specific_info.empty())
384 *os << specific_info;
390 BaseRAII scoped_globals(
this, part, desc);
394 msg_handler.push(desc);
396 throw(
Exception(
"Hash called with NULL Descriptor"));
398 field_hash(hash,
static_cast<google::protobuf::FieldDescriptor*
>(
nullptr));
402 const google::protobuf::FieldDescriptor* field)
406 if (field && dccl_field_options().in_head() && variable_size())
407 throw(
Exception(
"Variable size codec used in header - header fields must be encoded with "
408 "fixed size codec."));
412 "Oneof field used in header - oneof fields cannot be encoded in the header."));
416 google::protobuf::FieldDescriptorProto field_to_hash;
417 this_field()->CopyTo(&field_to_hash);
420 field_to_hash.clear_name();
422 field_to_hash.clear_options();
423 field_to_hash.clear_type_name();
424 field_to_hash.clear_default_value();
435 dccl_opts.clear_max_bytes();
436 dccl_opts.clear_dynamic_conditions();
444std::string dccl::FieldCodecBase::codec_group(
const google::protobuf::Descriptor* desc)
446 if (desc->options().GetExtension(dccl::msg).has_codec_group())
447 return desc->options().GetExtension(dccl::msg).codec_group();
449 return Codec::default_codec_name(desc->options().GetExtension(dccl::msg).codec_version());
458void dccl::FieldCodecBase::any_encode_repeated(
dccl::Bitset* bits,
459 const std::vector<dccl::any>& wire_values)
463 unsigned wire_vector_size = dccl_field_options().max_repeat();
465 if (wire_values.size() > wire_vector_size && strict())
469 this->this_field(), this->this_descriptor()));
471 if (wire_values.size() < dccl_field_options().min_repeat() && strict())
473 std::string(
"Repeated size is less than min_repeat for field: ") +
475 this->this_field(), this->this_descriptor()));
478 if (codec_version() > 2)
480 wire_vector_size = std::min(
static_cast<int>(dccl_field_options().max_repeat()),
481 static_cast<int>(wire_values.size()));
483 wire_vector_size = std::max(
static_cast<int>(dccl_field_options().min_repeat()),
484 static_cast<int>(wire_vector_size));
486 Bitset size_bits(repeated_vector_field_size(dccl_field_options().min_repeat(),
487 dccl_field_options().max_repeat()),
488 wire_vector_size - dccl_field_options().min_repeat());
491 dlog.
is(DEBUG2, ENCODE) && dlog <<
"repeated size field ... produced these "
492 << size_bits.size() <<
" bits: " << size_bits << std::endl;
496 for (
unsigned i = 0, n = wire_vector_size; i < n; ++i)
498 msg_handler.update_index(root_message(), this->this_field(), i);
501 dc.set_repeated_index(i);
502 if (dc.has_omit_if())
504 dc.regenerate(this_message(), root_message(), i);
510 if (i < wire_values.size())
511 any_encode(&new_bits, wire_values[i]);
513 any_encode(&new_bits, dccl::any());
518void dccl::FieldCodecBase::any_decode_repeated(
Bitset* repeated_bits,
519 std::vector<dccl::any>* wire_values)
521 unsigned wire_vector_size = dccl_field_options().max_repeat();
522 if (codec_version() > 2)
524 Bitset size_bits(repeated_bits);
525 size_bits.get_more_bits(repeated_vector_field_size(dccl_field_options().min_repeat(),
526 dccl_field_options().max_repeat()));
528 wire_vector_size = size_bits.to_ulong() + dccl_field_options().min_repeat();
531 wire_values->resize(wire_vector_size);
534 for (
unsigned i = 0, n = wire_vector_size; i < n; ++i)
536 msg_handler.update_index(root_message(), this->this_field(), i);
539 dc.set_repeated_index(i);
540 if (dc.has_omit_if())
542 dc.regenerate(this_message(), root_message(), i);
547 Bitset these_bits(repeated_bits);
548 these_bits.get_more_bits(min_size());
549 any_decode(&these_bits, &(*wire_values)[i]);
553unsigned dccl::FieldCodecBase::any_size_repeated(
const std::vector<dccl::any>& wire_values)
556 unsigned wire_vector_size = dccl_field_options().max_repeat();
558 if (codec_version() > 2)
560 wire_vector_size = std::min(
static_cast<int>(dccl_field_options().max_repeat()),
561 static_cast<int>(wire_values.size()));
562 out += repeated_vector_field_size(dccl_field_options().min_repeat(),
563 dccl_field_options().max_repeat());
567 for (
unsigned i = 0, n = wire_vector_size; i < n; ++i)
569 msg_handler.update_index(root_message(), this->this_field(), i);
571 dc.set_repeated_index(i);
572 if (dc.has_omit_if())
574 dc.regenerate(this_message(), root_message(), i);
579 if (i < wire_values.size())
580 out += any_size(wire_values[i]);
582 out += any_size(dccl::any());
587void dccl::FieldCodecBase::check_repeat_settings()
const
589 if (!dccl_field_options().has_max_repeat())
590 throw(
Exception(
"Missing (dccl.field).max_repeat option on `repeated` field: " +
591 this_field()->DebugString(),
592 this->this_descriptor()));
593 else if (dccl_field_options().max_repeat() < 1)
594 throw(
Exception(
"(dccl.field).max_repeat must not be less than 1: " +
595 this_field()->DebugString(),
596 this->this_descriptor()));
597 else if (dccl_field_options().max_repeat() < dccl_field_options().min_repeat())
598 throw(
Exception(
"(dccl.field).max_repeat must not be less than (dccl.field).min_repeat: " +
599 this_field()->DebugString(),
600 this->this_descriptor()));
603unsigned dccl::FieldCodecBase::max_size_repeated()
605 check_repeat_settings();
607 if (codec_version() > 2)
608 return repeated_vector_field_size(dccl_field_options().min_repeat(),
609 dccl_field_options().max_repeat()) +
610 max_size() * dccl_field_options().max_repeat();
612 return max_size() * dccl_field_options().max_repeat();
615unsigned dccl::FieldCodecBase::min_size_repeated()
617 check_repeat_settings();
619 if (codec_version() > 2)
620 return repeated_vector_field_size(dccl_field_options().min_repeat(),
621 dccl_field_options().max_repeat()) +
622 min_size() * dccl_field_options().min_repeat();
625 return min_size() * dccl_field_options().max_repeat();
628void dccl::FieldCodecBase::any_pre_encode_repeated(std::vector<dccl::any>* wire_values,
629 const std::vector<dccl::any>& field_values)
631 for (
const auto& field_value : field_values)
633 dccl::any wire_value;
634 any_pre_encode(&wire_value, field_value);
635 wire_values->push_back(wire_value);
638void dccl::FieldCodecBase::any_post_decode_repeated(
const std::vector<dccl::any>& wire_values,
639 std::vector<dccl::any>* field_values)
641 for (
const auto& wire_value : wire_values)
643 dccl::any field_value;
644 any_post_decode(wire_value, &field_value);
645 field_values->push_back(field_value);
653void dccl::FieldCodecBase::disp_size(
const google::protobuf::FieldDescriptor* field,
654 const Bitset& new_bits,
int depth,
int vector_size )
656 if (!root_descriptor())
659 if (dlog.
check(DEBUG2))
662 ((field) ? std::string(field->name()) : std::string(root_descriptor()->full_name()));
663 if (vector_size >= 0)
664 name +=
"[" + std::to_string(vector_size) +
"]";
666 dlog.
is(DEBUG2, SIZE) && dlog << std::string(depth,
'|') << name << std::setfill(
'.')
667 << std::setw(40 - name.size() - depth) << new_bits.size()
671 dlog.
is(DEBUG2, SIZE) && dlog << std::endl;
677 using google::protobuf::FieldDescriptor;
678 return os <<
"[FieldCodec '" << field_codec.
name() <<
"']: field type: "
679 << field_codec.manager().type_helper().find(field_codec.
field_type())->as_str()
681 << field_codec.manager()
683 .find(FieldDescriptor::TypeToCppType(field_codec.
field_type()))
686 << field_codec.manager().type_helper().find(field_codec.
wire_type())->as_str();
691 return message_data().top_field();
696 return message_data().top_descriptor();
699const google::protobuf::Message* dccl::FieldCodecBase::this_message()
701 return message_data().top_message();
704const google::protobuf::Message* dccl::FieldCodecBase::root_message()
706 return manager().codec_data().root_message_;
709const google::protobuf::Descriptor* dccl::FieldCodecBase::root_descriptor()
const
711 return manager().codec_data().root_descriptor_;
716 return manager().codec_data().root_bits_;
721 return manager().codec_data().message_data_;
726 return manager().codec_data().message_data_;
728bool dccl::FieldCodecBase::has_codec_group()
730 const google::protobuf::Descriptor* root_desc = root_descriptor();
733 return root_desc->options().GetExtension(dccl::msg).has_codec_group() ||
734 root_desc->options().GetExtension(dccl::msg).has_codec_version();
742bool dccl::FieldCodecBase::strict() {
return manager().codec_data().strict_; }
744int dccl::FieldCodecBase::codec_version()
746 return root_descriptor()->options().GetExtension(dccl::msg).codec_version();
749std::string dccl::FieldCodecBase::codec_group() {
return codec_group(root_descriptor()); }
752dccl::FieldCodecBase::dynamic_conditions(
const google::protobuf::FieldDescriptor* field)
754 manager().codec_data().dynamic_conditions_.set_field(field);
755 return manager().codec_data().dynamic_conditions_;
758dccl::FieldCodecBase::BaseRAII::BaseRAII(
FieldCodecBase* field_codec, MessagePart part,
759 const google::protobuf::Descriptor* root_descriptor,
761 : field_codec_(field_codec)
764 field_codec_->manager().codec_data().part_ =
part;
765 field_codec_->manager().codec_data().strict_ = strict;
766 field_codec_->manager().codec_data().root_message_ =
nullptr;
767 field_codec_->manager().codec_data().root_descriptor_ = root_descriptor;
769dccl::FieldCodecBase::BaseRAII::BaseRAII(
FieldCodecBase* field_codec, MessagePart part,
770 const google::protobuf::Message* root_message,
bool strict)
771 : field_codec_(field_codec)
774 field_codec_->manager().codec_data().part_ =
part;
775 field_codec_->manager().codec_data().strict_ = strict;
776 field_codec_->manager().codec_data().root_message_ = root_message;
777 field_codec_->manager().codec_data().root_descriptor_ = root_message->GetDescriptor();
779dccl::FieldCodecBase::BaseRAII::~BaseRAII()
781 field_codec_->manager().codec_data().part_ = dccl::UNKNOWN;
782 field_codec_->manager().codec_data().strict_ =
false;
783 field_codec_->manager().codec_data().root_message_ =
nullptr;
784 field_codec_->manager().codec_data().root_descriptor_ =
nullptr;
785 field_codec_->manager().codec_data().root_bits_ =
nullptr;
786 field_codec_->manager().codec_data().decoded_bits_.clear();
A variable size container of bits (subclassed from std::deque<bool>) with an optional hierarchy....
void get_more_bits(size_type num_bits)
Retrieve more bits from the parent Bitset.
Bitset & append(const Bitset &bits)
Adds the bitset to the big end.
Exception class for DCCL.
Provides a base class for defining DCCL field encoders / decoders. Most users who wish to define cust...
const Bitset * root_bitset() const
Returns the root Bitset for the current encode or decode operation.
void field_encode(Bitset *bits, const dccl::any &field_value, const google::protobuf::FieldDescriptor *field)
Encode a non-repeated field.
void field_size(unsigned *bit_size, const dccl::any &field_value, const google::protobuf::FieldDescriptor *field)
Calculate the size of a field.
void base_hash(std::size_t *hash, const google::protobuf::Descriptor *desc, MessagePart part)
Provide a hash of the DCCL message definition to detect changes in the DCCL message.
const google::protobuf::Descriptor * this_descriptor() const
Returns the Descriptor (message schema meta-data) for the immediate parent Message.
virtual std::string info()
Write field specific information (in addition to general information such as sizes that are automatic...
google::protobuf::FieldDescriptor::CppType wire_type() const
the C++ type used "on the wire". This is the type visible after pre_encode and before post_decode fun...
const google::protobuf::FieldDescriptor * this_field() const
Returns the FieldDescriptor (field schema meta-data) for this field.
MessagePart part()
the part of the message currently being encoded (head or body)
void field_encode_repeated(Bitset *bits, const std::vector< dccl::any > &field_values, const google::protobuf::FieldDescriptor *field)
Encode a repeated field.
std::string name() const
the name of the codec used to identifier it in the .proto custom option extension
void base_validate(const google::protobuf::Descriptor *desc, MessagePart part)
Validate this part of the message to make sure all required extensions are set.
void field_decode(Bitset *bits, dccl::any *field_value, const google::protobuf::FieldDescriptor *field)
Decode a non-repeated field.
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_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 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 field_hash(std::size_t *hash, const google::protobuf::FieldDescriptor *field)
Provide a hash for this field definition.
void base_decode(Bitset *bits, google::protobuf::Message *msg, MessagePart part)
Decode part of a message.
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.
google::protobuf::FieldDescriptor::Type field_type() const
the type exposed to the user in the original and decoded Protobuf messages
void field_min_size(unsigned *bit_size, const google::protobuf::FieldDescriptor *field)
Calculate the lower bound on this field'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.
void field_validate(bool *b, const google::protobuf::FieldDescriptor *field)
Validate this field, checking that all required option extensions are set (e.g. (dccl....
void field_max_size(unsigned *bit_size, const google::protobuf::FieldDescriptor *field)
Calculate the upper bound on this field's size (in bits)
void field_decode_repeated(Bitset *bits, std::vector< dccl::any > *field_values, const google::protobuf::FieldDescriptor *field)
Decode a repeated field.
void field_size_repeated(unsigned *bit_size, const std::vector< dccl::any > &field_values, const google::protobuf::FieldDescriptor *field)
Calculate the size of a repeated field.
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.
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...
bool check(logger::Verbosity verbosity)
Same as is() but doesn't set the verbosity or lock the mutex.
bool is_part_of_oneof(const google::protobuf::FieldDescriptor *field_desc)
Checks whether a given field is part to a oneof or not.
void hash_combine(std::size_t &seed, const T &v)
hash combine - from boost::hash_combine