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