Skip to content

Instantly share code, notes, and snippets.

@vmrob
Created October 28, 2018 07:10
Show Gist options
  • Save vmrob/514221d65a6f1bcf6c6a24d69e73354b to your computer and use it in GitHub Desktop.
Save vmrob/514221d65a6f1bcf6c6a24d69e73354b to your computer and use it in GitHub Desktop.
Simple distance/velocity header
// Public domain, do whatever you want.
#include <chrono>
#include <cstdint>
class Distance {
public:
constexpr double kilometers() const { return _meters * 1e-3; }
constexpr double meters() const { return _meters; }
constexpr double decimeters() const { return _meters * 1e1; }
constexpr double centimeters() const { return _meters * 1e2; }
constexpr double millimeters() const { return _meters * 1e3; }
constexpr double micrometers() const { return _meters * 1e6; }
constexpr double nanometers() const { return _meters * 1e9; }
friend constexpr Distance Kilometers(double value);
friend constexpr Distance Meters(double value);
friend constexpr Distance Decimeters(double value);
friend constexpr Distance Centimeters(double value);
friend constexpr Distance Millimeters(double value);
friend constexpr Distance Micrometers(double value);
friend constexpr Distance Nanometers(double value);
friend constexpr Distance operator+(Distance lhs, Distance rhs);
friend constexpr Distance operator-(Distance lhs, Distance rhs);
friend constexpr Distance operator*(Distance lhs, double rhs);
friend constexpr Distance operator/(Distance lhs, double rhs);
constexpr Distance& operator+=(Distance lhs) {
_meters += lhs._meters;
return *this;
}
constexpr Distance& operator-=(Distance lhs) {
_meters -= lhs._meters;
return *this;
}
constexpr Distance& operator*=(double lhs) {
_meters *= lhs;
return *this;
}
constexpr Distance& operator/=(double lhs) {
_meters /= lhs;
return *this;
}
private:
double _meters = 0.0;
constexpr explicit Distance(double nm) : _meters{nm} {}
};
constexpr Distance operator+(Distance lhs, Distance rhs) {
return Distance{lhs._meters + rhs._meters};
}
constexpr Distance operator-(Distance lhs, Distance rhs) {
return Distance{lhs._meters - rhs._meters};
}
constexpr Distance operator*(Distance lhs, double rhs) {
return Distance(lhs._meters * rhs);
}
constexpr Distance operator/(Distance lhs, double rhs) {
return Distance(lhs._meters / rhs);
}
#define DEFINE_DISTANCE_UNIT(func, magnitude, abbrev) \
constexpr Distance func##s(double value) { \
return Distance(value * magnitude); \
} \
\
constexpr Distance operator""_##abbrev(long double value) { \
return func##s(value); \
} \
\
constexpr Distance operator""_##abbrev(unsigned long long int value) { \
return func##s(value); \
}
DEFINE_DISTANCE_UNIT(Kilometer, 1e3, km);
DEFINE_DISTANCE_UNIT(Meter, 1e0, m);
DEFINE_DISTANCE_UNIT(Decimeter, 1e-1, dm);
DEFINE_DISTANCE_UNIT(Centimeter, 1e-2, cm);
DEFINE_DISTANCE_UNIT(Millimeter, 1e-3, mm);
DEFINE_DISTANCE_UNIT(Micrometer, 1e-6, um);
DEFINE_DISTANCE_UNIT(Nanometer, 1e-9, nm);
#undef DEFINE_DISTANCE_UNIT
#define DEFINE_TIME_UNIT(func, num, den, abbrev) \
constexpr std::chrono::duration<double, std::ratio<num, den>> func##s( \
double value) { \
return std::chrono::duration<double, std::ratio<num, den>>(value); \
} \
\
constexpr std::chrono::duration<double, std::ratio<num, den>> \
operator""_##abbrev(long double value) { \
return func##s(value); \
} \
\
constexpr std::chrono::duration<double, std::ratio<num, den>> \
operator""_##abbrev(unsigned long long int value) { \
return func##s(value); \
}
DEFINE_TIME_UNIT(Hour, 3600, 1, h);
DEFINE_TIME_UNIT(Minute, 60, 1, min);
DEFINE_TIME_UNIT(Second, 1, 1, s);
DEFINE_TIME_UNIT(Millisecond, 1, 1000, ms);
DEFINE_TIME_UNIT(Microsecond, 1, 1'000'000, us);
DEFINE_TIME_UNIT(Nanosecond, 1, 1'000'000'000, ns);
#undef DEFINE_TIME_UNIT
class Velocity {
private:
public:
template <typename Rep, typename Period>
constexpr double metersPer(std::chrono::duration<Rep, Period> dur) const {
using Seconds = std::chrono::duration<double>;
return _distPerSecond.meters()
/ std::chrono::duration_cast<Seconds>(dur).count();
}
template <typename Rep, typename Period>
constexpr double
kilometersPer(std::chrono::duration<Rep, Period> dur) const {
using Seconds = std::chrono::duration<double>;
return _distPerSecond.kilometers()
/ std::chrono::duration_cast<Seconds>(dur).count();
}
friend constexpr Velocity operator+(Velocity lhs, Velocity rhs);
friend constexpr Velocity operator-(Velocity lhs, Velocity rhs);
friend constexpr Velocity operator*(Velocity lhs, double rhs);
friend constexpr Velocity operator/(Velocity lhs, double rhs);
constexpr Velocity& operator+=(Velocity rhs) {
_distPerSecond += rhs._distPerSecond;
return *this;
}
constexpr Velocity& operator-=(Velocity rhs) {
_distPerSecond -= rhs._distPerSecond;
return *this;
}
constexpr Velocity& operator*=(double rhs) {
_distPerSecond *= rhs;
return *this;
}
constexpr Velocity& operator/=(double rhs) {
_distPerSecond /= rhs;
return *this;
}
template <typename Rep, typename Period>
friend Velocity constexpr
operator/(Distance lhs, std::chrono::duration<Rep, Period> dur);
private:
Distance _distPerSecond;
constexpr explicit Velocity(Distance distancePerSecond)
: _distPerSecond{distancePerSecond} {}
};
constexpr Velocity operator+(Velocity lhs, Velocity rhs) {
return Velocity{lhs._distPerSecond + rhs._distPerSecond};
}
constexpr Velocity operator-(Velocity lhs, Velocity rhs) {
return Velocity{lhs._distPerSecond - rhs._distPerSecond};
}
constexpr Velocity operator*(Velocity lhs, double rhs) {
return Velocity{lhs._distPerSecond * rhs};
}
constexpr Velocity operator/(Velocity lhs, double rhs) {
return Velocity{lhs._distPerSecond / rhs};
}
template <typename Rep, typename Period>
constexpr Velocity
operator/(Distance lhs, std::chrono::duration<Rep, Period> dur) {
using Seconds = std::chrono::duration<double>;
return Velocity{lhs / std::chrono::duration_cast<Seconds>(dur).count()};
}
// a few tests
using namespace std::chrono_literals;
static_assert(Meters(1).nanometers() == 1'000'000'000);
static_assert(Kilometers(1).nanometers() == 1'000'000'000'000);
static_assert(Millimeters(50).micrometers() == 50'000);
static_assert(Seconds(50) == std::chrono::seconds(50));
static_assert(Seconds(50) == 50_s);
static_assert(Milliseconds(50) == std::chrono::microseconds(50000));
static_assert(50_us == std::chrono::microseconds(50));
static_assert(50_us == 50us);
static_assert((Meters(1) / Seconds(1)).metersPer(Seconds(1)) == 1.0);
static_assert((1_m / 1_s).metersPer(1_s) == 1.0);
static_assert((Kilometers(1) / Seconds(1)).metersPer(Seconds(1)) == 1000.0);
static_assert((1_km / 1_s).metersPer(1_s) == 1000.0);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment