Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update docs for reference<D, U> and remove operator/(Rep, reference) #262

Merged
merged 2 commits into from
Mar 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ static_assert(10_q_km / 5_q_km == 2);
static_assert(1000 / 1_q_s == 1_q_kHz);
```

_Try it on the [Compiler Explorer](https://godbolt.org/z/YWch6d)._
_Try it on the [Compiler Explorer](https://godbolt.org/z/shcohY)._

This library requires some C++20 features (concepts, classes as NTTPs, ...). Thanks to
them the user gets a powerful but still easy to use interface and all unit conversions
Expand All @@ -77,9 +77,9 @@ constexpr Speed auto avg_speed(Length auto d, Time auto t)
int main()
{
using namespace units::isq::si::literals;
using namespace units::isq::si::unit_constants;
using namespace units::isq::si::references;

constexpr Speed auto v1 = 110 * km / h;
constexpr Speed auto v1 = 110 * (km / h);
constexpr Speed auto v2 = avg_speed(220_q_km, 2_q_h);
constexpr Speed auto v3 = avg_speed(si::length<si::international::mile>(140), si::time<si::hour>(2));
constexpr Speed auto v4 = quantity_cast<si::speed<si::metre_per_second>>(v2);
Expand All @@ -95,4 +95,4 @@ int main()
}
```

