File indexing completed on 2026-11-06 10:15:19
0001
0002
0003
0004
0005
0006
0007 #pragma once
0008
0009 #include <type_traits>
0010
0011 #include "corecel/Macros.hh"
0012 #include "corecel/Types.hh"
0013 #include "corecel/data/Ldg.hh"
0014
0015 #include "detail/QuantityImpl.hh"
0016
0017 #if !CELER_DEVICE_COMPILE
0018 # include <ostream>
0019 #endif
0020
0021 namespace celeritas
0022 {
0023 class Constant;
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089 template<class UnitT, class ValueT>
0090 class Quantity
0091 {
0092 static_assert(std::is_arithmetic_v<ValueT>,
0093 "value type must be arithmetic");
0094 static_assert(std::is_arithmetic_v<decltype(UnitT::value())>
0095 || std::is_same_v<decltype(UnitT::value()), Constant>,
0096 "unit value type must be arithmetic or constant");
0097
0098 public:
0099
0100
0101 using value_type = ValueT;
0102 using unit_type = UnitT;
0103 using unit_value_type = decltype(UnitT::value());
0104 using common_type = decltype(std::declval<value_type>()
0105 * std::declval<unit_value_type>());
0106
0107
0108 public:
0109
0110 constexpr Quantity() = default;
0111
0112
0113 explicit CELER_CONSTEXPR_FUNCTION Quantity(value_type value) noexcept
0114 : value_(value)
0115 {
0116 }
0117
0118
0119 template<detail::QConstant QC>
0120 CELER_CONSTEXPR_FUNCTION Quantity(detail::UnitlessQuantity<QC>) noexcept
0121 : value_(detail::get_constant<ValueT>(QC))
0122 {
0123 }
0124
0125
0126 template<class ValueT2,
0127 std::enable_if_t<!std::is_same_v<ValueT, ValueT2>
0128 && std::is_convertible_v<ValueT2, ValueT>,
0129 bool> = true>
0130 CELER_CONSTEXPR_FUNCTION Quantity(Quantity<UnitT, ValueT2> other) noexcept
0131 : value_(static_cast<ValueT>(other.value()))
0132 {
0133 }
0134
0135
0136
0137 CELER_CONSTEXPR_FUNCTION value_type& value() & noexcept { return value_; }
0138 CELER_CONSTEXPR_FUNCTION value_type const& value() const& noexcept
0139 {
0140 return value_;
0141 }
0142
0143
0144
0145 CELER_CONSTEXPR_FUNCTION value_type const* data() const { return &value_; }
0146
0147
0148
0149 #define CELER_DEFINE_QUANTITY_CMP(TOKEN) \
0150 template<class T2> \
0151 CELER_CONSTEXPR_FUNCTION friend bool operator TOKEN( \
0152 Quantity lhs, Quantity<UnitT, T2> rhs) noexcept \
0153 { \
0154 return lhs.value() TOKEN rhs.value(); \
0155 } \
0156 template<detail::QConstant QC> \
0157 CELER_CONSTEXPR_FUNCTION friend bool operator TOKEN( \
0158 Quantity lhs, detail::UnitlessQuantity<QC>) noexcept \
0159 { \
0160 return lhs.value() TOKEN detail::get_constant<ValueT>(QC); \
0161 } \
0162 template<detail::QConstant QC> \
0163 CELER_CONSTEXPR_FUNCTION friend bool operator TOKEN( \
0164 detail::UnitlessQuantity<QC>, Quantity rhs) noexcept \
0165 { \
0166 return detail::get_constant<ValueT>(QC) TOKEN rhs.value(); \
0167 }
0168
0169
0170
0171 CELER_DEFINE_QUANTITY_CMP(==)
0172 CELER_DEFINE_QUANTITY_CMP(!=)
0173 CELER_DEFINE_QUANTITY_CMP(<)
0174 CELER_DEFINE_QUANTITY_CMP(>)
0175 CELER_DEFINE_QUANTITY_CMP(<=)
0176 CELER_DEFINE_QUANTITY_CMP(>=)
0177
0178
0179 #undef CELER_DEFINE_QUANTITY_CMP
0180
0181 private:
0182 template<class T2>
0183 using OtherQuantity = Quantity<UnitT, std::common_type_t<ValueT, T2>>;
0184
0185 public:
0186
0187
0188
0189
0190
0191 template<class T2>
0192 CELER_CONSTEXPR_FUNCTION friend auto operator*(Quantity lhs,
0193 T2 rhs) noexcept
0194 {
0195 return OtherQuantity<T2>{lhs.value() * rhs};
0196 }
0197
0198 template<class T2>
0199 CELER_CONSTEXPR_FUNCTION friend auto operator*(T2 lhs,
0200 Quantity rhs) noexcept
0201 {
0202 return OtherQuantity<T2>{lhs * rhs.value()};
0203 }
0204
0205 template<class T2>
0206 CELER_CONSTEXPR_FUNCTION friend auto operator/(Quantity lhs,
0207 T2 rhs) noexcept
0208 {
0209 return OtherQuantity<T2>{lhs.value() / rhs};
0210 }
0211
0212
0213
0214
0215
0216 template<class T2>
0217 CELER_CONSTEXPR_FUNCTION friend auto operator+(
0218 Quantity lhs, Quantity<UnitT, T2> rhs) noexcept
0219 {
0220 return OtherQuantity<T2>{lhs.value() + rhs.value()};
0221 }
0222
0223 template<class T2>
0224 CELER_CONSTEXPR_FUNCTION friend auto operator-(
0225 Quantity lhs, Quantity<UnitT, T2> rhs) noexcept
0226 {
0227 return OtherQuantity<T2>{lhs.value() - rhs.value()};
0228 }
0229
0230 template<class T2>
0231 CELER_CONSTEXPR_FUNCTION friend auto operator/(
0232 Quantity lhs, Quantity<UnitT, T2> rhs) noexcept
0233 {
0234 return lhs.value() / rhs.value();
0235 }
0236
0237
0238
0239 CELER_CONSTEXPR_FUNCTION friend auto operator-(Quantity q) noexcept
0240 {
0241 return Quantity{-q.value()};
0242 }
0243
0244
0245 CELER_CONSTEXPR_FUNCTION friend Quantity ldg(Quantity const* q) noexcept
0246 {
0247 return Quantity{ldg(&q->value_)};
0248 }
0249
0250 private:
0251 value_type value_{};
0252 };
0253
0254
0255
0256 template<class UnitT>
0257 using RealQuantity = Quantity<UnitT, real_type>;
0258
0259
0260 template<class U, class V>
0261 struct IsAutoLdg<Quantity<U, V>> : std::true_type
0262 {
0263 };
0264
0265
0266
0267
0268
0269
0270
0271
0272
0273 CELER_CONSTEXPR_FUNCTION auto zero_quantity() noexcept
0274 {
0275 return detail::UnitlessQuantity<detail::QConstant::zero>{};
0276 }
0277
0278
0279
0280
0281
0282 CELER_CONSTEXPR_FUNCTION auto max_quantity() noexcept
0283 {
0284 return detail::UnitlessQuantity<detail::QConstant::max>{};
0285 }
0286
0287
0288
0289
0290
0291 CELER_CONSTEXPR_FUNCTION auto neg_max_quantity() noexcept
0292 {
0293 return detail::UnitlessQuantity<detail::QConstant::neg_max>{};
0294 }
0295
0296
0297
0298
0299
0300 template<class U, class V>
0301 CELER_CONSTEXPR_FUNCTION void swap(Quantity<U, V>& a,
0302 Quantity<U, V>& b) noexcept
0303 {
0304 Quantity<U, V> tmp{a};
0305 a = b;
0306 b = tmp;
0307 }
0308
0309
0310
0311
0312
0313
0314
0315
0316
0317
0318 template<class UnitT, class ValueT>
0319 CELER_CONSTEXPR_FUNCTION auto native_value_from(
0320 Quantity<UnitT, ValueT> quant) noexcept
0321 {
0322 using common_type = typename Quantity<UnitT, ValueT>::common_type;
0323 return static_cast<common_type>(quant.value())
0324 * static_cast<common_type>(UnitT::value());
0325 }
0326
0327
0328
0329
0330
0331
0332
0333
0334
0335
0336
0337 template<class Q, class T>
0338 CELER_CONSTEXPR_FUNCTION Q native_value_to(T value) noexcept
0339 {
0340 using common_type = typename Q::common_type;
0341 using value_type = typename Q::value_type;
0342 constexpr auto unit_value = Q::unit_type::value();
0343 return Q{
0344 static_cast<value_type>(value / static_cast<common_type>(unit_value))};
0345 }
0346
0347
0348
0349
0350
0351
0352
0353
0354
0355
0356
0357
0358 template<class Q, class SrcUnitT, class ValueT>
0359 CELER_CONSTEXPR_FUNCTION auto value_as(
0360 Quantity<SrcUnitT, ValueT> quant) noexcept -> ValueT
0361 {
0362 static_assert(std::is_same<Q, Quantity<SrcUnitT, ValueT>>::value,
0363 "quantity units do not match");
0364 return quant.value();
0365 }
0366
0367
0368
0369
0370
0371
0372
0373
0374
0375
0376 template<class T>
0377 inline char const* accessor_unit_label()
0378 {
0379 return detail::AccessorResultType<T>::unit_type::label();
0380 }
0381
0382 #if !CELER_DEVICE_COMPILE
0383
0384
0385
0386
0387 template<class UnitT, class ValueT>
0388 std::ostream& operator<<(std::ostream& os, Quantity<UnitT, ValueT> const& q)
0389 {
0390 static_assert(sizeof(UnitT::label()) > 0,
0391 "Unit does not have a 'label' definition");
0392 os << q.value() << " [" << UnitT::label() << ']';
0393 return os;
0394 }
0395
0396 #endif
0397
0398
0399
0400 template<class T>
0401 inline constexpr bool is_quantity_v = detail::IsQuantity<T>::value;
0402
0403
0404 }