diff --git a/maths.hpp b/maths.hpp index 452f35c0..824233a0 100644 --- a/maths.hpp +++ b/maths.hpp @@ -6,13 +6,13 @@ * Copyright 2010-2018 Danny Robson */ -#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 - constexpr - std::enable_if_t, T> + template + constexpr T abs [[gnu::const]] (T t) { return t > 0 ? t : -t; @@ -116,47 +115,27 @@ namespace cruft { //----------------------------------------------------------------------------- template - constexpr - std::enable_if_t< - std::is_integral::value, bool - > + constexpr bool almost_zero (T t) { - return t == 0; + if constexpr (std::is_integral_v) { + return t == 0; + } else { + return almost_equal (t, T{0}); + } } //------------------------------------------------------------------------- template - std::enable_if_t< - !std::is_integral::value, bool - > - almost_zero (T a) - { - return almost_equal (a, T{0}); - } - - - //------------------------------------------------------------------------- - template - constexpr - typename std::enable_if_t< - std::is_integral::value, bool - > + constexpr bool exactly_zero (T t) { - return equal (t, T{0}); - } - - - template - constexpr - typename std::enable_if_t< - !std::is_integral::value, bool - > - exactly_zero (T t) - { - return equal (t, T{0}); + if constexpr (std::is_integral_v) { + return equal (t, T{0}); + } else { + 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, - void - > + concepts::integral ExponentT > constexpr BaseT pow [[gnu::const]] (BaseT base, ExponentT exponent) @@ -200,10 +175,9 @@ namespace cruft { //------------------------------------------------------------------------- - template - constexpr - std::enable_if_t::value, bool> - is_pow2 [[gnu::const]] (T value) + template + constexpr bool + is_pow2 [[gnu::const]] (T value) { return value && !(value & (value - 1)); } @@ -211,9 +185,8 @@ namespace cruft { //----------------------------------------------------------------------------- // Logarithms - template - constexpr - std::enable_if_t, T> + template + constexpr T log2 (T val) { T tally = 0; @@ -231,12 +204,9 @@ namespace cruft { /////////////////////////////////////////////////////////////////////////////// /// round T up to the nearest multiple of U - template + template inline - typename std::common_type< - std::enable_if_t::value,T>, - std::enable_if_t::value,U> - >::type + std::common_type_t 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> - > - constexpr - auto + template + 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 - constexpr std::enable_if_t< - std::is_integral::value && - std::is_integral::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 - constexpr - std::enable_if_t::value, bool> + template + constexpr bool is_integer (T) { return true; } - template - constexpr - std::enable_if_t::value, bool> + + template + 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, - void - > - > + template constexpr auto digits10 (NumericT v) noexcept { @@ -339,12 +297,8 @@ namespace cruft { } - template - constexpr - std::enable_if_t< - std::is_integral_v && std::is_integral_v, - int - > + template + 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 - constexpr std::enable_if_t< - std::is_signed::value && std::is_integral::value, T - > + template + 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 - constexpr std::enable_if_t< - std::is_floating_point::value, T - > + template + 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 - constexpr - std::enable_if_t< - std::is_floating_point::value, T - > + template + constexpr T mod (T x, T y) { return std::fmod (x, y); } - template - constexpr - std::enable_if_t< - std::is_integral::value, T - > + template + constexpr T mod (T x, T y) { return x % y; } - template < - typename ValueT, - typename = std::enable_if_t> - > + template ValueT frac (ValueT val) { @@ -544,13 +485,11 @@ namespace cruft { /////////////////////////////////////////////////////////////////////////////// // kahan summation for long floating point sequences - template - std::enable_if_t< - std::is_floating_point< - typename std::iterator_traits::value_type - >::value, - typename std::iterator_traits::value_type - > + template + requires + concepts::legacy_input_iterator && + concepts::floating_point::value_type> + typename std::iterator_traits::value_type sum (InputT first, InputT last) { using T = typename std::iterator_traits::value_type; @@ -576,13 +515,11 @@ namespace cruft { //------------------------------------------------------------------------- - template - std::enable_if_t< - std::is_integral< - typename std::iterator_traits::value_type - >::value, - typename std::iterator_traits::value_type - > + template + requires + concepts::legacy_input_iterator && + concepts::integral::value_type> + typename std::iterator_traits::value_type sum (InputT first, InputT last) { using T = typename std::iterator_traits::value_type; @@ -625,37 +562,37 @@ namespace cruft { //------------------------------------------------------------------------- - template - const ValueT& - max (const std::array &vals) + template + typename ContainerT::value_type const& + max (ContainerT const &vals) { return *std::max_element (vals.begin (), vals.end ()); } - template - ValueT& - max (std::array &&) = delete; + template + typename ValueT::value_type & + max (ValueT &&) = delete; //------------------------------------------------------------------------- - template - const ValueT& - min (const std::array &vals) + template + typename ContainerT::value_type const& + min (ContainerT const &vals) { return *std::min_element (vals.begin (), vals.end ()); } - template - ValueT& - min (std::array &&) = delete; + template + typename ContainerT::value_type& + min (ContainerT &&) = delete; ///------------------------------------------------------------------------ /// Returns an ordered pair where the elements come from the parameters. template - std::pair + std::pair maxmin (ValueT a, ValueT b) { if (a >= b) @@ -669,13 +606,13 @@ namespace cruft { // Limiting functions // min/max clamping - template - constexpr - std::enable_if_t< - std::is_scalar_v && std::is_scalar_v && std::is_scalar_v, - std::common_type_t + 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 + clamp (T const val, U const lo, V const hi) { assert (lo <= hi); @@ -699,10 +636,12 @@ namespace cruft { //------------------------------------------------------------------------- - template - constexpr - std::enable_if_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 - constexpr - typename std::enable_if< - std::is_unsigned::value && std::is_floating_point::value, U - >::type + template < + concepts::unsigned_integral T, + concepts::floating_point U + > + constexpr U renormalise (T t) { return t / static_cast (std::numeric_limits::max ()); @@ -734,11 +673,11 @@ namespace cruft { //------------------------------------------------------------------------- // float -> uint - template - constexpr - typename std::enable_if< - std::is_floating_point::value && std::is_unsigned::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 - constexpr - typename std::enable_if< - std::is_floating_point::value && - std::is_floating_point::value && - !std::is_same::value, U - >::type + requires + concepts::floating_point && + concepts::floating_point && + (!std::is_same_v) + constexpr U renormalise (T t) { return static_cast (t); @@ -784,12 +722,11 @@ namespace cruft { //------------------------------------------------------------------------- // hi_uint -> lo_uint template - constexpr - typename std::enable_if< - std::is_unsigned::value && - std::is_unsigned::value && - (sizeof (T) > sizeof (U)), U - >::type + requires + concepts::unsigned_integral && + concepts::unsigned_integral && + (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::value && - std::is_unsigned::value && - sizeof (SrcT) < sizeof (DstT), DstT - > + typename DstT > + requires + concepts::unsigned_integral && + concepts::unsigned_integral && + (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 - constexpr - typename std::enable_if< - std::is_same::value, U - >::type + requires (std::is_same_v) + constexpr U renormalise (T t) { return t; } @@ -863,13 +797,10 @@ namespace cruft { //------------------------------------------------------------------------- // anything-to-sint template - constexpr - typename std::enable_if< - std::is_signed::value && - std::is_integral::value && - !std::is_same::value, - U - >::type + requires + concepts::signed_integral && + (!std::is_same::value) + constexpr U renormalise (T t) { using uint_t = typename std::make_unsigned::type; @@ -883,13 +814,10 @@ namespace cruft { //------------------------------------------------------------------------- // sint-to-anything template - constexpr - typename std::enable_if< - std::is_signed::value && - std::is_integral::value && - !std::is_same::value, - U - >::type + requires + concepts::signed_integral && + (!std::is_same::value) + constexpr U renormalise (T sint) { using uint_t = typename std::make_unsigned::type; @@ -899,6 +827,3 @@ namespace cruft { ); }; } - - -#endif // __MATHS_HPP