Skip to content

Commit

Permalink
Merge pull request #484 from mpusz/mpusz/issue477
Browse files Browse the repository at this point in the history
Renaming of accessor functions
  • Loading branch information
mpusz authored Sep 18, 2023
2 parents 2834c57 + b76337d commit becca90
Show file tree
Hide file tree
Showing 31 changed files with 705 additions and 573 deletions.
4 changes: 2 additions & 2 deletions docs/users_guide/framework_basics/generic_interfaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,11 @@ some issues start to be clearly visible:
Trying to use an integral type in this scenario will work only for `s1`, while `s2` and `s3`
will fail to compile. Failing to compile is a good thing here as the library tries to prevent
the user from doing a clearly wrong thing. To make the code compile, the user needs to use
a dedicated [`value_cast`](value_conversions.md#value-truncating-conversions) like this:
dedicated [`value_cast` or `force_in`](value_conversions.md#value-truncating-conversions) like this:

```cpp
quantity<isq::speed[mi / h]> s2 = avg_speed(value_cast<km>(140 * mi), 2 * h);
quantity<isq::speed[m / s]> s3 = avg_speed(value_cast<km>(20 * m), value_cast<h>(2 * s));
quantity<isq::speed[m / s]> s3 = avg_speed((20 * m).force_in(km), (2 * s).force_in(h));
```

but the above will obviously provide an incorrect behavior (i.e. division by `0` in the evaluation
Expand Down
4 changes: 2 additions & 2 deletions docs/users_guide/framework_basics/text_output.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ associated with this quantity.
before passing it to the text output:
```cpp
std::cout << v1.in(km / h) << '\n'; // 110 km/h
std::cout << value_cast<m / s>(v1) << '\n'; // 30.5556 m/s
std::cout << v1.in(km / h) << '\n'; // 110 km/h
std::cout << v1.force_in(m / s) << '\n'; // 30.5556 m/s
```


Expand Down
8 changes: 7 additions & 1 deletion docs/users_guide/framework_basics/value_conversions.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,18 @@ The second solution is to force a truncating conversion:
```cpp
auto q1 = 5 * m;
std::cout << value_cast<km>(q1) << '\n';
quantity<si::kilo<si::metre>, int> q2 = value_cast<km>(q1);
quantity<si::kilo<si::metre>, int> q2 = q1.force_in(km);
```

This explicit cast makes it clear that something unsafe is going on. It is easy to spot in code
reviews or while chasing a bug in the source code.

!!! note

`q.force_in(U)` is just a shortcut to run `value_cast<U>(q)`. There is no difference in behavior
between those two interfaces. `q.force_in(U)` was added for consistency with `q.in(U)` and
`q.force_numerical_value_in(U)`.

Another place where this cast is useful is when a user wants to convert a quantity with
a floating-point representation to the one using an integral one. Again this is a truncating
conversion, so an explicit cast is needed:
Expand Down
10 changes: 5 additions & 5 deletions example/avg_speed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ constexpr QuantityOf<isq::speed> auto avg_speed(QuantityOf<isq::length> auto d,
template<QuantityOf<isq::length> D, QuantityOf<isq::time> T, QuantityOf<isq::speed> V>
void print_result(D distance, T duration, V speed)
{
const auto result_in_kmph = value_cast<si::kilo<si::metre> / non_si::hour>(speed);
const auto result_in_kmph = speed.force_in(si::kilo<si::metre> / non_si::hour);
std::cout << "Average speed of a car that makes " << distance << " in " << duration << " is " << result_in_kmph
<< ".\n";
}
Expand Down Expand Up @@ -101,7 +101,7 @@ void example()

// it is not possible to make a lossless conversion of miles to meters on an integral type
// (explicit cast needed)
print_result(distance, duration, fixed_int_si_avg_speed(value_cast<si::metre>(distance), duration));
print_result(distance, duration, fixed_int_si_avg_speed(distance.force_in(m), duration));
print_result(distance, duration, fixed_double_si_avg_speed(distance, duration));
print_result(distance, duration, avg_speed(distance, duration));
}
Expand All @@ -119,7 +119,7 @@ void example()
// also it is not possible to make a lossless conversion of miles to meters on an integral type
// (explicit cast needed)
print_result(distance, duration,
fixed_int_si_avg_speed(value_cast<int>(value_cast<si::metre>(distance)), value_cast<int>(duration)));
fixed_int_si_avg_speed(value_cast<int>(distance.force_in(m)), value_cast<int>(duration)));
print_result(distance, duration, fixed_double_si_avg_speed(distance, duration));
print_result(distance, duration, avg_speed(distance, duration));
}
Expand All @@ -133,7 +133,7 @@ void example()

// it is not possible to make a lossless conversion of centimeters to meters on an integral type
// (explicit cast needed)
print_result(distance, duration, fixed_int_si_avg_speed(value_cast<si::metre>(distance), duration));
print_result(distance, duration, fixed_int_si_avg_speed(distance.force_in(m), duration));
print_result(distance, duration, fixed_double_si_avg_speed(distance, duration));
print_result(distance, duration, avg_speed(distance, duration));
}
Expand All @@ -149,7 +149,7 @@ void example()
// it is not possible to make a lossless conversion of centimeters to meters on an integral type
// (explicit cast needed)
print_result(distance, duration,
fixed_int_si_avg_speed(value_cast<int>(value_cast<m>(distance)), value_cast<int>(duration)));
fixed_int_si_avg_speed(value_cast<int>(distance.force_in(m)), value_cast<int>(duration)));

