30 #ifndef DCCLFIELDCODECDEFAULT20110322H
31 #define DCCLFIELDCODECDEFAULT20110322H
35 #include <google/protobuf/descriptor.h>
37 #include "dccl/option_extensions.pb.h"
39 #include "../binary.h"
40 #include "../field_codec.h"
41 #include "../field_codec_fixed.h"
42 #include "../thread_safety.h"
43 #include "field_codec_default_message.h"
53 template <
typename WireType,
typename FieldType = WireType>
64 dc.regenerate(this->this_message(), this->root_message());
80 dc.regenerate(this->this_message(), this->root_message());
93 virtual double resolution()
96 return std::pow(10.0, -precision());
104 "missing (dccl.field).min");
106 "missing (dccl.field).max");
109 "(dccl.field).resolution must be greater than 0");
113 "at most one of either (dccl.field).precision or (dccl.field).resolution can be set");
115 validate_numeric_bounds();
118 void validate_numeric_bounds()
122 std::numeric_limits<WireType>::lowest(),
123 "(dccl.field).min must be >= minimum of this field type.");
125 std::numeric_limits<WireType>::max(),
126 "(dccl.field).max must be <= maximum of this field type.");
129 const double min_max_eps = 1e-10;
130 bool min_multiple_of_res = std::abs(quantize(min(), resolution()) - min()) < min_max_eps;
131 bool max_multiple_of_res = std::abs(quantize(max(), resolution()) - max()) < min_max_eps;
137 "(dccl.field).min must be an exact multiple of (dccl.field).resolution");
140 "(dccl.field).max must be an exact multiple of (dccl.field).resolution");
144 auto res = resolution();
146 if (!min_multiple_of_res)
147 dccl::dlog.
is(dccl::logger::WARN, dccl::logger::GENERAL) &&
148 dccl::dlog <<
"Warning: (dccl.field).min should be an exact multiple of "
149 "10^(-(dccl.field).precision), i.e. "
150 << res <<
": " << this->
this_field()->DebugString() << std::endl;
151 if (!max_multiple_of_res)
152 dccl::dlog.
is(dccl::logger::WARN, dccl::logger::GENERAL) &&
153 dccl::dlog <<
"Warning: (dccl.field).max should be an exact multiple of "
154 "10^(-(dccl.field).precision), i.e. "
155 << res <<
": " << this->
this_field()->DebugString() << std::endl;
160 std::numeric_limits<double>::digits,
161 "[(dccl.field).max-(dccl.field).min]/(dccl.field).resolution must "
162 "fit in a double-precision floating point value. Please increase "
163 "min, decrease max, or decrease precision.");
170 dccl::dlog.
is(dccl::logger::DEBUG2, dccl::logger::ENCODE) &&
171 dlog <<
"Encode " << value <<
" with bounds: [" << min() <<
"," << max() <<
"]"
175 double res = resolution();
176 WireType wire_value = dccl::quantize(value, res);
179 if (wire_value < min() || wire_value > max())
184 std::string(
"Value exceeds min/max bounds for field: ") +
193 wire_value -= dccl::quantize(
static_cast<WireType
>(min()), res);
197 wire_value *= (1.0 / res);
198 auto uint_value =
static_cast<dccl::uint64>(dccl::round(wire_value, 0));
211 dccl::dlog.
is(dccl::logger::DEBUG2, dccl::logger::DECODE) &&
212 dlog <<
"Decode with bounds: [" << min() <<
"," << max() <<
"]" << std::endl;
218 dccl::uint64 uint_value = (bits->template to<dccl::uint64>)();
227 auto wire_value = (WireType)uint_value;
228 double res = resolution();
232 wire_value /= (1.0 / res);
237 dccl::quantize(wire_value + dccl::quantize(
static_cast<WireType
>(min()), res), res);
249 return dccl::ceil_log2((max() - min()) / resolution() + 1 + NULL_VALUE);
262 unsigned size()
override;
263 unsigned size(
const bool& wire_value)
override {
return size(); }
274 Bitset encode(
const std::string& wire_value)
override;
275 std::string decode(
Bitset* bits)
override;
276 unsigned size()
override;
277 unsigned size(
const std::string& wire_value)
override;
278 unsigned max_size()
override;
279 unsigned min_size()
override;
280 void validate()
override;
285 MAX_STRING_LENGTH = 255
296 unsigned size()
override;
297 unsigned size(
const std::string& wire_value)
override;
308 int32 pre_encode(
const google::protobuf::EnumValueDescriptor*
const& field_value)
override;
309 const google::protobuf::EnumValueDescriptor* post_decode(
const int32& wire_value)
override;
312 void validate()
override {}
313 std::size_t hash()
override
315 return std::hash<std::string>{}(
this_field()->enum_type()->DebugString());
318 double max()
override
320 const google::protobuf::EnumDescriptor* e =
this_field()->enum_type();
321 return e->value_count() - 1;
323 double min()
override {
return 0; }
332 if (!this->has_clock())
333 this->set_clock<std::chrono::system_clock>();
336 template <
typename Clock>
static void set_clock()
338 #if DCCL_THREAD_SUPPORT
339 const std::lock_guard<std::mutex> lock(clock_mutex_);
342 epoch_sec_func_ = []() ->
int64
344 typename Clock::time_point now = Clock::now();
345 std::chrono::seconds sec =
346 std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch());
350 static bool has_clock()
352 #if DCCL_THREAD_SUPPORT
353 const std::lock_guard<std::mutex> lock(clock_mutex_);
355 return epoch_sec_func_ ? true :
false;
359 static int64 epoch_sec()
361 #if DCCL_THREAD_SUPPORT
362 const std::lock_guard<std::mutex> lock(clock_mutex_);
364 return epoch_sec_func_();
368 #if DCCL_THREAD_SUPPORT
369 static std::mutex clock_mutex_;
371 static std::function<
int64()> epoch_sec_func_;
374 typedef double time_wire_type;
378 template <
typename TimeType,
int conversion_factor>
385 time_wire_type pre_encode(
const TimeType& time_of_day)
override
387 time_wire_type max_secs = max();
388 return std::fmod(time_of_day /
static_cast<time_wire_type
>(conversion_factor), max_secs);
391 TimeType post_decode(
const time_wire_type& encoded_time)
override
393 auto max_secs =
static_cast<int64>(max());
394 int64_t now_secs = this->epoch_sec();
395 int64 daystart = now_secs - (now_secs % max_secs);
396 int64 today_time = now_secs - daystart;
399 if ((encoded_time - today_time) > (max_secs / 2))
400 daystart -= max_secs;
401 else if ((today_time - encoded_time) > (max_secs / 2))
402 daystart += max_secs;
404 return dccl::round((TimeType)(conversion_factor * (daystart + encoded_time)),
405 precision() - std::log10((
double)conversion_factor));
409 void validate()
override
414 double max()
override
419 double min()
override {
return 0; }
420 double precision()
override
427 (double)std::log10((
double)conversion_factor);
434 SECONDS_IN_DAY = 86400
440 static_assert(
sizeof(
TimeCodec) == 0,
"Must use specialization of TimeCodec");
456 Bitset encode(
const T&)
override {
return Bitset(size()); }
460 T decode(
Bitset* )
override
468 unsigned size()
override {
return 0; }
470 void validate()
override
473 "missing (dccl.field).static_value");
476 std::istringstream iss(t);
A variable size container of bits (subclassed from std::deque<bool>) with an optional hierarchy....
void from(IntType value, size_type num_bits=std::numeric_limits< IntType >::digits)
Sets value of the Bitset to the contents of an integer.
const google::protobuf::Descriptor * this_descriptor() const
Returns the Descriptor (message schema meta-data) for the immediate parent Message.
const google::protobuf::FieldDescriptor * this_field() const
Returns the FieldDescriptor (field schema meta-data) for this field.
void require(bool b, const std::string &description)
Essentially an assertion to be used in the validate() virtual method.
dccl::DCCLFieldOptions dccl_field_options() const
Get the DCCL field option extension value for the current field.
bool use_required()
Whether to use the required or optional encoding.
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...
Exception used to signal null (non-existent) value within field codecs during decode.
Base class for static-typed (no dccl::any) field encoders/decoders. Most single-valued user defined v...
Base class for static-typed field encoders/decoders that use a fixed number of bits on the wire regar...
Provides a bool encoder. Uses 1 bit if field is required, 2 bits if optional
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...
Provides an fixed length byte string encoder.
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()),...
Provides an enum encoder. This converts the enumeration to an integer (based on the enumeration index...
Provides a basic bounded arbitrary length numeric (double, float, uint32, uint64, int32,...
Bitset encode() override
Encode an empty field.
WireType decode(Bitset *bits) override
Decode a field. If the field is empty (i.e. was encoded using the zero-argument encode()),...
unsigned size() override
The size of the encoded message in bits. Use TypedFieldCodec if the size depends on the data.
void validate() override
Validate a field. Use require() inside your overloaded validate() to assert requirements or throw Exc...
Bitset encode(const WireType &value) override
Encode a non-empty field.
Provides an variable length ASCII string encoder. Can encode strings up to 255 bytes by using a lengt...
Placeholder codec that takes no space on the wire (0 bits).
Encodes time of day (default: second precision, but can be set with (dccl.field).precision extension)
Dynamic Compact Control Language namespace.
google::protobuf::uint64 uint64
an unsigned 64 bit integer
google::protobuf::int32 int32
a signed 32 bit integer
google::protobuf::int64 int64
a signed 64 bit integer
unsigned ceil_log2(dccl::uint64 v)