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);
133 std::ptrdiff_t buffered = 0;
136 return static_cast<std::ptrdiff_t
>(part_bits.size()) - buffered;
148 auto offset = decoded_offset(bits, part_bits);
149 if (offset <
static_cast<std::ptrdiff_t
>(decoded.size()) ||
150 offset >
static_cast<std::ptrdiff_t
>(part_bits.size()))
153 for (
auto i = decoded.size(); i < static_cast<dccl::Bitset::size_type>(offset); ++i)
154 decoded.push_back(part_bits[i]);
162 BaseRAII scoped_globals(
this, part, field_value);
167 manager().codec_data().decoded_bits_.clear();
168 manager().codec_data().root_bits_ = &manager().codec_data().decoded_bits_;
169 manager().codec_data().part_bits_ = *bits;
170 dccl::any value(field_value);
171 field_decode(bits, &value,
nullptr);
175 const google::protobuf::FieldDescriptor* field)
180 throw(
Exception(
"Decode called with NULL dccl::any"));
182 throw(
Exception(
"Decode called with NULL Bitset"));
185 dlog.
is(DEBUG2, DECODE) && dlog <<
"Starting decode for field: " << field->DebugString()
189 dlog.
is(DEBUG3, DECODE) && dlog <<
"Message thus far is: " << root_message()->DebugString()
194 if (field && msg_handler.field_size() == 1)
195 update_decoded_bits(manager().codec_data(), *bits);
199 unsigned bits_to_transfer = 0;
200 field_min_size(&bits_to_transfer, field);
204 dlog.
is(DEBUG2, DECODE) && dlog <<
"... using these bits: " << these_bits << std::endl;
206 dccl::any wire_value = *field_value;
213 Bitset* prev_root_bits = manager().codec_data().root_bits_;
214 manager().codec_data().root_bits_ = &manager().codec_data().decoded_bits_;
216 any_decode(&these_bits, &wire_value);
217 field_post_decode(wire_value, field_value);
219 manager().codec_data().root_bits_ = prev_root_bits;
224 any_decode(&these_bits, &wire_value);
225 field_post_decode(wire_value, field_value);
230 const google::protobuf::FieldDescriptor* field)
235 throw(
Exception(
"Decode called with NULL field_values"));
237 throw(
Exception(
"Decode called with NULL Bitset"));
240 dlog.
is(DEBUG2, DECODE) &&
241 dlog <<
"Starting repeated decode for field: " << field->DebugString() << std::endl;
243 if (field && msg_handler.field_size() == 1)
244 update_decoded_bits(manager().codec_data(), *bits);
248 unsigned bits_to_transfer = 0;
249 field_min_size(&bits_to_transfer, field);
252 dlog.
is(DEBUG2, DECODE) && dlog <<
"using these " << these_bits.size()
253 <<
" bits: " << these_bits << std::endl;
255 Bitset* prev_root_bits = manager().codec_data().root_bits_;
256 manager().codec_data().root_bits_ = &manager().codec_data().decoded_bits_;
258 std::vector<dccl::any> wire_values = *field_values;
259 any_decode_repeated(&these_bits, &wire_values);
261 field_values->clear();
262 field_post_decode_repeated(wire_values, field_values);
264 manager().codec_data().root_bits_ = prev_root_bits;
268 const google::protobuf::Descriptor* desc, MessagePart part)
270 BaseRAII scoped_globals(
this, part, desc);
275 msg_handler.push(desc);
277 throw(
Exception(
"Max Size called with NULL Descriptor"));
279 field_max_size(bit_size,
static_cast<google::protobuf::FieldDescriptor*
>(
nullptr));
283 const google::protobuf::FieldDescriptor* field)
288 *bit_size += this_field()->is_repeated() ? max_size_repeated() : max_size();
290 *bit_size += max_size();
294 const google::protobuf::Descriptor* desc, MessagePart part)
296 BaseRAII scoped_globals(
this, part, desc);
302 msg_handler.push(desc);
304 throw(
Exception(
"Min Size called with NULL Descriptor"));
306 field_min_size(bit_size,
static_cast<google::protobuf::FieldDescriptor*
>(
nullptr));
310 const google::protobuf::FieldDescriptor* field)
316 *bit_size += this_field()->is_repeated() ? min_size_repeated() : min_size();
318 *bit_size += min_size();
323 BaseRAII scoped_globals(
this, part, desc);
327 msg_handler.push(desc);
329 throw(
Exception(
"Validate called with NULL Descriptor"));
332 field_validate(&b,
static_cast<google::protobuf::FieldDescriptor*
>(
nullptr));
336 const google::protobuf::FieldDescriptor* field)
340 if (field && dccl_field_options().in_head() && variable_size())
341 throw(
Exception(
"Variable size codec used in header - header fields must be encoded with "
342 "fixed size codec."));
346 "Oneof field used in header - oneof fields cannot be encoded in the header."));
354 BaseRAII scoped_globals(
this, part, desc);
358 msg_handler.push(desc);
360 throw(
Exception(
"info called with NULL Descriptor"));
362 field_info(os,
static_cast<google::protobuf::FieldDescriptor*
>(
nullptr));
366 const google::protobuf::FieldDescriptor* field)
370 std::stringstream ss;
371 int depth = msg_handler.count();
373 std::string name = ((this_field()) ? std::to_string(this_field()->number()) +
". " +
374 std::string(this_field()->name())
375 : std::string(this_descriptor()->full_name()));
376 if (this_field() && this_field()->is_repeated())
378 (dccl_field_options().has_min_repeat()
379 ? (std::to_string(dccl_field_options().min_repeat()) +
"-")
381 std::to_string(dccl_field_options().max_repeat()) +
"]";
383 if (!this_field() || this_field()->type() == google::protobuf::FieldDescriptor::TYPE_MESSAGE)
386 const int spaces = 8;
388 std::string(spaces * (depth) + spaces / 2 * (field &&
is_part_of_oneof(field)),
391 const int full_width = 40;
393 bool is_zero_size =
false;
395 std::stringstream range;
398 unsigned max_sz = 0, min_sz = 0;
399 field_max_size(&max_sz, field);
400 field_min_size(&min_sz, field);
403 range << min_sz <<
"-" << max_sz;
408 field_max_size(&sz, field);
414 int width = this_field() ? full_width - name.size() : full_width - name.size() + spaces;
415 ss << indent << name << std::setfill(
'.') << std::setw(std::max(1, width)) << range.str()
417 << (this_field() ? manager()
418 .find(this_field(), codec_version(), has_codec_group(), codec_group())
420 : manager().find(manager().codec_data().root_descriptor_)->name())
424 *os << ss.str() <<
"\n";
426 std::string specific_info = info();
427 if (!specific_info.empty())
428 *os << specific_info;
434 BaseRAII scoped_globals(
this, part, desc);
438 msg_handler.push(desc);
440 throw(
Exception(
"Hash called with NULL Descriptor"));
442 field_hash(hash,
static_cast<google::protobuf::FieldDescriptor*
>(
nullptr));
446 const google::protobuf::FieldDescriptor* field)
450 if (field && dccl_field_options().in_head() && variable_size())
451 throw(
Exception(
"Variable size codec used in header - header fields must be encoded with "
452 "fixed size codec."));
456 "Oneof field used in header - oneof fields cannot be encoded in the header."));
460 google::protobuf::FieldDescriptorProto field_to_hash;
461 this_field()->CopyTo(&field_to_hash);
464 field_to_hash.clear_name();
466 field_to_hash.clear_options();
467 field_to_hash.clear_type_name();
468 field_to_hash.clear_default_value();
479 dccl_opts.clear_max_bytes();
480 dccl_opts.clear_dynamic_conditions();
488std::string dccl::FieldCodecBase::codec_group(
const google::protobuf::Descriptor* desc)
490 if (desc->options().GetExtension(dccl::msg).has_codec_group())
491 return desc->options().GetExtension(dccl::msg).codec_group();
493 return Codec::default_codec_name(desc->options().GetExtension(dccl::msg).codec_version());
502void dccl::FieldCodecBase::any_encode_repeated(
dccl::Bitset* bits,
503 const std::vector<dccl::any>& wire_values)
507 unsigned wire_vector_size = dccl_field_options().max_repeat();
509 if (wire_values.size() > wire_vector_size && strict())
513 this->this_field(), this->this_descriptor()));
515 if (wire_values.size() < dccl_field_options().min_repeat() && strict())
517 std::string(
"Repeated size is less than min_repeat for field: ") +
519 this->this_field(), this->this_descriptor()));
522 if (codec_version() > 2)
524 wire_vector_size = std::min(
static_cast<int>(dccl_field_options().max_repeat()),
525 static_cast<int>(wire_values.size()));
527 wire_vector_size = std::max(
static_cast<int>(dccl_field_options().min_repeat()),
528 static_cast<int>(wire_vector_size));
530 Bitset size_bits(repeated_vector_field_size(dccl_field_options().min_repeat(),
531 dccl_field_options().max_repeat()),
532 wire_vector_size - dccl_field_options().min_repeat());
535 dlog.
is(DEBUG2, ENCODE) && dlog <<
"repeated size field ... produced these "
536 << size_bits.size() <<
" bits: " << size_bits << std::endl;
540 for (
unsigned i = 0, n = wire_vector_size; i < n; ++i)
542 msg_handler.update_index(root_message(), this->this_field(), i);
545 dc.set_repeated_index(i);
546 if (dc.has_omit_if())
548 dc.regenerate(this_message(), root_message(), i);
554 if (i < wire_values.size())
555 any_encode(&new_bits, wire_values[i]);
557 any_encode(&new_bits, dccl::any());
562void dccl::FieldCodecBase::any_decode_repeated(
Bitset* repeated_bits,
563 std::vector<dccl::any>* wire_values)
565 unsigned wire_vector_size = dccl_field_options().max_repeat();
566 if (codec_version() > 2)
568 Bitset size_bits(repeated_bits);
569 size_bits.get_more_bits(repeated_vector_field_size(dccl_field_options().min_repeat(),
570 dccl_field_options().max_repeat()));
572 wire_vector_size = size_bits.to_ulong() + dccl_field_options().min_repeat();
575 wire_values->resize(wire_vector_size);
578 for (
unsigned i = 0, n = wire_vector_size; i < n; ++i)
580 msg_handler.update_index(root_message(), this->this_field(), i);
583 dc.set_repeated_index(i);
584 if (dc.has_omit_if())
586 dc.regenerate(this_message(), root_message(), i);
591 Bitset these_bits(repeated_bits);
592 these_bits.get_more_bits(min_size());
593 any_decode(&these_bits, &(*wire_values)[i]);
597unsigned dccl::FieldCodecBase::any_size_repeated(
const std::vector<dccl::any>& wire_values)
600 unsigned wire_vector_size = dccl_field_options().max_repeat();
602 if (codec_version() > 2)
604 wire_vector_size = std::min(
static_cast<int>(dccl_field_options().max_repeat()),
605 static_cast<int>(wire_values.size()));
606 out += repeated_vector_field_size(dccl_field_options().min_repeat(),
607 dccl_field_options().max_repeat());
611 for (
unsigned i = 0, n = wire_vector_size; i < n; ++i)
613 msg_handler.update_index(root_message(), this->this_field(), i);
615 dc.set_repeated_index(i);
616 if (dc.has_omit_if())
618 dc.regenerate(this_message(), root_message(), i);
623 if (i < wire_values.size())
624 out += any_size(wire_values[i]);
626 out += any_size(dccl::any());
631void dccl::FieldCodecBase::check_repeat_settings()
const
633 if (!dccl_field_options().has_max_repeat())
634 throw(
Exception(
"Missing (dccl.field).max_repeat option on `repeated` field: " +
635 this_field()->DebugString(),
636 this->this_descriptor()));
637 else if (dccl_field_options().max_repeat() < 1)
638 throw(
Exception(
"(dccl.field).max_repeat must not be less than 1: " +
639 this_field()->DebugString(),
640 this->this_descriptor()));
641 else if (dccl_field_options().max_repeat() < dccl_field_options().min_repeat())
642 throw(
Exception(
"(dccl.field).max_repeat must not be less than (dccl.field).min_repeat: " +
643 this_field()->DebugString(),
644 this->this_descriptor()));
647unsigned dccl::FieldCodecBase::max_size_repeated()
649 check_repeat_settings();
651 if (codec_version() > 2)
652 return repeated_vector_field_size(dccl_field_options().min_repeat(),
653 dccl_field_options().max_repeat()) +
654 max_size() * dccl_field_options().max_repeat();
656 return max_size() * dccl_field_options().max_repeat();
659unsigned dccl::FieldCodecBase::min_size_repeated()
661 check_repeat_settings();
663 if (codec_version() > 2)
664 return repeated_vector_field_size(dccl_field_options().min_repeat(),
665 dccl_field_options().max_repeat()) +
666 min_size() * dccl_field_options().min_repeat();
669 return min_size() * dccl_field_options().max_repeat();
672void dccl::FieldCodecBase::any_pre_encode_repeated(std::vector<dccl::any>* wire_values,
673 const std::vector<dccl::any>& field_values)
675 for (
const auto& field_value : field_values)
677 dccl::any wire_value;
678 any_pre_encode(&wire_value, field_value);
679 wire_values->push_back(wire_value);
682void dccl::FieldCodecBase::any_post_decode_repeated(
const std::vector<dccl::any>& wire_values,
683 std::vector<dccl::any>* field_values)
685 for (
const auto& wire_value : wire_values)
687 dccl::any field_value;
688 any_post_decode(wire_value, &field_value);
689 field_values->push_back(field_value);
697void dccl::FieldCodecBase::disp_size(
const google::protobuf::FieldDescriptor* field,
698 const Bitset& new_bits,
int depth,
int vector_size )
700 if (!root_descriptor())
703 if (dlog.
check(DEBUG2))
706 ((field) ? std::string(field->name()) : std::string(root_descriptor()->full_name()));
707 if (vector_size >= 0)
708 name +=
"[" + std::to_string(vector_size) +
"]";
710 dlog.
is(DEBUG2, SIZE) && dlog << std::string(depth,
'|') << name << std::setfill(
'.')
711 << std::setw(40 - name.size() - depth) << new_bits.size()
715 dlog.
is(DEBUG2, SIZE) && dlog << std::endl;
721 using google::protobuf::FieldDescriptor;
722 return os <<
"[FieldCodec '" << field_codec.
name() <<
"']: field type: "
723 << field_codec.manager().type_helper().find(field_codec.
field_type())->as_str()
725 << field_codec.manager()
727 .find(FieldDescriptor::TypeToCppType(field_codec.
field_type()))
730 << field_codec.manager().type_helper().find(field_codec.
wire_type())->as_str();
735 return message_data().top_field();
740 return message_data().top_descriptor();
743const google::protobuf::Message* dccl::FieldCodecBase::this_message()
745 return message_data().top_message();
748const google::protobuf::Message* dccl::FieldCodecBase::root_message()
750 return manager().codec_data().root_message_;
753const google::protobuf::Descriptor* dccl::FieldCodecBase::root_descriptor()
const
755 return manager().codec_data().root_descriptor_;
760 return manager().codec_data().root_bits_;
765 return manager().codec_data().message_data_;
770 return manager().codec_data().message_data_;
772bool dccl::FieldCodecBase::has_codec_group()
774 const google::protobuf::Descriptor* root_desc = root_descriptor();
777 return root_desc->options().GetExtension(dccl::msg).has_codec_group() ||
778 root_desc->options().GetExtension(dccl::msg).has_codec_version();
786bool dccl::FieldCodecBase::strict() {
return manager().codec_data().strict_; }
788int dccl::FieldCodecBase::codec_version()
790 return root_descriptor()->options().GetExtension(dccl::msg).codec_version();
793std::string dccl::FieldCodecBase::codec_group() {
return codec_group(root_descriptor()); }
796dccl::FieldCodecBase::dynamic_conditions(
const google::protobuf::FieldDescriptor* field)
798 manager().codec_data().dynamic_conditions_.set_field(field);
799 return manager().codec_data().dynamic_conditions_;
802dccl::FieldCodecBase::BaseRAII::BaseRAII(
FieldCodecBase* field_codec, MessagePart part,
803 const google::protobuf::Descriptor* root_descriptor,
805 : field_codec_(field_codec)
808 field_codec_->manager().codec_data().part_ =
part;
809 field_codec_->manager().codec_data().strict_ = strict;
810 field_codec_->manager().codec_data().root_message_ =
nullptr;
811 field_codec_->manager().codec_data().root_descriptor_ = root_descriptor;
813dccl::FieldCodecBase::BaseRAII::BaseRAII(
FieldCodecBase* field_codec, MessagePart part,
814 const google::protobuf::Message* root_message,
bool strict)
815 : field_codec_(field_codec)
818 field_codec_->manager().codec_data().part_ =
part;
819 field_codec_->manager().codec_data().strict_ = strict;
820 field_codec_->manager().codec_data().root_message_ = root_message;
821 field_codec_->manager().codec_data().root_descriptor_ = root_message->GetDescriptor();
823dccl::FieldCodecBase::BaseRAII::~BaseRAII()
825 field_codec_->manager().codec_data().part_ = dccl::UNKNOWN;
826 field_codec_->manager().codec_data().strict_ =
false;
827 field_codec_->manager().codec_data().root_message_ =
nullptr;
828 field_codec_->manager().codec_data().root_descriptor_ =
nullptr;
829 field_codec_->manager().codec_data().root_bits_ =
nullptr;
830 field_codec_->manager().codec_data().decoded_bits_.clear();
831 field_codec_->manager().codec_data().part_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.
const Bitset * parent() const
The parent Bitset that get_more_bits() draws from, or nullptr if there is none.
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