@ -9,6 +9,7 @@
# pragma once
# pragma once
# include <AzCore/base.h>
# include <AzCore/base.h>
# include <AzCore/std/limits.h>
# include <AzCore/std/math.h>
# include <AzCore/std/math.h>
# include <AzCore/std/typetraits/conditional.h>
# include <AzCore/std/typetraits/conditional.h>
# include <AzCore/std/typetraits/is_integral.h>
# include <AzCore/std/typetraits/is_integral.h>
@ -20,6 +21,7 @@
# include <limits>
# include <limits>
# include <math.h>
# include <math.h>
# include <utility>
# include <utility>
# include <inttypes.h>
// We have a separate inline define for math functions.
// We have a separate inline define for math functions.
// The performance of these functions is very sensitive to inlining, and some compilers don't deal well with this.
// The performance of these functions is very sensitive to inlining, and some compilers don't deal well with this.
@ -256,13 +258,13 @@ namespace AZ
struct ClampedIntegralLimits
struct ClampedIntegralLimits
{
{
//! If SourceType and ClampType are different, returns the greater value of
//! If SourceType and ClampType are different, returns the greater value of
//! std::numeric_limits<SourceType>::lowest() and s td::numeric_limits<ClampType>::lowest(),
//! AZStd::numeric_limits<SourceType>::lowest() and AZS td::numeric_limits<ClampType>::lowest(),
//! otherwise returns s td::numeric_limits<SourceType>::lowest().
//! otherwise returns AZS td::numeric_limits<SourceType>::lowest().
static constexpr SourceType Min ( ) ;
static constexpr SourceType Min ( ) ;
//! If SourceType and ClampType are different, returns the lesser value of
//! If SourceType and ClampType are different, returns the lesser value of
//! std::numeric_limits<SourceType>::max() and s td::numeric_limits<ClampType>::max(),
//! AZStd::numeric_limits<SourceType>::max() and AZS td::numeric_limits<ClampType>::max(),
//! otherwise returns s td::numeric_limits<SourceType>::max().
//! otherwise returns AZS td::numeric_limits<SourceType>::max().
static constexpr SourceType Max ( ) ;
static constexpr SourceType Max ( ) ;
//! Safely clamps a value of type ValueType to the [Min(), Max()] range as determined by the
//! Safely clamps a value of type ValueType to the [Min(), Max()] range as determined by the
@ -375,12 +377,12 @@ namespace AZ
//! Returns a value t where Lerp(a, b, t) == value (or 0 if a == b).
//! Returns a value t where Lerp(a, b, t) == value (or 0 if a == b).
inline float LerpInverse ( float a , float b , float value )
inline float LerpInverse ( float a , float b , float value )
{
{
return IsClose ( a , b , s td: : numeric_limits < float > : : epsilon ( ) ) ? 0.0f : ( value - a ) / ( b - a ) ;
return IsClose ( a , b , AZS td: : numeric_limits < float > : : epsilon ( ) ) ? 0.0f : ( value - a ) / ( b - a ) ;
}
}
inline double LerpInverse ( double a , double b , double value )
inline double LerpInverse ( double a , double b , double value )
{
{
return IsClose ( a , b , s td: : numeric_limits < double > : : epsilon ( ) ) ? 0.0 : ( value - a ) / ( b - a ) ;
return IsClose ( a , b , AZS td: : numeric_limits < double > : : epsilon ( ) ) ? 0.0 : ( value - a ) / ( b - a ) ;
}
}
//! Returns true if the number provided is even.
//! Returns true if the number provided is even.
@ -431,19 +433,19 @@ namespace AZ
AZ_MATH_INLINE float GetFloatQNaN ( )
AZ_MATH_INLINE float GetFloatQNaN ( )
{
{
return s td: : numeric_limits < float > : : quiet_NaN ( ) ;
return AZS td: : numeric_limits < float > : : quiet_NaN ( ) ;
}
}
//! IsCloseMag(x, y, epsilon) returns true if y and x are sufficiently close, taking magnitude of x and y into account in the epsilon
//! IsCloseMag(x, y, epsilon) returns true if y and x are sufficiently close, taking magnitude of x and y into account in the epsilon
template < typename T >
template < typename T >
AZ_MATH_INLINE bool IsCloseMag ( T x , T y , T epsilonValue = s td: : numeric_limits < T > : : epsilon ( ) )
AZ_MATH_INLINE bool IsCloseMag ( T x , T y , T epsilonValue = AZS td: : numeric_limits < T > : : epsilon ( ) )
{
{
return ( AZStd : : abs ( x - y ) < = epsilonValue * GetMax < T > ( GetMax < T > ( T ( 1.0 ) , AZStd : : abs ( x ) ) , AZStd : : abs ( y ) ) ) ;
return ( AZStd : : abs ( x - y ) < = epsilonValue * GetMax < T > ( GetMax < T > ( T ( 1.0 ) , AZStd : : abs ( x ) ) , AZStd : : abs ( y ) ) ) ;
}
}
//! ClampIfCloseMag(x, y, epsilon) returns y when x and y are within epsilon of each other (taking magnitude into account). Otherwise returns x.
//! ClampIfCloseMag(x, y, epsilon) returns y when x and y are within epsilon of each other (taking magnitude into account). Otherwise returns x.
template < typename T >
template < typename T >
AZ_MATH_INLINE T ClampIfCloseMag ( T x , T y , T epsilonValue = s td: : numeric_limits < T > : : epsilon ( ) )
AZ_MATH_INLINE T ClampIfCloseMag ( T x , T y , T epsilonValue = AZS td: : numeric_limits < T > : : epsilon ( ) )
{
{
return IsCloseMag < T > ( x , y , epsilonValue ) ? y : x ;
return IsCloseMag < T > ( x , y , epsilonValue ) ? y : x ;
}
}
@ -461,6 +463,44 @@ namespace AZ
return ( azisfinite ( x ) ! = 0 ) ;
return ( azisfinite ( x ) ! = 0 ) ;
}
}
//! Returns the value divided by alignment, where the result is rounded up if the remainder is non-zero.
//! Example: alignment: 4
//! Value: 0 1 2 3 4 5 6 7 8
//! Result: 0 1 1 1 1 2 2 2 2
constexpr uint32_t DivideAndRoundUp ( uint32_t value , uint32_t alignment )
{
AZ_Assert ( alignment ! = 0 , " 0 is an invalid multiple to round to. " ) ;
AZ_Assert (
AZStd : : numeric_limits < uint32_t > : : max ( ) - value > = alignment ,
" value '% " PRIu32 " ' and alignment '% " PRIu32 " ' will overflow when added together during DivideAndRoundUp. " , value , alignment ) ;
return ( value + alignment - 1 ) / alignment ;
}
constexpr uint64_t DivideAndRoundUp ( uint64_t value , uint64_t alignment )
{
AZ_Assert ( alignment ! = 0 , " 0 is an invalid multiple to round to. " ) ;
AZ_Assert (
AZStd : : numeric_limits < uint64_t > : : max ( ) - value > = alignment ,
" value '% " PRIu64 " ' and alignment '% " PRIu64 " ' will overflow when added together during DivideAndRoundUp. " , value , alignment ) ;
return ( value + alignment - 1 ) / alignment ;
}
//! Returns the value rounded up to a multiple of alignment.
//! This function will work for non power of two alignments.
//! If your alignment is guaranteed to be a power of two, SizeAlignUp in base.h is a more efficient implementation.
//! Example: roundTo: 4
//! Value: 0 1 2 3 4 5 6 7 8
//! Result: 0 4 4 4 4 8 8 8 8
constexpr uint32_t RoundUpToMultiple ( uint32_t value , uint32_t alignment )
{
return DivideAndRoundUp ( value , alignment ) * alignment ;
}
constexpr uint64_t RoundUpToMultiple ( uint64_t value , uint64_t alignment )
{
return DivideAndRoundUp ( value , alignment ) * alignment ;
}
//! Returns the maximum value for SourceType as constrained by the numerical range of ClampType.
//! Returns the maximum value for SourceType as constrained by the numerical range of ClampType.
template < typename SourceType , typename ClampType >
template < typename SourceType , typename ClampType >
constexpr SourceType ClampedIntegralLimits < SourceType , ClampType > : : Min ( )
constexpr SourceType ClampedIntegralLimits < SourceType , ClampType > : : Min ( )
@ -474,8 +514,8 @@ namespace AZ
{
{
// Both SourceType and ClampType are signed, take the greater of the lower limits of each type
// Both SourceType and ClampType are signed, take the greater of the lower limits of each type
return sizeof ( SourceType ) < sizeof ( ClampType ) ?
return sizeof ( SourceType ) < sizeof ( ClampType ) ?
( s td: : numeric_limits < SourceType > : : lowest ) ( ) :
( AZS td: : numeric_limits < SourceType > : : lowest ) ( ) :
static_cast < SourceType > ( ( s td: : numeric_limits < ClampType > : : lowest ) ( ) ) ;
static_cast < SourceType > ( ( AZS td: : numeric_limits < ClampType > : : lowest ) ( ) ) ;
}
}
}
}
@ -486,12 +526,12 @@ namespace AZ
if constexpr ( sizeof ( SourceType ) < sizeof ( ClampType ) )
if constexpr ( sizeof ( SourceType ) < sizeof ( ClampType ) )
{
{
// If SourceType is narrower than ClampType, the upper limit will be SourceType's
// If SourceType is narrower than ClampType, the upper limit will be SourceType's
return ( s td: : numeric_limits < SourceType > : : max ) ( ) ;
return ( AZS td: : numeric_limits < SourceType > : : max ) ( ) ;
}
}
else if constexpr ( sizeof ( SourceType ) > sizeof ( ClampType ) )
else if constexpr ( sizeof ( SourceType ) > sizeof ( ClampType ) )
{
{
// If SourceType is wider than ClampType, the upper limit will be ClampType's
// If SourceType is wider than ClampType, the upper limit will be ClampType's
return static_cast < SourceType > ( ( s td: : numeric_limits < ClampType > : : max ) ( ) ) ;
return static_cast < SourceType > ( ( AZS td: : numeric_limits < ClampType > : : max ) ( ) ) ;
}
}
else
else
{
{
@ -499,13 +539,13 @@ namespace AZ
{
{
// SourceType and ClampType are the same width, ClampType is signed
// SourceType and ClampType are the same width, ClampType is signed
// so our upper limit will be ClampType
// so our upper limit will be ClampType
return static_cast < SourceType > ( ( s td: : numeric_limits < ClampType > : : max ) ( ) ) ;
return static_cast < SourceType > ( ( AZS td: : numeric_limits < ClampType > : : max ) ( ) ) ;
}
}
else
else
{
{
// SourceType and ClampType are the same width, ClampType is unsigned
// SourceType and ClampType are the same width, ClampType is unsigned
// then our upper limit will be SourceType
// then our upper limit will be SourceType
return ( s td: : numeric_limits < SourceType > : : max ) ( ) ;
return ( AZS td: : numeric_limits < SourceType > : : max ) ( ) ;
}
}
}
}
}
}
@ -588,7 +628,7 @@ namespace AZ
// LeftTypeSize <= RightTypeSize
// LeftTypeSize <= RightTypeSize
// LeftType is signed
// LeftType is signed
// RightType is unsigned
// RightType is unsigned
RightType max = static_cast < RightType > ( ( s td: : numeric_limits < LeftType > : : max ) ( ) ) ;
RightType max = static_cast < RightType > ( ( AZS td: : numeric_limits < LeftType > : : max ) ( ) ) ;
if ( rhs > max )
if ( rhs > max )
{
{
@ -604,7 +644,7 @@ namespace AZ
// LeftType < RightType
// LeftType < RightType
// LeftType is unsigned
// LeftType is unsigned
// RightType is signed
// RightType is signed
RightType max = static_cast < RightType > ( ( s td: : numeric_limits < LeftType > : : max ) ( ) ) ;
RightType max = static_cast < RightType > ( ( AZS td: : numeric_limits < LeftType > : : max ) ( ) ) ;
if ( rhs < 0 )
if ( rhs < 0 )
{
{