print_result(distance, duration, fixed_double_si_avg_speed(distance, duration));
print_result(distance, duration, avg_speed(distance, duration));
Expand Down
5 changes: 3 additions & 2 deletions example/conversion_factor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ template<mp_units::Quantity Target, mp_units::Quantity Source>
requires std::constructible_from<Target, Source>
inline constexpr double conversion_factor(Target, Source)
{
return mp_units::value_cast<Target::unit>(1. * Source::reference).numerical_value();
return (1. * Source::reference).force_numerical_value_in(Target::unit);
}

} // namespace
Expand All @@ -56,6 +56,7 @@ int main()
std::cout << MP_UNITS_STD_FMT::format("conversion factor from lengthA::unit of {:%q} to lengthB::unit of {:%q}:\n\n",
lengthA, lengthB)
<< MP_UNITS_STD_FMT::format("lengthB.value( {} ) == lengthA.value( {} ) * conversion_factor( {} )\n",
lengthB.numerical_value(), lengthA.numerical_value(),
lengthB.numerical_value_ref_in(lengthB.unit),
lengthA.numerical_value_ref_in(lengthA.unit),
conversion_factor(lengthB, lengthA));
}
10 changes: 5 additions & 5 deletions example/currency.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,16 +81,16 @@ quantity<To, Rep> exchange_to(quantity<From, Rep> q)
template<ReferenceOf<currency> auto To, ReferenceOf<currency> auto From, auto PO, typename Rep>
quantity_point<To, PO, Rep> exchange_to(quantity_point<From, PO, Rep> q)
{
return quantity_point{
zero +
static_cast<Rep>(exchange_rate<q.unit, get_unit(To)>() * (q - q.absolute_point_origin).numerical_value()) * To};
return quantity_point{zero + static_cast<Rep>(exchange_rate<q.unit, get_unit(To)>() *
(q - q.absolute_point_origin).numerical_value_in(q.unit)) *
To};
}

