xref: /haiku/headers/libs/agg/agg_array.h (revision 4f00613311d0bd6b70fa82ce19931c41f071ea4e)
1 //----------------------------------------------------------------------------
2 // Anti-Grain Geometry - Version 2.2
3 // Copyright (C) 2002-2004 Maxim Shemanarev (http://www.antigrain.com)
4 //
5 // Permission to copy, use, modify, sell and distribute this software
6 // is granted provided this copyright notice appears in all copies.
7 // This software is provided "as is" without express or implied
8 // warranty, and with no claim as to its suitability for any purpose.
9 //
10 //----------------------------------------------------------------------------
11 // Contact: mcseem@antigrain.com
12 //          mcseemagg@yahoo.com
13 //          http://www.antigrain.com
14 //----------------------------------------------------------------------------
15 #ifndef AGG_ARRAY_INCLUDED
16 #define AGG_ARRAY_INCLUDED
17 
18 #include <stddef.h>
19 #include <string.h>
20 #include "agg_basics.h"
21 
22 namespace agg
23 {
24 
25     //---------------------------------------------------------------pod_array
26     // A simple class template to store Plain Old Data, a vector
27     // of a fixed size. The data is continous in memory
28     //------------------------------------------------------------------------
29     template<class T> class pod_array
30     {
31     public:
32         typedef T value_type;
33 
34         ~pod_array() { delete [] m_array; }
35         pod_array() : m_size(0), m_capacity(0), m_array(0) {}
36         pod_array(unsigned cap, unsigned extra_tail=0);
37 
38         // Copying
39         pod_array(const pod_array<T>&);
40         const pod_array<T>& operator = (const pod_array<T>&);
41 
42         unsigned capacity() const { return m_capacity; }
43         void capacity(unsigned cap, unsigned extra_tail=0);
44 
45         void resize(unsigned new_size);
46 
47         void add(const T& v)  { m_array[m_size++] = v; }
48         void inc_size(unsigned size) { m_size += size; }
49         unsigned size()      const { return m_size; }
50         unsigned byte_size() const { return m_size * sizeof(T); }
51         void serialize(int8u* ptr) const;
52         void deserialize(const int8u* data, unsigned byte_size);
53         const T& operator [] (unsigned idx) const { return m_array[idx]; }
54               T& operator [] (unsigned idx)       { return m_array[idx]; }
55 
56         void remove_all()         { m_size = 0; }
57         void cut_at(unsigned num) { if(num < m_size) m_size = num; }
58 
59     private:
60         unsigned m_size;
61         unsigned m_capacity;
62         T*       m_array;
63     };
64 
65     //------------------------------------------------------------------------
66     template<class T>
67     void pod_array<T>::capacity(unsigned cap, unsigned extra_tail)
68     {
69         m_size = 0;
70         if(cap > m_capacity)
71         {
72             delete [] m_array;
73             m_capacity = cap + extra_tail;
74             m_array = m_capacity ? new T [m_capacity] : 0;
75         }
76     }
77 
78     //------------------------------------------------------------------------
79     template<class T>
80     void pod_array<T>::resize(unsigned new_size)
81     {
82         if(new_size > m_size)
83         {
84             if(new_size > m_capacity)
85             {
86                 T* data = new T[new_size];
87                 memcpy(data, m_array, m_size * sizeof(T));
88                 delete [] m_array;
89                 m_array = data;
90             }
91         }
92         else
93         {
94             m_size = new_size;
95         }
96     }
97 
98     //------------------------------------------------------------------------
99     template<class T> pod_array<T>::pod_array(unsigned cap, unsigned extra_tail) :
100         m_size(0), m_capacity(0), m_array(0)
101     {
102         capacity(cap, extra_tail);
103     }
104 
105     //------------------------------------------------------------------------
106     template<class T> pod_array<T>::pod_array(const pod_array<T>& v) :
107         m_size(v.m_size),
108         m_capacity(v.m_capacity),
109         m_array(v.m_capacity ? new T [v.m_capacity] : 0)
110     {
111         memcpy(m_array, v.m_array, sizeof(T) * v.m_size);
112     }
113 
114     //------------------------------------------------------------------------
115     template<class T> const pod_array<T>&
116     pod_array<T>::operator = (const pod_array<T>&v)
117     {
118         capacity(v.m_capacity);
119         if(v.m_size) memcpy(m_array, v.m_array, sizeof(T) * v.m_size);
120         return *this;
121     }
122 
123     //------------------------------------------------------------------------
124     template<class T> void pod_array<T>::serialize(int8u* ptr) const
125     {
126         if(m_size) memcpy(ptr, m_array, m_size * sizeof(T));
127     }
128 
129     //------------------------------------------------------------------------
130     template<class T>
131     void pod_array<T>::deserialize(const int8u* data, unsigned byte_size)
132     {
133         byte_size /= sizeof(T);
134         capacity(byte_size);
135         if(byte_size) memcpy(m_array, data, byte_size * sizeof(T));
136     }
137 
138     //------------------------------------------------------------------------
139     template<class T> class pod_array_adaptor
140     {
141     public:
142         typedef T value_type;
143         pod_array_adaptor(T* array, unsigned size) :
144             m_array(array), m_size(size) {}
145 
146         unsigned size() const { return m_size; }
147         const T& operator [] (unsigned idx) const { return m_array[idx]; }
148               T& operator [] (unsigned idx)       { return m_array[idx]; }
149     private:
150         T*       m_array;
151         unsigned m_size;
152     };
153 
154 
155 
156 
157 
158 
159     //---------------------------------------------------------------pod_deque
160     // A simple class template to store Plain Old Data, similar to std::deque
161     // It doesn't reallocate memory but instead, uses blocks of data of size
162     // of (1 << S), that is, power of two. The data is NOT continuous in memory,
163     // so the only valid access method is operator [] or curr(), prev(), next()
164     //
165     // There reallocs occure only when the pool of pointers to blocks needs
166     // to be extended (it happens very rear). You can control the value
167     // of increment to reallocate the pointer buffer. See the second constructor.
168     // By default, the incremeent value equals (1 << S), i.e., the block size.
169     //------------------------------------------------------------------------
170     template<class T, unsigned S=6> class pod_deque
171     {
172     public:
173         enum
174         {
175             block_shift = S,
176             block_size  = 1 << block_shift,
177             block_mask  = block_size - 1
178         };
179 
180         typedef T value_type;
181 
182         ~pod_deque();
183         pod_deque();
184         pod_deque(unsigned block_ptr_inc);
185 
186         // Copying
187         pod_deque(const pod_deque<T, S>& v);
188         const pod_deque<T, S>& operator = (const pod_deque<T, S>& v);
189 
190         void remove_all() { m_size = 0; }
191         void free_all() { free_tail(0); }
192         void free_tail(unsigned size);
193         void add(const T& val);
194         void modify_last(const T& val);
195         void remove_last();
196 
197         int allocate_continuous_block(unsigned num_elements);
198 
199         void add_array(const T* ptr, unsigned num_elem)
200         {
201             while(num_elem--)
202             {
203                 add(*ptr++);
204             }
205         }
206 
207         template<class DataAccessor> void add_data(DataAccessor& data)
208         {
209             while(data.size())
210             {
211                 add(*data);
212                 ++data;
213             }
214         }
215 
216         void cut_at(unsigned size)
217         {
218             if(size < m_size) m_size = size;
219         }
220 
221         unsigned size() const { return m_size; }
222 
223         const T& operator [] (unsigned idx) const
224         {
225             return m_blocks[idx >> block_shift][idx & block_mask];
226         }
227 
228         T& operator [] (unsigned idx)
229         {
230             return m_blocks[idx >> block_shift][idx & block_mask];
231         }
232 
233         const T& curr(unsigned idx) const
234         {
235             return (*this)[idx];
236         }
237 
238         T& curr(unsigned idx)
239         {
240             return (*this)[idx];
241         }
242 
243         const T& prev(unsigned idx) const
244         {
245             return (*this)[(idx + m_size - 1) % m_size];
246         }
247 
248         T& prev(unsigned idx)
249         {
250             return (*this)[(idx + m_size - 1) % m_size];
251         }
252 
253         const T& next(unsigned idx) const
254         {
255             return (*this)[(idx + 1) % m_size];
256         }
257 
258         T& next(unsigned idx)
259         {
260             return (*this)[(idx + 1) % m_size];
261         }
262 
263         const T& last() const
264         {
265             return (*this)[m_size - 1];
266         }
267 
268         T& last()
269         {
270             return (*this)[m_size - 1];
271         }
272 
273         unsigned byte_size() const;
274         void serialize(int8u* ptr) const;
275         void deserialize(const int8u* data, unsigned byte_size);
276         void deserialize(unsigned start, const T& empty_val,
277                          const int8u* data, unsigned byte_size);
278 
279         template<class ByteAccessor>
280         void deserialize(ByteAccessor data)
281         {
282             remove_all();
283             unsigned elem_size = data.size() / sizeof(T);
284 
285             for(unsigned i = 0; i < elem_size; ++i)
286             {
287                 int8u* ptr = (int8u*)data_ptr();
288                 for(unsigned j = 0; j < sizeof(T); ++j)
289                 {
290                     *ptr++ = *data;
291                     ++data;
292                 }
293                 ++m_size;
294             }
295         }
296 
297         template<class ByteAccessor>
298         void deserialize(unsigned start, const T& empty_val, ByteAccessor data)
299         {
300             while(m_size < start)
301             {
302                 add(empty_val);
303             }
304 
305             unsigned elem_size = data.size() / sizeof(T);
306             for(unsigned i = 0; i < elem_size; ++i)
307             {
308                 int8u* ptr;
309                 if(start + i < m_size)
310                 {
311                     ptr = (int8u*)(&((*this)[start + i]));
312                 }
313                 else
314                 {
315                     ptr = (int8u*)data_ptr();
316                     ++m_size;
317                 }
318                 for(unsigned j = 0; j < sizeof(T); ++j)
319                 {
320                     *ptr++ = *data;
321                     ++data;
322                 }
323             }
324         }
325 
326         const T* block(unsigned nb) const { return m_blocks[nb]; }
327 
328     private:
329         void allocate_block(unsigned nb);
330         T*   data_ptr();
331 
332         unsigned        m_size;
333         unsigned        m_num_blocks;
334         unsigned        m_max_blocks;
335         T**             m_blocks;
336         unsigned        m_block_ptr_inc;
337     };
338 
339 
340     //------------------------------------------------------------------------
341     template<class T, unsigned S> pod_deque<T, S>::~pod_deque()
342     {
343         if(m_num_blocks)
344         {
345             T** blk = m_blocks + m_num_blocks - 1;
346             while(m_num_blocks--)
347             {
348                 delete [] *blk;
349                 --blk;
350             }
351             delete [] m_blocks;
352         }
353     }
354 
355 
356     //------------------------------------------------------------------------
357     template<class T, unsigned S>
358     void pod_deque<T, S>::free_tail(unsigned size)
359     {
360         if(size < m_size)
361         {
362             unsigned nb = (size + block_mask) >> block_shift;
363             while(m_num_blocks > nb)
364             {
365                 delete [] m_blocks[--m_num_blocks];
366             }
367             m_size = size;
368         }
369     }
370 
371 
372     //------------------------------------------------------------------------
373     template<class T, unsigned S> pod_deque<T, S>::pod_deque() :
374         m_size(0),
375         m_num_blocks(0),
376         m_max_blocks(0),
377         m_blocks(0),
378         m_block_ptr_inc(block_size)
379     {
380     }
381 
382 
383     //------------------------------------------------------------------------
384     template<class T, unsigned S>
385     pod_deque<T, S>::pod_deque(unsigned block_ptr_inc) :
386         m_size(0),
387         m_num_blocks(0),
388         m_max_blocks(0),
389         m_blocks(0),
390         m_block_ptr_inc(block_ptr_inc)
391     {
392     }
393 
394 
395     //------------------------------------------------------------------------
396     template<class T, unsigned S>
397     pod_deque<T, S>::pod_deque(const pod_deque<T, S>& v) :
398         m_size(v.m_size),
399         m_num_blocks(v.m_num_blocks),
400         m_max_blocks(v.m_max_blocks),
401         m_blocks(v.m_max_blocks ? new T* [v.m_max_blocks] : 0),
402         m_block_ptr_inc(v.m_block_ptr_inc)
403     {
404         unsigned i;
405         for(i = 0; i < v.m_num_blocks; ++i)
406         {
407             m_blocks[i] = new T [block_size];
408             memcpy(m_blocks[i], v.m_blocks[i], block_size * sizeof(T));
409         }
410     }
411 
412 
413     //------------------------------------------------------------------------
414     template<class T, unsigned S>
415     const pod_deque<T, S>& pod_deque<T, S>::operator = (const pod_deque<T, S>& v)
416     {
417         unsigned i;
418         for(i = m_num_blocks; i < v.m_num_blocks; ++i)
419         {
420             allocate_block(i);
421         }
422         for(i = 0; i < v.m_num_blocks; ++i)
423         {
424             memcpy(m_blocks[i], v.m_blocks[i], block_size * sizeof(T));
425         }
426         m_size = v.m_size;
427         return *this;
428     }
429 
430 
431     //------------------------------------------------------------------------
432     template<class T, unsigned S>
433     void pod_deque<T, S>::allocate_block(unsigned nb)
434     {
435         if(nb >= m_max_blocks)
436         {
437             T** new_blocks = new T* [m_max_blocks + m_block_ptr_inc];
438 
439             if(m_blocks)
440             {
441                 memcpy(new_blocks,
442                        m_blocks,
443                        m_num_blocks * sizeof(T*));
444 
445                 delete [] m_blocks;
446             }
447             m_blocks = new_blocks;
448             m_max_blocks += m_block_ptr_inc;
449         }
450         m_blocks[nb] = new T [block_size];
451         m_num_blocks++;
452     }
453 
454 
455 
456     //------------------------------------------------------------------------
457     template<class T, unsigned S>
458     inline T* pod_deque<T, S>::data_ptr()
459     {
460         unsigned nb = m_size >> block_shift;
461         if(nb >= m_num_blocks)
462         {
463             allocate_block(nb);
464         }
465         return m_blocks[nb] + (m_size & block_mask);
466     }
467 
468 
469 
470     //------------------------------------------------------------------------
471     template<class T, unsigned S>
472     inline void pod_deque<T, S>::add(const T& val)
473     {
474         *data_ptr() = val;
475         ++m_size;
476     }
477 
478 
479     //------------------------------------------------------------------------
480     template<class T, unsigned S>
481     inline void pod_deque<T, S>::remove_last()
482     {
483         if(m_size) --m_size;
484     }
485 
486 
487     //------------------------------------------------------------------------
488     template<class T, unsigned S>
489     void pod_deque<T, S>::modify_last(const T& val)
490     {
491         remove_last();
492         add(val);
493     }
494 
495 
496     //------------------------------------------------------------------------
497     template<class T, unsigned S>
498     int pod_deque<T, S>::allocate_continuous_block(unsigned num_elements)
499     {
500         if(num_elements < block_size)
501         {
502             data_ptr(); // Allocate initial block if necessary
503             unsigned rest = block_size - (m_size & block_mask);
504             unsigned index;
505             if(num_elements <= rest)
506             {
507                 // The rest of the block is good, we can use it
508                 //-----------------
509                 index = m_size;
510                 m_size += num_elements;
511                 return index;
512             }
513 
514             // New block
515             //---------------
516             m_size += rest;
517             data_ptr();
518             index = m_size;
519             m_size += num_elements;
520             return index;
521         }
522         return -1; // Impossible to allocate
523     }
524 
525 
526     //------------------------------------------------------------------------
527     template<class T, unsigned S>
528     unsigned pod_deque<T, S>::byte_size() const
529     {
530         return m_size * sizeof(T);
531     }
532 
533 
534     //------------------------------------------------------------------------
535     template<class T, unsigned S>
536     void pod_deque<T, S>::serialize(int8u* ptr) const
537     {
538         unsigned i;
539         for(i = 0; i < m_size; i++)
540         {
541             memcpy(ptr, &(*this)[i], sizeof(T));
542             ptr += sizeof(T);
543         }
544     }
545 
546     //------------------------------------------------------------------------
547     template<class T, unsigned S>
548     void pod_deque<T, S>::deserialize(const int8u* data, unsigned byte_size)
549     {
550         remove_all();
551         byte_size /= sizeof(T);
552         for(unsigned i = 0; i < byte_size; ++i)
553         {
554             T* ptr = data_ptr();
555             memcpy(ptr, data, sizeof(T));
556             ++m_size;
557             data += sizeof(T);
558         }
559     }
560 
561 
562     // Replace or add a number of elements starting from "start" position
563     //------------------------------------------------------------------------
564     template<class T, unsigned S>
565     void pod_deque<T, S>::deserialize(unsigned start, const T& empty_val,
566                                       const int8u* data, unsigned byte_size)
567     {
568         while(m_size < start)
569         {
570             add(empty_val);
571         }
572 
573         byte_size /= sizeof(T);
574         for(unsigned i = 0; i < byte_size; ++i)
575         {
576             if(start + i < m_size)
577             {
578                 memcpy(&((*this)[start + i]), data, sizeof(T));
579             }
580             else
581             {
582                 T* ptr = data_ptr();
583                 memcpy(ptr, data, sizeof(T));
584                 ++m_size;
585             }
586             data += sizeof(T);
587         }
588     }
589 
590 
591     //-----------------------------------------------------------pod_allocator
592     // Allocator for arbitrary POD data. Most usable in different cache
593     // systems for efficient memory allocations.
594     // Memory is allocated with blocks of fixed size ("block_size" in
595     // the constructor). If required size exceeds the block size the allocator
596     // creates a new block of the required size. However, the most efficient
597     // use is when the average reqired size is much less than the block size.
598     //------------------------------------------------------------------------
599     class pod_allocator
600     {
601     public:
602         void remove_all()
603         {
604             if(m_num_blocks)
605             {
606                 int8u** blk = m_blocks + m_num_blocks - 1;
607                 while(m_num_blocks--)
608                 {
609                     delete [] *blk;
610                     --blk;
611                 }
612                 delete [] m_blocks;
613             }
614             m_num_blocks = 0;
615             m_max_blocks = 0;
616             m_blocks = 0;
617             m_buf_ptr = 0;
618             m_rest = 0;
619         }
620 
621         ~pod_allocator()
622         {
623             remove_all();
624         }
625 
626         pod_allocator(unsigned block_size, unsigned block_ptr_inc=256-8) :
627             m_block_size(block_size),
628             m_block_ptr_inc(block_ptr_inc),
629             m_num_blocks(0),
630             m_max_blocks(0),
631             m_blocks(0),
632             m_buf_ptr(0),
633             m_rest(0)
634         {
635         }
636 
637 
638         int8u* allocate(unsigned size, unsigned alignment=1)
639         {
640             if(size == 0) return 0;
641             if(size <= m_rest)
642             {
643                 int8u* ptr = m_buf_ptr;
644                 if(alignment > 1)
645                 {
646                     unsigned align = (alignment - unsigned((size_t)ptr) % alignment) % alignment;
647                     size += align;
648                     ptr += align;
649                     if(size <= m_rest)
650                     {
651                         m_rest -= size;
652                         m_buf_ptr += size;
653                         return ptr;
654                     }
655                     allocate_block(size);
656                     return allocate(size - align, alignment);
657                 }
658                 m_rest -= size;
659                 m_buf_ptr += size;
660                 return ptr;
661             }
662             allocate_block(size + alignment - 1);
663             return allocate(size, alignment);
664         }
665 
666 
667     private:
668         void allocate_block(unsigned size)
669         {
670             if(size < m_block_size) size = m_block_size;
671             if(m_num_blocks >= m_max_blocks)
672             {
673                 int8u** new_blocks = new int8u* [m_max_blocks + m_block_ptr_inc];
674 
675                 if(m_blocks)
676                 {
677                     memcpy(new_blocks,
678                            m_blocks,
679                            m_num_blocks * sizeof(int8u*));
680 
681                     delete [] m_blocks;
682                 }
683                 m_blocks = new_blocks;
684                 m_max_blocks += m_block_ptr_inc;
685             }
686             m_blocks[m_num_blocks] = m_buf_ptr = new int8u [size];
687             m_num_blocks++;
688             m_rest = size;
689         }
690 
691         unsigned m_block_size;
692         unsigned m_block_ptr_inc;
693         unsigned m_num_blocks;
694         unsigned m_max_blocks;
695         int8u**  m_blocks;
696         int8u*   m_buf_ptr;
697         unsigned m_rest;
698     };
699 
700 
701 
702 
703 
704 
705 
706 
707     //------------------------------------------------------------------------
708     enum
709     {
710         quick_sort_threshold = 9
711     };
712 
713 
714     //-----------------------------------------------------------swap_elements
715     template<class T> inline void swap_elements(T& a, T& b)
716     {
717         T temp = a;
718         a = b;
719         b = temp;
720     }
721 
722 
723     //--------------------------------------------------------------quick_sort
724     template<class Array, class Less>
725     void quick_sort(Array& arr, Less less)
726     {
727         if(arr.size() < 2) return;
728 
729         typename Array::value_type* e1;
730         typename Array::value_type* e2;
731 
732         int  stack[80];
733         int* top = stack;
734         int  limit = arr.size();
735         int  base = 0;
736 
737         for(;;)
738         {
739             int len = limit - base;
740 
741             int i;
742             int j;
743             int pivot;
744 
745             if(len > quick_sort_threshold)
746             {
747                 // we use base + len/2 as the pivot
748                 pivot = base + len / 2;
749                 swap_elements(arr[base], arr[pivot]);
750 
751                 i = base + 1;
752                 j = limit - 1;
753 
754                 // now ensure that *i <= *base <= *j
755                 e1 = &(arr[j]);
756                 e2 = &(arr[i]);
757                 if(less(*e1, *e2)) swap_elements(*e1, *e2);
758 
759                 e1 = &(arr[base]);
760                 e2 = &(arr[i]);
761                 if(less(*e1, *e2)) swap_elements(*e1, *e2);
762 
763                 e1 = &(arr[j]);
764                 e2 = &(arr[base]);
765                 if(less(*e1, *e2)) swap_elements(*e1, *e2);
766 
767                 for(;;)
768                 {
769                     do i++; while( less(arr[i], arr[base]) );
770                     do j--; while( less(arr[base], arr[j]) );
771 
772                     if( i > j )
773                     {
774                         break;
775                     }
776 
777                     swap_elements(arr[i], arr[j]);
778                 }
779 
780                 swap_elements(arr[base], arr[j]);
781 
782                 // now, push the largest sub-array
783                 if(j - base > limit - i)
784                 {
785                     top[0] = base;
786                     top[1] = j;
787                     base   = i;
788                 }
789                 else
790                 {
791                     top[0] = i;
792                     top[1] = limit;
793                     limit  = j;
794                 }
795                 top += 2;
796             }
797             else
798             {
799                 // the sub-array is small, perform insertion sort
800                 j = base;
801                 i = j + 1;
802 
803                 for(; i < limit; j = i, i++)
804                 {
805                     for(; less(*(e1 = &(arr[j + 1])), *(e2 = &(arr[j]))); j--)
806                     {
807                         swap_elements(*e1, *e2);
808                         if(j == base)
809                         {
810                             break;
811                         }
812                     }
813                 }
814                 if(top > stack)
815                 {
816                     top  -= 2;
817                     base  = top[0];
818                     limit = top[1];
819                 }
820                 else
821                 {
822                     break;
823                 }
824             }
825         }
826     }
827 
828 
829 
830 
831     //------------------------------------------------------remove_duplicates
832     // Remove duplicates from a sorted array. It doesn't cut the the
833     // tail of the array, it just returns the number of remaining elements.
834     //-----------------------------------------------------------------------
835     template<class Array, class Equal>
836     unsigned remove_duplicates(Array& arr, Equal equal)
837     {
838         if(arr.size() < 2) return arr.size();
839 
840         unsigned i, j;
841         for(i = 1, j = 1; i < arr.size(); i++)
842         {
843             typename Array::value_type& e = arr[i];
844             if(!equal(e, arr[i - 1]))
845             {
846                 arr[j++] = e;
847             }
848         }
849         return j;
850     }
851 
852 
853 
854 
855 }
856 
857 #endif
858