Code View

fson / source / fson-1.1.0.0 / libs / internal / sdk / fson / Number.cpp
// 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