1 /*
2 	copyright: Steve Dekorte, 2006. All rights reserved.
3 	license: See _BSDLicense.txt.
4 */
5 
6 #include "UArray.h"
7 #include <math.h>
8 #include <float.h>
9 
10 #define IO_USE_SIMD 1
11 
12 #ifdef IO_USE_SIMD
13 
14 /*
15 #ifdef _MSC_VER
16 	#pragma message("Note: IO_USE_SIMD on, attempting to use SIMD acceleration")
17 #else
18 	#warning Note: IO_USE_SIMD on, attempting to use SIMD acceleration
19 #endif
20 */
21 
22 #include "simd_cp.h"
23 #else
24 
25 #ifdef _MSC_VER
26 	#pragma message("Uncomment the IO_USE_SIMD define to turn on SIMD acceleration")
27 #else
28 	#warning Uncomment the IO_USE_SIMD define to turn on SIMD acceleration
29 #endif
30 
31 #define __UNK__EMU__
32 #include "simd_cp_emu.h"
33 #endif
34 
35 #define VEC_SIZE 4
36 
37 #define LLVEC_DUALARG_OP(VNAME, COP, TYPE) \
38 void v ## TYPE ## _ ## VNAME(TYPE ##_t *aa, TYPE ##_t *bb, size_t size)\
39 {\
40 	size_t i = 0;\
41 	simd_m128 *a = (simd_m128 *)aa;\
42 	simd_m128 *b = (simd_m128 *)bb;\
43 	size_t max = (size / VEC_SIZE);\
44 	for(i = 0; i < max; i ++) { simd_4f_ ## VNAME (a[i], b[i], a[i]); }\
45 	i = i * VEC_SIZE;\
46 	while (i < size) { aa[i] COP bb[i]; i ++; }\
47 }
48 
49 LLVEC_DUALARG_OP(add,  +=, float32);
50 LLVEC_DUALARG_OP(sub,  -=, float32);
51 LLVEC_DUALARG_OP(mult, *=, float32);
52 LLVEC_DUALARG_OP(div,  /=, float32);
53 
54 // set
55 
UArray_round(UArray * self)56 void UArray_round(UArray *self)
57 {
58 	UARRAY_FOREACHASSIGN(self, i, v, floor((double)(v+.5)));
59 }
60 
UArray_clear(UArray * self)61 void UArray_clear(UArray *self)
62 {
63 	UARRAY_FOREACHASSIGN_VALUE_UNUSED(self, i, 0);
64 }
65 
UArray_setItemsToLong_(UArray * self,long x)66 void UArray_setItemsToLong_(UArray *self, long x)
67 {
68 	UARRAY_FOREACHASSIGN_VALUE_UNUSED(self, i, x);
69 }
70 
UArray_setItemsToDouble_(UArray * self,double x)71 void UArray_setItemsToDouble_(UArray *self, double x)
72 {
73 	UARRAY_FOREACHASSIGN_VALUE_UNUSED(self, i, x);
74 }
75 
UArray_rangeFill(UArray * self)76 void UArray_rangeFill(UArray *self)
77 {
78 	UARRAY_FOREACHASSIGN_VALUE_UNUSED(self, i, i);
79 }
80 
UArray_negate(const UArray * self)81 void UArray_negate(const UArray *self)
82 {
83 	if(UArray_isSignedType(self))
84 	{
85 		UARRAY_FOREACHASSIGN(self, i, v, -v);
86 	}
87 	else
88 	{
89 		UArray_error_(self, "UArray_negate not supported on this type");
90 	}
91 }
92 
93 // basic vector math
94 
UArray_add_(UArray * self,const UArray * other)95 void UArray_add_(UArray *self, const UArray *other)
96 {
97 	if (self->itemType == CTYPE_float32_t && other->itemType == CTYPE_float32_t)
98 	{
99 		vfloat32_add((float32_t *)self->data, (float32_t *)other->data, UArray_minSizeWith_(self, other));
100 		return;
101 	}
102 
103 	DUARRAY_OP(UARRAY_BASICOP_TYPES, +=, self, other);
104 }
105 
UArray_subtract_(UArray * self,const UArray * other)106 void UArray_subtract_(UArray *self, const UArray *other)
107 {
108 	if (self->itemType == CTYPE_float32_t && other->itemType == CTYPE_float32_t)
109 	{
110 		vfloat32_sub((float32_t *)self->data, (float32_t *)other->data, UArray_minSizeWith_(self, other));
111 		return;
112 	}
113 
114 	DUARRAY_OP(UARRAY_BASICOP_TYPES, -=, self, other);
115 }
116 
UArray_multiply_(UArray * self,const UArray * other)117 void UArray_multiply_(UArray *self, const UArray *other)
118 {
119 	if (self->itemType == CTYPE_float32_t && other->itemType == CTYPE_float32_t)
120 	{
121 		vfloat32_mult((float32_t *)self->data, (float32_t *)other->data, UArray_minSizeWith_(self, other));
122 		return;
123 	}
124 
125 	DUARRAY_OP(UARRAY_BASICOP_TYPES, *=, self, other);
126 }
127 
UArray_divide_(UArray * self,const UArray * other)128 void UArray_divide_(UArray *self, const UArray *other)
129 {
130 	if (self->itemType == CTYPE_float32_t && other->itemType == CTYPE_float32_t)
131 	{
132 		vfloat32_div((float32_t *)self->data, (float32_t *)other->data, UArray_minSizeWith_(self, other));
133 		return;
134 	}
135 
136 	DUARRAY_OP(UARRAY_BASICOP_TYPES, /=, self, other);
137 }
138 
UArray_power_(UArray * self,const UArray * other)139 void UArray_power_(UArray *self, const UArray *other)
140 {
141 /*
142 	if (self->itemType == CTYPE_float32_t && other->itemType == CTYPE_float32_t)
143 	{
144 		vfloat32_div((float32_t *)self->data, (float32_t *)other->data, UArray_minSizeWith_(self, other));
145 		return;
146 	}
147 */
148 	DUARRAY_OP(UARRAY_FUNCTION_TYPES, pow, self, other);
149 }
150 
151 #define UARRAY_DOT(OP2, TYPE1, self, TYPE2, other)\
152 {\
153 	double p = 0;\
154 	size_t i, minSize = self->size < other->size ? self->size : other->size;\
155 	for(i = 0; i < minSize; i ++)\
156 	{ p += ((TYPE1 *)self->data)[i] * ((TYPE2 *)other->data)[i]; }\
157 	return p; \
158 }
159 
160 
UArray_dotProduct_(const UArray * self,const UArray * other)161 double UArray_dotProduct_(const UArray *self, const UArray *other)
162 {
163 	DUARRAY_OP(UARRAY_DOT, NULL, self, other);
164 	return 0; // to keep compiler from annoying us
165 }
166 
167 // basic scalar math
168 
UArray_addScalarDouble_(UArray * self,double value)169 void UArray_addScalarDouble_(UArray *self, double value)
170 {
171 	UARRAY_FOREACHASSIGN(self, i, v, v + value);
172 }
173 
UArray_subtractScalarDouble_(UArray * self,double value)174 void UArray_subtractScalarDouble_(UArray *self, double value)
175 {
176 	UARRAY_FOREACHASSIGN(self, i, v, v - value);
177 }
178 
UArray_multiplyScalarDouble_(UArray * self,double value)179 void UArray_multiplyScalarDouble_(UArray *self, double value)
180 {
181 	UARRAY_FOREACHASSIGN(self, i, v, v * value);
182 }
183 
UArray_divideScalarDouble_(UArray * self,double value)184 void UArray_divideScalarDouble_(UArray *self, double value)
185 {
186 	UARRAY_FOREACHASSIGN(self, i, v, v / value);
187 }
188 
UArray_powerScalarDouble_(UArray * self,double value)189 void UArray_powerScalarDouble_(UArray *self, double value)
190 {
191 	UARRAY_FOREACHASSIGN(self, i, v, pow(v, value));
192 }
193 
194 // bitwise
195 
UArray_bitwiseOr_(UArray * self,const UArray * other)196 void UArray_bitwiseOr_(UArray *self, const UArray *other)
197 {
198 	size_t i, max = UArray_minSizeInBytesWith_(self, other);
199 	uint8_t *d1 = self->data;
200 	uint8_t *d2 = other->data;
201 	for (i = 0; i < max; i ++) { d1[i] |= d2[i]; }
202 }
203 
UArray_bitwiseAnd_(UArray * self,const UArray * other)204 void UArray_bitwiseAnd_(UArray *self, const UArray *other)
205 {
206 	size_t i, max = UArray_minSizeInBytesWith_(self, other);
207 	uint8_t *d1 = self->data;
208 	uint8_t *d2 = other->data;
209 	for (i = 0; i < max; i ++) { d1[i] &= d2[i]; }
210 }
211 
UArray_bitwiseXor_(UArray * self,const UArray * other)212 void UArray_bitwiseXor_(UArray *self, const UArray *other)
213 {
214 	size_t i, max = UArray_minSizeInBytesWith_(self, other);
215 	uint8_t *d1 = self->data;
216 	uint8_t *d2 = other->data;
217 	for (i = 0; i < max; i ++) { d1[i] ^= d2[i]; }
218 }
219 
UArray_bitwiseNot(UArray * self)220 void UArray_bitwiseNot(UArray *self)
221 {
222 	size_t i, max = UArray_sizeInBytes(self);
223 	uint8_t *data = self->data;
224 	for (i = 0; i < max; i ++) { data[i] = ~(data[i]); }
225 }
226 
227 // bitwise ops
228 
UArray_setAllBitsTo_(UArray * self,uint8_t aBool)229 void UArray_setAllBitsTo_(UArray *self, uint8_t aBool)
230 {
231 	size_t i, max = UArray_sizeInBytes(self);
232 	uint8_t *data = self->data;
233 	uint8_t bits = aBool ? ~0 : 0;
234 	for (i = 0; i < max; i ++) { data[i] = bits; }
235 }
236 
237 // adjust for endianess?
238 
UArray_bitAt_(UArray * self,size_t i)239 int UArray_bitAt_(UArray *self, size_t i)
240 {
241 	size_t bytePos = i / 8;
242 	size_t bitPos  = i % 8;
243 	if (bytePos >= UArray_sizeInBytes(self)) return 0;
244 	return (self->data[bytePos] >> bitPos) & 0x1;
245 }
246 
UArray_byteAt_(UArray * self,size_t i)247 uint8_t UArray_byteAt_(UArray *self, size_t i)
248 {
249 	if (i < UArray_sizeInBytes(self)) return self->data[i];
250 	return 0;
251 }
252 
UArray_setBit_at_(UArray * self,int aBool,size_t i)253 void UArray_setBit_at_(UArray *self, int aBool, size_t i)
254 {
255 	size_t bytePos = i / 8;
256 	size_t bitPos  = i % 8;
257 	uint8_t n = 0x1 << bitPos;
258 	uint8_t b;
259 	if (bytePos >= UArray_sizeInBytes(self)) return;
260 	b = self->data[bytePos];
261 	b ^= n;
262 	if (aBool) b |= (0x1 << bitPos);
263 	self->data[bytePos] = b;
264 }
265 
UArray_asBits(const UArray * self)266 UArray *UArray_asBits(const UArray *self)
267 {
268 	UArray *out = UArray_new();
269 	size_t i, max = UArray_sizeInBytes(self);
270 	uint8_t *data = self->data;
271 
272 	for (i = 0; i < max; i ++)
273 	{
274 		uint8_t b = data[i];
275 		int j;
276 
277 		for (j = 0; j < 8; j ++)
278 		{
279 			int v = (b >> j) & 0x1;
280 			UArray_appendCString_(out, v ? "1" : "0");
281 		}
282 	}
283 
284 	return out;
285 }
286 
UArray_bitCount(UArray * self)287 size_t UArray_bitCount(UArray *self)
288 {
289 	const unsigned char map[] =
290 	{
291 		0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
292 		1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
293 		1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
294 		2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
295 		1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
296 		2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
297 		2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
298 		3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
299 		1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
300 		2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
301 		2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
302 		3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
303 		2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
304 		3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
305 		3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
306 		4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
307 	};
308 
309 	size_t i, max = UArray_sizeInBytes(self);
310 	uint8_t *data = self->data;
311 	size_t total = 0;
312 
313 	for (i = 0; i < max; i ++) { total += map[data[i]]; }
314 
315 	return total;
316 }
317 
318 // logic
319 
320 #define UARRAY_LOGICOP_TYPES(OP2, TYPE1, self, TYPE2, other)\
321 {\
322 	size_t i, minSize = self->size < other->size ? self->size : other->size;\
323 	for(i = 0; i < minSize; i ++)\
324 	{\
325 		((TYPE1 *)self->data)[i] = ((TYPE1 *)self->data)[i] OP2 (TYPE1)((TYPE2 *)other->data)[i];\
326 	}\
327 }
328 
UArray_logicalOr_(UArray * self,const UArray * other)329 void UArray_logicalOr_(UArray *self, const UArray *other)
330 {
331 	DUARRAY_INTOP(UARRAY_LOGICOP_TYPES, ||, self, other);
332 }
333 
UArray_logicalAnd_(UArray * self,const UArray * other)334 void UArray_logicalAnd_(UArray *self, const UArray *other)
335 {
336 	DUARRAY_INTOP(UARRAY_LOGICOP_TYPES, &&, self, other);
337 }
338 
339 // trigonometry
340 
341 #define UARRAY_DOP(OP) \
342 void UArray_ ## OP (UArray *self) { UARRAY_FOREACHASSIGN(self, i, v, OP((double)v)); }
343 
344 UARRAY_DOP(sin);
345 UARRAY_DOP(cos);
346 UARRAY_DOP(tan);
347 UARRAY_DOP(asin);
348 UARRAY_DOP(acos);
349 UARRAY_DOP(atan);
350 UARRAY_DOP(sinh);
351 UARRAY_DOP(cosh);
352 UARRAY_DOP(tanh);
353 UARRAY_DOP(exp);
354 UARRAY_DOP(log);
355 UARRAY_DOP(log10);
356 
357 UARRAY_DOP(sqrt);
358 UARRAY_DOP(ceil);
359 UARRAY_DOP(floor);
360 UARRAY_DOP(fabs);
361 
UArray_abs(UArray * self)362 void UArray_abs(UArray *self)
363 {
364 	UArray_fabs(self);
365 }
366 
UArray_square(UArray * self)367 void UArray_square(UArray *self)
368 {
369 	UArray_multiply_(self, self);
370 }
371 
372 // extras
373 
UArray_sumAsDouble(const UArray * self)374 double UArray_sumAsDouble(const UArray *self)
375 {
376 	double sum = 0;
377 	UARRAY_FOREACH(self, i, v, sum += v);
378 	return sum;
379 }
380 
UArray_productAsDouble(const UArray * self)381 double UArray_productAsDouble(const UArray *self)
382 {
383 	double p = 1;
384 	UARRAY_FOREACH(self, i, v, p *= v);
385 	return p;
386 }
387 
UArray_arithmeticMeanAsDouble(const UArray * self)388 double UArray_arithmeticMeanAsDouble(const UArray *self)
389 {
390 	return UArray_sumAsDouble(self) / ((double)self->size);
391 }
392 
UArray_arithmeticMeanSquareAsDouble(const UArray * self)393 double UArray_arithmeticMeanSquareAsDouble(const UArray *self)
394 {
395 	double r;
396 	UArray *s = UArray_clone(self);
397 	UArray_square(s);
398 	r = UArray_arithmeticMeanAsDouble(s);
399 	UArray_free(s);
400 	return r;
401 }
402 
UArray_maxAsDouble(const UArray * self)403 double UArray_maxAsDouble(const UArray *self)
404 {
405 	if(self->size > 0)
406 	{
407 		double max = DBL_MIN;
408 		UARRAY_FOREACH(self, i, v, if(v > max) { max = v; });
409 		return max;
410 	}
411 
412 	return 0;
413 }
414 
UArray_minAsDouble(const UArray * self)415 double UArray_minAsDouble(const UArray *self)
416 {
417 	if(self->size > 0)
418 	{
419 		double max = DBL_MAX;
420 		UARRAY_FOREACH(self, i, v, if(v < max) { max = v; });
421 		return max;
422 	}
423 
424 	return 0;
425 }
426 
UArray_Max(UArray * self,const UArray * other)427 BASEKIT_API void UArray_Max(UArray *self, const UArray *other)
428 {
429 	size_t i, minSize = self->size < other->size ? self->size : other->size;
430 
431 	for(i = 0; i < minSize; i ++)
432 	{
433 		double v1 = UArray_rawDoubleAt_(self, i);
434 		double v2 = UArray_rawDoubleAt_(other, i);
435 		double m = v1 > v2 ? v1 : v2;
436 		UArray_at_putDouble_(self, i, m);
437 	}
438 }
439 
UArray_Min(UArray * self,const UArray * other)440 BASEKIT_API void UArray_Min(UArray *self, const UArray *other)
441 {
442 	size_t i, minSize = self->size < other->size ? self->size : other->size;
443 
444 	for(i = 0; i < minSize; i ++)
445 	{
446 		double v1 = UArray_rawDoubleAt_(self, i);
447 		double v2 = UArray_rawDoubleAt_(other, i);
448 		double m = v1 < v2 ? v1 : v2;
449 		UArray_at_putDouble_(self, i, m);
450 	}
451 }
452 
453 
UArray_normalize(UArray * self)454 void UArray_normalize(UArray *self)
455 {
456 	double a;
457 	UArray *s = UArray_clone(self);
458 	UArray_square(s);
459 	a = UArray_sumAsDouble(s);
460 	UArray_free(s);
461 	a = sqrt(a);
462 	//double max = UArray_maxAsDouble(self);
463 	UArray_divideScalarDouble_(self, a);
464 }
465 
UArray_crossProduct_(UArray * self,const UArray * other)466 void UArray_crossProduct_(UArray *self, const UArray *other)
467 {
468 	if (self->itemType == CTYPE_float32_t &&
469 		other->itemType == CTYPE_float32_t &&
470 		self->size > 2 && other->size > 2)
471 	{
472 		float32_t *a = (float32_t *)self->data;
473 		float32_t *b = (float32_t *)other->data;
474 
475 		float32_t i = (a[1]*b[2]) - (a[2]*b[1]);
476 		float32_t j = (a[2]*b[0]) - (a[0]*b[2]);
477 		float32_t k = (a[0]*b[1]) - (a[1]*b[0]);
478 
479 		a[0] = i;
480 		a[1] = j;
481 		a[2] = k;
482 
483 		UArray_changed(self);
484 
485 		return;
486 	}
487 }
488 
UArray_distanceTo_(const UArray * self,const UArray * other)489 double UArray_distanceTo_(const UArray *self, const UArray *other)
490 {
491 	if (self->itemType == CTYPE_float32_t &&
492 		other->itemType == CTYPE_float32_t)
493 	{
494 		float32_t *a = (float32_t *)self->data;
495 		float32_t *b = (float32_t *)other->data;
496 		size_t max = self->size > other->size ? self->size : other->size;
497 		double sum = 0;
498 
499 		if (self->size == other->size)
500 		{
501 			size_t i;
502 
503 			for (i = 0; i < max; i ++)
504 			{
505 				float32_t d = a[i] - b[i];
506 				sum += d * d;
507 			}
508 		}
509 
510 		return (double)sqrt((double)sum);
511 	}
512 	else if (self->itemType == CTYPE_float64_t &&
513 		other->itemType == CTYPE_float64_t)
514 	{
515 		float64_t *a = (float64_t *)self->data;
516 		float64_t *b = (float64_t *)other->data;
517 		size_t max = self->size > other->size ? self->size : other->size;
518 		double sum = 0;
519 
520 		if (self->size == other->size)
521 		{
522 			size_t i;
523 
524 			for (i = 0; i < max; i ++)
525 			{
526 				float32_t d = a[i] - b[i];
527 				sum += d * d;
528 			}
529 		}
530 
531 		return (double)sqrt((double)sum);
532 	}
533 
534 	return 0;
535 }
536 
537 // hash
538 
UArray_changed(UArray * self)539 void UArray_changed(UArray *self)
540 {
541 	self->evenHash = 0;
542 	self->oddHash = 0;
543 }
544 
545 #include "Hash_fnv.h"
546 #include "Hash_superfast.h"
547 #include "Hash_murmur.h"
548 
UArray_superfastHash(UArray * self)549 uintptr_t UArray_superfastHash(UArray *self)
550 {
551 	return SuperFastHash((char *)(self->data), (int)UArray_sizeInBytes(self));
552 }
553 
UArray_fnvHash(UArray * self)554 uintptr_t UArray_fnvHash(UArray *self)
555 {
556 	return (uintptr_t)fnv_32_buf((void *)(self->data), UArray_sizeInBytes(self), FNV1_32_INIT) << 1; // ensures odd result
557 }
558 
UArray_murmurHash(UArray * self)559 uintptr_t UArray_murmurHash(UArray *self)
560 {
561 	return (uintptr_t)MurmurHash2((const void *)(self->data), (int)UArray_sizeInBytes(self), 0);
562 }
563 
564 // even/odd hashes for cuckoo hashtables
565 
UArray_calcOddHash(UArray * self)566 uintptr_t UArray_calcOddHash(UArray *self)
567 {
568 	return UArray_superfastHash(self) | 0x1; // ensures odd result
569 }
570 
UArray_calcEvenHash(UArray * self)571 uintptr_t UArray_calcEvenHash(UArray *self)
572 {
573 	return UArray_fnvHash(self) << 1; // ensures odd result
574 }
575 
576 // Caching even/odd hashes for cuckoo hashtables
577 
UArray_oddHash(UArray * self)578 uintptr_t UArray_oddHash(UArray *self)
579 {
580 	if (!self->oddHash)
581 	{
582 		self->oddHash = UArray_calcOddHash(self);
583 	}
584 
585 	return self->oddHash;
586 }
587 
UArray_evenHash(UArray * self)588 uintptr_t UArray_evenHash(UArray *self)
589 {
590 	if (!self->evenHash)
591 	{
592 		self->evenHash = UArray_calcEvenHash(self);
593 	}
594 
595 	return self->evenHash;
596 }
597 
UArray_equalsWithHashCheck_(UArray * self,UArray * other)598 int UArray_equalsWithHashCheck_(UArray *self, UArray *other)
599 {
600 	if (self == other)
601 	{
602 		return 1;
603 	}
604 	else
605 	{
606 		if (UArray_evenHash(self) != UArray_evenHash(other))
607 		{
608 			return 0;
609 		}
610 
611 		if (UArray_oddHash(self) != UArray_oddHash(other))
612 		{
613 			return 0;
614 		}
615 		/*
616 		if(strcmp(self->data, other->data) != 0)
617 		{
618 			printf("[%s] %i == %i [%s]\n", self->data, h1, h2, other->data);
619 		}
620 		*/
621 	}
622 
623 	return UArray_equals_(self, other);
624 }
625 
626 // indexes
627 
UArray_duplicateIndexes(UArray * self)628 BASEKIT_API void UArray_duplicateIndexes(UArray *self)
629 {
630 	size_t size = self->size;
631 	int itemSize = self->itemSize;
632 
633 	if (size)
634 	{
635 		size_t si = size - 1;
636 		size_t di = (size * 2) - 1;
637 		uint8_t *b;
638 
639 		UArray_setSize_(self, self->size * 2);
640 
641 		b = self->data;
642 
643 		for (;;)
644 		{
645 			uint8_t *src  = b + si * itemSize;
646 			uint8_t *dest = b + di * itemSize;
647 
648 			memcpy(dest, src, itemSize);
649 			memcpy(dest - itemSize, src, itemSize);
650 
651 			if (si == 0) break;
652 			di = di - 2;
653 			si --;
654 		}
655 	}
656 }
657 
UArray_removeOddIndexes(UArray * self)658 void UArray_removeOddIndexes(UArray *self)
659 {
660 	size_t itemSize = self->itemSize;
661 	size_t di = 1;
662 	size_t si = 2;
663 	size_t max = self->size;
664 	uint8_t *b = self->data;
665 
666 	if (max == 0)
667 	{
668 		return;
669 	}
670 
671 	while (si < max)
672 	{
673 		uint8_t *src  = b + (si * itemSize);
674 		uint8_t *dest = b + (di * itemSize);
675 		memcpy(dest, src, itemSize);
676 		si = si + 2;
677 		di = di + 1;
678 	}
679 
680 	UArray_setSize_(self, di);
681 }
682 
UArray_removeEvenIndexes(UArray * self)683 void UArray_removeEvenIndexes(UArray *self)
684 {
685 	size_t itemSize = self->itemSize;
686 	size_t di = 0;
687 	size_t si = 1;
688 	size_t max = self->size;
689 	uint8_t *b = self->data;
690 
691 	while (si < max)
692 	{
693 		uint8_t *src  = b + (si * itemSize);
694 		uint8_t *dest = b + (di * itemSize);
695 		memcpy(dest, src, itemSize);
696 		si = si + 2;
697 		di = di + 1;
698 	}
699 
700 	UArray_setSize_(self, di);
701 }
702 
UArray_reverseItemByteOrders(UArray * self)703 void UArray_reverseItemByteOrders(UArray *self)
704 {
705 	size_t itemSize = self->itemSize;
706 
707 	if (itemSize > 1)
708 	{
709 		size_t i, max = self->size;
710 		uint8_t *d = self->data;
711 
712 		for(i = 0; i < max; i ++)
713 		{
714 			size_t j;
715 
716 			for(j = 0; j < itemSize; j ++)
717 			{
718 				size_t i1 = i + j;
719 				size_t i2 = i + itemSize - j;
720 				uint8_t v = d[i1];
721 				d[i1] = d[i2];
722 				d[i2] = v;
723 			}
724 		}
725 
726 		UArray_changed(self);
727 	}
728 }
729 
730 //
UArray_addEqualsOffsetXScaleYScale(UArray * self,UArray * other,float offset,float xscale,float yscale)731 void UArray_addEqualsOffsetXScaleYScale(UArray *self, UArray *other, float offset, float xscale, float yscale)
732 {
733 	if (self->itemType == CTYPE_float32_t && other->itemType == CTYPE_float32_t)
734 	{
735 		float32_t *d1 = (float32_t *)self->data;
736 		float32_t *d2 = (float32_t *)other->data;
737 
738 		long i = offset;
739 		long j = 0;
740 
741 		while (i < (long)self->size)
742 		{
743 			size_t jj = j/xscale;
744 
745 			//printf("self->size: %i i: %i jj: %i\n", self->size, i, jj);
746 			if (jj > other->size - 1) break;
747 
748 			if (i >= 0) //&& jj < other->size - 1)
749 			{
750 				d1[i] += d2[jj] * yscale;
751 			}
752 
753 			j ++;
754 			i ++;
755 		}
756 
757 		UArray_changed(self);
758 	}
759 	else
760 	{
761 		printf("UArray_addEqualsOffsetXScaleYScale called on non float array\n");
762 		exit(-1);
763 	}
764 }
765 
766