DCCL v4
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 Bitset value_bits;
102 value_bits.from_byte_string(s);
103
104 Bitset length_bits(min_size(), s.length());
105
106 dccl::dlog.is(DEBUG2) && dccl::dlog << "DefaultStringCodec value_bits: " << value_bits
107 << std::endl;
108
109 dccl::dlog.is(DEBUG2) && dccl::dlog << "DefaultStringCodec length_bits: " << length_bits
110 << std::endl;
111
112 // adds to MSBs
113 for (int i = 0, n = value_bits.size(); i < n; ++i) length_bits.push_back(value_bits[i]);
114
115 dccl::dlog.is(DEBUG2) && dccl::dlog << "DefaultStringCodec created: " << length_bits
116 << std::endl;
117
118 return length_bits;
119}
120
121std::string dccl::v2::DefaultStringCodec::decode(Bitset* bits)
122{
123 unsigned value_length = bits->to_ulong();
124
125 if (value_length)
126 {
127 unsigned header_length = min_size();
128
129 dccl::dlog.is(DEBUG2) && dccl::dlog << "Length of string is = " << value_length
130 << std::endl;
131
132 dccl::dlog.is(DEBUG2) && dccl::dlog << "bits before get_more_bits " << *bits << std::endl;
133
134 // grabs more bits to add to the MSBs of `bits`
135 bits->get_more_bits(value_length * BITS_IN_BYTE);
136
137 dccl::dlog.is(DEBUG2) && dccl::dlog << "bits after get_more_bits " << *bits << std::endl;
138 Bitset string_body_bits = *bits;
139 string_body_bits >>= header_length;
140 string_body_bits.resize(bits->size() - header_length);
141
142 return string_body_bits.to_byte_string();
143 }
144 else
145 {
146 throw NullValueException();
147 }
148}
149
150unsigned dccl::v2::DefaultStringCodec::size() { return min_size(); }
151
152unsigned dccl::v2::DefaultStringCodec::size(const std::string& wire_value)
153{
154 return std::min(min_size() + static_cast<unsigned>(wire_value.length() * BITS_IN_BYTE),
155 max_size());
156}
157
158unsigned dccl::v2::DefaultStringCodec::max_size()
159{
160 // string length + actual string
161 return min_size() + dccl_field_options().max_length() * BITS_IN_BYTE;
162}
163
164unsigned dccl::v2::DefaultStringCodec::min_size() { return dccl::ceil_log2(MAX_STRING_LENGTH + 1); }
165
166void dccl::v2::DefaultStringCodec::validate()
167{
168 require(dccl_field_options().has_max_length(), "missing (dccl.field).max_length");
169 require(dccl_field_options().max_length() <= MAX_STRING_LENGTH,
170 "(dccl.field).max_length must be <= " +
171 std::to_string(static_cast<int>(MAX_STRING_LENGTH)));
172}
173
174//
175// DefaultBytesCodec
176//
178
180{
181 Bitset bits;
182 bits.from_byte_string(wire_value);
183
184 if (bits.size() > max_size() && this->strict())
185 throw(dccl::OutOfRangeException(std::string("Bytes too long for field: ") +
186 FieldCodecBase::this_field()->DebugString(),
187 this->this_field(), this->this_descriptor()));
188
189 bits.resize(max_size());
190
191 if (!use_required())
192 {
193 bits <<= 1;
194 bits.set(0, true); // presence bit
195 }
196
197 return bits;
198}
199
200unsigned dccl::v2::DefaultBytesCodec::size() { return min_size(); }
201
202unsigned dccl::v2::DefaultBytesCodec::size(const std::string& /*wire_value*/) { return max_size(); }
203
205{
206 if (!use_required())
207 {
208 if (bits->to_ulong())
209 {
210 // grabs more bits to add to the MSBs of `bits`
211 bits->get_more_bits(max_size() - min_size());
212
213 Bitset bytes_body_bits = *bits;
214 bytes_body_bits >>= min_size();
215 bytes_body_bits.resize(bits->size() - min_size());
216
217 return bytes_body_bits.to_byte_string();
218 }
219 else
220 {
221 throw NullValueException();
222 }
223 }
224 else
225 {
226 return bits->to_byte_string();
227 }
228}
229
231{
232 return dccl_field_options().max_length() * BITS_IN_BYTE +
233 (use_required() ? 0 : 1); // presence bit?
234}
235
237{
238 if (use_required())
239 return max_size();
240 else
241 return 1; // presence bit
242}
243
245{
246 require(dccl_field_options().has_max_length(), "missing (dccl.field).max_length");
247}
248
249//
250// DefaultEnumCodec
251//
252dccl::int32 dccl::v2::DefaultEnumCodec::pre_encode(
253 const google::protobuf::EnumValueDescriptor* const& field_value)
254{
255 return field_value->index();
256}
257
258const google::protobuf::EnumValueDescriptor*
259dccl::v2::DefaultEnumCodec::post_decode(const dccl::int32& wire_value)
260{
261 const google::protobuf::EnumDescriptor* e = this_field()->enum_type();
262
263 if (wire_value < e->value_count())
264 {
265 const google::protobuf::EnumValueDescriptor* return_value = e->value(wire_value);
266 return return_value;
267 }
268 else
269 throw NullValueException();
270}
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:192
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:178