Skip to content

Commit e723823

Browse files
committed
feat: si/core.h and si/prefix_utils.h added
1 parent 89c64cd commit e723823

File tree

8 files changed

+171
-100
lines changed

8 files changed

+171
-100
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"source_hash": "b30c77ccf3f096dd9de0a5541afe09d920705e45e17ef136fdbe04e2897cbfab"
2+
"source_hash": "45ab6f3687af3925e0efe5a9ab5f5919aa5dedddf7b571b8c6b9525db4b06698"
33
}

docs/reference/systems_reference/systems/si.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313

1414
- `<mp-units/systems/si/chrono.h>`
1515
- `<mp-units/systems/si/constants.h>`
16+
- `<mp-units/systems/si/core.h>`
1617
- `<mp-units/systems/si/math.h>`
18+
- `<mp-units/systems/si/prefix_utils.h>`
1719
- `<mp-units/systems/si/prefixes.h>`
1820
- `<mp-units/systems/si/unit_symbols.h>`
1921
- `<mp-units/systems/si/units.h>`

src/systems/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ add_mp_units_module(
4141
include/mp-units/systems/isq/space_and_time.h
4242
include/mp-units/systems/isq/thermodynamics.h
4343
include/mp-units/systems/si/constants.h
44+
include/mp-units/systems/si/core.h
4445
include/mp-units/systems/si/prefixes.h
4546
include/mp-units/systems/si/unit_symbols.h
4647
include/mp-units/systems/si/units.h
@@ -77,6 +78,7 @@ if(NOT MP_UNITS_API_FREESTANDING)
7778
include/mp-units/systems/angular/math.h
7879
include/mp-units/systems/si/math.h
7980
include/mp-units/systems/si/chrono.h
81+
include/mp-units/systems/si/prefix_utils.h
8082
)
8183
endif()
8284

src/systems/include/mp-units/systems/si.h

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,8 @@
2828
#if MP_UNITS_HOSTED
2929
#include <mp-units/systems/si/chrono.h>
3030
#include <mp-units/systems/si/math.h>
31+
#include <mp-units/systems/si/prefix_utils.h>
3132
#endif
32-
#include <mp-units/systems/si/constants.h>
33-
#include <mp-units/systems/si/prefixes.h>
33+
#include <mp-units/systems/si/core.h>
3434
#include <mp-units/systems/si/unit_symbols.h>
35-
#include <mp-units/systems/si/units.h>
36-
37-
#ifndef MP_UNITS_IN_MODULE_INTERFACE
38-
#include <mp-units/framework.h>
39-
#endif
4035
// IWYU pragma: end_exports
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// The MIT License (MIT)
2+
//
3+
// Copyright (c) 2018 Mateusz Pusz
4+
//
5+
// Permission is hereby granted, free of charge, to any person obtaining a copy
6+
// of this software and associated documentation files (the "Software"), to deal
7+
// in the Software without restriction, including without limitation the rights
8+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
// copies of the Software, and to permit persons to whom the Software is
10+
// furnished to do so, subject to the following conditions:
11+
//
12+
// The above copyright notice and this permission notice shall be included in all
13+
// copies or substantial portions of the Software.
14+
//
15+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
// SOFTWARE.
22+
23+
#pragma once
24+
25+
#include <mp-units/bits/hacks.h>
26+
27+
// IWYU pragma: begin_exports
28+
#include <mp-units/systems/si/constants.h>
29+
#include <mp-units/systems/si/prefixes.h>
30+
#include <mp-units/systems/si/units.h>
31+
32+
#ifndef MP_UNITS_IN_MODULE_INTERFACE
33+
#include <mp-units/framework.h>
34+
#endif
35+
// IWYU pragma: end_exports

src/systems/include/mp-units/systems/si/math.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
#include <mp-units/bits/requires_hosted.h>
2626
//
2727
#include <mp-units/bits/module_macros.h>
28-
#include <mp-units/systems/isq/space_and_time.h>
28+
#include <mp-units/systems/isq/si_quantities.h>
2929
#include <mp-units/systems/si/units.h>
3030

3131
#ifndef MP_UNITS_IN_MODULE_INTERFACE
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
// The MIT License (MIT)
2+
//
3+
// Copyright (c) 2018 Mateusz Pusz
4+
//
5+
// Permission is hereby granted, free of charge, to any person obtaining a copy
6+
// of this software and associated documentation files (the "Software"), to deal
7+
// in the Software without restriction, including without limitation the rights
8+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
// copies of the Software, and to permit persons to whom the Software is
10+
// furnished to do so, subject to the following conditions:
11+
//
12+
// The above copyright notice and this permission notice shall be included in all
13+
// copies or substantial portions of the Software.
14+
//
15+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
// SOFTWARE.
22+
23+
#pragma once
24+
25+
#include <mp-units/bits/module_macros.h>
26+
#include <mp-units/systems/si/prefixes.h>
27+
28+
#ifndef MP_UNITS_IN_MODULE_INTERFACE
29+
#if MP_UNITS_HOSTED
30+
#ifdef MP_UNITS_IMPORT_STD
31+
import std;
32+
#else
33+
#include <cmath>
34+
#endif // MP_UNITS_IMPORT_STD
35+
#endif // MP_UNITS_HOSTED
36+
#endif // MP_UNITS_IN_MODULE_INTERFACE
37+
38+
namespace mp_units::si {
39+
40+
MP_UNITS_EXPORT_BEGIN
41+
42+
#if MP_UNITS_HOSTED
43+
44+
enum class prefix_range : std::uint8_t { engineering, full };
45+
46+
/**
47+
* @brief Calls an invocable with a quantity scaled to an automatically selected SI prefix
48+
*
49+
* Selects an SI prefix such that the integral part of the quantity's numerical value
50+
* has at least @c min_integral_digits digits.
51+
*
52+
* @tparam Q Quantity type
53+
* @tparam Func Invocable type that accepts a quantity
54+
* @tparam U PrefixableUnit type
55+
*
56+
* @param func Invocable to call with the scaled quantity
57+
* @param q Quantity to scale
58+
* @param u Unit to use as the base for prefix selection
59+
* @param range Prefix selection mode:
60+
* - @c prefix_range::engineering selects only powers of 1000 (kilo, mega, milli, etc.),
61+
* resulting in values in range [1.0, 1000)
62+
* - @c prefix_range::full selects all SI prefixes including deca, hecto, deci, centi,
63+
* resulting in values in range [1.0, 10.0)
64+
* @param min_integral_digits Minimum number of digits in the integral part (default: 1)
65+
*
66+
* @return The result of calling @c func with the scaled quantity
67+
*
68+
* @note For @c min_integral_digits=1:
69+
* - engineering mode: values displayed in range [1.0, 999.999...]
70+
* - full mode: values displayed in range [1.0, 9.999...]
71+
*/
72+
template<Quantity Q, std::invocable<Q> Func, PrefixableUnit U, auto Character = quantity_character::real_scalar>
73+
requires RepresentationOf<typename Q::rep, Character> && treat_as_floating_point<typename Q::rep> &&
74+
requires(Q::rep v) {
75+
requires requires { abs(v); } || requires { std::abs(v); };
76+
requires requires { log10(v); } || requires { std::log10(v); };
77+
requires requires { floor(v); } || requires { std::floor(v); };
78+
}
79+
constexpr decltype(auto) invoke_with_prefixed(Func func, Q q, U u, prefix_range range = prefix_range::engineering,
80+
int min_integral_digits = 1)
81+
{
82+
if (q == 0) return func(q.in(u));
83+
84+
using std::abs, std::log10, std::floor;
85+
86+
// Calculate the order of magnitude to determine appropriate prefix
87+
const auto value = q.numerical_value_in(u);
88+
const auto mag = static_cast<int>(floor(log10(abs(value))));
89+
90+
// Exponent ensures value has at least min_integral_digits in integral part
91+
// For min_integral_digits=1: select prefix giving value in [1, base) where base is 1000 or 10
92+
const int exponent = mag - (min_integral_digits - 1);
93+
94+
// Try each SI prefix from largest to smallest
95+
// clang-format off
96+
if (exponent >= 30) return func(q.in(si::quetta<U{}>));
97+
else if (exponent >= 27) return func(q.in(si::ronna<U{}>));
98+
else if (exponent >= 24) return func(q.in(si::yotta<U{}>));
99+
else if (exponent >= 21) return func(q.in(si::zetta<U{}>));
100+
else if (exponent >= 18) return func(q.in(si::exa<U{}>));
101+
else if (exponent >= 15) return func(q.in(si::peta<U{}>));
102+
else if (exponent >= 12) return func(q.in(si::tera<U{}>));
103+
else if (exponent >= 9) return func(q.in(si::giga<U{}>));
104+
else if (exponent >= 6) return func(q.in(si::mega<U{}>));
105+
else if (exponent >= 3) return func(q.in(si::kilo<U{}>));
106+
else if (exponent >= 2 && range == prefix_range::full) return func(q.in(si::hecto<U{}>));
107+
else if (exponent >= 1 && range == prefix_range::full) return func(q.in(si::deca<U{}>));
108+
else if (exponent >= 0) return func(q.in(U{}));
109+
else if (exponent >= -1 && range == prefix_range::full) return func(q.in(si::deci<U{}>));
110+
else if (exponent >= -2 && range == prefix_range::full) return func(q.in(si::centi<U{}>));
111+
else if (exponent >= -3) return func(q.in(si::milli<U{}>));
112+
else if (exponent >= -6) return func(q.in(si::micro<U{}>));
113+
else if (exponent >= -9) return func(q.in(si::nano<U{}>));
114+
else if (exponent >= -12) return func(q.in(si::pico<U{}>));
115+
else if (exponent >= -15) return func(q.in(si::femto<U{}>));
116+
else if (exponent >= -18) return func(q.in(si::atto<U{}>));
117+
else if (exponent >= -21) return func(q.in(si::zepto<U{}>));
118+
else if (exponent >= -24) return func(q.in(si::yocto<U{}>));
119+
else if (exponent >= -27) return func(q.in(si::ronto<U{}>));
120+
else return func(q.in(si::quecto<U{}>));
121+
// clang-format on
122+
}
123+
124+
#endif // MP_UNITS_HOSTED
125+
126+
MP_UNITS_EXPORT_END
127+
128+
} // namespace mp_units::si

