c++visual-studionatvis

Local variables for Visual studio natvis statements


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>

Solution

  • 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() &gt;= 0 ? z() : z() - 146096) / 146097) * 146097)"/>
        <Intrinsic Name="yoe"  Expression="(doe() - doe() / 1460 + doe() / 36524 - doe() / 146096) / 365"/>
        <Intrinsic Name="era"  Expression="(z() &gt;= 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() &lt; 10 ? 3 : -9)                               "/>
        <Intrinsic Name="DOEy" Expression="y() + (m() &lt;= 2)                                          "/>
        <Expand>
          <Item Name="day">d()</Item>
          <Item Name="month">m()</Item>
          <Item Name="year">DOEy()</Item>
        </Expand>
      </Type>