int main()
{
quantity_point price_usd = zero + 100 * us_dollar;
quantity_point price_euro = exchange_to<euro>(price_usd);

std::cout << price_usd.quantity_from_origin() << " -> " << price_euro.quantity_from_origin() << "\n";
// std::cout << price_usd.quantity_from_origin() + price_euro.quantity_from_origin() << "\n"; // does not compile
std::cout << price_usd.quantity_from(zero) << " -> " << price_euro.quantity_from(zero) << "\n";
// std::cout << price_usd.quantity_from(zero) + price_euro.quantity_from(zero) << "\n"; // does not compile
}
4 changes: 2 additions & 2 deletions example/glide_computer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,12 @@ void print(const R& gliders)
std::cout << "- Name: " << g.name << "\n";
std::cout << "- Polar:\n";
for (const auto& p : g.polar) {
const auto ratio = value_cast<one>(glide_ratio(g.polar[0]));
const auto ratio = glide_ratio(g.polar[0]).force_in(one);
std::cout << MP_UNITS_STD_FMT::format(" * {:%.4Q %q} @ {:%.1Q %q} -> {:%.1Q %q} ({:%.1Q %q})\n", p.climb, p.v,
ratio,
// TODO is it possible to make ADL work below (we need another set of trig
// functions for strong angle in a different namespace)
value_cast<si::degree>(isq::asin(1 / ratio)));
isq::asin(1 / ratio).force_in(si::degree));
}
std::cout << "\n";
}
Expand Down
24 changes: 13 additions & 11 deletions example/include/geographic.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ struct MP_UNITS_STD_FMT::formatter<geographic::latitude<T>> :
auto format(geographic::latitude<T> lat, FormatContext& ctx)
{
formatter<typename geographic::latitude<T>::quantity_type>::format(
is_gt_zero(lat) ? lat.quantity_from_origin() : -lat.quantity_from_origin(), ctx);
is_gt_zero(lat) ? lat.quantity_from(geographic::equator) : -lat.quantity_from(geographic::equator), ctx);
MP_UNITS_STD_FMT::format_to(ctx.out(), "{}", is_gt_zero(lat) ? " N" : "S");
return ctx.out();
}
Expand All @@ -151,7 +151,8 @@ struct MP_UNITS_STD_FMT::formatter<geographic::longitude<T>> :
auto format(geographic::longitude<T> lon, FormatContext& ctx)
{
formatter<typename geographic::longitude<T>::quantity_type>::format(
is_gt_zero(lon) ? lon.quantity_from_origin() : -lon.quantity_from_origin(), ctx);
is_gt_zero(lon) ? lon.quantity_from(geographic::prime_meridian) : -lon.quantity_from(geographic::prime_meridian),
ctx);
MP_UNITS_STD_FMT::format_to(ctx.out(), "{}", is_gt_zero(lon) ? " E" : " W");
return ctx.out();
}
Expand All @@ -171,28 +172,29 @@ template<typename T>
distance spherical_distance(position<T> from, position<T> to)
{
using namespace mp_units;
constexpr auto earth_radius = 6'371 * isq::radius[si::kilo<si::metre>];
constexpr quantity earth_radius = 6'371 * isq::radius[si::kilo<si::metre>];

using isq::sin, isq::cos, isq::asin, isq::acos;

const auto& from_lat = from.lat.quantity_from_origin();
const auto& from_lon = from.lon.quantity_from_origin();
const auto& to_lat = to.lat.quantity_from_origin();
const auto& to_lon = to.lon.quantity_from_origin();
const quantity from_lat = from.lat.quantity_from(equator);
const quantity from_lon = from.lon.quantity_from(prime_meridian);
const quantity to_lat = to.lat.quantity_from(equator);
const quantity to_lon = to.lon.quantity_from(prime_meridian);

// https://en.wikipedia.org/wiki/Great-circle_distance#Formulae
if constexpr (sizeof(T) >= 8) {
// spherical law of cosines
const auto central_angle = acos(sin(from_lat) * sin(to_lat) + cos(from_lat) * cos(to_lat) * cos(to_lon - from_lon));
const quantity central_angle =
acos(sin(from_lat) * sin(to_lat) + cos(from_lat) * cos(to_lat) * cos(to_lon - from_lon));
// const auto central_angle = 2 * asin(sqrt(0.5 - cos(to_lat - from_lat) / 2 + cos(from_lat) * cos(to_lat) * (1
// - cos(lon2_rad - from_lon)) / 2));

return quantity_cast<isq::distance>(earth_radius * central_angle);
} else {
// the haversine formula
const auto sin_lat = sin((to_lat - from_lat) / 2);
const auto sin_lon = sin((to_lon - from_lon) / 2);
const auto central_angle = 2 * asin(sqrt(sin_lat * sin_lat + cos(from_lat) * cos(to_lat) * sin_lon * sin_lon));
const quantity sin_lat = sin((to_lat - from_lat) / 2);
const quantity sin_lon = sin((to_lon - from_lon) / 2);
const quantity central_angle = 2 * asin(sqrt(sin_lat * sin_lat + cos(from_lat) * cos(to_lat) * sin_lon * sin_lon));

return quantity_cast<isq::distance>(earth_radius * central_angle);
}
Expand Down
2 changes: 1 addition & 1 deletion example/kalman_filter/kalman.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ struct MP_UNITS_STD_FMT::formatter<kalman::estimation<Q>> {
if constexpr (mp_units::Quantity<Q>)
return t;
else
return t.quantity_from_origin();
return t.quantity_ref_from(t.point_origin);
}(kalman::get<0>(e.state));

std::string value_buffer;
Expand Down
2 changes: 1 addition & 1 deletion example/kalman_filter/kalman_filter-example_6.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ template<QuantityPoint QP, QuantityOf<dimensionless> K>
void print(auto iteration, K gain, QP measured, kalman::estimation<QP> current, kalman::estimation<QP> next)
{
std::cout << MP_UNITS_STD_FMT::format("{:2} | {:7%.4Q} | {:10%.3Q %q} | {:>18.3} | {:>18.3}\n", iteration, gain,
measured.quantity_from_origin(), current, next);
measured.quantity_ref_from(QP::point_origin), current, next);
}

