9#include <boost/fusion/algorithm.hpp>
10#include <boost/fusion/container.hpp>
11#include <boost/fusion/sequence.hpp>
12#include <boost/numeric/conversion/cast.hpp>
30 template<
typename RawType>
47 std::string variableName,
unsigned int nBits = 32,
int fractionalBits = 0,
bool isSignedFlag =
true);
56 template<
typename UserType>
57 RawType
toRaw(UserType cookedValue)
const;
63 template<
typename UserType,
typename RAW_ITERATOR,
typename COOKED_ITERATOR>
65 const RAW_ITERATOR& raw_begin,
const RAW_ITERATOR& raw_end,
const COOKED_ITERATOR& cooked_begin)
const {
66 static_assert(std::is_same<typename std::iterator_traits<RAW_ITERATOR>::iterator_category,
67 std::random_access_iterator_tag>::value,
68 "RAW_ITERATOR template argument must be a random access iterator.");
69 static_assert(std::is_same<typename std::iterator_traits<COOKED_ITERATOR>::iterator_category,
70 std::random_access_iterator_tag>::value,
71 "COOKED_ITERATOR template argument must be a random access iterator.");
72 static_assert(std::is_same<typename std::iterator_traits<RAW_ITERATOR>::value_type, int8_t>::value ||
73 std::is_same<typename std::iterator_traits<RAW_ITERATOR>::value_type, int16_t>::value ||
74 std::is_same<typename std::iterator_traits<RAW_ITERATOR>::value_type, int32_t>::value ||
75 std::is_same<typename std::iterator_traits<RAW_ITERATOR>::value_type, int64_t>::value,
76 "RAW_ITERATOR template argument must be an iterator with value type equal to int8_t, int16_t, int32_t or "
78 static_assert(std::is_same<typename std::iterator_traits<COOKED_ITERATOR>::value_type, UserType>::value,
79 "COOKED_ITERATOR template argument must be an iterator with value type equal to the UserType template "
83 template<
typename UserType,
typename RAW_ITERATOR,
typename COOKED_ITERATOR>
86 COOKED_ITERATOR cooked_begin);
90 template<
typename UserType>
93 vectorToCooked<UserType>(&
raw, (&
raw) + 1, &cooked);
98 [[nodiscard]]
unsigned int getNBits()
const {
return _nBits; }
104 [[nodiscard]]
bool isSigned()
const {
return _isSigned; }
109 return _nBits == other._nBits && _fractionalBits == other._fractionalBits && _isSigned == other._isSigned;
114 std::string _variableName;
121 double _fractionalBitsCoefficient;
126 double _inverseFractionalBitsCoefficient;
128 RawType _signBitMask{};
129 RawType _usedBitsMask{};
130 RawType _unusedBitsMask{};
132 RawType _maxRawValue{};
133 RawType _minRawValue{};
143 FixedUserTypeMap<int> conversionBranch_toCooked;
147 const static int zero;
150 class initCoefficients {
154 template<
typename Pair>
155 void operator()(Pair)
const {
157 using UserType =
typename Pair::first_type;
160 if(_fpc->_nBits == 16 && _fpc->_fractionalBits == 0 && !_fpc->_isSigned) {
161 boost::fusion::at_key<UserType>(_fpc->conversionBranch_toCooked.table) = 9;
163 else if(_fpc->_nBits == 16 && _fpc->_fractionalBits == 0 && _fpc->_isSigned) {
164 boost::fusion::at_key<UserType>(_fpc->conversionBranch_toCooked.table) = 10;
166 else if(std::numeric_limits<UserType>::is_integer && _fpc->_fractionalBits == 0 && !_fpc->_isSigned) {
167 boost::fusion::at_key<UserType>(_fpc->conversionBranch_toCooked.table) = 1;
169 else if(std::numeric_limits<UserType>::is_integer && _fpc->_fractionalBits == 0 && _fpc->_isSigned) {
170 boost::fusion::at_key<UserType>(_fpc->conversionBranch_toCooked.table) = 2;
172 else if(_fpc->_nBits == 16 && _fpc->_fractionalBits < 0 && _fpc->_fractionalBits > -16 && !_fpc->_isSigned) {
173 boost::fusion::at_key<UserType>(_fpc->conversionBranch_toCooked.table) = 7;
175 else if(_fpc->_nBits == 16 && _fpc->_fractionalBits < 0 && _fpc->_fractionalBits > -16 && _fpc->_isSigned) {
176 boost::fusion::at_key<UserType>(_fpc->conversionBranch_toCooked.table) = 8;
178 else if(_fpc->_nBits == 16 && !_fpc->_isSigned) {
179 boost::fusion::at_key<UserType>(_fpc->conversionBranch_toCooked.table) = 5;
181 else if(_fpc->_nBits == 16 && _fpc->_isSigned) {
182 boost::fusion::at_key<UserType>(_fpc->conversionBranch_toCooked.table) = 6;
184 else if(!_fpc->_isSigned) {
185 boost::fusion::at_key<UserType>(_fpc->conversionBranch_toCooked.table) = 3;
187 else if(_fpc->_isSigned) {
188 boost::fusion::at_key<UserType>(_fpc->conversionBranch_toCooked.table) = 4;
192 boost::fusion::at_key<UserType>(_fpc->_minCookedValues) = _fpc->scalarToCooked<UserType>(_fpc->_minRawValue);
193 boost::fusion::at_key<UserType>(_fpc->_maxCookedValues) = _fpc->scalarToCooked<UserType>(_fpc->_maxRawValue);
202 template<
typename UserType,
typename std::enable_if<std::is_
signed<UserType>{},
int>::type = 0>
203 bool isNegativeUserType(UserType value)
const;
204 template<
typename UserType,
typename std::enable_if<!std::is_
signed<UserType>{},
int>::type = 0>
205 bool isNegativeUserType(UserType value)
const;
211 void padUnusedBits(RawType& rawValue)
const {
212 if(!(rawValue & _signBitMask)) {
213 rawValue &= _usedBitsMask;
216 rawValue |= _unusedBitsMask;
224 template<
typename RawType>
225 template<
typename UserType,
typename RAW_ITERATOR,
typename COOKED_ITERATOR>
227 const FixedPointConverter& fpc,
const RAW_ITERATOR& raw_begin,
const RAW_ITERATOR& raw_end,
228 COOKED_ITERATOR cooked_begin) {
230 switch(boost::fusion::at_key<UserType>(fpc.conversionBranch_toCooked.
table)) {
232 std::transform(raw_begin, raw_end, cooked_begin, [&fpc](RawType rawValue) {
233 fpc.padUnusedBits(rawValue);
234 if constexpr(
sizeof(RawType) == 4) {
235 return numericToUserType<UserType>(*(std::bit_cast<uint32_t*>(&rawValue)));
237 else if constexpr(
sizeof(RawType) == 8) {
238 return numericToUserType<UserType>(*(std::bit_cast<uint64_t*>(&rawValue)));
244 std::transform(raw_begin, raw_end, cooked_begin, [&fpc](RawType rawValue) {
245 fpc.padUnusedBits(rawValue);
246 return numericToUserType<UserType>(rawValue);
251 std::transform(raw_begin, raw_end, cooked_begin, [](
const auto& rawValue) {
252 return numericToUserType<UserType>(*(std::bit_cast<const uint16_t*>(&rawValue)));
257 std::transform(raw_begin, raw_end, cooked_begin, [](
const auto& rawValue) {
258 return numericToUserType<UserType>(*(std::bit_cast<const int16_t*>(&rawValue)));
263 const auto f =
static_cast<uint32_t
>(fpc._fractionalBitsCoefficient);
264 std::transform(raw_begin, raw_end, cooked_begin, [f](
const auto& rawValue) {
265 return numericToUserType<UserType>(f * *(std::bit_cast<const uint16_t*>(&rawValue)));
270 const auto f =
static_cast<int32_t
>(fpc._fractionalBitsCoefficient);
271 std::transform(raw_begin, raw_end, cooked_begin, [f](
const auto& rawValue) {
272 return numericToUserType<UserType>(f * *(std::bit_cast<const int16_t*>(&rawValue)));
277 const auto f = fpc._fractionalBitsCoefficient;
278 std::transform(raw_begin, raw_end, cooked_begin, [f](
const auto& rawValue) {
279 return numericToUserType<UserType>(f * *(std::bit_cast<const uint16_t*>(&rawValue)));
284 const auto f = fpc._fractionalBitsCoefficient;
285 std::transform(raw_begin, raw_end, cooked_begin, [f](
const auto& rawValue) {
286 return numericToUserType<UserType>(f * *(std::bit_cast<const int16_t*>(&rawValue)));
291 const auto f = fpc._fractionalBitsCoefficient;
292 std::transform(raw_begin, raw_end, cooked_begin, [&fpc, f](RawType rawValue) {
293 fpc.padUnusedBits(rawValue);
294 if constexpr(
sizeof(RawType) == 4) {
295 return numericToUserType<UserType>(f * *(std::bit_cast<uint32_t*>(&rawValue)));
297 else if constexpr(
sizeof(RawType) == 8) {
298 return numericToUserType<UserType>(f * *(std::bit_cast<uint64_t*>(&rawValue)));
304 const auto f = fpc._fractionalBitsCoefficient;
305 std::transform(raw_begin, raw_end, cooked_begin, [&fpc, f](RawType rawValue) {
306 fpc.padUnusedBits(rawValue);
307 auto ttt = numericToUserType<UserType>(f * rawValue);
313 std::cerr <<
"Fixed point converter configuration is corrupt." << std::endl;
321 template<
typename RawType>
322 template<
typename UserType>
324 if constexpr(std::is_same<UserType, std::string>::value) {
325 if(_fractionalBits == 0) {
327 return toRaw(std::stoi(cookedValue));
329 return toRaw(std::stoul(cookedValue));
332 return toRaw(std::stod(cookedValue));
334 else if constexpr(std::is_same<UserType, Boolean>::value) {
335 if((
bool)cookedValue) {
340 else if constexpr(std::is_same<UserType, Void>::value) {
346 if(cookedValue < boost::fusion::at_key<UserType>(_minCookedValues)) {
349 if(cookedValue > boost::fusion::at_key<UserType>(_maxCookedValues)) {
354 if constexpr(std::numeric_limits<UserType>::is_integer) {
355 if(_fractionalBits == 0) {
357 bool isNegative = isNegativeUserType(cookedValue);
358 if(isNegative && !_isSigned) {
362 cookedValue = -(cookedValue + 1);
365 auto rawValue =
static_cast<RawType
>(cookedValue);
368 if(_isSigned && isNegative) {
369 rawValue = ~rawValue;
373 return rawValue & _usedBitsMask;
377 double d_cooked = _inverseFractionalBitsCoefficient *
static_cast<double>(cookedValue);
386 if constexpr(
sizeof(RawType) == 4) {
387 raw = RawType(numeric::convert<int32_t>(d_cooked));
389 else if constexpr(
sizeof(RawType) == 8) {
390 raw = RawType(numeric::convert<int64_t>(d_cooked));
394 if constexpr(
sizeof(RawType) == 4) {
395 raw = RawType(numeric::convert<uint32_t>(d_cooked));
397 else if constexpr(
sizeof(RawType) == 8) {
398 raw = RawType(numeric::convert<uint64_t>(d_cooked));
404 return raw & _usedBitsMask;
409 template<
typename RawType>
410 template<
typename UserType,
typename std::enable_if<std::is_
signed<UserType>{},
int>::type>
412 return static_cast<bool>(value < 0);
415 template<
typename RawType>
416 template<
typename UserType,
typename std::enable_if<!std::is_
signed<UserType>{},
int>::type>
423 template<
typename RawType>
424 template<
typename RAW_ITERATOR,
typename COOKED_ITERATOR>
427 COOKED_ITERATOR cooked_begin) {
428 if(fpc._fractionalBits == 0) {
430 std::vector<int32_t> intValues(raw_end - raw_begin);
431 fpc.
vectorToCooked<int32_t>(raw_begin, raw_end, intValues.begin());
432 for(
auto it : intValues) {
438 std::vector<uint32_t> uintValues(raw_end - raw_begin);
439 fpc.
vectorToCooked<uint32_t>(raw_begin, raw_end, uintValues.begin());
440 for(
auto it : uintValues) {
447 std::vector<double> doubleValues(raw_end - raw_begin);
448 fpc.
vectorToCooked<
double>(raw_begin, raw_end, doubleValues.begin());
449 for(
auto it : doubleValues) {
458 template<
typename RawType>
460 std::string variableName,
unsigned int nBits,
int fractionalBits,
bool isSignedFlag)
461 : _variableName(
std::move(variableName)), _nBits(nBits), _fractionalBits(fractionalBits), _isSigned(isSignedFlag),
462 _fractionalBitsCoefficient(pow(2., -fractionalBits)), _inverseFractionalBitsCoefficient(pow(2., fractionalBits)) {
463 _fractionalBitsCoefficient = pow(2., -_fractionalBits);
464 _inverseFractionalBitsCoefficient = pow(2., _fractionalBits);
466 const auto maxBits = (
sizeof(RawType) * 8);
467 if(nBits > maxBits) {
468 std::stringstream errorMessage;
469 errorMessage <<
"The number of bits must be <= " << maxBits <<
", but is " << nBits;
476 if((fractionalBits > -std::numeric_limits<double>::min_exponent -
static_cast<int>(nBits)) ||
477 (fractionalBits < -std::numeric_limits<double>::max_exponent +
static_cast<int>(nBits))) {
478 std::stringstream errorMessage;
479 errorMessage <<
"The number of fractional bits exceeds the dynamic"
480 <<
" range of a double.";
487 if(_isSigned && nBits > 0) {
489 _signBitMask = RawType(1) << (nBits - 1);
494 _usedBitsMask = ~RawType(0);
495 if(nBits <
sizeof(RawType) * 8) {
496 _usedBitsMask =
static_cast<RawType
>((RawType(1) << nBits) - RawType(1));
499 _unusedBitsMask = ~_usedBitsMask;
503 _maxRawValue = _usedBitsMask ^ _signBitMask;
505 _minRawValue = _signBitMask;
512 boost::fusion::for_each(_minCookedValues, initCoefficients(
this));
The fixed point converter provides conversion functions between a user type and up to 32 bit fixed po...
bool operator==(const FixedPointConverter &other) const
Compare two fixed point converters.
int getFractionalBits() const
Read back the fractional bits the converter is using.
FixedPointConverter(std::string variableName, unsigned int nBits=32, int fractionalBits=0, bool isSignedFlag=true)
The constructor defines the conversion factor.
bool operator!=(const FixedPointConverter &other) const
UserType scalarToCooked(RawType const &raw) const
Inefficient convenience function for converting a single value to cooked.
RawType toRaw(UserType cookedValue) const
Conversion function from type T to fixed point.
bool isSigned() const
Read back wether the conversion is using signed values.
unsigned int getNBits() const
Read back the number of bits the converter is using.
void vectorToCooked(const RAW_ITERATOR &raw_begin, const RAW_ITERATOR &raw_end, const COOKED_ITERATOR &cooked_begin) const
Conversion function from fixed-point values to type T.
boost::fusion::map< boost::fusion::pair< int8_t, TargetType >, boost::fusion::pair< uint8_t, TargetType >, boost::fusion::pair< int16_t, TargetType >, boost::fusion::pair< uint16_t, TargetType >, boost::fusion::pair< int32_t, TargetType >, boost::fusion::pair< uint32_t, TargetType >, boost::fusion::pair< int64_t, TargetType >, boost::fusion::pair< uint64_t, TargetType >, boost::fusion::pair< float, TargetType >, boost::fusion::pair< double, TargetType >, boost::fusion::pair< std::string, TargetType >, boost::fusion::pair< Boolean, TargetType >, boost::fusion::pair< Void, TargetType > > table
Exception thrown when a logic error has occured.
boost::fusion::map< boost::fusion::pair< int8_t, int8_t >, boost::fusion::pair< uint8_t, uint8_t >, boost::fusion::pair< int16_t, int16_t >, boost::fusion::pair< uint16_t, uint16_t >, boost::fusion::pair< int32_t, int32_t >, boost::fusion::pair< uint32_t, uint32_t >, boost::fusion::pair< int64_t, int64_t >, boost::fusion::pair< uint64_t, uint64_t >, boost::fusion::pair< float, float >, boost::fusion::pair< double, double >, boost::fusion::pair< std::string, std::string >, boost::fusion::pair< Boolean, Boolean >, boost::fusion::pair< Void, Void > > userTypeMap
Map of UserType to value of the UserType.
int32_t DEPRECATED_FIXEDPOINT_DEFAULT
@ raw
Raw access: disable any possible conversion from the original hardware data type into the given UserT...
std::string to_string(const std::string &v)
static void impl(const FixedPointConverter &fpc, const RAW_ITERATOR &raw_begin, const RAW_ITERATOR &raw_end, COOKED_ITERATOR cooked_begin)
static void impl(const FixedPointConverter &fpc, const RAW_ITERATOR &raw_begin, const RAW_ITERATOR &raw_end, COOKED_ITERATOR cooked_begin)