Skip to content

Instantly share code, notes, and snippets.

@unvBell
Last active August 29, 2015 14:26
Show Gist options
  • Save unvBell/6d21b854cf719d64ab06 to your computer and use it in GitHub Desktop.
Save unvBell/6d21b854cf719d64ab06 to your computer and use it in GitHub Desktop.
UnitType
#include <iostream>
#include <gtest/gtest.h>
#include "Unit.hpp"
using namespace bell::unit;
namespace {
template <typename T> using Number = Unit<T, 0, 0, 0>;
template <typename T> using Length = Unit<T, 1, 0, 0>;
template <typename T> using Mass = Unit<T, 0, 1, 0>;
template <typename T> using Time = Unit<T, 0, 0, 1>;
template <typename T> using Velocity = decltype(Length <T>{} / Time <T>{});
template <typename T> using Acceleration = decltype(Velocity <T>{} / Time <T>{});
template <typename T> using Momentum = decltype(Velocity <T>{} * Mass <T>{});
template <typename T> using Force = decltype(Acceleration <T>{} * Mass <T>{});
template <typename T> using Energy = decltype(Length <T>{} * Force <T>{});
template <typename T> using Area = decltype(Length <T>{} * Length <T>{});
template <typename T> using Volume = decltype(Area <T>{} * Length <T>{});
template <typename T> using Density = decltype(Mass <T>{} / Volume <T>{});
template <typename T> using Frequency = decltype(1. / Time<T>{});
constexpr Length<double> operator""_m (long double v) noexcept { return { static_cast<double>(v) }; }
constexpr Mass <double> operator""_kg (long double v) noexcept { return { static_cast<double>(v) }; }
constexpr Time <double> operator""_sec (long double v) noexcept { return { static_cast<double>(v) }; }
}
TEST(Bell_Unit, Unit) {
using namespace std;
constexpr Acceleration <double> gravity = 9.8;
constexpr Length <double> height = 3._m + 2._m;
constexpr Mass <double> mass = 3._kg;
constexpr Energy <double> potential = mass * gravity * height;
constexpr Time <double> duration = 2._sec;
constexpr Velocity <double> velocity = gravity * duration;
constexpr Length <double> position = 1./2 * gravity * duration*duration;
constexpr Momentum <double> momentum = velocity * mass;
constexpr Energy <double> kinetic = 1./2 * mass * velocity*velocity;
constexpr Energy <double> mechanical = potential + kinetic;
static_assert(gravity == 9.8 , "");
static_assert(height == 5.0 , "");
static_assert(mass == 3.0 , "");
static_assert(potential == 3.0*9.8*5.0 , "");
static_assert(duration == 2.0 , "");
static_assert(velocity == 9.8*2.0 , "");
static_assert(position == 9.8*2.0*2.0/2 , "");
static_assert(kinetic == 3.0*9.8*9.8*2.0*2.0/2, "");
static_assert(mechanical == potential.get() + kinetic.get(), "");
cout << endl;
cout << "gravity : " << gravity << endl;
cout << "height : " << height << endl;
cout << "mass : " << mass << endl;
cout << "potention energy : " << potential << endl;
cout << endl;
cout << "duration : " << duration << endl;
cout << "velocity : " << velocity << endl;
cout << "position : " << position << endl;
cout << "momentum : " << momentum << endl;
cout << "kinetic energy : " << kinetic << endl;
cout << endl;
}
#pragma once
#include <ostream>
namespace bell { namespace unit {
/**
* 単位
*/
template <typename Val, int L, int M, int T>
class Unit final {
Val val_;
public:
using ValueType = Val;
static constexpr int lengthDimension = L;
static constexpr int massDimension = M;
static constexpr int timeDimension = T;
// コンストラクタ
constexpr Unit() noexcept : val_() {}
constexpr Unit(const Val& val) noexcept : val_(val) {}
// 演算子
constexpr Unit operator+() const noexcept { return +val; }
constexpr Unit operator-() const noexcept { return -val; }
Unit& operator++() noexcept { ++val_; return *this; }
Unit& operator--() noexcept { --val_; return *this; }
Unit operator++(int) noexcept { Val v = val_++; return v; }
Unit operator--(int) noexcept { Val v = val_--; return v; };
constexpr auto operator+(const Unit& a) const noexcept -> Unit<decltype(val_+a.val_),L,M,T> { return val_+a.val_; }
constexpr auto operator-(const Unit& a) const noexcept -> Unit<decltype(val_-a.val_),L,M,T> { return val_-a.val_; }
template <typename U> constexpr auto operator*(const U& a) const noexcept -> Unit<decltype(val_*a),L,M,T> { return val_*a; }
template <typename U> constexpr auto operator/(const U& a) const noexcept -> Unit<decltype(val_/a),L,M,T> { return val_/a; }
template <typename U, int L_, int M_, int T_> constexpr auto operator*(const Unit<U,L_,M_,T_>& a) const noexcept -> Unit<decltype(val_*a.get()),L+L_,M+M_,T+T_> { return val_*a.get(); }
template <typename U, int L_, int M_, int T_> constexpr auto operator/(const Unit<U,L_,M_,T_>& a) const noexcept -> Unit<decltype(val_/a.get()),L-L_,M-M_,T-T_> { return val_/a.get(); }
template <typename U> friend constexpr auto operator*(const U& a, const Unit& b) noexcept -> Unit<decltype(a*b.val_), L, M, T> { return a*b.val_; }
template <typename U> friend constexpr auto operator/(const U& a, const Unit& b) noexcept -> Unit<decltype(a/b.val_),-L,-M,-T> { return a/b.val_; }
Unit& operator+=(const Unit& a) noexcept { return *this = *this+a; }
Unit& operator-=(const Unit& a) noexcept { return *this = *this-a; }
Unit& operator*=(const Unit<Val, 0, 0, 0>& a) noexcept { return *this = *this*a; }
Unit& operator/=(const Unit<Val, 0, 0, 0>& a) noexcept { return *this = *this/a; }
Unit& operator*=(const Val& a) noexcept { return *this = *this*a; }
Unit& operator/=(const Val& a) noexcept { return *this = *this/a; }
constexpr bool operator< (const Unit<Val, L, M, T>& a) const noexcept { return val_ < a.val_; }
constexpr bool operator<=(const Unit<Val, L, M, T>& a) const noexcept { return val_ <= a.val_; }
constexpr bool operator> (const Unit<Val, L, M, T>& a) const noexcept { return val_ > a.val_; }
constexpr bool operator>=(const Unit<Val, L, M, T>& a) const noexcept { return val_ >= a.val_; }
constexpr bool operator==(const Unit<Val, L, M, T>& a) const noexcept { return val_ == a.val_; }
constexpr bool operator!=(const Unit<Val, L, M, T>& a) const noexcept { return val_ != a.val_; }
constexpr explicit operator bool() const noexcept {
return !!val_;
}
constexpr Val* operator->() const noexcept {
return &val_;
}
template <typename Ch, typename Traits>
friend std::basic_ostream<Ch, Traits>& operator<<(std::basic_ostream<Ch, Traits>& os, const Unit& a) noexcept {
os << a.val_;
if(M) {
if(M < 0) os << Ch{'/'};
os << Ch{'k'} << Ch{'g'};
if(abs(M) != 1) os << Ch{'^'} << abs(M);
}
if(L) {
if(L < 0) os << Ch{'/'};
else if(M) os << Ch{'*'};
os << Ch{'m'};
if(abs(L) != 1) os << Ch{'^'} << abs(L);
}
if(T) {
if(T < 0) os << Ch{'/'};
else if(M || L) os << Ch{'*'};
os << Ch{'s'};
if(abs(T) != 1) os << Ch{'^'} << abs(T);
}
return os;
}
/**
* 値の取得
* @return 現在保持している値
*/
constexpr Val get() const noexcept {
return val_;
}
/**
* 値の設定
* @param val 設定する値
* @return this参照
*/
Unit& set(const Val& val) noexcept {
val_ = val;
return *this;
}
};
}}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment