mirror of
https://github.com/mpusz/mp-units.git
synced 2025-07-30 18:37:15 +02:00
feat: initial very dirty version of V2 framework
This commit is contained in:
@ -44,6 +44,7 @@ add_compile_definitions($<$<CONFIG:Debug>:gsl_CONFIG_CONTRACT_CHECKING_AUDIT>)
|
|||||||
|
|
||||||
# enable include-what-you-use
|
# enable include-what-you-use
|
||||||
option(${projectPrefix}IWYU "Enables include-what-you-use" OFF)
|
option(${projectPrefix}IWYU "Enables include-what-you-use" OFF)
|
||||||
|
|
||||||
if(${projectPrefix}IWYU)
|
if(${projectPrefix}IWYU)
|
||||||
include(include-what-you-use)
|
include(include-what-you-use)
|
||||||
enable_iwyu(
|
enable_iwyu(
|
||||||
@ -52,12 +53,13 @@ if(${projectPrefix}IWYU)
|
|||||||
MAX_LINE_LENGTH 120
|
MAX_LINE_LENGTH 120
|
||||||
NO_COMMENTS
|
NO_COMMENTS
|
||||||
)
|
)
|
||||||
|
|
||||||
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||||
set(${projectPrefix}AS_SYSTEM_HEADERS ON)
|
set(${projectPrefix}AS_SYSTEM_HEADERS ON)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
#enable_clang_tidy()
|
# enable_clang_tidy()
|
||||||
|
|
||||||
# add project code
|
# add project code
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
@ -66,11 +68,12 @@ add_subdirectory(src)
|
|||||||
add_subdirectory(example)
|
add_subdirectory(example)
|
||||||
|
|
||||||
# generate project documentation
|
# generate project documentation
|
||||||
add_subdirectory(docs)
|
# add_subdirectory(docs)
|
||||||
|
|
||||||
# add unit tests
|
# add unit tests
|
||||||
enable_testing()
|
enable_testing()
|
||||||
add_subdirectory(test)
|
|
||||||
|
# add_subdirectory(test)
|
||||||
|
|
||||||
# tests for standalone headers
|
# tests for standalone headers
|
||||||
include(TestPublicHeaders)
|
include(TestPublicHeaders)
|
||||||
|
@ -33,17 +33,19 @@ function(add_example target)
|
|||||||
target_link_libraries(${target} PRIVATE ${ARGN})
|
target_link_libraries(${target} PRIVATE ${ARGN})
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
add_example(conversion_factor mp-units::core-fmt mp-units::core-io mp-units::si)
|
add_example(v2_framework mp-units::core-fmt mp-units::core-io mp-units::si)
|
||||||
add_example(custom_systems mp-units::core-io mp-units::si)
|
|
||||||
add_example(hello_units mp-units::core-fmt mp-units::core-io mp-units::si mp-units::si-international)
|
|
||||||
add_example(measurement mp-units::core-io mp-units::si)
|
|
||||||
add_example(si_constants mp-units::core-fmt mp-units::si)
|
|
||||||
|
|
||||||
if(NOT ${projectPrefix}LIBCXX)
|
# add_example(conversion_factor mp-units::core-fmt mp-units::core-io mp-units::si)
|
||||||
add_subdirectory(glide_computer)
|
# add_example(custom_systems mp-units::core-io mp-units::si)
|
||||||
endif()
|
# add_example(hello_units mp-units::core-fmt mp-units::core-io mp-units::si mp-units::si-international)
|
||||||
|
# add_example(measurement mp-units::core-io mp-units::si)
|
||||||
|
# add_example(si_constants mp-units::core-fmt mp-units::si)
|
||||||
|
|
||||||
add_subdirectory(aliases)
|
# if(NOT ${projectPrefix}LIBCXX)
|
||||||
add_subdirectory(kalman_filter)
|
# add_subdirectory(glide_computer)
|
||||||
add_subdirectory(literals)
|
# endif()
|
||||||
add_subdirectory(references)
|
|
||||||
|
# add_subdirectory(aliases)
|
||||||
|
# add_subdirectory(kalman_filter)
|
||||||
|
# add_subdirectory(literals)
|
||||||
|
# add_subdirectory(references)
|
||||||
|
@ -20,43 +20,391 @@
|
|||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
// SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
#include <units/format.h>
|
// #include <units/concepts.h>
|
||||||
#include <units/isq/si/international/length.h>
|
#include <units/dimension.h>
|
||||||
#include <units/isq/si/international/speed.h> // IWYU pragma: keep
|
|
||||||
#include <units/isq/si/length.h>
|
|
||||||
#include <units/isq/si/speed.h> // IWYU pragma: keep
|
|
||||||
#include <units/isq/si/time.h>
|
|
||||||
#include <units/quantity_io.h>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
using namespace units::isq;
|
namespace units::isq {
|
||||||
|
|
||||||
constexpr Speed auto avg_speed(Length auto d, Time auto t) { return d / t; }
|
inline constexpr struct dim_length : base_dimension<"L"> {
|
||||||
|
} dim_length;
|
||||||
|
|
||||||
|
// template<typename T>
|
||||||
|
// concept Length = QuantityOf<T, dim_length>;
|
||||||
|
|
||||||
|
inline constexpr struct dim_time : base_dimension<"T"> {
|
||||||
|
} dim_time;
|
||||||
|
inline constexpr struct dim_frequency : decltype(1 / dim_time) {
|
||||||
|
} dim_frequency;
|
||||||
|
inline constexpr struct dim_area : decltype(dim_length * dim_length) {
|
||||||
|
} dim_area;
|
||||||
|
inline constexpr struct dim_volume : decltype(dim_area * dim_length) {
|
||||||
|
} dim_volume;
|
||||||
|
inline constexpr struct dim_speed : decltype(dim_length / dim_time) {
|
||||||
|
} dim_speed;
|
||||||
|
inline constexpr struct dim_acceleration : decltype(dim_speed / dim_time) {
|
||||||
|
} dim_acceleration;
|
||||||
|
|
||||||
|
// inline constexpr auto speed = length / time;
|
||||||
|
|
||||||
|
} // namespace units::isq
|
||||||
|
|
||||||
|
#include <units/isq/si/prefixes.h>
|
||||||
|
#include <units/unit.h>
|
||||||
|
|
||||||
|
namespace units {
|
||||||
|
|
||||||
|
namespace isq::si {
|
||||||
|
|
||||||
|
// length units
|
||||||
|
inline constexpr struct metre : named_unit<"m"> {
|
||||||
|
} metre;
|
||||||
|
inline constexpr struct kilometre : kilo<metre> {
|
||||||
|
} kilometre;
|
||||||
|
|
||||||
|
inline constexpr struct astronomical_unit : named_scaled_unit<"au", mag<149'597'870'700>(), metre> {
|
||||||
|
} astronomical_unit;
|
||||||
|
|
||||||
|
// area units
|
||||||
|
inline constexpr struct square_metre : derived_unit<decltype(metre * metre)> {
|
||||||
|
} square_metre;
|
||||||
|
|
||||||
|
// volume units
|
||||||
|
inline constexpr struct cubic_metre : derived_unit<decltype(square_metre * metre)> {
|
||||||
|
} cubic_metre;
|
||||||
|
|
||||||
|
// time units
|
||||||
|
inline constexpr struct second : named_unit<"s"> {
|
||||||
|
} second;
|
||||||
|
inline constexpr struct minute : named_scaled_unit<"min", mag<60>(), second> {
|
||||||
|
} minute;
|
||||||
|
inline constexpr struct hour : named_scaled_unit<"h", mag<60>(), minute> {
|
||||||
|
} hour;
|
||||||
|
inline constexpr struct day : named_scaled_unit<"d", mag<24>(), hour> {
|
||||||
|
} day;
|
||||||
|
|
||||||
|
// not a time unit!
|
||||||
|
inline constexpr struct second_squared : derived_unit<decltype(second * second)> {
|
||||||
|
} second_squared;
|
||||||
|
|
||||||
|
// mass units
|
||||||
|
inline constexpr struct gram : named_unit<"g"> {
|
||||||
|
} gram;
|
||||||
|
inline constexpr struct kilogram : kilo<gram> {
|
||||||
|
} kilogram;
|
||||||
|
inline constexpr struct tonne : named_scaled_unit<"t", mag<1000>(), gram> {
|
||||||
|
} tonne;
|
||||||
|
|
||||||
|
// other units
|
||||||
|
inline constexpr struct hertz : named_unit<"Hz", 1 / second> {
|
||||||
|
} hertz;
|
||||||
|
inline constexpr struct newton : named_unit<"N", kilogram * metre / second_squared> {
|
||||||
|
} newton;
|
||||||
|
inline constexpr struct pascal : named_unit<"Pa", kilogram / (metre * second_squared)> {
|
||||||
|
} pascal;
|
||||||
|
inline constexpr struct joule : named_unit<"J", newton * metre> {
|
||||||
|
} joule;
|
||||||
|
inline constexpr struct watt : named_unit<"W", joule / second> {
|
||||||
|
} watt;
|
||||||
|
|
||||||
|
namespace short_units {
|
||||||
|
|
||||||
|
// TODO collide with reference names
|
||||||
|
// inline namespace length {
|
||||||
|
|
||||||
|
inline constexpr auto m = metre;
|
||||||
|
inline constexpr auto km = kilometre;
|
||||||
|
inline constexpr auto au = astronomical_unit;
|
||||||
|
|
||||||
|
// } // namespace length
|
||||||
|
|
||||||
|
// inline namespace area {
|
||||||
|
|
||||||
|
inline constexpr auto m2 = square_metre;
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// inline namespace volume {
|
||||||
|
|
||||||
|
inline constexpr auto m3 = cubic_metre;
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// inline namespace time {
|
||||||
|
|
||||||
|
inline constexpr auto s = second;
|
||||||
|
inline constexpr auto min = minute;
|
||||||
|
inline constexpr auto h = hour;
|
||||||
|
inline constexpr auto d = day;
|
||||||
|
|
||||||
|
inline constexpr auto s2 = second_squared;
|
||||||
|
|
||||||
|
// } // namespace time
|
||||||
|
|
||||||
|
// inline namespace mass {
|
||||||
|
|
||||||
|
inline constexpr auto g = gram;
|
||||||
|
inline constexpr auto kg = kilogram;
|
||||||
|
inline constexpr auto t = tonne;
|
||||||
|
|
||||||
|
// } // namespace mass
|
||||||
|
|
||||||
|
// inline namespace frequency {
|
||||||
|
|
||||||
|
inline constexpr auto Hz = hertz;
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// inline namespace force {
|
||||||
|
|
||||||
|
inline constexpr auto N = newton;
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// inline namespace pressure {
|
||||||
|
|
||||||
|
inline constexpr auto Pa = pascal;
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// inline namespace energy {
|
||||||
|
|
||||||
|
inline constexpr auto J = joule;
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// inline namespace power {
|
||||||
|
|
||||||
|
inline constexpr auto W = watt;
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
} // namespace short_units
|
||||||
|
|
||||||
|
} // namespace isq::si
|
||||||
|
} // namespace units
|
||||||
|
|
||||||
|
#include <units/system_reference.h>
|
||||||
|
|
||||||
|
namespace units::isq::si {
|
||||||
|
|
||||||
|
inline constexpr struct length : system_reference<length, dim_length, metre> {
|
||||||
|
} length;
|
||||||
|
inline constexpr struct time : system_reference<time, dim_time, second> {
|
||||||
|
} time;
|
||||||
|
inline constexpr struct frequency : system_reference<frequency, dim_frequency, hertz> {
|
||||||
|
} frequency;
|
||||||
|
inline constexpr struct area : system_reference<area, dim_area, square_metre> {
|
||||||
|
} area;
|
||||||
|
inline constexpr struct volume : system_reference<volume, dim_volume, cubic_metre> {
|
||||||
|
} volume;
|
||||||
|
inline constexpr struct speed : system_reference<speed, dim_speed, metre / second> {
|
||||||
|
} speed;
|
||||||
|
inline constexpr struct acceleration : system_reference<acceleration, dim_acceleration, metre / second / second> {
|
||||||
|
} acceleration;
|
||||||
|
|
||||||
|
} // namespace units::isq::si
|
||||||
|
|
||||||
|
|
||||||
|
template<auto V, typename T>
|
||||||
|
inline constexpr bool is_of_type = std::is_same_v<std::remove_cvref_t<decltype(V)>, T>;
|
||||||
|
|
||||||
|
namespace units::isq {
|
||||||
|
|
||||||
|
// derived dimension expression template syntax verification
|
||||||
|
static_assert(is_of_type<1 / dim_time, derived_dimension<struct dim_one, per<struct dim_time>>>);
|
||||||
|
static_assert(is_of_type<1 / (1 / dim_time), struct dim_time>);
|
||||||
|
|
||||||
|
static_assert(is_of_type<dim_one * dim_time, struct dim_time>);
|
||||||
|
static_assert(is_of_type<dim_time * dim_one, struct dim_time>);
|
||||||
|
static_assert(is_of_type<dim_one * (1 / dim_time), derived_dimension<struct dim_one, per<struct dim_time>>>);
|
||||||
|
static_assert(is_of_type<1 / dim_time * dim_one, derived_dimension<struct dim_one, per<struct dim_time>>>);
|
||||||
|
|
||||||
|
static_assert(is_of_type<dim_length * dim_time, derived_dimension<struct dim_length, struct dim_time>>);
|
||||||
|
static_assert(is_of_type<dim_length * dim_length, derived_dimension<power<struct dim_length, 2>>>);
|
||||||
|
|
||||||
|
static_assert(
|
||||||
|
is_of_type<dim_length * dim_length * dim_time, derived_dimension<power<struct dim_length, 2>, struct dim_time>>);
|
||||||
|
static_assert(
|
||||||
|
is_of_type<dim_length * dim_time * dim_length, derived_dimension<power<struct dim_length, 2>, struct dim_time>>);
|
||||||
|
|
||||||
|
static_assert(
|
||||||
|
is_of_type<dim_length*(dim_time* dim_length), derived_dimension<power<struct dim_length, 2>, struct dim_time>>);
|
||||||
|
static_assert(
|
||||||
|
is_of_type<dim_time*(dim_length* dim_length), derived_dimension<power<struct dim_length, 2>, struct dim_time>>);
|
||||||
|
|
||||||
|
static_assert(is_of_type<1 / dim_time * dim_length, derived_dimension<struct dim_length, per<struct dim_time>>>);
|
||||||
|
static_assert(is_of_type<1 / dim_time * dim_time, struct dim_one>);
|
||||||
|
|
||||||
|
static_assert(is_of_type<dim_time / dim_one, struct dim_time>);
|
||||||
|
static_assert(is_of_type<1 / dim_time / dim_one, derived_dimension<struct dim_one, per<struct dim_time>>>);
|
||||||
|
|
||||||
|
static_assert(is_of_type<dim_length / dim_time * dim_time, struct dim_length>);
|
||||||
|
static_assert(
|
||||||
|
is_of_type<1 / dim_time * (1 / dim_time), derived_dimension<struct dim_one, per<power<struct dim_time, 2>>>>);
|
||||||
|
static_assert(is_of_type<1 / (dim_time * dim_time), derived_dimension<struct dim_one, per<power<struct dim_time, 2>>>>);
|
||||||
|
static_assert(is_of_type<1 / (1 / (dim_time * dim_time)), derived_dimension<power<struct dim_time, 2>>>);
|
||||||
|
|
||||||
|
static_assert(is_of_type<dim_length / dim_time * (1 / dim_time),
|
||||||
|
derived_dimension<struct dim_length, per<power<struct dim_time, 2>>>>);
|
||||||
|
static_assert(is_of_type<dim_length / dim_time*(dim_length / dim_time),
|
||||||
|
derived_dimension<power<struct dim_length, 2>, per<power<struct dim_time, 2>>>>);
|
||||||
|
static_assert(is_of_type<dim_length / dim_time*(dim_time / dim_length), struct dim_one>);
|
||||||
|
|
||||||
|
static_assert(
|
||||||
|
is_of_type<dim_speed / dim_acceleration, derived_dimension<struct dim_speed, per<struct dim_acceleration>>>);
|
||||||
|
static_assert(
|
||||||
|
is_of_type<dim_acceleration / dim_speed, derived_dimension<struct dim_acceleration, per<struct dim_speed>>>);
|
||||||
|
static_assert(is_of_type<dim_speed * dim_speed / dim_length,
|
||||||
|
derived_dimension<power<struct dim_speed, 2>, per<struct dim_length>>>);
|
||||||
|
static_assert(is_of_type<1 / (dim_speed * dim_speed) * dim_length,
|
||||||
|
derived_dimension<struct dim_length, per<power<struct dim_speed, 2>>>>);
|
||||||
|
|
||||||
|
// comparisons of equivalent dimensions
|
||||||
|
static_assert(dim_length / dim_length == dim_one);
|
||||||
|
|
||||||
|
static_assert(1 / dim_time == dim_frequency);
|
||||||
|
static_assert(1 / dim_frequency == dim_time);
|
||||||
|
static_assert(dim_frequency * dim_time == dim_one);
|
||||||
|
|
||||||
|
static_assert(dim_length * dim_length == dim_area);
|
||||||
|
static_assert(dim_length * dim_length != dim_volume);
|
||||||
|
static_assert(dim_area / dim_length == dim_length);
|
||||||
|
|
||||||
|
static_assert(dim_length * dim_length * dim_length == dim_volume);
|
||||||
|
static_assert(dim_area * dim_length == dim_volume);
|
||||||
|
static_assert(dim_volume / dim_length == dim_area);
|
||||||
|
static_assert(dim_volume / dim_length / dim_length == dim_length);
|
||||||
|
static_assert(dim_area * dim_area / dim_length == dim_volume);
|
||||||
|
static_assert(dim_area * (dim_area / dim_length) == dim_volume);
|
||||||
|
static_assert(dim_volume / (dim_length * dim_length) == dim_length);
|
||||||
|
|
||||||
|
static_assert(dim_length / dim_time == dim_speed);
|
||||||
|
static_assert(dim_length * dim_time != dim_speed);
|
||||||
|
static_assert(dim_length / dim_time / dim_time != dim_speed);
|
||||||
|
static_assert(dim_length / dim_speed == dim_time);
|
||||||
|
static_assert(dim_speed * dim_time == dim_length);
|
||||||
|
|
||||||
|
static_assert(dim_length / dim_time / dim_time == dim_acceleration);
|
||||||
|
static_assert(dim_length / (dim_time * dim_time) == dim_acceleration);
|
||||||
|
static_assert(dim_speed / dim_time == dim_acceleration);
|
||||||
|
static_assert(dim_speed / dim_acceleration == dim_time);
|
||||||
|
static_assert(dim_acceleration * dim_time == dim_speed);
|
||||||
|
static_assert(dim_acceleration * (dim_time * dim_time) == dim_length);
|
||||||
|
static_assert(dim_acceleration / dim_speed == dim_frequency);
|
||||||
|
|
||||||
|
} // namespace units::isq
|
||||||
|
|
||||||
|
|
||||||
|
namespace units::isq::si {
|
||||||
|
|
||||||
|
// derived unit expression template syntax verification
|
||||||
|
static_assert(is_of_type<1 / second, derived_unit<struct one, per<struct second>>>);
|
||||||
|
static_assert(is_of_type<1 / (1 / second), struct second>);
|
||||||
|
|
||||||
|
static_assert(is_of_type<one * second, struct second>);
|
||||||
|
static_assert(is_of_type<second * one, struct second>);
|
||||||
|
static_assert(is_of_type<one * (1 / second), derived_unit<struct one, per<struct second>>>);
|
||||||
|
static_assert(is_of_type<1 / second * one, derived_unit<struct one, per<struct second>>>);
|
||||||
|
|
||||||
|
static_assert(is_of_type<metre * second, derived_unit<struct metre, struct second>>);
|
||||||
|
static_assert(is_of_type<metre * metre, derived_unit<power<struct metre, 2>>>);
|
||||||
|
|
||||||
|
static_assert(is_of_type<metre * metre * second, derived_unit<power<struct metre, 2>, struct second>>);
|
||||||
|
static_assert(is_of_type<metre * second * metre, derived_unit<power<struct metre, 2>, struct second>>);
|
||||||
|
|
||||||
|
static_assert(is_of_type<metre*(second* metre), derived_unit<power<struct metre, 2>, struct second>>);
|
||||||
|
static_assert(is_of_type<second*(metre* metre), derived_unit<power<struct metre, 2>, struct second>>);
|
||||||
|
|
||||||
|
static_assert(is_of_type<1 / second * metre, derived_unit<struct metre, per<struct second>>>);
|
||||||
|
static_assert(is_of_type<1 / second * second, struct one>);
|
||||||
|
|
||||||
|
static_assert(is_of_type<second / one, struct second>);
|
||||||
|
static_assert(is_of_type<1 / second / one, derived_unit<struct one, per<struct second>>>);
|
||||||
|
|
||||||
|
static_assert(is_of_type<metre / second * second, struct metre>);
|
||||||
|
static_assert(is_of_type<1 / second * (1 / second), derived_unit<struct one, per<power<struct second, 2>>>>);
|
||||||
|
static_assert(is_of_type<1 / (second * second), derived_unit<struct one, per<power<struct second, 2>>>>);
|
||||||
|
static_assert(is_of_type<1 / (1 / (second * second)), derived_unit<power<struct second, 2>>>);
|
||||||
|
|
||||||
|
static_assert(is_of_type<metre / second * (1 / second), derived_unit<struct metre, per<power<struct second, 2>>>>);
|
||||||
|
static_assert(
|
||||||
|
is_of_type<metre / second*(metre / second), derived_unit<power<struct metre, 2>, per<power<struct second, 2>>>>);
|
||||||
|
static_assert(is_of_type<metre / second*(second / metre), struct one>);
|
||||||
|
|
||||||
|
static_assert(is_of_type<watt / joule, derived_unit<struct watt, per<struct joule>>>);
|
||||||
|
static_assert(is_of_type<joule / watt, derived_unit<struct joule, per<struct watt>>>);
|
||||||
|
|
||||||
|
// comparisons of equivalent dimensions
|
||||||
|
// static_assert(metre / metre == one);
|
||||||
|
|
||||||
|
// static_assert(1 / second == dim_frequency);
|
||||||
|
// static_assert(1 / dim_frequency == second);
|
||||||
|
// static_assert(dim_frequency * second == one);
|
||||||
|
|
||||||
|
// static_assert(metre * metre == dim_area);
|
||||||
|
// static_assert(metre * metre != dim_volume);
|
||||||
|
// static_assert(dim_area / metre == metre);
|
||||||
|
|
||||||
|
// static_assert(metre * metre * metre == dim_volume);
|
||||||
|
// static_assert(dim_area * metre == dim_volume);
|
||||||
|
// static_assert(dim_volume / metre == dim_area);
|
||||||
|
// static_assert(dim_volume / metre / metre == metre);
|
||||||
|
// static_assert(dim_area * dim_area / metre == dim_volume);
|
||||||
|
// static_assert(dim_area * (dim_area / metre) == dim_volume);
|
||||||
|
// static_assert(dim_volume / (metre * metre) == metre);
|
||||||
|
|
||||||
|
// static_assert(metre / second == dim_speed);
|
||||||
|
// static_assert(metre * second != dim_speed);
|
||||||
|
// static_assert(metre / second / second != dim_speed);
|
||||||
|
// static_assert(metre / dim_speed == second);
|
||||||
|
// static_assert(dim_speed * second == metre);
|
||||||
|
|
||||||
|
// static_assert(metre / second / second == dim_acceleration);
|
||||||
|
// static_assert(metre / (second * second) == dim_acceleration);
|
||||||
|
// static_assert(dim_speed / second == dim_acceleration);
|
||||||
|
// static_assert(dim_speed / dim_acceleration == second);
|
||||||
|
// static_assert(dim_acceleration * second == dim_speed);
|
||||||
|
// static_assert(dim_acceleration * (second * second) == metre);
|
||||||
|
// static_assert(dim_acceleration / dim_speed == dim_frequency);
|
||||||
|
|
||||||
|
|
||||||
|
// Bq + Hz should not compile
|
||||||
|
|
||||||
|
// Bq + Hz + 1/s should compile?
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace units::isq::si
|
||||||
|
|
||||||
|
|
||||||
|
using namespace units;
|
||||||
|
using namespace units::isq::si;
|
||||||
|
using namespace units::isq::si::short_units;
|
||||||
|
|
||||||
|
/* Frequency */ auto freq1 = 20 * frequency[Hz];
|
||||||
|
// /* Frequency */ auto freq2 = 20 / (1 * time[s]);
|
||||||
|
quantity<frequency[Hz]> freq3(20);
|
||||||
|
// quantity<frequency[1 / s]> freq4(20);
|
||||||
|
// quantity<1 / time[s]> freq5(20);
|
||||||
|
|
||||||
|
|
||||||
|
/* Speed */ auto speed1 = 20 * speed[m / s];
|
||||||
|
/* Speed */ auto speed2 = 20 * (length[m] / isq::si::time[s]);
|
||||||
|
// quantity<speed[m / s]> speed3(20);
|
||||||
|
// quantity<length[m] / time[s]> speed4(20);
|
||||||
|
|
||||||
|
|
||||||
|
// quantity<kilo<metre> / second> speed1(123);
|
||||||
|
// quantity<km / s> speed2(123);
|
||||||
|
// auto speed3 = 123 * (kilo<metre> / second);
|
||||||
|
// auto speed4 = 123 * (km / s);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void print();
|
||||||
|
|
||||||
|
// constexpr auto avg_speed(quantity<length[km]> d, quantity<isq::si::time[h]> t) { return d / t; }
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
using namespace units::isq::si::literals;
|
print<decltype(speed1)>();
|
||||||
using namespace units::isq::si::references;
|
print<decltype(speed2)>();
|
||||||
using namespace units::aliases::isq::si::international;
|
|
||||||
|
|
||||||
constexpr Speed auto v1 = 110 * (km / h);
|
|
||||||
constexpr Speed auto v2 = mi_per_h<>(70.);
|
|
||||||
constexpr Speed auto v3 = avg_speed(220_q_km, 2_q_h);
|
|
||||||
constexpr Speed auto v4 = avg_speed(si::length<si::international::mile>(140), si::time<si::hour>(2));
|
|
||||||
#if UNITS_DOWNCAST_MODE == 0
|
|
||||||
constexpr Speed auto v5 = quantity_cast<si::speed<si::metre_per_second>>(v3);
|
|
||||||
constexpr Speed auto v6 = quantity_cast<si::dim_speed, si::metre_per_second>(v4);
|
|
||||||
#else
|
|
||||||
constexpr Speed auto v5 = quantity_cast<si::speed<si::metre_per_second>>(v3);
|
|
||||||
constexpr Speed auto v6 = quantity_cast<si::metre_per_second>(v4);
|
|
||||||
#endif
|
|
||||||
constexpr Speed auto v7 = quantity_cast<int>(v6);
|
|
||||||
|
|
||||||
std::cout << v1 << '\n'; // 110 km/h
|
|
||||||
std::cout << v2 << '\n'; // 70 mi/h
|
|
||||||
std::cout << STD_FMT::format("{}", v3) << '\n'; // 110 km/h
|
|
||||||
std::cout << STD_FMT::format("{:*^14}", v4) << '\n'; // ***70 mi/h****
|
|
||||||
std::cout << STD_FMT::format("{:%Q in %q}", v5) << '\n'; // 30.5556 in m/s
|
|
||||||
std::cout << STD_FMT::format("{0:%Q} in {0:%q}", v6) << '\n'; // 31.2928 in m/s
|
|
||||||
std::cout << STD_FMT::format("{:%Q}", v7) << '\n'; // 31
|
|
||||||
}
|
}
|
||||||
|
418
example/v2_framework.cpp
Normal file
418
example/v2_framework.cpp
Normal file
@ -0,0 +1,418 @@
|
|||||||
|
// The MIT License (MIT)
|
||||||
|
//
|
||||||
|
// Copyright (c) 2018 Mateusz Pusz
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||||
|
// copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
|
||||||
|
// #include <units/concepts.h>
|
||||||
|
#include <units/dimension.h>
|
||||||
|
|
||||||
|
namespace units::isq {
|
||||||
|
|
||||||
|
inline constexpr struct dim_length : base_dimension<"L"> {
|
||||||
|
} dim_length;
|
||||||
|
|
||||||
|
// template<typename T>
|
||||||
|
// concept Length = QuantityOf<T, dim_length>;
|
||||||
|
|
||||||
|
inline constexpr struct dim_time : base_dimension<"T"> {
|
||||||
|
} dim_time;
|
||||||
|
inline constexpr struct dim_frequency : decltype(1 / dim_time) {
|
||||||
|
} dim_frequency;
|
||||||
|
inline constexpr struct dim_area : decltype(dim_length * dim_length) {
|
||||||
|
} dim_area;
|
||||||
|
inline constexpr struct dim_volume : decltype(dim_area * dim_length) {
|
||||||
|
} dim_volume;
|
||||||
|
inline constexpr struct dim_speed : decltype(dim_length / dim_time) {
|
||||||
|
} dim_speed;
|
||||||
|
inline constexpr struct dim_acceleration : decltype(dim_speed / dim_time) {
|
||||||
|
} dim_acceleration;
|
||||||
|
|
||||||
|
// inline constexpr auto speed = length / time;
|
||||||
|
|
||||||
|
} // namespace units::isq
|
||||||
|
|
||||||
|
#include <units/isq/si/prefixes.h>
|
||||||
|
#include <units/unit.h>
|
||||||
|
|
||||||
|
namespace units {
|
||||||
|
|
||||||
|
namespace isq::si {
|
||||||
|
|
||||||
|
// length units
|
||||||
|
inline constexpr struct metre : named_unit<"m"> {
|
||||||
|
} metre;
|
||||||
|
inline constexpr struct kilometre : kilo<metre> {
|
||||||
|
} kilometre;
|
||||||
|
|
||||||
|
inline constexpr struct astronomical_unit : named_scaled_unit<"au", mag<149'597'870'700>(), metre> {
|
||||||
|
} astronomical_unit;
|
||||||
|
|
||||||
|
// area units
|
||||||
|
inline constexpr struct square_metre : derived_unit<decltype(metre * metre)> {
|
||||||
|
} square_metre;
|
||||||
|
|
||||||
|
// volume units
|
||||||
|
inline constexpr struct cubic_metre : derived_unit<decltype(square_metre * metre)> {
|
||||||
|
} cubic_metre;
|
||||||
|
|
||||||
|
// time units
|
||||||
|
inline constexpr struct second : named_unit<"s"> {
|
||||||
|
} second;
|
||||||
|
inline constexpr struct minute : named_scaled_unit<"min", mag<60>(), second> {
|
||||||
|
} minute;
|
||||||
|
inline constexpr struct hour : named_scaled_unit<"h", mag<60>(), minute> {
|
||||||
|
} hour;
|
||||||
|
inline constexpr struct day : named_scaled_unit<"d", mag<24>(), hour> {
|
||||||
|
} day;
|
||||||
|
|
||||||
|
// not a time unit!
|
||||||
|
inline constexpr struct second_squared : derived_unit<decltype(second * second)> {
|
||||||
|
} second_squared;
|
||||||
|
|
||||||
|
// mass units
|
||||||
|
inline constexpr struct gram : named_unit<"g"> {
|
||||||
|
} gram;
|
||||||
|
inline constexpr struct kilogram : kilo<gram> {
|
||||||
|
} kilogram;
|
||||||
|
inline constexpr struct tonne : named_scaled_unit<"t", mag<1000>(), gram> {
|
||||||
|
} tonne;
|
||||||
|
|
||||||
|
// other units
|
||||||
|
inline constexpr struct hertz : named_unit<"Hz", 1 / second> {
|
||||||
|
} hertz;
|
||||||
|
inline constexpr struct newton : named_unit<"N", kilogram * metre / second_squared> {
|
||||||
|
} newton;
|
||||||
|
inline constexpr struct pascal : named_unit<"Pa", kilogram / (metre * second_squared)> {
|
||||||
|
} pascal;
|
||||||
|
inline constexpr struct joule : named_unit<"J", newton * metre> {
|
||||||
|
} joule;
|
||||||
|
inline constexpr struct watt : named_unit<"W", joule / second> {
|
||||||
|
} watt;
|
||||||
|
|
||||||
|
namespace short_units {
|
||||||
|
|
||||||
|
// TODO collide with reference names
|
||||||
|
// inline namespace length {
|
||||||
|
|
||||||
|
inline constexpr auto m = metre;
|
||||||
|
inline constexpr auto km = kilometre;
|
||||||
|
inline constexpr auto au = astronomical_unit;
|
||||||
|
|
||||||
|
// } // namespace length
|
||||||
|
|
||||||
|
// inline namespace area {
|
||||||
|
|
||||||
|
inline constexpr auto m2 = square_metre;
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// inline namespace volume {
|
||||||
|
|
||||||
|
inline constexpr auto m3 = cubic_metre;
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// inline namespace time {
|
||||||
|
|
||||||
|
inline constexpr auto s = second;
|
||||||
|
inline constexpr auto min = minute;
|
||||||
|
inline constexpr auto h = hour;
|
||||||
|
inline constexpr auto d = day;
|
||||||
|
|
||||||
|
inline constexpr auto s2 = second_squared;
|
||||||
|
|
||||||
|
// } // namespace time
|
||||||
|
|
||||||
|
// inline namespace mass {
|
||||||
|
|
||||||
|
inline constexpr auto g = gram;
|
||||||
|
inline constexpr auto kg = kilogram;
|
||||||
|
inline constexpr auto t = tonne;
|
||||||
|
|
||||||
|
// } // namespace mass
|
||||||
|
|
||||||
|
// inline namespace frequency {
|
||||||
|
|
||||||
|
inline constexpr auto Hz = hertz;
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// inline namespace force {
|
||||||
|
|
||||||
|
inline constexpr auto N = newton;
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// inline namespace pressure {
|
||||||
|
|
||||||
|
inline constexpr auto Pa = pascal;
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// inline namespace energy {
|
||||||
|
|
||||||
|
inline constexpr auto J = joule;
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// inline namespace power {
|
||||||
|
|
||||||
|
inline constexpr auto W = watt;
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
} // namespace short_units
|
||||||
|
|
||||||
|
} // namespace isq::si
|
||||||
|
} // namespace units
|
||||||
|
|
||||||
|
#include <units/reference.h>
|
||||||
|
|
||||||
|
namespace units {
|
||||||
|
|
||||||
|
inline constexpr struct dimensionless : system_reference<dimensionless, dim_one, one> {
|
||||||
|
} dimensionless;
|
||||||
|
|
||||||
|
} // namespace units
|
||||||
|
|
||||||
|
namespace units::isq::si {
|
||||||
|
|
||||||
|
inline constexpr struct length : system_reference<length, dim_length, metre> {
|
||||||
|
} length;
|
||||||
|
inline constexpr struct time : system_reference<time, dim_time, second> {
|
||||||
|
} time;
|
||||||
|
inline constexpr struct frequency : system_reference<frequency, dim_frequency, hertz> {
|
||||||
|
} frequency;
|
||||||
|
inline constexpr struct area : system_reference<area, dim_area, square_metre> {
|
||||||
|
} area;
|
||||||
|
inline constexpr struct volume : system_reference<volume, dim_volume, cubic_metre> {
|
||||||
|
} volume;
|
||||||
|
inline constexpr struct speed : system_reference<speed, dim_speed, metre / second> {
|
||||||
|
} speed;
|
||||||
|
inline constexpr struct acceleration : system_reference<acceleration, dim_acceleration, metre / second / second> {
|
||||||
|
} acceleration;
|
||||||
|
|
||||||
|
} // namespace units::isq::si
|
||||||
|
|
||||||
|
|
||||||
|
template<auto V, typename T>
|
||||||
|
inline constexpr bool is_of_type = std::is_same_v<std::remove_cvref_t<decltype(V)>, T>;
|
||||||
|
|
||||||
|
namespace units::isq {
|
||||||
|
|
||||||
|
// derived dimension expression template syntax verification
|
||||||
|
static_assert(is_of_type<1 / dim_time, derived_dimension<struct dim_one, per<struct dim_time>>>);
|
||||||
|
static_assert(is_of_type<1 / (1 / dim_time), struct dim_time>);
|
||||||
|
|
||||||
|
static_assert(is_of_type<dim_one * dim_time, struct dim_time>);
|
||||||
|
static_assert(is_of_type<dim_time * dim_one, struct dim_time>);
|
||||||
|
static_assert(is_of_type<dim_one * (1 / dim_time), derived_dimension<struct dim_one, per<struct dim_time>>>);
|
||||||
|
static_assert(is_of_type<1 / dim_time * dim_one, derived_dimension<struct dim_one, per<struct dim_time>>>);
|
||||||
|
|
||||||
|
static_assert(is_of_type<dim_length * dim_time, derived_dimension<struct dim_length, struct dim_time>>);
|
||||||
|
static_assert(is_of_type<dim_length * dim_length, derived_dimension<power<struct dim_length, 2>>>);
|
||||||
|
|
||||||
|
static_assert(
|
||||||
|
is_of_type<dim_length * dim_length * dim_time, derived_dimension<power<struct dim_length, 2>, struct dim_time>>);
|
||||||
|
static_assert(
|
||||||
|
is_of_type<dim_length * dim_time * dim_length, derived_dimension<power<struct dim_length, 2>, struct dim_time>>);
|
||||||
|
|
||||||
|
static_assert(
|
||||||
|
is_of_type<dim_length*(dim_time* dim_length), derived_dimension<power<struct dim_length, 2>, struct dim_time>>);
|
||||||
|
static_assert(
|
||||||
|
is_of_type<dim_time*(dim_length* dim_length), derived_dimension<power<struct dim_length, 2>, struct dim_time>>);
|
||||||
|
|
||||||
|
static_assert(is_of_type<1 / dim_time * dim_length, derived_dimension<struct dim_length, per<struct dim_time>>>);
|
||||||
|
static_assert(is_of_type<1 / dim_time * dim_time, struct dim_one>);
|
||||||
|
|
||||||
|
static_assert(is_of_type<dim_time / dim_one, struct dim_time>);
|
||||||
|
static_assert(is_of_type<1 / dim_time / dim_one, derived_dimension<struct dim_one, per<struct dim_time>>>);
|
||||||
|
|
||||||
|
static_assert(is_of_type<dim_length / dim_time * dim_time, struct dim_length>);
|
||||||
|
static_assert(
|
||||||
|
is_of_type<1 / dim_time * (1 / dim_time), derived_dimension<struct dim_one, per<power<struct dim_time, 2>>>>);
|
||||||
|
static_assert(is_of_type<1 / (dim_time * dim_time), derived_dimension<struct dim_one, per<power<struct dim_time, 2>>>>);
|
||||||
|
static_assert(is_of_type<1 / (1 / (dim_time * dim_time)), derived_dimension<power<struct dim_time, 2>>>);
|
||||||
|
|
||||||
|
static_assert(is_of_type<dim_length / dim_time * (1 / dim_time),
|
||||||
|
derived_dimension<struct dim_length, per<power<struct dim_time, 2>>>>);
|
||||||
|
static_assert(is_of_type<dim_length / dim_time*(dim_length / dim_time),
|
||||||
|
derived_dimension<power<struct dim_length, 2>, per<power<struct dim_time, 2>>>>);
|
||||||
|
static_assert(is_of_type<dim_length / dim_time*(dim_time / dim_length), struct dim_one>);
|
||||||
|
|
||||||
|
static_assert(
|
||||||
|
is_of_type<dim_speed / dim_acceleration, derived_dimension<struct dim_speed, per<struct dim_acceleration>>>);
|
||||||
|
static_assert(
|
||||||
|
is_of_type<dim_acceleration / dim_speed, derived_dimension<struct dim_acceleration, per<struct dim_speed>>>);
|
||||||
|
static_assert(is_of_type<dim_speed * dim_speed / dim_length,
|
||||||
|
derived_dimension<power<struct dim_speed, 2>, per<struct dim_length>>>);
|
||||||
|
static_assert(is_of_type<1 / (dim_speed * dim_speed) * dim_length,
|
||||||
|
derived_dimension<struct dim_length, per<power<struct dim_speed, 2>>>>);
|
||||||
|
|
||||||
|
// comparisons of equivalent dimensions
|
||||||
|
static_assert(dim_length / dim_length == dim_one);
|
||||||
|
|
||||||
|
static_assert(1 / dim_time == dim_frequency);
|
||||||
|
static_assert(1 / dim_frequency == dim_time);
|
||||||
|
static_assert(dim_frequency * dim_time == dim_one);
|
||||||
|
|
||||||
|
static_assert(dim_length * dim_length == dim_area);
|
||||||
|
static_assert(dim_length * dim_length != dim_volume);
|
||||||
|
static_assert(dim_area / dim_length == dim_length);
|
||||||
|
|
||||||
|
static_assert(dim_length * dim_length * dim_length == dim_volume);
|
||||||
|
static_assert(dim_area * dim_length == dim_volume);
|
||||||
|
static_assert(dim_volume / dim_length == dim_area);
|
||||||
|
static_assert(dim_volume / dim_length / dim_length == dim_length);
|
||||||
|
static_assert(dim_area * dim_area / dim_length == dim_volume);
|
||||||
|
static_assert(dim_area * (dim_area / dim_length) == dim_volume);
|
||||||
|
static_assert(dim_volume / (dim_length * dim_length) == dim_length);
|
||||||
|
|
||||||
|
static_assert(dim_length / dim_time == dim_speed);
|
||||||
|
static_assert(dim_length * dim_time != dim_speed);
|
||||||
|
static_assert(dim_length / dim_time / dim_time != dim_speed);
|
||||||
|
static_assert(dim_length / dim_speed == dim_time);
|
||||||
|
static_assert(dim_speed * dim_time == dim_length);
|
||||||
|
|
||||||
|
static_assert(dim_length / dim_time / dim_time == dim_acceleration);
|
||||||
|
static_assert(dim_length / (dim_time * dim_time) == dim_acceleration);
|
||||||
|
static_assert(dim_speed / dim_time == dim_acceleration);
|
||||||
|
static_assert(dim_speed / dim_acceleration == dim_time);
|
||||||
|
static_assert(dim_acceleration * dim_time == dim_speed);
|
||||||
|
static_assert(dim_acceleration * (dim_time * dim_time) == dim_length);
|
||||||
|
static_assert(dim_acceleration / dim_speed == dim_frequency);
|
||||||
|
|
||||||
|
} // namespace units::isq
|
||||||
|
|
||||||
|
|
||||||
|
namespace units::isq::si {
|
||||||
|
|
||||||
|
// derived unit expression template syntax verification
|
||||||
|
static_assert(is_of_type<1 / second, derived_unit<struct one, per<struct second>>>);
|
||||||
|
static_assert(is_of_type<1 / (1 / second), struct second>);
|
||||||
|
|
||||||
|
static_assert(is_of_type<one * second, struct second>);
|
||||||
|
static_assert(is_of_type<second * one, struct second>);
|
||||||
|
static_assert(is_of_type<one * (1 / second), derived_unit<struct one, per<struct second>>>);
|
||||||
|
static_assert(is_of_type<1 / second * one, derived_unit<struct one, per<struct second>>>);
|
||||||
|
|
||||||
|
static_assert(is_of_type<metre * second, derived_unit<struct metre, struct second>>);
|
||||||
|
static_assert(is_of_type<metre * metre, derived_unit<power<struct metre, 2>>>);
|
||||||
|
|
||||||
|
static_assert(is_of_type<metre * metre * second, derived_unit<power<struct metre, 2>, struct second>>);
|
||||||
|
static_assert(is_of_type<metre * second * metre, derived_unit<power<struct metre, 2>, struct second>>);
|
||||||
|
|
||||||
|
static_assert(is_of_type<metre*(second* metre), derived_unit<power<struct metre, 2>, struct second>>);
|
||||||
|
static_assert(is_of_type<second*(metre* metre), derived_unit<power<struct metre, 2>, struct second>>);
|
||||||
|
|
||||||
|
static_assert(is_of_type<1 / second * metre, derived_unit<struct metre, per<struct second>>>);
|
||||||
|
static_assert(is_of_type<1 / second * second, struct one>);
|
||||||
|
|
||||||
|
static_assert(is_of_type<second / one, struct second>);
|
||||||
|
static_assert(is_of_type<1 / second / one, derived_unit<struct one, per<struct second>>>);
|
||||||
|
|
||||||
|
static_assert(is_of_type<metre / second * second, struct metre>);
|
||||||
|
static_assert(is_of_type<1 / second * (1 / second), derived_unit<struct one, per<power<struct second, 2>>>>);
|
||||||
|
static_assert(is_of_type<1 / (second * second), derived_unit<struct one, per<power<struct second, 2>>>>);
|
||||||
|
static_assert(is_of_type<1 / (1 / (second * second)), derived_unit<power<struct second, 2>>>);
|
||||||
|
|
||||||
|
static_assert(is_of_type<metre / second * (1 / second), derived_unit<struct metre, per<power<struct second, 2>>>>);
|
||||||
|
static_assert(
|
||||||
|
is_of_type<metre / second*(metre / second), derived_unit<power<struct metre, 2>, per<power<struct second, 2>>>>);
|
||||||
|
static_assert(is_of_type<metre / second*(second / metre), struct one>);
|
||||||
|
|
||||||
|
static_assert(is_of_type<watt / joule, derived_unit<struct watt, per<struct joule>>>);
|
||||||
|
static_assert(is_of_type<joule / watt, derived_unit<struct joule, per<struct watt>>>);
|
||||||
|
|
||||||
|
// comparisons of equivalent dimensions
|
||||||
|
// static_assert(metre / metre == one);
|
||||||
|
|
||||||
|
// static_assert(1 / second == dim_frequency);
|
||||||
|
// static_assert(1 / dim_frequency == second);
|
||||||
|
// static_assert(dim_frequency * second == one);
|
||||||
|
|
||||||
|
// static_assert(metre * metre == dim_area);
|
||||||
|
// static_assert(metre * metre != dim_volume);
|
||||||
|
// static_assert(dim_area / metre == metre);
|
||||||
|
|
||||||
|
// static_assert(metre * metre * metre == dim_volume);
|
||||||
|
// static_assert(dim_area * metre == dim_volume);
|
||||||
|
// static_assert(dim_volume / metre == dim_area);
|
||||||
|
// static_assert(dim_volume / metre / metre == metre);
|
||||||
|
// static_assert(dim_area * dim_area / metre == dim_volume);
|
||||||
|
// static_assert(dim_area * (dim_area / metre) == dim_volume);
|
||||||
|
// static_assert(dim_volume / (metre * metre) == metre);
|
||||||
|
|
||||||
|
// static_assert(metre / second == dim_speed);
|
||||||
|
// static_assert(metre * second != dim_speed);
|
||||||
|
// static_assert(metre / second / second != dim_speed);
|
||||||
|
// static_assert(metre / dim_speed == second);
|
||||||
|
// static_assert(dim_speed * second == metre);
|
||||||
|
|
||||||
|
// static_assert(metre / second / second == dim_acceleration);
|
||||||
|
// static_assert(metre / (second * second) == dim_acceleration);
|
||||||
|
// static_assert(dim_speed / second == dim_acceleration);
|
||||||
|
// static_assert(dim_speed / dim_acceleration == second);
|
||||||
|
// static_assert(dim_acceleration * second == dim_speed);
|
||||||
|
// static_assert(dim_acceleration * (second * second) == metre);
|
||||||
|
// static_assert(dim_acceleration / dim_speed == dim_frequency);
|
||||||
|
|
||||||
|
|
||||||
|
// Bq + Hz should not compile
|
||||||
|
|
||||||
|
// Bq + Hz + 1/s should compile?
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace units::isq::si
|
||||||
|
|
||||||
|
|
||||||
|
using namespace units;
|
||||||
|
using namespace units::isq::si;
|
||||||
|
using namespace units::isq::si::short_units;
|
||||||
|
|
||||||
|
/* Frequency */ auto freq1 = 20 * frequency[Hz];
|
||||||
|
// /* Frequency */ auto freq2 = 20 / (1 * isq::si::time[s]);
|
||||||
|
quantity<frequency[Hz]> freq3(20);
|
||||||
|
quantity<frequency[1 / s]> freq4(20);
|
||||||
|
quantity<dimensionless[one] / isq::si::time[s]> freq5(20);
|
||||||
|
|
||||||
|
/* Speed */ auto speed1 = 20 * speed[m / s];
|
||||||
|
/* Speed */ auto speed2 = 20 * (length[m] / isq::si::time[s]);
|
||||||
|
quantity<speed[m / s]> speed3(20);
|
||||||
|
quantity<length[m] / isq::si::time[s]> speed4(20);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void print();
|
||||||
|
|
||||||
|
// constexpr auto avg_speed(quantity<length[km]> d, quantity<isq::si::time[h]> t) { return d / t; }
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
print<decltype(freq1)>();
|
||||||
|
// print<decltype(freq2)>();
|
||||||
|
print<decltype(freq3)>();
|
||||||
|
print<decltype(freq4)>();
|
||||||
|
print<decltype(freq5)>();
|
||||||
|
|
||||||
|
print<decltype(speed1)>();
|
||||||
|
print<decltype(speed2)>();
|
||||||
|
print<decltype(speed3)>();
|
||||||
|
print<decltype(speed4)>();
|
||||||
|
}
|
@ -37,12 +37,10 @@ check_libcxx_in_use(${projectPrefix}LIBCXX)
|
|||||||
add_library(
|
add_library(
|
||||||
mp-units-core
|
mp-units-core
|
||||||
INTERFACE
|
INTERFACE
|
||||||
include/units/base_dimension.h
|
|
||||||
include/units/chrono.h
|
include/units/chrono.h
|
||||||
include/units/concepts.h
|
include/units/concepts.h
|
||||||
include/units/customization_points.h
|
include/units/customization_points.h
|
||||||
include/units/derived_dimension.h
|
include/units/dimension.h
|
||||||
include/units/exponent.h
|
|
||||||
include/units/generic/angle.h
|
include/units/generic/angle.h
|
||||||
include/units/generic/dimensionless.h
|
include/units/generic/dimensionless.h
|
||||||
include/units/generic/solid_angle.h
|
include/units/generic/solid_angle.h
|
||||||
@ -50,7 +48,6 @@ add_library(
|
|||||||
include/units/magnitude.h
|
include/units/magnitude.h
|
||||||
include/units/math.h
|
include/units/math.h
|
||||||
include/units/point_origin.h
|
include/units/point_origin.h
|
||||||
include/units/prefix.h
|
|
||||||
include/units/quantity.h
|
include/units/quantity.h
|
||||||
include/units/quantity_cast.h
|
include/units/quantity_cast.h
|
||||||
include/units/quantity_kind.h
|
include/units/quantity_kind.h
|
||||||
|
@ -1,66 +0,0 @@
|
|||||||
// The MIT License (MIT)
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018 Mateusz Pusz
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
// IWYU pragma: begin_exports
|
|
||||||
#include <units/bits/basic_concepts.h>
|
|
||||||
#include <units/bits/external/fixed_string.h>
|
|
||||||
// IWYU pragma: end_exports
|
|
||||||
|
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
namespace units {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A dimension of a base quantity
|
|
||||||
*
|
|
||||||
* Base quantity is a quantity in a conventionally chosen subset of a given system of quantities, where no quantity
|
|
||||||
* in the subset can be expressed in terms of the other quantities within that subset. They are referred to as
|
|
||||||
* being mutually independent since a base quantity cannot be expressed as a product of powers of the other base
|
|
||||||
* quantities.
|
|
||||||
*
|
|
||||||
* Base unit is a measurement unit that is adopted by convention for a base quantity in a specific system of units.
|
|
||||||
*
|
|
||||||
* Pair of Symbol and Unit template parameters form an unique identifier of the base dimension. The same identifiers can
|
|
||||||
* be multiplied and divided which will result with an adjustment of its factor in an Exponent of a DerivedDimension
|
|
||||||
* (in case of zero the dimension will be simplified and removed from further analysis of current expresion). In case
|
|
||||||
* the Symbol is the same but the Unit differs (i.e. mixing SI and CGS length), there is no automatic simplification but
|
|
||||||
* is possible to force it with a quantity_cast.
|
|
||||||
*
|
|
||||||
* @tparam Symbol an unique identifier of the base dimension used to provide dimensional analysis support
|
|
||||||
* @tparam U a base unit to be used for this base dimension
|
|
||||||
*/
|
|
||||||
template<basic_fixed_string Symbol, NamedUnit U>
|
|
||||||
struct base_dimension {
|
|
||||||
static constexpr auto symbol = Symbol; ///< Unique base dimension identifier
|
|
||||||
using base_unit = U; ///< Base unit adopted for this dimension
|
|
||||||
static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto mag = magnitude{};
|
|
||||||
};
|
|
||||||
|
|
||||||
// base_dimension_less
|
|
||||||
template<BaseDimension D1, BaseDimension D2>
|
|
||||||
struct base_dimension_less :
|
|
||||||
std::bool_constant<(D1::symbol < D2::symbol) ||
|
|
||||||
(D1::symbol == D2::symbol && D1::base_unit::symbol < D1::base_unit::symbol)> {};
|
|
||||||
|
|
||||||
} // namespace units
|
|
@ -1,60 +0,0 @@
|
|||||||
// The MIT License (MIT)
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018 Mateusz Pusz
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <units/base_dimension.h>
|
|
||||||
#include <units/bits/external/downcasting.h>
|
|
||||||
#include <units/exponent.h>
|
|
||||||
|
|
||||||
namespace units::detail {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A dimension of a derived quantity
|
|
||||||
*
|
|
||||||
* Expression of the dependence of a quantity on the base quantities (and their base dimensions) of a system of
|
|
||||||
* quantities as a product of powers of factors corresponding to the base quantities, omitting any numerical factors.
|
|
||||||
* A power of a factor is the factor raised to an exponent.
|
|
||||||
*
|
|
||||||
* A derived dimension can be formed from multiple exponents (i.e. speed is represented as "exponent<L, 1>, exponent<T,
|
|
||||||
* -1>"). It is also possible to form a derived dimension with only one exponent (i.e. frequency is represented as just
|
|
||||||
* "exponent<T, -1>").
|
|
||||||
*
|
|
||||||
* @note This class template is used by the library engine and should not be directly instantiated by the user.
|
|
||||||
*
|
|
||||||
* @tparam Es zero or more exponents of a derived dimension
|
|
||||||
*/
|
|
||||||
template<Exponent... Es>
|
|
||||||
requires(BaseDimension<typename Es::dimension> && ...)
|
|
||||||
struct derived_dimension_base : downcast_base<derived_dimension_base<Es...>> {
|
|
||||||
using exponents = exponent_list<Es...>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct to_derived_dimension_base;
|
|
||||||
|
|
||||||
template<Exponent... Es>
|
|
||||||
struct to_derived_dimension_base<exponent_list<Es...>> {
|
|
||||||
using type = derived_dimension_base<Es...>;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace units::detail
|
|
@ -1,48 +0,0 @@
|
|||||||
// The MIT License (MIT)
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018 Mateusz Pusz
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <units/derived_dimension.h>
|
|
||||||
#include <units/magnitude.h>
|
|
||||||
|
|
||||||
namespace units::detail {
|
|
||||||
|
|
||||||
// compatible_units
|
|
||||||
template<typename ExpList, Unit... Us>
|
|
||||||
inline constexpr bool compatible_units = false;
|
|
||||||
|
|
||||||
template<typename... Es, Unit... Us>
|
|
||||||
inline constexpr bool compatible_units<exponent_list<Es...>, Us...> = (UnitOf<Us, typename Es::dimension> && ...);
|
|
||||||
|
|
||||||
// derived_scaled_unit
|
|
||||||
|
|
||||||
template<Unit... Us, typename... Es>
|
|
||||||
constexpr Magnitude auto derived_mag(exponent_list<Es...>)
|
|
||||||
{
|
|
||||||
return (magnitude<>{} * ... * pow<ratio{Es::num, Es::den}>(Us::mag / dimension_unit<typename Es::dimension>::mag));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<DerivedDimension D, Unit... Us>
|
|
||||||
using derived_scaled_unit = scaled_unit<derived_mag<Us...>(typename D::recipe()), typename D::coherent_unit::reference>;
|
|
||||||
|
|
||||||
} // namespace units::detail
|
|
@ -1,67 +0,0 @@
|
|||||||
// The MIT License (MIT)
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018 Mateusz Pusz
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <units/bits/external/type_list.h>
|
|
||||||
#include <units/exponent.h>
|
|
||||||
#include <ratio>
|
|
||||||
|
|
||||||
namespace units::detail {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Consolidates contiguous ranges of exponents of the same dimension
|
|
||||||
*
|
|
||||||
* If there is more than one exponent with the same dimension they are aggregated into one exponent by adding
|
|
||||||
* their exponents. If this accumulation will result with 0, such a dimension is removed from the list.
|
|
||||||
*
|
|
||||||
* @tparam D derived dimension to consolidate
|
|
||||||
*/
|
|
||||||
template<typename ExpList>
|
|
||||||
struct dim_consolidate;
|
|
||||||
|
|
||||||
template<>
|
|
||||||
struct dim_consolidate<exponent_list<>> {
|
|
||||||
using type = exponent_list<>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename E>
|
|
||||||
struct dim_consolidate<exponent_list<E>> {
|
|
||||||
using type = exponent_list<E>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename E1, typename... ERest>
|
|
||||||
struct dim_consolidate<exponent_list<E1, ERest...>> {
|
|
||||||
using type = type_list_push_front<typename dim_consolidate<exponent_list<ERest...>>::type, E1>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<BaseDimension Dim, std::intmax_t Num1, std::intmax_t Den1, std::intmax_t Num2, std::intmax_t Den2,
|
|
||||||
typename... ERest>
|
|
||||||
struct dim_consolidate<exponent_list<exponent<Dim, Num1, Den1>, exponent<Dim, Num2, Den2>, ERest...>> {
|
|
||||||
using r1 = std::ratio<Num1, Den1>;
|
|
||||||
using r2 = std::ratio<Num2, Den2>;
|
|
||||||
using r = std::ratio_add<r1, r2>;
|
|
||||||
using type = conditional<r::num == 0, typename dim_consolidate<exponent_list<ERest...>>::type,
|
|
||||||
typename dim_consolidate<exponent_list<exponent<Dim, r::num, r::den>, ERest...>>::type>;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace units::detail
|
|
@ -1,59 +0,0 @@
|
|||||||
// The MIT License (MIT)
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018 Mateusz Pusz
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <units/bits/derived_dimension_base.h>
|
|
||||||
#include <units/bits/external/type_list.h>
|
|
||||||
#include <units/exponent.h>
|
|
||||||
|
|
||||||
namespace units::detail {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Unpacks the list of potentially derived dimensions to a list containing only base dimensions
|
|
||||||
*
|
|
||||||
* @tparam Es Exponents of potentially derived dimensions
|
|
||||||
*/
|
|
||||||
template<Exponent... Es>
|
|
||||||
struct dim_unpack;
|
|
||||||
|
|
||||||
template<>
|
|
||||||
struct dim_unpack<> {
|
|
||||||
using type = exponent_list<>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<BaseDimension Dim, std::intmax_t Num, std::intmax_t Den, Exponent... ERest>
|
|
||||||
struct dim_unpack<exponent<Dim, Num, Den>, ERest...> {
|
|
||||||
using type = type_list_push_front<typename dim_unpack<ERest...>::type, exponent<Dim, Num, Den>>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<DerivedDimension Dim, std::intmax_t Num, std::intmax_t Den, Exponent... ERest>
|
|
||||||
struct dim_unpack<exponent<Dim, Num, Den>, ERest...> {
|
|
||||||
using type = TYPENAME dim_unpack<exponent<downcast_base_t<Dim>, Num, Den>, ERest...>::type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<Exponent... Es, std::intmax_t Num, std::intmax_t Den, Exponent... ERest>
|
|
||||||
struct dim_unpack<exponent<derived_dimension_base<Es...>, Num, Den>, ERest...> {
|
|
||||||
using type = type_list_push_front<typename dim_unpack<ERest...>::type, exponent_multiply<Es, Num, Den>...>;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace units::detail
|
|
@ -1,208 +0,0 @@
|
|||||||
// The MIT License (MIT)
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018 Mateusz Pusz
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <units/bits/derived_dimension_base.h>
|
|
||||||
#include <units/bits/dim_consolidate.h>
|
|
||||||
#include <units/bits/external/downcasting.h>
|
|
||||||
#include <units/bits/external/hacks.h>
|
|
||||||
#include <units/bits/external/type_list.h>
|
|
||||||
#include <units/derived_dimension.h>
|
|
||||||
#include <units/unit.h>
|
|
||||||
|
|
||||||
namespace units {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Unknown dimension
|
|
||||||
*
|
|
||||||
* Sometimes a temporary partial result of a complex calculation may not result in a predefined
|
|
||||||
* dimension. In such a case an `unknown_dimension` is created with a coherent unit of `unknown_coherent_unit`
|
|
||||||
* with a magnitude being the absolute one of all the exponents of such a dimension.
|
|
||||||
*
|
|
||||||
* @tparam Es the list of exponents of ingredient dimensions
|
|
||||||
*/
|
|
||||||
template<Exponent... Es>
|
|
||||||
struct unknown_dimension : derived_dimension<unknown_dimension<Es...>, unknown_coherent_unit<Es...>, Es...> {};
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
template<DerivedDimension D>
|
|
||||||
struct check_unknown {
|
|
||||||
using type = D;
|
|
||||||
};
|
|
||||||
|
|
||||||
// downcast did not find a user predefined type
|
|
||||||
template<typename... Es>
|
|
||||||
struct check_unknown<derived_dimension_base<Es...>> {
|
|
||||||
using type = unknown_dimension<Es...>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<Dimension D>
|
|
||||||
struct downcast_dimension_impl;
|
|
||||||
|
|
||||||
template<BaseDimension D>
|
|
||||||
struct downcast_dimension_impl<D> {
|
|
||||||
using type = D;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<DerivedDimension D>
|
|
||||||
struct downcast_dimension_impl<D> {
|
|
||||||
using type = TYPENAME check_unknown<downcast<D>>::type;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
template<Dimension D>
|
|
||||||
using downcast_dimension = TYPENAME detail::downcast_dimension_impl<D>::type;
|
|
||||||
|
|
||||||
// dim_invert
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
template<Dimension D>
|
|
||||||
struct dim_invert_impl;
|
|
||||||
|
|
||||||
template<BaseDimension D>
|
|
||||||
struct dim_invert_impl<D> {
|
|
||||||
using type = downcast_dimension<derived_dimension_base<exponent<D, -1>>>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<BaseDimension D>
|
|
||||||
struct dim_invert_impl<derived_dimension_base<exponent<D, -1>>> {
|
|
||||||
using type = D;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename... Es>
|
|
||||||
struct dim_invert_impl<derived_dimension_base<Es...>> {
|
|
||||||
using type = downcast_dimension<derived_dimension_base<exponent_invert<Es>...>>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<DerivedDimension D>
|
|
||||||
struct dim_invert_impl<D> : dim_invert_impl<downcast_base_t<D>> {};
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
template<Dimension D>
|
|
||||||
using dim_invert = TYPENAME detail::dim_invert_impl<D>::type;
|
|
||||||
|
|
||||||
// dimension_multiply
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct to_dimension;
|
|
||||||
|
|
||||||
template<Exponent... Es>
|
|
||||||
struct to_dimension<exponent_list<Es...>> {
|
|
||||||
using type = derived_dimension_base<Es...>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<BaseDimension D>
|
|
||||||
struct to_dimension<exponent_list<exponent<D, 1>>> {
|
|
||||||
using type = D;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Merges 2 sorted derived dimensions into one units::derived_dimension_base
|
|
||||||
*
|
|
||||||
* A result of a dimensional calculation may result with many exponents of the same base dimension orginated
|
|
||||||
* from different parts of the equation. As the exponents lists of both operands it is enough to merge them
|
|
||||||
* into one list and consolidate duplicates. Also it is possible that final exponents list will contain only
|
|
||||||
* one element being a base dimension with exponent 1. In such a case the final dimension should be the base
|
|
||||||
* dimension itself.
|
|
||||||
*/
|
|
||||||
template<Dimension D1, Dimension D2>
|
|
||||||
using merge_dimension = TYPENAME to_dimension<typename dim_consolidate<
|
|
||||||
type_list_merge_sorted<typename D1::exponents, typename D2::exponents, exponent_less>>::type>::type;
|
|
||||||
|
|
||||||
template<Dimension D1, Dimension D2>
|
|
||||||
struct dimension_multiply_impl;
|
|
||||||
|
|
||||||
template<BaseDimension D1, BaseDimension D2>
|
|
||||||
struct dimension_multiply_impl<D1, D2> {
|
|
||||||
using type = downcast_dimension<
|
|
||||||
merge_dimension<derived_dimension_base<exponent<D1, 1>>, derived_dimension_base<exponent<D2, 1>>>>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<BaseDimension D1, DerivedDimension D2>
|
|
||||||
struct dimension_multiply_impl<D1, D2> {
|
|
||||||
using type =
|
|
||||||
downcast_dimension<merge_dimension<derived_dimension_base<exponent<D1, 1>>, typename D2::downcast_base_type>>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<DerivedDimension D1, BaseDimension D2>
|
|
||||||
struct dimension_multiply_impl<D1, D2> {
|
|
||||||
using type = TYPENAME dimension_multiply_impl<D2, D1>::type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<DerivedDimension D1, DerivedDimension D2>
|
|
||||||
struct dimension_multiply_impl<D1, D2> {
|
|
||||||
using type = downcast_dimension<merge_dimension<typename D1::downcast_base_type, typename D2::downcast_base_type>>;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
template<Dimension D1, Dimension D2>
|
|
||||||
using dimension_multiply = TYPENAME detail::dimension_multiply_impl<D1, D2>::type;
|
|
||||||
|
|
||||||
template<Dimension D1, Dimension D2>
|
|
||||||
using dimension_divide = TYPENAME detail::dimension_multiply_impl<D1, dim_invert<D2>>::type;
|
|
||||||
|
|
||||||
// dimension_pow
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
template<Dimension D, std::intmax_t Num, std::intmax_t Den = 1>
|
|
||||||
struct dimension_pow_impl;
|
|
||||||
|
|
||||||
template<BaseDimension D, std::intmax_t Num, std::intmax_t Den>
|
|
||||||
struct dimension_pow_impl<D, Num, Den> {
|
|
||||||
using type = downcast_dimension<derived_dimension_base<exponent<D, Num, Den>>>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<BaseDimension D>
|
|
||||||
struct dimension_pow_impl<D, 1, 1> {
|
|
||||||
using type = D;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<BaseDimension D, std::intmax_t Num, std::intmax_t Den>
|
|
||||||
struct dimension_pow_impl<derived_dimension_base<exponent<D, Den, Num>>, Num, Den> {
|
|
||||||
using type = D;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<DerivedDimension D, std::intmax_t Num, std::intmax_t Den>
|
|
||||||
struct dimension_pow_impl<D, Num, Den> {
|
|
||||||
using type = TYPENAME dimension_pow_impl<downcast_base_t<D>, Num, Den>::type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename... Es, std::intmax_t Num, std::intmax_t Den>
|
|
||||||
struct dimension_pow_impl<derived_dimension_base<Es...>, Num, Den> {
|
|
||||||
using type = downcast_dimension<derived_dimension_base<exponent_multiply<Es, Num, Den>...>>;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
template<Dimension D, std::intmax_t Num, std::intmax_t Den = 1>
|
|
||||||
using dimension_pow = TYPENAME detail::dimension_pow_impl<D, Num, Den>::type;
|
|
||||||
|
|
||||||
template<Dimension D>
|
|
||||||
using dimension_sqrt = TYPENAME detail::dimension_pow_impl<D, 1, 2>::type;
|
|
||||||
|
|
||||||
} // namespace units
|
|
390
src/core/include/units/bits/expression_template.h
Normal file
390
src/core/include/units/bits/expression_template.h
Normal file
@ -0,0 +1,390 @@
|
|||||||
|
// The MIT License (MIT)
|
||||||
|
//
|
||||||
|
// Copyright (c) 2018 Mateusz Pusz
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||||
|
// copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <units/bits/external/type_list.h>
|
||||||
|
#include <units/bits/external/type_traits.h>
|
||||||
|
#include <units/ratio.h>
|
||||||
|
|
||||||
|
namespace units {
|
||||||
|
|
||||||
|
template<typename... Ts>
|
||||||
|
struct type_list {};
|
||||||
|
|
||||||
|
template<typename... Ts>
|
||||||
|
struct per {};
|
||||||
|
|
||||||
|
template<typename F, int...>
|
||||||
|
struct power;
|
||||||
|
|
||||||
|
// TODO make_power() that will simplify cases like <dim_length, 2, 2>?
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
inline constexpr bool is_specialization_of_power = false;
|
||||||
|
|
||||||
|
template<typename F, int... Ints>
|
||||||
|
inline constexpr bool is_specialization_of_power<power<F, Ints...>> = true;
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
template<typename F, int Num>
|
||||||
|
struct power<F, Num> {
|
||||||
|
using factor = F;
|
||||||
|
static constexpr int num = Num;
|
||||||
|
static constexpr int den = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename F, int Num, int Den>
|
||||||
|
struct power<F, Num, Den> {
|
||||||
|
using factor = F;
|
||||||
|
static constexpr int num = Num;
|
||||||
|
static constexpr int den = Den;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<typename T, int Num, int Den>
|
||||||
|
constexpr auto power_or_T_impl()
|
||||||
|
{
|
||||||
|
constexpr ratio r{Num, Den};
|
||||||
|
if constexpr (r.den == 1) {
|
||||||
|
if constexpr (r.num == 1)
|
||||||
|
return T{};
|
||||||
|
else
|
||||||
|
return power<T, r.num>{};
|
||||||
|
} else {
|
||||||
|
return power<T, r.num, r.den>{};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, int Num, int Den>
|
||||||
|
using power_or_T = decltype(power_or_T_impl<T, Num, Den>());
|
||||||
|
|
||||||
|
// type_power
|
||||||
|
template<typename T, int Num, int Den>
|
||||||
|
struct type_power {
|
||||||
|
using type = conditional<Den == 1, power<T, Num>, power<T, Num, Den>>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, int Num2, int Num>
|
||||||
|
struct type_power<power<T, Num2>, Num, 1> {
|
||||||
|
using type = power<T, Num * Num2>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, int Num, int Den, int... Ints>
|
||||||
|
struct type_power<power<T, Ints...>, Num, Den> {
|
||||||
|
static constexpr ratio r = ratio(power<T, Ints...>::num, power<T, Ints...>::den) * ratio(Num, Den);
|
||||||
|
using type = power_or_T<T, r.num, r.den>;
|
||||||
|
};
|
||||||
|
|
||||||
|
// expr_power
|
||||||
|
template<typename List, int Num, int Den>
|
||||||
|
struct expr_power;
|
||||||
|
|
||||||
|
template<typename... Ts, int Num, int Den>
|
||||||
|
struct expr_power<type_list<Ts...>, Num, Den> {
|
||||||
|
using type = type_list<typename type_power<Ts, Num, Den>::type...>;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Consolidates contiguous ranges of exponents of the same dimension
|
||||||
|
*
|
||||||
|
* If there is more than one exponent with the same dimension they are aggregated into one exponent by adding
|
||||||
|
* their exponents. If this accumulation will result with 0, such a dimension is removed from the list.
|
||||||
|
*
|
||||||
|
* @tparam D derived dimension to consolidate
|
||||||
|
*/
|
||||||
|
template<typename List>
|
||||||
|
struct expr_consolidate_impl;
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct expr_consolidate_impl<type_list<>> {
|
||||||
|
using type = type_list<>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct expr_consolidate_impl<type_list<T>> {
|
||||||
|
using type = type_list<T>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, typename... Rest>
|
||||||
|
struct expr_consolidate_impl<type_list<T, Rest...>> {
|
||||||
|
using type = type_list_push_front<typename expr_consolidate_impl<type_list<Rest...>>::type, T>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, typename... Rest>
|
||||||
|
struct expr_consolidate_impl<type_list<T, T, Rest...>> {
|
||||||
|
using type = expr_consolidate_impl<type_list<power<T, 2>, Rest...>>::type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, int... Ints, typename... Rest>
|
||||||
|
struct expr_consolidate_impl<type_list<T, power<T, Ints...>, Rest...>> {
|
||||||
|
using type = expr_consolidate_impl<
|
||||||
|
type_list<power_or_T<T, power<T, Ints...>::num + power<T, Ints...>::den, power<T, Ints...>::den>, Rest...>>::type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, int... Ints1, int... Ints2, typename... Rest>
|
||||||
|
struct expr_consolidate_impl<type_list<power<T, Ints1...>, power<T, Ints2...>, Rest...>> {
|
||||||
|
static constexpr ratio r =
|
||||||
|
ratio(power<T, Ints1...>::num, power<T, Ints1...>::den) + ratio(power<T, Ints2...>::num, power<T, Ints2...>::den);
|
||||||
|
using type = conditional<r.num == 0, typename expr_consolidate_impl<type_list<Rest...>>::type,
|
||||||
|
typename expr_consolidate_impl<type_list<power_or_T<T, r.num, r.den>, Rest...>>::type>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename List>
|
||||||
|
using expr_consolidate = typename expr_consolidate_impl<List>::type;
|
||||||
|
|
||||||
|
|
||||||
|
// expr_simplify
|
||||||
|
|
||||||
|
template<typename T, typename powerNum, typename powerDen>
|
||||||
|
struct expr_simplify_power {
|
||||||
|
static constexpr ratio r = ratio(powerNum::num, powerNum::den) - ratio(powerDen::num, powerDen::den);
|
||||||
|
using type = power_or_T<T, abs(r.num), r.den>;
|
||||||
|
using num = conditional<(r > 0), type_list<type>, type_list<>>;
|
||||||
|
using den = conditional<(r < 0), type_list<type>, type_list<>>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename NumList, typename DenList, template<typename, typename> typename Pred>
|
||||||
|
struct expr_simplify;
|
||||||
|
|
||||||
|
template<typename NumList, typename DenList, template<typename, typename> typename Pred>
|
||||||
|
requires(type_list_size<NumList> == 0) || (type_list_size<DenList> == 0)
|
||||||
|
struct expr_simplify<NumList, DenList, Pred> {
|
||||||
|
using num = NumList;
|
||||||
|
using den = DenList;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Num, typename... NRest, typename Den, typename... DRest, template<typename, typename> typename Pred>
|
||||||
|
struct expr_simplify<type_list<Num, NRest...>, type_list<Den, DRest...>, Pred> {
|
||||||
|
using impl = conditional<Pred<Num, Den>::value, expr_simplify<type_list<NRest...>, type_list<Den, DRest...>, Pred>,
|
||||||
|
expr_simplify<type_list<Num, NRest...>, type_list<DRest...>, Pred>>;
|
||||||
|
using num = conditional<Pred<Num, Den>::value, type_list_push_front<typename impl::num, Num>, typename impl::num>;
|
||||||
|
using den = conditional<Pred<Num, Den>::value, typename impl::den, type_list_push_front<typename impl::den, Den>>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, typename... NRest, typename... DRest, template<typename, typename> typename Pred>
|
||||||
|
struct expr_simplify<type_list<T, NRest...>, type_list<T, DRest...>, Pred> :
|
||||||
|
expr_simplify<type_list<NRest...>, type_list<DRest...>, Pred> {};
|
||||||
|
|
||||||
|
template<typename T, typename... NRest, int... Ints, typename... DRest, template<typename, typename> typename Pred>
|
||||||
|
struct expr_simplify<type_list<power<T, Ints...>, NRest...>, type_list<T, DRest...>, Pred> {
|
||||||
|
using impl = expr_simplify<type_list<NRest...>, type_list<DRest...>, Pred>;
|
||||||
|
using type = expr_simplify_power<T, power<T, Ints...>, power<T, 1>>;
|
||||||
|
using num = type_list_join<typename type::num, typename impl::num>;
|
||||||
|
using den = type_list_join<typename type::den, typename impl::den>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, typename... NRest, typename... DRest, int... Ints, template<typename, typename> typename Pred>
|
||||||
|
struct expr_simplify<type_list<T, NRest...>, type_list<power<T, Ints...>, DRest...>, Pred> {
|
||||||
|
using impl = expr_simplify<type_list<NRest...>, type_list<DRest...>, Pred>;
|
||||||
|
using type = expr_simplify_power<T, power<T, 1>, power<T, Ints...>>;
|
||||||
|
using num = type_list_join<typename impl::num, typename type::num>;
|
||||||
|
using den = type_list_join<typename impl::den, typename type::den>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, typename... NRest, int... Ints1, typename... DRest, int... Ints2,
|
||||||
|
template<typename, typename> typename Pred>
|
||||||
|
requires(!std::same_as<power<T, Ints1...>, power<T, Ints2...>>)
|
||||||
|
struct expr_simplify<type_list<power<T, Ints1...>, NRest...>, type_list<power<T, Ints2...>, DRest...>, Pred> {
|
||||||
|
using impl = expr_simplify<type_list<NRest...>, type_list<DRest...>, Pred>;
|
||||||
|
using type = expr_simplify_power<T, power<T, Ints1...>, power<T, Ints2...>>;
|
||||||
|
using num = type_list_join<typename impl::num, typename type::num>;
|
||||||
|
using den = type_list_join<typename impl::den, typename type::den>;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// expr_less
|
||||||
|
template<typename T1, typename T2, template<typename, typename> typename Pred>
|
||||||
|
struct expr_less_impl : Pred<T1, T2> {};
|
||||||
|
|
||||||
|
template<typename T1, int... Ints1, typename T2, int... Ints2, template<typename, typename> typename Pred>
|
||||||
|
struct expr_less_impl<power<T1, Ints1...>, power<T2, Ints2...>, Pred> : Pred<T1, T2> {};
|
||||||
|
|
||||||
|
template<typename T1, int... Ints, typename T2, template<typename, typename> typename Pred>
|
||||||
|
struct expr_less_impl<power<T1, Ints...>, T2, Pred> : Pred<T1, T2> {};
|
||||||
|
|
||||||
|
template<typename T1, typename T2, int... Ints, template<typename, typename> typename Pred>
|
||||||
|
struct expr_less_impl<T1, power<T2, Ints...>, Pred> : Pred<T1, T2> {};
|
||||||
|
|
||||||
|
template<typename T, int... Ints, template<typename, typename> typename Pred>
|
||||||
|
struct expr_less_impl<T, power<T, Ints...>, Pred> : std::true_type {};
|
||||||
|
|
||||||
|
template<typename T1, typename T2, template<typename, typename> typename Pred>
|
||||||
|
using expr_less = expr_less_impl<T1, T2, Pred>;
|
||||||
|
|
||||||
|
|
||||||
|
// expr_fractions
|
||||||
|
template<typename OneTypeBase, bool PerFound, typename... Ts>
|
||||||
|
struct expr_fractions_impl;
|
||||||
|
|
||||||
|
template<typename OneTypeBase>
|
||||||
|
struct expr_fractions_impl<OneTypeBase, true> {
|
||||||
|
using den = type_list<>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename OneTypeBase, typename T, typename... Rest>
|
||||||
|
struct expr_fractions_impl<OneTypeBase, true, T, Rest...> {
|
||||||
|
using den = type_list_push_front<typename expr_fractions_impl<OneTypeBase, true, Rest...>::den, T>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename OneTypeBase, std::derived_from<OneTypeBase> T, typename... Rest>
|
||||||
|
struct expr_fractions_impl<OneTypeBase, true, T, Rest...> :
|
||||||
|
TYPENAME expr_fractions_impl<OneTypeBase, true, Rest...>::den {};
|
||||||
|
|
||||||
|
template<typename OneTypeBase>
|
||||||
|
struct expr_fractions_impl<OneTypeBase, false> {
|
||||||
|
using num = type_list<>;
|
||||||
|
using den = type_list<>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename OneTypeBase, typename... Rest>
|
||||||
|
struct expr_fractions_impl<OneTypeBase, false, per<Rest...>> {
|
||||||
|
using num = type_list<>;
|
||||||
|
using den = TYPENAME expr_fractions_impl<OneTypeBase, true, Rest...>::den;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename OneTypeBase, std::derived_from<OneTypeBase> T, typename... Rest>
|
||||||
|
struct expr_fractions_impl<OneTypeBase, false, T, Rest...> : expr_fractions_impl<OneTypeBase, false, Rest...> {};
|
||||||
|
|
||||||
|
template<typename OneTypeBase, typename T, typename... Rest>
|
||||||
|
struct expr_fractions_impl<OneTypeBase, false, T, Rest...> {
|
||||||
|
using impl = expr_fractions_impl<OneTypeBase, false, Rest...>;
|
||||||
|
using num = type_list_push_front<typename impl::num, T>;
|
||||||
|
using den = TYPENAME impl::den;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename OneTypeBase, typename... Ts>
|
||||||
|
struct expr_fractions {
|
||||||
|
private:
|
||||||
|
using impl = expr_fractions_impl<OneTypeBase, false, Ts...>;
|
||||||
|
public:
|
||||||
|
using num = TYPENAME impl::num;
|
||||||
|
using den = TYPENAME impl::den;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename NumList, typename DenList, typename OneType, template<typename...> typename To>
|
||||||
|
constexpr auto expr_expression_impl()
|
||||||
|
{
|
||||||
|
constexpr std::size_t num = type_list_size<NumList>;
|
||||||
|
constexpr std::size_t den = type_list_size<DenList>;
|
||||||
|
|
||||||
|
if constexpr (num == 0 && den == 0) {
|
||||||
|
return OneType{};
|
||||||
|
} else if constexpr (num > 0 && den > 0) {
|
||||||
|
return type_list_map<type_list_push_back<NumList, type_list_map<DenList, per>>, To>{};
|
||||||
|
} else if constexpr (den > 0) {
|
||||||
|
return To<OneType, type_list_map<DenList, per>>{};
|
||||||
|
} else {
|
||||||
|
if constexpr (num == 1 && !is_specialization_of_power<type_list_front<NumList>>)
|
||||||
|
// temporary derived type not needed -> just return the original one
|
||||||
|
return type_list_front<NumList>{};
|
||||||
|
else
|
||||||
|
return type_list_map<NumList, To>{};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename NumList, typename DenList, typename OneType, template<typename...> typename To>
|
||||||
|
using expr_expression = decltype(expr_expression_impl<NumList, DenList, OneType, To>());
|
||||||
|
|
||||||
|
template<typename NumList, typename DenList, typename OneType, template<typename, typename> typename Pred,
|
||||||
|
template<typename...> typename To>
|
||||||
|
constexpr auto get_optimized_expression()
|
||||||
|
{
|
||||||
|
using num_list = expr_consolidate<NumList>;
|
||||||
|
using den_list = expr_consolidate<DenList>;
|
||||||
|
using simple = expr_simplify<num_list, den_list, Pred>;
|
||||||
|
using expr = expr_expression<typename simple::num, typename simple::den, OneType, To>;
|
||||||
|
return expr{};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Merges 2 sorted derived dimensions into one units::normalized_dimension
|
||||||
|
*
|
||||||
|
* A result of a dimensional calculation may result with many exponents of the same base dimension originated
|
||||||
|
* from different parts of the equation. As the exponents lists of both operands it is enough to merge them
|
||||||
|
* into one list and consolidate duplicates. Also it is possible that final exponents list will contain only
|
||||||
|
* one element being a base dimension with exponent 1. In such a case the final dimension should be the base
|
||||||
|
* dimension itself.
|
||||||
|
*/
|
||||||
|
template<typename T1, typename T2, typename OneType, template<typename, typename> typename Pred,
|
||||||
|
template<typename...> typename To>
|
||||||
|
constexpr auto expr_multiply()
|
||||||
|
{
|
||||||
|
if constexpr (is_same_v<T1, OneType>) {
|
||||||
|
return T2{};
|
||||||
|
} else if constexpr (is_same_v<T2, OneType>) {
|
||||||
|
return T1{};
|
||||||
|
} else if constexpr (is_specialization_of<T1, To> && is_specialization_of<T2, To>) {
|
||||||
|
return get_optimized_expression<type_list_merge_sorted<typename T1::num, typename T2::num, Pred>,
|
||||||
|
type_list_merge_sorted<typename T1::den, typename T2::den, Pred>, OneType, Pred,
|
||||||
|
To>();
|
||||||
|
} else if constexpr (is_specialization_of<T1, To>) {
|
||||||
|
return get_optimized_expression<type_list_merge_sorted<typename T1::num, type_list<T2>, Pred>, typename T1::den,
|
||||||
|
OneType, Pred, To>();
|
||||||
|
} else if constexpr (is_specialization_of<T2, To>) {
|
||||||
|
return get_optimized_expression<type_list_merge_sorted<typename T2::num, type_list<T1>, Pred>, typename T2::den,
|
||||||
|
OneType, Pred, To>();
|
||||||
|
} else {
|
||||||
|
return get_optimized_expression<type_list_merge_sorted<type_list<T1>, type_list<T2>, Pred>, type_list<>, OneType,
|
||||||
|
Pred, To>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T1, typename T2, typename OneType, template<typename, typename> typename Pred,
|
||||||
|
template<typename...> typename To>
|
||||||
|
constexpr auto expr_divide()
|
||||||
|
{
|
||||||
|
if constexpr (is_same_v<T1, T2>) {
|
||||||
|
return OneType{};
|
||||||
|
} else if constexpr (is_same_v<T2, OneType>) {
|
||||||
|
return T1{};
|
||||||
|
} else if constexpr (is_specialization_of<T1, To> && is_specialization_of<T2, To>) {
|
||||||
|
return get_optimized_expression<type_list_merge_sorted<typename T1::num, typename T2::den, Pred>,
|
||||||
|
type_list_merge_sorted<typename T1::den, typename T2::num, Pred>, OneType, Pred,
|
||||||
|
To>();
|
||||||
|
} else if constexpr (is_specialization_of<T1, To>) {
|
||||||
|
return get_optimized_expression<typename T1::num, type_list_merge_sorted<typename T1::den, type_list<T2>, Pred>,
|
||||||
|
OneType, Pred, To>();
|
||||||
|
} else if constexpr (is_specialization_of<T2, To>) {
|
||||||
|
return get_optimized_expression<type_list_merge_sorted<typename T2::den, type_list<T1>, Pred>, typename T2::num,
|
||||||
|
OneType, Pred, To>();
|
||||||
|
} else {
|
||||||
|
return To<T1, per<T2>>{};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename OneType, template<typename...> typename To>
|
||||||
|
constexpr auto expr_invert()
|
||||||
|
{
|
||||||
|
if constexpr (is_specialization_of<T, To>)
|
||||||
|
return expr_expression<typename T::den, typename T::num, OneType, To>{};
|
||||||
|
else
|
||||||
|
return To<OneType, per<T>>{};
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
} // namespace units
|
50
src/core/include/units/bits/external/type_list.h
vendored
50
src/core/include/units/bits/external/type_list.h
vendored
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <units/bits/external/hacks.h> // IWYU pragma: keep
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
UNITS_DIAGNOSTIC_PUSH
|
UNITS_DIAGNOSTIC_PUSH
|
||||||
@ -42,6 +43,38 @@ inline constexpr bool is_type_list<T<Types...>> = true;
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
concept TypeList = detail::is_type_list<T>;
|
concept TypeList = detail::is_type_list<T>;
|
||||||
|
|
||||||
|
// size
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<template<typename...> typename List, typename... Ts>
|
||||||
|
constexpr std::size_t type_list_size_impl(List<Ts...>)
|
||||||
|
{
|
||||||
|
return sizeof...(Ts);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
template<TypeList List>
|
||||||
|
inline constexpr std::size_t type_list_size = detail::type_list_size_impl(List{});
|
||||||
|
|
||||||
|
// front
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<typename List>
|
||||||
|
struct type_list_front_impl;
|
||||||
|
|
||||||
|
template<template<typename...> typename List, typename T, typename... Ts>
|
||||||
|
struct type_list_front_impl<List<T, Ts...>> {
|
||||||
|
using type = T;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
template<TypeList List>
|
||||||
|
using type_list_front = TYPENAME detail::type_list_front_impl<List>::type;
|
||||||
|
|
||||||
// push_front
|
// push_front
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
@ -218,6 +251,23 @@ struct type_list_sort_impl<List<Types...>, Pred> {
|
|||||||
template<TypeList List, template<typename, typename> typename Pred>
|
template<TypeList List, template<typename, typename> typename Pred>
|
||||||
using type_list_sort = TYPENAME detail::type_list_sort_impl<List, Pred>::type;
|
using type_list_sort = TYPENAME detail::type_list_sort_impl<List, Pred>::type;
|
||||||
|
|
||||||
|
// map
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<typename T, template<typename...> typename To>
|
||||||
|
struct type_list_map_impl;
|
||||||
|
|
||||||
|
template<template<typename...> typename From, template<typename...> typename To, typename... Args>
|
||||||
|
struct type_list_map_impl<From<Args...>, To> {
|
||||||
|
using type = To<Args...>;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
template<TypeList From, template<typename...> typename To>
|
||||||
|
using type_list_map = TYPENAME detail::type_list_map_impl<From, To>::type;
|
||||||
|
|
||||||
} // namespace units
|
} // namespace units
|
||||||
|
|
||||||
UNITS_DIAGNOSTIC_POP
|
UNITS_DIAGNOSTIC_POP
|
||||||
|
27
src/core/include/units/bits/external/type_name.h
vendored
Normal file
27
src/core/include/units/bits/external/type_name.h
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// https://stackoverflow.com/questions/81870/is-it-possible-to-print-a-variables-type-in-standard-c/56766138#56766138
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
constexpr auto type_name()
|
||||||
|
{
|
||||||
|
std::string_view name, prefix, suffix;
|
||||||
|
#ifdef __clang__
|
||||||
|
name = __PRETTY_FUNCTION__;
|
||||||
|
prefix = "auto type_name() [T = ";
|
||||||
|
suffix = "]";
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
name = __PRETTY_FUNCTION__;
|
||||||
|
prefix = "constexpr auto type_name() [with T = ";
|
||||||
|
suffix = "]";
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
name = __FUNCSIG__;
|
||||||
|
prefix = "auto __cdecl type_name<";
|
||||||
|
suffix = ">(void)";
|
||||||
|
#endif
|
||||||
|
name.remove_prefix(prefix.size());
|
||||||
|
name.remove_suffix(suffix.size());
|
||||||
|
return name;
|
||||||
|
}
|
@ -1,92 +0,0 @@
|
|||||||
// The MIT License (MIT)
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018 Mateusz Pusz
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <units/base_dimension.h>
|
|
||||||
#include <units/bits/absolute_magnitude.h>
|
|
||||||
#include <units/bits/derived_dimension_base.h>
|
|
||||||
#include <units/bits/dim_consolidate.h>
|
|
||||||
#include <units/bits/dim_unpack.h>
|
|
||||||
#include <units/bits/external/downcasting.h>
|
|
||||||
#include <units/bits/external/type_list.h>
|
|
||||||
|
|
||||||
// IWYU pragma: begin_exports
|
|
||||||
#include <units/exponent.h>
|
|
||||||
// IWYU pragma: end_exports
|
|
||||||
|
|
||||||
namespace units {
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Converts user provided derived dimension specification into a valid units::derived_dimension_base definition
|
|
||||||
*
|
|
||||||
* User provided definition of a derived dimension may contain the same base dimension repeated more than once on the
|
|
||||||
* list possibly hidden in other derived units provided by the user. The process here should:
|
|
||||||
* 1. Extract derived dimensions into exponents of base dimensions.
|
|
||||||
* 2. Sort the exponents so the same dimensions are placed next to each other.
|
|
||||||
* 3. Consolidate contiguous range of exponents of the same base dimensions to a one (or possibly zero) exponent for
|
|
||||||
* this base dimension.
|
|
||||||
*/
|
|
||||||
template<Exponent... Es>
|
|
||||||
using make_dimension = TYPENAME to_derived_dimension_base<
|
|
||||||
typename dim_consolidate<type_list_sort<typename dim_unpack<Es...>::type, exponent_less>>::type>::type;
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief The list of exponents of dimensions (both base and derived) provided by the user
|
|
||||||
*
|
|
||||||
* This is the user's interface to create derived dimensions. Exponents list can contain powers of factors of both
|
|
||||||
* base and derived dimensions. This is called a "recipe" of the dimension and among others is used to print
|
|
||||||
* unnamed coherent units of this dimension.
|
|
||||||
*
|
|
||||||
* Coherent unit is a unit that, for a given system of quantities and for a chosen set of base units, is a product
|
|
||||||
* of powers of base units with no other proportionality factor than one.
|
|
||||||
*
|
|
||||||
* The implementation is responsible for unpacking all of the dimensions into a list containing only base dimensions
|
|
||||||
* and their factors and putting them to derived_dimension_base class template.
|
|
||||||
*
|
|
||||||
* Sometimes units of equivalent quantities in different systems of units do not share the same reference so they
|
|
||||||
* cannot be easily converted to each other. An example can be a pressure for which a coherent unit in SI is pascal
|
|
||||||
* and in CGS barye. Those two units are not directly related with each other with some ratio. As they both are
|
|
||||||
* coherent units of their dimensions, the ratio between them is directly determined by the ratios of base units
|
|
||||||
* defined in base dimensions end their exponents in the derived dimension recipe. To provide interoperability of
|
|
||||||
* such quantities of different systems mag is being used. The result of the division of two
|
|
||||||
* mag of two quantities of equivalent dimensions in two different systems gives a ratio between their
|
|
||||||
* coherent units. Alternatively, the user would always have to directly define a barye in terms of pascal or vice
|
|
||||||
* versa.
|
|
||||||
*
|
|
||||||
* @tparam Child inherited class type used by the downcasting facility (CRTP Idiom)
|
|
||||||
* @tparam U a coherent unit of a derived dimension
|
|
||||||
* @tparam Es the list of exponents of ingredient dimensions
|
|
||||||
*/
|
|
||||||
template<typename Child, Unit U, Exponent... Es>
|
|
||||||
struct derived_dimension : downcast_dispatch<Child, typename detail::make_dimension<Es...>> {
|
|
||||||
using recipe = exponent_list<Es...>;
|
|
||||||
using coherent_unit = U;
|
|
||||||
static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto mag =
|
|
||||||
detail::absolute_magnitude(typename derived_dimension::exponents()) / U::mag;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace units
|
|
260
src/core/include/units/dimension.h
Normal file
260
src/core/include/units/dimension.h
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
// The MIT License (MIT)
|
||||||
|
//
|
||||||
|
// Copyright (c) 2018 Mateusz Pusz
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all
|
||||||
|
// copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <units/bits/expression_template.h>
|
||||||
|
#include <units/bits/external/fixed_string.h>
|
||||||
|
#include <units/bits/external/type_name.h>
|
||||||
|
#include <units/bits/external/type_traits.h>
|
||||||
|
|
||||||
|
namespace units {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A dimension of a base quantity
|
||||||
|
*
|
||||||
|
* Base quantity is a quantity in a conventionally chosen subset of a given system of quantities, where no quantity
|
||||||
|
* in the subset can be expressed in terms of the other quantities within that subset. They are referred to as
|
||||||
|
* being mutually independent since a base quantity cannot be expressed as a product of powers of the other base
|
||||||
|
* quantities.
|
||||||
|
*
|
||||||
|
* Symbol template parameters is an unique identifier of the base dimension. The same identifiers can be multiplied
|
||||||
|
* and divided which will result with an adjustment of its factor in an Exponent of a DerivedDimension
|
||||||
|
* (in case of zero the dimension will be simplified and removed from further analysis of current expresion).
|
||||||
|
*
|
||||||
|
* @tparam Symbol an unique identifier of the base dimension used to provide dimensional analysis support
|
||||||
|
*/
|
||||||
|
template<basic_fixed_string Symbol>
|
||||||
|
struct base_dimension {
|
||||||
|
static constexpr auto symbol = Symbol; ///< Unique base dimension identifier
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<basic_fixed_string Symbol>
|
||||||
|
void to_base_base_dimension(const volatile base_dimension<Symbol>*);
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A concept matching all base dimensions in the library.
|
||||||
|
*
|
||||||
|
* Satisfied by all dimension types derived from an specialization of `base_dimension`.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
concept BaseDimension = requires(T* t) { detail::to_base_base_dimension(t); };
|
||||||
|
|
||||||
|
template<BaseDimension D1, BaseDimension D2>
|
||||||
|
struct base_dimension_less : std::bool_constant<(D1::symbol < D2::symbol)> {};
|
||||||
|
|
||||||
|
// TODO Can we provide a smarter implementation?
|
||||||
|
std::false_type is_derived_dimension(...);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A concept matching all derived dimensions in the library.
|
||||||
|
*
|
||||||
|
* Satisfied by all dimension types derived from an specialization of `derived_dimension`.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
concept DerivedDimension = decltype(is_derived_dimension(std::declval<T*>()))::value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A concept matching all dimensions in the library.
|
||||||
|
*
|
||||||
|
* Satisfied by all dimension types for which either `BaseDimension<T>` or `DerivedDimension<T>` is `true`.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
concept Dimension = BaseDimension<T> || DerivedDimension<T>;
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unpacks the list of potentially derived dimensions to a list containing only base dimensions
|
||||||
|
*
|
||||||
|
* @tparam Es Exponents of potentially derived dimensions
|
||||||
|
*/
|
||||||
|
template<typename NumList, typename DenList>
|
||||||
|
struct dim_extract;
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct dim_extract<type_list<>, type_list<>> {
|
||||||
|
using num = type_list<>;
|
||||||
|
using den = type_list<>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, typename... NRest, typename... Dens>
|
||||||
|
requires BaseDimension<T> || BaseDimension<typename T::factor>
|
||||||
|
struct dim_extract<type_list<T, NRest...>, type_list<Dens...>> {
|
||||||
|
using impl = dim_extract<type_list<NRest...>, type_list<Dens...>>;
|
||||||
|
using num = type_list_push_front<typename impl::num, T>;
|
||||||
|
using den = TYPENAME impl::den;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, typename... DRest>
|
||||||
|
requires BaseDimension<T> || BaseDimension<typename T::factor>
|
||||||
|
struct dim_extract<type_list<>, type_list<T, DRest...>> {
|
||||||
|
using impl = dim_extract<type_list<>, type_list<DRest...>>;
|
||||||
|
using num = TYPENAME impl::num;
|
||||||
|
using den = type_list_push_front<typename impl::den, T>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<DerivedDimension T, typename... NRest, typename... Dens>
|
||||||
|
struct dim_extract<type_list<T, NRest...>, type_list<Dens...>> :
|
||||||
|
dim_extract<type_list_push_back<typename T::normalized_num, NRest...>,
|
||||||
|
type_list_push_back<typename T::normalized_den, Dens...>> {};
|
||||||
|
|
||||||
|
template<DerivedDimension T, int... Ints, typename... NRest, typename... Dens>
|
||||||
|
struct dim_extract<type_list<power<T, Ints...>, NRest...>, type_list<Dens...>> :
|
||||||
|
dim_extract<type_list_push_back<
|
||||||
|
typename expr_power<typename T::normalized_num, power<T, Ints...>::num, power<T, Ints...>::den>::type,
|
||||||
|
NRest...>,
|
||||||
|
type_list_push_back<
|
||||||
|
typename expr_power<typename T::normalized_den, power<T, Ints...>::num, power<T, Ints...>::den>::type,
|
||||||
|
Dens...>> {};
|
||||||
|
|
||||||
|
|
||||||
|
template<DerivedDimension T, typename... DRest>
|
||||||
|
struct dim_extract<type_list<>, type_list<T, DRest...>> :
|
||||||
|
dim_extract<typename T::normalized_den, type_list_push_back<typename T::normalized_num, DRest...>> {};
|
||||||
|
|
||||||
|
template<DerivedDimension T, int... Ints, typename... DRest>
|
||||||
|
struct dim_extract<type_list<>, type_list<power<T, Ints...>, DRest...>> :
|
||||||
|
dim_extract<typename expr_power<typename T::normalized_den, power<T, Ints...>::num, power<T, Ints...>::den>::type,
|
||||||
|
type_list_push_back<
|
||||||
|
typename expr_power<typename T::normalized_num, power<T, Ints...>::num, power<T, Ints...>::den>::type,
|
||||||
|
DRest...>> {};
|
||||||
|
|
||||||
|
template<typename T1, typename T2>
|
||||||
|
using type_list_of_base_dimension_less = expr_less<T1, T2, base_dimension_less>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Converts user provided derived dimension specification into a valid units::normalized_dimension definition
|
||||||
|
*
|
||||||
|
* User provided definition of a derived dimension may contain the same base dimension repeated more than once on the
|
||||||
|
* list possibly hidden in other derived units provided by the user. The process here should:
|
||||||
|
* 1. Extract derived dimensions into exponents of base dimensions.
|
||||||
|
* 2. Sort the exponents so the same dimensions are placed next to each other.
|
||||||
|
* 3. Consolidate contiguous range of exponents of the same base dimensions to a one (or possibly zero) exponent for
|
||||||
|
* this base dimension.
|
||||||
|
*/
|
||||||
|
template<typename OneTypeBase, typename... Ds>
|
||||||
|
struct normalized_dimension : detail::expr_fractions<OneTypeBase, Ds...> {
|
||||||
|
private:
|
||||||
|
using base = detail::expr_fractions<OneTypeBase, Ds...>;
|
||||||
|
using extracted = dim_extract<typename base::num, typename base::den>;
|
||||||
|
using num_list = expr_consolidate<type_list_sort<typename extracted::num, type_list_of_base_dimension_less>>;
|
||||||
|
using den_list = expr_consolidate<type_list_sort<typename extracted::den, type_list_of_base_dimension_less>>;
|
||||||
|
using simple = expr_simplify<num_list, den_list, type_list_of_base_dimension_less>;
|
||||||
|
public:
|
||||||
|
using normalized_num = TYPENAME simple::num;
|
||||||
|
using normalized_den = TYPENAME simple::den;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
// TODO add checking for `per` and power elements as well
|
||||||
|
template<typename T>
|
||||||
|
concept DimensionSpec = Dimension<T> || is_specialization_of<T, per> || detail::is_specialization_of_power<T>;
|
||||||
|
|
||||||
|
// User should not instantiate this type!!!
|
||||||
|
template<DimensionSpec... Ds>
|
||||||
|
struct derived_dimension : detail::normalized_dimension<derived_dimension<>, Ds...> {};
|
||||||
|
|
||||||
|
// TODO move type_list_fractions out of
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
std::true_type is_derived_dimension(const volatile derived_dimension<Args...>*);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Dimension one
|
||||||
|
*
|
||||||
|
* Dimension for which all the exponents of the factors corresponding to the base
|
||||||
|
* dimensions are zero. Also commonly named as "dimensionless".
|
||||||
|
*/
|
||||||
|
inline constexpr struct dim_one : derived_dimension<> {
|
||||||
|
} dim_one;
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<Dimension D1, Dimension D2>
|
||||||
|
struct dimension_less : std::bool_constant<type_name<D1>() < type_name<D2>()> {};
|
||||||
|
|
||||||
|
template<typename T1, typename T2>
|
||||||
|
using type_list_of_dimension_less = expr_less<T1, T2, dimension_less>;
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
template<Dimension D1, Dimension D2>
|
||||||
|
constexpr Dimension auto operator*(D1, D2)
|
||||||
|
{
|
||||||
|
return detail::expr_multiply<D1, D2, struct dim_one, detail::type_list_of_dimension_less, derived_dimension>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<Dimension D1, Dimension D2>
|
||||||
|
constexpr Dimension auto operator/(D1, D2)
|
||||||
|
{
|
||||||
|
return detail::expr_divide<D1, D2, struct dim_one, detail::type_list_of_dimension_less, derived_dimension>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<Dimension D>
|
||||||
|
constexpr Dimension auto operator/(int value, D)
|
||||||
|
{
|
||||||
|
gsl_Assert(value == 1);
|
||||||
|
return detail::expr_invert<D, struct dim_one, derived_dimension>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<Dimension D1, Dimension D2>
|
||||||
|
constexpr bool operator==(D1, D2)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<BaseDimension D1, BaseDimension D2>
|
||||||
|
constexpr bool operator==(D1, D2)
|
||||||
|
{
|
||||||
|
return D1::symbol == D2::symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<BaseDimension D1, Dimension D2>
|
||||||
|
requires(type_list_size<typename D2::normalized_den> == 0) && (type_list_size<typename D2::normalized_num> == 1) &&
|
||||||
|
BaseDimension<type_list_front<typename D2::normalized_num>>
|
||||||
|
constexpr bool operator==(D1, D2)
|
||||||
|
{
|
||||||
|
return D1::symbol == type_list_front<typename D2::normalized_num>::symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<Dimension D1, BaseDimension D2>
|
||||||
|
requires(type_list_size<typename D1::normalized_den> == 0) && (type_list_size<typename D1::normalized_num> == 1) &&
|
||||||
|
BaseDimension<type_list_front<typename D1::normalized_num>>
|
||||||
|
constexpr bool operator==(D1, D2)
|
||||||
|
{
|
||||||
|
return type_list_front<typename D1::normalized_num>::symbol == D2::symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<DerivedDimension D1, DerivedDimension D2>
|
||||||
|
constexpr bool operator==(D1, D2)
|
||||||
|
{
|
||||||
|
return is_same_v<typename D1::normalized_num, typename D2::normalized_num> &&
|
||||||
|
is_same_v<typename D1::normalized_den, typename D2::normalized_den>;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace units
|
@ -1,85 +0,0 @@
|
|||||||
// The MIT License (MIT)
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018 Mateusz Pusz
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <units/base_dimension.h>
|
|
||||||
#include <units/ratio.h>
|
|
||||||
|
|
||||||
namespace units {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A power of factor corresponding to the dimension of a quantity
|
|
||||||
*
|
|
||||||
* @tparam Dim component dimension of a derived quantity
|
|
||||||
* @tparam Num numinator of the factor
|
|
||||||
* @tparam Den denominator of the factor
|
|
||||||
*/
|
|
||||||
template<Dimension Dim, std::intmax_t Num, std::intmax_t Den = 1>
|
|
||||||
struct exponent {
|
|
||||||
using dimension = Dim;
|
|
||||||
static constexpr std::intmax_t num = Num;
|
|
||||||
static constexpr std::intmax_t den = Den;
|
|
||||||
};
|
|
||||||
|
|
||||||
// is_exponent
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
template<typename Dim, std::intmax_t Num, std::intmax_t Den>
|
|
||||||
inline constexpr bool is_exponent<exponent<Dim, Num, Den>> = true;
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
// exponent_less
|
|
||||||
template<Exponent E1, Exponent E2>
|
|
||||||
requires BaseDimension<typename E1::dimension> && BaseDimension<typename E2::dimension>
|
|
||||||
struct exponent_less : base_dimension_less<typename E1::dimension, typename E2::dimension> {};
|
|
||||||
|
|
||||||
// exponent_invert
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
template<typename Dim, std::intmax_t Num, std::intmax_t Den>
|
|
||||||
constexpr exponent<Dim, -Num, Den> exponent_invert_impl(exponent<Dim, Num, Den>);
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
template<Exponent E>
|
|
||||||
using exponent_invert = decltype(detail::exponent_invert_impl(E()));
|
|
||||||
|
|
||||||
// exponent_multiply
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
template<Exponent E, std::intmax_t Num, std::intmax_t Den>
|
|
||||||
struct exponent_multiply_impl {
|
|
||||||
static constexpr ratio r = ratio(E::num, E::den) * ratio(Num, Den);
|
|
||||||
using type = exponent<typename E::dimension, r.num, r.den>;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
template<Exponent E, std::intmax_t Num, std::intmax_t Den>
|
|
||||||
using exponent_multiply = TYPENAME detail::exponent_multiply_impl<E, Num, Den>::type;
|
|
||||||
|
|
||||||
template<Exponent... Es>
|
|
||||||
struct exponent_list {};
|
|
||||||
|
|
||||||
} // namespace units
|
|
@ -595,7 +595,7 @@ constexpr auto common_magnitude(magnitude<H1, T1...>, magnitude<H2, T2...>)
|
|||||||
} else {
|
} else {
|
||||||
// When the bases are equal, pick whichever has the lower power.
|
// When the bases are equal, pick whichever has the lower power.
|
||||||
constexpr auto common_tail = common_magnitude(magnitude<T1...>{}, magnitude<T2...>{});
|
constexpr auto common_tail = common_magnitude(magnitude<T1...>{}, magnitude<T2...>{});
|
||||||
if constexpr (H1.power < H2.power) {
|
if constexpr ((H1.power) < (H2.power)) {
|
||||||
return magnitude<H1>{} * common_tail;
|
return magnitude<H1>{} * common_tail;
|
||||||
} else {
|
} else {
|
||||||
return magnitude<H2>{} * common_tail;
|
return magnitude<H2>{} * common_tail;
|
||||||
|
@ -1,62 +0,0 @@
|
|||||||
// The MIT License (MIT)
|
|
||||||
//
|
|
||||||
// Copyright (c) 2018 Mateusz Pusz
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
// of this software and associated documentation files (the "Software"), to deal
|
|
||||||
// in the Software without restriction, including without limitation the rights
|
|
||||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
// copies of the Software, and to permit persons to whom the Software is
|
|
||||||
// furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all
|
|
||||||
// copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
// SOFTWARE.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <units/bits/basic_concepts.h>
|
|
||||||
#include <units/bits/external/downcasting.h>
|
|
||||||
// IWYU pragma: begin_exports
|
|
||||||
#include <units/magnitude.h>
|
|
||||||
#include <units/ratio.h>
|
|
||||||
#include <units/symbol_text.h>
|
|
||||||
// IWYU pragma: end_exports
|
|
||||||
|
|
||||||
namespace units {
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
template<Magnitude auto M>
|
|
||||||
struct prefix_base : downcast_base<prefix_base<M>> {
|
|
||||||
static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto mag = M;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A prefix used to scale units
|
|
||||||
*
|
|
||||||
* Data from a prefix class is used in two cases:
|
|
||||||
* - when defining a prefixed_unit its ratio is used to scale the reference unit and its
|
|
||||||
* symbol is used to prepend to the symbol of referenced unit
|
|
||||||
* - when printing the symbol of a scaled unit that was not predefined by the user but its
|
|
||||||
* factor matches ratio of a prefix, its symbol will be prepended to the symbol of the unit
|
|
||||||
*
|
|
||||||
* @tparam Child inherited class type used by the downcasting facility (CRTP Idiom)
|
|
||||||
* @tparam Symbol a text representation of the prefix
|
|
||||||
* @tparam R factor to be used to scale a unit
|
|
||||||
*/
|
|
||||||
template<typename Child, basic_symbol_text Symbol, Magnitude auto M>
|
|
||||||
struct prefix : downcast_dispatch<Child, detail::prefix_base<M>, downcast_mode::on> {
|
|
||||||
static constexpr auto symbol = Symbol;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace units
|
|
@ -22,35 +22,37 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <units/bits/basic_concepts.h>
|
#include <units/dimension.h>
|
||||||
#include <units/bits/dimension_op.h>
|
#include <units/unit.h>
|
||||||
|
|
||||||
namespace units {
|
namespace units {
|
||||||
|
|
||||||
template<Dimension D, UnitOf<D> U, Representation Rep>
|
// TODO Concept for system reference
|
||||||
class quantity;
|
template<auto R, typename Rep = double>
|
||||||
|
class quantity {
|
||||||
|
public:
|
||||||
|
using reference = decltype(R);
|
||||||
|
static constexpr auto dimension = reference::dimension;
|
||||||
|
static constexpr auto unit = reference::unit;
|
||||||
|
|
||||||
template<Dimension D, UnitOf<D> U>
|
quantity(Rep) {}
|
||||||
struct reference;
|
};
|
||||||
|
|
||||||
|
template<typename Child, Dimension auto Dim, Unit auto CoU>
|
||||||
|
struct system_reference;
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
template<Dimension D, Reference R1, Reference R2>
|
template<typename Child, auto Dim, auto CoU>
|
||||||
using reference_multiply_impl = reference<D, downcast_unit<D, R1::mag * R2::mag / D::mag>>;
|
void to_base_specialization_of_system_reference(const volatile system_reference<Child, Dim, CoU>*);
|
||||||
|
|
||||||
template<typename D, Reference R1, Reference R2>
|
template<typename T>
|
||||||
using reference_divide_impl = reference<D, downcast_unit<D, R1::mag / R2::mag / D::mag>>;
|
// inline constexpr bool // TODO: Replace with concept when it works with MSVC
|
||||||
|
concept is_derived_from_specialization_of_system_reference =
|
||||||
|
requires(T* t) { detail::to_base_specialization_of_system_reference(t); };
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
template<Reference R1, Reference R2>
|
|
||||||
using reference_multiply =
|
|
||||||
detail::reference_multiply_impl<dimension_multiply<typename R1::dimension, typename R2::dimension>, R1, R2>;
|
|
||||||
|
|
||||||
template<Reference R1, Reference R2>
|
|
||||||
using reference_divide =
|
|
||||||
detail::reference_divide_impl<dimension_divide<typename R1::dimension, typename R2::dimension>, R1, R2>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The type for quantity references
|
* @brief The type for quantity references
|
||||||
*
|
*
|
||||||
@ -90,50 +92,71 @@ using reference_divide =
|
|||||||
* The following syntaxes are not allowed:
|
* The following syntaxes are not allowed:
|
||||||
* `2 / s`, `km * 3`, `s / 4`, `70 * km / h`.
|
* `2 / s`, `km * 3`, `s / 4`, `70 * km / h`.
|
||||||
*/
|
*/
|
||||||
template<Dimension D, UnitOf<D> U>
|
template<typename T, Unit U>
|
||||||
struct reference {
|
struct reference;
|
||||||
using dimension = D;
|
|
||||||
using unit = U;
|
|
||||||
static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto mag = dimension::mag * unit::mag;
|
|
||||||
|
|
||||||
// Hidden Friends
|
template<typename R, Unit U>
|
||||||
// Below friend functions are to be found via argument-dependent lookup only
|
requires detail::is_derived_from_specialization_of_system_reference<R>
|
||||||
|
struct reference<R, U> {
|
||||||
template<Reference R2>
|
using system_reference = R;
|
||||||
[[nodiscard]] friend constexpr reference_multiply<reference, R2> operator*(reference, R2)
|
static constexpr auto dimension = R::dimension;
|
||||||
{
|
static constexpr U unit{};
|
||||||
return {};
|
// static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto mag = dimension::mag * unit::mag;
|
||||||
}
|
|
||||||
|
|
||||||
template<Reference R2>
|
|
||||||
[[nodiscard]] friend constexpr reference_divide<reference, R2> operator/(reference, R2)
|
|
||||||
{
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
template<Representation Rep>
|
|
||||||
[[nodiscard]] friend constexpr Quantity auto operator*(const Rep& lhs, reference)
|
|
||||||
{
|
|
||||||
return quantity<D, U, Rep>(lhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
friend void /*Use `q * (1 * r)` rather than `q * r`.*/ operator*(Quantity auto, reference) = delete;
|
|
||||||
|
|
||||||
template<Reference R2>
|
|
||||||
[[nodiscard]] friend constexpr bool operator==(reference, R2)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] friend constexpr bool operator==(reference, reference) { return true; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// type traits
|
template<DerivedDimension D, Unit U>
|
||||||
namespace detail {
|
struct reference<D, U> {
|
||||||
|
static constexpr D dimension{};
|
||||||
|
static constexpr U unit{};
|
||||||
|
// static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto mag = dimension::mag * unit::mag;
|
||||||
|
};
|
||||||
|
|
||||||
template<typename D, typename U>
|
// Reference
|
||||||
inline constexpr bool is_reference<reference<D, U>> = true;
|
/**
|
||||||
|
* @brief A concept matching all references in the library.
|
||||||
|
*
|
||||||
|
* Satisfied by all specializations of @c reference.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
concept Reference = is_specialization_of<T, reference>;
|
||||||
|
|
||||||
} // namespace detail
|
template<Reference R1, Reference R2>
|
||||||
|
[[nodiscard]] constexpr reference<decltype(R1::dimension * R2::dimension), decltype(R1::unit * R2::unit)> operator*(R1,
|
||||||
|
R2)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<Reference R1, Reference R2>
|
||||||
|
[[nodiscard]] constexpr reference<decltype(R1::dimension / R2::dimension), decltype(R1::unit / R2::unit)> operator/(R1,
|
||||||
|
R2)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO Update when quantity is done
|
||||||
|
// template<Representation Rep>
|
||||||
|
// [[nodiscard]] friend constexpr Quantity auto operator*(const Rep& lhs, reference)
|
||||||
|
template<typename Rep, Reference R>
|
||||||
|
[[nodiscard]] constexpr quantity<R{}, Rep> operator*(const Rep& lhs, R)
|
||||||
|
{
|
||||||
|
return quantity<R{}, Rep>(lhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
// friend void /*Use `q * (1 * r)` rather than `q * r`.*/ operator*(Quantity auto, reference) = delete;
|
||||||
|
|
||||||
|
// TODO will use deducing this
|
||||||
|
template<typename Child, Dimension auto Dim, Unit auto CoU>
|
||||||
|
struct system_reference {
|
||||||
|
static constexpr auto dimension = Dim;
|
||||||
|
static constexpr auto coherent_unit = CoU;
|
||||||
|
|
||||||
|
template<Unit U>
|
||||||
|
// requires same_unit_reference<CoU, U>
|
||||||
|
[[nodiscard]] constexpr reference<Child, U> operator[](U) const
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace units
|
} // namespace units
|
||||||
|
@ -22,27 +22,28 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <units/bits/derived_symbol_text.h>
|
#include <units/bits/expression_template.h>
|
||||||
#include <units/bits/external/downcasting.h>
|
#include <units/bits/external/fixed_string.h>
|
||||||
|
#include <units/bits/external/type_name.h>
|
||||||
#include <units/bits/external/type_traits.h>
|
#include <units/bits/external/type_traits.h>
|
||||||
|
#include <units/magnitude.h>
|
||||||
|
#include <units/symbol_text.h>
|
||||||
|
|
||||||
|
// #include <units/bits/derived_symbol_text.h>
|
||||||
|
|
||||||
// IWYU pragma: begin_exports
|
// IWYU pragma: begin_exports
|
||||||
#include <units/bits/derived_scaled_unit.h>
|
// #include <units/bits/absolute_magnitude.h>
|
||||||
#include <units/bits/external/fixed_string.h>
|
// #include <units/ratio.h>
|
||||||
#include <units/magnitude.h>
|
|
||||||
#include <units/prefix.h>
|
|
||||||
#include <units/ratio.h>
|
|
||||||
#include <units/symbol_text.h>
|
|
||||||
// IWYU pragma: end_exports
|
// IWYU pragma: end_exports
|
||||||
|
|
||||||
namespace units {
|
namespace units {
|
||||||
|
|
||||||
namespace detail {
|
// namespace detail {
|
||||||
|
|
||||||
template<typename>
|
// template<typename>
|
||||||
inline constexpr bool can_be_prefixed = false;
|
// inline constexpr bool can_be_prefixed = false;
|
||||||
|
|
||||||
} // namespace detail
|
// } // namespace detail
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A common point for a hierarchy of units
|
* @brief A common point for a hierarchy of units
|
||||||
@ -63,16 +64,56 @@ inline constexpr bool can_be_prefixed = false;
|
|||||||
* it gets the incomplete child's type with the CRTP idiom.
|
* it gets the incomplete child's type with the CRTP idiom.
|
||||||
*/
|
*/
|
||||||
template<Magnitude auto M, typename U>
|
template<Magnitude auto M, typename U>
|
||||||
struct scaled_unit : downcast_base<scaled_unit<M, U>> {
|
struct scaled_unit {
|
||||||
static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto mag = M;
|
static constexpr UNITS_MSVC_WORKAROUND(Magnitude) auto mag = M;
|
||||||
using reference = U;
|
using reference = U;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<Dimension D, Magnitude auto M>
|
// TODO: Remove when P1985 accepted
|
||||||
using downcast_unit = downcast<scaled_unit<M, typename dimension_unit<D>::reference>>;
|
namespace detail {
|
||||||
|
|
||||||
template<Unit U1, Unit U2>
|
template<Magnitude auto M, typename U>
|
||||||
struct same_unit_reference : is_same<typename U1::reference, typename U2::reference> {};
|
void to_base_scaled_unit(const volatile scaled_unit<M, U>*);
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A concept matching all unit types in the library
|
||||||
|
*
|
||||||
|
* Satisfied by all unit types derived from an specialization of :class:`scaled_unit`.
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
concept Unit = requires(T* t) { detail::to_base_scaled_unit(t); };
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template<typename>
|
||||||
|
inline constexpr bool is_named = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
concept NamedUnit = Unit<T> && detail::is_named<T>;
|
||||||
|
|
||||||
|
template<Unit auto U1, Unit auto U2>
|
||||||
|
struct same_unit_reference : is_same<typename decltype(U1)::reference, typename decltype(U2)::reference> {};
|
||||||
|
|
||||||
|
// TODO add checking for `per` and power elements as well
|
||||||
|
template<typename T>
|
||||||
|
concept UnitSpec = Unit<T> || is_specialization_of<T, per> || detail::is_specialization_of_power<T>;
|
||||||
|
|
||||||
|
template<UnitSpec... Us>
|
||||||
|
struct derived_unit : detail::expr_fractions<derived_unit<>, Us...>, scaled_unit<mag<1>(), derived_unit<Us...>> {};
|
||||||
|
|
||||||
|
// : detail::normalized_dimension<derived_dimension<>, Ds...> {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unit one
|
||||||
|
*
|
||||||
|
* Unit of a dimensionless quantity.
|
||||||
|
*/
|
||||||
|
inline constexpr struct one : derived_unit<> {
|
||||||
|
} one;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A named unit
|
* @brief A named unit
|
||||||
@ -80,27 +121,35 @@ struct same_unit_reference : is_same<typename U1::reference, typename U2::refere
|
|||||||
* Defines a named (in most cases coherent) unit that is then passed to a dimension definition.
|
* Defines a named (in most cases coherent) unit that is then passed to a dimension definition.
|
||||||
* A named unit may be composed with a prefix to create a prefixed_unit.
|
* A named unit may be composed with a prefix to create a prefixed_unit.
|
||||||
*
|
*
|
||||||
* @tparam Child inherited class type used by the downcasting facility (CRTP Idiom)
|
|
||||||
* @tparam Symbol a short text representation of the unit
|
* @tparam Symbol a short text representation of the unit
|
||||||
*/
|
*/
|
||||||
template<typename Child, basic_symbol_text Symbol>
|
template<basic_symbol_text Symbol, auto...>
|
||||||
struct named_unit : downcast_dispatch<Child, scaled_unit<mag<1>(), Child>> {
|
struct named_unit;
|
||||||
|
|
||||||
|
template<basic_symbol_text Symbol>
|
||||||
|
struct named_unit<Symbol> : scaled_unit<mag<1>(), named_unit<Symbol>> {
|
||||||
static constexpr auto symbol = Symbol;
|
static constexpr auto symbol = Symbol;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<basic_symbol_text Symbol, auto U>
|
||||||
|
requires is_specialization_of<std::remove_const_t<decltype(U)>, derived_unit>
|
||||||
|
struct named_unit<Symbol, U> : decltype(U) {
|
||||||
|
static constexpr auto symbol = Symbol;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A named scaled unit
|
* @brief A named scaled unit
|
||||||
*
|
*
|
||||||
* Defines a new named unit that is a scaled version of another unit.
|
* Defines a new named unit that is a scaled version of another unit.
|
||||||
* A named unit may be composed with a prefix to create a prefixed_unit.
|
* A named unit may be composed with a prefix to create a prefixed_unit.
|
||||||
*
|
*
|
||||||
* @tparam Child inherited class type used by the downcasting facility (CRTP Idiom)
|
|
||||||
* @tparam Symbol a short text representation of the unit
|
* @tparam Symbol a short text representation of the unit
|
||||||
* @tparam M the Magnitude by which to scale U
|
* @tparam M the Magnitude by which to scale U
|
||||||
* @tparam U a reference unit to scale
|
* @tparam U a reference unit to scale
|
||||||
*/
|
*/
|
||||||
template<typename Child, basic_symbol_text Symbol, Magnitude auto M, Unit U>
|
template<basic_symbol_text Symbol, Magnitude auto M, Unit auto U>
|
||||||
struct named_scaled_unit : downcast_dispatch<Child, scaled_unit<M * U::mag, typename U::reference>> {
|
struct named_scaled_unit : scaled_unit<M* decltype(U)::mag, typename decltype(U)::reference> {
|
||||||
static constexpr auto symbol = Symbol;
|
static constexpr auto symbol = Symbol;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -115,11 +164,15 @@ struct named_scaled_unit : downcast_dispatch<Child, scaled_unit<M * U::mag, type
|
|||||||
* @tparam P prefix to be appied to the reference unit
|
* @tparam P prefix to be appied to the reference unit
|
||||||
* @tparam U reference unit
|
* @tparam U reference unit
|
||||||
*/
|
*/
|
||||||
template<typename Child, Prefix P, NamedUnit U>
|
// template<typename Child, Prefix P, NamedUnit U>
|
||||||
requires detail::can_be_prefixed<U>
|
// requires detail::can_be_prefixed<U>
|
||||||
struct prefixed_unit : downcast_dispatch<Child, scaled_unit<P::mag * U::mag, typename U::reference>> {
|
// struct prefixed_unit : downcast_dispatch<Child, scaled_unit<P::mag * U::mag, typename U::reference>> {
|
||||||
static constexpr auto symbol = P::symbol + U::symbol;
|
// static constexpr auto symbol = P::symbol + U::symbol;
|
||||||
};
|
// };
|
||||||
|
|
||||||
|
|
||||||
|
template<basic_symbol_text Symbol, Magnitude auto M, NamedUnit auto U>
|
||||||
|
struct prefixed_unit : scaled_unit<M* decltype(U)::mag, typename decltype(U)::reference> {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A coherent unit of a derived quantity
|
* @brief A coherent unit of a derived quantity
|
||||||
@ -129,105 +182,96 @@ struct prefixed_unit : downcast_dispatch<Child, scaled_unit<P::mag * U::mag, typ
|
|||||||
*
|
*
|
||||||
* @tparam Child inherited class type used by the downcasting facility (CRTP Idiom)
|
* @tparam Child inherited class type used by the downcasting facility (CRTP Idiom)
|
||||||
*/
|
*/
|
||||||
template<typename Child>
|
// template<typename Child>
|
||||||
struct derived_unit : downcast_dispatch<Child, scaled_unit<mag<1>(), Child>> {};
|
// struct derived_unit : downcast_dispatch<Child, scaled_unit<mag<1>(), Child>> {};
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A unit with a deduced ratio and symbol
|
|
||||||
*
|
|
||||||
* Defines a new unit with a deduced ratio and symbol based on the recipe from the provided
|
|
||||||
* derived dimension. The number and order of provided units should match the recipe of the
|
|
||||||
* derived dimension. All of the units provided should also be a named ones so it is possible
|
|
||||||
* to create a deduced symbol text.
|
|
||||||
*
|
|
||||||
* @tparam Child inherited class type used by the downcasting facility (CRTP Idiom)
|
|
||||||
* @tparam Dim a derived dimension recipe to use for deduction
|
|
||||||
* @tparam U the unit of the first composite dimension from provided derived dimension's recipe
|
|
||||||
* @tparam URest the units for the rest of dimensions from the recipe
|
|
||||||
*/
|
|
||||||
template<typename Child, DerivedDimension Dim, NamedUnit U, NamedUnit... URest>
|
|
||||||
requires detail::compatible_units<typename Dim::recipe, U, URest...>
|
|
||||||
struct derived_scaled_unit : downcast_dispatch<Child, detail::derived_scaled_unit<Dim, U, URest...>> {
|
|
||||||
static constexpr auto symbol = detail::derived_symbol_text<Dim, U, URest...>();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief An aliased named unit
|
|
||||||
*
|
|
||||||
* Defines a named alias for another unit. It is useful to assign alternative names and symbols
|
|
||||||
* to the already predefined units (i.e. "tonne" for "megagram").
|
|
||||||
* A alias unit may be composed with a prefix to create a prefixed_alias_unit.
|
|
||||||
*
|
|
||||||
* @tparam U Unit for which an alias is defined
|
|
||||||
* @tparam Symbol a short text representation of the unit
|
|
||||||
*/
|
|
||||||
template<Unit U, basic_symbol_text Symbol>
|
|
||||||
struct alias_unit : U {
|
|
||||||
static constexpr auto symbol = Symbol;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief A prefixed alias unit
|
|
||||||
*
|
|
||||||
* Defines a new unit that is an alias for a scaled version of another unit by the provided
|
|
||||||
* prefix. It is only possible to create such a unit if the given prefix type matches the one
|
|
||||||
* defined in a reference unit.
|
|
||||||
*
|
|
||||||
* @tparam U Unit for which an alias is defined
|
|
||||||
* @tparam P prefix to be appied to the reference unit
|
|
||||||
* @tparam AU reference alias unit
|
|
||||||
*/
|
|
||||||
template<Unit U, Prefix P, AliasUnit AU>
|
|
||||||
requires(!AliasUnit<U>)
|
|
||||||
struct prefixed_alias_unit : U {
|
|
||||||
static constexpr auto symbol = P::symbol + AU::symbol;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Unknown coherent unit
|
|
||||||
*
|
|
||||||
* Used as a coherent unit of an unknown dimension.
|
|
||||||
*/
|
|
||||||
template<Exponent... Es>
|
|
||||||
struct unknown_coherent_unit :
|
|
||||||
downcast_dispatch<unknown_coherent_unit<Es...>,
|
|
||||||
scaled_unit<detail::absolute_magnitude(exponent_list<Es...>()), unknown_coherent_unit<Es...>>> {};
|
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
template<typename Child, basic_symbol_text Symbol>
|
template<basic_symbol_text Symbol>
|
||||||
void is_named_impl(const volatile named_unit<Child, Symbol>*);
|
void is_named_impl(const volatile named_unit<Symbol>*);
|
||||||
|
|
||||||
template<typename Child, basic_symbol_text Symbol, Magnitude auto M, typename U>
|
template<basic_symbol_text Symbol, Magnitude auto M, auto U>
|
||||||
void is_named_impl(const volatile named_scaled_unit<Child, Symbol, M, U>*);
|
void is_named_impl(const volatile named_scaled_unit<Symbol, M, U>*);
|
||||||
|
|
||||||
template<typename Child, typename P, typename U>
|
|
||||||
void is_named_impl(const volatile prefixed_unit<Child, P, U>*);
|
|
||||||
|
|
||||||
template<typename U, basic_symbol_text Symbol>
|
|
||||||
void is_named_impl(const volatile alias_unit<U, Symbol>*);
|
|
||||||
|
|
||||||
template<typename U, typename P, typename AU>
|
|
||||||
void is_named_impl(const volatile prefixed_alias_unit<U, P, AU>*);
|
|
||||||
|
|
||||||
template<Unit U>
|
template<Unit U>
|
||||||
inline constexpr bool is_named<U> = requires(U * u) { is_named_impl(u); };
|
inline constexpr bool is_named<U> = requires(U * u) { is_named_impl(u); };
|
||||||
|
|
||||||
template<typename Child, basic_symbol_text Symbol>
|
// template<typename Child, basic_symbol_text Symbol>
|
||||||
void can_be_prefixed_impl(const volatile named_unit<Child, Symbol>*);
|
// void can_be_prefixed_impl(const volatile named_unit<Child, Symbol>*);
|
||||||
|
|
||||||
template<typename Child, basic_symbol_text Symbol, Magnitude auto M, typename U>
|
// template<typename Child, basic_symbol_text Symbol, Magnitude auto M, typename U>
|
||||||
void can_be_prefixed_impl(const volatile named_scaled_unit<Child, Symbol, M, U>*);
|
// void can_be_prefixed_impl(const volatile named_scaled_unit<Child, Symbol, M, U>*);
|
||||||
|
|
||||||
template<typename U, basic_symbol_text Symbol>
|
// template<typename U, basic_symbol_text Symbol>
|
||||||
void can_be_prefixed_impl(const volatile alias_unit<U, Symbol>*);
|
// void can_be_prefixed_impl(const volatile alias_unit<U, Symbol>*);
|
||||||
|
|
||||||
template<Unit U>
|
// template<Unit U>
|
||||||
inline constexpr bool can_be_prefixed<U> = requires(U * u) { can_be_prefixed_impl(u); };
|
// inline constexpr bool can_be_prefixed<U> = requires(U * u) { can_be_prefixed_impl(u); };
|
||||||
|
|
||||||
template<Magnitude auto M, typename U>
|
// template<Magnitude auto M, typename U>
|
||||||
inline constexpr bool can_be_prefixed<scaled_unit<M, U>> = can_be_prefixed<typename U::reference>;
|
// inline constexpr bool can_be_prefixed<scaled_unit<M, U>> = can_be_prefixed<typename U::reference>;
|
||||||
|
|
||||||
|
|
||||||
|
template<Unit U1, Unit U2>
|
||||||
|
struct unit_less : std::bool_constant<type_name<U1>() < type_name<U2>()> {};
|
||||||
|
|
||||||
|
template<typename T1, typename T2>
|
||||||
|
using type_list_of_unit_less = expr_less<T1, T2, unit_less>;
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
|
template<Unit U1, Unit U2>
|
||||||
|
constexpr Unit auto operator*(U1, U2)
|
||||||
|
{
|
||||||
|
return detail::expr_multiply<U1, U2, struct one, detail::type_list_of_unit_less, derived_unit>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<Unit U1, Unit U2>
|
||||||
|
constexpr Unit auto operator/(U1, U2)
|
||||||
|
{
|
||||||
|
return detail::expr_divide<U1, U2, struct one, detail::type_list_of_unit_less, derived_unit>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<Unit U>
|
||||||
|
constexpr Unit auto operator/(int value, U)
|
||||||
|
{
|
||||||
|
gsl_Assert(value == 1);
|
||||||
|
return detail::expr_invert<U, struct one, derived_unit>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<Unit U1, Unit U2>
|
||||||
|
constexpr bool operator==(U1, U2)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// template<BaseDimension D1, BaseDimension D2>
|
||||||
|
// constexpr bool operator==(D1, D2)
|
||||||
|
// {
|
||||||
|
// return D1::symbol == D2::symbol;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// template<BaseDimension D1, Dimension D2>
|
||||||
|
// requires(type_list_size<typename D2::normalized_den> == 0) && (type_list_size<typename D2::normalized_num> == 1) &&
|
||||||
|
// BaseDimension<type_list_front<typename D2::normalized_num>>
|
||||||
|
// constexpr bool operator==(D1, D2)
|
||||||
|
// {
|
||||||
|
// return D1::symbol == type_list_front<typename D2::normalized_num>::symbol;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// template<Dimension D1, BaseDimension D2>
|
||||||
|
// requires(type_list_size<typename D1::normalized_den> == 0) && (type_list_size<typename D1::normalized_num> == 1) &&
|
||||||
|
// BaseDimension<type_list_front<typename D1::normalized_num>>
|
||||||
|
// constexpr bool operator==(D1, D2)
|
||||||
|
// {
|
||||||
|
// return type_list_front<typename D1::normalized_num>::symbol == D2::symbol;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// template<DerivedDimension D1, DerivedDimension D2>
|
||||||
|
// constexpr bool operator==(D1, D2)
|
||||||
|
// {
|
||||||
|
// return std::is_same_v<typename D1::normalized_num, typename D2::normalized_num> &&
|
||||||
|
// std::is_same_v<typename D1::normalized_den, typename D2::normalized_den>;
|
||||||
|
// }
|
||||||
|
|
||||||
} // namespace units
|
} // namespace units
|
||||||
|
@ -22,31 +22,49 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <units/prefix.h>
|
#include <units/unit.h>
|
||||||
|
|
||||||
namespace units::isq::si {
|
namespace units::isq::si {
|
||||||
|
|
||||||
// clang-format off
|
template<NamedUnit auto U>
|
||||||
struct yocto : prefix<yocto, "y", pow<-24>(mag<10>())> {};
|
struct yocto : prefixed_unit<"y", pow<-24>(mag<10>()), U> {};
|
||||||
struct zepto : prefix<zepto, "z", pow<-21>(mag<10>())> {};
|
template<NamedUnit auto U>
|
||||||
struct atto : prefix<atto, "a", pow<-18>(mag<10>())> {};
|
struct zepto : prefixed_unit<"z", pow<-21>(mag<10>()), U> {};
|
||||||
struct femto : prefix<femto, "f", pow<-15>(mag<10>())> {};
|
template<NamedUnit auto U>
|
||||||
struct pico : prefix<pico, "p", pow<-12>(mag<10>())> {};
|
struct atto : prefixed_unit<"a", pow<-18>(mag<10>()), U> {};
|
||||||
struct nano : prefix<nano, "n", pow<-9>(mag<10>())> {};
|
template<NamedUnit auto U>
|
||||||
struct micro : prefix<micro, basic_symbol_text{"\u00b5", "u"}, pow<-6>(mag<10>())> {};
|
struct femto : prefixed_unit<"f", pow<-15>(mag<10>()), U> {};
|
||||||
struct milli : prefix<milli, "m", pow<-3>(mag<10>())> {};
|
template<NamedUnit auto U>
|
||||||
struct centi : prefix<centi, "c", pow<-2>(mag<10>())> {};
|
struct pico : prefixed_unit<"p", pow<-12>(mag<10>()), U> {};
|
||||||
struct deci : prefix<deci, "d", pow<-1>(mag<10>())> {};
|
template<NamedUnit auto U>
|
||||||
struct deca : prefix<deca, "da", pow<1>(mag<10>())> {};
|
struct nano : prefixed_unit<"n", pow<-9>(mag<10>()), U> {};
|
||||||
struct hecto : prefix<hecto, "h", pow<2>(mag<10>())> {};
|
template<NamedUnit auto U>
|
||||||
struct kilo : prefix<kilo, "k", pow<3>(mag<10>())> {};
|
struct micro : prefixed_unit<basic_symbol_text{"\u00b5", "u"}, pow<-6>(mag<10>()), U> {};
|
||||||
struct mega : prefix<mega, "M", pow<6>(mag<10>())> {};
|
template<NamedUnit auto U>
|
||||||
struct giga : prefix<giga, "G", pow<9>(mag<10>())> {};
|
struct milli : prefixed_unit<"m", pow<-3>(mag<10>()), U> {};
|
||||||
struct tera : prefix<tera, "T", pow<12>(mag<10>())> {};
|
template<NamedUnit auto U>
|
||||||
struct peta : prefix<peta, "P", pow<15>(mag<10>())> {};
|
struct centi : prefixed_unit<"c", pow<-2>(mag<10>()), U> {};
|
||||||
struct exa : prefix<exa, "E", pow<18>(mag<10>())> {};
|
template<NamedUnit auto U>
|
||||||
struct zetta : prefix<zetta, "Z", pow<21>(mag<10>())> {};
|
struct deci : prefixed_unit<"d", pow<-1>(mag<10>()), U> {};
|
||||||
struct yotta : prefix<yotta, "Y", pow<24>(mag<10>())> {};
|
template<NamedUnit auto U>
|
||||||
// clang-format on
|
struct deca : prefixed_unit<"da", pow<1>(mag<10>()), U> {};
|
||||||
|
template<NamedUnit auto U>
|
||||||
|
struct hecto : prefixed_unit<"h", pow<2>(mag<10>()), U> {};
|
||||||
|
template<NamedUnit auto U>
|
||||||
|
struct kilo : prefixed_unit<"k", pow<3>(mag<10>()), U> {};
|
||||||
|
template<NamedUnit auto U>
|
||||||
|
struct mega : prefixed_unit<"M", pow<6>(mag<10>()), U> {};
|
||||||
|
template<NamedUnit auto U>
|
||||||
|
struct giga : prefixed_unit<"G", pow<9>(mag<10>()), U> {};
|
||||||
|
template<NamedUnit auto U>
|
||||||
|
struct tera : prefixed_unit<"T", pow<12>(mag<10>()), U> {};
|
||||||
|
template<NamedUnit auto U>
|
||||||
|
struct peta : prefixed_unit<"P", pow<15>(mag<10>()), U> {};
|
||||||
|
template<NamedUnit auto U>
|
||||||
|
struct exa : prefixed_unit<"E", pow<18>(mag<10>()), U> {};
|
||||||
|
template<NamedUnit auto U>
|
||||||
|
struct zetta : prefixed_unit<"Z", pow<21>(mag<10>()), U> {};
|
||||||
|
template<NamedUnit auto U>
|
||||||
|
struct yotta : prefixed_unit<"Y", pow<24>(mag<10>()), U> {};
|
||||||
|
|
||||||
} // namespace units::isq::si
|
} // namespace units::isq::si
|
||||||
|
Reference in New Issue
Block a user