1+ #pragma once
2+
3+ #include " Unit.hpp"
4+
5+ namespace UnitGuard
6+ {
7+
8+ #if ! defined( DISABLE_UNITGUARD )
9+ template < typename T, typename U >
10+ class Quantity
11+ {
12+ public:
13+ T value;
14+ explicit Quantity ( T v ) : value(v) {}
15+
16+ // Convert to raw number
17+ operator T () const { return value; }
18+
19+ // For printing
20+ operator std::string () const
21+ {
22+ return std::to_string (value);
23+ }
24+
25+ template < typename _U >
26+ Quantity< T, U > & operator =( const Quantity< T, _U > & other )
27+ {
28+ static_assert ( are_same_units< U, _U >::value, " Cannot assign incompatible units" );
29+ value = other.value ;
30+ return *this ;
31+ }
32+
33+ template < typename _U >
34+ Quantity< T, U > & operator +=( const Quantity< T, _U > & other )
35+ {
36+ static_assert ( are_same_units< U, _U >::value, " Cannot add different units" );
37+ value += other.value ;
38+ return *this ;
39+ }
40+
41+ template < typename _U >
42+ Quantity< T, U > & operator -=( const Quantity< T, _U > & other )
43+ {
44+ static_assert ( are_same_units< U, U >::value, " Cannot subtract different units" );
45+ value -= other.value ;
46+ return *this ;
47+ }
48+
49+ Quantity< T, U > operator +( const Quantity & other ) const
50+ {
51+ return Quantity< T, U >( value + other.value );
52+ }
53+
54+ Quantity< T, U > operator -( const Quantity & other ) const
55+ {
56+ return Quantity< T, U >( value - other.value );
57+ }
58+
59+ // Multiply: results in new Unit with exponents added
60+ template < typename OU >
61+ auto operator *( const Quantity< T, OU > & other ) const
62+ {
63+ using ResultUnit = typename Multiply< U, OU >::type;
64+ return Quantity< T, ResultUnit >( value * other.value );
65+ }
66+
67+ // Divide: results in new Unit with exponents subtracted
68+ template < typename OU >
69+ auto operator /( const Quantity< T, OU > & other ) const
70+ {
71+ using ResultUnit = typename Divide< U, OU >::type;
72+ return Quantity< T, ResultUnit >( value / other.value );
73+ }
74+ };
75+ #else
76+ template < typename T, typename >
77+ using Quantity = T;
78+ #endif
79+
80+ // --------------------------------------------
81+ // Fundamental tags for all atomic dimensions:
82+ struct MassTag : public AtomTag {};
83+ struct LengthTag : public AtomTag {};
84+ struct TimeTag : public AtomTag {};
85+ struct CurrentTag : public AtomTag {}; // e.g. electrice current
86+ struct TemperatureTag : public AtomTag {};
87+ struct AmmountTag : public AtomTag {}; // e.g. moles
88+ struct LuminanceTag : public AtomTag {}; // e.g. candelas
89+
90+
91+ // Establish canonical ordering
92+ template < >
93+ struct CanonicalOrder < MassTag >
94+ {
95+ static constexpr int value = 0 ;
96+ };
97+
98+ template < >
99+ struct CanonicalOrder < LengthTag >
100+ {
101+ static constexpr int value = 1 ;
102+ };
103+
104+ template < >
105+ struct CanonicalOrder < TimeTag >
106+ {
107+ static constexpr int value = 2 ;
108+ };
109+
110+ template < >
111+ struct CanonicalOrder < CurrentTag >
112+ {
113+ static constexpr int value = 3 ;
114+ };
115+
116+
117+ template < >
118+ struct CanonicalOrder < TemperatureTag >
119+ {
120+ static constexpr int value = 4 ;
121+ };
122+
123+ template < >
124+ struct CanonicalOrder < AmmountTag >
125+ {
126+ static constexpr int value = 5 ;
127+ };
128+
129+ template < >
130+ struct CanonicalOrder < LuminanceTag >
131+ {
132+ static constexpr int value = 6 ;
133+ };
134+
135+ // --------------------------------------------
136+ // Dimensionless (no base units at all):
137+ using Dimensionless = Unit<>;
138+
139+ // --------------------------------------------
140+ // Single-base (fundamental) units:
141+ using MassDimension = Unit<Power<MassTag, 1 >>;
142+ using LengthDimension = Unit<Power<LengthTag, 1 >>;
143+ using TimeDimension = Unit<Power<TimeTag, 1 >>;
144+ using CurrentDimension = Unit<Power<CurrentTag, 1 >>;
145+ using TemperatureDimension = Unit<Power<TemperatureTag, 1 >>;
146+ using AmmountDimension = Unit<Power<AmmountTag, 1 >>;
147+ using LuminanceDimension = Unit<Power<LuminanceTag, 1 >>;
148+
149+ // --------------------------------------------
150+ // Derived units:
151+
152+ // Frequency = Time^-1
153+ using FrequencyDimension = Unit< Power< TimeTag, -1 > >;
154+
155+ // Area = Length^2
156+ using AreaDimension = Unit< Power< LengthTag, 2 > >;
157+
158+ // Volume = Length^3
159+ using VolumeDimension = Unit< Power< LengthTag, 3 > >;
160+
161+ // Velocity = Length^1 * Time^-1
162+ using VelocityDimension = Unit<
163+ Power< LengthTag, 1 >,
164+ Power< TimeTag, -1 >
165+ >;
166+
167+ // Acceleration = Length^1 * Time^-2
168+ using AccelerationDimension = Unit<
169+ Power< LengthTag, 1 >,
170+ Power< TimeTag, -2 >
171+ >;
172+
173+ // Momentum = Mass^1 * Length^1 * Time^-1
174+ using MomentumDimension = Unit<
175+ Power< MassTag, 1 >,
176+ Power< LengthTag, 1 >,
177+ Power< TimeTag, -1 >
178+ >;
179+
180+ // Force = Mass^1 * Length^1 * Time^-2
181+ using ForceDimension = Unit<
182+ Power< MassTag, 1 >,
183+ Power< LengthTag, 1 >,
184+ Power< TimeTag, -2 >
185+ >;
186+
187+ // Pressure = Force / Area = Mass^1 * Length^-1 * Time^-2
188+ using PressureDimension = Unit<
189+ Power< MassTag, 1 >,
190+ Power< LengthTag, -1 >,
191+ Power< TimeTag, -2 >
192+ >;
193+
194+ // Energy = Force * Distance = Mass^1 * Length^2 * Time^-2
195+ using EnergyDimension = Unit<
196+ Power< MassTag, 1 >,
197+ Power< LengthTag, 2 >,
198+ Power< TimeTag, -2 >
199+ >;
200+
201+ // Power = Energy / Time = Mass^1 * Length^2 * Time^-3
202+ using PowerDimension = Unit<
203+ Power< MassTag, 1 >,
204+ Power< LengthTag, 2 >,
205+ Power< TimeTag, -3 >
206+ >;
207+
208+ // --------------------------------------------
209+ // thermodynamic-derived
210+
211+ // Entropy = Energy / Temperature = Mass^1 * Length^2 * Time^-2 * Temperature^-1
212+ using EntropyDimension = Unit<
213+ Power< MassTag, 1 >,
214+ Power< LengthTag, 2 >,
215+ Power< TimeTag, -2 >,
216+ Power< TemperatureTag, -1 >
217+ >;
218+
219+ // HeatCapacity = Energy / Temperature (identical to Entropy dimensionally)
220+ using HeatCapacityDimension = EntropyDimension;
221+
222+ // ----------------------------------------------------------------------------
223+
224+ template < typename T > using Length = Quantity< T, LengthDimension >;
225+ template < typename T > using Mass = Quantity< T, MassDimension >;
226+ template < typename T > using Time = Quantity< T, TimeDimension >;
227+ template < typename T > using Temp = Quantity< T, TemperatureDimension >;
228+
229+ // Derived:
230+ template < typename T > using Frequency = Quantity< T, FrequencyDimension >;
231+ template < typename T > using Area = Quantity< T, AreaDimension >;
232+ template < typename T > using Volume = Quantity< T, VolumeDimension >;
233+ template < typename T > using Velocity = Quantity< T, VelocityDimension >;
234+ template < typename T > using Force = Quantity< T, ForceDimension >;
235+ template < typename T > using Pressure = Quantity< T, PressureDimension >;
236+ template < typename T > using Energy = Quantity< T, EnergyDimension >;
237+ template < typename T > using Entropy = Quantity< T, EntropyDimension >;
238+
239+ // Optionally also define dimensionless (which is sometimes handy):
240+ template < typename T > using Scalar = Quantity< T, Dimensionless >;
241+
242+ }
0 commit comments