2016-01-28 14:52:40 +01:00
|
|
|
/** @file
|
|
|
|
|
*
|
|
|
|
|
* @par History
|
|
|
|
|
*/
|
2016-02-11 22:54:43 +01:00
|
|
|
|
|
|
|
|
|
2023-12-20 22:13:39 +01:00
|
|
|
#include <charconv>
|
2018-01-29 21:55:48 +01:00
|
|
|
#include <cmath>
|
|
|
|
|
#include <sstream>
|
|
|
|
|
#include <string>
|
2023-12-20 22:13:39 +01:00
|
|
|
#include <system_error>
|
2018-01-29 21:55:48 +01:00
|
|
|
|
|
|
|
|
#include "../clib/stlutil.h"
|
2016-02-11 22:54:43 +01:00
|
|
|
#include "berror.h"
|
2018-01-05 20:04:01 +01:00
|
|
|
#include "bobject.h"
|
2016-02-11 22:54:43 +01:00
|
|
|
#include "impstr.h"
|
2023-12-20 22:13:39 +01:00
|
|
|
namespace
|
|
|
|
|
{
|
|
|
|
|
std::string double_to_string( double val )
|
|
|
|
|
{
|
|
|
|
|
std::string buff( 100, '\0' );
|
|
|
|
|
auto [buffptr, ec] = std::to_chars( buff.data(), buff.data() + buff.size(), val );
|
|
|
|
|
if ( ec == std::errc() )
|
|
|
|
|
{
|
|
|
|
|
buff.resize( buffptr - buff.data() );
|
|
|
|
|
return buff;
|
|
|
|
|
}
|
|
|
|
|
throw std::system_error( std::make_error_code( ec ) );
|
|
|
|
|
}
|
|
|
|
|
} // namespace
|
2016-02-19 19:26:35 +01:00
|
|
|
namespace Pol
|
|
|
|
|
{
|
|
|
|
|
namespace Bscript
|
|
|
|
|
{
|
|
|
|
|
std::string Double::pack() const
|
|
|
|
|
{
|
2023-12-20 22:13:39 +01:00
|
|
|
return std::string( "r" ) + double_to_string( dval_ );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Double::packonto( std::ostream& os ) const
|
|
|
|
|
{
|
2023-12-20 22:13:39 +01:00
|
|
|
os << "r" << double_to_string( dval_ );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
|
2020-09-26 06:57:10 -07:00
|
|
|
BObjectImp* Double::unpack( std::istream& is )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
double dv;
|
2020-09-26 06:57:10 -07:00
|
|
|
#ifndef __APPLE__
|
2016-02-19 19:26:35 +01:00
|
|
|
if ( is >> dv )
|
2020-09-26 06:57:10 -07:00
|
|
|
#else
|
|
|
|
|
// well this (and the pack format) is terrible:
|
|
|
|
|
// 1) the pack format depends on operator>>(double) magically reading a whole double,
|
|
|
|
|
// but stopping without an error if it's followed by something else
|
|
|
|
|
// 2) on osx, operator>>(double) reports an error if the double is followed
|
|
|
|
|
// by something else
|
|
|
|
|
// 3) the pack format is ambiguous, mostly, if an error follows a double
|
|
|
|
|
// 4) fortunately, nobody will probably ever really run a server on osx
|
|
|
|
|
// 5) our options are a bit limited in peeking at an iostream, I think
|
|
|
|
|
// so:
|
|
|
|
|
// 4.5e-16 a double
|
|
|
|
|
// 4.5e+16 a double
|
|
|
|
|
// 4.5e62... a double, followed by an error with 62 elements
|
|
|
|
|
// - note that technically, this could be a double, but it seems
|
|
|
|
|
// that the double formatter is being nice and always including - or +
|
|
|
|
|
std::string tmp;
|
|
|
|
|
tmp.reserve( 16 );
|
|
|
|
|
while ( !is.eof() )
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
2020-09-26 06:57:10 -07:00
|
|
|
char ch = is.peek();
|
|
|
|
|
if ( std::isdigit( ch ) || ch == '.' || ch == '-' || ch == '+' )
|
|
|
|
|
{
|
|
|
|
|
tmp.push_back( is.get() );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2023-12-20 22:13:39 +01:00
|
|
|
if ( ch == 'e' ) // might be an exponent, or an error struct following the double (sadface)
|
2020-09-26 06:57:10 -07:00
|
|
|
{
|
2023-12-20 22:13:39 +01:00
|
|
|
is.get(); // the 'e'
|
2016-02-19 19:26:35 +01:00
|
|
|
|
2023-12-20 22:13:39 +01:00
|
|
|
if ( std::isdigit( is.peek() ) ) // assume it's followed by an error struct
|
2020-09-26 06:57:10 -07:00
|
|
|
{
|
|
|
|
|
is.unget();
|
|
|
|
|
}
|
2023-12-20 22:13:39 +01:00
|
|
|
else // assume it's an exponent
|
2020-09-26 06:57:10 -07:00
|
|
|
{
|
|
|
|
|
tmp.push_back( ch ); // the e
|
|
|
|
|
tmp.push_back( is.get() ); // the '+' or '-'
|
|
|
|
|
while ( !is.eof() && std::isdigit( is.peek() ) )
|
|
|
|
|
{
|
|
|
|
|
tmp.push_back( is.get() );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-12-20 22:13:39 +01:00
|
|
|
ISTRINGSTREAM is2( tmp );
|
2020-09-26 06:57:10 -07:00
|
|
|
if ( is2 >> dv )
|
|
|
|
|
#endif
|
2016-02-19 19:26:35 +01:00
|
|
|
{
|
|
|
|
|
return new Double( dv );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return new BError( "Error extracting Real value" );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t Double::sizeEstimate() const
|
|
|
|
|
{
|
|
|
|
|
return sizeof( Double );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool Double::operator==( const BObjectImp& objimp ) const
|
|
|
|
|
{
|
|
|
|
|
if ( objimp.isa( OTDouble ) )
|
|
|
|
|
{
|
|
|
|
|
double diff = dval_ - ( (Double&)objimp ).dval_;
|
|
|
|
|
return fabs( diff ) < 0.00000001;
|
|
|
|
|
}
|
|
|
|
|
else if ( objimp.isa( OTLong ) )
|
|
|
|
|
{
|
|
|
|
|
double diff = dval_ - ( (BLong&)objimp ).value();
|
|
|
|
|
return fabs( diff ) < 0.00000001;
|
2016-02-11 22:54:43 +01:00
|
|
|
}
|
2018-01-05 20:04:01 +01:00
|
|
|
else if ( objimp.isa( OTBoolean ) )
|
|
|
|
|
{
|
|
|
|
|
return isTrue() == static_cast<const BBoolean&>( objimp ).isTrue();
|
|
|
|
|
}
|
2016-02-19 19:26:35 +01:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Double::operator<( const BObjectImp& objimp ) const
|
|
|
|
|
{
|
|
|
|
|
if ( objimp.isa( OTDouble ) )
|
|
|
|
|
{
|
|
|
|
|
return ( dval_ < ( (Double&)objimp ).dval_ );
|
|
|
|
|
}
|
|
|
|
|
else if ( objimp.isa( OTLong ) )
|
|
|
|
|
{
|
|
|
|
|
return ( dval_ < ( (BLong&)objimp ).value() );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return base::operator<( objimp );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string Double::getStringRep() const
|
|
|
|
|
{
|
2023-12-20 22:13:39 +01:00
|
|
|
return double_to_string( dval_ );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BObjectImp* Double::selfPlusObjImp( const BObjectImp& objimp ) const
|
|
|
|
|
{
|
|
|
|
|
return objimp.selfPlusObj( *this );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BObjectImp* Double::selfPlusObj( const BLong& objimp ) const
|
|
|
|
|
{
|
|
|
|
|
return new Double( dval_ + objimp.value() );
|
|
|
|
|
}
|
|
|
|
|
BObjectImp* Double::selfPlusObj( const Double& objimp ) const
|
|
|
|
|
{
|
|
|
|
|
return new Double( dval_ + objimp.dval_ );
|
|
|
|
|
}
|
|
|
|
|
BObjectImp* Double::selfPlusObj( const String& objimp ) const
|
|
|
|
|
{
|
2018-05-06 19:18:21 +02:00
|
|
|
return new String( getStringRep() + objimp.value() );
|
2016-02-19 19:26:35 +01:00
|
|
|
}
|
|
|
|
|
void Double::selfPlusObjImp( BObjectImp& objimp, BObject& obj )
|
|
|
|
|
{
|
|
|
|
|
objimp.selfPlusObj( *this, obj );
|
|
|
|
|
}
|
|
|
|
|
void Double::selfPlusObj( BLong& objimp, BObject& obj )
|
|
|
|
|
{
|
|
|
|
|
obj.setimp( selfPlusObj( objimp ) );
|
|
|
|
|
}
|
|
|
|
|
void Double::selfPlusObj( Double& objimp, BObject& /*obj*/ )
|
|
|
|
|
{
|
|
|
|
|
dval_ += objimp.dval_;
|
|
|
|
|
}
|
|
|
|
|
void Double::selfPlusObj( String& objimp, BObject& obj )
|
|
|
|
|
{
|
|
|
|
|
obj.setimp( selfPlusObj( objimp ) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BObjectImp* Double::selfMinusObjImp( const BObjectImp& objimp ) const
|
|
|
|
|
{
|
|
|
|
|
return objimp.selfMinusObj( *this );
|
|
|
|
|
}
|
|
|
|
|
BObjectImp* Double::selfMinusObj( const BLong& objimp ) const
|
|
|
|
|
{
|
|
|
|
|
return new Double( dval_ - objimp.value() );
|
|
|
|
|
}
|
|
|
|
|
BObjectImp* Double::selfMinusObj( const Double& objimp ) const
|
|
|
|
|
{
|
|
|
|
|
return new Double( dval_ - objimp.dval_ );
|
|
|
|
|
}
|
|
|
|
|
BObjectImp* Double::selfMinusObj( const String& objimp ) const
|
|
|
|
|
{
|
|
|
|
|
String s( getStringRep() );
|
|
|
|
|
return s.selfMinusObj( objimp );
|
|
|
|
|
}
|
|
|
|
|
void Double::selfMinusObjImp( BObjectImp& objimp, BObject& obj )
|
|
|
|
|
{
|
|
|
|
|
objimp.selfMinusObj( *this, obj );
|
|
|
|
|
}
|
|
|
|
|
void Double::selfMinusObj( BLong& objimp, BObject& /*obj*/ )
|
|
|
|
|
{
|
|
|
|
|
dval_ -= objimp.value();
|
|
|
|
|
}
|
|
|
|
|
void Double::selfMinusObj( Double& objimp, BObject& /*obj*/ )
|
|
|
|
|
{
|
|
|
|
|
dval_ -= objimp.value();
|
|
|
|
|
}
|
|
|
|
|
void Double::selfMinusObj( String& objimp, BObject& obj )
|
|
|
|
|
{
|
|
|
|
|
obj.setimp( selfMinusObj( objimp ) );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BObjectImp* Double::selfTimesObjImp( const BObjectImp& objimp ) const
|
|
|
|
|
{
|
|
|
|
|
return objimp.selfTimesObj( *this );
|
|
|
|
|
}
|
|
|
|
|
BObjectImp* Double::selfTimesObj( const BLong& objimp ) const
|
|
|
|
|
{
|
|
|
|
|
return new Double( dval_ * objimp.value() );
|
|
|
|
|
}
|
|
|
|
|
BObjectImp* Double::selfTimesObj( const Double& objimp ) const
|
|
|
|
|
{
|
|
|
|
|
return new Double( dval_ * objimp.value() );
|
|
|
|
|
}
|
|
|
|
|
void Double::selfTimesObjImp( BObjectImp& objimp, BObject& obj )
|
|
|
|
|
{
|
|
|
|
|
objimp.selfTimesObj( *this, obj );
|
|
|
|
|
}
|
|
|
|
|
void Double::selfTimesObj( BLong& objimp, BObject& /*obj*/ )
|
|
|
|
|
{
|
|
|
|
|
dval_ *= objimp.value();
|
|
|
|
|
}
|
|
|
|
|
void Double::selfTimesObj( Double& objimp, BObject& /*obj*/ )
|
|
|
|
|
{
|
|
|
|
|
dval_ *= objimp.value();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BObjectImp* Double::selfDividedByObjImp( const BObjectImp& objimp ) const
|
|
|
|
|
{
|
|
|
|
|
return objimp.selfDividedByObj( *this );
|
|
|
|
|
}
|
|
|
|
|
BObjectImp* Double::selfDividedByObj( const BLong& objimp ) const
|
|
|
|
|
{
|
|
|
|
|
int divisor = objimp.value();
|
|
|
|
|
if ( !divisor )
|
|
|
|
|
return new BError( "Divide by Zero" );
|
|
|
|
|
else
|
|
|
|
|
return new Double( dval_ / divisor );
|
|
|
|
|
}
|
|
|
|
|
BObjectImp* Double::selfDividedByObj( const Double& objimp ) const
|
|
|
|
|
{
|
|
|
|
|
double divisor = objimp.value();
|
|
|
|
|
if ( divisor == 0.0 )
|
|
|
|
|
return new BError( "Divide by Zero" );
|
|
|
|
|
else
|
|
|
|
|
return new Double( dval_ / divisor );
|
|
|
|
|
}
|
|
|
|
|
void Double::selfDividedByObjImp( BObjectImp& objimp, BObject& obj )
|
|
|
|
|
{
|
|
|
|
|
objimp.selfDividedByObj( *this, obj );
|
|
|
|
|
}
|
|
|
|
|
void Double::selfDividedByObj( BLong& objimp, BObject& obj )
|
|
|
|
|
{
|
|
|
|
|
if ( !objimp.value() )
|
|
|
|
|
obj.setimp( new BError( "Divide by Zero" ) );
|
|
|
|
|
else
|
|
|
|
|
dval_ /= objimp.value();
|
|
|
|
|
}
|
|
|
|
|
void Double::selfDividedByObj( Double& objimp, BObject& obj )
|
|
|
|
|
{
|
|
|
|
|
if ( !objimp.value() )
|
|
|
|
|
obj.setimp( new BError( "Divide by Zero" ) );
|
|
|
|
|
else
|
|
|
|
|
dval_ /= objimp.value();
|
|
|
|
|
}
|
2023-12-20 22:13:39 +01:00
|
|
|
} // namespace Bscript
|
|
|
|
|
} // namespace Pol
|