214 lines
4.2 KiB
C++
214 lines
4.2 KiB
C++
#include "HANumeric.h"
|
|||
|
|
|
||
|
|
const uint8_t HANumeric::MaxDigitsNb = 19;
|
||
|
|
|
||
|
|
HANumeric HANumeric::fromStr(const uint8_t* buffer, const uint16_t length)
|
||
|
|
{
|
||
|
|
if (length == 0) {
|
||
|
|
return HANumeric();
|
||
|
|
}
|
||
|
|
|
||
|
|
const uint8_t* firstCh = &buffer[0];
|
||
|
|
int64_t out = 0;
|
||
|
|
bool isSigned = false;
|
||
|
|
|
||
|
|
if (*firstCh == '-') {
|
||
|
|
isSigned = true;
|
||
|
|
firstCh++;
|
||
|
|
}
|
||
|
|
|
||
|
|
uint8_t digitsNb = isSigned ? length - 1 : length;
|
||
|
|
if (digitsNb > MaxDigitsNb) {
|
||
|
|
return HANumeric();
|
||
|
|
}
|
||
|
|
|
||
|
|
uint64_t base = 1;
|
||
|
|
const uint8_t* ptr = &buffer[length - 1];
|
||
|
|
|
||
|
|
while (ptr >= firstCh) {
|
||
|
|
uint8_t digit = *ptr - '0';
|
||
|
|
if (digit > 9) {
|
||
|
|
return HANumeric();
|
||
|
|
}
|
||
|
|
|
||
|
|
out += digit * base;
|
||
|
|
ptr--;
|
||
|
|
base *= 10;
|
||
|
|
}
|
||
|
|
|
||
|
|
return HANumeric(isSigned ? out * -1 : out);
|
||
|
|
}
|
||
|
|
|
||
|
|
HANumeric::HANumeric():
|
||
|
|
_isSet(false),
|
||
|
|
_value(0),
|
||
|
|
_precision(0)
|
||
|
|
{
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
HANumeric::HANumeric(const float value, const uint8_t precision):
|
||
|
|
_isSet(true),
|
||
|
|
_precision(precision)
|
||
|
|
{
|
||
|
|
_value = value * static_cast<float>(getPrecisionBase());
|
||
|
|
}
|
||
|
|
|
||
|
|
HANumeric::HANumeric(const int8_t value, const uint8_t precision):
|
||
|
|
_isSet(true),
|
||
|
|
_precision(precision)
|
||
|
|
{
|
||
|
|
_value = value * static_cast<int32_t>(getPrecisionBase());
|
||
|
|
}
|
||
|
|
|
||
|
|
HANumeric::HANumeric(const int16_t value, const uint8_t precision):
|
||
|
|
_isSet(true),
|
||
|
|
_precision(precision)
|
||
|
|
{
|
||
|
|
_value = value * static_cast<int32_t>(getPrecisionBase());
|
||
|
|
}
|
||
|
|
|
||
|
|
HANumeric::HANumeric(const int32_t value, const uint8_t precision):
|
||
|
|
_isSet(true),
|
||
|
|
_precision(precision)
|
||
|
|
{
|
||
|
|
_value = value * static_cast<int32_t>(getPrecisionBase());
|
||
|
|
}
|
||
|
|
|
||
|
|
HANumeric::HANumeric(const uint8_t value, const uint8_t precision):
|
||
|
|
_isSet(true),
|
||
|
|
_precision(precision)
|
||
|
|
{
|
||
|
|
_value = value * getPrecisionBase();
|
||
|
|
}
|
||
|
|
|
||
|
|
HANumeric::HANumeric(const uint16_t value, const uint8_t precision):
|
||
|
|
_isSet(true),
|
||
|
|
_precision(precision)
|
||
|
|
{
|
||
|
|
_value = value * getPrecisionBase();
|
||
|
|
}
|
||
|
|
|
||
|
|
HANumeric::HANumeric(const uint32_t value, const uint8_t precision):
|
||
|
|
_isSet(true),
|
||
|
|
_precision(precision)
|
||
|
|
{
|
||
|
|
_value = value * getPrecisionBase();
|
||
|
|
}
|
||
|
|
|
||
|
|
#ifdef ARDUINOHA_INT_OVERLOAD
|
||
|
|
HANumeric::HANumeric(const int value, const uint8_t precision):
|
||
|
|
_isSet(true),
|
||
|
|
_precision(precision)
|
||
|
|
{
|
||
|
|
_value = value * static_cast<int>(getPrecisionBase());
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
HANumeric::HANumeric(const int64_t value):
|
||
|
|
_isSet(true),
|
||
|
|
_value(value),
|
||
|
|
_precision(0)
|
||
|
|
{
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
uint32_t HANumeric::getPrecisionBase() const
|
||
|
|
{
|
||
|
|
// using pow() increases the flash size by ~2KB
|
||
|
|
switch (_precision) {
|
||
|
|
case 1:
|
||
|
|
return 10;
|
||
|
|
|
||
|
|
case 2:
|
||
|
|
return 100;
|
||
|
|
|
||
|
|
case 3:
|
||
|
|
return 1000;
|
||
|
|
|
||
|
|
default:
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
uint8_t HANumeric::calculateSize() const
|
||
|
|
{
|
||
|
|
if (!_isSet) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int64_t value = _value;
|
||
|
|
const bool isSigned = value < 0;
|
||
|
|
|
||
|
|
if (isSigned) {
|
||
|
|
value *= -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
uint8_t digitsNb = 1;
|
||
|
|
while (value > 9) {
|
||
|
|
value /= 10;
|
||
|
|
digitsNb++;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (isSigned) {
|
||
|
|
digitsNb++; // sign
|
||
|
|
}
|
||
|
|
|
||
|
|
if (_precision > 0) {
|
||
|
|
if (value == 0) {
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
// one digit + dot + decimal digits (+ sign)
|
||
|
|
const uint8_t minValue = isSigned ? _precision + 3 : _precision + 2;
|
||
|
|
return digitsNb >= minValue ? digitsNb + 1 : minValue;
|
||
|
|
}
|
||
|
|
|
||
|
|
return digitsNb;
|
||
|
|
}
|
||
|
|
|
||
|
|
uint16_t HANumeric::toStr(char* dst) const
|
||
|
|
{
|
||
|
|
char* prefixCh = &dst[0];
|
||
|
|
if (!_isSet || _value == 0) {
|
||
|
|
*prefixCh = '0';
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
int64_t value = _value;
|
||
|
|
const uint8_t numberLength = calculateSize();
|
||
|
|
if (value < 0) {
|
||
|
|
value *= -1;
|
||
|
|
*prefixCh = '-';
|
||
|
|
prefixCh++;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (_precision > 0) {
|
||
|
|
uint8_t i = _precision;
|
||
|
|
char* dotPtr = prefixCh + 1;
|
||
|
|
do {
|
||
|
|
*prefixCh = '0';
|
||
|
|
prefixCh++;
|
||
|
|
} while(i-- > 0);
|
||
|
|
|
||
|
|
*dotPtr = '.';
|
||
|
|
}
|
||
|
|
|
||
|
|
char* ch = &dst[numberLength - 1];
|
||
|
|
char* lastCh = ch;
|
||
|
|
char* dotPos = _precision > 0 ? &dst[numberLength - 1 - _precision] : nullptr;
|
||
|
|
|
||
|
|
while (value != 0) {
|
||
|
|
if (ch == dotPos) {
|
||
|
|
*dotPos = '.';
|
||
|
|
ch--;
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
*ch = (value % 10) + '0';
|
||
|
|
value /= 10;
|
||
|
|
ch--;
|
||
|
|
}
|
||
|
|
|
||
|
|
return lastCh - &dst[0] + 1;
|
||
|
|
}
|