_Try it on the [Compiler Explorer](https://godbolt.org/z/eca49d)._
_Try it on the [Compiler Explorer](https://godbolt.org/z/dY1dEd)._
2 changes: 1 addition & 1 deletion docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
- refactor: basic concepts, `quantity` and `quantity_cast` refactored
- refactor: `abs()` definition refactored to be more explicit about the return type
- feat: quantity (point) kind support added (thanks [@johelegp](https://github.com/johelegp))
- feat: unit constants support added (thanks [@johelegp](https://github.com/johelegp))
- feat: quantity references support added (thanks [@johelegp](https://github.com/johelegp))
- feat: interoperability with `std::chrono::duration` and other units libraries
- feat: CTAD for dimensionless quantity added
- perf: preconditions check do not influence the runtime performance of a Release build
Expand Down
2 changes: 1 addition & 1 deletion docs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,11 @@ set(unitsSphinxDocs
"${CMAKE_CURRENT_SOURCE_DIR}/reference/core/types/dimensions.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/core/types/kinds.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/core/types/prefixes.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/core/types/reference.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/core/types/quantity.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/core/types/quantity_kind.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/core/types/quantity_point_kind.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/core/types/quantity_point.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/core/types/representation.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/core/types/units.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/core/types/utilities.rst"
"${CMAKE_CURRENT_SOURCE_DIR}/reference/core/types/utilities/basic_fixed_string.rst"
Expand Down
76 changes: 28 additions & 48 deletions docs/framework/quantities.rst
Original file line number Diff line number Diff line change
Expand Up @@ -83,39 +83,40 @@ Thanks to them the same code can be as simple as::
``_q_`` prefix was consistently applied to all the UDLs.


Unit Constants
++++++++++++++
Quantity References
+++++++++++++++++++

Unit Constants provide an alternative way to simplify quantities creation.
They are defined using a special `one_rep` representation type::
Quantity References provide an alternative way to simplify quantities creation.
They are defined using the `reference` class template::

namespace unit_constants {
namespace references {

inline constexpr auto km = length<kilometre, one_rep>{};
inline constexpr auto h = time<hour, one_rep>{};
inline constexpr auto km = reference<dim_length, kilometre>{};
inline constexpr auto h = reference<dim_time, hour>{};

}

With the above our code can look as follows::

using namespace units::isq::si::unit_constants;
using namespace units::isq::si::references;
auto d = 123. * km; // si::length<si::kilometre, double>
auto v = 70 * km / h; // si::speed<si::kilometre_per_hour, int>
auto v = 70 * (km / h); // si::speed<si::kilometre_per_hour, int>

.. important::

``km * 3`` or ``s / 4`` syntax is not allowed.
The following syntaxes are not allowed:
``2 / s``, ``km * 3``, ``s / 4``, ``70 * km / h``.

It is also allowed to easily define custom unit constants from existing ones::
It is also allowed to easily define custom quantity references from existing ones::

inline constexpr auto Nm = N * m;
inline constexpr auto km_per_h = km / h;
inline constexpr auto mph = mi / h;

UDLs vs Unit Constants
++++++++++++++++++++++
UDLs vs Quantity References
+++++++++++++++++++++++++++

UDLs are helpful but they also have some disadvantages compared to Unit Constants:
UDLs are helpful but they also have some disadvantages compared to Quantity References:

1. UDLs are only for compile-time known values and do not work for runtime variables

Expand All @@ -125,13 +126,13 @@ UDLs are helpful but they also have some disadvantages compared to Unit Constant
auto v1 = 120_q_km / 2_q_h;
auto v2 = length<kilometre>(distance) / time<hour>(duration);

- Unit Constants::
- Quantity References::

using namespace units::isq::si::unit_constants;
using namespace units::isq::si::references;
auto v1 = 120 * km / (2 * h);
auto v2 = distance * km / (duration * h);
auto v2 = distance * (1 * km) / (duration * (1 * h));

Constants treat both cases in a unified way. It is also worth to notice that we work
References treat both cases in a unified way. It is also worth to notice that we work
mostly with runtime variables and compile-time known values mostly appear only in physical
constants and unit tests.

Expand All @@ -143,10 +144,10 @@ UDLs are helpful but they also have some disadvantages compared to Unit Constant
using namespace units::isq::si::cgs::literals;
auto d = 1_q_cm; // FAILS TO COMPILE

- Unit Constants::
- Quantity References::

inline constexpr auto si_cm = units::isq::si::unit_constants::cm;
inline constexpr auto cgs_cm = units::isq::si::cgs::unit_constants::cm;
inline constexpr auto si_cm = units::isq::si::references::cm;
inline constexpr auto cgs_cm = units::isq::si::cgs::references::cm;

auto d1 = 1. * si_cm; // si::length<si::centimetre>
auto d2 = 1. * cgs_cm; // si::cgs::length<si::centimetre>
Expand All @@ -162,9 +163,9 @@ UDLs are helpful but they also have some disadvantages compared to Unit Constant

No possibility to obtain any other representation type.

- Unit Constants::
- Quantity References::

using namespace units::isq::si::unit_constants;
using namespace units::isq::si::references;
auto d1 = 123. * km; // si::length<si::kilometre, double>
auto d2 = 123 * km; // si::length<si::kilometre, int>
auto d3 = 123.f * km; // si::length<si::kilometre, float>
Expand All @@ -179,39 +180,18 @@ UDLs are helpful but they also have some disadvantages compared to Unit Constant
- for each unit an integral and a floating-point UDL have to be defined
- have to be provided for unnamed derived units (i.e. ``_q_km_per_h``)

- Unit Constants:
- Quantity References:

- one constant per unit
- unnamed derived units constructed from base constants (i.e. ``km / h``)
- one reference per unit
- unnamed derived units constructed from base references (i.e. ``km / h``)

5. Typical UDL definition for quantities when compiled with a ``-Wsign-conversion``
flag results in a compilation warning. This warning could be silenced with a
``static_cast<std::int64_t>(value)`` in every UDL, but in a such case other safety
and security issues could be silently introduced.
Unit Constants, on the opposite, always use the exact representation type provided
Quantity References, on the opposite, always use the exact representation type provided
by the user so there is no chance for a truncating conversion on a quantity construction.

The only issue we are aware of with Unit Constants is a potential problem of specifying
a quantity in denominator::

using namespace units::isq::si::unit_constants;
Speed auto v = 220 * km / 2 * h; // FAILS TO COMPILE (not a quantity of a speed dimension)

The above code can be fixed in one of the below ways:

- braces around quantities in denominator::

Speed auto v = 220 * km / (2 * h);

- inverting an operator for quantities in denominator::

Speed auto v = 220 * km / 2 / h;

- creating a custom unit constant for a derived quantity::

inline constexpr auto km_per_h = km / h;
Speed auto v = 220 / 2 * km_per_h;


Dimension-specific Concepts
---------------------------
Expand Down
2 changes: 1 addition & 1 deletion docs/framework/quantity_kinds.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ The library provides:

- no kinds, such as ``radius`` or ``width``, therefore

* no UDLs or unit constants,
* no UDLs or quantity references,
* no kind-specific concepts, such as ``Radius``,
(there's the generic `QuantityKind` and kind-specifiable `QuantityKindOf`),

Expand Down
6 changes: 3 additions & 3 deletions docs/quick_start.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Here is a small example of possible operations::

.. admonition:: Try it on Compiler Explorer

`Example #1 <https://godbolt.org/z/YWch6d>`_
`Example #1 <https://godbolt.org/z/shcohY>`_

This library requires some C++20 features (concepts, classes as
:abbr:`NTTP (Non-Type Template Parameter)`, ...). Thanks to them the user gets a powerful
Expand All @@ -55,7 +55,7 @@ of basic library features::
using namespace units::isq::si::literals;
using namespace units::isq::si::unit_constants;

constexpr Speed auto v1 = 110 * km / h;
constexpr Speed auto v1 = 110 * (km / h);
constexpr Speed auto v2 = avg_speed(220_q_km, 2_q_h);
constexpr Speed auto v3 = avg_speed(si::length<si::international::mile>(140), si::time<si::hour>(2));
constexpr Speed auto v4 = quantity_cast<si::speed<si::metre_per_second>>(v2);
Expand All @@ -72,7 +72,7 @@ of basic library features::

.. admonition:: Try it on Compiler Explorer

`Example #2 <https://godbolt.org/z/eca49d>`_
`Example #2 <https://godbolt.org/z/dY1dEd>`_

.. seealso::

Expand Down
6 changes: 6 additions & 0 deletions docs/reference/core/types/reference.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Quantity Reference
==================

.. doxygenstruct:: units::reference
:members:
:undoc-members:
6 changes: 0 additions & 6 deletions docs/reference/core/types/representation.rst

This file was deleted.

11 changes: 2 additions & 9 deletions src/core/include/units/reference.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ using reference_divide = detail::reference_divide_impl<
* constexpr auto mph = mi / h;
* @endcode
*
* `km * 3` or `s / 4` syntax is not allowed for quantity creation.
* Neither is `70 * km / h`, but `70 * (km / h)` is.
* The following syntaxes are not allowed:
* `2 / s`, `km * 3`, `s / 4`, `70 * km / h`.
*/
template<Dimension D, UnitOf<D> U>
struct reference {
Expand All @@ -108,14 +108,7 @@ struct reference {
return quantity<D, U, Rep>(lhs);
}

template<QuantityValue Rep>
[[nodiscard]] friend constexpr Quantity auto operator/(const Rep& lhs, reference)
{
return lhs / quantity<D, U, Rep>::one();
}

friend void /*Use `q * (1 * r)` rather than `q * r`.*/ operator*(Quantity auto, reference) = delete;
friend void /*Use `q / (1 * r)` rather than `q / r`.*/ operator/(Quantity auto, reference) = delete;
};

// type traits
Expand Down
18 changes: 9 additions & 9 deletions test/unit_test/static/quantity_kind_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -578,28 +578,28 @@ static_assert(same(width<metre, double>(2. * m) / quantity_kind<downcast_kind<wi
width<metre, double>(2. / 3 * m)));

static_assert(same(2 / quantity_kind<time_kind, second, int>(3 * s),
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, int>(2 / 3 / s)));
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, int>(2 / 3 / (1 * s))));
static_assert(same(2 / quantity_kind<time_kind, second, double>(3. * s),
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, double>(2 / 3. / s)));
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, double>(2 / 3. / (1 * s))));
static_assert(same(2. / quantity_kind<time_kind, second, int>(3 * s),
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, double>(2 / 3. / s)));
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, double>(2 / 3. / (1 * s))));

static_assert(same(quantity(2) / quantity_kind<time_kind, second, int>(3 * s),
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, int>(2 / 3 / s)));
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, int>(2 / 3 / (1 * s))));
static_assert(same(quantity(2) / quantity_kind<time_kind, second, double>(3. * s),
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, double>(2 / 3. / s)));
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, double>(2 / 3. / (1 * s))));
static_assert(same(quantity(2.) / quantity_kind<time_kind, second, int>(3 * s),
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, double>(2 / 3. / s)));
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, double>(2 / 3. / (1 * s))));