src/systems/include/mp-units/systems/si/prefixes.h

Lines changed: 0 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,6 @@
2626

2727
#ifndef MP_UNITS_IN_MODULE_INTERFACE
2828
#include <mp-units/framework/unit.h>
29-
#if MP_UNITS_HOSTED
30-
#ifdef MP_UNITS_IMPORT_STD
31-
import std;
32-
#else
33-
#include <cmath>
34-
#endif // MP_UNITS_IMPORT_STD
35-
#endif // MP_UNITS_HOSTED
3629
#endif // MP_UNITS_IN_MODULE_INTERFACE
3730

3831
namespace mp_units::si {
@@ -91,90 +84,6 @@ template<PrefixableUnit auto U> constexpr ronna_<MP_UNITS_REMOVE_CONST(decltype(
9184
template<PrefixableUnit auto U> constexpr quetta_<MP_UNITS_REMOVE_CONST(decltype(U))> quetta;
9285
// clang-format on
9386

94-
#if MP_UNITS_HOSTED
95-
96-
enum class prefix_range : std::uint8_t { engineering, full };
97-
98-
/**
99-
* @brief Calls an invocable with a quantity scaled to an automatically selected SI prefix
100-
*
101-
* Selects an SI prefix such that the integral part of the quantity's numerical value
102-
* has at least @c min_integral_digits digits.
103-
*
104-
* @tparam Q Quantity type
105-
* @tparam Func Invocable type that accepts a quantity
106-
* @tparam U PrefixableUnit type
107-
*
108-
* @param func Invocable to call with the scaled quantity
109-
* @param q Quantity to scale
110-
* @param u Unit to use as the base for prefix selection
111-
* @param range Prefix selection mode:
112-
* - @c prefix_range::engineering selects only powers of 1000 (kilo, mega, milli, etc.),
113-
* resulting in values in range [1.0, 1000)
114-
* - @c prefix_range::full selects all SI prefixes including deca, hecto, deci, centi,
115-
* resulting in values in range [1.0, 10.0)
116-
* @param min_integral_digits Minimum number of digits in the integral part (default: 1)
117-
*
118-
* @return The result of calling @c func with the scaled quantity
119-
*
120-
* @note For @c min_integral_digits=1:
121-
* - engineering mode: values displayed in range [1.0, 999.999...]
122-
* - full mode: values displayed in range [1.0, 9.999...]
123-
*/
124-
template<Quantity Q, std::invocable<Q> Func, PrefixableUnit U, auto Character = quantity_character::real_scalar>
125-
requires RepresentationOf<typename Q::rep, Character> && treat_as_floating_point<typename Q::rep> &&
126-
requires(Q::rep v) {
127-
requires requires { abs(v); } || requires { std::abs(v); };
128-
requires requires { log10(v); } || requires { std::log10(v); };
129-
requires requires { floor(v); } || requires { std::floor(v); };
130-
}
131-
constexpr decltype(auto) invoke_with_prefixed(Func func, Q q, U u, prefix_range range = prefix_range::engineering,
132-
int min_integral_digits = 1)
133-
{
134-
if (q == 0) return func(q.in(u));
135-
136-
using std::abs, std::log10, std::floor;
137-
138-
// Calculate the order of magnitude to determine appropriate prefix
139-
const auto value = q.numerical_value_in(u);
140-
const auto mag = static_cast<int>(floor(log10(abs(value))));
141-
142-
// Exponent ensures value has at least min_integral_digits in integral part
143-
// For min_integral_digits=1: select prefix giving value in [1, base) where base is 1000 or 10
144-
const int exponent = mag - (min_integral_digits - 1);
145-
146-
// Try each SI prefix from largest to smallest
147-
// clang-format off
148-
if (exponent >= 30) return func(q.in(si::quetta<U{}>));
149-
else if (exponent >= 27) return func(q.in(si::ronna<U{}>));
150-
else if (exponent >= 24) return func(q.in(si::yotta<U{}>));
151-
else if (exponent >= 21) return func(q.in(si::zetta<U{}>));
152-
else if (exponent >= 18) return func(q.in(si::exa<U{}>));
153-
else if (exponent >= 15) return func(q.in(si::peta<U{}>));
154-
else if (exponent >= 12) return func(q.in(si::tera<U{}>));
155-
else if (exponent >= 9) return func(q.in(si::giga<U{}>));
156-
else if (exponent >= 6) return func(q.in(si::mega<U{}>));
157-
else if (exponent >= 3) return func(q.in(si::kilo<U{}>));
158-
else if (exponent >= 2 && range == prefix_range::full) return func(q.in(si::hecto<U{}>));
159-
else if (exponent >= 1 && range == prefix_range::full) return func(q.in(si::deca<U{}>));
160-
else if (exponent >= 0) return func(q.in(U{}));
161-
else if (exponent >= -1 && range == prefix_range::full) return func(q.in(si::deci<U{}>));
162-
else if (exponent >= -2 && range == prefix_range::full) return func(q.in(si::centi<U{}>));
163-
else if (exponent >= -3) return func(q.in(si::milli<U{}>));
164-
else if (exponent >= -6) return func(q.in(si::micro<U{}>));
165-
else if (exponent >= -9) return func(q.in(si::nano<U{}>));
166-
else if (exponent >= -12) return func(q.in(si::pico<U{}>));
167-
else if (exponent >= -15) return func(q.in(si::femto<U{}>));
168-
else if (exponent >= -18) return func(q.in(si::atto<U{}>));
169-
else if (exponent >= -21) return func(q.in(si::zepto<U{}>));
170-
else if (exponent >= -24) return func(q.in(si::yocto<U{}>));
171-
else if (exponent >= -27) return func(q.in(si::ronto<U{}>));
172-
else return func(q.in(si::quecto<U{}>));
173-
// clang-format on
174-
}
175-
176-
#endif // MP_UNITS_HOSTED
177-
17887
MP_UNITS_EXPORT_END
17988

18089
} // namespace mp_units::si

0 commit comments

Comments
 (0)