1#include "../integer.hpp" 2 3namespace glm{ 4namespace detail 5{ 6 template<length_t L, typename T, qualifier Q, bool compute = false> 7 struct compute_ceilShift 8 { 9 GLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& v, T) 10 { 11 return v; 12 } 13 }; 14 15 template<length_t L, typename T, qualifier Q> 16 struct compute_ceilShift<L, T, Q, true> 17 { 18 GLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& v, T Shift) 19 { 20 return v | (v >> Shift); 21 } 22 }; 23 24 template<length_t L, typename T, qualifier Q, bool isSigned = true> 25 struct compute_ceilPowerOfTwo 26 { 27 GLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& x) 28 { 29 GLM_STATIC_ASSERT(!std::numeric_limits<T>::is_iec559, "'ceilPowerOfTwo' only accept integer scalar or vector inputs"); 30 31 vec<L, T, Q> const Sign(sign(x)); 32 33 vec<L, T, Q> v(abs(x)); 34 35 v = v - static_cast<T>(1); 36 v = v | (v >> static_cast<T>(1)); 37 v = v | (v >> static_cast<T>(2)); 38 v = v | (v >> static_cast<T>(4)); 39 v = compute_ceilShift<L, T, Q, sizeof(T) >= 2>::call(v, 8); 40 v = compute_ceilShift<L, T, Q, sizeof(T) >= 4>::call(v, 16); 41 v = compute_ceilShift<L, T, Q, sizeof(T) >= 8>::call(v, 32); 42 return (v + static_cast<T>(1)) * Sign; 43 } 44 }; 45 46 template<length_t L, typename T, qualifier Q> 47 struct compute_ceilPowerOfTwo<L, T, Q, false> 48 { 49 GLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& x) 50 { 51 GLM_STATIC_ASSERT(!std::numeric_limits<T>::is_iec559, "'ceilPowerOfTwo' only accept integer scalar or vector inputs"); 52 53 vec<L, T, Q> v(x); 54 55 v = v - static_cast<T>(1); 56 v = v | (v >> static_cast<T>(1)); 57 v = v | (v >> static_cast<T>(2)); 58 v = v | (v >> static_cast<T>(4)); 59 v = compute_ceilShift<L, T, Q, sizeof(T) >= 2>::call(v, 8); 60 v = compute_ceilShift<L, T, Q, sizeof(T) >= 4>::call(v, 16); 61 v = compute_ceilShift<L, T, Q, sizeof(T) >= 8>::call(v, 32); 62 return v + static_cast<T>(1); 63 } 64 }; 65 66 template<bool is_float, bool is_signed> 67 struct compute_ceilMultiple{}; 68 69 template<> 70 struct compute_ceilMultiple<true, true> 71 { 72 template<typename genType> 73 GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) 74 { 75 if(Source > genType(0)) 76 return Source + (Multiple - std::fmod(Source, Multiple)); 77 else 78 return Source + std::fmod(-Source, Multiple); 79 } 80 }; 81 82 template<> 83 struct compute_ceilMultiple<false, false> 84 { 85 template<typename genType> 86 GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) 87 { 88 genType Tmp = Source - genType(1); 89 return Tmp + (Multiple - (Tmp % Multiple)); 90 } 91 }; 92 93 template<> 94 struct compute_ceilMultiple<false, true> 95 { 96 template<typename genType> 97 GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) 98 { 99 assert(Multiple > genType(0)); 100 if(Source > genType(0)) 101 { 102 genType Tmp = Source - genType(1); 103 return Tmp + (Multiple - (Tmp % Multiple)); 104 } 105 else 106 return Source + (-Source % Multiple); 107 } 108 }; 109 110 template<bool is_float, bool is_signed> 111 struct compute_floorMultiple{}; 112 113 template<> 114 struct compute_floorMultiple<true, true> 115 { 116 template<typename genType> 117 GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) 118 { 119 if(Source >= genType(0)) 120 return Source - std::fmod(Source, Multiple); 121 else 122 return Source - std::fmod(Source, Multiple) - Multiple; 123 } 124 }; 125 126 template<> 127 struct compute_floorMultiple<false, false> 128 { 129 template<typename genType> 130 GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) 131 { 132 if(Source >= genType(0)) 133 return Source - Source % Multiple; 134 else 135 { 136 genType Tmp = Source + genType(1); 137 return Tmp - Tmp % Multiple - Multiple; 138 } 139 } 140 }; 141 142 template<> 143 struct compute_floorMultiple<false, true> 144 { 145 template<typename genType> 146 GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) 147 { 148 if(Source >= genType(0)) 149 return Source - Source % Multiple; 150 else 151 { 152 genType Tmp = Source + genType(1); 153 return Tmp - Tmp % Multiple - Multiple; 154 } 155 } 156 }; 157}//namespace detail 158 159 template<typename genIUType> 160 GLM_FUNC_QUALIFIER bool isPowerOfTwo(genIUType Value) 161 { 162 GLM_STATIC_ASSERT(std::numeric_limits<genIUType>::is_integer, "'isPowerOfTwo' only accept integer inputs"); 163 164 genIUType const Result = glm::abs(Value); 165 return !(Result & (Result - 1)); 166 } 167 168 template<typename genIUType> 169 GLM_FUNC_QUALIFIER genIUType nextPowerOfTwo(genIUType value) 170 { 171 GLM_STATIC_ASSERT(std::numeric_limits<genIUType>::is_integer, "'nextPowerOfTwo' only accept integer inputs"); 172 173 return detail::compute_ceilPowerOfTwo<1, genIUType, defaultp, std::numeric_limits<genIUType>::is_signed>::call(vec<1, genIUType, defaultp>(value)).x; 174 } 175 176 template<typename genIUType> 177 GLM_FUNC_QUALIFIER genIUType prevPowerOfTwo(genIUType value) 178 { 179 GLM_STATIC_ASSERT(std::numeric_limits<genIUType>::is_integer, "'prevPowerOfTwo' only accept integer inputs"); 180 181 return isPowerOfTwo(value) ? value : static_cast<genIUType>(static_cast<genIUType>(1) << static_cast<genIUType>(findMSB(value))); 182 } 183 184 template<typename genIUType> 185 GLM_FUNC_QUALIFIER bool isMultiple(genIUType Value, genIUType Multiple) 186 { 187 GLM_STATIC_ASSERT(std::numeric_limits<genIUType>::is_integer, "'isMultiple' only accept integer inputs"); 188 189 return isMultiple(vec<1, genIUType>(Value), vec<1, genIUType>(Multiple)).x; 190 } 191 192 template<typename genIUType> 193 GLM_FUNC_QUALIFIER genIUType nextMultiple(genIUType Source, genIUType Multiple) 194 { 195 GLM_STATIC_ASSERT(std::numeric_limits<genIUType>::is_integer, "'nextMultiple' only accept integer inputs"); 196 197 return detail::compute_ceilMultiple<std::numeric_limits<genIUType>::is_iec559, std::numeric_limits<genIUType>::is_signed>::call(Source, Multiple); 198 } 199 200 template<typename genIUType> 201 GLM_FUNC_QUALIFIER genIUType prevMultiple(genIUType Source, genIUType Multiple) 202 { 203 GLM_STATIC_ASSERT(std::numeric_limits<genIUType>::is_integer, "'prevMultiple' only accept integer inputs"); 204 205 return detail::compute_floorMultiple<std::numeric_limits<genIUType>::is_iec559, std::numeric_limits<genIUType>::is_signed>::call(Source, Multiple); 206 } 207 208 template<typename genIUType> 209 GLM_FUNC_QUALIFIER int findNSB(genIUType x, int significantBitCount) 210 { 211 GLM_STATIC_ASSERT(std::numeric_limits<genIUType>::is_integer, "'findNSB' only accept integer inputs"); 212 213 if(bitCount(x) < significantBitCount) 214 return -1; 215 216 genIUType const One = static_cast<genIUType>(1); 217 int bitPos = 0; 218 219 genIUType key = x; 220 int nBitCount = significantBitCount; 221 int Step = sizeof(x) * 8 / 2; 222 while (key > One) 223 { 224 genIUType Mask = static_cast<genIUType>((One << Step) - One); 225 genIUType currentKey = key & Mask; 226 int currentBitCount = bitCount(currentKey); 227 if (nBitCount > currentBitCount) 228 { 229 nBitCount -= currentBitCount; 230 bitPos += Step; 231 key >>= static_cast<genIUType>(Step); 232 } 233 else 234 { 235 key = key & Mask; 236 } 237 238 Step >>= 1; 239 } 240 241 return static_cast<int>(bitPos); 242 } 243}//namespace glm 244