int main()
Expand Down
2 changes: 1 addition & 1 deletion example/kalman_filter/kalman_filter-example_7.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ template<QuantityPoint QP, QuantityOf<dimensionless> K>
void print(auto iteration, K gain, QP measured, kalman::estimation<QP> current, kalman::estimation<QP> next)
{
std::cout << MP_UNITS_STD_FMT::format("{:2} | {:7%.4Q} | {:10%.3Q %q} | {:>18.3} | {:>18.3}\n", iteration, gain,
measured.quantity_from_origin(), current, next);
measured.quantity_ref_from(QP::point_origin), current, next);
}

int main()
Expand Down
2 changes: 1 addition & 1 deletion example/kalman_filter/kalman_filter-example_8.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ template<QuantityPoint QP, QuantityOf<dimensionless> K>
void print(auto iteration, K gain, QP measured, kalman::estimation<QP> current, kalman::estimation<QP> next)
{
std::cout << MP_UNITS_STD_FMT::format("{:2} | {:7%.3Q} | {:10%.3Q %q} | {:>16.2} | {:>16.2}\n", iteration, gain,
measured.quantity_from_origin(), current, next);
measured.quantity_ref_from(QP::point_origin), current, next);
}

int main()
Expand Down
2 changes: 1 addition & 1 deletion example/total_energy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ void si_example()
<< "E = " << E3 << "\n";

std::cout << "\n[converted from SI units back to GeV]\n"
<< "E = " << value_cast<GeV>(E3) << "\n";
<< "E = " << E3.force_in(GeV) << "\n";
}

void natural_example()
Expand Down
8 changes: 4 additions & 4 deletions example/unmanned_aerial_vehicle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,8 @@ template<earth_gravity_model M>
hae_altitude<M> to_hae(msl_altitude msl, position<long double> pos)
{
const auto geoid_undulation =
isq::height(GeographicLibWhatsMyOffset(pos.lat.quantity_from_origin().numerical_value_in(si::degree),
pos.lon.quantity_from_origin().numerical_value_in(si::degree)) *
isq::height(GeographicLibWhatsMyOffset(pos.lat.quantity_from(equator).numerical_value_in(si::degree),
pos.lon.quantity_from(prime_meridian).numerical_value_in(si::degree)) *
si::metre);
return height_above_ellipsoid<M> + (msl - mean_sea_level - geoid_undulation);
}
Expand All @@ -115,15 +115,15 @@ using hal_altitude = quantity_point<isq::altitude[si::metre], height_above_launc
template<class CharT, class Traits>
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const hal_altitude& a)
{
return os << a.quantity_from_origin() << " HAL";
return os << a.quantity_from(height_above_launch) << " HAL";
}

