mptBaseUtils.h 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. /*
  2. * mptBaseUtils.h
  3. * --------------
  4. * Purpose: Various useful utility functions.
  5. * Notes : (currently none)
  6. * Authors: OpenMPT Devs
  7. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  8. */
  9. #pragma once
  10. #include "openmpt/all/BuildSettings.hpp"
  11. #include "mpt/base/algorithm.hpp"
  12. #include "mpt/base/arithmetic_shift.hpp"
  13. #include "mpt/base/array.hpp"
  14. #include "mpt/base/bit.hpp"
  15. #include "mpt/base/constexpr_throw.hpp"
  16. #include "mpt/base/math.hpp"
  17. #include "mpt/base/memory.hpp"
  18. #include "mpt/base/numeric.hpp"
  19. #include "mpt/base/saturate_cast.hpp"
  20. #include "mpt/base/saturate_round.hpp"
  21. #include "mpt/base/utility.hpp"
  22. #include "mpt/base/wrapping_divide.hpp"
  23. #include "mptBaseMacros.h"
  24. #include "mptBaseTypes.h"
  25. #include <algorithm>
  26. #include <limits>
  27. #include <numeric>
  28. #include <utility>
  29. #include <cmath>
  30. #include <cstdlib>
  31. #include <math.h>
  32. #include <stdlib.h>
  33. #if MPT_COMPILER_MSVC
  34. #include <intrin.h>
  35. #endif
  36. OPENMPT_NAMESPACE_BEGIN
  37. template <typename T>
  38. inline void Clear(T& x)
  39. {
  40. static_assert(!std::is_pointer<T>::value);
  41. mpt::reset(x);
  42. }
  43. // Memset given object to zero.
  44. template <class T>
  45. inline void MemsetZero(T& a)
  46. {
  47. static_assert(std::is_pointer<T>::value == false, "Won't memset pointers.");
  48. mpt::memclear(a);
  49. }
  50. // Limits 'val' to given range. If 'val' is less than 'lowerLimit', 'val' is set to value 'lowerLimit'.
  51. // Similarly if 'val' is greater than 'upperLimit', 'val' is set to value 'upperLimit'.
  52. // If 'lowerLimit' > 'upperLimit', 'val' won't be modified.
  53. template<class T, class C>
  54. inline void Limit(T& val, const C lowerLimit, const C upperLimit)
  55. {
  56. if(lowerLimit > upperLimit) return;
  57. if(val < lowerLimit) val = lowerLimit;
  58. else if(val > upperLimit) val = upperLimit;
  59. }
  60. // Like Limit, but returns value
  61. template<class T, class C>
  62. inline T Clamp(T val, const C lowerLimit, const C upperLimit)
  63. {
  64. if(val < lowerLimit) return lowerLimit;
  65. else if(val > upperLimit) return upperLimit;
  66. else return val;
  67. }
  68. // Like Limit, but with upperlimit only.
  69. template<class T, class C>
  70. inline void LimitMax(T& val, const C upperLimit)
  71. {
  72. if(val > upperLimit)
  73. val = upperLimit;
  74. }
  75. namespace Util
  76. {
  77. // Returns maximum value of given integer type.
  78. template <class T> constexpr T MaxValueOfType(const T&) {static_assert(std::numeric_limits<T>::is_integer == true, "Only integer types are allowed."); return (std::numeric_limits<T>::max)();}
  79. } // namespace Util
  80. namespace Util {
  81. // Multiply two 32-bit integers, receive 64-bit result.
  82. // MSVC generates unnecessarily complicated code for the unoptimized variant using _allmul.
  83. MPT_CONSTEXPR20_FUN int64 mul32to64(int32 a, int32 b)
  84. {
  85. #if MPT_COMPILER_MSVC && (defined(_M_IX86) || defined(_M_X64))
  86. MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED20())
  87. {
  88. return static_cast<int64>(a) * b;
  89. } else
  90. {
  91. return __emul(a, b);
  92. }
  93. #else
  94. return static_cast<int64>(a) * b;
  95. #endif
  96. }
  97. MPT_CONSTEXPR20_FUN uint64 mul32to64_unsigned(uint32 a, uint32 b)
  98. {
  99. #if MPT_COMPILER_MSVC && (defined(_M_IX86) || defined(_M_X64))
  100. MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED20())
  101. {
  102. return static_cast<uint64>(a) * b;
  103. } else
  104. {
  105. return __emulu(a, b);
  106. }
  107. #else
  108. return static_cast<uint64>(a) * b;
  109. #endif
  110. }
  111. MPT_CONSTEXPR20_FUN int32 muldiv(int32 a, int32 b, int32 c)
  112. {
  113. return mpt::saturate_cast<int32>( mul32to64( a, b ) / c );
  114. }
  115. MPT_CONSTEXPR20_FUN int32 muldivr(int32 a, int32 b, int32 c)
  116. {
  117. return mpt::saturate_cast<int32>( ( mul32to64( a, b ) + ( c / 2 ) ) / c );
  118. }
  119. // Do not use overloading because catching unsigned version by accident results in slower X86 code.
  120. MPT_CONSTEXPR20_FUN uint32 muldiv_unsigned(uint32 a, uint32 b, uint32 c)
  121. {
  122. return mpt::saturate_cast<uint32>( mul32to64_unsigned( a, b ) / c );
  123. }
  124. MPT_CONSTEXPR20_FUN uint32 muldivr_unsigned(uint32 a, uint32 b, uint32 c)
  125. {
  126. return mpt::saturate_cast<uint32>( ( mul32to64_unsigned( a, b ) + ( c / 2u ) ) / c );
  127. }
  128. constexpr MPT_FORCEINLINE int32 muldivrfloor(int64 a, uint32 b, uint32 c)
  129. {
  130. a *= b;
  131. a += c / 2u;
  132. return (a >= 0) ? mpt::saturate_cast<int32>(a / c) : mpt::saturate_cast<int32>((a - (c - 1)) / c);
  133. }
  134. } // namespace Util
  135. OPENMPT_NAMESPACE_END