Quantify
An extensible C++ units library
Loading...
Searching...
No Matches
quantity.cppm
Go to the documentation of this file.
1// Copyright (c) 2024-2025, Víctor Castillo Agüero.
2// SPDX-License-Identifier: Apache-2.0
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16module;
17
19#define R(...) reduce<__VA_ARGS__>
20
21export module quantify.core:quantity;
22import std;
23import :preface;
24import :concepts;
25export import :frac;
26export import :mul;
27
28export namespace quantify {
29 template<typename U, typename T>
30 struct quantity {
31 using unit = U;
32 using data_type = T;
33
34 T value { };
35
37 return value * U::template factor<T>::numerator / U::template factor<T>::denominator;
38 }
39
40 template<typename U1>
41 requires SameScale<U, U1>
42 auto operator<=>(const quantity<U1, T>& rhl) const {
43 return this->value <=> rhl.template as<U>().value;
44 }
45
46 template<typename U1>
47 requires SameScale<U, U1>
48 bool operator<(const quantity<U1, T>& rhl) const {
49 return this->value < rhl.template as<U>().value;
50 }
51
52 template<typename U1>
53 requires SameScale<U, U1>
54 bool operator==(const quantity<U1, T>& rhl) const {
55 return this->value == rhl.template as<U>().value;
56 }
57
58 template<typename T1>
59 requires (not QuantityConcept<T1>)
60 auto operator<=>(const T1& rhl) const {
61 return this->value <=> rhl;
62 }
63
64 template<typename T1>
65 requires (not QuantityConcept<T1>)
66 bool operator<(const T1& rhl) const {
67 return this->value < rhl;
68 }
69
70 template<typename T1>
71 requires (not QuantityConcept<T1>)
72 bool operator==(const T1& rhl) const {
73 return this->value == rhl;
74 }
75
76 template<typename U1>
77 requires SameScale<U, U1>
78 quantity<R(frac<R(U), R(U)>), T> operator/(const quantity<U1, T> &rhl) const {
79 return {this->value / rhl.template as<R(U)>().value};
80 }
81
82 template<typename U1>
83 requires (!SameScale<U, U1>)
84 quantity<R(frac<R(U), R(U1)>), T> operator/(const quantity<U1, T> &rhl) const {
85 return {this->value / rhl.value};
86 }
87
88 template<typename T1>
89 requires (not QuantityConcept<T1>)
90 quantity<R(U), T> operator/(const T1& rhl) const {
91 return {this->value / rhl};
92 }
93
94 template<typename U1>
95 requires SameScale<U, U1>
96 quantity<R(mul<R(U), R(U)>), T> operator*(const quantity<U1, T> &rhl) const {
97 return {this->value * rhl.template as<R(U)>().value};
98 }
99
100 template<typename U1>
101 requires (!SameScale<U, U1>)
102 quantity<R(mul<R(U), R(U1)>), T> operator*(const quantity<U1, T> &rhl) const {
103 return {this->value * rhl.value};
104 }
105
106 template<typename T1>
107 requires (not QuantityConcept<T1>)
108 quantity<R(U), T> operator*(const T1& rhl) const {
109 return {this->value * rhl};
110 }
111
112 template<typename U1, typename T1>
113 requires (SameScale<U, U1>)
114 quantity<R(U), T1> operator+(const quantity<U1, T1> &rhl) const {
115 return {this->value + rhl.template as<R(U)>().value};
116 }
117
118 template<typename U1, typename T1>
119 requires (SameScale<U, U1>)
120 quantity<R(U), T1>& operator+=(const quantity<U1, T1> &rhl) {
121 this->value += rhl.template as<R(U)>().value;
122 return *this;
123 }
124
125 template<typename U1, typename T1>
126 requires (SameScale<U, U1>)
127 quantity<R(U), T1> operator-(const quantity<U1, T1> &rhl) const {
128 return {this->value - rhl.template as<R(U)>().value};
129 }
130
131 template<typename U1, typename T1>
132 requires (SameScale<U, U1>)
133 quantity<R(U), T1>& operator-=(const quantity<U1, T1> &rhl) {
134 this->value -= rhl.template as<R(U)>().value;
135 return *this;
136 }
137
139 return {-(this->value)};
140 }
141
142 constexpr quantity() = default;
143
144 constexpr quantity(T value_): value(value_) {
145 }
146
148 template <typename T1>
149 quantity(const quantity<U,T1> &other) {
150 this->value = other.value;
151 }
152
154 template <typename U1, typename T1>
155 requires(
156 not std::same_as<R(U), R(U1)> &&
159 )
161 this->value = other.template as<U>().value;
162 }
163
165 template <typename T1>
167 this->value = rhl.value;
168 return *this;
169 }
170
172 template <typename U1, typename T1>
173 requires(
174 not std::same_as<R(U), R(U1)> &&
177 )
179 this->value = rhl.template as<U>().value;
180 return *this;
181 }
182
184 template <typename T1>
185 quantity(quantity<U,T1> &&other) noexcept {
186 this->value = other.value;
187 }
188
190 template <typename U1, typename T1>
191 requires(
192 not std::same_as<R(U), R(U1)> &&
195 )
197 this->value = other.template as<U>().value;
198 }
199
201 template <typename T1>
203 this->value = rhl.value;
204 return *this;
205 }
206
208 template <typename U1, typename T1>
209 requires(
210 not std::same_as<R(U), R(U1)> &&
213 )
215 this->value = rhl.template as<U>().value;
216 return *this;
217 }
218
219
220 template<typename U1>
222 [[nodiscard]]
223 constexpr quantity<U1, T> as() const {
224 if constexpr (std::is_same_v<U, U1>) {
225 return *this;
226 } else if constexpr (SameScale<U, U1>) {
227 return quantity<U1, T> {
228 this->value
229 * (U1::template factor<T>::denominator
230 * U::template factor<T>::numerator)
231 / (U1::template factor<T>::numerator
232 * U::template factor<T>::denominator)
233 };
234 // } else if constexpr (requires { scale_conversion_t<typename U::scale, typename U1::scale>::template forward<U, U1, T>(*this); }) {
235 // return scale_conversion_t<typename U::scale, typename U1::scale>::template forward<U, U1, T>(*this);
236 // } else if constexpr (requires { scale_conversion_t<typename U1::scale, typename U::scale>::template backward<U, U1, T>(*this); }) {
237 // return scale_conversion_t<typename U1::scale, typename U::scale>::template backward<U, U1, T>(*this);
238 } else if constexpr (requires { scale_conversion_t<typename U::scale, typename U1::scale>{}; }) {
240 } else if constexpr (requires { scale_conversion_t<typename U1::scale, typename U::scale>{}; }) {
242 } else if constexpr (requires { unit_conversion_t<U, U1, T>::factor; }) {
244 } else if constexpr (requires { unit_conversion_t<U1, U, T>::factor; }) {
246 } else {
247 static_assert(false, "No conversion factor available between these units.");
248 return {0};
249 }
250 }
251
252 [[nodiscard]]
253 inline std::string to_string() const noexcept {
254 std::string str { };
255 str.append(std::to_string(value));
256 str.append(" [");
257 str.append(U::symbol());
258 str.append(":");
259 str.append(typeid(T).name());
260 str.append("]");
261 return str;
262 }
263 };
264
265 template <QuantityConcept Q, typename T1>
266 requires(not QuantityConcept<T1>)
267 Q operator/(const T1& lhs, const Q& rhs) {
268 return {lhs / rhs->value};
269 }
270
271 template <QuantityConcept Q, typename T1>
272 requires(not QuantityConcept<T1>)
273 Q operator*(const T1& lhs, const Q& rhs) {
274 return rhs * lhs;
275 }
276
277 template<typename U, typename T>
279}
280
281export template<typename U, typename T>
282std::ostream &operator<<(std::ostream &o, const quantify::quantity<U, T> &quantity) {
283 o << quantity.to_string();
284 return o;
285}
Predicate that checks if a type is a quantity regardless of its unit.
Core components of the Quantify library.
quantity< U, T > Q
#define R(...)
Syntax sugar - Apply reduce.
Definition quantity.cppm:19
std::ostream & operator<<(std::ostream &o, const quantify::quantity< U, T > &quantity)
quantity< R(U), T > operator/(const T1 &rhl) const
Definition quantity.cppm:90
quantity(quantity< U1, T1 > &&other)
Move.
quantity & operator=(quantity< U1, T1 > &&rhl)
Move.
quantity< R(mul< R(U), R(U1)>), T > operator*(const quantity< U1, T > &rhl) const
quantity(const quantity< U, T1 > &other)
Copy.
quantity & operator=(const quantity< U, T1 > &rhl)
Copy.
bool operator==(const quantity< U1, T > &rhl) const
Definition quantity.cppm:54
quantity< R(frac< R(U), R(U)>), T > operator/(const quantity< U1, T > &rhl) const
Definition quantity.cppm:78
quantity< R(U), T1 > operator-(const quantity< U1, T1 > &rhl) const
quantity(const quantity< U1, T1 > &other)
Copy.
quantity & operator=(const quantity< U1, T1 > &rhl)
Copy.
std::string to_string() const noexcept
quantity< R(U), T > operator*(const T1 &rhl) const
quantity< R(mul< R(U), R(U)>), T > operator*(const quantity< U1, T > &rhl) const
Definition quantity.cppm:96
auto operator<=>(const quantity< U1, T > &rhl) const
Definition quantity.cppm:42
quantity< R(frac< R(U), R(U1)>), T > operator/(const quantity< U1, T > &rhl) const
Definition quantity.cppm:84
constexpr quantity(T value_)
quantity< R(U), T1 > operator+(const quantity< U1, T1 > &rhl) const
constexpr quantity()=default
quantity & operator=(quantity< U, T1 > &&rhl) noexcept
Move.
quantity< R(U), T1 > & operator-=(const quantity< U1, T1 > &rhl)
quantity(quantity< U, T1 > &&other) noexcept
Move.
bool operator<(const quantity< U1, T > &rhl) const
Definition quantity.cppm:48
T value_as_base_unit() const
Definition quantity.cppm:36
constexpr quantity< U1, T > as() const
quantity< U, T > operator-() const
quantity< R(U), T1 > & operator+=(const quantity< U1, T1 > &rhl)