template<>
struct MP_UNITS_STD_FMT::formatter<hal_altitude> : formatter<hal_altitude::quantity_type> {
template<typename FormatContext>
auto format(const hal_altitude& a, FormatContext& ctx)
{
formatter<hal_altitude::quantity_type>::format(a.quantity_from_origin(), ctx);
formatter<hal_altitude::quantity_type>::format(a.quantity_from(height_above_launch), ctx);
return MP_UNITS_STD_FMT::format_to(ctx.out(), " HAL");
}
};
Expand Down
7 changes: 4 additions & 3 deletions src/core-fmt/include/mp-units/format.h
Original file line number Diff line number Diff line change
Expand Up @@ -224,9 +224,9 @@ struct quantity_formatter {
const quantity_format_specs<CharT>& specs;
Locale loc;

explicit quantity_formatter(OutputIt o, quantity<Reference, Rep> q, const quantity_format_specs<CharT>& fspecs,
explicit quantity_formatter(OutputIt o, const quantity<Reference, Rep>& q, const quantity_format_specs<CharT>& fspecs,
Locale lc) :
out(o), val(std::move(q).numerical_value()), specs(fspecs), loc(std::move(lc))
out(o), val(q.numerical_value_ref_in(q.unit)), specs(fspecs), loc(std::move(lc))
{
}

Expand Down Expand Up @@ -396,7 +396,8 @@ struct MP_UNITS_STD_FMT::formatter<mp_units::quantity<Reference, Rep>, CharT> {

if (begin == end || *begin == '}') {
// default format should print value followed by the unit separated with 1 space
out = mp_units::detail::format_units_quantity_value<CharT>(out, q.numerical_value(), specs.rep, ctx.locale());
out = mp_units::detail::format_units_quantity_value<CharT>(out, q.numerical_value_ref_in(q.unit), specs.rep,
ctx.locale());
if constexpr (mp_units::detail::has_unit_symbol(get_unit(Reference))) {
if constexpr (mp_units::space_before_unit_symbol<get_unit(Reference)>) *out++ = CharT(' ');
out = unit_symbol_to<CharT>(out, get_unit(Reference));
Expand Down
6 changes: 3 additions & 3 deletions src/core-io/include/mp-units/ostream.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ void to_stream(std::basic_ostream<CharT, Traits>& os, const quantity<R, Rep>& q)
{
if constexpr (is_same_v<Rep, std::uint8_t> || is_same_v<Rep, std::int8_t>)
// promote the value to int
os << +q.numerical_value();
os << +q.numerical_value_ref_in(q.unit);
else
os << q.numerical_value();
os << q.numerical_value_ref_in(q.unit);
if constexpr (has_unit_symbol(get_unit(R))) {
if constexpr (space_before_unit_symbol<get_unit(R)>) os << " ";
unit_symbol_to<CharT>(std::ostream_iterator<CharT>(os), get_unit(R));
Expand All @@ -49,7 +49,7 @@ void to_stream(std::basic_ostream<CharT, Traits>& os, const quantity<R, Rep>& q)

template<typename CharT, typename Traits, auto R, typename Rep>
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, const quantity<R, Rep>& q)
requires requires { os << q.numerical_value(); }
requires requires { os << q.numerical_value_ref_in(q.unit); }
{
if (os.width()) {
// std::setw() applies to the whole quantity output so it has to be first put into std::string
Expand Down
4 changes: 2 additions & 2 deletions src/core/include/mp-units/bits/quantity_cast.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ template<QuantitySpec auto ToQS, typename Q>
{
if constexpr (detail::QuantityKindSpec<std::remove_const_t<decltype(ToQS)>> &&
AssociatedUnit<std::remove_const_t<decltype(Q::unit)>>)
return make_quantity<Q::unit>(std::forward<Q>(q).numerical_value());
return make_quantity<Q::unit>(std::forward<Q>(q).numerical_value_);
else
return make_quantity<reference<ToQS, Q::unit>{}>(std::forward<Q>(q).numerical_value());
return make_quantity<reference<ToQS, Q::unit>{}>(std::forward<Q>(q).numerical_value_);
}

} // namespace mp_units
10 changes: 5 additions & 5 deletions src/core/include/mp-units/bits/sudo_cast.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,10 @@ template<Quantity To, typename From>
if constexpr (q_unit == To::unit) {
// no scaling of the number needed
return make_quantity<To::reference>(static_cast<MP_UNITS_TYPENAME To::rep>(
std::forward<From>(q).numerical_value())); // this is the only (and recommended) way to do
// a truncating conversion on a number, so we are
// using static_cast to suppress all the compiler
// warnings on conversions
std::forward<From>(q).numerical_value_)); // this is the only (and recommended) way to do
// a truncating conversion on a number, so we are
// using static_cast to suppress all the compiler
// warnings on conversions
} else {
// scale the number
constexpr Magnitude auto c_mag = get_canonical_unit(q_unit).mag / get_canonical_unit(To::unit).mag;
Expand All @@ -78,7 +78,7 @@ template<Quantity To, typename From>
using multiplier_type =
conditional<treat_as_floating_point<c_rep_type>, std::common_type_t<c_mag_type, long double>, c_mag_type>;
constexpr auto val = [](Magnitude auto m) { return get_value<multiplier_type>(m); };
return static_cast<MP_UNITS_TYPENAME To::rep>(static_cast<c_rep_type>(std::forward<From>(q).numerical_value()) *
return static_cast<MP_UNITS_TYPENAME To::rep>(static_cast<c_rep_type>(std::forward<From>(q).numerical_value_) *
val(num) / val(den) * val(irr)) *
To::reference;
}
Expand Down
Loading

0 comments on commit becca90

Please sign in to comment.