DCCL v5
Loading...
Searching...
No Matches
field_codec_default.cpp
1// Copyright 2014-2023:
2// GobySoft, LLC (2013-)
3// Massachusetts Institute of Technology (2007-2014)
4// Community contributors (see AUTHORS file)
5// File authors:
6// Toby Schneider <toby@gobysoft.org>
7// Chris Murphy <cmurphy@aphysci.com>
8//
9//
10// This file is part of the Dynamic Compact Control Language Library
11// ("DCCL").
12//
13// DCCL is free software: you can redistribute it and/or modify
14// it under the terms of the GNU Lesser General Public License as published by
15// the Free Software Foundation, either version 2.1 of the License, or
16// (at your option) any later version.
17//
18// DCCL is distributed in the hope that it will be useful,
19// but WITHOUT ANY WARRANTY; without even the implied warranty of
20// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21// GNU Lesser General Public License for more details.
22//
23// You should have received a copy of the GNU Lesser General Public License
24// along with DCCL. If not, see <http://www.gnu.org/licenses/>.
25#include "field_codec_default.h"
26
27using namespace dccl::logger;
28
29//
30// DefaultStringCodec
31//
32
34
36{
37 std::string s = wire_value;
38 if (s.size() > dccl_field_options().max_length())
39 {
40 if (this->strict())
41 throw(dccl::OutOfRangeException(std::string("String too long for field: ") +
42 FieldCodecBase::this_field()->DebugString(),
43 this->this_field(), this->this_descriptor()));
44
45 dccl::dlog.is(DEBUG2) &&
46 dccl::dlog << "String " << s << " exceeds `dccl.max_length`, truncating" << std::endl;
47 s.resize(dccl_field_options().max_length());
48 }
49
50 if (s.size() < dccl_field_options().min_length())
51 {
52 if (this->strict())
53 throw(dccl::OutOfRangeException(std::string("String too short for field: ") +
54 FieldCodecBase::this_field()->DebugString(),
55 this->this_field(), this->this_descriptor()));
56
57 dccl::dlog.is(DEBUG2) &&
58 dccl::dlog << "String " << s << " is shorter than `dccl.min_length`, padding"
59 << std::endl;
60 s.resize(dccl_field_options().min_length(), '\0');
61 }
62
63 Bitset value_bits;
64 value_bits.from_byte_string(s);
65
66 Bitset length_bits(min_size(), s.length());
67
68 dccl::dlog.is(DEBUG2) && dccl::dlog << "DefaultStringCodec value_bits: " << value_bits
69 << std::endl;
70
71 dccl::dlog.is(DEBUG2) && dccl::dlog << "DefaultStringCodec length_bits: " << length_bits
72 << std::endl;
73
74 // adds to MSBs
75 for (int i = 0, n = value_bits.size(); i < n; ++i) length_bits.push_back(value_bits[i]);
76
77 dccl::dlog.is(DEBUG2) && dccl::dlog << "DefaultStringCodec created: " << length_bits
78 << std::endl;
79
80 return length_bits;
81}
82
84{
85 unsigned value_length = bits->to_ulong();
86
87 if (value_length)
88 {
89 unsigned header_length = min_size();
90
91 dccl::dlog.is(DEBUG2) && dccl::dlog << "Length of string is = " << value_length
92 << std::endl;
93
94 dccl::dlog.is(DEBUG2) && dccl::dlog << "bits before get_more_bits " << *bits << std::endl;
95
96 // grabs more bits to add to the MSBs of `bits`
97 bits->get_more_bits(value_length * BITS_IN_BYTE);
98
99 dccl::dlog.is(DEBUG2) && dccl::dlog << "bits after get_more_bits " << *bits << std::endl;
100 Bitset string_body_bits = *bits;
101 string_body_bits >>= header_length;
102 string_body_bits.resize(bits->size() - header_length);
103
104 return string_body_bits.to_byte_string();
105 }
106 else
107 {
108 throw NullValueException();
109 }
110}
111
112unsigned dccl::v3::DefaultStringCodec::size() { return min_size(); }
113
114unsigned dccl::v3::DefaultStringCodec::size(const std::string& wire_value)
115{
116 return std::min(min_size() + static_cast<unsigned>(wire_value.length() * BITS_IN_BYTE),
117 max_size());
118}
119
121{
122 // string length + actual string
123 return min_size() + dccl_field_options().max_length() * BITS_IN_BYTE;
124}
125
127{
128 return dccl::ceil_log2(dccl_field_options().max_length() + 1);
129}
130
132{
133 require(dccl_field_options().has_max_length(), "missing (dccl.field).max_length");
134 require(dccl_field_options().max_length() >= dccl_field_options().min_length(),
135 "(dccl.field).max_length must be >= (dccl.field).min_length");
136}
137
138//
139// DefaultEnumCodec
140//
141double dccl::v3::DefaultEnumCodec::max()
142{
143 const google::protobuf::EnumDescriptor* e = this_field()->enum_type();
144
145 if (dccl_field_options().packed_enum())
146 {
147 return e->value_count() - 1;
148 }
149 else
150 {
151 const google::protobuf::EnumValueDescriptor* value = e->value(0);
152 int32 maxVal = value->number();
153 for (int i = 1; i < e->value_count(); ++i)
154 {
155 value = e->value(i);
156 if (value->number() > maxVal)
157 {
158 maxVal = value->number();
159 }
160 }
161 return maxVal;
162 }
163}
164
165double dccl::v3::DefaultEnumCodec::min()
166{
167 if (dccl_field_options().packed_enum())
168 {
169 return 0;
170 }
171 else
172 {
173 const google::protobuf::EnumDescriptor* e = this_field()->enum_type();
174 const google::protobuf::EnumValueDescriptor* value = e->value(0);
175 int32 minVal = value->number();
176 for (int i = 1; i < e->value_count(); ++i)
177 {
178 value = e->value(i);
179 if (value->number() < minVal)
180 {
181 minVal = value->number();
182 }
183 }
184 return minVal;
185 }
186}
187
188dccl::int32 dccl::v3::DefaultEnumCodec::pre_encode(
189 const google::protobuf::EnumValueDescriptor* const& field_value)
190{
191 if (dccl_field_options().packed_enum())
192 return field_value->index();
193 else
194 return field_value->number();
195}
196
197const google::protobuf::EnumValueDescriptor*
198dccl::v3::DefaultEnumCodec::post_decode(const dccl::int32& wire_value)
199{
200 const google::protobuf::EnumDescriptor* e = this_field()->enum_type();
201
202 if (dccl_field_options().packed_enum())
203 {
204 if (wire_value < e->value_count())
205 {
206 const google::protobuf::EnumValueDescriptor* return_value = e->value(wire_value);
207 return return_value;
208 }
209 else
210 throw NullValueException();
211 }
212 else
213 {
214 const google::protobuf::EnumValueDescriptor* return_value =
215 e->FindValueByNumber(wire_value);
216 if (return_value != nullptr)
217 return return_value;
218 else
219 throw NullValueException();
220 }
221}
A variable size container of bits (subclassed from std::deque<bool>) with an optional hierarchy....
Definition bitset.h:43
void get_more_bits(size_type num_bits)
Retrieve more bits from the parent Bitset.
Definition bitset.h:420
unsigned long to_ulong() const
Returns the value of the Bitset as an unsigned long integer. Equivalent to to<unsigned long>().
Definition bitset.h:275
void from_byte_string(const std::string &s)
Sets the value of the Bitset to the contents of a byte string, where each character represents 8 bits...
Definition bitset.h:335
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:297
const google::protobuf::FieldDescriptor * this_field() const
Returns the FieldDescriptor (field schema meta-data) for this field.
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:191
Exception used to signal null (non-existent) value within field codecs during decode.
Definition exception.h:62
unsigned max_size() override
Calculate maximum size of the field in bits.
unsigned min_size() override
Calculate minimum size of the field in bits.
std::string decode(Bitset *bits) override
Decode a field. If the field is empty (i.e. was encoded using the zero-argument encode()),...
Bitset encode() override
Encode an empty field.
unsigned size() override
Calculate the size (in bits) of an empty field.
void validate() override
Validate a field. Use require() inside your overloaded validate() to assert requirements or throw Exc...
google::protobuf::int32 int32
a signed 32 bit integer
Definition common.h:58
unsigned ceil_log2(dccl::uint64 v)
Definition binary.h:163