/* * Copyright (C) 2014 Pavel Kirienko */ #pragma once #include #include #include #include #include #include namespace uavcan { template class DurationBase { int64_t usec_; public: DurationBase() : usec_(0) { StaticAssert<(sizeof(D) == 8)>::check(); } static D getInfinite() { return fromUSec(std::numeric_limits::max()); } static D fromUSec(int64_t us) { D d; d.usec_ = us; return d; } static D fromMSec(int64_t ms) { return fromUSec(ms * 1000); } int64_t toUSec() const { return usec_; } int64_t toMSec() const { return usec_ / 1000; } D getAbs() const { return D::fromUSec(std::abs(usec_)); } bool isPositive() const { return usec_ > 0; } bool isNegative() const { return usec_ < 0; } bool isZero() const { return usec_ == 0; } bool operator==(const D& r) const { return usec_ == r.usec_; } bool operator!=(const D& r) const { return !operator==(r); } bool operator<(const D& r) const { return usec_ < r.usec_; } bool operator>(const D& r) const { return usec_ > r.usec_; } bool operator<=(const D& r) const { return usec_ <= r.usec_; } bool operator>=(const D& r) const { return usec_ >= r.usec_; } D operator+(const D& r) const { return fromUSec(usec_ + r.usec_); } // TODO: overflow check D operator-(const D& r) const { return fromUSec(usec_ - r.usec_); } // ditto D operator-() const { return fromUSec(-usec_); } D& operator+=(const D& r) { *this = *this + r; return *static_cast(this); } D& operator-=(const D& r) { *this = *this - r; return *static_cast(this); } template D operator*(Scale scale) const { return fromUSec(usec_ * scale); } template D& operator*=(Scale scale) { *this = *this * scale; return *static_cast(this); } enum { StringBufSize = 32 }; void toString(char buf[StringBufSize]) const; #if UAVCAN_TOSTRING std::string toString() const; #endif }; template class TimeBase { uint64_t usec_; public: TimeBase() : usec_(0) { StaticAssert<(sizeof(T) == 8)>::check(); StaticAssert<(sizeof(D) == 8)>::check(); } static T getMax() { return fromUSec(std::numeric_limits::max()); } static T fromUSec(uint64_t us) { T d; d.usec_ = us; return d; } static T fromMSec(uint64_t ms) { return fromUSec(ms * 1000); } uint64_t toUSec() const { return usec_; } uint64_t toMSec() const { return usec_ / 1000; } bool isZero() const { return usec_ == 0; } bool operator==(const T& r) const { return usec_ == r.usec_; } bool operator!=(const T& r) const { return !operator==(r); } bool operator<(const T& r) const { return usec_ < r.usec_; } bool operator>(const T& r) const { return usec_ > r.usec_; } bool operator<=(const T& r) const { return usec_ <= r.usec_; } bool operator>=(const T& r) const { return usec_ >= r.usec_; } T operator+(const D& r) const { if (r.isNegative()) { if (uint64_t(r.getAbs().toUSec()) > usec_) { return fromUSec(0); } } else { if (uint64_t(usec_ + r.toUSec()) < usec_) { return fromUSec(std::numeric_limits::max()); } } return fromUSec(usec_ + r.toUSec()); } T operator-(const D& r) const { return *static_cast(this) + (-r); } D operator-(const T& r) const { return D::fromUSec((usec_ > r.usec_) ? (usec_ - r.usec_) : -(r.usec_ - usec_)); } T& operator+=(const D& r) { *this = *this + r; return *static_cast(this); } T& operator-=(const D& r) { *this = *this - r; return *static_cast(this); } enum { StringBufSize = 32 }; void toString(char buf[StringBufSize]) const; #if UAVCAN_TOSTRING std::string toString() const; #endif }; /* * Monotonic */ class UAVCAN_EXPORT MonotonicDuration : public DurationBase { }; class UAVCAN_EXPORT MonotonicTime : public TimeBase { }; /* * UTC */ class UAVCAN_EXPORT UtcDuration : public DurationBase { }; class UAVCAN_EXPORT UtcTime : public TimeBase { public: UtcTime() { } UtcTime(const Timestamp& ts) // Implicit { operator=(ts); } UtcTime& operator=(const Timestamp& ts) { *this = fromUSec(ts.husec * Timestamp::USEC_PER_LSB); return *this; } operator Timestamp() const { Timestamp ts; ts.husec = toUSec() / Timestamp::USEC_PER_LSB; return ts; } }; // ---------------------------------------------------------------------------- template void DurationBase::toString(char buf[StringBufSize]) const { using namespace std; // For snprintf() char* ptr = buf; if (isNegative()) { *ptr++ = '-'; } (void)snprintf(ptr, StringBufSize - 1, "%llu.%06lu", static_cast(std::abs(toUSec() / 1000000L)), static_cast(std::abs(toUSec() % 1000000L))); } template void TimeBase::toString(char buf[StringBufSize]) const { using namespace std; // For snprintf() (void)snprintf(buf, StringBufSize, "%llu.%06lu", static_cast(toUSec() / 1000000UL), static_cast(toUSec() % 1000000UL)); } #if UAVCAN_TOSTRING template std::string DurationBase::toString() const { char buf[StringBufSize]; toString(buf); return std::string(buf); } template std::string TimeBase::toString() const { char buf[StringBufSize]; toString(buf); return std::string(buf); } #endif template UAVCAN_EXPORT Stream& operator<<(Stream& s, DurationBase d) { char buf[DurationBase::StringBufSize]; d.toString(buf); s << buf; return s; } template UAVCAN_EXPORT Stream& operator<<(Stream& s, TimeBase t) { char buf[TimeBase::StringBufSize]; t.toString(buf); s << buf; return s; } }