Merge branch 'master' into feature/more-value-casts

This commit is contained in:
Yves Delley
2024-06-02 08:03:30 +02:00
97 changed files with 2063 additions and 941 deletions
+12 -1
View File
@@ -42,6 +42,9 @@ message(STATUS "${projectPrefix}BUILD_AS_SYSTEM_HEADERS: ${${projectPrefix}BUILD
option(${projectPrefix}BUILD_CXX_MODULES "Add C++ modules to the list of default targets" OFF)
message(STATUS "${projectPrefix}BUILD_CXX_MODULES: ${${projectPrefix}BUILD_CXX_MODULES}")
option(${projectPrefix}API_FREESTANDING "Builds only freestanding part of the library" OFF)
message(STATUS "${projectPrefix}API_FREESTANDING: ${${projectPrefix}API_FREESTANDING}")
if(${projectPrefix}BUILD_AS_SYSTEM_HEADERS)
set(${projectPrefix}_AS_SYSTEM SYSTEM)
endif()
@@ -68,13 +71,21 @@ cache_var_values(API_STRING_VIEW_RET AUTO TRUE FALSE)
set(${projectPrefix}API_NO_CRTP AUTO CACHE STRING "Enable class definitions without CRTP idiom")
cache_var_values(API_NO_CRTP AUTO TRUE FALSE)
set(${projectPrefix}API_CONTRACTS GSL-LITE CACHE STRING "Enable contract checking")
cache_var_values(API_CONTRACTS NONE GSL-LITE MS-GSL)
if(${projectPrefix}API_FREESTANDING AND NOT ${projectPrefix}API_CONTRACTS STREQUAL "NONE")
message(FATAL_ERROR "'${projectPrefix}API_CONTRACTS' should be set to 'NONE' for a freestanding build")
endif()
# C++ features
check_cxx_feature_supported(__cpp_lib_format ${projectPrefix}LIB_FORMAT_SUPPORTED)
check_cxx_feature_supported("__cpp_constexpr >= 202211L" ${projectPrefix}STATIC_CONSTEXPR_VARS_IN_CONSTEXPR_FUNCTIONS)
check_cxx_feature_supported(__cpp_explicit_this_parameter ${projectPrefix}EXPLICIT_THIS_PARAMETER_SUPPORTED)
# validate settings
if(${projectPrefix}API_STD_FORMAT STREQUAL "TRUE"
if(NOT ${projectPrefix}API_FREESTANDING
AND ${projectPrefix}API_STD_FORMAT STREQUAL "TRUE"
AND NOT
(${projectPrefix}LIB_FORMAT_SUPPORTED
# libc++ has a basic supports for std::format but does not set __cpp_lib_format
+1 -1
View File
@@ -54,7 +54,7 @@ function(add_mp_units_module name target_name)
# validate and process arguments
validate_unparsed(${name} ARG)
validate_arguments_exists(${name} ARG DEPENDENCIES MODULE_INTERFACE_UNIT)
validate_arguments_exists(${name} ARG MODULE_INTERFACE_UNIT)
if(${projectPrefix}TARGET_SCOPE STREQUAL INTERFACE)
set(SCOPE "INTERFACE")
+45 -14
View File
@@ -31,17 +31,10 @@ function(set_feature_flag name)
endif()
endfunction()
# find dependencies
if(NOT TARGET gsl::gsl-lite)
find_package(gsl-lite REQUIRED)
endif()
# core library definition
add_mp_units_module(
core mp-units-core
DEPENDENCIES gsl::gsl-lite
HEADERS include/mp-units/bits/core_gmf.h
include/mp-units/bits/fmt.h
include/mp-units/bits/get_associated_quantity.h
include/mp-units/bits/get_common_base.h
include/mp-units/bits/hacks.h
@@ -79,20 +72,35 @@ add_mp_units_module(
include/mp-units/framework/value_cast.h
include/mp-units/compat_macros.h
include/mp-units/concepts.h
include/mp-units/format.h
include/mp-units/framework.h
include/mp-units/math.h
include/mp-units/ostream.h
include/mp-units/random.h
MODULE_INTERFACE_UNIT mp-units-core.cpp
)
if(NOT ${projectPrefix}API_FREESTANDING)
target_sources(
mp-units-core
PUBLIC FILE_SET
HEADERS
BASE_DIRS
${CMAKE_CURRENT_SOURCE_DIR}/include
FILES
include/mp-units/bits/fmt.h
include/mp-units/bits/requires_hosted.h
include/mp-units/math.h
include/mp-units/ostream.h
include/mp-units/format.h
include/mp-units/random.h
)
endif()
set_feature_flag(API_STD_FORMAT)
set_feature_flag(API_STRING_VIEW_RET)
set_feature_flag(API_NO_CRTP)
if(${projectPrefix}API_STD_FORMAT STREQUAL "FALSE" OR (${projectPrefix}API_STD_FORMAT STREQUAL "AUTO"
AND NOT ${projectPrefix}LIB_FORMAT_SUPPORTED)
# Text formatting
if(NOT ${projectPrefix}API_FREESTANDING
AND (${projectPrefix}API_STD_FORMAT STREQUAL "FALSE" OR (${projectPrefix}API_STD_FORMAT STREQUAL "AUTO"
AND NOT ${projectPrefix}LIB_FORMAT_SUPPORTED))
)
if(NOT TARGET fmt::fmt)
find_package(fmt REQUIRED)
@@ -100,6 +108,24 @@ if(${projectPrefix}API_STD_FORMAT STREQUAL "FALSE" OR (${projectPrefix}API_STD_F
target_link_libraries(mp-units-core ${${projectPrefix}TARGET_SCOPE} fmt::fmt)
endif()
# Contracts checking
if(${projectPrefix}API_CONTRACTS STREQUAL "NONE")
target_compile_definitions(mp-units-core ${${projectPrefix}TARGET_SCOPE} ${projectPrefix}API_CONTRACTS=0)
elseif(${projectPrefix}API_CONTRACTS STREQUAL "GSL-LITE")
if(NOT TARGET gsl::gsl-lite)
find_package(gsl-lite REQUIRED)
endif()
target_link_libraries(mp-units-core ${${projectPrefix}TARGET_SCOPE} gsl::gsl-lite)
target_compile_definitions(mp-units-core ${${projectPrefix}TARGET_SCOPE} ${projectPrefix}API_CONTRACTS=2)
elseif(${projectPrefix}API_CONTRACTS STREQUAL "MS-GSL")
if(NOT TARGET Microsoft.GSL::GSL)
find_package(Microsoft.GSL REQUIRED)
endif()
target_link_libraries(mp-units-core ${${projectPrefix}TARGET_SCOPE} Microsoft.GSL::GSL)
target_compile_definitions(mp-units-core ${${projectPrefix}TARGET_SCOPE} ${projectPrefix}API_CONTRACTS=3)
endif()
# C++20 modules
if(${projectPrefix}BUILD_CXX_MODULES)
if(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang")
if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 18)
@@ -112,6 +138,7 @@ if(${projectPrefix}BUILD_CXX_MODULES)
endif()
endif()
# UTF-8 source and execution character set
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
target_compile_options(
mp-units-core ${${projectPrefix}TARGET_SCOPE}
@@ -119,4 +146,8 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
)
endif()
# target_compile_options(mp-units-core ${${projectPrefix}TARGET_SCOPE} "-ftime-trace")
# Freestanding
target_compile_definitions(
mp-units-core ${${projectPrefix}TARGET_SCOPE}
${projectPrefix}HOSTED=$<NOT:$<BOOL:${${projectPrefix}API_FREESTANDING}>>
)
+12 -5
View File
@@ -22,15 +22,14 @@
#pragma once
#include <gsl/gsl-lite.hpp>
#include <mp-units/bits/hacks.h>
#include <mp-units/compat_macros.h>
#include <array>
#include <cmath>
#include <compare>
#include <concepts>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <functional>
#include <initializer_list>
#include <iterator>
@@ -38,14 +37,20 @@
#include <numbers>
#include <numeric>
#include <optional>
#include <random>
#include <sstream>
#include <string>
#include <ranges>
#include <string_view>
#include <tuple>
#include <type_traits>
#include <utility>
#if MP_UNITS_HOSTED
#include <cmath>
#include <locale>
#include <ostream>
#include <random>
#include <sstream>
#include <string>
#if MP_UNITS_USE_FMTLIB
MP_UNITS_DIAGNOSTIC_PUSH
MP_UNITS_DIAGNOSTIC_IGNORE_UNREACHABLE
@@ -56,6 +61,8 @@ MP_UNITS_DIAGNOSTIC_POP
#include <format>
#endif
#endif
#if __cpp_lib_text_encoding
#include <text_encoding>
#endif
+31 -20
View File
@@ -30,11 +30,12 @@
// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic, cppcoreguidelines-pro-type-union-access)
#pragma once
#include <mp-units/bits/module_macros.h>
#include <mp-units/compat_macros.h>
#include <mp-units/ext/algorithm.h>
#ifndef MP_UNITS_IN_MODULE_INTERFACE
#include <gsl/gsl-lite.hpp>
#include <array>
#include <concepts>
#include <cstdint>
#include <limits>
@@ -45,6 +46,9 @@
namespace mp_units::detail {
// TODO the below should be exposed by the C++ Standard Library (used in our examples)
MP_UNITS_EXPORT_BEGIN
enum class fmt_align : std::int8_t { none, left, right, center, numeric };
enum class fmt_arg_id_kind : std::int8_t {
none,
@@ -109,6 +113,8 @@ public:
[[nodiscard]] constexpr const Char& operator[](size_t index) const { return data_[index]; }
};
MP_UNITS_EXPORT_END
template<typename T>
inline constexpr bool is_integer =
std::is_integral_v<T> && !std::is_same_v<T, bool> && !std::is_same_v<T, char> && !std::is_same_v<T, wchar_t>;
@@ -131,24 +137,10 @@ template<typename Char>
template<typename Int>
[[nodiscard]] constexpr std::make_unsigned_t<Int> to_unsigned(Int value)
{
gsl_Expects(std::is_unsigned_v<Int> || value >= 0);
MP_UNITS_EXPECTS(std::is_unsigned_v<Int> || value >= 0);
return static_cast<std::make_unsigned_t<Int>>(value);
}
struct width_checker {
template<typename T>
[[nodiscard]] constexpr unsigned long long operator()(T value) const
{
if constexpr (is_integer<T>) {
if constexpr (std::numeric_limits<T>::is_signed)
if (value < 0) MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("negative width"));
return static_cast<unsigned long long>(value);
}
MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("width is not integer"));
return 0;
}
};
template<class Handler, typename FormatArg>
[[nodiscard]] constexpr int get_dynamic_spec(FormatArg arg)
{
@@ -167,6 +159,9 @@ template<typename Context, typename ID>
return arg;
}
// TODO the below should be exposed by the C++ Standard Library (used in our examples)
MP_UNITS_EXPORT_BEGIN
template<class Handler, typename Context>
constexpr void handle_dynamic_spec(int& value, fmt_arg_ref<typename Context::char_type> ref, Context& ctx)
{
@@ -184,12 +179,28 @@ constexpr void handle_dynamic_spec(int& value, fmt_arg_ref<typename Context::cha
}
}
struct width_checker {
template<typename T>
[[nodiscard]] constexpr unsigned long long operator()(T value) const
{
if constexpr (is_integer<T>) {
if constexpr (std::numeric_limits<T>::is_signed)
if (value < 0) MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("negative width"));
return static_cast<unsigned long long>(value);
}
MP_UNITS_THROW(MP_UNITS_STD_FMT::format_error("width is not integer"));
return 0;
}
};
MP_UNITS_EXPORT_END
// Parses the range [begin, end) as an unsigned integer. This function assumes
// that the range is non-empty and the first character is a digit.
template<typename Char>
[[nodiscard]] constexpr int parse_nonnegative_int(const Char*& begin, const Char* end, int error_value)
{
gsl_Expects(begin != end && '0' <= *begin && *begin <= '9');
MP_UNITS_EXPECTS(begin != end && '0' <= *begin && *begin <= '9');
unsigned value = 0, prev = 0;
auto p = begin;
do {
@@ -250,7 +261,7 @@ template<typename Char, typename Handler>
template<typename Char, typename Handler>
[[nodiscard]] constexpr const Char* parse_arg_id(const Char* begin, const Char* end, Handler& handler)
{
gsl_Expects(begin != end);
MP_UNITS_EXPECTS(begin != end);
Char c = *begin;
if (c != '}' && c != ':') return ::mp_units::detail::do_parse_arg_id(begin, end, handler);
handler.on_auto();
@@ -292,7 +303,7 @@ template<typename Char>
fmt_arg_ref<Char>& ref,
MP_UNITS_STD_FMT::basic_format_parse_context<Char>& ctx)
{
gsl_Expects(begin != end);
MP_UNITS_EXPECTS(begin != end);
if ('0' <= *begin && *begin <= '9') {
const int val = ::mp_units::detail::parse_nonnegative_int(begin, end, -1);
if (val != -1)
@@ -329,7 +340,7 @@ template<typename Char, typename Specs>
[[nodiscard]] constexpr const Char* parse_align(const Char* begin, const Char* end, Specs& specs,
fmt_align default_align = fmt_align::none)
{
gsl_Expects(begin != end);
MP_UNITS_EXPECTS(begin != end);
auto align = fmt_align::none;
auto p = begin + code_point_length(begin);
if (end - p <= 0) p = begin;
@@ -59,7 +59,7 @@ template<AssociatedUnit U>
[[nodiscard]] consteval auto get_associated_quantity_impl(U u);
template<AssociatedUnit U>
using to_quantity_spec = std::remove_const_t<decltype(get_associated_quantity_impl(U{}))>;
using to_quantity_spec = decltype(get_associated_quantity_impl(U{}));
template<AssociatedUnit U>
[[nodiscard]] consteval auto get_associated_quantity_impl(U u)
+23 -3
View File
@@ -73,6 +73,10 @@
#define MP_UNITS_DIAGNOSTIC_IGNORE_DEPRECATED
#endif
#if !defined MP_UNITS_HOSTED && defined __STDC_HOSTED__
#define MP_UNITS_HOSTED __STDC_HOSTED__
#endif
#if MP_UNITS_COMP_MSVC
#define MP_UNITS_TYPENAME typename
@@ -83,10 +87,26 @@
#endif
// TODO revise the below when clang-18 is released
#if MP_UNITS_COMP_CLANG >= 18 && __cplusplus >= 202300L && !defined __cpp_explicit_this_parameter
#if MP_UNITS_COMP_GCC
#define __cpp_explicit_this_parameter 202110L
#define MP_UNITS_REMOVE_CONST(expr) std::remove_const_t<expr>
#else
#define MP_UNITS_REMOVE_CONST(expr) expr
#endif
#if !defined __cpp_lib_ranges_to_container
namespace std {
struct from_range_t {
explicit from_range_t() = default;
};
inline constexpr from_range_t from_range{};
} // namespace std
#endif
+13 -13
View File
@@ -24,9 +24,9 @@
#include <mp-units/bits/hacks.h>
#include <mp-units/bits/module_macros.h>
#include <mp-units/compat_macros.h>
#ifndef MP_UNITS_IN_MODULE_INTERFACE
#include <gsl/gsl-lite.hpp>
#include <compare> // IWYU pragma: export
#include <cstdint>
#include <numeric>
@@ -44,16 +44,16 @@ template<typename T>
{
constexpr std::intmax_t c = std::uintmax_t{1} << (sizeof(std::intmax_t) * 4);
const std::intmax_t a0 = abs(lhs) % c;
const std::intmax_t a1 = abs(lhs) / c;
const std::intmax_t b0 = abs(rhs) % c;
const std::intmax_t b1 = abs(rhs) / c;
[[maybe_unused]] const std::intmax_t a0 = abs(lhs) % c;
[[maybe_unused]] const std::intmax_t a1 = abs(lhs) / c;
[[maybe_unused]] const std::intmax_t b0 = abs(rhs) % c;
[[maybe_unused]] const std::intmax_t b1 = abs(rhs) / c;
// overflow in multiplication
gsl_Assert(a1 == 0 || b1 == 0);
gsl_Assert(a0 * b1 + b0 * a1 < (c >> 1)); // NOLINT(hicpp-signed-bitwise)
gsl_Assert(b0 * a0 <= INTMAX_MAX);
gsl_Assert((a0 * b1 + b0 * a1) * c <= INTMAX_MAX - b0 * a0);
MP_UNITS_ASSERT(a1 == 0 || b1 == 0);
MP_UNITS_ASSERT(a0 * b1 + b0 * a1 < (c >> 1)); // NOLINT(hicpp-signed-bitwise)
MP_UNITS_ASSERT(b0 * a0 <= INTMAX_MAX);
MP_UNITS_ASSERT((a0 * b1 + b0 * a1) * c <= INTMAX_MAX - b0 * a0);
return lhs * rhs;
}
@@ -72,7 +72,7 @@ MP_UNITS_EXPORT struct ratio {
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters, google-explicit-constructor, hicpp-explicit-conversions)
MP_UNITS_CONSTEVAL explicit(false) ratio(std::intmax_t n, std::intmax_t d = 1) : num{n}, den{d}
{
gsl_Expects(den != 0);
MP_UNITS_EXPECTS(den != 0);
if (num == 0)
den = 1;
else {
@@ -112,9 +112,9 @@ MP_UNITS_EXPORT struct ratio {
if (r1.num == r2.num && r1.den == r2.den) return ratio{r1.num, r1.den};
// gcd(a/b,c/d) = gcd(a⋅d, c⋅b) / b⋅d
gsl_Assert(std::numeric_limits<std::intmax_t>::max() / r1.num > r2.den);
gsl_Assert(std::numeric_limits<std::intmax_t>::max() / r2.num > r1.den);
gsl_Assert(std::numeric_limits<std::intmax_t>::max() / r1.den > r2.den);
MP_UNITS_ASSERT(std::numeric_limits<std::intmax_t>::max() / r1.num > r2.den);
MP_UNITS_ASSERT(std::numeric_limits<std::intmax_t>::max() / r2.num > r1.den);
MP_UNITS_ASSERT(std::numeric_limits<std::intmax_t>::max() / r1.den > r2.den);
const std::intmax_t num = std::gcd(r1.num * r2.den, r2.num * r1.den);
const std::intmax_t den = r1.den * r2.den;
@@ -0,0 +1,29 @@
// 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 <mp-units/bits/hacks.h>
#if !MP_UNITS_HOSTED
#error "This header is not available in freestanding mode."
#endif
+3 -2
View File
@@ -23,6 +23,7 @@
#pragma once
#include <mp-units/bits/ratio.h>
#include <mp-units/compat_macros.h>
#include <mp-units/ext/fixed_string.h>
#include <mp-units/ext/type_traits.h>
#include <mp-units/framework/symbol_text.h>
@@ -100,12 +101,12 @@ constexpr Out copy(const symbol_text<N, M>& txt, text_encoding encoding, Out out
for (const char8_t ch : txt.unicode()) *out++ = static_cast<char>(ch);
return out;
} else
throw std::invalid_argument("Unicode text can't be copied to CharT output");
MP_UNITS_THROW(std::invalid_argument("Unicode text can't be copied to CharT output"));
} else {
if constexpr (is_same_v<CharT, char>)
return ::mp_units::detail::copy(txt.ascii().begin(), txt.ascii().end(), out);
else
throw std::invalid_argument("ASCII text can't be copied to CharT output");
MP_UNITS_THROW(std::invalid_argument("ASCII text can't be copied to CharT output"));
}
}
+45 -18
View File
@@ -40,6 +40,15 @@
#endif
#if MP_UNITS_HOSTED
#define MP_UNITS_THROW(expr) throw expr
#else
#include <cstdlib>
#define MP_UNITS_THROW(expr) std::abort()
#endif
#if MP_UNITS_HOSTED
#if defined MP_UNITS_API_STD_FORMAT && !MP_UNITS_API_STD_FORMAT
#define MP_UNITS_USE_FMTLIB 1
@@ -59,21 +68,7 @@
#define MP_UNITS_FMT_TO_ARG_ID(arg) (arg)
#define MP_UNITS_FMT_FROM_ARG_ID(arg) (arg)
// This re-uses code from fmt;
#if FMT_EXCEPTIONS
#if FMT_MSC_VERSION || defined(__NVCC__)
#define MP_UNITS_THROW(x) ::fmt::detail::do_throw(x)
#else
#define MP_UNITS_THROW(x) throw x
#endif
#else
#define MP_UNITS_THROW(x) \
do { \
FMT_ASSERT(false, (x).what()); \
} while (false)
#endif
#else
#else // MP_UNITS_USE_FMTLIB
#if !defined __cpp_lib_format && !defined MP_UNITS_COMP_CLANG
#error "std::formatting facility not supported"
@@ -83,10 +78,8 @@
#define MP_UNITS_FMT_LOCALE(loc) loc
#define MP_UNITS_FMT_TO_ARG_ID(arg) static_cast<std::size_t>(arg)
#define MP_UNITS_FMT_FROM_ARG_ID(arg) static_cast<int>(arg)
#define MP_UNITS_THROW(arg) throw arg
#endif
#endif // MP_UNITS_USE_FMTLIB
#ifndef MP_UNITS_IN_MODULE_INTERFACE
@@ -102,5 +95,39 @@ MP_UNITS_DIAGNOSTIC_POP
#endif
// IWYU pragma: end_exports
#endif
#endif // MP_UNITS_HOSTED
#if MP_UNITS_API_CONTRACTS == 2 || __has_include(<gsl/gsl-lite.hpp>)
#include <gsl/gsl-lite.hpp>
#define MP_UNITS_EXPECTS(expr) gsl_Expects(expr)
#define MP_UNITS_EXPECTS_DEBUG(expr) gsl_ExpectsDebug(expr)
#define MP_UNITS_ASSERT(expr) gsl_Assert(expr)
#define MP_UNITS_ASSERT_DEBUG(expr) gsl_AssertDebug(expr)
#elif MP_UNITS_API_CONTRACTS == 3 || __has_include(<gsl/gsl>)
#include <gsl/gsl>
#include <cassert>
#define MP_UNITS_EXPECTS(expr) Expects(expr)
#if defined NDEBUG
#define MP_UNITS_EXPECTS_DEBUG(expr) static_cast<void>(0)
#else
#define MP_UNITS_EXPECTS_DEBUG(expr) Expects(expr)
#endif
#define MP_UNITS_ASSERT(expr) Expects(expr)
#define MP_UNITS_ASSERT_DEBUG(expr) assert(expr)
#else
#define MP_UNITS_EXPECTS(expr) static_cast<void>(0)
#define MP_UNITS_EXPECTS_DEBUG(expr) static_cast<void>(0)
#define MP_UNITS_ASSERT(expr) static_cast<void>(0)
#define MP_UNITS_ASSERT_DEBUG(expr) static_cast<void>(0)
#endif
// NOLINTEND(cppcoreguidelines-macro-usage)
+17 -41
View File
@@ -20,8 +20,9 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// Copy-pasted C++ standard libraries to be replaced with `import std;` when available
// `#include <algorithm.h>` is too heavy to do in every translation unit
// Copy-pasted C++ standard libraries
// TODO To be replaced with `import std;` when available
// `#include <algorithm.h>` is too heavy to do in every translation unit
#pragma once
@@ -72,45 +73,6 @@ constexpr bool all_of(InputIt first, InputIt last, UnaryPred p)
return find_if_not(first, last, p) == last;
}
template<class InputIt1, class InputIt2>
constexpr bool equal(InputIt1 first1, InputIt1 last1, InputIt2 first2)
{
for (; first1 != last1; ++first1, ++first2) {
if (!(*first1 == *first2)) {
return false;
}
}
return true;
}
template<class I1, class I2, class Cmp>
constexpr auto lexicographical_compare_three_way(I1 first1, I1 last1, I2 first2, I2 last2, Cmp comp)
-> decltype(comp(*first1, *first2))
{
using ret_t = decltype(comp(*first1, *first2));
static_assert(std::disjunction_v<std::is_same<ret_t, std::strong_ordering>, std::is_same<ret_t, std::weak_ordering>,
std::is_same<ret_t, std::partial_ordering>>,
"The return type must be a comparison category type.");
bool exhaust1 = (first1 == last1);
bool exhaust2 = (first2 == last2);
MP_UNITS_DIAGNOSTIC_PUSH
MP_UNITS_DIAGNOSTIC_IGNORE_ZERO_AS_NULLPOINTER_CONSTANT
for (; !exhaust1 && !exhaust2; exhaust1 = (++first1 == last1), exhaust2 = (++first2 == last2))
if (auto c = comp(*first1, *first2); c != 0) return c;
MP_UNITS_DIAGNOSTIC_POP
if (!exhaust1) return std::strong_ordering::greater;
if (!exhaust2) return std::strong_ordering::less;
return std::strong_ordering::equal;
}
template<class I1, class I2>
constexpr auto lexicographical_compare_three_way(I1 first1, I1 last1, I2 first2, I2 last2)
{
return ::mp_units::detail::lexicographical_compare_three_way(first1, last1, first2, last2, std::compare_three_way());
}
template<class ForwardIt>
constexpr ForwardIt max_element(ForwardIt first, ForwardIt last)
{
@@ -170,4 +132,18 @@ constexpr OutputIt copy(InputIt first, InputIt last, OutputIt d_first)
return d_first;
}
template<class ForwardIt1, class ForwardIt2>
constexpr void iter_swap(ForwardIt1 a, ForwardIt2 b)
{
using std::swap;
swap(*a, *b);
}
template<class ForwardIt1, class ForwardIt2>
constexpr ForwardIt2 swap_ranges(ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2)
{
for (; first1 != last1; ++first1, ++first2) iter_swap(first1, first2);
return first2;
}
} // namespace mp_units::detail
+194 -64
View File
@@ -26,18 +26,20 @@
// NOLINTBEGIN(*-avoid-c-arrays)
#pragma once
// TODO use <algorithm> when moved to C++20 modules (parsing takes too long for each translation unit)
#include <mp-units/bits/hacks.h> // IWYU pragma: keep
#include <mp-units/bits/module_macros.h>
#include <mp-units/compat_macros.h> // IWYU pragma: keep
#include <mp-units/ext/algorithm.h>
#include <mp-units/ext/type_traits.h>
#ifndef MP_UNITS_IN_MODULE_INTERFACE
#include <gsl/gsl-lite.hpp>
#include <compare> // IWYU pragma: export
#include <cstddef>
#include <cstdlib>
#include <ostream>
#include <ranges>
#include <string_view>
#if MP_UNITS_HOSTED
#include <ostream>
#endif
#endif
MP_UNITS_EXPORT
@@ -49,121 +51,247 @@ namespace mp_units {
* @tparam CharT Character type to be used by the string
* @tparam N The size of the string
*/
template<typename CharT, std::size_t N>
struct basic_fixed_string {
CharT data_[N + 1] = {};
template<typename CharT, std::size_t N, typename Traits = std::char_traits<CharT>>
class basic_fixed_string {
public:
CharT data_[N + 1] = {}; // exposition only
// types
using traits_type = Traits;
using value_type = CharT;
using pointer = CharT*;
using const_pointer = const CharT*;
using reference = CharT&;
using const_reference = const CharT&;
using const_iterator = const CharT*;
using pointer = value_type*;
using const_pointer = const value_type*;
using reference = value_type&;
using const_reference = const value_type&;
using const_iterator = const value_type*;
using iterator = const_iterator;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using reverse_iterator = const_reverse_iterator;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
constexpr explicit(false) basic_fixed_string(const CharT (&txt)[N + 1]) noexcept
// construction and assignment
template<std::convertible_to<CharT>... Chars>
requires(sizeof...(Chars) == N) && (... && !std::is_pointer_v<Chars>)
constexpr explicit basic_fixed_string(Chars... chars) noexcept : data_{chars..., CharT{}}
{
gsl_Expects(txt[N] == CharT{});
}
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
consteval explicit(false) basic_fixed_string(const CharT (&txt)[N + 1]) noexcept
{
MP_UNITS_EXPECTS(txt[N] == CharT{});
for (std::size_t i = 0; i < N; ++i) data_[i] = txt[i];
}
template<std::input_iterator It, std::sentinel_for<It> S>
requires std::convertible_to<std::iter_value_t<It>, CharT>
constexpr explicit basic_fixed_string(It first, S last) noexcept
constexpr basic_fixed_string(It begin, S end)
{
gsl_Expects(std::distance(first, last) == N);
for (auto it = data_; first != last; ++first, ++it) *it = *first;
MP_UNITS_EXPECTS(std::distance(begin, end) == N);
for (auto it = data_; begin != end; ++begin, ++it) *it = *begin;
}
template<std::convertible_to<CharT>... Rest>
requires(1 + sizeof...(Rest) == N)
constexpr explicit basic_fixed_string(CharT first, Rest... rest) noexcept : data_{first, rest..., CharT{}}
template<std::ranges::input_range R>
requires std::convertible_to<std::ranges::range_reference_t<R>, CharT>
constexpr basic_fixed_string(std::from_range_t, R&& r)
{
MP_UNITS_EXPECTS(std::ranges::size(r) == N);
for (auto it = data_; auto&& v : std::forward<R>(r)) *it++ = std::forward<decltype(v)>(v);
}
[[nodiscard]] constexpr bool empty() const noexcept { return N == 0; }
[[nodiscard]] constexpr size_type size() const noexcept { return N; }
[[nodiscard]] constexpr const_pointer data() const noexcept { return static_cast<const_pointer>(data_); }
[[nodiscard]] constexpr const CharT* c_str() const noexcept { return data(); }
[[nodiscard]] constexpr value_type operator[](size_type index) const noexcept
{
gsl_Expects(index < N);
return data()[index];
}
constexpr basic_fixed_string(const basic_fixed_string&) noexcept = default;
constexpr basic_fixed_string& operator=(const basic_fixed_string&) noexcept = default;
// iterator support
[[nodiscard]] constexpr const_iterator begin() const noexcept { return data(); }
[[nodiscard]] constexpr const_iterator cbegin() const noexcept { return data(); }
[[nodiscard]] constexpr const_iterator end() const noexcept { return data() + size(); }
[[nodiscard]] constexpr const_iterator cend() const noexcept { return data() + size(); }
[[nodiscard]] constexpr const_iterator cbegin() const noexcept { return begin(); }
[[nodiscard]] constexpr const_iterator cend() const noexcept { return end(); }
[[nodiscard]] constexpr const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); }
[[nodiscard]] constexpr const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); }
[[nodiscard]] constexpr const_reverse_iterator crbegin() const noexcept { return rbegin(); }
[[nodiscard]] constexpr const_reverse_iterator crend() const noexcept { return rend(); }
// capacity
[[nodiscard]] static constexpr std::integral_constant<size_type, N> size() noexcept { return {}; }
[[nodiscard]] static constexpr std::integral_constant<size_type, N> length() noexcept { return {}; }
[[nodiscard]] static constexpr std::integral_constant<size_type, N> max_size() noexcept { return {}; }
[[nodiscard]] static constexpr std::bool_constant<N == 0> empty() noexcept { return {}; }
// element access
[[nodiscard]] constexpr const_reference operator[](size_type pos) const
{
MP_UNITS_EXPECTS(pos < N);
return data()[pos];
}
#if MP_UNITS_HOSTED
[[nodiscard]] constexpr const_reference at(size_type pos) const
{
if (pos >= size()) throw std::out_of_range("basic_fixed_string::at");
return (*this)[pos];
}
#endif
[[nodiscard]] constexpr const_reference front() const
{
MP_UNITS_EXPECTS(!empty());
return (*this)[0];
}
[[nodiscard]] constexpr const_reference back() const
{
MP_UNITS_EXPECTS(!empty());
return (*this)[N - 1];
}
// modifiers
constexpr void swap(basic_fixed_string& s) noexcept { swap_ranges(begin(), end(), s.begin()); }
// string operations
[[nodiscard]] constexpr const_pointer c_str() const noexcept { return data(); }
[[nodiscard]] constexpr const_pointer data() const noexcept { return static_cast<const_pointer>(data_); }
[[nodiscard]] constexpr std::basic_string_view<CharT, Traits> view() const noexcept
{
return std::basic_string_view<CharT, Traits>(cbegin(), cend());
}
// NOLINTNEXTLINE(*-explicit-conversions, google-explicit-constructor)
[[nodiscard]] constexpr explicit(false) operator std::basic_string_view<CharT>() const noexcept
[[nodiscard]] constexpr explicit(false) operator std::basic_string_view<CharT, Traits>() const noexcept
{
return std::basic_string_view<CharT>(cbegin(), cend());
return view();
}
template<std::size_t N2>
[[nodiscard]] constexpr friend basic_fixed_string<CharT, N + N2> operator+(
const basic_fixed_string& lhs, const basic_fixed_string<CharT, N2>& rhs) noexcept
[[nodiscard]] constexpr friend basic_fixed_string<CharT, N + N2, Traits> operator+(
const basic_fixed_string& lhs, const basic_fixed_string<CharT, N2, Traits>& rhs) noexcept
{
CharT txt[N + N2 + 1] = {};
for (size_t i = 0; i != N; ++i) txt[i] = lhs[i];
for (size_t i = 0; i != N2; ++i) txt[N + i] = rhs[i];
return basic_fixed_string<CharT, N + N2>(txt);
CharT txt[N + N2];
CharT* it = txt;
for (CharT c : lhs) *it++ = c;
for (CharT c : rhs) *it++ = c;
return basic_fixed_string<CharT, N + N2, Traits>(txt, it);
}
[[nodiscard]] constexpr bool operator==(const basic_fixed_string&) const = default;
template<std::size_t N2>
[[nodiscard]] friend constexpr bool operator==(const basic_fixed_string&, const basic_fixed_string<CharT, N2>&)
[[nodiscard]] constexpr friend basic_fixed_string<CharT, N + 1, Traits> operator+(const basic_fixed_string& lhs,
CharT rhs) noexcept
{
return false;
CharT txt[N + 1];
CharT* it = txt;
for (CharT c : lhs) *it++ = c;
*it++ = rhs;
return basic_fixed_string<CharT, N + 1, Traits>(txt, it);
}
[[nodiscard]] constexpr friend basic_fixed_string<CharT, 1 + N, Traits> operator+(
const CharT lhs, const basic_fixed_string& rhs) noexcept
{
CharT txt[1 + N];
CharT* it = txt;
*it++ = lhs;
for (CharT c : rhs) *it++ = c;
return basic_fixed_string<CharT, 1 + N, Traits>(txt, it);
}
template<std::size_t N2>
[[nodiscard]] consteval friend basic_fixed_string<CharT, N + N2 - 1, Traits> operator+(
const basic_fixed_string& lhs, const CharT (&rhs)[N2]) noexcept
{
MP_UNITS_EXPECTS(rhs[N2 - 1] == CharT{});
CharT txt[N + N2];
CharT* it = txt;
for (CharT c : lhs) *it++ = c;
for (CharT c : rhs) *it++ = c;
return txt;
}
template<std::size_t N1>
[[nodiscard]] consteval friend basic_fixed_string<CharT, N1 + N - 1, Traits> operator+(
const CharT (&lhs)[N1], const basic_fixed_string& rhs) noexcept
{
MP_UNITS_EXPECTS(lhs[N1 - 1] == CharT{});
CharT txt[N1 + N];
CharT* it = txt;
for (size_t i = 0; i != N1 - 1; ++i) *it++ = lhs[i];
for (CharT c : rhs) *it++ = c;
*it++ = CharT();
return txt;
}
// non-member comparison functions
template<size_t N2>
[[nodiscard]] friend constexpr bool operator==(const basic_fixed_string& lhs,
const basic_fixed_string<CharT, N2, Traits>& rhs)
{
return lhs.view() == rhs.view();
}
template<size_t N2>
[[nodiscard]] friend consteval bool operator==(const basic_fixed_string& lhs, const CharT (&rhs)[N2])
{
MP_UNITS_EXPECTS(rhs[N2 - 1] == CharT{});
return lhs.view() == std::basic_string_view<CharT, Traits>(std::cbegin(rhs), std::cend(rhs) - 1);
}
template<size_t N2>
[[nodiscard]] friend constexpr auto operator<=>(const basic_fixed_string& lhs,
const basic_fixed_string<CharT, N2>& rhs)
const basic_fixed_string<CharT, N2, Traits>& rhs)
{
// TODO std::lexicographical_compare_three_way(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
return detail::lexicographical_compare_three_way(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
return lhs.view() <=> rhs.view();
}
template<size_t N2>
[[nodiscard]] friend consteval auto operator<=>(const basic_fixed_string& lhs, const CharT (&rhs)[N2])
{
MP_UNITS_EXPECTS(rhs[N2 - 1] == CharT{});
return lhs.view() <=> std::basic_string_view<CharT, Traits>(std::cbegin(rhs), std::cend(rhs) - 1);
}
template<typename Traits>
// inserters and extractors
#if MP_UNITS_HOSTED
friend std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os,
const basic_fixed_string<CharT, N>& str)
const basic_fixed_string& str)
{
return os << str.c_str();
}
#endif
};
// deduction guides
template<one_of<char, char8_t, char16_t, char32_t, wchar_t> CharT, std::convertible_to<CharT>... Rest>
basic_fixed_string(CharT, Rest...) -> basic_fixed_string<CharT, 1 + sizeof...(Rest)>;
template<typename CharT, std::size_t N>
basic_fixed_string(const CharT (&str)[N]) -> basic_fixed_string<CharT, N - 1>;
template<typename CharT, std::convertible_to<CharT>... Rest>
basic_fixed_string(CharT, Rest...) -> basic_fixed_string<CharT, 1 + sizeof...(Rest)>;
template<one_of<char, char8_t, char16_t, char32_t, wchar_t> CharT, std::size_t N>
basic_fixed_string(std::from_range_t, std::array<CharT, N>) -> basic_fixed_string<CharT, N>;
// typedef-names
template<std::size_t N>
using fixed_string = basic_fixed_string<char, N>;
template<std::size_t N>
using fixed_u8string = basic_fixed_string<char8_t, N>;
template<std::size_t N>
using fixed_u16string = basic_fixed_string<char16_t, N>;
template<std::size_t N>
using fixed_u32string = basic_fixed_string<char32_t, N>;
template<std::size_t N>
using fixed_wstring = basic_fixed_string<wchar_t, N>;
template<std::size_t N>
using fixed_u8string = basic_fixed_string<char8_t, N>;
template<std::size_t N>
using fixed_u16string = basic_fixed_string<char16_t, N>;
template<std::size_t N>
using fixed_u32string = basic_fixed_string<char32_t, N>;
} // namespace mp_units
// hash support
template<std::size_t N>
struct std::hash<mp_units::fixed_string<N>> : std::hash<std::string_view> {};
template<std::size_t N>
struct std::hash<mp_units::fixed_u8string<N>> : std::hash<std::u8string_view> {};
template<std::size_t N>
struct std::hash<mp_units::fixed_u16string<N>> : std::hash<std::u16string_view> {};
template<std::size_t N>
struct std::hash<mp_units::fixed_u32string<N>> : std::hash<std::u32string_view> {};
template<std::size_t N>
struct std::hash<mp_units::fixed_wstring<N>> : std::hash<std::wstring_view> {};
#if MP_UNITS_HOSTED
// formatting support
template<typename CharT, std::size_t N>
struct MP_UNITS_STD_FMT::formatter<mp_units::basic_fixed_string<CharT, N>> : formatter<std::basic_string_view<CharT>> {
template<typename FormatContext>
@@ -172,4 +300,6 @@ struct MP_UNITS_STD_FMT::formatter<mp_units::basic_fixed_string<CharT, N>> : for
return formatter<std::basic_string_view<CharT>>::format(std::basic_string_view<CharT>(str), ctx);
}
};
#endif
// NOLINTEND(*-avoid-c-arrays)
+4 -5
View File
@@ -88,9 +88,8 @@ void to_base_specialization_of(const volatile Type<Params...>*);
} // namespace detail
template<typename T, template<typename...> typename Type>
// inline constexpr bool // TODO: Replace with concept when it works with MSVC
concept is_derived_from_specialization_of = requires(T* t) { detail::to_base_specialization_of<Type>(t); };
inline constexpr bool is_derived_from_specialization_of =
requires(T* t) { detail::to_base_specialization_of<Type>(t); };
namespace detail {
@@ -137,7 +136,7 @@ concept one_of = (false || ... || std::same_as<T, Ts>);
template<typename T, auto... Vs>
[[nodiscard]] consteval bool contains()
{
return (false || ... || is_same_v<std::remove_const_t<decltype(Vs)>, T>);
return (false || ... || is_same_v<MP_UNITS_REMOVE_CONST(decltype(Vs)), T>);
}
template<template<typename...> typename T, typename... Ts>
@@ -161,7 +160,7 @@ template<typename T, std::same_as<T> auto V>
template<typename T, auto V1, auto V2, auto... Vs>
[[nodiscard]] consteval auto get()
{
if constexpr (is_same_v<T, std::remove_const_t<decltype(V1)>>)
if constexpr (is_same_v<T, MP_UNITS_REMOVE_CONST(decltype(V1))>)
return V1;
else
return get<T, V2, Vs...>();
+20 -8
View File
@@ -24,22 +24,21 @@
#pragma once
#include <mp-units/bits/requires_hosted.h>
//
#include <mp-units/bits/fmt.h>
#include <mp-units/bits/module_macros.h>
#include <mp-units/compat_macros.h>
#include <mp-units/ext/algorithm.h>
#include <mp-units/framework/customization_points.h>
#include <mp-units/framework/quantity.h>
#include <mp-units/framework/unit.h>
namespace mp_units::detail {
#ifndef MP_UNITS_IN_MODULE_INTERFACE
#include <locale>
#endif
template<typename Char>
struct fill_align_width_format_specs {
fill_t<Char> fill;
fmt_align align : 4 = fmt_align::none;
int width = 0;
fmt_arg_ref<Char> width_ref;
};
namespace mp_units::detail {
template<typename Char>
[[nodiscard]] constexpr const Char* at_most_one_of(const Char* begin, const Char* end, std::string_view modifiers)
@@ -51,6 +50,17 @@ template<typename Char>
return it;
}
// TODO the below should be exposed by the C++ Standard Library (used in our examples)
MP_UNITS_EXPORT_BEGIN
template<typename Char>
struct fill_align_width_format_specs {
fill_t<Char> fill;
fmt_align align : 4 = fmt_align::none;
int width = 0;
fmt_arg_ref<Char> width_ref;
};
template<typename Char, typename Specs>
[[nodiscard]] constexpr const Char* parse_fill_align_width(MP_UNITS_STD_FMT::basic_format_parse_context<Char>& ctx,
const Char* begin, const Char* end, Specs& specs,
@@ -89,6 +99,8 @@ OutputIt format_global_buffer(OutputIt out, const fill_align_width_format_specs<
return MP_UNITS_STD_FMT::format_to(out, "}}");
}
MP_UNITS_EXPORT_END
} // namespace mp_units::detail
//
@@ -26,6 +26,7 @@
#include <mp-units/bits/hacks.h>
#include <mp-units/bits/module_macros.h>
#include <mp-units/bits/text_tools.h>
#include <mp-units/compat_macros.h>
#include <mp-units/ext/fixed_string.h>
#include <mp-units/ext/type_traits.h>
#include <mp-units/framework/dimension_concepts.h>
@@ -33,12 +34,13 @@
#include <mp-units/framework/symbol_text.h>
#ifndef MP_UNITS_IN_MODULE_INTERFACE
#include <gsl/gsl-lite.hpp>
#include <array>
#include <cstdint>
#include <iterator>
#include <string>
#include <string_view>
#if MP_UNITS_HOSTED
#include <string>
#endif
#endif
namespace mp_units {
@@ -280,7 +282,8 @@ template<typename CharT, std::output_iterator<CharT> Out, typename... Expr>
constexpr Out dimension_symbol_impl(Out out, const derived_dimension<Expr...>&, const dimension_symbol_formatting& fmt,
bool negative_power)
{
gsl_Expects(negative_power == false);
(void)negative_power;
MP_UNITS_EXPECTS(negative_power == false);
return dimension_symbol_impl<CharT>(out, typename derived_dimension<Expr...>::_num_{},
typename derived_dimension<Expr...>::_den_{}, fmt);
}
@@ -317,9 +320,15 @@ MP_UNITS_EXPORT template<dimension_symbol_formatting fmt = dimension_symbol_form
#endif
{
auto get_size = []() consteval {
#if MP_UNITS_HOSTED
std::basic_string<CharT> buffer;
dimension_symbol_to<CharT>(std::back_inserter(buffer), D{}, fmt);
return buffer.size();
#else
std::array<CharT, 128> buffer; // TODO unsafe
auto end = dimension_symbol_to<CharT>(buffer.begin(), D{}, fmt);
return end - buffer.begin();
#endif
};
#if MP_UNITS_API_STRING_VIEW_RET // Permitting static constexpr variables in constexpr functions
@@ -328,8 +337,7 @@ MP_UNITS_EXPORT template<dimension_symbol_formatting fmt = dimension_symbol_form
return std::string_view(buffer.data(), size);
#else
constexpr std::size_t size = get_size();
constexpr auto buffer = detail::get_symbol_buffer<CharT, size, fmt>(D{});
return basic_fixed_string<CharT, size>(buffer.begin(), buffer.end());
return basic_fixed_string(std::from_range, detail::get_symbol_buffer<CharT, size, fmt>(D{}));
#endif
}
@@ -109,6 +109,6 @@ concept Dimension = detail::BaseDimension<T> || detail::DerivedDimension<T>;
* Satisfied when both argument satisfy a `Dimension` concept and when they compare equal.
*/
MP_UNITS_EXPORT template<typename T, auto D>
concept DimensionOf = Dimension<T> && Dimension<std::remove_const_t<decltype(D)>> && (T{} == D);
concept DimensionOf = Dimension<T> && Dimension<MP_UNITS_REMOVE_CONST(decltype(D))> && (T{} == D);
} // namespace mp_units
@@ -534,8 +534,8 @@ template<template<typename> typename Proj, template<typename...> typename To, ty
expr_type_projectable<Proj>... Dens>
[[nodiscard]] consteval auto expr_map_impl(type_list<Nums...>, type_list<Dens...>)
{
return (OneType{} * ... * map_power(typename expr_type_map<std::remove_const_t<Nums>, Proj>::type{})) /
(OneType{} * ... * map_power(typename expr_type_map<std::remove_const_t<Dens>, Proj>::type{}));
return (OneType{} * ... * map_power(typename expr_type_map<Nums, Proj>::type{})) /
(OneType{} * ... * map_power(typename expr_type_map<Dens, Proj>::type{}));
}
/**
@@ -38,6 +38,7 @@
#ifndef MP_UNITS_IN_MODULE_INTERFACE
#include <concepts>
#include <cstdint>
#include <cstdlib>
#include <numbers>
#include <optional>
#endif
@@ -278,7 +279,7 @@ template<typename T>
// As this function should only be called at compile time, the terminations herein function as
// "parameter-compatible static_asserts", and should not result in terminations at runtime.
if (exp < 0) {
std::terminate(); // int_power only supports positive integer powers
std::abort(); // int_power only supports positive integer powers
}
constexpr auto checked_multiply = [](auto a, auto b) {
@@ -286,7 +287,7 @@ template<typename T>
MP_UNITS_DIAGNOSTIC_PUSH
MP_UNITS_DIAGNOSTIC_IGNORE_FLOAT_EQUAL
if (result / a != b) {
std::terminate(); // Wraparound detected
std::abort(); // Wraparound detected
}
MP_UNITS_DIAGNOSTIC_POP
return result;
@@ -294,17 +295,8 @@ template<typename T>
constexpr auto checked_square = [checked_multiply](auto a) { return checked_multiply(a, a); };
// TODO(chogg): Unify this implementation with the one in pow.h. That one takes its exponent as a
// template parameter, rather than a function parameter.
if (exp == 0) {
return T{1};
}
if (exp % 2 == 1) {
return checked_multiply(base, int_power(base, exp - 1));
}
if (exp == 0) return T{1};
if (exp % 2 == 1) return checked_multiply(base, int_power(base, exp - 1));
return checked_square(int_power(base, exp / 2));
}
@@ -319,12 +311,12 @@ template<typename T>
// terminations is to act as "static_assert substitutes", not to actually terminate at runtime.
const auto exp = get_exponent(el);
if (exp.den != 1) {
std::terminate(); // Rational powers not yet supported
std::abort(); // Rational powers not yet supported
}
if (exp.num < 0) {
if constexpr (std::is_integral_v<T>) {
std::terminate(); // Cannot represent reciprocal as integer
std::abort(); // Cannot represent reciprocal as integer
} else {
return T{1} / compute_base_power<T>(inverse(el));
}
@@ -339,7 +331,6 @@ template<typename T>
// The input is the desired result, but in a (wider) intermediate type. The point of this function
// is to cast to the desired type, but avoid overflow in doing so.
template<typename To, typename From>
// TODO(chogg): Migrate this to use `treat_as_floating_point`.
requires(!std::is_integral_v<To> || std::is_integral_v<From>)
[[nodiscard]] consteval To checked_static_cast(From x)
{
@@ -347,7 +338,7 @@ template<typename To, typename From>
// to produce compiler errors, because we cannot `static_assert` on function arguments.
if constexpr (std::is_integral_v<To>) {
if (!std::in_range<To>(x)) {
std::terminate(); // Cannot represent magnitude in this type
std::abort(); // Cannot represent magnitude in this type
}
}
@@ -26,6 +26,7 @@
// IWYU pragma: private, include <mp-units/framework.h>
#include <mp-units/bits/module_macros.h>
#include <mp-units/bits/sudo_cast.h>
#include <mp-units/compat_macros.h>
#include <mp-units/framework/customization_points.h>
#include <mp-units/framework/dimension_concepts.h>
#include <mp-units/framework/quantity_concepts.h>
@@ -36,7 +37,6 @@
#include <mp-units/framework/unit_concepts.h>
#ifndef MP_UNITS_IN_MODULE_INTERFACE
#include <gsl/gsl-lite.hpp>
#include <compare> // IWYU pragma: export
#include <utility>
#endif
@@ -140,8 +140,7 @@ public:
template<typename Value>
requires std::same_as<std::remove_cvref_t<Value>, Rep>
constexpr quantity(Value&& v, std::remove_const_t<decltype(R)>) :
numerical_value_is_an_implementation_detail_(std::forward<Value>(v))
constexpr quantity(Value&& v, decltype(R)) : numerical_value_is_an_implementation_detail_(std::forward<Value>(v))
{
}
@@ -353,7 +352,7 @@ public:
friend constexpr decltype(auto) operator%=(Q&& lhs, const quantity& rhs)
{
gsl_ExpectsDebug(rhs != zero());
MP_UNITS_EXPECTS_DEBUG(rhs != zero());
lhs.numerical_value_is_an_implementation_detail_ %= rhs.numerical_value_is_an_implementation_detail_;
return std::forward<Q>(lhs);
}
@@ -393,7 +392,7 @@ public:
}
friend constexpr decltype(auto) operator/=(Q&& lhs, const Value& v)
{
gsl_ExpectsDebug(v != quantity_values<Value>::zero());
MP_UNITS_EXPECTS_DEBUG(v != quantity_values<Value>::zero());
lhs.numerical_value_is_an_implementation_detail_ /= v;
return std::forward<Q>(lhs);
}
@@ -407,7 +406,7 @@ public:
}
friend constexpr decltype(auto) operator/=(Q1&& lhs, const Q2& rhs)
{
gsl_ExpectsDebug(rhs != rhs.zero());
MP_UNITS_EXPECTS_DEBUG(rhs != rhs.zero());
lhs.numerical_value_is_an_implementation_detail_ /= rhs.numerical_value_is_an_implementation_detail_;
return std::forward<Q1>(lhs);
}
@@ -451,7 +450,7 @@ template<auto R1, typename Rep1, auto R2, typename Rep2>
detail::CommonlyInvocableQuantities<std::modulus<>, quantity<R1, Rep1>, quantity<R2, Rep2>>
[[nodiscard]] constexpr Quantity auto operator%(const quantity<R1, Rep1>& lhs, const quantity<R2, Rep2>& rhs)
{
gsl_ExpectsDebug(rhs != rhs.zero());
MP_UNITS_EXPECTS_DEBUG(rhs != rhs.zero());
using ret = detail::common_quantity_for<std::modulus<>, quantity<R1, Rep1>, quantity<R2, Rep2>>;
const ret ret_lhs(lhs);
const ret ret_rhs(rhs);
@@ -486,7 +485,7 @@ template<auto R1, typename Rep1, auto R2, typename Rep2>
requires detail::InvocableQuantities<std::divides<>, quantity<R1, Rep1>, quantity<R2, Rep2>>
[[nodiscard]] constexpr Quantity auto operator/(const quantity<R1, Rep1>& lhs, const quantity<R2, Rep2>& rhs)
{
gsl_ExpectsDebug(rhs != rhs.zero());
MP_UNITS_EXPECTS_DEBUG(rhs != rhs.zero());
return quantity{lhs.numerical_value_ref_in(get_unit(R1)) / rhs.numerical_value_ref_in(get_unit(R2)), R1 / R2};
}
@@ -495,7 +494,7 @@ template<auto R, typename Rep, typename Value>
detail::InvokeResultOf<get_quantity_spec(R).character, std::divides<>, Rep, const Value&>
[[nodiscard]] constexpr QuantityOf<get_quantity_spec(R)> auto operator/(const quantity<R, Rep>& q, const Value& v)
{
gsl_ExpectsDebug(v != quantity_values<Value>::zero());
MP_UNITS_EXPECTS_DEBUG(v != quantity_values<Value>::zero());
return quantity{q.numerical_value_ref_in(get_unit(R)) / v, R};
}
@@ -41,7 +41,7 @@ void to_base_specialization_of_quantity(const volatile quantity<R, Rep>*);
template<typename T>
inline constexpr bool is_derived_from_specialization_of_quantity =
requires(std::remove_reference_t<T>* t) { to_base_specialization_of_quantity(t); };
requires(T* t) { to_base_specialization_of_quantity(t); };
} // namespace detail
@@ -169,8 +169,7 @@ public:
template<typename Q>
requires QuantityOf<std::remove_cvref_t<Q>, get_quantity_spec(R)> && std::constructible_from<quantity_type, Q>
constexpr quantity_point(Q&& q, std::remove_const_t<decltype(PO)>) :
quantity_from_origin_is_an_implementation_detail_(std::forward<Q>(q))
constexpr quantity_point(Q&& q, decltype(PO)) : quantity_from_origin_is_an_implementation_detail_(std::forward<Q>(q))
{
}
@@ -187,7 +186,6 @@ public:
template<QuantityPointOf<absolute_point_origin> QP>
requires std::constructible_from<quantity_type, typename QP::quantity_type>
// TODO add perfect forwarding
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
constexpr explicit(!std::convertible_to<typename QP::quantity_type, quantity_type>) quantity_point(const QP& qp) :
quantity_from_origin_is_an_implementation_detail_([&] {
@@ -222,7 +220,7 @@ public:
[[nodiscard]] constexpr MP_UNITS_CONSTRAINED_AUTO_WORKAROUND(QuantityPointOf<NewPO{}>) auto point_for(
NewPO new_origin) const
{
if constexpr (is_same_v<NewPO, std::remove_const_t<decltype(point_origin)>>)
if constexpr (is_same_v<NewPO, decltype(PO)>)
return *this;
else
return ::mp_units::quantity_point{*this - new_origin, new_origin};
@@ -388,7 +386,7 @@ explicit(
template<auto R1, auto PO1, typename Rep1, auto R2, typename Rep2>
// TODO simplify when gcc catches up
requires ReferenceOf<std::remove_const_t<decltype(R2)>, PO1.quantity_spec>
requires ReferenceOf<MP_UNITS_REMOVE_CONST(decltype(R2)), PO1.quantity_spec>
[[nodiscard]] constexpr QuantityPoint auto operator+(const quantity_point<R1, PO1, Rep1>& qp,
const quantity<R2, Rep2>& q)
requires requires { qp.quantity_ref_from(PO1) + q; }
@@ -401,7 +399,7 @@ template<auto R1, auto PO1, typename Rep1, auto R2, typename Rep2>
template<auto R1, typename Rep1, auto R2, auto PO2, typename Rep2>
// TODO simplify when gcc catches up
requires ReferenceOf<std::remove_const_t<decltype(R1)>, PO2.quantity_spec>
requires ReferenceOf<MP_UNITS_REMOVE_CONST(decltype(R1)), PO2.quantity_spec>
[[nodiscard]] constexpr QuantityPoint auto operator+(const quantity<R1, Rep1>& q,
const quantity_point<R2, PO2, Rep2>& qp)
requires requires { q + qp.quantity_ref_from(PO2); }
@@ -425,7 +423,7 @@ template<Quantity Q, PointOrigin PO>
template<auto R1, auto PO1, typename Rep1, auto R2, typename Rep2>
// TODO simplify when gcc catches up
requires ReferenceOf<std::remove_const_t<decltype(R2)>, PO1.quantity_spec>
requires ReferenceOf<MP_UNITS_REMOVE_CONST(decltype(R2)), PO1.quantity_spec>
[[nodiscard]] constexpr QuantityPoint auto operator-(const quantity_point<R1, PO1, Rep1>& qp,
const quantity<R2, Rep2>& q)
requires requires { qp.quantity_ref_from(PO1) - q; }
@@ -105,7 +105,7 @@ concept PointOrigin = detail::AbsolutePointOrigin<T> || detail::RelativePointOri
* Satisfied by all quantity point origins that are defined using a provided quantity specification.
*/
MP_UNITS_EXPORT template<typename T, auto QS>
concept PointOriginFor = PointOrigin<T> && QuantitySpecOf<std::remove_const_t<decltype(QS)>, T::quantity_spec>;
concept PointOriginFor = PointOrigin<T> && QuantitySpecOf<MP_UNITS_REMOVE_CONST(decltype(QS)), T::quantity_spec>;
MP_UNITS_EXPORT template<Reference auto R, PointOriginFor<get_quantity_spec(R)> auto PO,
RepresentationOf<get_quantity_spec(R).character> Rep>
@@ -141,7 +141,7 @@ template<PointOrigin PO1, PointOrigin PO2>
template<typename T, auto V>
concept SameAbsolutePointOriginAs =
PointOrigin<T> && PointOrigin<std::remove_const_t<decltype(V)>> && same_absolute_point_origins(T{}, V);
PointOrigin<T> && PointOrigin<MP_UNITS_REMOVE_CONST(decltype(V))> && same_absolute_point_origins(T{}, V);
} // namespace detail
@@ -38,8 +38,10 @@
#include <mp-units/framework/representation_concepts.h>
#ifndef MP_UNITS_IN_MODULE_INTERFACE
#include <concepts>
#include <cstdint>
#include <tuple>
#include <type_traits>
#endif
namespace mp_units {
@@ -216,11 +218,11 @@ MP_UNITS_EXPORT_END
*/
#ifdef MP_UNITS_API_NO_CRTP
template<detail::BaseDimension auto Dim, one_of<quantity_character> auto... Args>
requires(... && !QuantitySpec<std::remove_const_t<decltype(Args)>>)
requires(... && !QuantitySpec<decltype(Args)>)
struct quantity_spec<Dim, Args...> : detail::quantity_spec_interface {
#else
template<typename Self, detail::BaseDimension auto Dim, one_of<quantity_character> auto... Args>
requires(... && !QuantitySpec<std::remove_const_t<decltype(Args)>>)
requires(... && !QuantitySpec<decltype(Args)>)
struct quantity_spec<Self, Dim, Args...> : detail::quantity_spec_interface<Self> {
#endif
static constexpr detail::BaseDimension auto dimension = Dim;
@@ -259,11 +261,11 @@ struct quantity_spec<Self, Dim, Args...> : detail::quantity_spec_interface<Self>
*/
#ifdef MP_UNITS_API_NO_CRTP
template<detail::IntermediateDerivedQuantitySpec auto Eq, one_of<quantity_character> auto... Args>
requires(... && !QuantitySpec<std::remove_const_t<decltype(Args)>>)
requires(... && !QuantitySpec<decltype(Args)>)
struct quantity_spec<Eq, Args...> : detail::quantity_spec_interface {
#else
template<typename Self, detail::IntermediateDerivedQuantitySpec auto Eq, one_of<quantity_character> auto... Args>
requires(... && !QuantitySpec<std::remove_const_t<decltype(Args)>>)
requires(... && !QuantitySpec<decltype(Args)>)
struct quantity_spec<Self, Eq, Args...> : detail::quantity_spec_interface<Self> {
#endif
static constexpr auto _equation_ = Eq;
@@ -300,12 +302,12 @@ struct quantity_spec<Self, Eq, Args...> : detail::quantity_spec_interface<Self>
*/
#ifdef MP_UNITS_API_NO_CRTP
template<detail::NamedQuantitySpec auto QS, one_of<quantity_character, struct is_kind> auto... Args>
requires(... && !QuantitySpec<std::remove_const_t<decltype(Args)>>)
struct quantity_spec<QS, Args...> : std::remove_const_t<decltype(QS)> {
requires(... && !QuantitySpec<decltype(Args)>)
struct quantity_spec<QS, Args...> : decltype(QS) {
#else
template<typename Self, detail::NamedQuantitySpec auto QS, one_of<quantity_character, struct is_kind> auto... Args>
requires(... && !QuantitySpec<std::remove_const_t<decltype(Args)>>)
struct quantity_spec<Self, QS, Args...> : std::remove_const_t<decltype(QS)> {
requires(... && !QuantitySpec<decltype(Args)>)
struct quantity_spec<Self, QS, Args...> : decltype(QS) {
#endif
static constexpr auto _parent_ = QS;
static constexpr quantity_character character = detail::quantity_character_init<Args...>(QS.character);
@@ -359,16 +361,16 @@ struct quantity_spec<Self, QS, Args...> : std::remove_const_t<decltype(QS)> {
#ifdef MP_UNITS_API_NO_CRTP
template<detail::NamedQuantitySpec auto QS, detail::IntermediateDerivedQuantitySpec auto Eq,
one_of<quantity_character, struct is_kind> auto... Args>
requires(!requires { QS._equation_; } ||
(requires { QS._equation_; } && (explicitly_convertible(Eq, QS._equation_)))) &&
(... && !QuantitySpec<std::remove_const_t<decltype(Args)>>)
requires(!requires { QS._equation_; } || (requires {
QS._equation_;
} && (explicitly_convertible(Eq, QS._equation_)))) && (... && !QuantitySpec<decltype(Args)>)
struct quantity_spec<QS, Eq, Args...> : quantity_spec<QS, Args...> {
#else
template<typename Self, detail::NamedQuantitySpec auto QS, detail::IntermediateDerivedQuantitySpec auto Eq,
one_of<quantity_character, struct is_kind> auto... Args>
requires(!requires { QS._equation_; } ||
(requires { QS._equation_; } && (explicitly_convertible(Eq, QS._equation_)))) &&
(... && !QuantitySpec<std::remove_const_t<decltype(Args)>>)
requires(!requires { QS._equation_; } || (requires {
QS._equation_;
} && (explicitly_convertible(Eq, QS._equation_)))) && (... && !QuantitySpec<decltype(Args)>)
struct quantity_spec<Self, QS, Eq, Args...> : quantity_spec<Self, QS, Args...> {
#endif
static constexpr auto _equation_ = Eq;
@@ -481,7 +483,7 @@ struct kind_of_<Q> : quantity_spec<kind_of_<Q>, Q{}> {
MP_UNITS_EXPORT template<detail::QuantitySpecWithNoSpecifiers auto Q>
requires(detail::get_kind_tree_root(Q) == Q)
inline constexpr kind_of_<std::remove_const_t<decltype(Q)>> kind_of;
inline constexpr kind_of_<MP_UNITS_REMOVE_CONST(decltype(Q))> kind_of;
namespace detail {
@@ -491,7 +493,7 @@ struct is_dimensionless<struct dimensionless> : std::true_type {};
template<QuantitySpec auto... From, QuantitySpec Q>
[[nodiscard]] consteval QuantitySpec auto clone_kind_of(Q q)
{
if constexpr ((... && QuantityKindSpec<std::remove_const_t<decltype(From)>>))
if constexpr ((... && QuantityKindSpec<MP_UNITS_REMOVE_CONST(decltype(From))>))
return kind_of<Q{}>;
else
return q;
@@ -550,11 +552,6 @@ template<std::intmax_t Num, std::intmax_t Den = 1, QuantitySpec Q>
requires detail::non_zero<Den>
[[nodiscard]] consteval QuantitySpec auto pow(Q q)
{
// TODO Does the below make sense?
// `2 * 2` should compare to `4`
// `2 * one * (2 * one)` should compare to `4 * one`
// `2 * rad * (2 * rad)` should compare to `4 * rad^2`
// all are dimensionless quantities :-(
if constexpr (Num == 0 || Q{} == dimensionless)
return dimensionless;
else if constexpr (detail::ratio{Num, Den} == 1)
@@ -564,11 +561,9 @@ template<std::intmax_t Num, std::intmax_t Den = 1, QuantitySpec Q>
detail::expr_pow<Num, Den, derived_quantity_spec, struct dimensionless, detail::type_list_of_quantity_spec_less>(
detail::remove_kind(q)));
else if constexpr (Den == 1)
return detail::clone_kind_of<Q{}>(
derived_quantity_spec<power<std::remove_const_t<decltype(detail::remove_kind(Q{}))>, Num>>{});
return detail::clone_kind_of<Q{}>(derived_quantity_spec<power<decltype(detail::remove_kind(Q{})), Num>>{});
else
return detail::clone_kind_of<Q{}>(
derived_quantity_spec<power<std::remove_const_t<decltype(detail::remove_kind(Q{}))>, Num, Den>>{});
return detail::clone_kind_of<Q{}>(derived_quantity_spec<power<decltype(detail::remove_kind(Q{})), Num, Den>>{});
}
@@ -915,12 +910,11 @@ template<typename From, typename To>
return extract_results{false};
else if constexpr (from_exp > to_exp)
return extract_results{true, pow<to_exp.num, to_exp.den>(from_factor), pow<to_exp.num, to_exp.den>(to_factor),
prepend_rest::first,
power_or_T<std::remove_cvref_t<decltype(from_factor)>, from_exp - to_exp>{}};
prepend_rest::first, power_or_T<decltype(from_factor), from_exp - to_exp>{}};
else
return extract_results{true, pow<from_exp.num, from_exp.den>(from_factor),
pow<from_exp.num, from_exp.den>(to_factor), prepend_rest::second,
power_or_T<std::remove_cvref_t<decltype(to_factor)>, to_exp - from_exp>{}};
power_or_T<decltype(to_factor), to_exp - from_exp>{}};
}
}
@@ -934,7 +928,7 @@ template<process_entities Entities, auto Ext, TypeList NumFrom, TypeList DenFrom
if constexpr (Ext.prepend == prepend_rest::no)
return min(res, are_ingredients_convertible(num_from, den_from, num_to, den_to));
else {
using elem = std::remove_cvref_t<decltype(Ext.elem)>;
using elem = decltype(Ext.elem);
if constexpr (Entities == process_entities::numerators) {
if constexpr (Ext.prepend == prepend_rest::first)
return min(res, are_ingredients_convertible(type_list_push_front<NumFrom, elem>{}, den_from, num_to, den_to));
@@ -959,7 +953,7 @@ template<process_entities Entities, auto Ext, TypeList NumFrom, TypeList DenFrom
if constexpr (Ext.prepend == prepend_rest::no)
return are_ingredients_convertible(num_from, den_from, num_to, den_to);
else {
using elem = std::remove_cvref_t<decltype(Ext.elem)>;
using elem = decltype(Ext.elem);
if constexpr (Entities == process_entities::from) {
if constexpr (Ext.prepend == prepend_rest::first)
return are_ingredients_convertible(type_list_push_front<NumFrom, elem>{}, den_from, num_to, den_to);
@@ -1342,8 +1336,7 @@ template<QuantitySpec From, QuantitySpec To>
using enum specs_convertible_result;
return res == no ? no : yes;
};
if constexpr ((NamedQuantitySpec<std::remove_cvref_t<decltype(from_kind)>> &&
NamedQuantitySpec<std::remove_cvref_t<decltype(to_kind)>>) ||
if constexpr ((NamedQuantitySpec<decltype(from_kind)> && NamedQuantitySpec<decltype(to_kind)>) ||
get_complexity(from_kind) == get_complexity(to_kind))
return convertible_impl(from_kind, to_kind);
else if constexpr (get_complexity(from_kind) > get_complexity(to_kind))
@@ -1396,7 +1389,7 @@ template<QuantitySpec From, QuantitySpec To>
return are_ingredients_convertible(from, to);
} else if constexpr (IntermediateDerivedQuantitySpec<From>) {
auto res = explode<get_complexity(to)>(from);
if constexpr (NamedQuantitySpec<std::remove_const_t<decltype(res.quantity)>>)
if constexpr (NamedQuantitySpec<decltype(res.quantity)>)
return convertible_impl(res.quantity, to);
else if constexpr (requires { to._equation_; }) {
auto eq = explode_to_equation(to);
@@ -1405,7 +1398,7 @@ template<QuantitySpec From, QuantitySpec To>
return are_ingredients_convertible(from, to);
} else if constexpr (IntermediateDerivedQuantitySpec<To>) {
auto res = explode<get_complexity(from)>(to);
if constexpr (NamedQuantitySpec<std::remove_const_t<decltype(res.quantity)>>)
if constexpr (NamedQuantitySpec<decltype(res.quantity)>)
return min(res.result, convertible_impl(from, res.quantity));
else if constexpr (requires { from._equation_; })
return min(res.result, convertible_impl(from._equation_, res.quantity));
@@ -1450,7 +1443,7 @@ namespace detail {
template<QuantitySpec Q>
requires requires(Q q) { get_kind_tree_root(q); }
using to_kind = std::remove_const_t<decltype(get_kind_tree_root(Q{}))>;
using to_kind = decltype(get_kind_tree_root(Q{}));
#ifdef MP_UNITS_API_NO_CRTP
template<NamedQuantitySpec auto QS, auto... Args>
@@ -1507,8 +1500,8 @@ template<QuantitySpec Q1, QuantitySpec Q2>
requires(implicitly_convertible(get_kind_tree_root(q1), get_kind_tree_root(q2)) ||
implicitly_convertible(get_kind_tree_root(q2), get_kind_tree_root(q1)))
{
using QQ1 = std::remove_const_t<decltype(detail::remove_kind(q1))>;
using QQ2 = std::remove_const_t<decltype(detail::remove_kind(q2))>;
using QQ1 = decltype(detail::remove_kind(q1));
using QQ2 = decltype(detail::remove_kind(q2));
// NOLINTBEGIN(bugprone-branch-clone)
if constexpr (is_same_v<Q1, Q2>)
@@ -140,15 +140,14 @@ namespace detail {
template<auto To, auto From>
concept NestedQuantityKindSpecOf =
QuantitySpec<std::remove_const_t<decltype(From)>> && QuantitySpec<std::remove_const_t<decltype(To)>> &&
get_kind(From) != get_kind(To) &&
std::derived_from<std::remove_cvref_t<decltype(To)>, std::remove_cvref_t<decltype(get_kind(From)._quantity_spec_)>>;
QuantitySpec<decltype(From)> && QuantitySpec<decltype(To)> && get_kind(From) != get_kind(To) &&
std::derived_from<decltype(To), std::remove_const_t<decltype(get_kind(From)._quantity_spec_)>>;
}
MP_UNITS_EXPORT template<typename T, auto QS>
concept QuantitySpecOf =
QuantitySpec<T> && QuantitySpec<std::remove_const_t<decltype(QS)>> && implicitly_convertible(T{}, QS) &&
QuantitySpec<T> && QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS))> && implicitly_convertible(T{}, QS) &&
// the below is to make the following work
// static_assert(ReferenceOf<si::radian, isq::angular_measure>);
// static_assert(!ReferenceOf<si::radian, dimensionless>);
@@ -38,7 +38,7 @@ namespace mp_units {
namespace detail {
template<QuantitySpec auto Q, Unit auto U>
using reference_t = reference<std::remove_const_t<decltype(Q)>, std::remove_const_t<decltype(U)>>;
using reference_t = reference<MP_UNITS_REMOVE_CONST(decltype(Q)), MP_UNITS_REMOVE_CONST(decltype(U))>;
}
@@ -258,13 +258,13 @@ MP_UNITS_EXPORT_END
namespace detail {
template<AssociatedUnit auto To, AssociatedUnit From>
[[nodiscard]] consteval std::remove_const_t<decltype(To)> clone_reference_with(From)
[[nodiscard]] consteval MP_UNITS_REMOVE_CONST(decltype(To)) clone_reference_with(From)
{
return {};
}
template<Unit auto To, QuantitySpec QS, Unit U>
[[nodiscard]] consteval reference<QS, std::remove_const_t<decltype(To)>> clone_reference_with(reference<QS, U>)
[[nodiscard]] consteval reference<QS, MP_UNITS_REMOVE_CONST(decltype(To))> clone_reference_with(reference<QS, U>)
{
return {};
}
@@ -76,7 +76,7 @@ template<typename Q, typename U>
* the provided quantity_spec type.
*/
template<typename T, auto QS>
concept ReferenceOf = Reference<T> && QuantitySpecOf<std::remove_const_t<decltype(get_quantity_spec(T{}))>, QS>;
concept ReferenceOf = Reference<T> && QuantitySpecOf<decltype(get_quantity_spec(T{})), QS>;
MP_UNITS_EXPORT_END
@@ -26,10 +26,11 @@
// IWYU pragma: private, include <mp-units/framework.h>
#include <mp-units/bits/hacks.h>
#include <mp-units/bits/module_macros.h>
#include <mp-units/compat_macros.h>
#include <mp-units/ext/algorithm.h>
#include <mp-units/ext/fixed_string.h>
#ifndef MP_UNITS_IN_MODULE_INTERFACE
#include <gsl/gsl-lite.hpp>
#include <compare> // IWYU pragma: export
#include <cstddef>
#include <cstdint>
@@ -85,41 +86,42 @@ constexpr fixed_u8string<N> to_u8string(fixed_string<N> txt)
* @tparam M The size of the ASCII-only symbol
*/
MP_UNITS_EXPORT template<std::size_t N, std::size_t M>
struct symbol_text {
class symbol_text {
public:
fixed_u8string<N> unicode_;
fixed_string<M> ascii_;
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
constexpr explicit(false) symbol_text(char ch) : unicode_(static_cast<char8_t>(ch)), ascii_(ch)
{
gsl_Expects(detail::is_basic_literal_character_set_char(ch));
MP_UNITS_EXPECTS(detail::is_basic_literal_character_set_char(ch));
}
// NOLINTNEXTLINE(*-avoid-c-arrays, google-explicit-constructor, hicpp-explicit-conversions)
constexpr explicit(false) symbol_text(const char (&txt)[N + 1]) :
consteval explicit(false) symbol_text(const char (&txt)[N + 1]) :
unicode_(detail::to_u8string(basic_fixed_string{txt})), ascii_(txt)
{
gsl_Expects(txt[N] == char{});
gsl_Expects(detail::is_basic_literal_character_set(txt));
MP_UNITS_EXPECTS(txt[N] == char{});
MP_UNITS_EXPECTS(detail::is_basic_literal_character_set(txt));
}
// NOLINTNEXTLINE(google-explicit-constructor, hicpp-explicit-conversions)
constexpr explicit(false) symbol_text(const fixed_string<N>& txt) : unicode_(detail::to_u8string(txt)), ascii_(txt)
{
gsl_Expects(detail::is_basic_literal_character_set(txt.data_));
MP_UNITS_EXPECTS(detail::is_basic_literal_character_set(txt.data_));
}
// NOLINTNEXTLINE(*-avoid-c-arrays)
constexpr symbol_text(const char8_t (&u)[N + 1], const char (&a)[M + 1]) : unicode_(u), ascii_(a)
consteval symbol_text(const char8_t (&u)[N + 1], const char (&a)[M + 1]) : unicode_(u), ascii_(a)
{
gsl_Expects(u[N] == char8_t{});
gsl_Expects(a[M] == char{});
gsl_Expects(detail::is_basic_literal_character_set(a));
MP_UNITS_EXPECTS(u[N] == char8_t{});
MP_UNITS_EXPECTS(a[M] == char{});
MP_UNITS_EXPECTS(detail::is_basic_literal_character_set(a));
}
constexpr symbol_text(const fixed_u8string<N>& u, const fixed_string<M>& a) : unicode_(u), ascii_(a)
{
gsl_Expects(detail::is_basic_literal_character_set(a.data_));
MP_UNITS_EXPECTS(detail::is_basic_literal_character_set(a.data_));
}
[[nodiscard]] constexpr const auto& unicode() const { return unicode_; }
@@ -127,7 +129,7 @@ struct symbol_text {
[[nodiscard]] constexpr bool empty() const
{
gsl_AssertDebug(unicode().empty() == ascii().empty());
MP_UNITS_ASSERT_DEBUG(unicode().empty() == ascii().empty());
return unicode().empty();
}
@@ -60,7 +60,7 @@ namespace mp_units {
* @tparam CoU coherent unit for a quantity in this system
*/
template<QuantitySpec auto Q, Unit auto CoU>
requires(!AssociatedUnit<std::remove_const_t<decltype(CoU)>>) || (CoU == one)
requires(!AssociatedUnit<decltype(CoU)>) || (CoU == one)
struct system_reference {
static constexpr auto quantity_spec = Q;
static constexpr auto coherent_unit = CoU;
@@ -68,9 +68,9 @@ struct system_reference {
template<Unit U>
requires(convertible(coherent_unit, U{}))
#if MP_UNITS_COMP_MSVC
[[nodiscard]] constexpr decltype(reference<std::remove_const_t<decltype(quantity_spec)>, U>{}) operator[](U) const
[[nodiscard]] constexpr decltype(reference<MP_UNITS_REMOVE_CONST(decltype(Q)), U>{}) operator[](U) const
#else
[[nodiscard]] constexpr reference<std::remove_const_t<decltype(quantity_spec)>, U> operator[](U) const
[[nodiscard]] constexpr reference<MP_UNITS_REMOVE_CONST(decltype(Q)), U> operator[](U) const
#endif
{
return {};
+26 -18
View File
@@ -28,6 +28,7 @@
#include <mp-units/bits/module_macros.h>
#include <mp-units/bits/ratio.h>
#include <mp-units/bits/text_tools.h>
#include <mp-units/compat_macros.h>
#include <mp-units/ext/algorithm.h>
#include <mp-units/ext/fixed_string.h>
#include <mp-units/ext/type_name.h>
@@ -40,12 +41,13 @@
#include <mp-units/framework/unit_concepts.h>
#ifndef MP_UNITS_IN_MODULE_INTERFACE
#include <gsl/gsl-lite.hpp>
#include <array>
#include <cstdint>
#include <iterator>
#include <string>
#include <string_view>
#if MP_UNITS_HOSTED
#include <string>
#endif
#endif
namespace mp_units {
@@ -173,13 +175,13 @@ struct named_unit<Symbol> {
*/
template<symbol_text Symbol, Unit auto U>
requires(!Symbol.empty())
struct named_unit<Symbol, U> : std::remove_const_t<decltype(U)> {
struct named_unit<Symbol, U> : decltype(U) {
static constexpr auto symbol = Symbol; ///< Unique unit identifier
};
template<symbol_text Symbol, Unit auto U, PointOrigin auto PO>
requires(!Symbol.empty())
struct named_unit<Symbol, U, PO> : std::remove_const_t<decltype(U)> {
struct named_unit<Symbol, U, PO> : decltype(U) {
static constexpr auto symbol = Symbol; ///< Unique unit identifier
static constexpr auto point_origin = PO;
};
@@ -195,14 +197,14 @@ struct named_unit<Symbol, U, PO> : std::remove_const_t<decltype(U)> {
*/
template<symbol_text Symbol, AssociatedUnit auto U, detail::QuantityKindSpec auto QS>
requires(!Symbol.empty()) && (QS.dimension == detail::get_associated_quantity(U).dimension)
struct named_unit<Symbol, U, QS> : std::remove_const_t<decltype(U)> {
struct named_unit<Symbol, U, QS> : decltype(U) {
static constexpr auto symbol = Symbol; ///< Unique unit identifier
static constexpr auto quantity_spec = QS;
};
template<symbol_text Symbol, AssociatedUnit auto U, detail::QuantityKindSpec auto QS, PointOrigin auto PO>
requires(!Symbol.empty()) && (QS.dimension == detail::get_associated_quantity(U).dimension)
struct named_unit<Symbol, U, QS, PO> : std::remove_const_t<decltype(U)> {
struct named_unit<Symbol, U, QS, PO> : decltype(U) {
static constexpr auto symbol = Symbol; ///< Unique unit identifier
static constexpr auto quantity_spec = QS;
static constexpr auto point_origin = PO;
@@ -232,7 +234,7 @@ struct named_unit<Symbol, U, QS, PO> : std::remove_const_t<decltype(U)> {
*/
MP_UNITS_EXPORT template<symbol_text Symbol, Magnitude auto M, PrefixableUnit auto U>
requires(!Symbol.empty())
struct prefixed_unit : std::remove_const_t<decltype(M * U)> {
struct prefixed_unit : decltype(M * U) {
static constexpr auto symbol = Symbol + U.symbol;
};
@@ -390,7 +392,7 @@ template<typename T, typename F, int Num, int... Den>
return canonical_unit{pow<Num, Den...>(base.mag) * num.mag / den.mag, num.reference_unit / den.reference_unit};
} else {
return canonical_unit{pow<Num, Den...>(base.mag),
derived_unit<power<std::remove_const_t<decltype(base.reference_unit)>, Num, Den...>>{}};
derived_unit<power<decltype(base.reference_unit), Num, Den...>>{}};
}
}
@@ -430,9 +432,9 @@ MP_UNITS_EXPORT_BEGIN
* Multiplication by `1` returns the same unit, otherwise `scaled_unit` is being returned.
*/
template<Magnitude M, Unit U>
[[nodiscard]] MP_UNITS_CONSTEVAL Unit auto operator*(M, const U u)
[[nodiscard]] MP_UNITS_CONSTEVAL Unit auto operator*(M, U u)
{
if constexpr (std::is_same_v<M, std::remove_cvref_t<decltype(mp_units::mag<1>)>>)
if constexpr (std::is_same_v<M, std::remove_const_t<decltype(mp_units::mag<1>)>>)
return u;
else
return scaled_unit<M{}, U>{};
@@ -444,7 +446,7 @@ template<Magnitude M, Unit U>
* Returns the result of multiplication with an inverse unit.
*/
template<Magnitude M, Unit U>
[[nodiscard]] MP_UNITS_CONSTEVAL Unit auto operator/(M mag, const U u)
[[nodiscard]] MP_UNITS_CONSTEVAL Unit auto operator/(M mag, U u)
{
return mag * inverse(u);
}
@@ -571,7 +573,7 @@ template<std::intmax_t Num, std::intmax_t Den = 1, Unit U>
else if constexpr (detail::ratio{Num, Den} == 1)
return u;
else if constexpr (detail::is_specialization_of_scaled_unit<U>)
return scaled_unit<pow<Num, Den>(U::mag), std::remove_const_t<decltype(pow<Num, Den>(U::reference_unit))>>{};
return scaled_unit<pow<Num, Den>(U::mag), decltype(pow<Num, Den>(U::reference_unit))>{};
else if constexpr (detail::is_specialization_of_derived_unit<U>)
return detail::expr_pow<Num, Den, derived_unit, struct one, detail::type_list_of_unit_less>(u);
else if constexpr (Den == 1)
@@ -657,7 +659,7 @@ template<Unit U1, Unit U2>
return u1;
else {
constexpr auto cm = detail::common_magnitude(canonical_lhs.mag, canonical_rhs.mag);
return scaled_unit<cm, std::remove_const_t<decltype(canonical_lhs.reference_unit)>>{};
return scaled_unit<cm, decltype(canonical_lhs.reference_unit)>{};
}
}
}
@@ -718,8 +720,8 @@ constexpr Out print_separator(Out out, const unit_symbol_formatting& fmt)
{
if (fmt.separator == unit_symbol_separator::half_high_dot) {
if (fmt.encoding != text_encoding::unicode)
throw std::invalid_argument(
"'unit_symbol_separator::half_high_dot' can be only used with 'text_encoding::unicode'");
MP_UNITS_THROW(
std::invalid_argument("'unit_symbol_separator::half_high_dot' can be only used with 'text_encoding::unicode'"));
const std::string_view dot = "⋅";
out = detail::copy(dot.begin(), dot.end(), out);
} else {
@@ -808,7 +810,8 @@ template<typename CharT, std::output_iterator<CharT> Out, typename... Expr>
constexpr Out unit_symbol_impl(Out out, const derived_unit<Expr...>&, const unit_symbol_formatting& fmt,
bool negative_power)
{
gsl_Expects(negative_power == false);
(void)negative_power;
MP_UNITS_EXPECTS(negative_power == false);
return unit_symbol_impl<CharT>(out, typename derived_unit<Expr...>::_num_{}, typename derived_unit<Expr...>::_den_{},
fmt);
}
@@ -843,9 +846,15 @@ MP_UNITS_EXPORT template<unit_symbol_formatting fmt = unit_symbol_formatting{},
#endif
{
auto get_size = []() consteval {
#if MP_UNITS_HOSTED
std::basic_string<CharT> buffer;
unit_symbol_to<CharT>(std::back_inserter(buffer), U{}, fmt);
return buffer.size();
#else
std::array<CharT, 128> buffer; // TODO unsafe
auto end = unit_symbol_to<CharT>(buffer.begin(), U{}, fmt);
return end - buffer.begin();
#endif
};
#if MP_UNITS_API_STRING_VIEW_RET // Permitting static constexpr variables in constexpr functions
@@ -854,8 +863,7 @@ MP_UNITS_EXPORT template<unit_symbol_formatting fmt = unit_symbol_formatting{},
return std::string_view(buffer.data(), size);
#else
constexpr std::size_t size = get_size();
constexpr auto buffer = detail::get_symbol_buffer<CharT, size, fmt>(U{});
return basic_fixed_string<CharT, size>(buffer.begin(), buffer.end());
return basic_fixed_string(std::from_range, detail::get_symbol_buffer<CharT, size, fmt>(U{}));
#endif
}
@@ -190,7 +190,7 @@ concept AssociatedUnit = Unit<U> && detail::has_associated_quantity(U{});
*/
MP_UNITS_EXPORT template<typename U, auto QS>
concept UnitOf =
AssociatedUnit<U> && QuantitySpec<std::remove_const_t<decltype(QS)>> &&
AssociatedUnit<U> && QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS))> &&
implicitly_convertible(get_quantity_spec(U{}), QS) &&
// the below is to make `dimensionless[radian]` invalid
(get_kind(QS) == get_kind(get_quantity_spec(U{})) || !detail::NestedQuantityKindSpecOf<get_quantity_spec(U{}), QS>);
@@ -209,7 +209,7 @@ namespace detail {
*/
MP_UNITS_EXPORT template<typename U, auto U2, auto QS>
concept UnitCompatibleWith =
Unit<U> && Unit<std::remove_const_t<decltype(U2)>> && QuantitySpec<std::remove_const_t<decltype(QS)>> &&
Unit<U> && Unit<MP_UNITS_REMOVE_CONST(decltype(U2))> && QuantitySpec<MP_UNITS_REMOVE_CONST(decltype(QS))> &&
(!AssociatedUnit<U> || UnitOf<U, QS>)&&detail::have_same_canonical_reference_unit(U{}, U2);
+25
View File
@@ -22,6 +22,8 @@
#pragma once
#include <mp-units/bits/requires_hosted.h>
//
#include <mp-units/bits/module_macros.h>
#include <mp-units/framework/customization_points.h>
#include <mp-units/framework/quantity.h>
@@ -237,6 +239,29 @@ template<auto R, auto S, auto T, typename Rep1, typename Rep2, typename Rep3>
common_reference(R * S, T)};
}
/**
* @brief Computes the fma of 2 quantities and a quantity point
*
* @param a: Multiplicand
* @param x: Multiplicand
* @param b: Addend
* @return QuantityPoint: The nearest floating point representable to ax+b
*/
template<auto R, auto S, auto T, auto Origin, typename Rep1, typename Rep2, typename Rep3>
requires requires { common_quantity_spec(get_quantity_spec(R) * get_quantity_spec(S), get_quantity_spec(T)); } &&
(get_unit(R) * get_unit(S) == get_unit(T)) && requires(Rep1 v1, Rep2 v2, Rep3 v3) {
requires requires { fma(v1, v2, v3); } || requires { std::fma(v1, v2, v3); };
}
[[nodiscard]] constexpr QuantityPointOf<
common_quantity_spec(get_quantity_spec(R) * get_quantity_spec(S),
get_quantity_spec(T))> auto fma(const quantity<R, Rep1>& a, const quantity<S, Rep2>& x,
const quantity_point<T, Origin, Rep3>& b) noexcept
{
using std::fma;
return Origin + quantity{fma(a.numerical_value_ref_in(a.unit), x.numerical_value_ref_in(x.unit),
b.quantity_ref_from(b.point_origin).numerical_value_ref_in(b.unit)),
common_reference(R * S, T)};
}
/**
* @brief Computes the floating-point remainder of the division operation x / y.
+2
View File
@@ -23,6 +23,8 @@
#pragma once
#include <mp-units/bits/requires_hosted.h>
//
#include <mp-units/bits/module_macros.h>
#include <mp-units/framework/quantity.h>
#include <mp-units/framework/unit.h>
+4 -1
View File
@@ -8,8 +8,11 @@ export module mp_units.core;
#include <mp-units/compat_macros.h>
#include <mp-units/concepts.h>
#include <mp-units/format.h>
#include <mp-units/framework.h>
#if MP_UNITS_HOSTED
#include <mp-units/format.h>
#include <mp-units/math.h>
#include <mp-units/ostream.h>
#include <mp-units/random.h>
#endif
+6 -2
View File
@@ -22,10 +22,14 @@
include(CMakeFindDependencyMacro)
if(NOT MP_UNITS_API_STD_FORMAT)
if(NOT MP_UNITS_API_FREESTANDING AND NOT MP_UNITS_API_STD_FORMAT)
find_dependency(fmt)
endif()
find_dependency(gsl-lite)
if(MP_UNITS_API_CONTRACTS STREQUAL "GSL-LITE")
find_dependency(gsl-lite)
elseif(MP_UNITS_API_CONTRACTS STREQUAL "MS-GSL")
find_dependency(Microsoft.GSL)
endif()
include("${CMAKE_CURRENT_LIST_DIR}/mp-unitsTargets.cmake")
+15 -4
View File
@@ -25,8 +25,7 @@ cmake_minimum_required(VERSION 3.23)
add_mp_units_module(
systems mp-units-systems
DEPENDENCIES mp-units::core
HEADERS include/mp-units/systems/angular/math.h
include/mp-units/systems/angular/units.h
HEADERS include/mp-units/systems/angular/units.h
include/mp-units/systems/iec80000/binary_prefixes.h
include/mp-units/systems/iec80000/quantities.h
include/mp-units/systems/iec80000/unit_symbols.h
@@ -39,9 +38,7 @@ add_mp_units_module(
include/mp-units/systems/isq/si_quantities.h
include/mp-units/systems/isq/space_and_time.h
include/mp-units/systems/isq/thermodynamics.h
include/mp-units/systems/si/chrono.h
include/mp-units/systems/si/constants.h
include/mp-units/systems/si/math.h
include/mp-units/systems/si/prefixes.h
include/mp-units/systems/si/unit_symbols.h
include/mp-units/systems/si/units.h
@@ -60,3 +57,17 @@ add_mp_units_module(
include/mp-units/systems/usc.h
MODULE_INTERFACE_UNIT mp-units-systems.cpp
)
if(NOT ${projectPrefix}API_FREESTANDING)
target_sources(
mp-units-systems
PUBLIC FILE_SET
HEADERS
BASE_DIRS
${CMAKE_CURRENT_SOURCE_DIR}/include
FILES
include/mp-units/systems/angular/math.h
include/mp-units/systems/si/math.h
include/mp-units/systems/si/chrono.h
)
endif()
@@ -23,7 +23,9 @@
#pragma once
// IWYU pragma: begin_exports
#if MP_UNITS_HOSTED
#include <mp-units/systems/angular/math.h>
#endif
#include <mp-units/systems/angular/units.h>
#ifndef MP_UNITS_IN_MODULE_INTERFACE
@@ -22,6 +22,8 @@
#pragma once
#include <mp-units/bits/requires_hosted.h>
//
#include <mp-units/bits/module_macros.h>
#include <mp-units/systems/angular/units.h>
@@ -42,14 +42,14 @@ template<PrefixableUnit U> struct yobi_ : prefixed_unit<"Yi", mag_power<2, 80>,
MP_UNITS_EXPORT_BEGIN
template<PrefixableUnit auto U> inline constexpr kibi_<std::remove_const_t<decltype(U)>> kibi;
template<PrefixableUnit auto U> inline constexpr mebi_<std::remove_const_t<decltype(U)>> mebi;
template<PrefixableUnit auto U> inline constexpr gibi_<std::remove_const_t<decltype(U)>> gibi;
template<PrefixableUnit auto U> inline constexpr tebi_<std::remove_const_t<decltype(U)>> tebi;
template<PrefixableUnit auto U> inline constexpr pebi_<std::remove_const_t<decltype(U)>> pebi;
template<PrefixableUnit auto U> inline constexpr exbi_<std::remove_const_t<decltype(U)>> exbi;
template<PrefixableUnit auto U> inline constexpr zebi_<std::remove_const_t<decltype(U)>> zebi;
template<PrefixableUnit auto U> inline constexpr yobi_<std::remove_const_t<decltype(U)>> yobi;
template<PrefixableUnit auto U> inline constexpr kibi_<MP_UNITS_REMOVE_CONST(decltype(U))> kibi;
template<PrefixableUnit auto U> inline constexpr mebi_<MP_UNITS_REMOVE_CONST(decltype(U))> mebi;
template<PrefixableUnit auto U> inline constexpr gibi_<MP_UNITS_REMOVE_CONST(decltype(U))> gibi;
template<PrefixableUnit auto U> inline constexpr tebi_<MP_UNITS_REMOVE_CONST(decltype(U))> tebi;
template<PrefixableUnit auto U> inline constexpr pebi_<MP_UNITS_REMOVE_CONST(decltype(U))> pebi;
template<PrefixableUnit auto U> inline constexpr exbi_<MP_UNITS_REMOVE_CONST(decltype(U))> exbi;
template<PrefixableUnit auto U> inline constexpr zebi_<MP_UNITS_REMOVE_CONST(decltype(U))> zebi;
template<PrefixableUnit auto U> inline constexpr yobi_<MP_UNITS_REMOVE_CONST(decltype(U))> yobi;
// clang-format on
MP_UNITS_EXPORT_END
+3 -1
View File
@@ -23,9 +23,11 @@
#pragma once
// IWYU pragma: begin_exports
#if MP_UNITS_HOSTED
#include <mp-units/systems/si/chrono.h>
#include <mp-units/systems/si/constants.h>
#include <mp-units/systems/si/math.h>
#endif
#include <mp-units/systems/si/constants.h>
#include <mp-units/systems/si/prefixes.h>
#include <mp-units/systems/si/unit_symbols.h>
#include <mp-units/systems/si/units.h>
@@ -22,6 +22,8 @@
#pragma once
#include <mp-units/bits/requires_hosted.h>
//
#include <mp-units/bits/module_macros.h>
#include <mp-units/systems/isq/si_quantities.h>
#include <mp-units/systems/si/prefixes.h>
@@ -22,6 +22,8 @@
#pragma once
#include <mp-units/bits/requires_hosted.h>
//
#include <mp-units/bits/module_macros.h>
#include <mp-units/systems/isq/space_and_time.h>
#include <mp-units/systems/si/units.h>
@@ -58,30 +58,30 @@ template<PrefixableUnit U> struct quetta_ : prefixed_unit<"Q", mag_power<10, 30>
MP_UNITS_EXPORT_BEGIN
template<PrefixableUnit auto U> inline constexpr quecto_<std::remove_const_t<decltype(U)>> quecto;
template<PrefixableUnit auto U> inline constexpr ronto_<std::remove_const_t<decltype(U)>> ronto;
template<PrefixableUnit auto U> inline constexpr yocto_<std::remove_const_t<decltype(U)>> yocto;
template<PrefixableUnit auto U> inline constexpr zepto_<std::remove_const_t<decltype(U)>> zepto;
template<PrefixableUnit auto U> inline constexpr atto_<std::remove_const_t<decltype(U)>> atto;
template<PrefixableUnit auto U> inline constexpr femto_<std::remove_const_t<decltype(U)>> femto;
template<PrefixableUnit auto U> inline constexpr pico_<std::remove_const_t<decltype(U)>> pico;
template<PrefixableUnit auto U> inline constexpr nano_<std::remove_const_t<decltype(U)>> nano;
template<PrefixableUnit auto U> inline constexpr micro_<std::remove_const_t<decltype(U)>> micro;
template<PrefixableUnit auto U> inline constexpr milli_<std::remove_const_t<decltype(U)>> milli;
template<PrefixableUnit auto U> inline constexpr centi_<std::remove_const_t<decltype(U)>> centi;
template<PrefixableUnit auto U> inline constexpr deci_<std::remove_const_t<decltype(U)>> deci;
template<PrefixableUnit auto U> inline constexpr deca_<std::remove_const_t<decltype(U)>> deca;
template<PrefixableUnit auto U> inline constexpr hecto_<std::remove_const_t<decltype(U)>> hecto;
template<PrefixableUnit auto U> inline constexpr kilo_<std::remove_const_t<decltype(U)>> kilo;
template<PrefixableUnit auto U> inline constexpr mega_<std::remove_const_t<decltype(U)>> mega;
template<PrefixableUnit auto U> inline constexpr giga_<std::remove_const_t<decltype(U)>> giga;
template<PrefixableUnit auto U> inline constexpr tera_<std::remove_const_t<decltype(U)>> tera;
template<PrefixableUnit auto U> inline constexpr peta_<std::remove_const_t<decltype(U)>> peta;
template<PrefixableUnit auto U> inline constexpr exa_<std::remove_const_t<decltype(U)>> exa;
template<PrefixableUnit auto U> inline constexpr zetta_<std::remove_const_t<decltype(U)>> zetta;
template<PrefixableUnit auto U> inline constexpr yotta_<std::remove_const_t<decltype(U)>> yotta;
template<PrefixableUnit auto U> inline constexpr ronna_<std::remove_const_t<decltype(U)>> ronna;
template<PrefixableUnit auto U> inline constexpr quetta_<std::remove_const_t<decltype(U)>> quetta;
template<PrefixableUnit auto U> inline constexpr quecto_<MP_UNITS_REMOVE_CONST(decltype(U))> quecto;
template<PrefixableUnit auto U> inline constexpr ronto_<MP_UNITS_REMOVE_CONST(decltype(U))> ronto;
template<PrefixableUnit auto U> inline constexpr yocto_<MP_UNITS_REMOVE_CONST(decltype(U))> yocto;
template<PrefixableUnit auto U> inline constexpr zepto_<MP_UNITS_REMOVE_CONST(decltype(U))> zepto;
template<PrefixableUnit auto U> inline constexpr atto_<MP_UNITS_REMOVE_CONST(decltype(U))> atto;
template<PrefixableUnit auto U> inline constexpr femto_<MP_UNITS_REMOVE_CONST(decltype(U))> femto;
template<PrefixableUnit auto U> inline constexpr pico_<MP_UNITS_REMOVE_CONST(decltype(U))> pico;
template<PrefixableUnit auto U> inline constexpr nano_<MP_UNITS_REMOVE_CONST(decltype(U))> nano;
template<PrefixableUnit auto U> inline constexpr micro_<MP_UNITS_REMOVE_CONST(decltype(U))> micro;
template<PrefixableUnit auto U> inline constexpr milli_<MP_UNITS_REMOVE_CONST(decltype(U))> milli;
template<PrefixableUnit auto U> inline constexpr centi_<MP_UNITS_REMOVE_CONST(decltype(U))> centi;
template<PrefixableUnit auto U> inline constexpr deci_<MP_UNITS_REMOVE_CONST(decltype(U))> deci;
template<PrefixableUnit auto U> inline constexpr deca_<MP_UNITS_REMOVE_CONST(decltype(U))> deca;
template<PrefixableUnit auto U> inline constexpr hecto_<MP_UNITS_REMOVE_CONST(decltype(U))> hecto;
template<PrefixableUnit auto U> inline constexpr kilo_<MP_UNITS_REMOVE_CONST(decltype(U))> kilo;
template<PrefixableUnit auto U> inline constexpr mega_<MP_UNITS_REMOVE_CONST(decltype(U))> mega;
template<PrefixableUnit auto U> inline constexpr giga_<MP_UNITS_REMOVE_CONST(decltype(U))> giga;
template<PrefixableUnit auto U> inline constexpr tera_<MP_UNITS_REMOVE_CONST(decltype(U))> tera;
template<PrefixableUnit auto U> inline constexpr peta_<MP_UNITS_REMOVE_CONST(decltype(U))> peta;
template<PrefixableUnit auto U> inline constexpr exa_<MP_UNITS_REMOVE_CONST(decltype(U))> exa;
template<PrefixableUnit auto U> inline constexpr zetta_<MP_UNITS_REMOVE_CONST(decltype(U))> zetta;
template<PrefixableUnit auto U> inline constexpr yotta_<MP_UNITS_REMOVE_CONST(decltype(U))> yotta;
template<PrefixableUnit auto U> inline constexpr ronna_<MP_UNITS_REMOVE_CONST(decltype(U))> ronna;
template<PrefixableUnit auto U> inline constexpr quetta_<MP_UNITS_REMOVE_CONST(decltype(U))> quetta;
// clang-format on
MP_UNITS_EXPORT_END
@@ -474,6 +474,32 @@ inline constexpr auto YF = yotta<farad>;
inline constexpr auto RF = ronna<farad>;
inline constexpr auto QF = quetta<farad>;
inline constexpr auto qohm = quecto<si::ohm>;
inline constexpr auto rohm = ronto<si::ohm>;
inline constexpr auto yohm = yocto<si::ohm>;
inline constexpr auto zohm = zepto<si::ohm>;
inline constexpr auto aohm = atto<si::ohm>;
inline constexpr auto fohm = femto<si::ohm>;
inline constexpr auto pohm = pico<si::ohm>;
inline constexpr auto nohm = nano<si::ohm>;
inline constexpr auto uohm = micro<si::ohm>;
inline constexpr auto mohm = milli<si::ohm>;
inline constexpr auto cohm = centi<si::ohm>;
inline constexpr auto dohm = deci<si::ohm>;
using si::ohm;
inline constexpr auto daohm = deca<si::ohm>;
inline constexpr auto hohm = hecto<si::ohm>;
inline constexpr auto kohm = kilo<si::ohm>;
inline constexpr auto Mohm = mega<si::ohm>;
inline constexpr auto Gohm = giga<si::ohm>;
inline constexpr auto Tohm = tera<si::ohm>;
inline constexpr auto Pohm = peta<si::ohm>;
inline constexpr auto Eohm = exa<si::ohm>;
inline constexpr auto Zohm = zetta<si::ohm>;
inline constexpr auto Yohm = yotta<si::ohm>;
inline constexpr auto Rohm = ronna<si::ohm>;
inline constexpr auto Qohm = quetta<si::ohm>;
inline constexpr auto qS = quecto<siemens>;
inline constexpr auto rS = ronto<siemens>;
inline constexpr auto yS = yocto<siemens>;
+1 -1
View File
@@ -118,7 +118,7 @@ inline constexpr struct troy_pound : named_unit<"lb t", mag<12> * troy_once> {}
inline constexpr struct inch_of_mercury : named_unit<"inHg", mag_ratio<3'386'389, 1'000> * si::pascal> {} inch_of_mercury;
// https://en.wikipedia.org/wiki/United_States_customary_units#Temperature
inline constexpr struct zeroth_degree_Fahrenheit : relative_point_origin<si::zeroth_degree_Celsius - 32 * (mag_ratio<5, 9> * si::degree_Celsius)> {} zeroth_degree_Fahrenheit;
inline constexpr struct zeroth_degree_Fahrenheit : relative_point_origin<quantity_point{-32 * (mag_ratio<5, 9> * si::degree_Celsius)}> {} zeroth_degree_Fahrenheit;
inline constexpr struct degree_Fahrenheit : named_unit<symbol_text{u8"°F", "`F"}, mag_ratio<5, 9> * si::degree_Celsius, zeroth_degree_Fahrenheit> {} degree_Fahrenheit;
// clang-format on