I'm currently writing a visualiser for a date type in natvis. The date type stores seconds since 1970 in the usual unix way but deriving year, month and day of the month from that is extremely long winded if not using temporary variables. I'd like to be able to store working variables in order to evaluate the visualiser in a sane manner. Is this possible?
The solution I arrived at looks like this:
struct SLowResAbsoluteTime
{
SLowResAbsoluteTime() : mTime(0) { calcDOE(); }
SLowResAbsoluteTime(int year, SDate::EMonth m, SDate::EDayOfWeek day, UINT8 hour, UINT8 minute, UINT8 seconds);
SLowResAbsoluteTime(const SDate &date);
SLowResAbsoluteTime(unsigned long long time) : mTime(time) { calcDOE(); }
SLowResAbsoluteTime(const SLowResAbsoluteTime &other) : mTime(other.mTime) { calcDOE(); }
SDate getDate() const; //calculate date object from given time
UINT32 getHour() const;
UINT32 getMinutes() const;
UINT32 getSeconds() const;
bool operator < (const SLowResAbsoluteTime &other) const { return mTime < other.mTime; }
bool operator > (const SLowResAbsoluteTime &other) const { return mTime > other.mTime; }
bool operator <= (const SLowResAbsoluteTime &other) const { return mTime <= other.mTime; }
bool operator >= (const SLowResAbsoluteTime &other) const { return mTime >= other.mTime; }
bool operator == (const SLowResAbsoluteTime &other) const { return mTime == other.mTime; }
bool operator != (const SLowResAbsoluteTime &other) const { return mTime != other.mTime; }
SLowResAbsoluteTime operator -(const SLowResAbsoluteTime &time) const { return SLowResAbsoluteTime(mTime - time.mTime); }
SLowResAbsoluteTime operator +(const SLowResAbsoluteTime &time) const { return SLowResAbsoluteTime(mTime + time.mTime); }
const SLowResAbsoluteTime &operator -=(const SLowResAbsoluteTime &time) { mTime -= time.mTime; return *this; }
const SLowResAbsoluteTime &operator +=(const SLowResAbsoluteTime &time) { mTime += time.mTime; return *this; }
unsigned long long mTime;
void invalidate() { mTime = -1; }
bool isValid() const {return mTime != UINT64(-1); }
operator unsigned long() const { return (long)mTime; }
void calcDOE();
#ifdef USING_DEBUG_TIMER_DOE
struct { UINT16 y; UINT8 m; UINT8 d; } mDOE;
#endif
};
Note the 'USING_DEBUG_TIMER_DOE' section. That's calculated like this:
void SLowResAbsoluteTime::calcDOE()
{
#ifdef USING_DEBUG_TIMER_DOE
int ts = mTime / (60 * 60 * 24);
int z = ts + 719468;
int doe = (z - ((z >= 0 ? z : z - 146096) / 146097) * 146097);
int yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365; // [0, 399]
int era = (z >= 0 ? z : z - 146096) / 146097;
int y = (yoe) + era * 400;
int doy = doe - (365 * yoe + yoe / 4 - yoe / 100); // [0, 365]
int mp = (5 * doy + 2) / 153; // [0, 11]
int d = doy - (153 * mp + 2) / 5 + 1; // [1, 31]
int m = mp + (mp < 10 ? 3 : -9); // [1, 12]
mDOE.y = y + (m <= 2);
mDOE.m = m;
mDOE.d = d;
#endif
}
and the natvis for visualising these is:
<Type Name="SLowResAbsoluteTime">
<DisplayString>{{time = { (mTime / (60 * 60)) % 24 }:{(mTime / 60) % 60}:{mTime % 60} } day-1970: {mTime / (60 * 60 * 24)} }</DisplayString>
<Expand>
<Item Name="month">(int)mDOE.m</Item>
<Item Name="day">(int)mDOE.d</Item>-->
<Item Name="secs since 1/1/1970"> mTime</Item>
</Expand>
</Type>
If you want to eliminate calcDOE
and mDOE
from your code and do calculation in the proper natvis - yes, it is possible. Use Intrinsic
functions:
<Type Name="SLowResAbsoluteTime">
<Intrinsic Name="ts" Expression="mTime / (60 * 60 * 24) "/>
<Intrinsic Name="z" Expression="ts() + 719468 "/>
<Intrinsic Name="doe" Expression="(z() - ((z() >= 0 ? z() : z() - 146096) / 146097) * 146097)"/>
<Intrinsic Name="yoe" Expression="(doe() - doe() / 1460 + doe() / 36524 - doe() / 146096) / 365"/>
<Intrinsic Name="era" Expression="(z() >= 0 ? z() : z() - 146096) / 146097 "/>
<Intrinsic Name="y" Expression="yoe() + era() * 400 "/>
<Intrinsic Name="doy" Expression="doe() - (365 * yoe() + yoe() / 4 - yoe() / 100) "/>
<Intrinsic Name="mp" Expression="(5 * doy() + 2) / 153 "/>
<Intrinsic Name="d" Expression="doy() - (153 * mp() + 2) / 5 + 1 "/>
<Intrinsic Name="m" Expression="mp() + (mp() < 10 ? 3 : -9) "/>
<Intrinsic Name="DOEy" Expression="y() + (m() <= 2) "/>
<Expand>
<Item Name="day">d()</Item>
<Item Name="month">m()</Item>
<Item Name="year">DOEy()</Item>
</Expand>
</Type>