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