diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 6a317600e..2e5a8926e 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -33,6 +33,7 @@ add_mp_units_module( include/mp-units/bits/core_gmf.h include/mp-units/bits/double_width_int.h include/mp-units/bits/fixed_point.h + include/mp-units/bits/int_power.h include/mp-units/bits/get_associated_quantity.h include/mp-units/bits/hacks.h include/mp-units/bits/module_macros.h diff --git a/src/core/include/mp-units/bits/double_width_int.h b/src/core/include/mp-units/bits/double_width_int.h index 1b822441c..fd4fd93fb 100644 --- a/src/core/include/mp-units/bits/double_width_int.h +++ b/src/core/include/mp-units/bits/double_width_int.h @@ -22,57 +22,24 @@ #pragma once -#include // IWYU pragma: keep +#include // IWYU pragma: keep +#include #include // IWYU pragma: keep #ifndef MP_UNITS_IN_MODULE_INTERFACE #ifdef MP_UNITS_IMPORT_STD import std; #else -#include -#include #include +#include #include -#include #include -#include #include -#include -// becomes partially freestanding in C++26 -// before that, there is no guarantee about this header even existing -// (GCC 14 has it, but actively #error's out) -#if __STDC_HOSTED__ -#include -#endif #endif #endif namespace mp_units::detail { -template -constexpr std::size_t integer_rep_width_v = std::numeric_limits>::digits; - -template -[[nodiscard]] consteval T int_power(T base, int exponent) -{ -#if __STDC_HOSTED__ && defined(__cpp_lib_constexpr_cmath) && __cpp_lib_constexpr_cmath >= 202202L - return std::ldexp(base, exponent); -#else - if (exponent < 0) { - base = T{1} / base; - exponent = -exponent; - } - T ret = 1; - while (exponent) { - if (exponent & 1) ret *= base; - exponent >>= 1; - base *= base; - } - return ret; - -#endif -} - // A double-width integer synthesized from two base-width integers. On platforms without a // native `__int128` (notably MSVC), `int128_t` / `uint128_t` are aliases for this template // instantiated on (u)int64_t; the operator set is therefore comprehensive enough for it to diff --git a/src/core/include/mp-units/bits/fixed_point.h b/src/core/include/mp-units/bits/fixed_point.h index 4376797ee..1b0383641 100644 --- a/src/core/include/mp-units/bits/fixed_point.h +++ b/src/core/include/mp-units/bits/fixed_point.h @@ -22,10 +22,16 @@ #pragma once -#include -#include // IWYU pragma: keep +#include // IWYU pragma: keep +#include #include // IWYU pragma: keep +// `double_width_int` only emulates `int128_t` on platforms without native `__int128` (notably +// MSVC). On every other platform `int128_t` is the builtin and dwint is unused in library code +#if !defined(__SIZEOF_INT128__) +#include +#endif + #ifndef MP_UNITS_IN_MODULE_INTERFACE #ifdef MP_UNITS_IMPORT_STD import std; @@ -74,9 +80,6 @@ constexpr std::size_t max_native_width = 64; template constexpr bool is_signed_v = std::is_signed_v; -template -constexpr bool is_signed_v> = double_width_int::is_signed; - #if defined(__SIZEOF_INT128__) MP_UNITS_DIAGNOSTIC_PUSH @@ -95,6 +98,13 @@ inline constexpr bool is_signed_v = false; MP_UNITS_DIAGNOSTIC_POP +#else + +// Only needed when `double_width_int` doubles as `int128_t`; the dwint header was included +// for that purpose above. +template +constexpr bool is_signed_v> = double_width_int::is_signed; + #endif template diff --git a/src/core/include/mp-units/bits/int_power.h b/src/core/include/mp-units/bits/int_power.h new file mode 100644 index 000000000..c245b3030 --- /dev/null +++ b/src/core/include/mp-units/bits/int_power.h @@ -0,0 +1,76 @@ +// 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 // IWYU pragma: keep + +#ifndef MP_UNITS_IN_MODULE_INTERFACE +#ifdef MP_UNITS_IMPORT_STD +import std; +#else +#include +#include +#include +#include +#include +// becomes partially freestanding in C++26 +// before that, there is no guarantee about this header even existing +// (GCC 14 has it, but actively #error's out) +#if __STDC_HOSTED__ +#include +#endif +#endif +#endif + +namespace mp_units::detail { + +// Representation width (in bits) of an integral type, as the digit count of its unsigned +// counterpart. Lives in its own header so that both `double_width_int.h` and +// `fixed_point.h` can use it without one having to include the other. +template +constexpr std::size_t integer_rep_width_v = std::numeric_limits>::digits; + +// `2^exponent` (or more precisely `base * 2^exponent`) as a compile-time floating-point +// constant. Used by `double_width_int`'s long-double conversions and by `fixed_point`'s +// long-double constructor. +template +[[nodiscard]] consteval T int_power(T base, int exponent) +{ +#if __STDC_HOSTED__ && defined(__cpp_lib_constexpr_cmath) && __cpp_lib_constexpr_cmath >= 202202L + return std::ldexp(base, exponent); +#else + if (exponent < 0) { + base = T{1} / base; + exponent = -exponent; + } + T ret = 1; + while (exponent) { + if (exponent & 1) ret *= base; + exponent >>= 1; + base *= base; + } + return ret; +#endif +} + +} // namespace mp_units::detail