1 /*****************************************************************************
2  *
3  * Copyright (c) 2008-2010, CoreCodec, Inc.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *     * Redistributions of source code must retain the above copyright
9  *       notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above copyright
11  *       notice, this list of conditions and the following disclaimer in the
12  *       documentation and/or other materials provided with the distribution.
13  *     * Neither the name of CoreCodec, Inc. nor the
14  *       names of its contributors may be used to endorse or promote products
15  *       derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY CoreCodec, Inc. ``AS IS'' AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL CoreCodec, Inc. BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  ****************************************************************************/
29 
30 #include "array.h"
31 
32 typedef struct datahead
33 {
34     size_t Size;
35 
36 } datahead;
37 
38 #define Data_Head(Name)         ((datahead*)(Name)-1)
39 #define Data_HeapHead(Name)     ((dataheaphead*)(Name)-1)
40 #define Data_IsHeap(Name)       (Data_Head(Name)->Size & DATA_FLAG_HEAP)
41 #define Data_IsMemHeap(Name)    (Data_Head(Name)->Size & DATA_FLAG_MEMHEAP)
42 #define Data_GetSize(Name)      (Data_Head(Name)->Size & ~(DATA_FLAG_HEAP|DATA_FLAG_MEMHEAP))
43 
Data_Size(const uint8_t * a)44 size_t Data_Size(const uint8_t* a)
45 {
46     if (!a) return 0;
47     return Data_GetSize(a);
48 }
49 
Data_ReAlloc(uint8_t ** a,size_t n)50 NOINLINE bool_t Data_ReAlloc(uint8_t** a,size_t n)
51 {
52     uint8_t* p = *a;
53     size_t oldsize;
54 
55     if (p)
56     {
57         if (!Data_Head(p)->Size) // const?
58             return 0;
59         oldsize = Data_GetSize(p);
60     }
61     else
62         oldsize = 0;
63 
64     if (oldsize<n)
65     {
66         if (p && Data_IsMemHeap(p))
67         {
68             const cc_memheap* Heap = Data_HeapHead(p)->Heap;
69             dataheaphead* Head;
70             if (!oldsize)
71                 Head = MemHeap_Alloc(Heap,n+sizeof(dataheaphead),0);
72             else
73                 Head = MemHeap_ReAlloc(Heap,Data_HeapHead(p),oldsize+sizeof(dataheaphead),n+sizeof(dataheaphead));
74             if (!Head)
75                 return 0;
76 
77             Head->Heap = Heap;
78             Head->Size = n|DATA_FLAG_HEAP|DATA_FLAG_MEMHEAP;
79             *a = (uint8_t*)(Head+1);
80         }
81         else
82         {
83             datahead* Head;
84             if (!p || !Data_IsHeap(p))
85             {
86                 uint8_t* old = p;
87                 Head = malloc(n+sizeof(datahead));
88                 if (Head && old)
89                     memcpy(Head+1,old,oldsize);
90             }
91             else
92                 Head = realloc(Data_Head(p),n+sizeof(datahead));
93 
94             if (!Head)
95                 return 0;
96 
97             Head->Size = n|DATA_FLAG_HEAP;
98             *a = (uint8_t*)(Head+1);
99         }
100     }
101     return 1;
102 }
103 
Data_Release(uint8_t ** a)104 NOINLINE void Data_Release(uint8_t** a)
105 {
106     uint8_t* p = *a;
107     if (p)
108     {
109         *a = NULL;
110         if (Data_IsHeap(p))
111         {
112             if (Data_IsMemHeap(p))
113             {
114                 if (Data_GetSize(p))
115                     MemHeap_Free(Data_HeapHead(p)->Heap,Data_HeapHead(p),Data_GetSize(p)+sizeof(dataheaphead));
116             }
117             else
118                 free(Data_Head(p));
119         }
120     }
121 }
122 
Data_Clear(uint8_t ** a)123 NOINLINE void Data_Clear(uint8_t** a)
124 {
125     uint8_t* p = *a;
126     if (p && Data_IsMemHeap(p))
127     {
128         p = MemHeap_Null(Data_HeapHead(p)->Heap);
129         Data_Release(a);
130         *a = p;
131     }
132     else
133         Data_Release(a);
134 }
135 
Data_Set(uint8_t ** a,const uint8_t * b,size_t pos,size_t len)136 bool_t Data_Set(uint8_t** a,const uint8_t* b,size_t pos,size_t len)
137 {
138     if (!Data_ReAlloc(a,pos+len))
139         return 0;
140 
141     memcpy(*a+pos,b,len);
142     return 1;
143 }
144 
ArraySize(const array * p)145 size_t ArraySize(const array*p)
146 {
147     return p->_End-p->_Begin;
148 }
149 
ArrayInitEx(array * p,const cc_memheap * Heap)150 void ArrayInitEx(array* p,const cc_memheap* Heap)
151 {
152     p->_Begin = p->_End = Heap ? MemHeap_Null(Heap):NULL;
153 }
154 
ArrayClear(array * p)155 NOINLINE void ArrayClear(array* p)
156 {
157 	Data_Clear(&p->_Begin);
158 	p->_End = p->_Begin;
159 }
160 
ArrayDrop(array * p)161 void ArrayDrop(array* p)
162 {
163 	p->_End = p->_Begin;
164 }
165 
SizeAlign(size_t Total,size_t Align)166 static size_t SizeAlign(size_t Total, size_t Align)
167 {
168     if (!Align)
169     {
170         for (Align=16;Align<16384;Align<<=1)
171             if (Align*8 > Total)
172                 break;
173     }
174     --Align;
175 	return (Total + Align) & ~Align;
176 }
177 
ArrayAlloc(array * p,size_t Total,size_t Align)178 bool_t ArrayAlloc(array* p,size_t Total,size_t Align)
179 {
180     size_t Size = ArraySize(p);
181     if (!Data_ReAlloc(&p->_Begin,SizeAlign(Total,Align)))
182         return 0;
183 	p->_End = p->_Begin + Size;
184 	return 1;
185 }
186 
ArrayShrink(array * p,size_t Length)187 void ArrayShrink(array* p, size_t Length)
188 {
189     p->_End -= Length;
190     if (p->_End < p->_Begin)
191         p->_End = p->_Begin;
192 }
193 
ArrayInsert(array * p,size_t Ofs,const void * Ptr,size_t Width,size_t Align)194 bool_t ArrayInsert(array* p, size_t Ofs, const void* Ptr, size_t Width, size_t Align)
195 {
196 	if (!ArrayAppend(p,NULL,Width,Align))
197 		return 0;
198 	memmove(p->_Begin+Ofs+Width,p->_Begin+Ofs,(p->_End-p->_Begin)-Width-Ofs);
199     if (Ptr)
200         memcpy(p->_Begin+Ofs,Ptr,Width);
201     return 1;
202 }
203 
ArrayDelete(array * p,size_t Ofs,size_t Width)204 void ArrayDelete(array* p, size_t Ofs, size_t Width)
205 {
206 	memmove(p->_Begin+Ofs,p->_Begin+Ofs+Width,(p->_End-p->_Begin)-Width-Ofs);
207 	p->_End -= Width;
208 }
209 
ArrayAppendStr(array * p,const tchar_t * Ptr,bool_t Merge,size_t Align)210 bool_t ArrayAppendStr(array* p, const tchar_t* Ptr, bool_t Merge, size_t Align)
211 {
212     if (Ptr && (Ptr[0] || !Merge))
213     {
214         if (Merge && !ARRAYEMPTY(*p) && ARRAYEND(*p,tchar_t)[-1]==0)
215             ArrayShrink(p,sizeof(tchar_t));
216 
217         return ArrayAppend(p,Ptr,(tcslen(Ptr)+1)*sizeof(tchar_t),Align);
218     }
219     return 1;
220 }
221 
ArrayAppend(array * p,const void * Ptr,size_t Length,size_t Align)222 bool_t ArrayAppend(array* p, const void* Ptr, size_t Length, size_t Align)
223 {
224 	size_t Total = p->_End - p->_Begin + Length;
225 	if (Total > Data_Size(p->_Begin) && !ArrayAlloc(p,Total,Align))
226 		return 0;
227 	if (Ptr)
228 		memcpy(p->_End,Ptr,Length);
229 	p->_End += Length;
230 	return 1;
231 }
232 
ArrayEq(const array * a,const array * b)233 bool_t ArrayEq(const array* a, const array* b)
234 {
235     size_t an = a ? ArraySize(a):0;
236     size_t bn = b ? ArraySize(b):0;
237     return an == bn && (!an || memcmp(ARRAYBEGIN(*a,uint8_t),ARRAYBEGIN(*b,uint8_t),an)==0);
238 }
239 
ArrayCopy(array * p,const array * q)240 bool_t ArrayCopy(array* p, const array* q)
241 {
242     size_t Size = ArraySize(q);
243     if (!ArrayResize(p,Size,0))
244         return 0;
245     memcpy(ARRAYBEGIN(*p,uint8_t),ARRAYBEGIN(*q,uint8_t),Size);
246     return 1;
247 }
248 
ArrayResize(array * p,size_t Total,size_t Align)249 bool_t ArrayResize(array* p,size_t Total, size_t Align)
250 {
251     if (Total > Data_Size(p->_Begin) && !ArrayAlloc(p,Total,Align))
252         return 0;
253     p->_End = p->_Begin + Total;
254     return 1;
255 }
256 
ArrayZero(array * p)257 void ArrayZero(array* p)
258 {
259     memset(p->_Begin,0,p->_End-p->_Begin);
260 }
261 
262 #define QSORTMINLEN 16
263 
InQSortSwap(uint_fast32_t * a,uint_fast32_t * b)264 static INLINE void InQSortSwap(uint_fast32_t* a, uint_fast32_t* b)
265 {
266     uint_fast32_t t = *a;
267     *a = *b;
268     *b = t;
269 }
270 
InQSort(uint_fast32_t * First,uint_fast32_t * Last,arraycmp Cmp,const void * CmpParam)271 static NOINLINE void InQSort(uint_fast32_t* First, uint_fast32_t* Last, arraycmp Cmp, const void* CmpParam)
272 {
273 	while (Last > First + QSORTMINLEN)
274 	{
275         uint_fast32_t* Mid = First + ((Last - First)>>1);
276         uint_fast32_t* Ref = First;
277         uint_fast32_t* Left;
278         uint_fast32_t* Right;
279 
280 		if (Cmp(CmpParam,First,Last) < 0)
281 		{
282 			if (Cmp(CmpParam,Last,Mid) < 0)
283 				Ref = Last;
284 			else
285 			if (Cmp(CmpParam,First,Mid) < 0)
286 				Ref = Mid;
287 		}
288 		else
289 		if (Cmp(CmpParam,First,Mid) >= 0)
290 		{
291 			if (Cmp(CmpParam,Last,Mid) < 0)
292 				Ref = Mid;
293 			else
294 				Ref = Last;
295 		}
296 
297 		if (Ref != First)
298             InQSortSwap(First,Ref);
299 
300 		Left = First;
301 		Right = Last+1;
302 
303 		for (;;)
304 		{
305 			while (++Left < Last && Cmp(CmpParam,First,Left) > 0) {}
306 
307 			while (Cmp(CmpParam,First,--Right) < 0) {}
308 
309 			if (Left >= Right)
310 				break;
311 
312 			InQSortSwap(Left,Right);
313 		}
314 
315 		if (Right == First)
316         {
317 			++First;
318         }
319 		else
320 		{
321 			InQSortSwap(First,Right);
322 
323 			--Right;
324 
325 			if (Right - First < Last - Left)
326 			{
327 				if (Right > QSORTMINLEN + First)
328 					InQSort(First,Right,Cmp,CmpParam);
329 				First = Left;
330 			}
331 			else
332             {
333 				if (Last > QSORTMINLEN + Left)
334 					InQSort(Left,Last,Cmp,CmpParam);
335 				Last = Right;
336 			}
337 		}
338 	}
339 }
340 
ArraySortEx(array * p,size_t Count,size_t Width,arraycmp Cmp,const void * CmpParam,bool_t Unique)341 void ArraySortEx(array* p, size_t Count, size_t Width, arraycmp Cmp, const void* CmpParam, bool_t Unique)
342 {
343     if (Count == ARRAY_AUTO_COUNT)
344         Count = ArraySize(p)/Width;
345 
346     if (Count>1)
347     {
348         if (Width == sizeof(uint_fast32_t))
349         {
350             uint_fast32_t* End = ARRAYBEGIN(*p,uint_fast32_t)+Count;
351             uint_fast32_t* i;
352             uint_fast32_t* j;
353 
354 		    InQSort(ARRAYBEGIN(*p,uint_fast32_t), End-1, Cmp, CmpParam);
355 
356             j = ARRAYBEGIN(*p,uint_fast32_t);
357 		    for (i=j+1; i!=End; ++i)
358 		    {
359                 if (Cmp(CmpParam,i,j) < 0)
360                 {
361                     uint_fast32_t Tmp = *i;
362                     do
363                     {
364                         j[1] = j[0];
365                         if (j-- == ARRAYBEGIN(*p,uint_fast32_t))
366                             break;
367                     }
368                     while (Cmp(CmpParam,&Tmp,j) < 0);
369                     j[1] = Tmp;
370                 }
371                 j = i;
372 		    }
373 
374             if (Unique)
375             {
376 		        j = ARRAYBEGIN(*p,uint_fast32_t);
377 		        for (i=j+1; i!=End; ++i)
378 		        {
379 			        if (Cmp(CmpParam,i,j) != 0)
380                         *(++j) = *i;
381 		        }
382 		        p->_End = (uint8_t*)(j+1);
383 	        }
384         }
385         else
386         {
387             // dummy fallback...
388 
389             uint8_t* Tmp = (uint8_t*)alloca(Width);
390             uint8_t* End = p->_Begin + Count*Width;
391             uint8_t* i;
392             uint8_t* j;
393 
394             j = p->_Begin;
395 		    for (i=j+Width; i!=End; i+=Width)
396 		    {
397                 if (Cmp(CmpParam,i,j) < 0)
398                 {
399                     memcpy(Tmp,i,Width);
400                     do
401                     {
402                         memcpy(j+Width,j,Width);
403                         if (j == p->_Begin)
404                         {
405                             j -= Width;
406                             break;
407                         }
408                         j -= Width;
409                     }
410                     while (Cmp(CmpParam,Tmp,j) < 0);
411                     memcpy(j+Width,Tmp,Width);
412                 }
413                 j = i;
414 		    }
415 
416             if (Unique)
417             {
418 		        j = p->_Begin;
419 		        for (i=j+Width; i!=End; i+=Width)
420 		        {
421 			        if (Cmp(CmpParam,i,j) != 0)
422                     {
423                         j += Width;
424                         memcpy(j,i,Width);
425                     }
426 		        }
427 		        p->_End = j+Width;
428 	        }
429         }
430 
431 	}
432 }
433 
ArrayFindEx(const array * p,size_t Count,size_t Width,const void * Data,arraycmp Cmp,const void * CmpParam,bool_t * Found)434 intptr_t ArrayFindEx(const array* p, size_t Count, size_t Width, const void* Data, arraycmp Cmp, const void* CmpParam, bool_t* Found)
435 {
436     if (ARRAYEMPTY(*p))
437     {
438         *Found = 0;
439         return 0;
440     }
441 
442     if (Count == ARRAY_AUTO_COUNT)
443     {
444         Count = ArraySize(p)/Width;
445         assert(Count*Width == ArraySize(p));
446     }
447 
448 	if (Cmp)
449 	{
450 		int i;
451 		intptr_t Mid = 0;
452 		intptr_t Lower = 0;
453 		intptr_t Upper = Count-1;
454 
455 		while (Upper >= Lower)
456 		{
457 			Mid = (Upper + Lower) >> 1;
458 
459 			i = Cmp(CmpParam,p->_Begin+Width*Mid,Data);
460 			if (i>0)
461 				Upper = Mid-1;
462 			else if (i<0)
463 				Lower = Mid+1;
464 			else
465 			{
466 				*Found = 1;
467 				return Mid;
468 			}
469 		}
470 
471 		*Found = 0;
472 
473 		if (Upper == Mid - 1)
474 			return Mid;
475 		else
476 			return Lower;
477 	}
478 	else
479 	{
480 		intptr_t No = 0;
481 		const uint8_t* i;
482 		for (i=p->_Begin;Count--;i+=Width,++No)
483 			if (memcmp(i,Data,Width)==0)
484 			{
485 				*Found = 1;
486 				return No;
487 			}
488 
489 		*Found = 0;
490 		return No;
491 	}
492 }
493 
ArrayAddEx(array * p,size_t Count,size_t Width,const void * Data,arraycmp Cmp,const void * CmpParam,size_t Align)494 intptr_t ArrayAddEx(array* p,size_t Count, size_t Width, const void* Data, arraycmp Cmp, const void* CmpParam, size_t Align)
495 {
496 	intptr_t Pos;
497 	bool_t Found;
498 
499 	Pos = ArrayFindEx(p,Count,Width,Data,Cmp,CmpParam,&Found);
500 	if (!Found)
501     {
502         if (!ArrayInsert(p,Width*Pos,Data,Width,Align))
503             return -1;
504     }
505     else
506     	memcpy(p->_Begin+Width*Pos,Data,Width);
507 
508 	return Pos;
509 }
510 
ArrayRemoveEx(array * p,size_t Count,size_t Width,const void * Data,arraycmp Cmp,const void * CmpParam)511 bool_t ArrayRemoveEx(array* p, size_t Count, size_t Width, const void* Data, arraycmp Cmp, const void* CmpParam)
512 {
513 	bool_t Found;
514 	size_t Pos = ArrayFindEx(p,Count,Width,Data,Cmp,CmpParam,&Found);
515 	if (Found)
516         ArrayDelete(p,Pos*Width,Width);
517 	return Found;
518 }
519 
Rand(uint32_t RndSeed)520 static INLINE uint32_t Rand(uint32_t RndSeed)
521 {
522 	return RndSeed*0x8088405U + 0x251001U;
523 }
524 
ArrayRandomize(array * Array,size_t Width,uint32_t RndSeed)525 void ArrayRandomize(array* Array,size_t Width,uint32_t RndSeed)
526 {
527     size_t i,j,Count = ArraySize(Array)/Width;
528     uint8_t *Buf=alloca(Width);
529     for (i=0;i<Count;++i)
530     {
531         RndSeed = Rand(RndSeed);
532         j = RndSeed % Count;
533         memcpy(Buf,ARRAYBEGIN(*Array,uint8_t)+i*Width,Width);
534         memcpy(ARRAYBEGIN(*Array,uint8_t)+i*Width,ARRAYBEGIN(*Array,uint8_t)+j*Width,Width);
535         memcpy(ARRAYBEGIN(*Array,uint8_t)+j*Width,Buf,Width);
536     }
537 }
538 
539 
540 #ifdef TARGET_PALMOS
541 
542 // TODO: move this to base/mem and depend on "mem" platform dependently(?)
543 #include "common.h"
544 // end TODO
545 
ArrayBlockClear(arrayblock * p)546 void ArrayBlockClear(arrayblock* p)
547 {
548 	if (p->Block.Ptr)
549     {
550 		FreeBlock(NULL,&p->Block);
551         p->Array._Begin = NULL;
552         p->Array._End = NULL;
553     }
554     else
555         ArrayClear(&p->Array);
556 }
557 
ArrayBlockLock(arrayblock * p)558 void ArrayBlockLock(arrayblock* p)
559 {
560 	if (!p->Block.Ptr && p->Array._End != p->Array._Begin)
561 	{
562 		size_t n = p->Array._End-p->Array._Begin;
563 		if (AllocBlock(NULL,n,&p->Block,1,HEAP_STORAGE))
564 		{
565 			WriteBlock(&p->Block,0,p->Array._Begin,n);
566 			ArrayClear(&p->Array);
567 			p->Array._Begin = (uint8_t*)p->Block.Ptr;
568 			p->Array._End = p->Array._Begin + n;
569 		}
570 	}
571 }
572 
573 #endif
574 
Fifo_Clear(cc_fifo * p)575 void Fifo_Clear(cc_fifo* p)
576 {
577 	ArrayClear(&p->_Base);
578     p->_Read = NULL;
579 }
580 
Fifo_Alloc(cc_fifo * p,size_t Total,size_t Align)581 bool_t Fifo_Alloc(cc_fifo* p, size_t Total, size_t Align)
582 {
583     size_t n = p->_Read - p->_Base._Begin;
584     if (!ArrayAlloc(&p->_Base,Total,Align))
585         return 0;
586     p->_Read = p->_Base._Begin+n;
587     return 1;
588 }
589 
Fifo_Drop(cc_fifo * p)590 void Fifo_Drop(cc_fifo* p)
591 {
592 	ArrayDrop(&p->_Base);
593 	p->_Read = p->_Base._Begin;
594 }
595 
Fifo_Write(cc_fifo * p,const void * Ptr,size_t Length,size_t Align)596 uint8_t* Fifo_Write(cc_fifo* p, const void* Ptr, size_t Length, size_t Align)
597 {
598     size_t Total = Data_Size(p->_Base._Begin);
599     size_t Read = p->_Read - p->_Base._Begin;
600     size_t End = p->_Base._End - p->_Base._Begin + Length + SAFETAIL;
601     uint8_t* Result;
602 
603     if (End>Total && Read>0)
604     {
605         memmove(p->_Base._Begin,p->_Read,FIFO_SIZE(*p));
606         p->_Read = p->_Base._Begin;
607         p->_Base._End -= Read;
608         End -= Read;
609         Read = 0;
610     }
611 
612     if (End>Total)
613     {
614         if (!ArrayAlloc(&p->_Base,End,Align))
615             return NULL;
616         p->_Read = p->_Base._Begin+Read;
617     }
618 
619     Result = p->_Base._End;
620     p->_Base._End += Length;
621 
622     if (Ptr)
623         memcpy(Result,Ptr,Length);
624     return Result;
625 }
626