Last active
June 10, 2024 10:31
-
-
Save misyltoad/04f666b8a0a0a15f6ab133937f6e0db8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
template <class _Ty> | |
_NODISCARD /* constexpr */ _Ty _Common_lerp(const _Ty _ArgA, const _Ty _ArgB, const _Ty _ArgT) noexcept { | |
// on a line intersecting {(0.0, _ArgA), (1.0, _ArgB)}, return the Y value for X == _ArgT | |
const int _Finite_mask = (int{isfinite(_ArgA)} << 2) | (int{isfinite(_ArgB)} << 1) | int{isfinite(_ArgT)}; | |
if (_Finite_mask == 0b111) { | |
// 99% case, put it first; this block comes from P0811R3 | |
if ((_ArgA <= 0 && _ArgB >= 0) || (_ArgA >= 0 && _ArgB <= 0)) { | |
// exact, monotonic, bounded, determinate, and (for _ArgA == _ArgB == 0) consistent: | |
return _ArgT * _ArgB + (1 - _ArgT) * _ArgA; | |
} | |
if (_ArgT == 1) { | |
// exact | |
return _ArgB; | |
} | |
// exact at _ArgT == 0, monotonic except near _ArgT == 1, bounded, determinate, and consistent: | |
const auto _Candidate = _ArgA + _ArgT * (_ArgB - _ArgA); | |
// monotonic near _ArgT == 1: | |
if ((_ArgT > 1) == (_ArgB > _ArgA)) { | |
if (_ArgB > _Candidate) { | |
return _ArgB; | |
} | |
} else { | |
if (_Candidate > _ArgB) { | |
return _ArgB; | |
} | |
} | |
return _Candidate; | |
} | |
if (isnan(_ArgA)) { | |
return _ArgA; | |
} | |
if (isnan(_ArgB)) { | |
return _ArgB; | |
} | |
if (isnan(_ArgT)) { | |
return _ArgT; | |
} | |
switch (_Finite_mask) { | |
case 0b000: | |
// All values are infinities | |
if (_ArgT >= 1) { | |
return _ArgB; | |
} | |
return _ArgA; | |
case 0b010: | |
case 0b100: | |
case 0b110: | |
// _ArgT is an infinity; return infinity in the "direction" of _ArgA and _ArgB | |
return _ArgT * (_ArgB - _ArgA); | |
case 0b001: | |
// Here _ArgA and _ArgB are infinities | |
if (_ArgA == _ArgB) { | |
// same sign, so T doesn't matter | |
return _ArgA; | |
} | |
// Opposite signs, choose the "infinity direction" according to T if it makes sense. | |
if (_ArgT <= 0) { | |
return _ArgA; | |
} | |
if (_ArgT >= 1) { | |
return _ArgB; | |
} | |
// Interpolating between infinities of opposite signs doesn't make sense, NaN | |
if constexpr (sizeof(_Ty) == sizeof(float)) { | |
return __builtin_nanf("0"); | |
} else { | |
return __builtin_nan("0"); | |
} | |
case 0b011: | |
// _ArgA is an infinity but _ArgB is not | |
if (_ArgT == 1) { | |
return _ArgB; | |
} | |
if (_ArgT < 1) { | |
// towards the infinity, return it | |
return _ArgA; | |
} | |
// away from the infinity | |
return -_ArgA; | |
case 0b101: | |
// _ArgA is finite and _ArgB is an infinity | |
if (_ArgT == 0) { | |
return _ArgA; | |
} | |
if (_ArgT > 0) { | |
// toward the infinity | |
return _ArgB; | |
} | |
return -_ArgB; | |
case 0b111: // impossible; handled in fast path | |
default: | |
_CSTD abort(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is more common than you think in high performance applications in the professional workspace. Look at Rad Game Tools for example.
But, I digress… I too enjoy using the STL as much as I can.
You can take your trolling elsewhere though, with all the sarcasm and such.