This is just CVector for arbitrary-sized array elements.
I know that we can store pointers to arbitrary things in the existing CVector array, but sometimes it's efficient to store arrays of structures.
This class will allow you to do so, although at the moment it uses RtlMoveMemory which may not be fastest.

Feedback appreciated :)



;Author - Homer
;Date - 13 July 2004
;Title - CArrayManager class
;Description -
;// This class manages an array of entries of arbitrary size.
;// By default it acts like CVector, with DWORD sized elements.
;// Use the SetElementSize method to set the elementsize to anything you choose.

class CArrayManager, ,C++ compatible
void SetElementSize:dwSize
void push_back:pData ;This method will store an entire struct to the array as a single element.
void pop_back:pReturn ;This method will return an entire data element to your receiving struct
void Find ;<-- Find element in array, return -1 or address of element in array
void Delete:dwIndex ;<-- Delete array element by index, array content is shifted back to fill gap
long pBase ;<-- This points to the BaseAddress of the array memory
long dwNextPlace ;<-- This holds offset to next empty write location
long cbSize ;<-- This holds the current size of the buffer in bytes
long dwElementSize
endclass

CArrayManager_SetElementSize proc dwSize:DWORD
m2m [ecx].CArrayManager.dwElementSize, dwSize
ret
CArrayManager_SetElementSize endp

CArrayManager_CArrayManager proc ;*** CONSTRUCTOR ***
mov eax,1024 ;Initialize the array @ 1024 bytes (256 dword entries)
mov [ecx].CArrayManager.cbSize,eax
mov [ecx].CArrayManager.pBase, malloc (eax)
mov [ecx].CArrayManager.dwElementSize,4 ;<--dword sized by default
ret
CArrayManager_CArrayManager endp

CArrayManager_$CArrayManager proc ;*** DESTRUCTOR ***
free [ecx].CArrayManager.pBase ;Release the array memory
ret
CArrayManager_$CArrayManager endp

CArrayManager_push_back proc pData:DWORD
mov ebx,[ecx].CArrayManager.pBase ;Calculate the address of the next empty place
mov eax,[ecx].CArrayManager.dwNextPlace ;in the array (=pBase+dwNextPlace)
add ebx,eax
pushad
invoke RtlMoveMemory,ebx,pData,[ecx].CArrayManager.dwElementSize ;Store the data at the next place in array
popad
add eax,[ecx].CArrayManager.dwElementSize
;mov [ecx].CArrayManager.dwNextPlace,eax ;Increment the NextPlace index
.if eax>=[ecx].CArrayManager.cbSize ;If we are out of bounds
add eax,[ecx].CArrayManager.dwElementSize ;Grow the array
mov [ecx].CArrayManager.cbSize,eax ;noting the new size
mov ebx,[ecx].CArrayManager.pBase
mov [ecx].CArrayManager.pBase, remalloc ([ecx].CArrayManager.pBase, eax)
.endif
mov eax,[ecx].CArrayManager.dwElementSize
add [ecx].CArrayManager.dwNextPlace,eax
ret
CArrayManager_push_back endp

CArrayManager_pop_back proc pReturn:DWORD
mov eax,[ecx].CArrayManager.dwElementSize
sub [ecx].CArrayManager.dwNextPlace,eax ;Decrement the NextPlace index
mov ebx,[ecx].CArrayManager.pBase ;Calculate the address of the last element
add ebx,[ecx].CArrayManager.dwNextPlace
pushad
invoke RtlMoveMemory,pReturn, ebx, [ecx].CArrayManager.dwElementSize
popad
invoke RtlZeroMemory,ebx,[ecx].CArrayManager.dwElementSize
ret
CArrayManager_pop_back endp

CArrayManager_Delete proc uses esi edi dwIndex:DWORD
mov edi,[ecx].CArrayManager.pBase
mov eax,dwIndex
mul [ecx].CArrayManager.dwElementSize
add edi,eax
add eax,[ecx].CArrayManager.dwElementSize
.while eax<[ecx].CArrayManager.cbSize
mov ebx,[ecx].CArrayManager.dwElementSize
add ebx,edi
pushad
invoke RtlMoveMemory,edi,ebx,[ecx].CArrayManager.dwElementSize
popad
add eax,[ecx].CArrayManager.dwElementSize
add edi,[ecx].CArrayManager.dwElementSize
.endw
mov eax,[ecx].CArrayManager.dwElementSize
sub [ecx].CArrayManager.dwNextPlace,eax
ret
CArrayManager_Delete endp

CArrayManager_Find proc pFind:DWORD
mov esi,pFind
mov ebx,[ecx].CArrayManager.pBase
.while ebx < [ecx].CArrayManager.dwNextPlace
push ebx
mov al,byte ptr[ebx]
.if byte ptr[esi]==al
mov ecx,[ecx].CArrayManager.dwElementSize
.while al==byte ptr[ebx] && ecx!=0
mov al,byte ptr[ebx]
inc esi
inc ebx
dec ecx
.endw
.if ecx==0
pop ebx
return ebx
.endif
.endif
pop ebx
add ebx,[ecx].CArrayManager.dwElementSize
add esi,[ecx].CArrayManager.dwElementSize
.endw
return -1
CArrayManager_Find endp
Posted on 2004-07-12 17:24:15 by Homer
I've added a useful function to CArrayManager.
It returns a pointer to the start of the Nth element in the managed array, based on the instance's internal elementsize.
This looks very tidy when addressing arrays when addressing messy double-dereferenced arrays and/or several arrays of varying element size, and looks especially tidy when used with pcall.

example:
pcall pBeer.GetPtrToNth, 11
will return in eax the address within the array memory where the 11th (zero-based) element begins, or it will return -1 meaning that the 11th (zero-based) element lays outside the currently used arrayspace.
Remember that since this class is derived from CVector that it has no theoretical array space limit - it grows on demand - also note that it does NOT shrink thereafter - only the "occupied" arrayspace shrinks.. the arrayspace is elastic, but it only stretches, it never contracts :)

CArrayManager_GetPtrToNth proc dwIndex:DWORD
mov eax,.CArrayManager.dwElementSize
mov ebx,cbSize
sub ebx,eax
mul dwIndex
.if eax>=ebx ;BoundsChecking - are we trying to read beyond occupied arraymem?
return -1
.endif
add eax,.CArrayManager.pBase
ret
CArrayManager_GetPtrToNth endp
Posted on 2004-07-13 04:04:05 by Homer