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
10
11 #pragma once
12
13 #include "openmpt/all/BuildSettings.hpp"
14
15
16 #include "mpt/base/algorithm.hpp"
17 #include "mpt/base/arithmetic_shift.hpp"
18 #include "mpt/base/array.hpp"
19 #include "mpt/base/bit.hpp"
20 #include "mpt/base/constexpr_throw.hpp"
21 #include "mpt/base/math.hpp"
22 #include "mpt/base/memory.hpp"
23 #include "mpt/base/numeric.hpp"
24 #include "mpt/base/saturate_cast.hpp"
25 #include "mpt/base/saturate_round.hpp"
26 #include "mpt/base/utility.hpp"
27 #include "mpt/base/wrapping_divide.hpp"
28
29 #include "mptBaseMacros.h"
30 #include "mptBaseTypes.h"
31
32 #include <algorithm>
33 #include <limits>
34 #include <numeric>
35 #include <utility>
36
37 #include <cmath>
38 #include <cstdlib>
39
40 #include <math.h>
41 #include <stdlib.h>
42
43 #if MPT_COMPILER_MSVC
44 #include <intrin.h>
45 #endif
46
47
48
49 OPENMPT_NAMESPACE_BEGIN
50
51
52
53 template <typename T>
Clear(T & x)54 inline void Clear(T& x)
55 {
56 static_assert(!std::is_pointer<T>::value);
57 mpt::reset(x);
58 }
59
60
61 // Memset given object to zero.
62 template <class T>
MemsetZero(T & a)63 inline void MemsetZero(T& a)
64 {
65 static_assert(std::is_pointer<T>::value == false, "Won't memset pointers.");
66 mpt::memclear(a);
67 }
68
69
70
71 // Limits 'val' to given range. If 'val' is less than 'lowerLimit', 'val' is set to value 'lowerLimit'.
72 // Similarly if 'val' is greater than 'upperLimit', 'val' is set to value 'upperLimit'.
73 // If 'lowerLimit' > 'upperLimit', 'val' won't be modified.
74 template<class T, class C>
Limit(T & val,const C lowerLimit,const C upperLimit)75 inline void Limit(T& val, const C lowerLimit, const C upperLimit)
76 {
77 if(lowerLimit > upperLimit) return;
78 if(val < lowerLimit) val = lowerLimit;
79 else if(val > upperLimit) val = upperLimit;
80 }
81
82
83 // Like Limit, but returns value
84 template<class T, class C>
Clamp(T val,const C lowerLimit,const C upperLimit)85 inline T Clamp(T val, const C lowerLimit, const C upperLimit)
86 {
87 if(val < lowerLimit) return lowerLimit;
88 else if(val > upperLimit) return upperLimit;
89 else return val;
90 }
91
92 // Like Limit, but with upperlimit only.
93 template<class T, class C>
LimitMax(T & val,const C upperLimit)94 inline void LimitMax(T& val, const C upperLimit)
95 {
96 if(val > upperLimit)
97 val = upperLimit;
98 }
99
100
101
102 namespace Util
103 {
104
105 // Returns maximum value of given integer type.
MaxValueOfType(const T &)106 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)();}
107
108 } // namespace Util
109
110
111
112 namespace Util {
113
114 // Multiply two 32-bit integers, receive 64-bit result.
115 // MSVC generates unnecessarily complicated code for the unoptimized variant using _allmul.
mul32to64(int32 a,int32 b)116 MPT_CONSTEXPR20_FUN int64 mul32to64(int32 a, int32 b)
117 {
118 #if MPT_COMPILER_MSVC && (defined(_M_IX86) || defined(_M_X64))
119 MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED20())
120 {
121 return static_cast<int64>(a) * b;
122 } else
123 {
124 return __emul(a, b);
125 }
126 #else
127 return static_cast<int64>(a) * b;
128 #endif
129 }
130
mul32to64_unsigned(uint32 a,uint32 b)131 MPT_CONSTEXPR20_FUN uint64 mul32to64_unsigned(uint32 a, uint32 b)
132 {
133 #if MPT_COMPILER_MSVC && (defined(_M_IX86) || defined(_M_X64))
134 MPT_MAYBE_CONSTANT_IF(MPT_IS_CONSTANT_EVALUATED20())
135 {
136 return static_cast<uint64>(a) * b;
137 } else
138 {
139 return __emulu(a, b);
140 }
141 #else
142 return static_cast<uint64>(a) * b;
143 #endif
144 }
145
muldiv(int32 a,int32 b,int32 c)146 MPT_CONSTEXPR20_FUN int32 muldiv(int32 a, int32 b, int32 c)
147 {
148 return mpt::saturate_cast<int32>( mul32to64( a, b ) / c );
149 }
150
muldivr(int32 a,int32 b,int32 c)151 MPT_CONSTEXPR20_FUN int32 muldivr(int32 a, int32 b, int32 c)
152 {
153 return mpt::saturate_cast<int32>( ( mul32to64( a, b ) + ( c / 2 ) ) / c );
154 }
155
156 // Do not use overloading because catching unsigned version by accident results in slower X86 code.
muldiv_unsigned(uint32 a,uint32 b,uint32 c)157 MPT_CONSTEXPR20_FUN uint32 muldiv_unsigned(uint32 a, uint32 b, uint32 c)
158 {
159 return mpt::saturate_cast<uint32>( mul32to64_unsigned( a, b ) / c );
160 }
muldivr_unsigned(uint32 a,uint32 b,uint32 c)161 MPT_CONSTEXPR20_FUN uint32 muldivr_unsigned(uint32 a, uint32 b, uint32 c)
162 {
163 return mpt::saturate_cast<uint32>( ( mul32to64_unsigned( a, b ) + ( c / 2u ) ) / c );
164 }
165
muldivrfloor(int64 a,uint32 b,uint32 c)166 constexpr MPT_FORCEINLINE int32 muldivrfloor(int64 a, uint32 b, uint32 c)
167 {
168 a *= b;
169 a += c / 2u;
170 return (a >= 0) ? mpt::saturate_cast<int32>(a / c) : mpt::saturate_cast<int32>((a - (c - 1)) / c);
171 }
172
173 } // namespace Util
174
175
176
177 OPENMPT_NAMESPACE_END
178