static_assert(
same(quantity_kind<downcast_kind<time_kind, dim_one>, one, int>(2) / quantity_kind<time_kind, second, int>(3 * s),
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, int>(2 / 3 / s)));
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, int>(2 / 3 / (1 * s))));
static_assert(
same(quantity_kind<downcast_kind<time_kind, dim_one>, one, int>(2) / quantity_kind<time_kind, second, double>(3. * s),
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, double>(2 / 3. / s)));
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, double>(2 / 3. / (1 * s))));
static_assert(
same(quantity_kind<downcast_kind<time_kind, dim_one>, one, double>(2.) / quantity_kind<time_kind, second, int>(3 * s),
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, double>(2 / 3. / s)));
quantity_kind<downcast_kind<time_kind, dim_frequency>, hertz, double>(2 / 3. / (1 * s))));

static_assert(same(height<metre, int>(2 * m) / (3 * s), rate_of_climb<metre_per_second, int>(0 * (m / s))));
static_assert(same(height<metre, int>(2 * m) / (3. * s), rate_of_climb<metre_per_second, double>(2 / 3. * (m / s))));
Expand Down
2 changes: 1 addition & 1 deletion test/unit_test/static/references_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ static_assert(2 * m == 2_q_m);
static_assert(2 * s == 2_q_s);
template<auto& s>
concept invalid_operations = requires {
requires !requires { 2 / s; };
requires !requires { s / 2; };
requires !requires { s * 2; };
requires !requires { s + 2; };
Expand All @@ -66,7 +67,6 @@ static_assert(invalid_operations<s>);

static_assert(2_q_m / (1 * s) == 2_q_m_per_s);
static_assert(2 * (m / s) == 2_q_m_per_s);
static_assert(2 / (s / m) == 2_q_m_per_s);

#if !(UNITS_COMP_GCC == 10 && UNITS_COMP_GCC_MINOR == 1) // GCC 10.1.0 ICEs
constexpr auto m_per_s = m / s;
Expand Down