2024-12-01 19:35:24 +00:00
//| Copyright: (C) 2020-2024 Kevin Larke <contact AT larke DOT org>
//| License: GNU GPL version 3.0 or above. See the accompanying LICENSE file.
2019-12-19 03:24:12 +00:00
# ifndef cwNumericConvert_H
# define cwNumericConvert_H
namespace cw
{
/*
template < typename T >
T minimum_value ( ) { return 0 ; }
template < > inline char minimum_value < char > ( ) { return 0 ; }
template < > inline int8_t minimum_value < int8_t > ( ) { return INT8_MIN ; }
template < > inline int16_t minimum_value < int16_t > ( ) { return INT16_MIN ; }
template < > inline int32_t minimum_value < int32_t > ( ) { return INT32_MIN ; }
template < > inline int64_t minimum_value < int64_t > ( ) { return INT64_MIN ; }
template < > inline float minimum_value < float > ( ) { return FLT_MIN ; }
template < > inline double minimum_value < double > ( ) { return DBL_MIN ; }
template < typename T >
T maximum_value ( ) { cwAssert ( 0 ) ; }
template < > inline char maximum_value < char > ( ) { return 255 ; }
template < > inline int8_t maximum_value < int8_t > ( ) { return INT8_MAX ; }
template < > inline int16_t maximum_value < int16_t > ( ) { return INT16_MAX ; }
template < > inline int32_t maximum_value < int32_t > ( ) { return INT32_MAX ; }
template < > inline int64_t maximum_value < int64_t > ( ) { return INT64_MAX ; }
template < > inline uint8_t maximum_value < uint8_t > ( ) { return UINT8_MAX ; }
template < > inline uint16_t maximum_value < uint16_t > ( ) { return UINT16_MAX ; }
template < > inline uint32_t maximum_value < uint32_t > ( ) { return UINT32_MAX ; }
template < > inline uint64_t maximum_value < uint64_t > ( ) { return UINT64_MAX ; }
template < > inline bool maximum_value < bool > ( ) { std : : numeric_limits < bool > : : max ( ) ; }
template < > inline float maximum_value < float > ( ) { return FLT_MAX ; }
template < > inline double maximum_value < double > ( ) { return DBL_MAX ; }
*/
template < typename SRC_t , typename DST_t >
rc_t numeric_convert ( const SRC_t & src , DST_t & dst )
{
// TODO: there is probably a way of using type_traits to make a more efficient comparison
// and avoid the double conversion
2020-04-28 20:38:43 +00:00
double d_min = 0 ; // std::numeric_limits<DST_t>::min() return smallest positive number which then fails this test when 'src' is zero.
2019-12-19 03:24:12 +00:00
double d_max = std : : numeric_limits < DST_t > : : max ( ) ;
2021-08-15 19:57:54 +00:00
if ( ( double ) src < = d_max )
2019-12-19 03:24:12 +00:00
dst = src ;
else
2020-04-28 20:38:43 +00:00
return cwLogError ( kInvalidArgRC , " Numeric conversion failed. The source value is outside the range of the destination value. min:%f max:%f src:%f " , d_min , d_max , ( double ) src ) ;
2019-12-19 03:24:12 +00:00
return kOkRC ;
}
template < typename SRC_t , typename DST_t >
rc_t numeric_convert2 ( const SRC_t & src , DST_t & dst , const DST_t & minv , const DST_t & maxv )
{
if ( sizeof ( SRC_t ) < sizeof ( DST_t ) )
{
dst = src ;
}
else
{
if ( minv < = src & & src < = maxv )
dst = src ;
else
{
return cwLogError ( kInvalidArgRC , " Numeric conversion failed. The source value is outside the range of the destination value. " ) ;
}
}
return kOkRC ;
}
template < typename T >
rc_t string_to_number ( const char * s , T & valueRef )
{
if ( s = = nullptr )
2020-03-23 14:43:38 +00:00
valueRef = 0 ; // BUG BUG BUG why is this not an error ????
2019-12-19 03:24:12 +00:00
else
{
2023-05-21 16:38:47 +00:00
int base = 10 ;
2019-12-19 03:24:12 +00:00
errno = 0 ;
2023-05-21 16:38:47 +00:00
if ( strlen ( s ) > = 2 & & s [ 0 ] = = ' 0 ' & & s [ 1 ] = = ' x ' )
base = 16 ;
long v = strtol ( s , nullptr , base ) ;
if ( v = = 0 & & errno ! = 0 )
2019-12-19 03:24:12 +00:00
return cwLogError ( kOpFailRC , " String to number conversion failed on '%s'. " , cwStringNullGuard ( s ) ) ;
return numeric_convert ( v , valueRef ) ;
}
return kOkRC ;
}
template < > inline
rc_t string_to_number < double > ( const char * s , double & valueRef )
{
if ( s = = nullptr )
2020-03-23 14:43:38 +00:00
valueRef = 0 ; // BUG BUG BUG why is this not an error ????
2019-12-19 03:24:12 +00:00
else
{
errno = 0 ;
valueRef = strtod ( s , nullptr ) ;
2023-05-21 16:38:47 +00:00
if ( valueRef = = 0 & & errno ! = 0 )
2019-12-19 03:24:12 +00:00
return cwLogError ( kOpFailRC , " String to number conversion failed on '%s'. " , cwStringNullGuard ( s ) ) ;
}
return kOkRC ;
}
template < > inline
rc_t string_to_number < float > ( const char * s , float & valueRef )
{
double d ;
rc_t rc ;
if ( ( rc = string_to_number < double > ( s , d ) ) ! = kOkRC )
return rc ;
return numeric_convert ( d , valueRef ) ;
}
2020-03-23 14:43:38 +00:00
template < > inline
rc_t string_to_number < bool > ( const char * s , bool & valueRef )
{
s = nextNonWhiteChar ( s ) ;
if ( s = = nullptr )
valueRef = false ; // BUG BUG BUG why is this not an error ????
else
{
if ( strncmp ( " true " , s , 4 ) = = 0 )
valueRef = true ;
else
if ( strncmp ( " false " , s , 5 ) = = 0 )
valueRef = false ;
else
return cwLogError ( kOpFailRC , " String to number conversion failed on '%s'. " , cwStringNullGuard ( s ) ) ;
}
return kOkRC ;
}
2019-12-19 03:24:12 +00:00
template < typename T >
2020-12-29 15:11:00 +00:00
int number_to_string ( const T & v , char * buf , int bufN , const char * fmt = nullptr )
{ return snprintf ( buf , bufN , fmt , v ) ; }
template < > inline
int number_to_string ( const int & v , char * buf , int bufN , const char * fmt ) { return snprintf ( buf , bufN , fmt = = nullptr ? " %i " : fmt , v ) ; }
template < > inline
int number_to_string ( const unsigned & v , char * buf , int bufN , const char * fmt ) { return snprintf ( buf , bufN , fmt = = nullptr ? " %i " : fmt , v ) ; }
template < > inline
int number_to_string ( const double & v , char * buf , int bufN , const char * fmt ) { return snprintf ( buf , bufN , fmt = = nullptr ? " %f " : fmt , v ) ; }
2020-03-23 14:43:38 +00:00
2024-11-29 18:15:44 +00:00
rc_t numericConvertTest ( const test : : test_args_t & args ) ;
2020-12-29 15:11:00 +00:00
2019-12-19 03:24:12 +00:00
}
# endif