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>
44 std::string variableName,
unsigned int nBits = 32,
int fractionalBits = 0,
bool isSignedFlag =
true);
53 template<
typename UserType>
54 uint32_t
toRaw(UserType cookedValue)
const;
60 template<
typename UserType,
typename RAW_ITERATOR,
typename COOKED_ITERATOR>
62 const RAW_ITERATOR& raw_begin,
const RAW_ITERATOR& raw_end,
const COOKED_ITERATOR& cooked_begin)
const {
63 static_assert(std::is_same<
typename std::iterator_traits<RAW_ITERATOR>::iterator_category,
64 std::random_access_iterator_tag>::value,
65 "RAW_ITERATOR template argument must be a random access iterator.");
66 static_assert(std::is_same<
typename std::iterator_traits<COOKED_ITERATOR>::iterator_category,
67 std::random_access_iterator_tag>::value,
68 "COOKED_ITERATOR template argument must be a random access iterator.");
69 static_assert(std::is_same<
typename std::iterator_traits<RAW_ITERATOR>::value_type, int8_t>::value ||
70 std::is_same<
typename std::iterator_traits<RAW_ITERATOR>::value_type, int16_t>::value ||
71 std::is_same<
typename std::iterator_traits<RAW_ITERATOR>::value_type, int32_t>::value,
72 "RAW_ITERATOR template argument must be an iterator with value type equal to int8_t, int16_t or int32_t");
73 static_assert(std::is_same<
typename std::iterator_traits<COOKED_ITERATOR>::value_type, UserType>::value,
74 "COOKED_ITERATOR template argument must be an iterator with value type equal to the UserType template "
78 template<
typename UserType,
typename RAW_ITERATOR,
typename COOKED_ITERATOR>
81 COOKED_ITERATOR cooked_begin);
85 template<
typename UserType>
88 vectorToCooked<UserType>(&
raw, (&
raw) + 1, &cooked);
93 [[nodiscard]]
unsigned int getNBits()
const {
return _nBits; }
99 [[nodiscard]]
bool isSigned()
const {
return _isSigned; }
102 void reconfigure(
unsigned int nBits = 32,
int fractionalBits = 0,
bool isSignedFlag =
true);
107 return _nBits == other._nBits && _fractionalBits == other._fractionalBits && _isSigned == other._isSigned;
112 std::string _variableName;
119 double _fractionalBitsCoefficient;
124 double _inverseFractionalBitsCoefficient;
126 int32_t _signBitMask{};
127 int32_t _usedBitsMask{};
128 int32_t _unusedBitsMask{};
129 int32_t _bitShiftMask{};
130 int32_t _bitShiftMaskSigned{};
134 int32_t _maxRawValue{};
135 int32_t _minRawValue{};
145 FixedUserTypeMap<int> conversionBranch_toCooked;
149 const static int zero;
152 class initCoefficients {
156 template<
typename Pair>
157 void operator()(Pair)
const {
159 typedef typename Pair::first_type UserType;
162 if(_fpc->_nBits == 16 && _fpc->_fractionalBits == 0 && !_fpc->_isSigned) {
163 boost::fusion::at_key<UserType>(_fpc->conversionBranch_toCooked.table) = 9;
165 else if(_fpc->_nBits == 16 && _fpc->_fractionalBits == 0 && _fpc->_isSigned) {
166 boost::fusion::at_key<UserType>(_fpc->conversionBranch_toCooked.table) = 10;
168 else if(std::numeric_limits<UserType>::is_integer && _fpc->_fractionalBits == 0 && !_fpc->_isSigned) {
169 boost::fusion::at_key<UserType>(_fpc->conversionBranch_toCooked.table) = 1;
171 else if(std::numeric_limits<UserType>::is_integer && _fpc->_fractionalBits == 0 && _fpc->_isSigned) {
172 boost::fusion::at_key<UserType>(_fpc->conversionBranch_toCooked.table) = 2;
174 else if(_fpc->_nBits == 16 && _fpc->_fractionalBits < 0 && _fpc->_fractionalBits > -16 && !_fpc->_isSigned) {
175 boost::fusion::at_key<UserType>(_fpc->conversionBranch_toCooked.table) = 7;
177 else if(_fpc->_nBits == 16 && _fpc->_fractionalBits < 0 && _fpc->_fractionalBits > -16 && _fpc->_isSigned) {
178 boost::fusion::at_key<UserType>(_fpc->conversionBranch_toCooked.table) = 8;
180 else if(_fpc->_nBits == 16 && !_fpc->_isSigned) {
181 boost::fusion::at_key<UserType>(_fpc->conversionBranch_toCooked.table) = 5;
183 else if(_fpc->_nBits == 16 && _fpc->_isSigned) {
184 boost::fusion::at_key<UserType>(_fpc->conversionBranch_toCooked.table) = 6;
186 else if(!_fpc->_isSigned) {
187 boost::fusion::at_key<UserType>(_fpc->conversionBranch_toCooked.table) = 3;
189 else if(_fpc->_isSigned) {
190 boost::fusion::at_key<UserType>(_fpc->conversionBranch_toCooked.table) = 4;
195 boost::fusion::at_key<UserType>(_fpc->_minCookedValues) = _fpc->scalarToCooked<UserType>(_fpc->_minRawValue);
197 catch(boost::numeric::negative_overflow& e) {
198 boost::fusion::at_key<UserType>(_fpc->_minCookedValues) = std::numeric_limits<UserType>::min();
201 boost::fusion::at_key<UserType>(_fpc->_maxCookedValues) = _fpc->scalarToCooked<UserType>(_fpc->_maxRawValue);
203 catch(boost::numeric::positive_overflow& e) {
204 boost::fusion::at_key<UserType>(_fpc->_maxCookedValues) = std::numeric_limits<UserType>::max();
215 static S nearbyint(S s) {
return round(s); }
217 using round_style = boost::mpl::integral_c<std::float_round_style, std::round_to_nearest>;
222 template<
typename UserType,
typename std::enable_if<std::is_
signed<UserType>{},
int>::type = 0>
223 bool isNegativeUserType(UserType value)
const;
224 template<
typename UserType,
typename std::enable_if<!std::is_
signed<UserType>{},
int>::type = 0>
225 bool isNegativeUserType(UserType value)
const;
231 void padUnusedBits(int32_t& rawValue)
const {
232 if(!(rawValue & _signBitMask)) {
233 rawValue &= _usedBitsMask;
236 rawValue |= _unusedBitsMask;
248 template<
typename UserType,
typename RAW_ITERATOR,
typename COOKED_ITERATOR>
250 const FixedPointConverter& fpc,
const RAW_ITERATOR& raw_begin,
const RAW_ITERATOR& raw_end,
251 COOKED_ITERATOR cooked_begin) {
253 switch(boost::fusion::at_key<UserType>(fpc.conversionBranch_toCooked.
table)) {
255 std::transform(raw_begin, raw_end, cooked_begin, [&fpc](int32_t rawValue) {
256 fpc.padUnusedBits(rawValue);
257 return numericToUserType<UserType>(*(
reinterpret_cast<uint32_t*
>(&rawValue)));
262 std::transform(raw_begin, raw_end, cooked_begin, [&fpc](int32_t rawValue) {
263 fpc.padUnusedBits(rawValue);
264 return numericToUserType<UserType>(rawValue);
269 std::transform(raw_begin, raw_end, cooked_begin, [](
const auto& rawValue) {
270 return numericToUserType<UserType>(*(
reinterpret_cast<const uint16_t*
>(&rawValue)));
275 std::transform(raw_begin, raw_end, cooked_begin, [](
const auto& rawValue) {
276 return numericToUserType<UserType>(*(
reinterpret_cast<const int16_t*
>(&rawValue)));
281 const auto f =
static_cast<uint32_t
>(fpc._fractionalBitsCoefficient);
282 std::transform(raw_begin, raw_end, cooked_begin, [f](
const auto& rawValue) {
283 return numericToUserType<UserType>(f * *(
reinterpret_cast<const uint16_t*
>(&rawValue)));
288 const auto f =
static_cast<int32_t
>(fpc._fractionalBitsCoefficient);
289 std::transform(raw_begin, raw_end, cooked_begin, [f](
const auto& rawValue) {
290 return numericToUserType<UserType>(f * *(
reinterpret_cast<const int16_t*
>(&rawValue)));
295 const auto f = fpc._fractionalBitsCoefficient;
296 std::transform(raw_begin, raw_end, cooked_begin, [f](
const auto& rawValue) {
297 return numericToUserType<UserType>(f * *(
reinterpret_cast<const uint16_t*
>(&rawValue)));
302 const auto f = fpc._fractionalBitsCoefficient;
303 std::transform(raw_begin, raw_end, cooked_begin, [f](
const auto& rawValue) {
304 return numericToUserType<UserType>(f * *(
reinterpret_cast<const int16_t*
>(&rawValue)));
309 const auto f = fpc._fractionalBitsCoefficient;
310 std::transform(raw_begin, raw_end, cooked_begin, [&fpc, f](int32_t rawValue) {
311 fpc.padUnusedBits(rawValue);
312 return numericToUserType<UserType>(f * *(
reinterpret_cast<uint32_t*
>(&rawValue)));
317 const auto f = fpc._fractionalBitsCoefficient;
318 std::transform(raw_begin, raw_end, cooked_begin, [&fpc, f](int32_t rawValue) {
319 fpc.padUnusedBits(rawValue);
320 auto ttt = numericToUserType<UserType>(f * rawValue);
326 std::cerr <<
"Fixed point converter configuration is corrupt." << std::endl;
335 template<
typename UserType>
339 if(cookedValue < boost::fusion::at_key<UserType>(_minCookedValues)) {
342 if(cookedValue > boost::fusion::at_key<UserType>(_maxCookedValues)) {
347 if(std::numeric_limits<UserType>::is_integer && _fractionalBits == 0) {
349 bool isNegative = isNegativeUserType(cookedValue);
350 if(isNegative && !_isSigned)
return _minRawValue;
352 cookedValue = -(cookedValue + 1);
355 auto rawValue =
static_cast<uint32_t
>(cookedValue);
358 if(_isSigned && isNegative) {
359 rawValue = ~rawValue;
363 return rawValue &
static_cast<uint32_t
>(_usedBitsMask);
366 double d_cooked = _inverseFractionalBitsCoefficient *
static_cast<double>(cookedValue);
378 typedef boost::numeric::converter<int32_t, double, boost::numeric::conversion_traits<int32_t, double>,
379 boost::numeric::def_overflow_handler, Round<double>>
381 raw = converter_signed::convert(d_cooked);
384 typedef boost::numeric::converter<uint32_t, double, boost::numeric::conversion_traits<uint32_t, double>,
385 boost::numeric::def_overflow_handler, Round<double>>
387 raw =
static_cast<int32_t
>(converter_unsigned::convert(d_cooked));
390 catch(boost::numeric::negative_overflow& e) {
396 return raw & _usedBitsMask;
401 template<
typename UserType,
typename std::enable_if<std::is_
signed<UserType>{},
int>::type>
402 bool FixedPointConverter::isNegativeUserType(UserType value)
const {
403 return static_cast<bool>(value < 0);
406 template<
typename UserType,
typename std::enable_if<!std::is_
signed<UserType>{},
int>::type>
407 bool FixedPointConverter::isNegativeUserType(UserType )
const {
413 template<
typename RAW_ITERATOR,
typename COOKED_ITERATOR>
416 COOKED_ITERATOR cooked_begin) {
417 if(fpc._fractionalBits == 0) {
419 std::vector<int32_t> intValues(raw_end - raw_begin);
420 fpc.
vectorToCooked<int32_t>(raw_begin, raw_end, intValues.begin());
421 for(
auto it : intValues) {
427 std::vector<uint32_t> uintValues(raw_end - raw_begin);
428 fpc.
vectorToCooked<uint32_t>(raw_begin, raw_end, uintValues.begin());
429 for(
auto it : uintValues) {
436 std::vector<double> doubleValues(raw_end - raw_begin);
437 fpc.
vectorToCooked<
double>(raw_begin, raw_end, doubleValues.begin());
438 for(
auto it : doubleValues) {
448 [[nodiscard]] uint32_t FixedPointConverter::toRaw<std::string>(std::string cookedValue)
const;
451 [[nodiscard]] uint32_t FixedPointConverter::toRaw<Boolean>(
Boolean cookedValue)
const;
454 [[nodiscard]] uint32_t FixedPointConverter::toRaw<Void>(__attribute__((unused))
Void cookedValue)
const;