summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAkarsh Simha <akarsh@kde.org>2016-09-26 10:43:09 (GMT)
committerAkarsh Simha <akarsh@kde.org>2016-09-29 02:20:26 (GMT)
commit1a6d50b0553763c2c3418952f3e85b12359ab699 (patch)
tree95dc972adcc3d9123d6086766c245b5961b9524a
parent5c0232bf4518319350648efdb9e538c15a0209ed (diff)
Virtualize dms setters to prevent wrong results if we convert to dms*
This ensures that if we ever convert CachingDms * to dms *, the setters all call SinCos to update the cache, thereby preventing an invalid cache that's out of sync. The test checks this.
-rw-r--r--Tests/auxiliary/testcachingdms.cpp52
-rw-r--r--Tests/auxiliary/testcachingdms.h1
-rw-r--r--kstars/auxiliary/cachingdms.h3
-rw-r--r--kstars/auxiliary/dms.cpp33
-rw-r--r--kstars/auxiliary/dms.h30
5 files changed, 86 insertions, 33 deletions
diff --git a/Tests/auxiliary/testcachingdms.cpp b/Tests/auxiliary/testcachingdms.cpp
index 0036c4b..902cc92 100644
--- a/Tests/auxiliary/testcachingdms.cpp
+++ b/Tests/auxiliary/testcachingdms.cpp
@@ -25,6 +25,9 @@
/* Qt Includes */
/* STL Includes */
+#include <ctime>
+#include <cstdlib>
+#include <cstdint>
TestCachingDms::TestCachingDms(): QObject()
{
@@ -244,4 +247,53 @@ void TestCachingDms::subtractionOperator() {
QVERIFY( fabs( ds2.cos() - coscmd ) < 1e-9 );
}
+
+void TestCachingDms::testFailsafeUseOfBaseClassPtr() {
+ typedef union angle { double x; int64_t y; } angle;
+ const int testCases = 5000;
+ std::srand( std::time( 0 ) );
+ for ( int k = 0; k < testCases; ++k ) {
+ angle a; CachingDms _a; dms __a;
+ a.y = std::rand();
+ _a.setD( a.x );
+ __a.setD( a.x );
+ dms *d;
+ if ( rand()%10 > 5 )
+ d = &_a;
+ else
+ d = &__a;
+ angle b;
+ b.y = std::rand();
+ switch( rand()%6 ) {
+ case 0:
+ d->setD( b.x );
+ break;
+ case 1:
+ d->setH( b.x / 15. );
+ break;
+ case 2: {
+ dms x( b.x );
+ d->setD( x.degree(), x.arcmin(), x.arcsec(), x.marcsec() );
+ break;
+ }
+ case 3: {
+ dms x( b.x );
+ d->setFromString( x.toDMSString() );
+ break;
+ }
+ case 4: {
+ dms x( b.x );
+ d->setFromString( x.toHMSString(), false );
+ break;
+ }
+ case 5:
+ default:
+ d->setRadians( b.x * dms::DegToRad );
+ break;
+ }
+ QVERIFY( fabs( d->sin() - sin( b.x * dms::DegToRad ) ) < 1e-12 );
+ QVERIFY( fabs( d->cos() - cos( b.x * dms::DegToRad ) ) < 1e-12 );
+ }
+}
+
QTEST_GUILESS_MAIN(TestCachingDms)
diff --git a/Tests/auxiliary/testcachingdms.h b/Tests/auxiliary/testcachingdms.h
index 0c0c7d7..9bc144f 100644
--- a/Tests/auxiliary/testcachingdms.h
+++ b/Tests/auxiliary/testcachingdms.h
@@ -58,6 +58,7 @@ private slots:
void additionOperator();
void subtractionOperator();
void unaryMinusOperator();
+ void testFailsafeUseOfBaseClassPtr();
};
#endif
diff --git a/kstars/auxiliary/cachingdms.h b/kstars/auxiliary/cachingdms.h
index 5aacf4d..4cc4c55 100644
--- a/kstars/auxiliary/cachingdms.h
+++ b/kstars/auxiliary/cachingdms.h
@@ -107,13 +107,14 @@ public:
* @short Sets the angle from string
* @note Re-implements dms::setFromString()
*/
- inline void setFromString( const QString &s, bool isDeg = true ) { dms::setFromString( s, isDeg ); dms::SinCos( m_sin, m_cos );
+ inline bool setFromString( const QString &s, bool isDeg = true ) { bool retval = dms::setFromString( s, isDeg ); dms::SinCos( m_sin, m_cos );
#ifdef COUNT_DMS_SINCOS_CALLS
cachingdms_delta -= 2;
if( !m_cacheUsed )
++cachingdms_bad_uses;
m_cacheUsed = false;
#endif
+ return retval;
}
/**
diff --git a/kstars/auxiliary/dms.cpp b/kstars/auxiliary/dms.cpp
index 9e36857..e72c571 100644
--- a/kstars/auxiliary/dms.cpp
+++ b/kstars/auxiliary/dms.cpp
@@ -39,13 +39,6 @@ void dms::setD(const int &d, const int &m, const int &s, const int &ms) {
#endif
}
-void dms::setH( const double &x ) {
- setD( x*15.0 );
-#ifdef COUNT_DMS_SINCOS_CALLS
- m_cosDirty = m_sinDirty = true;
-#endif
-}
-
void dms::setH(const int &h, const int &m, const int &s, const int &ms) {
D = 15.0*((double)abs(h) + ((double)m + ((double)s + (double)ms/1000.)/60.)/60.);
if (h<0) {D = -1.0*D;}
@@ -54,12 +47,6 @@ void dms::setH(const int &h, const int &m, const int &s, const int &ms) {
#endif
}
-void dms::setRadians( const double &Rad ) {
- setD( Rad/DegToRad );
-#ifdef COUNT_DMS_SINCOS_CALLS
- m_cosDirty = m_sinDirty = true;
-#endif
-}
bool dms::setFromString( const QString &str, bool isDeg ) {
int d(0), m(0);
@@ -74,23 +61,23 @@ bool dms::setFromString( const QString &str, bool isDeg ) {
//empty entry returns false
if ( entry.isEmpty() ) {
- setD( NaN::d );
+ dms::setD( NaN::d );
return false;
}
//try parsing a simple integer
d = entry.toInt( &checkValue );
if ( checkValue ) {
- if (isDeg) setD( d, 0, 0 );
- else setH( d, 0, 0 );
+ if (isDeg) dms::setD( d, 0, 0 );
+ else dms::setH( d, 0, 0 );
return true;
}
//try parsing a simple double
double x = entry.toDouble( &checkValue );
if ( checkValue ) {
- if ( isDeg ) setD( x );
- else setH( x );
+ if ( isDeg ) dms::setD( x );
+ else dms::setH( x );
return true;
}
@@ -104,7 +91,7 @@ bool dms::setFromString( const QString &str, bool isDeg ) {
//anything with one field is invalid!
if ( fields.count() == 1 ) {
- setD( NaN::d );
+ dms::setD( NaN::d );
return false;
}
@@ -122,7 +109,7 @@ bool dms::setFromString( const QString &str, bool isDeg ) {
fields[1] = QString::number( int(mx) );
fields.append( QString::number( int( 60.0*(mx - int(mx)) ) ) );
} else {
- setD( NaN::d );
+ dms::setD( NaN::d );
return false;
}
}
@@ -152,12 +139,12 @@ bool dms::setFromString( const QString &str, bool isDeg ) {
if ( negative || d<0 || m < 0 || s<0 ) { D = -1.0*D;}
if (isDeg) {
- setD( D );
+ dms::setD( D );
} else {
- setH( D );
+ dms::setH( D );
}
} else {
- setD( NaN::d );
+ dms::setD( NaN::d );
return false;
}
diff --git a/kstars/auxiliary/dms.h b/kstars/auxiliary/dms.h
index 0f77cfb..e75e78b 100644
--- a/kstars/auxiliary/dms.h
+++ b/kstars/auxiliary/dms.h
@@ -69,7 +69,7 @@ public:
#ifdef COUNT_DMS_SINCOS_CALLS
: m_sinCosCalled(false), m_sinDirty( true ), m_cosDirty( true )
#endif
- { setD( d, m, s, ms );
+ { dms::setD( d, m, s, ms );
#ifdef COUNT_DMS_SINCOS_CALLS
++dms_constructor_calls;
#endif
@@ -166,7 +166,7 @@ public:
/** Sets floating-point value of angle, in degrees.
* @param x new angle (double)
*/
- void setD( const double &x ) {
+ inline virtual void setD( const double &x ) {
#ifdef COUNT_DMS_SINCOS_CALLS
m_sinDirty = m_cosDirty = true;
#endif
@@ -186,7 +186,7 @@ public:
* @param s integer arcseconds portion of angle
* @param ms integer arcseconds portion of angle
*/
- void setD( const int &d, const int &m, const int &s, const int &ms=0 );
+ virtual void setD( const int &d, const int &m, const int &s, const int &ms=0 );
/** @short Sets floating-point value of angle, in hours.
*
@@ -195,7 +195,13 @@ public:
* @param x new angle, in hours (double)
* @sa setD()
*/
- void setH( const double &x );
+ inline virtual void setH( const double &x ) {
+ dms::setD( x*15.0 );
+#ifdef COUNT_DMS_SINCOS_CALLS
+ m_cosDirty = m_sinDirty = true;
+#endif
+ }
+
/** @short Sets floating-point value of angle, in hours.
*
@@ -209,7 +215,7 @@ public:
* @param ms integer milliseconds portion of angle
* @sa setD()
*/
- void setH( const int &h, const int &m, const int &s, const int &ms=0 );
+ virtual void setH( const int &h, const int &m, const int &s, const int &ms=0 );
/** @short Attempt to parse the string argument as a dms value, and set the dms object
* accordingly.
@@ -219,7 +225,7 @@ public:
* @return true if sting was parsed successfully. Otherwise, set the dms value
* to 0.0 and return false.
*/
- bool setFromString( const QString &s, bool isDeg=true );
+ virtual bool setFromString( const QString &s, bool isDeg=true );
/** @short Compute Sine and Cosine of the angle simultaneously.
* On machines using glibc >= 2.1, calling SinCos() is somewhat faster
@@ -289,7 +295,7 @@ public:
/** @short Express the angle in radians.
* @return the angle in radians (double)
*/
- double radians() const { return D*DegToRad; }
+ inline double radians() const { return D*DegToRad; }
/** @short Set angle according to the argument, in radians.
*
@@ -297,7 +303,13 @@ public:
* with setD().
* @param a angle in radians
*/
- void setRadians( const double &a );
+ inline virtual void setRadians( const double &Rad ) {
+ dms::setD( Rad/DegToRad );
+#ifdef COUNT_DMS_SINCOS_CALLS
+ m_cosDirty = m_sinDirty = true;
+#endif
+ }
+
/** return the equivalent angle between 0 and 360 degrees.
* @warning does not change the value of the parent angle itself.
@@ -352,7 +364,7 @@ public:
*/
static dms fromString(const QString & s, bool deg);
- dms operator - () { return dms(-D); }
+ inline dms operator - () { return dms(-D); }
#ifdef COUNT_DMS_SINCOS_CALLS
static long unsigned dms_constructor_calls; // counts number of DMS constructor calls
static long unsigned dms_with_sincos_called;