DCCL v4
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
32 std::mutex dccl::v2::TimeCodecClock::clock_mutex_;
33 #endif
34 
35 std::function<dccl::int64()> dccl::v2::TimeCodecClock::epoch_sec_func_;
36 
37 using 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 
84 dccl::Bitset dccl::v2::DefaultStringCodec::encode() { return Bitset(min_size()); }
85 
86 dccl::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 
121 std::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 
150 unsigned dccl::v2::DefaultStringCodec::size() { return min_size(); }
151 
152 unsigned 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 
158 unsigned 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 
164 unsigned dccl::v2::DefaultStringCodec::min_size() { return dccl::ceil_log2(MAX_STRING_LENGTH + 1); }
165 
166 void 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 
179 dccl::Bitset dccl::v2::DefaultBytesCodec::encode(const std::string& wire_value)
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 
200 unsigned dccl::v2::DefaultBytesCodec::size() { return min_size(); }
201 
202 unsigned 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 //
252 dccl::int32 dccl::v2::DefaultEnumCodec::pre_encode(
253  const google::protobuf::EnumValueDescriptor* const& field_value)
254 {
255  return field_value->index();
256 }
257 
258 const google::protobuf::EnumValueDescriptor*
259 dccl::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
Bitset & set(size_type n, bool val=true)
Set a bit to a given value.
Definition: bitset.h:175
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: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