27#ifndef DCCLFIELDCODECDEFAULT20110322H
28#define DCCLFIELDCODECDEFAULT20110322H
32#include <google/protobuf/descriptor.h>
34#include "dccl/option_extensions.pb.h"
37#include "../field_codec.h"
38#include "../field_codec_fixed.h"
39#include "../thread_safety.h"
40#include "field_codec_default_message.h"
50template <
typename WireType,
typename FieldType = WireType>
61 dc.regenerate(this->this_message(), this->root_message());
77 dc.regenerate(this->this_message(), this->root_message());
90 virtual double resolution()
93 return std::pow(10.0, -precision());
101 "missing (dccl.field).min");
103 "missing (dccl.field).max");
106 "(dccl.field).resolution must be greater than 0");
110 "at most one of either (dccl.field).precision or (dccl.field).resolution can be set");
112 validate_numeric_bounds();
115 void validate_numeric_bounds()
119 std::numeric_limits<WireType>::lowest(),
120 "(dccl.field).min must be >= minimum of this field type.");
122 std::numeric_limits<WireType>::max(),
123 "(dccl.field).max must be <= maximum of this field type.");
126 const double min_max_eps = 1e-10;
127 bool min_multiple_of_res = std::abs(
quantize(min(), resolution()) - min()) < min_max_eps;
128 bool max_multiple_of_res = std::abs(
quantize(max(), resolution()) - max()) < min_max_eps;
134 "(dccl.field).min must be an exact multiple of (dccl.field).resolution");
137 "(dccl.field).max must be an exact multiple of (dccl.field).resolution");
141 auto res = resolution();
143 if (!min_multiple_of_res)
144 dccl::dlog.is(dccl::logger::WARN, dccl::logger::GENERAL) &&
145 dccl::dlog <<
"Warning: (dccl.field).min should be an exact multiple of "
146 "10^(-(dccl.field).precision), i.e. "
147 << res <<
": " << this->
this_field()->DebugString() << std::endl;
148 if (!max_multiple_of_res)
149 dccl::dlog.is(dccl::logger::WARN, dccl::logger::GENERAL) &&
150 dccl::dlog <<
"Warning: (dccl.field).max should be an exact multiple of "
151 "10^(-(dccl.field).precision), i.e. "
152 << res <<
": " << this->
this_field()->DebugString() << std::endl;
157 std::numeric_limits<double>::digits,
158 "[(dccl.field).max-(dccl.field).min]/(dccl.field).resolution must "
159 "fit in a double-precision floating point value. Please increase "
160 "min, decrease max, or decrease precision.");
167 dccl::dlog.is(dccl::logger::DEBUG2, dccl::logger::ENCODE) &&
168 dlog <<
"Encode " << value <<
" with bounds: [" << min() <<
"," << max() <<
"]"
172 double res = resolution();
176 if (wire_value < min() || wire_value > max())
181 std::string(
"Value exceeds min/max bounds for field: ") +
194 wire_value *= (1.0 / res);
195 auto uint_value =
static_cast<dccl::uint64>(dccl::round(wire_value, 0));
208 dccl::dlog.is(dccl::logger::DEBUG2, dccl::logger::DECODE) &&
209 dlog <<
"Decode with bounds: [" << min() <<
"," << max() <<
"]" << std::endl;
215 dccl::uint64 uint_value = (bits->template to<dccl::uint64>)();
224 auto wire_value = (WireType)uint_value;
225 double res = resolution();
229 wire_value /= (1.0 / res);
246 return dccl::ceil_log2((max() - min()) / resolution() + 1 + NULL_VALUE);
259 unsigned size()
override;
260 unsigned size(
const bool& wire_value)
override {
return size(); }
272 std::string decode(
Bitset* bits)
override;
273 unsigned size()
override;
274 unsigned size(
const std::string& wire_value)
override;
282 MAX_STRING_LENGTH = 255
293 unsigned size()
override;
294 unsigned size(
const std::string& wire_value)
override;
305 int32 pre_encode(
const google::protobuf::EnumValueDescriptor*
const& field_value)
override;
306 const google::protobuf::EnumValueDescriptor*
post_decode(
const int32& wire_value)
override;
310 std::size_t
hash()
override
312 return std::hash<std::string>{}(
this_field()->enum_type()->DebugString());
315 double max()
override
317 const google::protobuf::EnumDescriptor* e =
this_field()->enum_type();
318 return e->value_count() - 1;
320 double min()
override {
return 0; }
329 if (!this->has_clock())
330 this->set_clock<std::chrono::system_clock>();
333 template <
typename Clock>
static void set_clock()
335#if DCCL_THREAD_SUPPORT
336 const std::lock_guard<std::mutex> lock(clock_mutex_);
339 epoch_sec_func_ = []() ->
int64
341 typename Clock::time_point now = Clock::now();
342 std::chrono::seconds sec =
343 std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch());
347 static bool has_clock()
349#if DCCL_THREAD_SUPPORT
350 const std::lock_guard<std::mutex> lock(clock_mutex_);
352 return epoch_sec_func_ ? true :
false;
356 static int64 epoch_sec()
358#if DCCL_THREAD_SUPPORT
359 const std::lock_guard<std::mutex> lock(clock_mutex_);
361 return epoch_sec_func_();
365#if DCCL_THREAD_SUPPORT
366 static std::mutex clock_mutex_;
368 static std::function<
int64()> epoch_sec_func_;
371typedef double time_wire_type;
375template <
typename TimeType,
int conversion_factor>
377 public TimeCodecClock
382 time_wire_type
pre_encode(
const TimeType& time_of_day)
override
384 time_wire_type max_secs = max();
385 return std::fmod(time_of_day /
static_cast<time_wire_type
>(conversion_factor), max_secs);
388 TimeType post_decode(
const time_wire_type& encoded_time)
override
390 auto max_secs =
static_cast<int64>(max());
391 int64_t now_secs = this->epoch_sec();
392 int64 daystart = now_secs - (now_secs % max_secs);
393 int64 today_time = now_secs - daystart;
396 if ((encoded_time - today_time) > (max_secs / 2))
397 daystart -= max_secs;
398 else if ((today_time - encoded_time) > (max_secs / 2))
399 daystart += max_secs;
401 return dccl::round((TimeType)(conversion_factor * (daystart + encoded_time)),
402 precision() - std::log10((
double)conversion_factor));
408 DefaultNumericFieldCodec<time_wire_type, TimeType>::validate_numeric_bounds();
411 double max()
override
416 double min()
override {
return 0; }
417 double precision()
override
424 (double)std::log10((
double)conversion_factor);
431 SECONDS_IN_DAY = 86400
435template <
typename TimeType>
class TimeCodec :
public TimeCodecBase<TimeType, 0>
437 static_assert(
sizeof(
TimeCodec) == 0,
"Must use specialization of TimeCodec");
446template <>
class TimeCodec<double> :
public TimeCodecBase<double, 1>
457 T decode(
Bitset* )
override
465 unsigned size()
override {
return 0; }
470 "missing (dccl.field).static_value");
473 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.
virtual void validate()
Validate a field. Use require() inside your overloaded validate() to assert requirements or throw Exc...
virtual unsigned min_size()=0
Calculate minimum size of the field in bits.
dccl::DCCLFieldOptions dccl_field_options() const
Get the DCCL field option extension value for the current field.
virtual std::size_t hash()
Generate a field specific hash to be combined with the descriptor hash.
virtual unsigned max_size()=0
Calculate maximum size of the field in bits.
bool use_required()
Whether to use the required or optional encoding.
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...
virtual Bitset encode()=0
virtual unsigned size()=0
Base class for static-typed field encoders/decoders that use a fixed number of bits on the wire regar...
unsigned size() override=0
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...
int32 pre_encode(const google::protobuf::EnumValueDescriptor *const &field_value) override
Convert from the FieldType representation (used in the Google Protobuf message) to the WireType repre...
const google::protobuf::EnumValueDescriptor * post_decode(const int32 &wire_value) override
Convert from the WireType representation (used with encode() and decode(), i.e. "on the wire") to the...
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...
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).
time_wire_type pre_encode(const TimeType &time_of_day) override
Convert from the FieldType representation (used in the Google Protobuf message) to the WireType repre...
Goby/DCCL version 2 default field codecs.
Dynamic Compact Control Language namespace.
google::protobuf::int64 int64
a signed 64 bit integer
std::enable_if< std::is_floating_point< Float >::value, Float >::type quantize(Float value, double interval)
google::protobuf::uint64 uint64
an unsigned 64 bit integer
google::protobuf::int32 int32
a signed 32 bit integer
unsigned ceil_log2(dccl::uint64 v)