maths: convert to concepts
This commit is contained in:
parent
c5174c2817
commit
6a15651694
297
maths.hpp
297
maths.hpp
@ -6,13 +6,13 @@
|
||||
* Copyright 2010-2018 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
#ifndef __MATHS_HPP
|
||||
#define __MATHS_HPP
|
||||
#pragma once
|
||||
|
||||
// DO NOT INCLUDE debug.hpp
|
||||
// it triggers a circular dependency; debug -> format -> maths -> debug
|
||||
// instead, just use cassert
|
||||
|
||||
#include "concepts.hpp"
|
||||
#include "types/traits.hpp"
|
||||
#include "coord/traits.hpp"
|
||||
#include "float.hpp"
|
||||
@ -37,9 +37,8 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
namespace cruft {
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
template <typename T>
|
||||
constexpr
|
||||
std::enable_if_t<std::is_arithmetic_v<T>, T>
|
||||
template <concepts::arithmetic T>
|
||||
constexpr T
|
||||
abs [[gnu::const]] (T t)
|
||||
{
|
||||
return t > 0 ? t : -t;
|
||||
@ -116,47 +115,27 @@ namespace cruft {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
constexpr
|
||||
std::enable_if_t<
|
||||
std::is_integral<T>::value, bool
|
||||
>
|
||||
constexpr bool
|
||||
almost_zero (T t)
|
||||
{
|
||||
if constexpr (std::is_integral_v<T>) {
|
||||
return t == 0;
|
||||
} else {
|
||||
return almost_equal (t, T{0});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
std::enable_if_t<
|
||||
!std::is_integral<T>::value, bool
|
||||
>
|
||||
almost_zero (T a)
|
||||
{
|
||||
return almost_equal (a, T{0});
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
constexpr
|
||||
typename std::enable_if_t<
|
||||
std::is_integral<T>::value, bool
|
||||
>
|
||||
constexpr bool
|
||||
exactly_zero (T t)
|
||||
{
|
||||
if constexpr (std::is_integral_v<T>) {
|
||||
return equal (t, T{0});
|
||||
} else {
|
||||
return equal (t, T{0});
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
constexpr
|
||||
typename std::enable_if_t<
|
||||
!std::is_integral<T>::value, bool
|
||||
>
|
||||
exactly_zero (T t)
|
||||
{
|
||||
return equal (t, T{0});
|
||||
}
|
||||
|
||||
|
||||
@ -173,11 +152,7 @@ namespace cruft {
|
||||
|
||||
template <
|
||||
typename BaseT,
|
||||
typename ExponentT,
|
||||
typename = std::enable_if_t<
|
||||
std::is_integral_v<ExponentT>,
|
||||
void
|
||||
>
|
||||
concepts::integral ExponentT
|
||||
>
|
||||
constexpr BaseT
|
||||
pow [[gnu::const]] (BaseT base, ExponentT exponent)
|
||||
@ -200,9 +175,8 @@ namespace cruft {
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
template <typename T>
|
||||
constexpr
|
||||
std::enable_if_t<std::is_integral<T>::value, bool>
|
||||
template <concepts::integral T>
|
||||
constexpr bool
|
||||
is_pow2 [[gnu::const]] (T value)
|
||||
{
|
||||
return value && !(value & (value - 1));
|
||||
@ -211,9 +185,8 @@ namespace cruft {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Logarithms
|
||||
template <typename T>
|
||||
constexpr
|
||||
std::enable_if_t<std::is_integral_v<T>, T>
|
||||
template <concepts::integral T>
|
||||
constexpr T
|
||||
log2 (T val)
|
||||
{
|
||||
T tally = 0;
|
||||
@ -231,12 +204,9 @@ namespace cruft {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// round T up to the nearest multiple of U
|
||||
template <typename T, typename U>
|
||||
template <concepts::integral T, concepts::integral U>
|
||||
inline
|
||||
typename std::common_type<
|
||||
std::enable_if_t<std::is_integral<T>::value,T>,
|
||||
std::enable_if_t<std::is_integral<U>::value,U>
|
||||
>::type
|
||||
std::common_type_t<T, U>
|
||||
round_up (T value, U size)
|
||||
{
|
||||
// we perform this as two steps to avoid unnecessarily incrementing when
|
||||
@ -249,12 +219,8 @@ namespace cruft {
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// round T up to the nearest power-of-2
|
||||
template <
|
||||
typename T,
|
||||
typename = std::enable_if_t<std::is_integral_v<T>>
|
||||
>
|
||||
constexpr
|
||||
auto
|
||||
template <concepts::integral T>
|
||||
constexpr auto
|
||||
round_pow2 (T value)
|
||||
{
|
||||
--value;
|
||||
@ -270,13 +236,12 @@ namespace cruft {
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// round T up to the nearest multiple of U and return the quotient.
|
||||
template <typename T, typename U>
|
||||
constexpr std::enable_if_t<
|
||||
std::is_integral<T>::value &&
|
||||
std::is_integral<U>::value,
|
||||
T
|
||||
template <
|
||||
concepts::integral T,
|
||||
concepts::integral U
|
||||
>
|
||||
divup (const T a, const U b)
|
||||
constexpr auto
|
||||
divup (T const a, U const b)
|
||||
{
|
||||
return (a + b - 1) / b;
|
||||
}
|
||||
@ -284,17 +249,16 @@ namespace cruft {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Properties
|
||||
template <typename T>
|
||||
constexpr
|
||||
std::enable_if_t<std::is_integral<T>::value, bool>
|
||||
template <concepts::integral T>
|
||||
constexpr bool
|
||||
is_integer (T)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr
|
||||
std::enable_if_t<std::is_floating_point<T>::value, bool>
|
||||
|
||||
template <concepts::floating_point T>
|
||||
constexpr bool
|
||||
is_integer (T t)
|
||||
{
|
||||
T i = 0;
|
||||
@ -303,13 +267,7 @@ namespace cruft {
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
template <
|
||||
typename NumericT,
|
||||
typename = std::enable_if_t<
|
||||
std::is_integral_v<NumericT>,
|
||||
void
|
||||
>
|
||||
>
|
||||
template <concepts::integral NumericT>
|
||||
constexpr auto
|
||||
digits10 (NumericT v) noexcept
|
||||
{
|
||||
@ -339,12 +297,8 @@ namespace cruft {
|
||||
}
|
||||
|
||||
|
||||
template <typename ValueT, typename BaseT>
|
||||
constexpr
|
||||
std::enable_if_t<
|
||||
std::is_integral_v<ValueT> && std::is_integral_v<BaseT>,
|
||||
int
|
||||
>
|
||||
template <concepts::integral ValueT, concepts::integral BaseT>
|
||||
constexpr int
|
||||
digits (ValueT value, BaseT base) noexcept
|
||||
{
|
||||
assert (base > 0);
|
||||
@ -362,10 +316,8 @@ namespace cruft {
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// return positive or negative unit value corresponding to the input.
|
||||
template <typename T>
|
||||
constexpr std::enable_if_t<
|
||||
std::is_signed<T>::value && std::is_integral<T>::value, T
|
||||
>
|
||||
template <concepts::signed_integral T>
|
||||
constexpr T
|
||||
sign (T t)
|
||||
{
|
||||
return t < 0 ? -1 : 1;
|
||||
@ -375,10 +327,8 @@ namespace cruft {
|
||||
/// return positive or negative unit value corresponding to the input.
|
||||
/// guaranteed to give correct results for signed zeroes, use another
|
||||
/// method if extreme speed is important.
|
||||
template <typename T>
|
||||
constexpr std::enable_if_t<
|
||||
std::is_floating_point<T>::value, T
|
||||
>
|
||||
template <concepts::floating_point T>
|
||||
constexpr T
|
||||
sign (T t)
|
||||
{
|
||||
return std::signbit (t) ? -1 : 1;
|
||||
@ -408,32 +358,23 @@ namespace cruft {
|
||||
// Modulus/etc
|
||||
|
||||
// namespaced wrapper for `man 3 fmod`
|
||||
template <typename T>
|
||||
constexpr
|
||||
std::enable_if_t<
|
||||
std::is_floating_point<T>::value, T
|
||||
>
|
||||
template <concepts::floating_point T>
|
||||
constexpr T
|
||||
mod (T x, T y)
|
||||
{
|
||||
return std::fmod (x, y);
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
constexpr
|
||||
std::enable_if_t<
|
||||
std::is_integral<T>::value, T
|
||||
>
|
||||
template <concepts::integral T>
|
||||
constexpr T
|
||||
mod (T x, T y)
|
||||
{
|
||||
return x % y;
|
||||
}
|
||||
|
||||
|
||||
template <
|
||||
typename ValueT,
|
||||
typename = std::enable_if_t<std::is_floating_point_v<ValueT>>
|
||||
>
|
||||
template <concepts::floating_point ValueT>
|
||||
ValueT
|
||||
frac (ValueT val)
|
||||
{
|
||||
@ -544,13 +485,11 @@ namespace cruft {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// kahan summation for long floating point sequences
|
||||
|
||||
template <class InputT>
|
||||
std::enable_if_t<
|
||||
std::is_floating_point<
|
||||
template <typename InputT>
|
||||
requires
|
||||
concepts::legacy_input_iterator<InputT> &&
|
||||
concepts::floating_point<typename std::iterator_traits<InputT>::value_type>
|
||||
typename std::iterator_traits<InputT>::value_type
|
||||
>::value,
|
||||
typename std::iterator_traits<InputT>::value_type
|
||||
>
|
||||
sum (InputT first, InputT last)
|
||||
{
|
||||
using T = typename std::iterator_traits<InputT>::value_type;
|
||||
@ -576,13 +515,11 @@ namespace cruft {
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
template <class InputT>
|
||||
std::enable_if_t<
|
||||
std::is_integral<
|
||||
template <typename InputT>
|
||||
requires
|
||||
concepts::legacy_input_iterator<InputT> &&
|
||||
concepts::integral<typename std::iterator_traits<InputT>::value_type>
|
||||
typename std::iterator_traits<InputT>::value_type
|
||||
>::value,
|
||||
typename std::iterator_traits<InputT>::value_type
|
||||
>
|
||||
sum (InputT first, InputT last)
|
||||
{
|
||||
using T = typename std::iterator_traits<InputT>::value_type;
|
||||
@ -625,31 +562,31 @@ namespace cruft {
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
template <typename ValueT, size_t CountV>
|
||||
const ValueT&
|
||||
max (const std::array<ValueT,CountV> &vals)
|
||||
template <concepts::container ContainerT>
|
||||
typename ContainerT::value_type const&
|
||||
max (ContainerT const &vals)
|
||||
{
|
||||
return *std::max_element (vals.begin (), vals.end ());
|
||||
}
|
||||
|
||||
|
||||
template <typename ValueT, size_t CountV>
|
||||
ValueT&
|
||||
max (std::array<ValueT,CountV> &&) = delete;
|
||||
template <concepts::container ValueT>
|
||||
typename ValueT::value_type &
|
||||
max (ValueT &&) = delete;
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
template <typename ValueT, size_t CountV>
|
||||
const ValueT&
|
||||
min (const std::array<ValueT,CountV> &vals)
|
||||
template <concepts::container ContainerT>
|
||||
typename ContainerT::value_type const&
|
||||
min (ContainerT const &vals)
|
||||
{
|
||||
return *std::min_element (vals.begin (), vals.end ());
|
||||
}
|
||||
|
||||
|
||||
template <typename ValueT, size_t CountV>
|
||||
ValueT&
|
||||
min (std::array<ValueT,CountV> &&) = delete;
|
||||
template <concepts::container ContainerT>
|
||||
typename ContainerT::value_type&
|
||||
min (ContainerT &&) = delete;
|
||||
|
||||
|
||||
///------------------------------------------------------------------------
|
||||
@ -669,13 +606,13 @@ namespace cruft {
|
||||
// Limiting functions
|
||||
|
||||
// min/max clamping
|
||||
template <typename T, typename U, typename V>
|
||||
constexpr
|
||||
std::enable_if_t<
|
||||
std::is_scalar_v<T> && std::is_scalar_v<U> && std::is_scalar_v<V>,
|
||||
std::common_type_t<T,U,V>
|
||||
template <
|
||||
concepts::scalar T,
|
||||
concepts::scalar U,
|
||||
concepts::scalar V
|
||||
>
|
||||
clamp (const T val, const U lo, const V hi)
|
||||
constexpr std::common_type_t<T,U,V>
|
||||
clamp (T const val, U const lo, V const hi)
|
||||
{
|
||||
assert (lo <= hi);
|
||||
|
||||
@ -699,10 +636,12 @@ namespace cruft {
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
template <typename U, typename T>
|
||||
constexpr
|
||||
std::enable_if_t<std::is_floating_point<T>::value, U>
|
||||
mix (U a, U b, T t)
|
||||
template <
|
||||
concepts::numeric U,
|
||||
concepts::numeric T
|
||||
>
|
||||
constexpr U
|
||||
mix (U const a, U const b, T const t)
|
||||
{
|
||||
// give some tolerance for floating point rounding
|
||||
assert (t >= -0.00001f);
|
||||
@ -721,11 +660,11 @@ namespace cruft {
|
||||
/// bits have some meaning (particularly when dealing with UINTMAX)
|
||||
|
||||
// uint -> float
|
||||
template <typename T, typename U>
|
||||
constexpr
|
||||
typename std::enable_if<
|
||||
std::is_unsigned<T>::value && std::is_floating_point<U>::value, U
|
||||
>::type
|
||||
template <
|
||||
concepts::unsigned_integral T,
|
||||
concepts::floating_point U
|
||||
>
|
||||
constexpr U
|
||||
renormalise (T t)
|
||||
{
|
||||
return t / static_cast<U> (std::numeric_limits<T>::max ());
|
||||
@ -734,11 +673,11 @@ namespace cruft {
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// float -> uint
|
||||
template <typename T, typename U>
|
||||
constexpr
|
||||
typename std::enable_if<
|
||||
std::is_floating_point<T>::value && std::is_unsigned<U>::value, U
|
||||
>::type
|
||||
template <
|
||||
concepts::floating_point T,
|
||||
concepts::unsigned_integral U
|
||||
>
|
||||
constexpr U
|
||||
renormalise (T t)
|
||||
{
|
||||
// Ideally std::ldexp would be involved but it complicates handing
|
||||
@ -769,12 +708,11 @@ namespace cruft {
|
||||
// float -> float, avoids identity conversion as we don't want to create
|
||||
// ambiguous overloads
|
||||
template <typename T, typename U>
|
||||
constexpr
|
||||
typename std::enable_if<
|
||||
std::is_floating_point<T>::value &&
|
||||
std::is_floating_point<U>::value &&
|
||||
!std::is_same<T,U>::value, U
|
||||
>::type
|
||||
requires
|
||||
concepts::floating_point<T> &&
|
||||
concepts::floating_point<U> &&
|
||||
(!std::is_same_v<T, U>)
|
||||
constexpr U
|
||||
renormalise (T t)
|
||||
{
|
||||
return static_cast<U> (t);
|
||||
@ -784,12 +722,11 @@ namespace cruft {
|
||||
//-------------------------------------------------------------------------
|
||||
// hi_uint -> lo_uint
|
||||
template <typename T, typename U>
|
||||
constexpr
|
||||
typename std::enable_if<
|
||||
std::is_unsigned<T>::value &&
|
||||
std::is_unsigned<U>::value &&
|
||||
(sizeof (T) > sizeof (U)), U
|
||||
>::type
|
||||
requires
|
||||
concepts::unsigned_integral<T> &&
|
||||
concepts::unsigned_integral<U> &&
|
||||
(sizeof (T) > sizeof (U))
|
||||
constexpr U
|
||||
renormalise (T t)
|
||||
{
|
||||
static_assert (sizeof (T) > sizeof (U),
|
||||
@ -805,13 +742,12 @@ namespace cruft {
|
||||
// lo_uint -> hi_uint
|
||||
template <
|
||||
typename SrcT,
|
||||
typename DstT,
|
||||
typename = std::enable_if_t<
|
||||
std::is_unsigned<SrcT>::value &&
|
||||
std::is_unsigned<DstT>::value &&
|
||||
sizeof (SrcT) < sizeof (DstT), DstT
|
||||
>
|
||||
typename DstT
|
||||
>
|
||||
requires
|
||||
concepts::unsigned_integral<SrcT> &&
|
||||
concepts::unsigned_integral<DstT> &&
|
||||
(sizeof (SrcT) < sizeof (DstT))
|
||||
constexpr DstT
|
||||
renormalise (SrcT src)
|
||||
{
|
||||
@ -852,10 +788,8 @@ namespace cruft {
|
||||
// identity transformation. must precede the signed cases, as they may rely
|
||||
// on this as a side effect of casts.
|
||||
template <typename T, typename U>
|
||||
constexpr
|
||||
typename std::enable_if<
|
||||
std::is_same<T,U>::value, U
|
||||
>::type
|
||||
requires (std::is_same_v<T, U>)
|
||||
constexpr U
|
||||
renormalise (T t)
|
||||
{ return t; }
|
||||
|
||||
@ -863,13 +797,10 @@ namespace cruft {
|
||||
//-------------------------------------------------------------------------
|
||||
// anything-to-sint
|
||||
template <typename T, typename U>
|
||||
constexpr
|
||||
typename std::enable_if<
|
||||
std::is_signed<U>::value &&
|
||||
std::is_integral<U>::value &&
|
||||
!std::is_same<T,U>::value,
|
||||
U
|
||||
>::type
|
||||
requires
|
||||
concepts::signed_integral<U> &&
|
||||
(!std::is_same<T,U>::value)
|
||||
constexpr U
|
||||
renormalise (T t)
|
||||
{
|
||||
using uint_t = typename std::make_unsigned<U>::type;
|
||||
@ -883,13 +814,10 @@ namespace cruft {
|
||||
//-------------------------------------------------------------------------
|
||||
// sint-to-anything
|
||||
template <typename T, typename U>
|
||||
constexpr
|
||||
typename std::enable_if<
|
||||
std::is_signed<T>::value &&
|
||||
std::is_integral<T>::value &&
|
||||
!std::is_same<T,U>::value,
|
||||
U
|
||||
>::type
|
||||
requires
|
||||
concepts::signed_integral<T> &&
|
||||
(!std::is_same<T,U>::value)
|
||||
constexpr U
|
||||
renormalise (T sint)
|
||||
{
|
||||
using uint_t = typename std::make_unsigned<T>::type;
|
||||
@ -899,6 +827,3 @@ namespace cruft {
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif // __MATHS_HPP
|
||||
|
Loading…
Reference in New Issue
Block a user