summaryrefslogtreecommitdiff
path: root/src/corelib/render/software/agg_array.pas
diff options
context:
space:
mode:
authorGraeme Geldenhuys <graeme@mastermaths.co.za>2012-02-27 19:53:35 +0200
committerGraeme Geldenhuys <graeme@mastermaths.co.za>2012-03-07 22:44:08 +0200
commitb50c7fe536960a49349475f5c361044b097f24dc (patch)
treeeb74f0624ebaca3b6ee64a08b3edb63883eb06c2 /src/corelib/render/software/agg_array.pas
parenta955b0e4833ba419478be83523fe433d645cd789 (diff)
downloadfpGUI-b50c7fe536960a49349475f5c361044b097f24dc.tar.xz
initial import of AggPas 2.4 RM3
The AggPas demos will not compile at this time, because I have restructured the directories a bit. I wanted a pristine checkin though. The demos will be fixed in the next few commits.
Diffstat (limited to 'src/corelib/render/software/agg_array.pas')
-rw-r--r--src/corelib/render/software/agg_array.pas1194
1 files changed, 1194 insertions, 0 deletions
diff --git a/src/corelib/render/software/agg_array.pas b/src/corelib/render/software/agg_array.pas
new file mode 100644
index 00000000..ad013c9a
--- /dev/null
+++ b/src/corelib/render/software/agg_array.pas
@@ -0,0 +1,1194 @@
+//----------------------------------------------------------------------------
+// Anti-Grain Geometry - Version 2.4 (Public License)
+// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
+//
+// Anti-Grain Geometry - Version 2.4 Release Milano 3 (AggPas 2.4 RM3)
+// Pascal Port By: Milan Marusinec alias Milano
+// milan@marusinec.sk
+// http://www.aggpas.org
+// Copyright (c) 2005-2006
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+//----------------------------------------------------------------------------
+// Contact: mcseem@antigrain.com
+// mcseemagg@yahoo.com
+// http://www.antigrain.com
+//
+// [Pascal Port History] -----------------------------------------------------
+//
+// 23.06.2006-Milano: ptrcomp adjustments
+// 18.02.2006-MIlano: pod_array_adaptor, quick_sort
+// 16.02.2006-Milano: pod_allocator
+// 19.12.2005-Milano: pod_deque
+// 15.11.2005-Milano: Unit port establishment
+//
+{ agg_array.pas }
+unit
+ agg_array ;
+
+INTERFACE
+
+{$I agg_mode.inc }
+
+uses
+ agg_basics ;
+
+{ TYPES DEFINITION }
+type
+ func_less = function(e1 ,e2 : pointer ) : boolean;
+ func_equal = function(e1 ,e2 : pointer ) : boolean;
+
+ array_base_ptr = ^array_base;
+ array_base = object
+ function size : unsigned; virtual; abstract;
+ function entry : unsigned; virtual; abstract;
+ function array_operator(i : unsigned ) : pointer; virtual; abstract;
+
+ function at(i : unsigned ) : pointer; virtual;
+
+ end;
+
+//----------------------------------------------------------range_adaptor
+ range_adaptor = object(array_base )
+ private
+ m_array : array_base_ptr;
+ m_start ,
+ m_size : unsigned;
+
+ public
+ constructor Construct(array_ : array_base_ptr; start ,size_ : unsigned );
+
+ function size : unsigned; virtual;
+ function entry : unsigned; virtual;
+ function array_operator(i : unsigned ) : pointer; virtual;
+
+ end;
+
+//-------------------------------------------------------pod_array_adaptor
+ pod_array_adaptor_ptr = ^pod_array_adaptor;
+ pod_array_adaptor = object(array_base )
+ m_array : pointer;
+ m_size ,
+ m_entry : unsigned;
+
+ constructor Construct(array_ : pointer; size_ ,entry_ : unsigned );
+
+ function size : unsigned; virtual;
+ function entry : unsigned; virtual;
+ function array_operator(i : unsigned ) : pointer; virtual;
+
+ function at(i : unsigned ) : pointer; virtual;
+
+ end;
+
+//---------------------------------------------------------pod_auto_array
+ pod_auto_array_ptr = ^pod_auto_array;
+ pod_auto_array = object(array_base )
+ m_size ,
+ m_entry_sz : unsigned;
+
+ m_array : pointer;
+
+ constructor Construct(size_ ,entry_sz : unsigned );
+ destructor Destruct;
+
+ function size : unsigned; virtual;
+ function entry : unsigned; virtual;
+ function array_operator(i : unsigned ) : pointer; virtual;
+
+ end;
+
+//---------------------------------------------------------------pod_array
+// A simple class template to store Plain Old Data, a vector
+// of a fixed size. The data is continous in memory
+//------------------------------------------------------------------------
+ pod_array = object(array_base )
+ m_entry_sz ,
+ m_size ,
+ m_capacity : unsigned;
+
+ m_array : pointer;
+
+ constructor Construct(entry_sz : unsigned ); overload;
+ constructor Construct(entry_sz ,size_ : unsigned ); overload;
+ constructor Create (entry_sz ,size_ : unsigned );
+ destructor Destruct;
+
+ procedure allocate(size_ : unsigned; extra_tail : unsigned = 0 );
+ procedure resize (new_size : unsigned );
+ procedure capacity(cap ,extra_tail : unsigned );
+
+ procedure zero;
+ procedure add(v : pointer );
+ function data : pointer;
+
+ function size : unsigned; virtual;
+ function entry : unsigned; virtual;
+ function array_operator(i : unsigned ) : pointer; virtual;
+
+ end;
+
+ pod_vector = pod_array;
+
+//---------------------------------------------------------------pod_deque
+// A simple class template to store Plain Old Data, similar to std::deque
+// It doesn't reallocate memory but instead, uses blocks of data of size
+// of (1 << S), that is, power of two. The data is NOT contiguous in memory,
+// so the only valid access method is operator [] or curr(), prev(), next()
+//
+// There reallocs occure only when the pool of pointers to blocks needs
+// to be extended (it happens very rarely). You can control the value
+// of increment to reallocate the pointer buffer. See the second constructor.
+// By default, the incremeent value equals (1 << S), i.e., the block size.
+//------------------------------------------------------------------------
+ pod_deque_ptr = ^pod_deque;
+ pod_deque = object(array_base )
+ block_shift ,
+ block_size ,
+ block_mask : unsigned;
+
+ m_size ,
+ m_num_blocks ,
+ m_max_blocks ,
+ m_block_ptr_inc : unsigned;
+
+ m_blocks : pointer;
+
+ m_entry_sz : unsigned;
+
+ constructor Construct(entry_sz : unsigned; s_ : unsigned = 6 ); overload;
+ constructor Construct(block_ptr_inc ,entry_sz : unsigned; s_ : unsigned ); overload;
+ destructor Destruct;
+
+ procedure remove_all;
+ procedure remove_last;
+
+ procedure add (val : pointer );
+ procedure modify_last(val : pointer );
+
+ procedure cut_at(size_ : unsigned );
+
+ function size : unsigned; virtual;
+ function entry : unsigned; virtual;
+
+ function array_operator (i : unsigned ) : pointer; virtual;
+ procedure assign_operator(v : pod_deque_ptr );
+
+ function curr(idx : unsigned ) : pointer;
+ function prev(idx : unsigned ) : pointer;
+ function next(idx : unsigned ) : pointer;
+ function last : pointer;
+
+ function allocate_continuous_block(num_elements : unsigned ) : int;
+ procedure allocate_block (nb : unsigned );
+
+ function data_ptr : pointer;
+
+ end;
+
+ pod_bvector_ptr = ^pod_bvector;
+ pod_bvector = pod_deque;
+
+//-----------------------------------------------------------pod_allocator
+// Allocator for arbitrary POD data. Most usable in different cache
+// systems for efficient memory allocations.
+// Memory is allocated with blocks of fixed size ("block_size" in
+// the constructor). If required size exceeds the block size the allocator
+// creates a new block of the required size. However, the most efficient
+// use is when the average reqired size is much less than the block size.
+//------------------------------------------------------------------------
+ pod_alloc_ptr = ^pod_alloc;
+ pod_alloc = record
+ ptr : int8u_ptr;
+ sz : unsigned;
+
+ end;
+
+ pod_allocator = object
+ m_block_size ,
+ m_block_ptr_inc ,
+ m_num_blocks ,
+ m_max_blocks : unsigned;
+
+ m_blocks : pod_alloc_ptr;
+ m_buf_ptr : int8u_ptr;
+
+ m_rest : unsigned;
+
+ constructor Construct(block_size : unsigned; block_ptr_inc : unsigned = 256 - 8 );
+ destructor Destruct;
+
+ procedure remove_all;
+
+ function allocate(size : unsigned; alignment : unsigned = 1 ) : int8u_ptr;
+
+ procedure allocate_block(size : unsigned );
+
+ end;
+
+{ GLOBAL VARIABLES & CONSTANTS }
+{ GLOBAL PROCEDURES }
+ procedure quick_sort (arr : array_base_ptr; less : func_less );
+ function remove_duplicates(arr : array_base_ptr; equal : func_equal ) : unsigned;
+
+ function int_less (a ,b : pointer ) : boolean;
+ function int_greater(a ,b : pointer ) : boolean;
+
+ function unsigned_less (a ,b : pointer ) : boolean;
+ function unsigned_greater(a ,b : pointer ) : boolean;
+
+IMPLEMENTATION
+{ LOCAL VARIABLES & CONSTANTS }
+{ QUICK_SORT }
+procedure quick_sort;
+const
+ quick_sort_threshold = 9;
+
+type
+ int80_ptr = ^int80;
+ int80 = array[0..79 ] of int;
+
+var
+ temp ,e1 ,e2 : pointer;
+
+ swap : unsigned;
+
+ stack : int80;
+
+ top : int80_ptr;
+
+ limit ,base ,len ,i ,j ,pivot : int;
+
+begin
+ if arr.size < 2 then
+ exit;
+
+ agg_getmem(temp ,arr.entry );
+
+ swap :=arr.entry;
+ top :=@stack;
+ limit:=arr.size;
+ base :=0;
+
+ repeat
+ len:=limit - base;
+
+ if len > quick_sort_threshold then
+ begin
+ // we use base + len/2 as the pivot
+ pivot:=base + len div 2;
+
+ // swap_elements(arr[base], arr[pivot]);
+ move(arr.at(base )^ ,temp^ ,swap );
+ move(arr.at(pivot )^ ,arr.at(base )^ ,swap );
+ move(temp^ ,arr.at(pivot )^ ,swap );
+
+ i:=base + 1;
+ j:=limit - 1;
+
+ // now ensure that *i <= *base <= *j
+ e1:=arr.at(j );
+ e2:=arr.at(i );
+
+ if less(e1 ,e2 ) then
+ begin
+ // swap_elements(*e1, *e2);
+ move(e1^ ,temp^ ,swap );
+ move(e2^ ,e1^ ,swap );
+ move(temp^ ,e2^ ,swap );
+
+ end;
+
+ e1:=arr.at(base );
+ e2:=arr.at(i );
+
+ if less(e1 ,e2 ) then
+ begin
+ // swap_elements(*e1, *e2);
+ move(e1^ ,temp^ ,swap );
+ move(e2^ ,e1^ ,swap );
+ move(temp^ ,e2^ ,swap );
+
+ end;
+
+ e1:=arr.at(j );
+ e2:=arr.at(base );
+
+ if less(e1 ,e2 ) then
+ begin
+ // swap_elements(*e1, *e2);
+ move(e1^ ,temp^ ,swap );
+ move(e2^ ,e1^ ,swap );
+ move(temp^ ,e2^ ,swap );
+
+ end;
+
+ repeat
+ repeat
+ inc(i )
+
+ until not less(arr.at(i ) ,arr.at(base ) );
+
+ repeat
+ dec(j );
+
+ until not less(arr.at(base ) ,arr.at(j ) );
+
+ if i > j then
+ break;
+
+ // swap_elements(arr[i], arr[j]);
+ move(arr.at(i )^ ,temp^ ,swap );
+ move(arr.at(j )^ ,arr.at(i )^ ,swap );
+ move(temp^ ,arr.at(j )^ ,swap );
+
+ until false;
+
+ // swap_elements(arr[base], arr[j]);
+ move(arr.at(base )^ ,temp^ ,swap );
+ move(arr.at(j )^ ,arr.at(base )^ ,swap );
+ move(temp^ ,arr.at(j )^ ,swap );
+
+ // now, push the largest sub-array
+ if j - base > limit - i then
+ begin
+ top^[0 ]:=base;
+ top^[1 ]:=j;
+ base :=i;
+
+ end
+ else
+ begin
+ top^[0 ]:=i;
+ top^[1 ]:=limit;
+ limit :=j;
+
+ end;
+
+ inc(ptrcomp(top ) ,2 * sizeof(int ) );
+
+ end
+ else
+ begin
+ // the sub-array is small, perform insertion sort
+ j:=base;
+ i:=j + 1;
+
+ while i < limit do
+ begin
+ e1:=arr.at(j + 1 );
+ e2:=arr.at(j );
+
+ while less(e1 ,e2 ) do
+ begin
+ // swap_elements(*e1, *e2);
+ move(e1^ ,temp^ ,swap );
+ move(e2^ ,e1^ ,swap );
+ move(temp^ ,e2^ ,swap );
+
+ if j = base then
+ break;
+
+ dec(j );
+
+ e1:=arr.at(j + 1 );
+ e2:=arr.at(j );
+
+ end;
+
+ j:=i;
+
+ inc(i );
+
+ end;
+
+ if ptrcomp(top ) > ptrcomp(@stack ) then
+ begin
+ dec(ptrcomp(top ) ,2 * sizeof(int ) );
+
+ base :=top^[0 ];
+ limit:=top^[1 ];
+
+ end
+ else
+ break;
+
+ end;
+
+ until false;
+
+ agg_freemem(temp ,arr.entry );
+
+end;
+
+{ REMOVE_DUPLICATES }
+// Remove duplicates from a sorted array. It doesn't cut the
+// tail of the array, it just returns the number of remaining elements.
+function remove_duplicates(arr : array_base_ptr; equal : func_equal ) : unsigned;
+var
+ i ,j : unsigned;
+
+ e : pointer;
+
+begin
+ if arr.size < 2 then
+ begin
+ result:=arr.size;
+
+ exit;
+
+ end;
+
+ i:=1;
+ j:=1;
+
+ while i < arr.size do
+ begin
+ e:=arr.array_operator(i );
+
+ if not equal(e ,arr.array_operator(i - 1 ) ) then
+ begin
+ move(e^ ,arr.array_operator(j )^ ,arr.entry );
+ inc (j );
+
+ end;
+
+ inc(i );
+
+ end;
+
+ result:=j;
+
+end;
+
+{ INT_LESS }
+function int_less(a ,b : pointer ) : boolean;
+begin
+ result:=int_ptr(a )^ < int_ptr(b )^;
+
+end;
+
+{ INT_GREATER }
+function int_greater(a ,b : pointer ) : boolean;
+begin
+ result:=int_ptr(a )^ > int_ptr(b )^;
+
+end;
+
+{ UNSIGNED_LESS }
+function unsigned_less(a ,b : pointer ) : boolean;
+begin
+ result:=unsigned_ptr(a )^ < unsigned_ptr(b )^;
+
+end;
+
+{ UNSIGNED_GREATER }
+function unsigned_greater(a ,b : pointer ) : boolean;
+begin
+ result:=unsigned_ptr(a )^ > unsigned_ptr(b )^;
+
+end;
+
+{ UNIT IMPLEMENTATION }
+{ AT }
+function array_base.at;
+begin
+ at:=array_operator(i );
+
+end;
+
+{ CONSTRUCT }
+constructor range_adaptor.Construct(array_ : array_base_ptr; start ,size_ : unsigned );
+begin
+ m_array:=array_;
+ m_start:=start;
+ m_size :=size_;
+
+end;
+
+{ SIZE }
+function range_adaptor.size : unsigned;
+begin
+ result:=m_size;
+
+end;
+
+{ ENTRY }
+function range_adaptor.entry : unsigned;
+begin
+ result:=m_array.entry;
+
+end;
+
+{ ARRAY_OPERATOR }
+function range_adaptor.array_operator(i : unsigned ) : pointer;
+begin
+ result:=m_array.array_operator(m_start + i );
+
+end;
+
+{ CONSTRUCT }
+constructor pod_array_adaptor.Construct;
+begin
+ m_array:=array_;
+ m_size :=size_;
+ m_entry:=entry_;
+
+end;
+
+{ SIZE }
+function pod_array_adaptor.size;
+begin
+ result:=m_size;
+
+end;
+
+{ ENTRY }
+function pod_array_adaptor.entry;
+begin
+ result:=m_entry;
+
+end;
+
+{ ARRAY_OPERATOR }
+function pod_array_adaptor.array_operator;
+begin
+ result:=pointer(ptrcomp(m_array ) + i * sizeof(m_entry ) );
+
+end;
+
+{ AT }
+function pod_array_adaptor.at;
+begin
+ result:=pointer(ptrcomp(m_array ) + i * m_entry );
+
+end;
+
+{ CONSTRUCT }
+constructor pod_auto_array.Construct;
+begin
+ m_size :=size_;
+ m_entry_sz:=entry_sz;
+
+ agg_getmem(m_array ,m_size * m_entry_sz );
+
+end;
+
+{ DESTRUCT }
+destructor pod_auto_array.Destruct;
+begin
+ agg_freemem(m_array ,m_size * m_entry_sz );
+
+end;
+
+{ SIZE }
+function pod_auto_array.size;
+begin
+ result:=m_size;
+
+end;
+
+{ ENTRY }
+function pod_auto_array.entry;
+begin
+ result:=m_entry_sz;
+
+end;
+
+{ ARRAY_OPERATOR }
+function pod_auto_array.array_operator;
+begin
+ result:=pointer(ptrcomp(m_array ) + i * m_entry_sz );
+
+end;
+
+{ CONSTRUCT }
+constructor pod_array.Construct(entry_sz : unsigned );
+begin
+ m_entry_sz:=entry_sz;
+ m_size :=0;
+ m_capacity:=0;
+
+ m_array:=NIL;
+
+end;
+
+{ CONSTRUCT }
+constructor pod_array.Construct(entry_sz ,size_ : unsigned );
+begin
+ Construct(entry_sz );
+ allocate (size_ );
+
+end;
+
+{ CREATE }
+constructor pod_array.Create(entry_sz ,size_ : unsigned );
+begin
+ Construct(entry_sz );
+ capacity (size_ ,0 );
+
+end;
+
+{ DESTRUCT }
+destructor pod_array.Destruct;
+begin
+ if m_array <> NIL then
+ agg_freemem(m_array ,m_capacity * m_entry_sz );
+
+end;
+
+{ ALLOCATE }
+// Allocate n elements. All data is lost,
+// but elements can be accessed in range 0...size-1.
+procedure pod_array.allocate;
+begin
+ capacity(size_ ,extra_tail );
+
+ m_size:=size_;
+
+end;
+
+{ RESIZE }
+// Resize keeping the content.
+procedure pod_array.resize;
+var
+ buff : pointer;
+
+begin
+ if new_size > m_size then
+ if new_size > m_capacity then
+ begin
+ agg_getmem(buff ,new_size * m_entry_sz );
+
+ if m_array <> NIL then
+ begin
+ move(m_array^ ,buff^ ,m_size * m_entry_sz );
+
+ agg_freemem(m_array ,m_capacity * m_entry_sz );
+
+ end;
+
+ m_array :=buff;
+ m_capacity:=new_size;
+
+ end
+ else
+ else
+ m_size:=new_size;
+
+end;
+
+{ CAPACITY }
+procedure pod_array.capacity;
+begin
+ m_size:=0;
+
+ if cap > m_capacity then
+ begin
+ agg_freemem(m_array ,m_capacity * m_entry_sz );
+
+ m_capacity:=cap + extra_tail;
+
+ if m_capacity > 0 then
+ agg_getmem(m_array ,m_capacity * m_entry_sz )
+ else
+ m_array:=0;
+
+ end;
+
+end;
+
+{ ZERO }
+procedure pod_array.zero;
+begin
+ fillchar(m_array^ ,m_entry_sz * m_size ,0 );
+
+end;
+
+{ ADD }
+procedure pod_array.add(v : pointer );
+begin
+ move(v^ ,pointer(ptrcomp(m_array ) + m_size * m_entry_sz )^ ,m_entry_sz );
+ inc (m_size );
+
+end;
+
+{ DATA }
+function pod_array.data;
+begin
+ result:=m_array;
+
+end;
+
+{ SIZE }
+function pod_array.size;
+begin
+ result:=m_size;
+
+end;
+
+{ ENTRY }
+function pod_array.entry;
+begin
+ result:=m_entry_sz;
+
+end;
+
+{ ARRAY_OPERATOR }
+function pod_array.array_operator(i : unsigned ) : pointer;
+begin
+ result:=pointer(ptrcomp(m_array ) + i * m_entry_sz );
+
+end;
+
+{ CONSTRUCT }
+constructor pod_deque.Construct(entry_sz : unsigned; s_ : unsigned = 6 );
+begin
+ block_shift:=s_;
+ block_size :=1 shl block_shift;
+ block_mask :=block_size - 1;
+
+ m_size :=0;
+ m_num_blocks :=0;
+ m_max_blocks :=0;
+ m_blocks :=0;
+ m_block_ptr_inc:=block_size;
+
+ m_entry_sz:=entry_sz;
+
+end;
+
+{ CONSTRUCT }
+constructor pod_deque.Construct(block_ptr_inc ,entry_sz : unsigned; s_ : unsigned );
+begin
+ Construct(entry_sz ,s_ );
+
+ m_block_ptr_inc:=block_ptr_inc;
+
+end;
+
+{ DESTRUCT }
+destructor pod_deque.Destruct;
+var
+ blk : pointer;
+
+begin
+ if m_num_blocks <> 0 then
+ begin
+ blk:=pointer(ptrcomp(m_blocks ) + (m_num_blocks - 1 ) * sizeof(pointer ) );
+
+ while m_num_blocks <> 0 do
+ begin
+ agg_freemem(p32(blk^ ).ptr ,block_size * m_entry_sz );
+
+ dec(ptrcomp(blk ) ,sizeof(pointer ) );
+ dec(m_num_blocks );
+
+ end;
+
+ agg_freemem(m_blocks ,m_max_blocks * sizeof(pointer ) );
+
+ end;
+
+end;
+
+{ REMOVE_ALL }
+procedure pod_deque.remove_all;
+begin
+ m_size:=0;
+
+end;
+
+{ REMOVE_LAST }
+procedure pod_deque.remove_last;
+begin
+ if m_size <> 0 then
+ dec(m_size );
+
+end;
+
+{ ADD }
+procedure pod_deque.add;
+var
+ p : pointer;
+
+begin
+ p:=data_ptr;
+
+ move(val^ ,p^ ,m_entry_sz );
+ inc (m_size );
+
+end;
+
+{ MODIFY_LAST }
+procedure pod_deque.modify_last;
+begin
+ remove_last;
+ add(val );
+
+end;
+
+{ CUT_AT }
+procedure pod_deque.cut_at(size_ : unsigned );
+begin
+ if size_ < m_size then
+ m_size:=size_;
+
+end;
+
+{ SIZE }
+function pod_deque.size;
+begin
+ result:=m_size;
+
+end;
+
+{ ENTRY }
+function pod_deque.entry;
+begin
+ result:=m_entry_sz;
+
+end;
+
+{ ARRAY_OPERATOR }
+function pod_deque.array_operator;
+begin
+ result:=
+ pointer(
+ p32(pointer(ptrcomp(m_blocks ) + (i shr block_shift ) * sizeof(pointer ) )^ ).int
+ + (i and block_mask ) * m_entry_sz );
+
+end;
+
+{ ASSIGN_OPERATOR }
+procedure pod_deque.assign_operator;
+var
+ i : unsigned;
+ src ,
+ dst : pointer;
+
+begin
+ Destruct;
+
+ block_shift:=v.block_shift;
+ block_size :=v.block_size;
+ block_mask :=v.block_mask;
+
+ m_size :=v.m_size;
+ m_entry_sz:=v.m_entry_sz;
+
+ m_num_blocks:=v.m_num_blocks;
+ m_max_blocks:=v.m_max_blocks;
+
+ m_block_ptr_inc:=v.m_block_ptr_inc;
+
+ if m_max_blocks <> 0 then
+ agg_getmem(m_blocks ,m_max_blocks * sizeof(pointer ) )
+ else
+ m_blocks:=NIL;
+
+
+ src:=v.m_blocks;
+ dst:=m_blocks;
+ i :=0;
+
+ while i < m_num_blocks do
+ begin
+ agg_getmem(p32(dst^ ).ptr ,block_size * m_entry_sz );
+
+ move(
+ p32(src^ ).ptr^ ,
+ p32(dst^ ).ptr^ ,
+ block_size * m_entry_sz );
+
+ inc(ptrcomp(src ) ,sizeof(pointer ) );
+ inc(ptrcomp(dst ) ,sizeof(pointer ) );
+ inc(i );
+
+ end;
+
+end;
+
+{ CURR }
+function pod_deque.curr;
+begin
+ result:=array_operator(idx );
+
+end;
+
+{ PREV }
+function pod_deque.prev;
+begin
+ result:=array_operator((idx + m_size - 1 ) mod m_size );
+
+end;
+
+{ NEXT }
+function pod_deque.next;
+begin
+ result:=array_operator((idx + 1 ) mod m_size );
+
+end;
+
+{ LAST }
+function pod_deque.last : pointer;
+begin
+ result:=array_operator(m_size - 1 );
+
+end;
+
+{ ALLOCATE_CONTINUOUS_BLOCK }
+function pod_deque.allocate_continuous_block;
+var
+ rest ,index : unsigned;
+
+begin
+ if num_elements < block_size then
+ begin
+ data_ptr; // Allocate initial block if necessary
+
+ rest:=block_size - (m_size and block_mask );
+
+ if num_elements <= rest then
+ begin
+ // The rest of the block is good, we can use it
+ index:=m_size;
+
+ inc(m_size ,num_elements );
+
+ result:=index;
+
+ exit;
+
+ end;
+
+ // New block
+ inc(m_size ,rest );
+
+ data_ptr;
+
+ index:=m_size;
+
+ inc(m_size ,num_elements );
+
+ result:=index;
+
+ exit;
+
+ end;
+
+ result:=-1; // Impossible to allocate
+
+end;
+
+{ ALLOCATE_BLOCK }
+procedure pod_deque.allocate_block;
+var
+ new_blocks : pointer;
+
+begin
+ if nb >= m_max_blocks then
+ begin
+ agg_getmem(new_blocks ,(m_max_blocks + m_block_ptr_inc ) * sizeof(pointer ) );
+
+ if m_blocks <> NIL then
+ begin
+ move(
+ m_blocks^ ,
+ new_blocks^ ,
+ m_num_blocks * sizeof(pointer ) );
+
+ agg_freemem(m_blocks ,m_max_blocks * sizeof(pointer ) );
+
+ end;
+
+ m_blocks:=new_blocks;
+
+ inc(m_max_blocks ,m_block_ptr_inc );
+
+ end;
+
+ agg_getmem(
+ p32(pointer(ptrcomp(m_blocks ) + nb * sizeof(pointer ) )^ ).ptr ,
+ block_size * m_entry_sz );
+
+ inc(m_num_blocks );
+
+end;
+
+{ DATA_PTR }
+function pod_deque.data_ptr;
+var
+ nb : unsigned;
+
+begin
+ nb:=m_size shr block_shift;
+
+ if nb >= m_num_blocks then
+ allocate_block(nb );
+
+ result:=
+ pointer(
+ p32(pointer(ptrcomp(m_blocks ) + nb * sizeof(pointer ) )^ ).int
+ + (m_size and block_mask ) * m_entry_sz );
+
+end;
+
+{ CONSTRUCT }
+constructor pod_allocator.Construct;
+begin
+ m_block_size :=block_size;
+ m_block_ptr_inc:=block_ptr_inc;
+
+ m_num_blocks:=0;
+ m_max_blocks:=0;
+
+ m_blocks :=NIL;
+ m_buf_ptr:=NIL;
+ m_rest :=0;
+
+end;
+
+{ DESTRUCT }
+destructor pod_allocator.Destruct;
+begin
+ remove_all;
+
+end;
+
+{ REMOVE_ALL }
+procedure pod_allocator.remove_all;
+var
+ blk : pod_alloc_ptr;
+
+begin
+ if m_num_blocks <> 0 then
+ begin
+ blk:=pod_alloc_ptr(ptrcomp(m_blocks ) + (m_num_blocks - 1 ) * sizeof(pod_alloc ) );
+
+ while m_num_blocks <> 0 do
+ begin
+ agg_freemem(pointer(blk.ptr ) ,blk.sz );
+
+ dec(ptrcomp(blk ) ,sizeof(pod_alloc ) );
+ dec(m_num_blocks );
+
+ end;
+
+ agg_freemem(pointer(m_blocks ) ,m_max_blocks * sizeof(pod_alloc ) );
+
+ end;
+
+ m_num_blocks:=0;
+ m_max_blocks:=0;
+
+ m_blocks :=NIL;
+ m_buf_ptr:=NIL;
+ m_rest :=0;
+
+end;
+
+{ ALLOCATE }
+function pod_allocator.allocate;
+var
+ ptr : int8u_ptr;
+ align : unsigned;
+
+begin
+ if size = 0 then
+ begin
+ result:=0;
+
+ exit;
+
+ end;
+
+ if size <= m_rest then
+ begin
+ ptr:=m_buf_ptr;
+
+ if alignment > 1 then
+ begin
+ align:=(alignment - unsigned(int32u(ptr ) ) mod alignment ) mod alignment;
+
+ inc(size ,align );
+ inc(ptrcomp(ptr ) ,align );
+
+ if size <= m_rest then
+ begin
+ dec(m_rest ,size );
+ inc(ptrcomp(m_buf_ptr ) ,size );
+
+ result:=ptr;
+
+ exit;
+
+ end;
+
+ allocate_block(size );
+
+ result:=allocate(size - align ,alignment );
+
+ exit;
+
+ end;
+
+ dec(m_rest ,size );
+ inc(ptrcomp(m_buf_ptr ) ,size );
+
+ result:=ptr;
+
+ exit;
+
+ end;
+
+ allocate_block(size + alignment - 1 );
+
+ result:=allocate(size ,alignment );
+
+end;
+
+{ ALLOCATE_BLOCK }
+procedure pod_allocator.allocate_block;
+var
+ new_blocks : pod_alloc_ptr;
+
+begin
+ if size < m_block_size then
+ size:=m_block_size;
+
+ if m_num_blocks >= m_max_blocks then
+ begin
+ agg_getmem(pointer(new_blocks ) ,(m_max_blocks + m_block_ptr_inc ) * sizeof(pod_alloc ) );
+
+ if m_blocks <> NIL then
+ begin
+ move(m_blocks^ ,new_blocks^ ,m_num_blocks * sizeof(pod_alloc ) );
+
+ agg_freemem(pointer(m_blocks ) ,m_max_blocks * sizeof(pod_alloc ) );
+
+ end;
+
+ m_blocks:=new_blocks;
+
+ inc(m_max_blocks ,m_block_ptr_inc );
+
+ end;
+
+ agg_getmem(pointer(m_buf_ptr ) ,size * sizeof(int8u ) );
+
+ pod_alloc_ptr(ptrcomp(m_blocks ) + m_num_blocks * sizeof(pod_alloc ) ).ptr:=m_buf_ptr;
+ pod_alloc_ptr(ptrcomp(m_blocks ) + m_num_blocks * sizeof(pod_alloc ) ).sz :=size;
+
+ inc(m_num_blocks );
+
+ m_rest:=size;
+
+end;
+
+END.
+