mirror of
https://github.com/mpusz/mp-units.git
synced 2026-07-07 17:10:53 +02:00
refactor: extract int_power / integer_rep_width_v to dedicated header; include double_width_int only when emulation is needed
Splits the two tiny utilities that both `double_width_int` and `fixed_point` depend on into `bits/int_power.h`, so neither has to include the other for them. With that dependency cut, `fixed_point.h` now includes `double_width_int.h` only when `__SIZEOF_INT128__` is not defined — i.e. exactly on the platforms where `int128_t` / `uint128_t` are dwint aliases. On compilers with native `__int128` the dwint definition is no longer parsed by every translation unit that pulls in `fixed_point.h`. The `is_signed_v<double_width_int<T>>` specialization moves inside the same conditional so it is only declared when dwint is actually visible.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -22,57 +22,24 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mp-units/bits/hacks.h> // IWYU pragma: keep
|
||||
#include <mp-units/bits/hacks.h> // IWYU pragma: keep
|
||||
#include <mp-units/bits/int_power.h>
|
||||
#include <mp-units/ext/type_traits.h> // IWYU pragma: keep
|
||||
|
||||
#ifndef MP_UNITS_IN_MODULE_INTERFACE
|
||||
#ifdef MP_UNITS_IMPORT_STD
|
||||
import std;
|
||||
#else
|
||||
#include <algorithm>
|
||||
#include <bit>
|
||||
#include <concepts>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <limits>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <version>
|
||||
// <cmath> 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 <cmath>
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace mp_units::detail {
|
||||
|
||||
template<typename T>
|
||||
constexpr std::size_t integer_rep_width_v = std::numeric_limits<std::make_unsigned_t<T>>::digits;
|
||||
|
||||
template<std::floating_point T>
|
||||
[[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
|
||||
|
||||
@@ -22,10 +22,16 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mp-units/bits/double_width_int.h>
|
||||
#include <mp-units/bits/hacks.h> // IWYU pragma: keep
|
||||
#include <mp-units/bits/hacks.h> // IWYU pragma: keep
|
||||
#include <mp-units/bits/int_power.h>
|
||||
#include <mp-units/ext/type_traits.h> // 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 <mp-units/bits/double_width_int.h>
|
||||
#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<typename T>
|
||||
constexpr bool is_signed_v = std::is_signed_v<T>;
|
||||
|
||||
template<typename T>
|
||||
constexpr bool is_signed_v<double_width_int<T>> = double_width_int<T>::is_signed;
|
||||
|
||||
#if defined(__SIZEOF_INT128__)
|
||||
|
||||
MP_UNITS_DIAGNOSTIC_PUSH
|
||||
@@ -95,6 +98,13 @@ inline constexpr bool is_signed_v<unsigned __int128> = 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<typename T>
|
||||
constexpr bool is_signed_v<double_width_int<T>> = double_width_int<T>::is_signed;
|
||||
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
|
||||
@@ -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 <mp-units/bits/hacks.h> // IWYU pragma: keep
|
||||
|
||||
#ifndef MP_UNITS_IN_MODULE_INTERFACE
|
||||
#ifdef MP_UNITS_IMPORT_STD
|
||||
import std;
|
||||
#else
|
||||
#include <concepts>
|
||||
#include <cstddef>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
#include <version>
|
||||
// <cmath> 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 <cmath>
|
||||
#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<typename T>
|
||||
constexpr std::size_t integer_rep_width_v = std::numeric_limits<std::make_unsigned_t<T>>::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<std::floating_point T>
|
||||
[[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
|
||||
Reference in New Issue
Block a user