// SPDX-License-Identifier: MIT
#include "Number.hh"
#include <charconv>
#include <cmath>
#include <stdexcept>
#include <system_error>
using namespace std;
namespace fedem
{
namespace fson
{
namespace
{
struct DecimalLexeme
{
string lexeme;
Number::Kind kind;
};
DecimalLexeme makeDecimalLexeme( double value )
{
if( isnan( value ) )
return { "NaN", Number::Kind::NaN };
if( isinf( value ) )
return value > 0.0
? DecimalLexeme{ "Infinity", Number::Kind::Infinity }
: DecimalLexeme{ "-Infinity", Number::Kind::NegativeInfinity };
char buffer[ 64 ];
auto const result = to_chars( buffer, buffer + sizeof( buffer ), value );
if( result.ec != errc( ) )
throw invalid_argument( "fson::Number: value conversion failed" );
return { string( buffer, result.ptr ), Number::Kind::Decimal };
}
string makeLexeme( long long value )
{
char buffer[ 32 ];
auto const result = to_chars( buffer, buffer + sizeof( buffer ), value );
return string( buffer, result.ptr );
}
} // end anonymous namespace
Number::Number( double value )
: value( value )
, lexeme( )
, kind( Kind::Decimal )
{
DecimalLexeme dl = makeDecimalLexeme( value );
lexeme = std::move( dl.lexeme );
kind = dl.kind;
}
Number::Number( long long value )
: value( static_cast< double >( value ) )
, lexeme( makeLexeme( value ) )
, kind( Kind::Decimal )
{
}
Number::Number( double value, string lexeme, Kind kind )
: value( value )
, lexeme( std::move( lexeme ) )
, kind( kind )
{
}
unique_ptr< Value > Number::clone( ) const
{
return unique_ptr< Value >( new Number( value, lexeme, kind ) );
}
bool Number::isIntegral( ) const noexcept
{
switch( kind )
{
case Kind::Decimal:
return lexeme.find_first_of( ".eE" ) == string::npos;
case Kind::Hex:
return true;
case Kind::Infinity:
case Kind::NegativeInfinity:
case Kind::NaN:
return false;
}
return false;
}
void Number::setValue( double value )
{
DecimalLexeme dl = makeDecimalLexeme( value );
lexeme = std::move( dl.lexeme );
kind = dl.kind;
this->value = value;
}
void Number::setValue( long long value )
{
lexeme = makeLexeme( value );
kind = Kind::Decimal;
this->value = static_cast< double >( value );
}
} // end namespace fson
} // end namespace fedem