Skip to content

Commit

Permalink
Merge branch 'master' of github.com:mpusz/mp-units
Browse files Browse the repository at this point in the history
  • Loading branch information
mpusz committed Jan 23, 2024
2 parents 55bf9a9 + 28f131f commit a9b2865
Show file tree
Hide file tree
Showing 26 changed files with 269 additions and 91 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

name: Check CI
name: Formatting CI

on: [push, pull_request]

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

[![Conan CI](https://img.shields.io/github/actions/workflow/status/mpusz/mp-units/ci-conan.yml?branch=master&label=Conan%20CI)](https://github.com/mpusz/mp-units/actions?query=workflow%3A%22Conan%20CI%22+branch%3Amaster)
[![CMake CI](https://img.shields.io/github/actions/workflow/status/mpusz/mp-units/ci-test-package-cmake.yml?branch=master&label=CMake%20CI)](https://github.com/mpusz/mp-units/actions?query=workflow%3A%22CMake+Test+Package+CI%22+branch%3Amaster)
[![Check CI](https://img.shields.io/github/actions/workflow/status/mpusz/mp-units/ci-check.yml?branch=master&label=Check%20CI)](https://github.com/mpusz/mp-units/actions?query=workflow%3A%22Check%20CI%22+branch%3Amaster)
[![Formatting CI](https://img.shields.io/github/actions/workflow/status/mpusz/mp-units/ci-formatting.yml?branch=master&label=Formatting%20CI)](https://github.com/mpusz/mp-units/actions?query=workflow%3A%22Formatting%20CI%22+branch%3Amaster)
[![GitHub Workflow Documentation](https://img.shields.io/github/actions/workflow/status/mpusz/mp-units/documentation.yml?branch=master&label=Documentation)](https://github.com/mpusz/mp-units/actions?query=workflow%3ADocumentation+branch%3Amaster)

[![Conan stable](https://img.shields.io/conan/v/mp-units?label=ConanCenter&color=blue)](https://conan.io/center/mp-units)
Expand Down
2 changes: 1 addition & 1 deletion docs/getting_started/installation_and_usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ specific feature:
| **Minimum support** | 12 | 16 | 15 | None |
| **`std::format`** | None | None | None | None |
| **C++ modules** | None | 17 | None | None |
| **C++23 extensions** | None | None | None | None |
| **C++23 extensions** | 14 | 18 | None | None |

More requirements for C++ modules support can be found in the
[CMake's documentation](https://cmake.org/cmake/help/latest/manual/cmake-cxxmodules.7.html).
Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ The library source code is hosted on [GitHub](https://github.com/mpusz/mp-units)
| **Minimum support** | 12 | 16 | 15 | None |
| **`std::format`** | None | None | None | None |
| **C++ modules** | None | 17 | None | None |
| **C++23 extensions** | None | None | None | None |
| **C++23 extensions** | 14 | 18 | None | None |

More requirements for C++ modules support can be found in the
[CMake's documentation](https://cmake.org/cmake/help/latest/manual/cmake-cxxmodules.7.html).
Expand Down
18 changes: 7 additions & 11 deletions docs/users_guide/framework_basics/concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,12 +165,8 @@ A `Reference` can either be:

### `ReferenceOf<T, V>` { #ReferenceOf }

`ReferenceOf` concept is satisfied by references `T` that match the following value `V`:

| `V` | Condition |
|----------------|-----------------------------------------------------------------------------------------------|
| `Dimension` | The dimension of a quantity specification satisfies [`DimensionOf<V>`](#DimensionOf) concept. |
| `QuantitySpec` | The quantity specification satisfies [`QuantitySpecOf<V>`](#QuantitySpecOf) concept. |
`ReferenceOf` concept is satisfied by references `T` which have a quantity specification that satisfies
[`QuantitySpecOf<V>`](#QuantitySpecOf) concept. |


## `Representation<T>` { #Representation }
Expand Down Expand Up @@ -212,7 +208,7 @@ satisfied by all types being or deriving from an instantiation of a `quantity` c

### `QuantityOf<T, V>` { #QuantityOf }

`QuantityOf` concept is satisfied by all the quantities for which a [`ReferenceOf<V>`](#ReferenceOf)
`QuantityOf` concept is satisfied by all the quantities for which a [`QuantitySpecOf<V>`](#QuantitySpecOf)
is `true`.


Expand Down Expand Up @@ -259,10 +255,10 @@ class template.

`QuantityPointOf` concept is satisfied by all the quantity points `T` that match the following value `V`:

| `V` | Condition |
|---------------|----------------------------------------------------------------------------------|
| `Reference` | The quantity point reference satisfies [`ReferenceOf<V>`](#ReferenceOf) concept. |
| `PointOrigin` | The _point_ and `V` have the same absolute point origin. |
| `V` | Condition |
|----------------|-----------------------------------------------------------------------------------------------------|
| `QuantitySpec` | The quantity point quantity specification satisfies [`QuantitySpecOf<V>`](#QuantitySpecOf) concept. |
| `PointOrigin` | The _point_ and `V` have the same absolute point origin. |


## `QuantityLike<T>` { #QuantityLike }
Expand Down
2 changes: 2 additions & 0 deletions docs/users_guide/framework_basics/dimensionless_quantities.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,8 @@ with dimensionless quantities:
```cpp
inline constexpr struct percent : named_unit<"%", mag<ratio{1, 100}> * one> {} percent;
inline constexpr struct per_mille : named_unit<basic_symbol_text{"‰", "%o"}, mag<ratio(1, 1000)> * one> {} per_mille;
inline constexpr struct parts_per_million : named_unit<"ppm", mag<ratio(1, 1'000'000)> * one> {} parts_per_million;
inline constexpr auto ppm = parts_per_million;
```
Expand Down
4 changes: 2 additions & 2 deletions docs/users_guide/framework_basics/quantity_arithmetics.md
Original file line number Diff line number Diff line change
Expand Up @@ -337,13 +337,13 @@ Among others, we can find there the following:
- `exp()`,
- `abs()`,
- `epsilon()`,
- `fma()`,
- `fma()`, `fmod()`,
- `isfinite()`, `isinf()`, `isnan()`,
- `floor()`, `ceil()`, `round()`,
- `inverse()`,
- `hypot()`,
- `sin()`, `cos()`, `tan()`,
- `asin()`, `acos()`, `atan()`.
- `asin()`, `acos()`, `atan()`, `atan2()`.

In the library, we can also find _mp-units/random.h_ header file with all the pseudo-random number
generators working on quantity types.
42 changes: 32 additions & 10 deletions src/core/include/mp-units/bits/external/fixed_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
// IWYU pragma: begin_exports
#include <compare>
#include <cstdlib>
#include <ostream>
// IWYU pragma: end_exports

#include <cstddef>
Expand Down Expand Up @@ -56,18 +57,18 @@ struct basic_fixed_string {
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;

constexpr explicit(false) basic_fixed_string(CharT ch) noexcept
requires(N == 1)
{
data_[0] = ch;
}

constexpr explicit(false) basic_fixed_string(const CharT (&txt)[N + 1]) noexcept
{
if constexpr (N != 0)
for (std::size_t i = 0; i < N; ++i) data_[i] = txt[i];
}

template<std::convertible_to<CharT>... Rest>
requires(1 + sizeof...(Rest) == N)
constexpr explicit basic_fixed_string(CharT first, Rest... rest) noexcept : data_{first, rest..., CharT('\0')}
{
}

constexpr basic_fixed_string(const CharT* ptr, std::integral_constant<std::size_t, N>) noexcept
{
if constexpr (N != 0)
Expand All @@ -78,13 +79,18 @@ struct basic_fixed_string {
[[nodiscard]] constexpr size_type size() const noexcept { return N; }
[[nodiscard]] constexpr const_pointer data() const noexcept { return data_; }
[[nodiscard]] constexpr const CharT* c_str() const noexcept { return data(); }
[[nodiscard]] constexpr const_reference operator[](size_type index) const noexcept { return data()[index]; }
[[nodiscard]] constexpr value_type operator[](size_type index) const noexcept { return data()[index]; }

[[nodiscard]] constexpr const_iterator begin() const noexcept { return data(); }
[[nodiscard]] constexpr const_iterator cbegin() const noexcept { return data(); }
[[nodiscard]] constexpr const_iterator end() const noexcept { return data() + size(); }
[[nodiscard]] constexpr const_iterator cend() const noexcept { return data() + size(); }

[[nodiscard]] constexpr std::basic_string_view<CharT> view() const noexcept
{
return std::basic_string_view<CharT>(cbegin(), cend());
}

template<std::size_t N2>
[[nodiscard]] constexpr friend basic_fixed_string<CharT, N + N2> operator+(
const basic_fixed_string& lhs, const basic_fixed_string<CharT, N2>& rhs) noexcept
Expand Down Expand Up @@ -116,18 +122,34 @@ struct basic_fixed_string {
// TODO std::lexicographical_compare_three_way(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
return detail::lexicographical_compare_three_way(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}
};

template<typename CharT>
basic_fixed_string(CharT) -> basic_fixed_string<CharT, 1>;
template<typename Traits>
friend std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os,
const basic_fixed_string<CharT, N>& str)
{
return os << str.c_str();
}
};

template<typename CharT, std::size_t N>
basic_fixed_string(const CharT (&str)[N]) -> basic_fixed_string<CharT, N - 1>;

template<typename CharT, std::convertible_to<CharT>... Rest>
basic_fixed_string(CharT, Rest...) -> basic_fixed_string<CharT, 1 + sizeof...(Rest)>;

template<typename CharT, std::size_t N>
basic_fixed_string(const CharT* ptr, std::integral_constant<std::size_t, N>) -> basic_fixed_string<CharT, N>;

template<std::size_t N>
using fixed_string = basic_fixed_string<char, N>;

} // namespace mp_units

template<typename CharT, std::size_t N>
struct MP_UNITS_STD_FMT::formatter<mp_units::basic_fixed_string<CharT, N>> : formatter<std::basic_string_view<CharT>> {
template<typename FormatContext>
auto format(const mp_units::basic_fixed_string<CharT, N>& str, FormatContext& ctx)
{
return formatter<std::basic_string_view<CharT>>::format(str.view(), ctx);
}
};
30 changes: 30 additions & 0 deletions src/core/include/mp-units/bits/external/type_traits.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,36 @@ template<typename T, template<typename...> typename Type>
// inline constexpr bool // TODO: Replace with concept when it works with MSVC
concept is_derived_from_specialization_of = requires(T* t) { detail::to_base_specialization_of<Type>(t); };


namespace detail {

template<typename T>
struct get_value_type {
using type = MP_UNITS_TYPENAME T::value_type;
};

template<typename T>
struct get_element_type {
using type = std::remove_reference_t<typename T::element_type>;
};

} // namespace detail

template<typename T>
struct underlying_type {
using type = T;
};

template<typename T>
requires requires { typename T::value_type; } || requires { typename T::element_type; }
struct underlying_type<T> {
using type = MP_UNITS_TYPENAME
conditional<requires { typename T::value_type; }, detail::get_value_type<T>, detail::get_element_type<T>>::type;
};

template<typename T>
using underlying_type_t = MP_UNITS_TYPENAME underlying_type<T>::type;

template<typename T, typename... Ts>
concept one_of = (false || ... || std::same_as<T, Ts>);

Expand Down
10 changes: 5 additions & 5 deletions src/core/include/mp-units/bits/quantity_concepts.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,13 @@ template<typename T>
concept Quantity = detail::is_derived_from_specialization_of_quantity<T>;

/**
* @brief A concept matching all quantities with provided dimension or quantity spec
* @brief A concept matching all quantities with provided quantity spec
*
* Satisfied by all quantities with a dimension/quantity_spec being the instantiation derived from
* the provided dimension/quantity_spec type.
* Satisfied by all quantities with a quantity_spec being the instantiation derived from
* the provided quantity_spec type.
*/
template<typename Q, auto V>
concept QuantityOf = Quantity<Q> && ReferenceOf<std::remove_const_t<decltype(Q::reference)>, V>;
template<typename Q, auto QS>
concept QuantityOf = Quantity<Q> && QuantitySpecOf<std::remove_const_t<decltype(Q::quantity_spec)>, QS>;

/**
* @brief A concept matching all external quantities like types
Expand Down
8 changes: 4 additions & 4 deletions src/core/include/mp-units/bits/quantity_point_concepts.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,15 +145,15 @@ concept SameAbsolutePointOriginAs =


/**
* @brief A concept matching all quantity points with provided dimension or quantity spec
* @brief A concept matching all quantity points with provided quantity spec
*
* Satisfied by all quantity points with a dimension/quantity_spec being the instantiation derived from
* the provided dimension/quantity_spec type, or quantity points having the origin with the same
* Satisfied by all quantity points with a quantity_spec being the instantiation derived from
* the provided quantity_spec type, or quantity points having the origin with the same
* `absolute_point_origin`.
*/
template<typename QP, auto V>
concept QuantityPointOf =
QuantityPoint<QP> && (ReferenceOf<std::remove_const_t<decltype(QP::reference)>, V> ||
QuantityPoint<QP> && (QuantitySpecOf<std::remove_const_t<decltype(QP::quantity_spec)>, V> ||
detail::SameAbsolutePointOriginAs<std::remove_const_t<decltype(QP::absolute_point_origin)>, V>);

/**
Expand Down
12 changes: 5 additions & 7 deletions src/core/include/mp-units/bits/reference_concepts.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,12 @@ template<auto Q, auto U>
}

/**
* @brief A concept matching all references with provided dimension or quantity spec
* @brief A concept matching all references with provided quantity spec
*
* Satisfied by all references with a dimension/quantity_spec being the instantiation derived from
* the provided dimension/quantity_spec type.
* Satisfied by all references with a quantity_spec being the instantiation derived from
* the provided quantity_spec type.
*/
template<typename T, auto V>
concept ReferenceOf =
Reference<T> && (DimensionOf<std::remove_const_t<decltype(get_quantity_spec(T{}).dimension)>, V> ||
QuantitySpecOf<std::remove_const_t<decltype(get_quantity_spec(T{}))>, V>);
template<typename T, auto QS>
concept ReferenceOf = Reference<T> && QuantitySpecOf<std::remove_const_t<decltype(get_quantity_spec(T{}))>, QS>;

} // namespace mp_units
45 changes: 27 additions & 18 deletions src/core/include/mp-units/bits/sudo_cast.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,12 @@

namespace mp_units::detail {

// determines the best available representation type
template<Quantity From, Quantity To>
[[nodiscard]] consteval auto common_rep_type(From, To)
{
if constexpr (requires { typename std::common_type_t<typename From::rep, typename To::rep>; })
// returns a common type of two representation types if available
// e.g. `double` and `int` will end up with `double` precision
return std::common_type_t<typename From::rep, typename To::rep>{};
else
return typename From::rep{};
}
template<typename T, typename Other>
struct get_common_type : std::common_type<T, Other> {};

template<typename T, typename Other>
using maybe_common_type = MP_UNITS_TYPENAME std::conditional_t<requires { typename std::common_type_t<T, Other>; },
get_common_type<T, Other>, std::type_identity<T>>::type;

/**
* @brief Explicit cast between different quantity types
Expand Down Expand Up @@ -73,15 +68,29 @@ template<Quantity To, typename From>
constexpr Magnitude auto num = numerator(c_mag);
constexpr Magnitude auto den = denominator(c_mag);
constexpr Magnitude auto irr = c_mag * (den / num);
using c_rep_type = decltype(common_rep_type(q, To{}));
using c_rep_type = maybe_common_type<typename std::remove_reference_t<From>::rep, typename To::rep>;
using c_mag_type = common_magnitude_type<c_mag>;
using multiplier_type =
conditional<treat_as_floating_point<c_rep_type>, std::common_type_t<c_mag_type, long double>, c_mag_type>;
using multiplier_type = conditional<treat_as_floating_point<c_rep_type>,
// ensure that the multiplier is also floating-point
conditional<std::is_arithmetic_v<underlying_type_t<c_rep_type>>,
// reuse user's type if possible
std::common_type_t<c_mag_type, underlying_type_t<c_rep_type>>,
std::common_type_t<c_mag_type, double>>,
c_mag_type>;
using c_type = maybe_common_type<c_rep_type, multiplier_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_is_an_implementation_detail_) * val(num) /
val(den) * val(irr)),
To::reference};
if constexpr (std::is_floating_point_v<multiplier_type>) {
// this results in great assembly
constexpr auto ratio = val(num) / val(den) * val(irr);
auto res = static_cast<MP_UNITS_TYPENAME To::rep>(
static_cast<c_type>(q.numerical_value_is_an_implementation_detail_) * ratio);
return {res, To::reference};
} else {
// this is slower but allows conversions like 2000 m -> 2 km without loosing data
auto res = static_cast<MP_UNITS_TYPENAME To::rep>(
static_cast<c_type>(q.numerical_value_is_an_implementation_detail_) * val(num) / val(den) * val(irr));
return {res, To::reference};
}
}
}

Expand Down
18 changes: 18 additions & 0 deletions src/core/include/mp-units/math.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,24 @@ template<auto R, auto S, auto T, typename Rep1, typename Rep2, typename Rep3>
}


/**
* @brief Computes the floating-point remainder of the division operation x / y.
*/
template<auto R1, typename Rep1, auto R2, typename Rep2>
requires requires(Rep1 v1, Rep2 v2) {
common_reference(R1, R2);
requires requires { fmod(v1, v2); } || requires { std::fmod(v1, v2); };
}
[[nodiscard]] constexpr QuantityOf<get_quantity_spec(R1)> auto fmod(const quantity<R1, Rep1>& x,
const quantity<R2, Rep2>& y) noexcept
{
constexpr auto ref = common_reference(R1, R2);
constexpr auto unit = get_unit(ref);
using std::fmod;
return quantity{fmod(x.numerical_value_in(unit), y.numerical_value_in(unit)), ref};
}


/**
* @brief Returns the epsilon of the quantity
*
Expand Down
4 changes: 2 additions & 2 deletions src/core/include/mp-units/quantity.h
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ class quantity {
return std::forward<Q>(lhs);
}

template<typename Q1, QuantityOf<dimension_one> Q2>
template<typename Q1, QuantityOf<dimensionless> Q2>
requires std::derived_from<std::remove_cvref_t<Q1>, quantity> && (Q2::unit == ::mp_units::one) &&
requires(rep a, const typename Q2::rep b) {
{
Expand All @@ -389,7 +389,7 @@ class quantity {
return std::forward<Q>(lhs);
}

template<typename Q1, QuantityOf<dimension_one> Q2>
template<typename Q1, QuantityOf<dimensionless> Q2>
requires std::derived_from<std::remove_cvref_t<Q1>, quantity> && (Q2::unit == ::mp_units::one) &&
requires(rep a, const typename Q2::rep b) {
{
Expand Down
Loading

0 comments on commit a9b2865

Please sign in to comment.