// Copyright (c) 2018-2020 Dr. Colin Hirsch and Daniel Frey // Please see LICENSE for license or visit https://github.com/taocpp/json/ #ifndef TAO_JSON_INTERNAL_NUMBER_TRAITS_HPP #define TAO_JSON_INTERNAL_NUMBER_TRAITS_HPP #include #include #include "../forward.hpp" #include "../message_extension.hpp" #include "../type.hpp" #include "format.hpp" #ifdef _MSC_VER #pragma warning( push ) #pragma warning( disable : 4702 ) #endif namespace tao::json::internal { template< typename T > struct number_trait { template< template< typename... > class Traits > [[nodiscard]] static T as( const basic_value< Traits >& v ) { switch( v.type() ) { case type::SIGNED: return static_cast< T >( v.get_signed() ); case type::UNSIGNED: return static_cast< T >( v.get_unsigned() ); case type::DOUBLE: return static_cast< T >( v.get_double() ); default: throw std::logic_error( internal::format( "invalid json type '", v.type(), "' for conversion to number", json::message_extension( v ) ) ); } } }; template< typename T > struct signed_trait : number_trait< T > { template< template< typename... > class, typename Parts > [[nodiscard]] static T consume( Parts& parser ) { return static_cast< T >( parser.number_signed() ); } template< template< typename... > class Traits, typename Consumer > static void produce( Consumer& c, const T i ) { c.number( std::int64_t( i ) ); } template< template< typename... > class Traits > static void assign( basic_value< Traits >& v, const T i ) noexcept { v.set_signed( i ); } template< template< typename... > class Traits > [[nodiscard]] static bool equal( const basic_value< Traits >& lhs, const T rhs ) noexcept { const auto& p = lhs.skip_value_ptr(); switch( p.type() ) { case type::SIGNED: return p.get_signed() == rhs; case type::UNSIGNED: return ( rhs >= 0 ) && ( p.get_unsigned() == static_cast< std::uint64_t >( rhs ) ); case type::DOUBLE: return p.get_double() == rhs; default: return false; } } template< template< typename... > class Traits > [[nodiscard]] static bool less_than( const basic_value< Traits >& lhs, const T rhs ) noexcept { const auto& p = lhs.skip_value_ptr(); switch( p.type() ) { case type::SIGNED: return p.get_signed() < rhs; case type::UNSIGNED: return ( rhs >= 0 ) && ( p.get_unsigned() < static_cast< std::uint64_t >( rhs ) ); case type::DOUBLE: return p.get_double() < rhs; default: return p.type() < type::SIGNED; } } template< template< typename... > class Traits > [[nodiscard]] static bool greater_than( const basic_value< Traits >& lhs, const T rhs ) noexcept { const auto& p = lhs.skip_value_ptr(); switch( p.type() ) { case type::SIGNED: return p.get_signed() > rhs; case type::UNSIGNED: return ( rhs < 0 ) || ( p.get_unsigned() > static_cast< std::uint64_t >( rhs ) ); case type::DOUBLE: return p.get_double() > rhs; default: return p.type() > type::SIGNED; } } }; template< typename T > struct unsigned_trait : number_trait< T > { template< template< typename... > class, typename Parts > [[nodiscard]] static T consume( Parts& parser ) { return static_cast< T >( parser.number_unsigned() ); } template< template< typename... > class Traits, typename Consumer > static void produce( Consumer& c, const T i ) { c.number( std::uint64_t( i ) ); } template< template< typename... > class Traits > static void assign( basic_value< Traits >& v, const T i ) noexcept { v.set_unsigned( i ); } template< template< typename... > class Traits > [[nodiscard]] static bool equal( const basic_value< Traits >& lhs, const T rhs ) noexcept { const auto& p = lhs.skip_value_ptr(); switch( p.type() ) { case type::SIGNED: { const auto v = p.get_signed(); return ( v >= 0 ) && ( static_cast< std::uint64_t >( v ) == rhs ); } case type::UNSIGNED: return p.get_unsigned() == rhs; case type::DOUBLE: return p.get_double() == rhs; default: return false; } } template< template< typename... > class Traits > [[nodiscard]] static bool less_than( const basic_value< Traits >& lhs, const T rhs ) noexcept { const auto& p = lhs.skip_value_ptr(); switch( p.type() ) { case type::SIGNED: { const auto v = p.get_signed(); return ( v < 0 ) || ( static_cast< std::uint64_t >( v ) < rhs ); } case type::UNSIGNED: return p.get_unsigned() < rhs; case type::DOUBLE: return p.get_double() < rhs; default: return p.type() < type::UNSIGNED; } } template< template< typename... > class Traits > [[nodiscard]] static bool greater_than( const basic_value< Traits >& lhs, const T rhs ) noexcept { const auto& p = lhs.skip_value_ptr(); switch( p.type() ) { case type::SIGNED: { const auto v = p.get_signed(); return ( v >= 0 ) && ( static_cast< std::uint64_t >( v ) > rhs ); } case type::UNSIGNED: return p.get_unsigned() > rhs; case type::DOUBLE: return p.get_double() > rhs; default: return p.type() > type::UNSIGNED; } } }; template< typename T > struct float_trait : number_trait< T > { template< template< typename... > class, typename Parts > [[nodiscard]] static T consume( Parts& parser ) { return static_cast< T >( parser.number_double() ); } template< template< typename... > class Traits, typename Consumer > static void produce( Consumer& c, const T f ) { c.number( double( f ) ); } template< template< typename... > class Traits > static void assign( basic_value< Traits >& v, const T f ) noexcept { v.set_double( f ); } template< template< typename... > class Traits > [[nodiscard]] static bool equal( const basic_value< Traits >& lhs, const T rhs ) noexcept { const auto& p = lhs.skip_value_ptr(); switch( p.type() ) { case type::SIGNED: return p.get_signed() == rhs; case type::UNSIGNED: return p.get_unsigned() == rhs; case type::DOUBLE: return p.get_double() == rhs; // TODO: Is it ok for overall semantics that NaN != NaN? default: return false; } } template< template< typename... > class Traits > [[nodiscard]] static bool less_than( const basic_value< Traits >& lhs, const T rhs ) noexcept { const auto& p = lhs.skip_value_ptr(); switch( p.type() ) { case type::SIGNED: return p.get_signed() < rhs; case type::UNSIGNED: return p.get_unsigned() < rhs; case type::DOUBLE: return p.get_double() < rhs; default: return p.type() < type::DOUBLE; } } template< template< typename... > class Traits > [[nodiscard]] static bool greater_than( const basic_value< Traits >& lhs, const T rhs ) noexcept { const auto& p = lhs.skip_value_ptr(); switch( p.type() ) { case type::SIGNED: return p.get_signed() > rhs; case type::UNSIGNED: return p.get_unsigned() > rhs; case type::DOUBLE: return p.get_double() > rhs; default: return p.type() > type::DOUBLE; } } }; } // namespace tao::json::internal #ifdef _MSC_VER #pragma warning( pop ) #endif #endif