DCCL v5
Loading...
Searching...
No Matches
field_codec_default.cpp
1// Copyright 2011-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 <algorithm>
26#include <sstream>
27
28#include "../codec.h"
29#include "field_codec_default.h"
30
31#if DCCL_THREAD_SUPPORT
32std::mutex dccl::v2::TimeCodecClock::clock_mutex_;
33#endif
34
35std::function<dccl::int64()> dccl::v2::TimeCodecClock::epoch_sec_func_;
36
37using namespace dccl::logger;
38
39//
40// DefaultBoolCodec
41//
42
44
46{
47 return Bitset(size(), use_required() ? wire_value : wire_value + 1);
48}
49
51{
52 unsigned long t = bits->to_ulong();
53 if (use_required())
54 {
55 return t;
56 }
57 else if (t)
58 {
59 --t;
60 return t;
61 }
62 else
63 {
64 throw NullValueException();
65 }
66}
67
69{
70 // true and false
71 const unsigned BOOL_VALUES = 2;
72 // if field unspecified
73 const unsigned NULL_VALUE = use_required() ? 0 : 1;
74
75 return dccl::ceil_log2(BOOL_VALUES + NULL_VALUE);
76}
77
79
80//
81// DefaultStringCodec
82//
83
84dccl::Bitset dccl::v2::DefaultStringCodec::encode() { return Bitset(min_size()); }
85
86dccl::Bitset dccl::v2::DefaultStringCodec::encode(const std::string& wire_value)
87{
88 std::string s = wire_value;
89 if (s.size() > dccl_field_options().max_length())
90 {
91 if (this->strict())
92 throw(dccl::OutOfRangeException(std::string("String too long for field: ") +
93 FieldCodecBase::this_field()->DebugString(),
94 this->this_field(), this->this_descriptor()));
95
96 dccl::dlog.is(DEBUG2) &&
97 dccl::dlog << "String " << s << " exceeds `dccl.max_length`, truncating" << std::endl;
98 s.resize(dccl_field_options().max_length());
99 }
100
101 if (s.size() < dccl_field_options().min_length())
102 {
103 if (this->strict())
104 throw(dccl::OutOfRangeException(std::string("String too short for field: ") +
105 FieldCodecBase::this_field()->DebugString(),
106 this->this_field(), this->this_descriptor()));
107
108 dccl::dlog.is(DEBUG2) &&
109 dccl::dlog << "String " << s << " is shorter than `dccl.min_length`, padding"
110 << std::endl;
111 s.resize(dccl_field_options().min_length(), '\0');
112 }
113
114 Bitset value_bits;
115 value_bits.from_byte_string(s);
116
117 Bitset length_bits(min_size(), s.length());
118
119 dccl::dlog.is(DEBUG2) && dccl::dlog << "DefaultStringCodec value_bits: " << value_bits
120 << std::endl;
121
122 dccl::dlog.is(DEBUG2) && dccl::dlog << "DefaultStringCodec length_bits: " << length_bits
123 << std::endl;
124
125 // adds to MSBs
126 for (int i = 0, n = value_bits.size(); i < n; ++i) length_bits.push_back(value_bits[i]);
127
128 dccl::dlog.is(DEBUG2) && dccl::dlog << "DefaultStringCodec created: " << length_bits
129 << std::endl;
130
131 return length_bits;
132}
133
134std::string dccl::v2::DefaultStringCodec::decode(Bitset* bits)
135{
136 unsigned value_length = bits->to_ulong();
137
138 if (value_length)
139 {
140 unsigned header_length = min_size();
141
142 dccl::dlog.is(DEBUG2) && dccl::dlog << "Length of string is = " << value_length
143 << std::endl;
144
145 dccl::dlog.is(DEBUG2) && dccl::dlog << "bits before get_more_bits " << *bits << std::endl;
146
147 // grabs more bits to add to the MSBs of `bits`
148 bits->get_more_bits(value_length * BITS_IN_BYTE);
149
150 dccl::dlog.is(DEBUG2) && dccl::dlog << "bits after get_more_bits " << *bits << std::endl;
151 Bitset string_body_bits = *bits;
152 string_body_bits >>= header_length;
153 string_body_bits.resize(bits->size() - header_length);
154
155 return string_body_bits.to_byte_string();
156 }
157 else
158 {
159 throw NullValueException();
160 }
161}
162
163unsigned dccl::v2::DefaultStringCodec::size() { return min_size(); }
164
165unsigned dccl::v2::DefaultStringCodec::size(const std::string& wire_value)
166{
167 return std::min(min_size() + static_cast<unsigned>(wire_value.length() * BITS_IN_BYTE),
168 max_size());
169}
170
171unsigned dccl::v2::DefaultStringCodec::max_size()
172{
173 // string length + actual string
174 return min_size() + dccl_field_options().max_length() * BITS_IN_BYTE;
175}
176
177unsigned dccl::v2::DefaultStringCodec::min_size() { return dccl::ceil_log2(MAX_STRING_LENGTH + 1); }
178
179void dccl::v2::DefaultStringCodec::validate()
180{
181 require(dccl_field_options().has_max_length(), "missing (dccl.field).max_length");
182 require(dccl_field_options().max_length() <= MAX_STRING_LENGTH,
183 "(dccl.field).max_length must be <= " +
184 std::to_string(static_cast<int>(MAX_STRING_LENGTH)));
185 require(dccl_field_options().max_length() >= dccl_field_options().min_length(),
186 "(dccl.field).max_length must be >= (dccl.field).min_length");
187}
188
189//
190// DefaultBytesCodec
191//
193
195{
196 Bitset bits;
197 bits.from_byte_string(wire_value);
198
199 if (bits.size() > max_size() && this->strict())
200 throw(dccl::OutOfRangeException(std::string("Bytes too long for field: ") +
201 FieldCodecBase::this_field()->DebugString(),
202 this->this_field(), this->this_descriptor()));
203
204 bits.resize(max_size());
205
206 if (!use_required())
207 {
208 bits <<= 1;
209 bits.set(0, true); // presence bit
210 }
211
212 return bits;
213}
214
215unsigned dccl::v2::DefaultBytesCodec::size() { return min_size(); }
216
217unsigned dccl::v2::DefaultBytesCodec::size(const std::string& /*wire_value*/) { return max_size(); }
218
220{
221 if (!use_required())
222 {
223 if (bits->to_ulong())
224 {
225 // grabs more bits to add to the MSBs of `bits`
226 bits->get_more_bits(max_size() - min_size());
227
228 Bitset bytes_body_bits = *bits;
229 bytes_body_bits >>= min_size();
230 bytes_body_bits.resize(bits->size() - min_size());
231
232 return bytes_body_bits.to_byte_string();
233 }
234 else
235 {
236 throw NullValueException();
237 }
238 }
239 else
240 {
241 return bits->to_byte_string();
242 }
243}
244
246{
247 return dccl_field_options().max_length() * BITS_IN_BYTE +
248 (use_required() ? 0 : 1); // presence bit?
249}
250
252{
253 if (use_required())
254 return max_size();
255 else
256 return 1; // presence bit
257}
258
260{
261 require(dccl_field_options().has_max_length(), "missing (dccl.field).max_length");
262}
263
264//
265// DefaultEnumCodec
266//
267dccl::int32 dccl::v2::DefaultEnumCodec::pre_encode(
268 const google::protobuf::EnumValueDescriptor* const& field_value)
269{
270 return field_value->index();
271}
272
273const google::protobuf::EnumValueDescriptor*
274dccl::v2::DefaultEnumCodec::post_decode(const dccl::int32& wire_value)
275{
276 const google::protobuf::EnumDescriptor* e = this_field()->enum_type();
277
278 if (wire_value < e->value_count())
279 {
280 const google::protobuf::EnumValueDescriptor* return_value = e->value(wire_value);
281 return return_value;
282 }
283 else
284 throw NullValueException();
285}
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
Bitset & set(size_type n, bool val=true)
Set a bit to a given value.
Definition bitset.h:175
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 size() override
The size of the encoded message in bits. Use TypedFieldCodec if the size depends on the data.
Bitset encode() override
Encode an empty field.
bool decode(Bitset *bits) override
Decode a field. If the field is empty (i.e. was encoded using the zero-argument encode()),...
void validate() override
Validate a field. Use require() inside your overloaded validate() to assert requirements or throw Exc...
unsigned min_size() override
Calculate minimum size of the field in bits.
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...
unsigned max_size() override
Calculate maximum 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()),...
google::protobuf::int32 int32
a signed 32 bit integer
Definition common.h:58
google::protobuf::int64 int64
a signed 64 bit integer
Definition common.h:62
unsigned ceil_log2(dccl::uint64 v)
Definition binary.h:163