home *** CD-ROM | disk | FTP | other *** search
- {+------------------------------------------------------------
- | Unit Arrays
- |
- | Version: 1.0 Last modified: 04/18/95, 11:47:00
- | Author : P. Below
- | Project: Delphi common objects
- | Description:
- | This Unit implements a base class for resizeable array types
- | and a few specific derivatives for the common numeric types.
- |
- | The array classes in this unit are all limited to a maximum
- | of 64Kbytes of data. The size of the stored items determines
- | the maximal number of items. Errors will raise exceptions,
- | index overflow is only reported if range checking is on. The
- | index range of each class is 0..MaxIndex, MaxIndex is a property
- | of all class types.
- |
- | The classes have iterator methods similar to BP collections.
- | These iterators can optionally call Application.ProcessMessages
- | between rounds. This requires usage of the Forms Unit. Since
- | this would involve a tremendous overhead for non-VCL projects
- | the correspondig USes clause and the iterator code calling
- | Application.ProcessMessages is enclosed in $IFDEF DOEVENTS
- | blocks. If DOEVENTS is defined, the Forms unit will be used.
- | DOEVENTS IS UNDEFINED BY DEFAULT! You need to define this
- | symbol in your project to make use of the ability to process
- | messages inside iterator loops and recompile this unit!
- | The unit does not make any other use of VCL window objects.
- +------------------------------------------------------------}
- Unit Arrays;
-
- Interface
-
- Uses SysUtils, Classes;
-
- Const
- (* the following value is returned by the Find method if the passed
- value could not be found in the array *)
- NOT_FOUND = High( Cardinal );
- Type
-
- (* Our virtual array need a function of this type to sort themselves
- and search items. As usual the return type should be < 0 if
- item1 < item2, > 0 if item1 > item2 and 0 if both are equal.
- Note that the result is not limited to -1, 0, +1! This allows
- faster comparison. *)
- TCompareProc = Function ( Var item1, item2 ): Integer;
-
- (* these procedural types represent functions that can be called
- from one of the iterator method, like ForEach. Version for stand-
- alone procedure and for object methods are provided. *)
- TIterator = Procedure( Var Element; index: Cardinal );
- TLocator = Function( Var Element; index: Cardinal ): Boolean;
- TIteratorMethod = Procedure( Var Element; index: Cardinal ) of Object;
- TLocatorMethod = Function( Var Element;
- index: Cardinal ): Boolean of Object;
-
- (* This error is raised when Sort or Find are called and a compare proc
- has not been assigned *)
- ECompUndefined = Class( Exception );
- (* This error is raised when two class instances are not comaptible
- for an operation *)
- ETypeMismatch = Class( Exception );
- (* This error is raised if a textfile is too large to be loaded into
- a TPCharArray or TPStringArray *)
- EFileTooLarge = Class( Exception );
-
- TSortOrder = ( TS_NONE, TS_ASCENDING, TS_DESCENDING );
-
- (* these flags covern some of the behaviour of array methods *)
- TArrayFlags = ( AF_OwnsData, AF_AutoSize, AF_CanCompare,
- AF_User1, AF_User2, AF_User3, AF_User4, AF_User5,
- AF_User6, AF_User7, AF_User8, AF_User9, AF_User10,
- AF_User11, AF_User12 );
- TArrayFlagSet = Set of TArrayFlags;
-
- (* this notification is used by the store/load from textfile methods
- of the string/pchar array classes *)
- TProgressReporter = Function( pos, max: LongInt;
- Var retain: Boolean ): Boolean of Object;
-
- (* T64KArray is our base array class. It is limited to a single 64K
- segment for all items. *)
- T64KArray = Class( TPersistent )
- private
- FMemory: Pointer; (* pointer to item buffer *)
- FMemSize, (* allocated size of buffer in bytes *)
- FItemSize, (* size of individual item in bytes *)
- FMaxIndex: Cardinal; (* max valid index, zero-based *)
- FSortOrder : TSortOrder; (* true if array is considered sorted *)
- FCompareProc : TCompareProc; (* pointer to compare proc *)
- FFlags : TArrayFlagSet; (* ability flags *)
-
- Procedure DefineProperties(Filer: TFiler);
- override;
- Procedure AssignTo( Dest: TPersistent );
- override;
- Function GetMaxCapacity: Cardinal;
- Function GetCapacity: Cardinal;
-
- public
- Procedure SaveToFile( Const Filename: String );
- virtual;
- Procedure LoadFromFile( Const Filename: String );
- virtual;
- Procedure SaveToStream( Stream: TStream );
- virtual;
- Procedure LoadFromStream( Stream: TStream );
- virtual;
- Function GetItemPtr( index: Cardinal ): Pointer;
- Procedure PutItem( index: Cardinal; Var data );
- Procedure GetItem( index: Cardinal; Var data );
- Procedure InvalidateItems( atIndex, numItems: Cardinal );
- virtual;
- Function ValidIndex( index: Cardinal ): Boolean;
- Function ValidateBounds( atIndex: Cardinal;
- Var numItems: Cardinal): Boolean;
- Constructor Create( itemcount, itemsize: Cardinal ); virtual;
- Destructor Destroy; override;
- Procedure Zap; virtual;
- Function Clone: T64KArray;
- virtual;
- Procedure ReDim( newcount: Cardinal );
- virtual;
- Procedure Insert( Var Source; atIndex, numItems: Cardinal );
- virtual;
- Procedure Delete( atIndex, numItems: Cardinal );
- virtual;
- Procedure Append( Var Source; numItems: Cardinal );
- virtual;
- Procedure CopyFrom( Var Source; toIndex, numItems: Cardinal );
- virtual;
- Procedure CopyTo( Var Dest; fromIndex, numItems: Cardinal );
- virtual;
- Procedure BlockCopy( Source: T64KArray;
- fromIndex, toIndex, numitems: Cardinal );
- virtual;
- Procedure Sort( ascending: Boolean );
- virtual;
- Function Find( Var value ): Cardinal;
- virtual;
- Procedure ForEach( iterator: TIteratorMethod; processMsg: Boolean;
- intervall: Cardinal );
- Function FirstThat( locator: TLocatorMethod;
- processMsg: Boolean;
- intervall: Cardinal ): Pointer;
- Function LastThat(locator: TLocatorMethod;
- processMsg: Boolean;
- intervall: Cardinal ): Pointer;
- Procedure ForEachProc( iterator: TIterator; processMsg: Boolean;
- intervall: Cardinal );
- Function FirstThatProc( locator: TLocator;
- processMsg: Boolean;
- intervall: Cardinal ): Pointer;
- Function LastThatProc(locator: TLocator;
- processMsg: Boolean;
- intervall: Cardinal ): Pointer;
- Function GetCount: Cardinal; virtual;
- Procedure SetCompareProc( proc: TCompareProc );
-
- Function HasFlag( aFlag: TArrayFlags ): Boolean;
- Procedure SetFlag( aFlag: TArrayFlags );
- Procedure ClearFlag( aFlag: TArrayFlags );
-
- property Memory: Pointer read FMemory;
- property MemSize: Cardinal read FMemSize;
- property ItemSize: Cardinal read FItemSize;
- property MaxIndex: Cardinal read FMaxIndex;
- property Count: Cardinal read GetCount;
- property ItemPtr[ Index:Cardinal ]: Pointer read GetItemPtr;
- property SortOrder: TSortOrder read FSortOrder write FSortOrder;
- property CompareProc: TCompareProc read FCompareProc write SetCompareProc;
- property Capacity: Cardinal read GetCapacity;
- property MaxCapacity: Cardinal read GetMaxCapacity;
- property Flags: TArrayFlagSet read FFlags write FFlags;
- End;
- C64KArray= Class of T64KArray;
-
- (* Following are a couple of derived classes for the common numeric types.
- Access to items can be done via normal array syntax on the instance
- via the default array property. *)
- TIntegerArray = Class( T64KArray )
- public
- Constructor Create( itemcount, dummy: Cardinal ); override;
- Procedure PutData( index: Cardinal; value: Integer );
- Function GetData(index: Cardinal): Integer;
-
- property Data[ Index:Cardinal ]: Integer
- read GetData write PutData; default;
- End;
-
- TCardinalArray = Class( T64KArray )
- public
- Constructor Create( itemcount, dummy: Cardinal ); override;
- Procedure PutData( index: Cardinal; value: Cardinal );
- Function GetData(index: Cardinal): Cardinal;
-
- property Data[ Index:Cardinal ]: Cardinal
- read GetData write PutData; default;
- End;
-
- TLongIntArray = Class( T64KArray )
- public
- Constructor Create( itemcount, dummy: Cardinal ); override;
- Procedure PutData( index: Cardinal; value: LongInt );
- Function GetData(index: Cardinal): LongInt;
-
- property Data[ Index:Cardinal ]: LongInt
- read GetData write PutData; default;
- End;
-
- TRealArray = Class( T64KArray )
- public
- Constructor Create( itemcount, dummy: Cardinal ); override;
- Procedure PutData( index: Cardinal; value: Real );
- Function GetData(index: Cardinal): Real;
-
- property Data[ Index:Cardinal ]: Real
- read GetData write PutData; default;
- End;
-
- TSingleArray = Class( T64KArray )
- public
- Constructor Create( itemcount, dummy: Cardinal ); override;
- Procedure PutData( index: Cardinal; value: Single );
- Function GetData(index: Cardinal): Single;
-
- property Data[ Index: Cardinal ]: Single
- read GetData write PutData; default;
- End;
-
- TDoubleArray = Class( T64KArray )
- public
- Constructor Create( itemcount, dummy: Cardinal ); override;
- Procedure PutData( index: Cardinal; value: Double );
- Function GetData(index: Cardinal): Double;
-
- property Data[ Index: Cardinal ]: Double
- read GetData write PutData; default;
- End;
-
- TExtendedArray = Class( T64KArray )
- public
- Constructor Create( itemcount, dummy: Cardinal ); override;
- Procedure PutData( index: Cardinal; value: Extended );
- Function GetData(index: Cardinal): Extended;
-
- property Data[ Index:Cardinal ]: Extended
- read GetData write PutData; default;
- End;
-
- TPointerArray = Class( T64KArray )
- public
- Constructor Create( itemcount, dummy: Cardinal ); override;
- Procedure PutData( index: Cardinal; value: Pointer );
- Function GetData(index: Cardinal): Pointer;
- Procedure CopyFrom( Var Source; toIndex, numItems: Cardinal );
- override;
- Procedure CopyTo( Var Dest; fromIndex, numItems: Cardinal );
- override;
- Procedure InvalidateItems(atIndex, numItems: Cardinal);
- override;
- Function CloneItem( item: Pointer ): Pointer; virtual;
- Procedure FreeItem( item: Pointer ); virtual;
- Procedure SaveToFile( Const Filename: String );
- override;
- Procedure LoadFromFile( Const Filename: String );
- override;
- Procedure SaveToStream( Stream: TStream );
- override;
- Procedure LoadFromStream( Stream: TStream );
- override;
- Procedure SaveItemToStream( S: TStream; Item: Pointer );
- virtual;
- Procedure LoadItemFromStream( S: TStream; Var Item: Pointer );
- virtual;
-
- property AsPtr[ Index: Cardinal ]: Pointer
- read GetData write PutData;
- property Data[ Index: Cardinal ]: Pointer
- read GetData write PutData; (* NOT default here! *)
- End;
-
- TPCharArray = Class( TPointerArray )
- public
- Constructor Create( itemcount, dummy: Cardinal ); override;
- Procedure PutData( index: Cardinal; value: PChar );
- Function GetData(index: Cardinal): PChar;
-
- Function CloneItem( item: Pointer ): Pointer;
- override;
- Procedure FreeItem( item: Pointer );
- override;
- Procedure SaveItemToStream( S: TStream; Item: Pointer );
- override;
- Procedure LoadItemFromStream( S: TStream; Var Item: Pointer );
- override;
-
- Procedure PutAsString( index: Cardinal; Const value: String );
- Function GetAsString(index: Cardinal): String;
- Procedure PutAsInteger( index: Cardinal; value: LongInt );
- Function GetAsInteger(index: Cardinal): LongInt;
- Procedure PutAsReal( index: Cardinal; value: Extended );
- Function GetAsReal(index: Cardinal): Extended;
-
- Procedure LoadFromTextfile( Const Filename: String;
- appendData: Boolean;
- reporter: TProgressReporter );
- Procedure SaveToTextfile( Const Filename: String;
- appendData: Boolean;
- reporter: TProgressReporter );
-
- property Data[ Index: Cardinal ]: PChar
- read GetData write PutData; Default;
- property AsString[ Index: Cardinal ]: String
- read GetAsString write PutAsString;
- property AsInteger[ Index: Cardinal ]: LongInt
- read GetAsInteger write PutAsInteger;
- property AsReal[ Index: Cardinal ]: Extended
- read GetAsReal write PutAsReal;
-
- End;
-
- TPStringArray = Class( TPointerArray )
- public
- Constructor Create( itemcount, dummy: Cardinal ); override;
- Procedure PutData( index: Cardinal; Const value: String );
- Function GetData(index: Cardinal): String;
-
- Function CloneItem( item: Pointer ): Pointer;
- override;
- Procedure FreeItem( item: Pointer );
- override;
- Procedure SaveItemToStream( S: TStream; Item: Pointer );
- override;
- Procedure LoadItemFromStream( S: TStream; Var Item: Pointer );
- override;
- Function GetAsPtr(index: Cardinal): PString;
- Procedure PutAsPChar( index: Cardinal; value: PChar );
- Function GetAsPChar(index: Cardinal): PChar;
- Procedure PutAsInteger( index: Cardinal; value: LongInt );
- Function GetAsInteger(index: Cardinal): LongInt;
- Procedure PutAsReal( index: Cardinal; value: Extended );
- Function GetAsReal(index: Cardinal): Extended;
- Procedure LoadFromTextfile( Const Filename: String;
- appendData: Boolean;
- reporter: TProgressReporter );
- Procedure SaveToTextfile( Const Filename: String;
- appendData: Boolean;
- reporter: TProgressReporter );
-
- property Data[ Index: Cardinal ]: String
- read GetData write PutData; Default;
- property AsPChar[ Index: Cardinal ]: Pchar
- read GetAsPChar write PutAsPChar;
- property AsInteger[ Index: Cardinal ]: LongInt
- read GetAsInteger write PutAsInteger;
- property AsReal[ Index: Cardinal ]: Extended
- read GetAsReal write PutAsReal;
- property AsPString[ Index: Cardinal ]: PString
- read GetAsPtr;
- End;
-
- (* a couple of compare procedures as used by the numeric array classes *)
-
- Function CmpIntegers( Var item1, item2 ): Integer;
- Function CmpCardinals( Var item1, item2 ): Integer;
- Function CmpLongs( Var item1, item2 ): Integer;
- Function CmpReals( Var item1, item2 ): Integer;
- Function CmpSingles( Var item1, item2 ): Integer;
- Function CmpDoubles( Var item1, item2 ): Integer;
- Function CmpExtendeds( Var item1, item2 ): Integer;
- Function CmpPChars( Var item1, item2 ): Integer;
- Function CmpPStrings( Var item1, item2 ): Integer;
-
- Implementation
-
- {$IFDEF DOEVENTS}
- Uses Forms, FastMem, WinProcs;
- {$ELSE}
- Uses FastMem, WinProcs;
- {$ENDIF}
-
- Const
- (* This section defines the error messages for exceptions specific to
- the objects in this Unit. Translate as necessary. *)
-
- ErrAssign =
- 'T64KArray.AssignTo: Destination object does not match this array.';
- ErrLoad =
- 'T64KArray.LoadFromStream: The stored items have different size than'+
- ' this arrays items.';
- ErrCompare =
- 'T64KArray.Sort/Find: No comparision function has been assigned '+
- 'for this array object.';
- ErrIndex =
- 'T64KArray: Index %u out of bounds, maximum allowed is %u';
- ErrSegmentOverflow =
- 'T64KArray.ReDim: requested size > 64Kbyte!';
- ErrFileTooLarge =
- 'LoadFromTextfile: File %s has too many lines to load completely!';
-
- {+----------------------
- | Methods of T64KArray
- +----------------------}
- {************************************************************
- * T64KArray.DefineProperties
- *
- * Parameters:
- * Filer: a storage handler object
- * Description:
- * This methods prepares the object for streaming by telling the
- * Filer which methods to call for loading and storing the array
- * data.
- * Error Conditions:
- * none
- *
- *Created: 04/18/95 14:33:53 by P. Below
- ************************************************************}
- Procedure T64KArray.DefineProperties(Filer: TFiler);
- Begin
- inherited DefineProperties( Filer );
- Filer.DefineBinaryProperty( 'ArrayData', LoadFromStream,
- SaveToStream, FMemory <> Nil );
- End; { T64KArray.DefineProperties }
-
- {************************************************************
- * T64KArray.AssignTo
- *
- * Parameters:
- * Dest: the target object
- * Description:
- * This method copies the contents of this array to the destination
- * array, provided the destination is a descendant of T64KArray and
- * has the same component size. The destination array is redim'ed to
- * the same size as this array. The actual copy is performed by
- * the BlockCopy method, which a descendant class can override to
- * realize a deep copy, for instance, if the items stored in the
- * array are pointers.
- * Error Conditions:
- * This method will raise a EConvertError exception, if the type of
- * the destination does not match that of Self. It may also cause
- * a protection fault, if Dest ist Nil ( really stupid! ) or an out
- * of memory exception in ReDim.
- *
- *Created: 04/18/95 15:01:29 by P. Below
- ************************************************************}
- Procedure T64KArray.AssignTo( Dest: TPersistent );
- Var
- D: T64KArray absolute Dest;
- Begin
- If ( Dest Is ClassType ) and ( ItemSize = D.ItemSize ) Then Begin
- If D.MaxIndex < MaxIndex Then
- D.Redim( Succ( MaxIndex ) );
- D.BlockCopy( Self, 0, 0, Succ( maxIndex ));
- D.SortOrder := SortOrder;
- D.Flags := Flags;
- D.CompareProc := CompareProc;
- End { If }
- Else
- raise ETypeMismatch.Create( errAssign );
- End; { T64KArray.AssignTo }
-
- Function T64KArray.GetMaxCapacity: Cardinal;
- Begin
- Result := High( Cardinal ) div ItemSize;
- End; { T64KArray.GetMaxCapacity }
-
- Function T64KArray.GetCapacity: Cardinal;
- Begin
- Result := Succ( MaxIndex );
- End; { T64KArray.GetCapacity }
-
- {************************************************************
- * T64KArray.SaveToFile
- *
- * Parameters:
- * Filename: name of file to write
- * Description:
- * Saves the data in this array to a file. Only the array data
- * itself is written, neither the component size not the number
- * of items are stored! This makes it possible to access the file
- * as a File Of Component ( where Component is the type stored in
- * this array, not a Delphi Component!).
- * Error Conditions:
- * May raise a EInOutError exception if a file-related error occurs.
- *
- *Created: 05/01/95 16:09:08 by P. Below
- ************************************************************}
- Procedure T64KArray.SaveToFile( Const Filename: String );
- Var
- F: File;
- Begin
- AssignFile( F, Filename );
- Rewrite( F, ItemSize );
- try
- BlockWrite( F, FMemory^, Succ( MaxIndex ));
- finally
- CloseFile( F );
- end;
- End; { T64KArray.SaveToFile }
-
- {************************************************************
- * T64KArray.LoadFromFile
- *
- * Parameters:
- * Filename: name of file to load
- * Description:
- * Loads the contents of the requested file into the array, which
- * is redimensioned to fit the data.
- * For this to work smoothly the file should have been created
- * by the SaveToFile method of an array object of the same type
- * as this one and it must be < 64KBytes in size! If it is larger
- * only part of it will be read. If the items in the file do have
- * a different item size that this array assumes (a fact we cannot
- * check), the loaded data will propably come out as garbage!
- * Error Conditions:
- * May raise a EInOutError exception if a file-related error occurs.
- *
- *Created: 05/01/95 16:28:50 by P. Below
- ************************************************************}
- Procedure T64KArray.LoadFromFile( Const Filename: String );
- Var
- F: File;
- N: LongInt;
- Begin
- AssignFile( F, Filename );
- FileMode := fmOpenRead or fmShareDenyWrite;
- try
- Reset( F, ItemSize );
- N := FileSize( F );
- If (N*ItemSize) > LongInt( High( Cardinal )) Then
- N := High( Cardinal ) div ItemSize;
- Redim( N );
- BlockRead( F, FMemory^, Succ( MaxIndex ));
- finally
- FileMode := 2;
- CloseFile( F );
- end;
- End; { T64KArray.LoadFromFile }
-
- {************************************************************
- * T64KArray.SaveToStream
- *
- * Parameters:
- * Stream: an opened stream that takes the array data
- * Description:
- * This method stores the arrays item size and max index
- * (NOT the number of items!) followed by the array data into
- * the passed stream. NOTE that this is different from SaveToFile,
- * which only writes the array data!
- * You can use this method to append the array data to an open
- * stream that can already contain other data in front and receive
- * additional data after we are done here.
- * We do not stream the array object itself, only its data!
- * Error Conditions:
- * The stream may raise an exception if it runs into problems.
- *
- *Created: 05/01/95 16:53:49 by P. Below
- ************************************************************}
- Procedure T64KArray.SaveToStream( Stream: TStream );
- Var
- {$IFDEF WIN32}
- TempSize, TempIndex: Cardinal;
- {$ELSE}
- TempSize, TempIndex: LongInt;
- {$ENDIF}
- Begin
- TempSize := FItemSize;
- TempIndex := FMaxIndex;
- With Stream Do Begin
- Write( TempSize, Sizeof( TempSize ));
- Write( TempIndex, Sizeof( TempIndex ));
- Write( FMemory^, FMemSize );
- End; { With }
- End; { T64KArray.SaveToStream }
-
- {************************************************************
- * T64KArray.LoadFromStream
- *
- * Parameters:
- * Stream: an opened stream that holds the array data to read
- * Description:
- * This method reads the stored arrays item size and max index
- * and checks the item size vs. our own item size. If these two
- * do match, the array is redimensioned according to the needed
- * size and the array data are read from the passed stream.
- * NOTE that this is different from LoadFromFile, which only
- * reads the array data and assumes they have the right item size!
- * You can use this method to get the array data from an open
- * stream that can already contain other data in front and
- * additional data after. However, it is your responsibility
- * to position the stream pointer correctly.
- * Error Conditions:
- * The stream may raise an exception if it runs into problems.
- * We will raise an ETypeMismatch exception if the item size read
- * from the stream does not match our own item size.
- *
- *Created: 05/01/95 16:53:49 by P. Below
- ************************************************************}
- Procedure T64KArray.LoadFromStream( Stream: TStream );
- Var
- {$IFDEF WIN32}
- TempSize, TempIndex: Cardinal;
- {$ELSE}
- TempSize, TempIndex: LongInt;
- {$ENDIF}
- Begin
- Zap;
- With Stream Do Begin
- Read( TempSize, Sizeof( TempSize ));
- Read( TempIndex, Sizeof( TempIndex ));
- If TempSize = ItemSize Then Begin
- Redim( Succ( TempIndex ));
- Read( FMemory^, FMemSize );
- End { If }
- Else
- raise ETypeMismatch.Create( errLoad );
- End; { With }
- End; { T64KArray.LoadFromStream }
-
- {************************************************************
- * T64KArray.GetItemPtr
- *
- * Parameters:
- * index: index ( zero-based ) of the item to access
- * Returns:
- * a pointer to the requested item in this array
- * Description:
- * Does brute-force pointer arithmetic to calculate the
- * items address from index and size.
- * WARNING! Does no checks for FMemory=Nil!
- * Error Conditions:
- * If the passed index is out of range, the method will raise
- * an ERangeError exception, if range checking is enabled,
- * otherwise it returns a pointer to the first item in the
- * array.
- *
- *Created: 04/18/95 15:56:08 by P. Below
- ************************************************************}
- Function T64KArray.GetItemPtr( index: Cardinal ): Pointer;
- Begin
- Result := FMemory;
- If ValidIndex( index ) Then
- Inc( PtrRec( Result ).ofs, index*FItemSize )
- End; { T64KArray.GetItemPtr }
-
- {************************************************************
- * T64KArray.GetCount
- *
- * Parameters:
- * none
- * Returns:
- * the number of used items in the array
- * Description:
- * This method is used to implement the Count property. For
- * this class it acts like Capacity, because all items of the
- * array are considered in use. But for a descendant class that
- * works more like a BP collection, only part of the items
- * may be actually used. These classes can override GetCount to
- * return the actually used number. The Count property is used
- * by Sort, Find and the iterator methods to get the upper bound
- * of the range to operate on; these methods will thus work
- * without changes in collection-like descendants.
- * Error Conditions:
- * none
- *
- *Created: 05/20/95 18:07:46 by P. Below
- ************************************************************}
- Function T64KArray.GetCount: Cardinal;
- Begin
- Result := Succ( FMaxIndex )
- End;
-
- {************************************************************
- * T64KArray.PutItem
- *
- * Parameters:
- * data: a data item to put into the array, must have same
- * size as the arrays components.
- * index: index of array slot to put the data into ( zero-based )
- * Description:
- * Uses a direct mem copy to put the data into the array. No
- * error checks on type of the passed data are possible here!
- * NOTE:
- * The method obviously overwrites the old contents of the index
- * slot but it does _not_ invalidate the old entry! Thus this
- * method can be used by an InvalidateItems handler to set a
- * pointer to Nil.
- * Error Conditions:
- * If the index is out ouf bounds, does nothing.
- *
- *Created: 04/18/95 16:10:14 by P. Below
- ************************************************************}
- Procedure T64KArray.PutItem(index: Cardinal; Var data );
- Begin
- If ValidIndex( index ) Then Begin
- MemMove( @data, GetItemPtr( index ), FItemSize );
- SortOrder := TS_NONE;
- End;
- End; { T64KArray.PutItem }
-
- { Same as above, only on reverse gear }
- Procedure T64KArray.GetItem( index: Cardinal; Var data );
- Begin
- If ValidIndex( index ) Then
- MemMove( GetItemPtr( index ), @data, FItemSize );
- End; { T64KArray.GetItem }
-
- {************************************************************
- * T64KArray.Create
- *
- * Parameters:
- * itemcount: number of items the array should hold, cannot be
- * 0! 0 is mapped to 1.
- * itemsize : size in bytes of an individual item
- * Description:
- * Allocates the memory for the array and sets the fields
- * according to the passed data. In the Win16 version the
- * product of itemcount and itemsize has to be < 64Kbyte.
- * We reduce the itemcount to an allowed value, if necessary,
- * without raising any error if it is to large.
- * Error Conditions:
- * If GetMem fails we rely on the default exception handling to
- * fail the constructor.
- *
- *Created: 04/18/95 16:30:08 by P. Below
- ************************************************************}
- Constructor T64KArray.Create( itemcount, itemsize: Cardinal );
- {$IFNDEF WIN32}
- Var
- s: LongInt;
- {$ENDIF}
- Begin
- inherited Create;
- If itemcount = 0 Then Inc( itemcount );
- {$IFNDEF WIN32}
- s := LongInt( itemcount ) * itemsize;
- If s >= $10000 Then Begin
- (* user has math problems, be gracious and reduce itemcount
- to allowed value *)
- itemcount := $FFFF div itemsize;
- End; { If }
- {$ENDIF}
- FMemSize := itemcount * itemsize;
- GetMem( FMemory, FMemSize );
- MemFill( FMemory, FMemSize, 0 );
- FItemSize := itemsize;
- FMaxIndex := Pred( itemcount );
- FFlags := [ AF_OwnsData, AF_AutoSize ];
- End; { T64KArray.Create }
-
- {************************************************************
- * T64KArray.Destroy
- *
- * Parameters:
- * none
- * Description:
- * Standard destructor, frees the memory allocated for the array
- * and then calls the inherited destructor. We invalidate all used
- * items first.
- * Error Conditions:
- * none
- *
- *Created: 04/18/95 16:34:35 by P. Below
- ************************************************************}
- Destructor T64KArray.Destroy;
- Begin
- If FMemory <> Nil Then Begin
- InvalidateItems( 0, Count );
- FreeMem( FMemory, FMemSize );
- FMemSize := 0;
- FMaxIndex := 0;
- FItemSize := 0;
- End; { If }
- inherited Destroy;
- End; { T64KArray.Destroy }
-
- (* Invalidate all used items and fill the memory with 0 *)
- Procedure T64KArray.Zap;
- Begin
- InvalidateItems( 0, Count );
- MemFill( Memory, Capacity*ItemSize, 0 );
- End; { T64KArray.Zap }
-
- {************************************************************
- * T64KArray.Clone
- *
- * Parameters:
- * none
- * Returns:
- * Pointer to a freshly minted exact copy of this object
- * Description:
- * Creates a new object of the same type as this one is and
- * copies the arrays contents to the new object via AssignTo.
- * If the actual class type stores pointers to other stuff it
- * is the responsibility of that class to override the BlockCopy
- * method used by AssignTo to implement a deep copy.
- * Error Conditions:
- * Construction of the new object may fail due to out of memory.
- * The assign process may conceivably also fail, if it involves
- * a deep copy. If that happens, the raised exception is trapped,
- * the new object destroyed and the exception is reraised for
- * handling at an upper level.
- *
- *Created: 04/18/95 16:46:35 by P. Below
- ************************************************************}
- Function T64KArray.Clone: T64KArray;
- Var
- cI : C64KArray;
- Begin
- cI := C64KArray(Self.ClassType);
- Result := cI.Create( Succ( FMaxIndex ), FItemSize );
- try
- AssignTo( Result );
- except
- on EOutOfMemory Do Begin
- Result.Free;
- Result := Nil;
- raise
- end;
- end;
- End; { T64KArray.Clone }
-
- {************************************************************
- * T64KArray.ReDim
- *
- * Parameters:
- * newcount: number of items the new array should hold, cannot
- * be 0! 0 is mapped to 1.
- * Description:
- * Reallocates the array to a new size. The old items are
- * copied over, as far as possible. New slots are nulled out.
- * If the new array is smaller than the old one the extra
- * items are invalidated so a derived class can do cleanup
- * on them.
- * Error Conditions:
- * ReAllocMem, the RTL function used, may raise an out of memory
- * exception.
- * If compiled with debugging on ($D+) we will raise an ERangeError
- * exception, if the requested size is > 64K and we are compiling
- * for Win16.
- *
- *Created: 04/18/95 17:12:12 by P. Below
- ************************************************************}
- Procedure T64KArray.ReDim( newcount: Cardinal );
- {$IFNDEF WIN32}
- Var
- s: LongInt;
- {$ENDIF}
- Begin
- If newcount = 0 Then Inc( newcount );
- If newcount <> Succ( FMaxIndex ) Then Begin
- If newcount < Succ( FMaxIndex ) Then
- InvalidateItems( newcount, FMaxIndex-newcount+1 )
- {$IFNDEF WIN32}
- Else Begin
- s := LongInt( newcount ) * itemsize;
- If s >= $10000 Then Begin
- (* user has math problems, be gracious and reduce newcount
- to allowed value *)
- newcount := GetMaxCapacity;
- {$IFOPT D+}
- (* raise an exception, if compiled for debugging *)
- raise
- ERangeError.Create( ErrSegmentOverflow );
- {$ENDIF}
- End; { If }
- End
- {$ENDIF}
- ;
- FMemory := ReAllocMem( FMemory,
- Succ( FMaxIndex )*FItemSize,
- newcount * FItemSize );
- FMemSize := newcount* FItemSize;
- FMaxIndex := Pred( newcount );
- SortOrder := TS_NONE;
- End; { If }
- End; { T64KArray.ReDim }
-
- {************************************************************
- * T64KArray.InvalidateItems
- *
- * Parameters:
- * atIndex: index of first item about to be nuked
- * numItems: number of items effected
- * Description:
- * This method is called is items are about to be deleted from
- * the array. It does nothing for this class but descendants
- * storing pointers or objects may use it to perform cleanup
- * tasks for the items about to be deleted.
- * Error Conditions:
- * none
- *
- *Created: 04/19/95 16:48:42 by P. Below
- ************************************************************}
- Procedure T64KArray.InvalidateItems( atIndex, numItems: Cardinal );
- Begin
- { This is a NOP for this class }
- End; (* T64KArray.InvalidateItems *)
-
- {************************************************************
- * T64KArray.ValidIndex
- *
- * Parameters:
- * atIndex: an index value
- * Returns:
- * true if the index is in range, false otherwise
- * Description:
- * This method is used by a couple of others to validate an
- * index.
- * Error Conditions:
- * If Index is > MaxIndex the method will raise a ERangeError
- * exception, if range checking is on, or return false if range
- * checking is off.
- *
- *Created: 04/19/95 16:58:57 by P. Below
- ************************************************************}
- Function T64KArray.ValidIndex( Index: Cardinal ): Boolean;
- Begin
- Result := True;
- If Index > FMaxIndex Then Begin
- {$IFOPT R+}
- raise ERangeError.CreateFmt( ErrIndex, [ index, FMaxIndex ] );
- {$ENDIF}
- Result := False;
- End { If }
- End;
-
- {************************************************************
- * T64KArray.ValidateBounds
- *
- * Parameters:
- * atIndex: an index value
- * numItems: a item count value
- * Returns:
- * true if the index is in range, false otherwise
- * Description:
- * This method is used by a couple of others to validate an
- * index and make sure that numItems is not higher than the
- * number of items from position atIndex on to the end of array.
- * Error Conditions:
- * If atIndex is > MaxIndex the method will raise a ERangeError
- * exception, if range checking is on, or return false if range
- * checking is off.
- *
- * If the numItem parameter is larger than the number of items
- * present after position atIndex (inclusive) it is adjusted to
- * the maximal number of items possible.
- *
- *
- *Created: 04/19/95 16:58:57 by P. Below
- ************************************************************}
- Function T64KArray.ValidateBounds( atIndex: Cardinal;
- Var numItems: Cardinal): Boolean;
- Begin
- Result := ValidIndex( atIndex );
- If Result Then
- If ( numItems > Succ( FMaxIndex )) or
- (( maxIndex-numItems+1 ) < atIndex ) Then
- numItems := FMaxIndex - atIndex + 1;
- End; (* T64KArray.ValidateBounds *)
-
-
- {************************************************************
- * T64KArray.Insert
- *
- * Parameters:
- * Source : the source of the new items to insert
- * atIndex: index to insert the new items at
- * numItems: number of items to insert
- * Description:
- * This method inserts the passed items, moving all items from
- * position atIndex and up numItems positions upwards. The array
- * grows as needed, if the ability flag AF_AutoSize is set.
- * If it cannot grow ( enough ), items may fall off
- * the end! If atIndex is beyond the end of array, Append is used.
- * Error Conditions:
- * If the method is asked to insert more items than can fit, the
- * numItems parameter is adjusted to the maximal number of items
- * possible without an exception beeing raised. Redim is used to
- * grow the array, to EOutOfMemory is a distinct posibility.
- *
- *Created: 04/19/95 16:03:29 by P. Below
- ************************************************************}
- Procedure T64KArray.Insert( Var Source; atIndex, numItems: Cardinal );
- Var
- oldCapacity, itemsToMove, moveTargetIndex, lostItems: Cardinal;
- Begin
- If numItems = 0 Then
- Exit;
-
- (* check 1: if AtIndex is beyond the end of array, we effectively
- do an append! *)
- If atIndex > MaxIndex Then Begin
- Append( Source, numItems );
- Exit;
- End; { If }
-
- oldCapacity := Capacity;
-
- (* resize the array, this may not succeed completely if the array
- would need to grow > 64K in Win16! In that case it will grow
- to the maximal possible size. *)
- If HasFlag( AF_AutoSize ) Then
- Redim( oldCapacity+numItems );
-
- (* check2: correct numItems downwards, if the array could not been
- grown to the required size. Note one pathological case here: if
- the original atIndex was > MaxIndex AND the array was already
- at maximal size, we will run into an invalid index error on the
- next statement and end up doing nothing! *)
- If ValidateBounds( atIndex, numItems ) Then Begin
-
- (* move the items after the insertion point up to make room for
- the new items. *)
- itemsToMove := oldCapacity - atIndex;
- If itemsToMove > 0 Then Begin
- moveTargetIndex := atIndex + numItems;
- (* Note: ValidateBounds makes sure that moveTargetIndex is at
- max MaxIndex+1 ( =Capacity )! *)
-
- (* check 3: if any items fall off at the end, invalidate them
- and reduce the number to move accordingly. *)
- If ( Capacity - moveTargetIndex ) < itemsToMove Then Begin
- lostItems := itemsToMove + moveTargetIndex - Capacity;
- InvalidateItems( atIndex + itemsToMove-lostItems, lostItems );
- itemsToMove := itemsToMove - lostItems;
- End; { If }
-
- (* move the items beyond the end of insertion range up *)
- MemMove( GetItemPtr( atIndex ),
- GetItemPtr( moveTargetIndex ),
- itemsToMove * ItemSize );
- (* now null out the places where we will put the new items.
- this is necessary to prevent the InvalidateItems call for
- these items CopyFrom will do from barfing, if the items
- are pointers, for example. *)
- MemFill( GetItemPtr( atIndex ), numItems*ItemSize, 0 );
- End; { If }
- (* move the items to insert into the array *)
- CopyFrom( Source, atIndex, numItems );
- End; { If }
- End; { T64KArray.Insert }
-
- {************************************************************
- * T64KArray.Delete
- *
- * Parameters:
- * atIndex: index to start deleting items
- * numItems: number of items to delete
- * Description:
- * This method deletes items by moving all items above the
- * requested range down numItems slots and redims the array
- * to the smaller size, if the ability flag AF_AutoSize is set.
- * The deleted items are invalidated first,
- * so descendant class storing pointers or objects can free the storage
- * for the deleted items or do other cleanup tasks, as appropriate.
- * Error Conditions:
- * If atIndex is > MaxIndex the method will raise a ERangeError
- * exception, if range checking is on, or do nothing if range
- * checking is off.
- *
- * If the method is asked to delete more items than there are, the
- * numItems parameter is adjusted to the maximal number of items
- * possible without an exception beeing raised.
- *
- *Created: 04/19/95 16:37:34 by P. Below
- ************************************************************}
- Procedure T64KArray.Delete( atIndex, numItems: Cardinal );
- Begin
- If numItems = 0 Then
- Exit;
- If ValidateBounds( atIndex, numItems ) Then Begin
- (* invalidate the items about to be deleted so a derived class
- can do cleanup on them. *)
- InvalidateItems( atIndex, numItems );
-
- (* move the items above those we delete down, if there are any *)
- If ( atIndex+numItems ) <= MaxIndex Then
- MemMove( GetItemPtr( atIndex+numItems ),
- GetItemPtr( atIndex ),
- ( maxIndex-atIndex-numItems+1 )*ItemSize );
- (* null out the now free slots *)
- MemFill( GetItemPtr( MaxIndex-numItems+1 ),
- numItems*ItemSize, 0 );
- If HasFlag( AF_AutoSize ) Then
- Redim( Capacity - numItems );
- End; { If }
- End; { T64KArray.Delete }
-
- {************************************************************
- * T64KArray.Append
- *
- * Parameters:
- * Source : the source of the new items to append
- * numItems: number of items to append
- * Description:
- * This method appends the passed items. The array
- * grows as needed. If it cannot grow enough, not all items may be
- * copied! Note that this method is independant of the settings
- * of the AF_AutoSize ability flag!
- * Error Conditions:
- * If the method is asked to append more items than can fit, the
- * numItems parameter is adjusted to the maximal number of items
- * possible without an exception beeing raised. Redim may raise
- * an EOutOfMemory exception.
- *
- *Created: 04/19/95 16:03:29 by P. Below
- ************************************************************}
- Procedure T64KArray.Append( Var Source; numItems: Cardinal );
- Var
- n: Cardinal;
- Begin
- n := Capacity;
- Redim( n+numItems );
- CopyFrom( Source, n, numItems );
- End; { T64KArray.Append }
-
- {************************************************************
- * T64KArray.CopyFrom
- *
- * Parameters:
- * Source: source of the items to be copied
- * toIndex: index for the first copied item
- * numItems: number of items to copy
- * Description:
- * This methods overwrites the next numItems items in this array
- * starting at position toIndex with items from the Source. The
- * overwritten items are invalidated first.
- * Error Conditions:
- * If toIndex is > MaxIndex the method will raise a ERangeError
- * exception, if range checking is on, or do nothing if range
- * checking is off. If the Source memory contains less than the
- * specified number of items to copy a protection fault may result.
- *
- * If the method is asked to copy more items than will fit, the
- * numItems parameter is adjusted to the maximal number of items
- * possible without an exception beeing raised.
- *
- *
- *Created: 04/19/95 17:14:49 by P. Below
- ************************************************************}
- Procedure T64KArray.CopyFrom( Var Source; toIndex, numItems: Cardinal );
- Begin
- If numItems = 0 Then
- Exit;
- If ValidateBounds( toIndex, numItems ) Then Begin
- (* invalidate the items about to be overwritten so a derived class
- can do cleanup on them. *)
- InvalidateItems( toIndex, numItems );
-
- (* do the copy *)
- MemMove( @Source,
- GetItemPtr(toIndex ),
- numItems*ItemSize );
- SortOrder := TS_NONE;
- End; { If }
- End; { T64KArray.CopyFrom }
-
- {************************************************************
- * T64KArray.CopyTo
- *
- * Parameters:
- * Dest: memory to copy items to
- * fromIndex: index of first item to copy
- * numItems: number of items to copy
- * Description:
- * This method copies items from this array to a memory target.
- * WARNING!
- * This may be a problem if the copied items are pointers or
- * objects, since this is a shallow copy and the result will
- * be several references to the same memory locations! A derived
- * class may have to override this method to deal with this problem.
- * Error Conditions:
- * If fromIndex is > MaxIndex the method will raise a ERangeError
- * exception, if range checking is on, or do nothing if range
- * checking is off. If the Dest memory can hold less than the
- * specified number of items to copy a protection fault may result.
- *
- * If the method is asked to copy more items than there are, the
- * numItems parameter is adjusted to the maximal number of items
- * possible without an exception beeing raised.
- *
- *Created: 04/19/95 17:19:07 by P. Below
- ************************************************************}
- Procedure T64KArray.CopyTo( Var Dest; fromIndex, numItems: Cardinal );
- Begin
- If numItems = 0 Then
- Exit;
- If ValidateBounds( fromIndex, numItems ) Then Begin
- MemMove( GetItemPtr( fromIndex ), @Dest,
- numItems*ItemSize );
- End; { If }
- End; { T64KArray.CopyTo }
-
- {************************************************************
- * T64KArray.BlockCopy
- *
- * Parameters:
- * Source: an array object instance to copy items from
- * fromIndex: index in source of first item to copy
- * toIndex: index in self to copy the first item to
- * numitems: number of items to copy
- * Description:
- * Uses CopyFrom to do the actual copy process after doing a
- * few sanity checks on the source. CopyFrom does the checks
- * on the target. The numitems count may be reduced if either
- * the source does not have that many items or Self cannot take
- * them.
- * Error Conditions:
- * Will raise a ETypeMismatch exception if the Source object is
- * not of the same or a derived type as Self and also if it has
- * a different item size. ERangeError exceptions may be raised
- * by called methods.
- *
- *Created: 04/19/95 17:57:41 by P. Below
- ************************************************************}
- Procedure T64KArray.BlockCopy( Source: T64KArray;
- fromIndex, toIndex, numitems: Cardinal );
- Begin
- If numitems = 0 Then
- Exit;
- If ( Source Is ClassType ) and ( ItemSize = Source.ItemSize ) Then
- Begin
- If Source.ValidateBounds( fromIndex, numItems ) Then
- CopyFrom( Source.GetItemPtr( fromIndex )^, toIndex, numItems )
- End
- Else
- raise ETypeMismatch.Create( ErrAssign );
- End; { T64KArray.BlockCopy }
-
- {************************************************************
- * T64KArray.Sort
- *
- * Parameters:
- * ascending: defines whether to sort in ascending or descending
- * order
- * Description:
- * This method implements a recursive QuickSort. It can only
- * do its work if a comparison function has been assigned to
- * the FCompareProc field. Since this is a generic procedure
- * to sort any kind of data, it is possible to get a much
- * better performance for specific data types by reimplementing
- * the Sort for this type.
- * Error Conditions:
- * Will raise a ECompUndefined exception if no comparison function
- * has been defined. Them method may also run out of memory
- * in GetMem while allocating the pivot data buffer.
- *
- *Created: 04/22/95 16:02:24 by P. Below
- ************************************************************}
- Procedure T64KArray.Sort( ascending: Boolean );
- Procedure QSort( L, R: Cardinal );
- Var
- i, j: Cardinal;
- pPivot: Pointer;
- Begin
- i:= L;
- j:= R;
- GetMem( pPivot, ItemSize );
- try
- GetItem( ( L+R ) div 2, pPivot^ );
- Repeat
- If ascending Then Begin
- While FCompareProc( GetItemPtr( i )^, pPivot^ ) < 0 Do
- Inc( i );
- While FCompareProc( pPivot^, GetItemPtr( j )^ ) < 0 Do
- Dec( j );
- End { If }
- Else Begin
- While FCompareProc( GetItemPtr( i )^, pPivot^ ) > 0 Do
- Inc( i );
- While FCompareProc( pPivot^, GetItemPtr( j )^ ) > 0 Do
- Dec( j );
- End; { Else }
- If i <= j Then Begin
- MemSwap( GetItemPtr( i ), GetItemPtr( j ), ItemSize );
- Inc( i );
- If j > 0 Then Dec( j );
- End; { If }
- Until i > j ;
- If L < j Then QSort( L, j );
- If i < R Then QSort( i, R );
- finally
- FreeMem( pPivot, ItemSize );
- end;
- End; { QSort }
- Begin { Sort }
- (* do we have anything to do? *)
- If ( Count = 0 ) or not HasFlag( AF_CanCompare ) Then
- Exit;
- If ascending Then
- If ( SortOrder = TS_ASCENDING ) Then Exit
- Else
- Else
- If ( SortOrder = TS_DESCENDING ) Then Exit;
-
- (* ok, _can_ we do it? *)
- If @FCompareProc <> Nil Then Begin
- QSort( 0, Pred( Count ));
- If ascending Then
- SortOrder := TS_ASCENDING
- Else
- SortOrder := TS_DESCENDING;
- End
- Else
- raise ECompUndefined.Create( ErrCompare );
- End; { T64KArray.Sort }
-
- {************************************************************
- * T64KArray.Find
- *
- * Parameters:
- * value: item to search for in the array
- * Returns:
- * index of found item or NOT_FOUND when the value is not in array.
- * Description:
- * Depending on the sort state of the array this Function will do
- * a binary or sequential search thru the array, using the
- * comparison function supplied in FCompareProc to compare value
- * to the current item.
- * WARNING!
- * If the list is sorted and contains multiple instances of the same
- * value, the search will not necessarily find the _first_ instance
- * of this value! This is a general shortcome of binary search; set
- * SortOrder to TS_NONE before the search to force sequential search
- * if the array contains multiple copies of the same value.
- *
- * Like for the Sort method descendants may gain a considerable
- * improvement in performance if they reimplement this method with
- * optimized data access and comparison.
- * Error Conditions:
- * Will raise a ECompUndefined exception if no comparison function
- * has been defined.
- *
- *
- *Created: 04/22/95 16:31:13 by P. Below
- ************************************************************}
- Function T64KArray.Find( Var value ): Cardinal;
- Function LinearSearch: Cardinal;
- Var
- i: Cardinal;
- p: Pointer;
- Begin
- Result := NOT_FOUND;
- p := FMemory;
- For i:= 0 To Pred( Count ) Do Begin
- If FCompareProc( value, p^ ) = 0 Then Begin
- Result := i;
- Break;
- End; { If }
- Inc( PtrRec( p ).ofs, ItemSize );
- End; { For }
- End; { LinearSearch }
- Function BinarySearch: Cardinal;
- Var
- u,l,i: Cardinal;
- n : Integer;
- asc : Boolean;
- Begin
- Result := NOT_FOUND;
- l := 0;
- u := Pred( Count );
- asc := SortOrder = TS_ASCENDING;
- While l <= u Do Begin
- i := ( l+u ) div 2;
- n := FCompareProc( value, GetItemPtr( i )^);
- If n = 0 Then Begin
- Result := i;
- Break;
- End;
- If l = u Then
- Break;
- If asc xor ( n < 0 )Then
- l := i
- Else
- u := i;
- End; { While }
- End; { BinarySearch }
-
- Begin { Find }
- Result := NOT_FOUND;
- If ( Count = 0 ) or not HasFlag( AF_CanCompare ) Then
- Exit;
- If @FCompareProc <> Nil Then Begin
- If SortOrder = TS_NONE Then
- Result := LinearSearch
- Else
- Result := BinarySearch;
- End
- Else
- raise ECompUndefined.Create( ErrCompare );
- End; { T64KArray.Find }
-
- {************************************************************
- * T64KArray.ForEach
- *
- * Parameters:
- * iterator: an object method adhering to the TIteratorMethod
- * prototype defined in the Interface.
- * processMsg: this flag deterimines whether the method will
- * call Application.ProcessMessages inside the iterator
- * loop
- * intervall: determines how often ProcessMessages is called, a
- * higher number means messages will be processed less
- * often since the method uses (index mod intervall)=0
- * as trigger to call ProcessMessages.
- * Description:
- * The method loops over all entries of the array and passes the
- * address of each with its index to the iterator method.
- * If processMsg = True, the method will call ProcessMessages on each
- * intervall'th round of the loop. Note that this only happens when
- * this Unit has been compiled with the symbol DOEVENTS defined!
- * Error Conditions:
- * The method has no error conditions per se but horrible things will
- * happen if you call it with a Nil iterator since we do not check
- * for this condition!
- *
- *Created: 04/22/95 17:07:27 by P. Below
- ************************************************************}
- Procedure T64KArray.ForEach( iterator: TIteratorMethod; processMsg: Boolean;
- intervall: Cardinal );
- Var
- i: Cardinal;
- p: Pointer;
- Begin
- p := FMemory;
- For i:= 0 To Pred( Count ) Do Begin
- Iterator( p^, i );
- Inc( PtrRec( p ).ofs, ItemSize );
- {$IFDEF DOEVENTS}
- If processMsg and (( i mod intervall ) = 0) Then
- Application.ProcessMessages;
- {$ENDIF}
- End; { For }
- End; { T64KArray.ForEach }
-
- {************************************************************
- * T64KArray.FirstThat
- *
- * Parameters:
- * locator: an object method adhering to the TLocatorMethod
- * prototype defined in the Interface.
- * processMsg: this flag determines whether the method will
- * call Application.ProcessMessages inside the iterator
- * loop
- * intervall: determines how often ProcessMessages is called, a
- * higher number means messages will be processed less
- * often since the method uses (index mod intervall)=0
- * as trigger to call ProcessMessages.
- * Returns:
- * The address of the item for which the locator returned True, or
- * Nil if it returned False for all items.
- * Description:
- * The method loops over all entries of the array and passes the
- * address of each with its index to the locator method. The loop
- * terminates immediately when the locator method returns True.
- * If processMsg = True, the method will call ProcessMessages on each
- * intervall'th round of the loop. Note that this only happens when
- * this Unit has been compiled with the symbol DOEVENTS defined!
- * Error Conditions:
- * The method has no error conditions per se but horrible things will
- * happen if you call it with a Nil locator since we do not check
- * for this condition!
- *
- *Created: 04/22/95 17:07:27 by P. Below
- ************************************************************}
- Function T64KArray.FirstThat( locator: TLocatorMethod;
- processMsg: Boolean;
- intervall: Cardinal ): Pointer;
- Var
- i: Cardinal;
- p: Pointer;
- Begin
- Result := Nil;
- p := FMemory;
- For i:= 0 To Pred( Count ) Do Begin
- If Locator( p^, i ) Then Begin
- Result := p;
- Break
- End;
- Inc( PtrRec( p ).ofs, ItemSize );
- {$IFDEF DOEVENTS}
- If processMsg and (( i mod intervall ) = 0) Then
- Application.ProcessMessages;
- {$ENDIF}
- End; { For }
- End; { T64KArray.FirstThat }
-
- {************************************************************
- * T64KArray.LastThat
- *
- * Parameters:
- * locator: an object method adhering to the TLocatorMethod
- * prototype defined in the Interface.
- * processMsg: this flag determines whether the method will
- * call Application.ProcessMessages inside the iterator
- * loop
- * intervall: determines how often ProcessMessages is called, a
- * higher number means messages will be processed less
- * often since the method uses (index mod intervall)=0
- * as trigger to call ProcessMessages.
- * Returns:
- * The address of the item for which the locator returned True, or
- * Nil if it returned False for all items.
- * Description:
- * The method loops over all entries of the array, starting with the
- * last item working backwards, and passes the
- * address of each with its index to the locator method. The loop
- * terminates immediately when the locator method returns True.
- * If processMsg = True, the method will call ProcessMessages on each
- * intervall'th round of the loop. Note that this only happens when
- * this Unit has been compiled with the symbol DOEVENTS defined!
- * Error Conditions:
- * The method has no error conditions per se but horrible things will
- * happen if you call it with a Nil locator since we do not check
- * for this condition!
- *
- *Created: 04/22/95 17:07:27 by P. Below
- ************************************************************}
- Function T64KArray.LastThat(locator: TLocatorMethod;
- processMsg: Boolean;
- intervall: Cardinal ): Pointer;
- Var
- i: Cardinal;
- p: Pointer;
- Begin
- Result := Nil;
- p := GetItemPtr( Pred( Count ) );
- For i:= Pred( Count ) DownTo 0 Do Begin
- If Locator( p^, i ) Then Begin
- Result := p;
- Break
- End;
- Dec( PtrRec( p ).ofs, ItemSize );
- {$IFDEF DOEVENTS}
- If processMsg and (( i mod intervall ) = 0) Then
- Application.ProcessMessages;
- {$ENDIF}
- End; { For }
- End; { T64KArray.LastThat }
-
- {************************************************************
- * T64KArray.ForEachProc
- *
- * Parameters:
- * iterator: a Procedure adhering to the TIterator
- * prototype defined in the Interface.
- * processMsg: this flag deterimines whether the method will
- * call Application.ProcessMessages inside the iterator
- * loop
- * intervall: determines how often ProcessMessages is called, a
- * higher number means messages will be processed less
- * often since the method uses (index mod intervall)=0
- * as trigger to call ProcessMessages.
- * Description:
- * The method loops over all entries of the array and passes the
- * address of each with its index to the iterator method.
- * If processMsg = True, the method will call ProcessMessages on each
- * intervall'th round of the loop. Note that this only happens when
- * this Unit has been compiled with the symbol DOEVENTS defined!
- * Error Conditions:
- * The method has no error conditions per se but horrible things will
- * happen if you call it with a Nil iterator since we do not check
- * for this condition!
- *
- *Created: 04/22/95 17:07:27 by P. Below
- ************************************************************}
- Procedure T64KArray.ForEachProc( iterator: TIterator; processMsg: Boolean;
- intervall: Cardinal );
- Var
- i: Cardinal;
- p: Pointer;
- Begin
- p := FMemory;
- For i:= 0 To Pred( Count ) Do Begin
- Iterator( p^, i );
- Inc( PtrRec( p ).ofs, ItemSize );
- {$IFDEF DOEVENTS}
- If processMsg and (( i mod intervall ) = 0) Then
- Application.ProcessMessages;
- {$ENDIF}
- End; { For }
- End; { T64KArray.ForEachProc }
-
- {************************************************************
- * T64KArray.FirstThatProc
- *
- * Parameters:
- * locator: a Function adhering to the TLocator
- * prototype defined in the Interface.
- * processMsg: this flag determines whether the method will
- * call Application.ProcessMessages inside the iterator
- * loop
- * intervall: determines how often ProcessMessages is called, a
- * higher number means messages will be processed less
- * often since the method uses (index mod intervall)=0
- * as trigger to call ProcessMessages.
- * Returns:
- * The address of the item for which the locator returned True, or
- * Nil if it returned False for all items.
- * Description:
- * The method loops over all entries of the array and passes the
- * address of each with its index to the locator method. The loop
- * terminates immediately when the locator method returns True.
- * If processMsg = True, the method will call ProcessMessages on each
- * intervall'th round of the loop. Note that this only happens when
- * this Unit has been compiled with the symbol DOEVENTS defined!
- * Error Conditions:
- * The method has no error conditions per se but horrible things will
- * happen if you call it with a Nil locator since we do not check
- * for this condition!
- *
- *Created: 04/22/95 17:07:27 by P. Below
- ************************************************************}
- Function T64KArray.FirstThatProc( locator: TLocator;
- processMsg: Boolean;
- intervall: Cardinal ): Pointer;
- Var
- i: Cardinal;
- p: Pointer;
- Begin
- Result := Nil;
- p := FMemory;
- For i:= 0 To Pred( Count ) Do Begin
- If Locator( p^, i ) Then Begin
- Result := p;
- Break
- End;
- Inc( PtrRec( p ).ofs, ItemSize );
- {$IFDEF DOEVENTS}
- If processMsg and (( i mod intervall ) = 0) Then
- Application.ProcessMessages;
- {$ENDIF}
- End; { For }
- End; { T64KArray.FirstThatProc }
-
- {************************************************************
- * T64KArray.LastThatProc
- *
- * Parameters:
- * locator: a Function adhering to the TLocator
- * prototype defined in the Interface.
- * processMsg: this flag determines whether the method will
- * call Application.ProcessMessages inside the iterator
- * loop
- * intervall: determines how often ProcessMessages is called, a
- * higher number means messages will be processed less
- * often since the method uses (index mod intervall)=0
- * as trigger to call ProcessMessages.
- * Returns:
- * The address of the item for which the locator returned True, or
- * Nil if it returned False for all items.
- * Description:
- * The method loops over all entries of the array, starting with the
- * last item working backwards, and passes the
- * address of each with its index to the locator method. The loop
- * terminates immediately when the locator method returns True.
- * If processMsg = True, the method will call ProcessMessages on each
- * intervall'th round of the loop. Note that this only happens when
- * this Unit has been compiled with the symbol DOEVENTS defined!
- * Error Conditions:
- * The method has no error conditions per se but horrible things will
- * happen if you call it with a Nil locator since we do not check
- * for this condition!
- *
- *Created: 04/22/95 17:07:27 by P. Below
- ************************************************************}
- Function T64KArray.LastThatProc(locator: TLocator;
- processMsg: Boolean;
- intervall: Cardinal ): Pointer;
- Var
- i: Cardinal;
- p: Pointer;
- Begin
- Result := Nil;
- p := GetItemPtr( Pred( Count ) );
- For i:= Pred( Count ) DownTo 0 Do Begin
- If Locator( p^, i ) Then Begin
- Result := p;
- Break
- End;
- Dec( PtrRec( p ).ofs, ItemSize );
- {$IFDEF DOEVENTS}
- If processMsg and (( i mod intervall ) = 0) Then
- Application.ProcessMessages;
- {$ENDIF}
- End; { For }
- End; { T64KArray.LastThatProc }
-
- Procedure T64KArray.SetCompareProc( proc: TCompareProc );
- Begin
- FCompareProc := proc;
- If @proc = Nil Then
- ClearFlag( AF_CanCompare )
- Else
- SetFlag( AF_CanCompare );
- End; { T64KArray.SetCompareProc }
-
- (* The following methods manipulate the FFlags set of array
- 'abilites'. *)
- Function T64KArray.HasFlag( aFlag: TArrayFlags ): Boolean;
- Begin
- Result := aFlag In Flags;
- End; { T64KArray.HasFlag }
-
- Procedure T64KArray.SetFlag( aFlag: TArrayFlags );
- Begin
- Include( FFLags, aFlag );
- End; { T64KArray.SetFlag }
-
- Procedure T64KArray.ClearFlag( aFlag: TArrayFlags );
- Begin
- Exclude( FFLags, aFlag );
- End; { T64KArray.ClearFlag }
-
-
-
- {+--------------------------
- | Methods of TIntegerArray
- +-------------------------}
- Type
- TIArray =Array[ 0..High( Cardinal ) div Sizeof( Integer )-1 ] of Integer;
- PIArray = ^TIArray;
- Constructor TIntegerArray.Create( itemcount, dummy: Cardinal );
- Begin
- inherited Create( itemcount, Sizeof( integer ));
- CompareProc := CmpIntegers;
- End; { TIntegerArray.Create }
-
- Procedure TIntegerArray.PutData( index: Cardinal ; value: Integer );
- Begin
- {$IFOPT R+}
- If ValidIndex( index ) Then Begin
- {$ENDIF}
- PIArray( FMemory )^[ index ] := value;
- SortOrder := TS_NONE;
- {$IFOPT R+}
- End;
- {$ENDIF}
- End; { TIntegerArray.PutData }
-
- Function TIntegerArray.GetData(index: Cardinal): Integer;
- Begin
- {$IFOPT R+}
- If ValidIndex( index ) Then
- {$ENDIF}
- Result := PIArray( FMemory )^[ index ];
- End; { TIntegerArray.GetData }
-
- {+---------------------------
- | Methods of TCardinalArray
- +--------------------------}
- Type
- TCArray =Array[ 0..High( Cardinal ) div Sizeof( Cardinal )-1 ] of Cardinal;
- PCArray = ^TCArray;
- Constructor TCardinalArray.Create( itemcount, dummy: Cardinal );
- Begin
- inherited Create( itemcount, Sizeof( Cardinal ));
- CompareProc := CmpCardinals;
- End; { TCardinalArray.Create }
-
- Procedure TCardinalArray.PutData( index: Cardinal ; value: Cardinal );
- Begin
- {$IFOPT R+}
- If ValidIndex( index ) Then Begin
- {$ENDIF}
- PCArray( FMemory )^[ index ] := value;
- SortOrder := TS_NONE;
- {$IFOPT R+}
- End;
- {$ENDIF}
- End; { TCardinalArray.PutData }
-
- Function TCardinalArray.GetData(index: Cardinal): Cardinal;
- Begin
- {$IFOPT R+}
- If ValidIndex( index ) Then
- {$ENDIF}
- Result := PCArray( FMemory )^[ index ];
- End; { TCardinalArray.GetData }
-
- {+---------------------------
- | Methods of TLongIntArray
- +--------------------------}
- Type
- TLArray = Array[ 0..High( Cardinal ) div Sizeof( LongInt )-1 ] of LongInt;
- PLArray = ^TLArray;
- Constructor TLongIntArray.Create( itemcount, dummy: Cardinal );
- Begin
- inherited Create( itemcount, Sizeof( LongInt ));
- CompareProc := CmpLongs;
- End; { TLongIntArray.Create }
-
- Procedure TLongIntArray.PutData( index: Cardinal ; value: LongInt );
- Begin
- {$IFOPT R+}
- If ValidIndex( index ) Then Begin
- {$ENDIF}
- PLArray( FMemory )^[ index ] := value;
- SortOrder := TS_NONE;
- {$IFOPT R+}
- End;
- {$ENDIF}
- End; { TLongIntArray.PutData }
-
- Function TLongIntArray.GetData(index: Cardinal): LongInt;
- Begin
- {$IFOPT R+}
- If ValidIndex( index ) Then
- {$ENDIF}
- Result := PLArray( FMemory )^[ index ];
- End; { TLongIntArray.GetData }
-
- {+-----------------------
- | Methods of TRealArray
- +----------------------}
- Type
- TRArray = Array[ 0..High( Cardinal ) div Sizeof( Real )-1 ] of Real;
- PRArray = ^TRArray;
- Constructor TRealArray.Create( itemcount, dummy: Cardinal );
- Begin
- inherited Create( itemcount, Sizeof( Real ));
- CompareProc := CmpReals;
- End; { TRealArray.Create }
-
- Procedure TRealArray.PutData( index: Cardinal ; value: Real );
- Begin
- {$IFOPT R+}
- If ValidIndex( index ) Then Begin
- {$ENDIF}
- PRArray( FMemory )^[ index ] := value;
- SortOrder := TS_NONE;
- {$IFOPT R+}
- End;
- {$ENDIF}
- End; { TRealArray.PutData }
-
- Function TRealArray.GetData(index: Cardinal): Real;
- Begin
- {$IFOPT R+}
- If ValidIndex( index ) Then
- {$ENDIF}
- Result := PRArray( FMemory )^[ index ];
- End; { TRealArray.GetData }
-
- {+-------------------------
- | Methods of TSingleArray
- +------------------------}
- Type
- TSArray = Array[ 0..High( Cardinal ) div Sizeof( Single )-1 ] of Single;
- PSArray = ^TSArray;
- Constructor TSingleArray.Create( itemcount, dummy: Cardinal );
- Begin
- inherited Create( itemcount, Sizeof( Single ));
- CompareProc := CmpSingles;
- End; { TSingleArray.Create }
-
- Procedure TSingleArray.PutData( index: Cardinal ; value: Single );
- Begin
- {$IFOPT R+}
- If ValidIndex( index ) Then Begin
- {$ENDIF}
- PSArray( FMemory )^[ index ] := value;
- SortOrder := TS_NONE;
- {$IFOPT R+}
- End;
- {$ENDIF}
- End; { TSingleArray.PutData }
-
- Function TSingleArray.GetData(index: Cardinal): Single;
- Begin
- {$IFOPT R+}
- If ValidIndex( index ) Then
- {$ENDIF}
- Result := PSArray( FMemory )^[ index ];
- End; { TSingleArray.GetData }
-
- {+-------------------------
- | Methods of TDoubleArray
- +------------------------}
- Type
- TDArray = Array[ 0..High( Cardinal ) div Sizeof( Double )-1 ] of Double;
- PDArray = ^TDArray;
- Constructor TDoubleArray.Create( itemcount, dummy: Cardinal );
- Begin
- inherited Create( itemcount, Sizeof( Double ));
- CompareProc := CmpDoubles;
- End; { TDoubleArray.Create }
-
- Procedure TDoubleArray.PutData( index: Cardinal ; value: Double );
- Begin
- {$IFOPT R+}
- If ValidIndex( index ) Then Begin
- {$ENDIF}
- PDArray( FMemory )^[ index ] := value;
- SortOrder := TS_NONE;
- {$IFOPT R+}
- End;
- {$ENDIF}
- End; { TDoubleArray.PutData }
-
- Function TDoubleArray.GetData(index: Cardinal): Double;
- Begin
- {$IFOPT R+}
- If ValidIndex( index ) Then
- {$ENDIF}
- Result := PDArray( FMemory )^[ index ];
- End; { TDoubleArray.GetData }
-
- {+---------------------------
- | Methods of TExtendedArray
- +--------------------------}
- Type
- TEArray = Array[ 0..High( Cardinal ) div Sizeof( Extended )-1 ] of Extended;
- PEArray = ^TEArray;
- Constructor TExtendedArray.Create( itemcount, dummy: Cardinal );
- Begin
- inherited Create( itemcount, Sizeof( Extended ));
- CompareProc := CmpExtendeds;
- End; { TExtendedArray.Create }
-
- Procedure TExtendedArray.PutData( index: Cardinal ; value: Extended );
- Begin
- {$IFOPT R+}
- If ValidIndex( index ) Then Begin
- {$ENDIF}
- PEArray( FMemory )^[ index ] := value;
- SortOrder := TS_NONE;
- {$IFOPT R+}
- End;
- {$ENDIF}
- End; { TExtendedArray.PutData }
-
- Function TExtendedArray.GetData(index: Cardinal): Extended;
- Begin
- {$IFOPT R+}
- If ValidIndex( index ) Then
- {$ENDIF}
- Result := PEArray( FMemory )^[ index ];
- End; { TExtendedArray.GetData }
-
- {+--------------------------
- | Methods of TPointerArray
- +-------------------------}
- Type
- TPArray = Array [ 0..High( Cardinal ) div Sizeof( Pointer )-1 ] Of Pointer;
- PPArray = ^TPArray;
-
- Constructor TPointerArray.Create( itemcount, dummy: Cardinal );
- Begin
- inherited Create( itemcount, Sizeof( Pointer ));
- Flags := [ AF_AutoSize ];
- (* no comparison function can be assigned here since we do not
- even know how large the memory areas are our pointers point to.
- by default the array will also not own the data it collects. *)
- End; { TPointerArray.Create }
-
- {************************************************************
- * TPointerArray.CopyFrom
- *
- * Parameters:
- * Source: source of the items to be copied
- * toIndex: index for the first copied item
- * numItems: number of items to copy
- * Description:
- * This methods overwrites the next numItems items in this array
- * starting at position toIndex with _copies_ (hopefully) of items
- * from the Source. The overwritten items are invalidated first.
- * The actual copy is done item by item with calls to the CloneItem
- * method. The version provided with this calls will only do a shallow
- * copy ( it has no idea about what the pointer point to ), so you
- * should derive your own class with an overriden CloneItem method
- * to get a deep copy.
- * Error Conditions:
- * If toIndex is > MaxIndex the method will raise a ERangeError
- * exception, if range checking is on, or do nothing if range
- * checking is off. If the Source memory contains less than the
- * specified number of items to copy a protection fault may result.
- *
- * If the method is asked to copy more items than will fit, the
- * numItems parameter is adjusted to the maximal number of items
- * possible without an exception beeing raised.
- *
- *
- *Created: 05/28/95 21:14:49 by P. Below
- ************************************************************}
- Procedure TPointerArray.CopyFrom( Var Source; toIndex, numItems: Cardinal );
- Var
- i: Cardinal;
- p: PPArray;
- arr: TPArray absolute Source;
- Begin
- If numItems = 0 Then
- Exit;
- If ValidateBounds( toIndex, numItems ) Then Begin
- (* invalidate the items about to be overwritten so a derived class
- can do cleanup on them. *)
- InvalidateItems( toIndex, numItems );
-
- p := PPArray( Memory );
- For i:= 0 To Pred( numItems ) Do
- p^[ toIndex+i ] := CloneItem( arr[ i ] );
- SortOrder := TS_NONE;
- End; { If }
- End; { TPointerArray.CopyFrom }
-
- {************************************************************
- * TPointerArray.CopyTo
- *
- * Parameters:
- * Dest: memory to copy items to
- * fromIndex: index of first item to copy
- * numItems: number of items to copy
- * Description:
- * This method copies items from this array to a memory target.
- * The items are copied one after the other using the CloneItem
- * method. The version in this class does only a shallow copy
- * (copies the pointer), since it has no idea what the pointers
- * point to. You should override CloneItem in derived classes to
- * get a deep copy.
- * Error Conditions:
- * If fromIndex is > MaxIndex the method will raise a ERangeError
- * exception, if range checking is on, or do nothing if range
- * checking is off. If the Dest memory can hold less than the
- * specified number of items to copy a protection fault may result.
- *
- * If the method is asked to copy more items than there are, the
- * numItems parameter is adjusted to the maximal number of items
- * possible without an exception beeing raised.
- *
- *Created: 05/28/95 21:19:07 by P. Below
- ************************************************************}
- Procedure TPointerArray.CopyTo( Var Dest; fromIndex, numItems: Cardinal );
- Var
- i: Cardinal;
- p: PPArray;
- arr: TPArray absolute Dest;
- Begin
- If numItems = 0 Then
- Exit;
- If ValidateBounds( fromIndex, numItems ) Then Begin
- p := PPArray( Memory );
- For i:= 0 To Pred( numItems ) Do
- arr[ i ] := CloneItem( p^[ fromIndex+i ] );
- End; { If }
- End; { TPointerArray.CopyTo }
-
- (* PutData implements the write access via the default Data property.
- It first frees the pointer at index and then stores a pointer to
- a _copy_ of the passed data into that slot. *)
- Procedure TPointerArray.PutData( index: Cardinal ; value: Pointer );
- Begin
- If ValidIndex( index ) Then Begin
- If ( PPArray( Memory )^[ index ] <> Nil ) and HasFlag( AF_OwnsData )
- Then
- FreeItem( PPArray( Memory )^[ index ] );
- PPArray( Memory )^[ index ] := CloneItem( value );
- SortOrder := TS_NONE;
- End;
- End; { TPointerArray.PutData }
-
- (* returns pointer in slot index, or Nil, if the index is invalid. *)
- Function TPointerArray.GetData(index: Cardinal): Pointer;
- Begin
- If ValidIndex( index ) Then
- Result := PPArray( Memory )^[ index ]
- Else
- Result := Nil;
- End; { TPointerArray.GetData }
-
- Procedure TPointerArray.FreeItem( item: Pointer );
- Begin
- (* this is a nop for this class since we do not know what item
- points to *)
- End; { TPointerArray.FreeItem }
-
- (* calls FreeItem of each of the items in range and sets the item
- to nil *)
- Procedure TPointerArray.InvalidateItems(atIndex, numItems: Cardinal);
- Var
- n: Cardinal;
- p: Pointer;
- Begin
- If (numItems > 0) and HasFlag( AF_OwnsData ) Then
- If ValidateBounds( atIndex, numItems ) Then
- For n := atIndex To Pred( numItems+atIndex ) Do Begin
- p:= AsPtr[ n ];
- If p <> Nil Then Begin
- FreeItem( p );
- p := Nil;
- PutItem(n, p);
- End;
- End; { For }
- End; { TPointerArray.InvalidateItems }
-
- (* this version of CloneItem does nothing since we have no info on
- the memory item points to. A descendent class would override this
- method to provide a deep copy of item *)
- Function TPointerArray.CloneItem( item: Pointer ): Pointer;
- Begin
- Result := item;
- End; { TPointerArray.CloneItem }
-
- (* since we need to save at least the number of items in the array in
- addition to the data we take the easy way out and realize file
- save via stream. *)
- Procedure TPointerArray.SaveToFile( Const Filename: String );
- Var
- S: TFileStream;
- Begin
- S:= TFileStream.Create( Filename, fmCreate );
- try
- SaveToStream( S );
- finally
- S.Free
- end;
- End; { TPointerArray.SaveToFile }
-
- Procedure TPointerArray.LoadFromFile( Const Filename: String );
- Var
- S: TFileStream;
- Begin
- S:= TFileStream.Create( Filename, fmOpenRead or fmShareDenyWrite );
- try
- LoadFromStream( S );
- finally
- S.Free
- end;
- End; { TPointerArray.LoadFromFile }
-
- (* write first the size of the array then call SaveItemToStream for
- each item *)
- Procedure TPointerArray.SaveToStream( Stream: TStream );
- Var
- {$IFDEF WIN32}
- temp: Cardinal;
- {$ELSE}
- temp: LongInt;
- {$ENDIF}
- n: Cardinal;
- Begin
- temp := Count;
- With Stream Do Begin
- Write( temp, Sizeof( temp ));
- For n := 0 To MaxIndex Do Begin
- SaveItemToStream( Stream, AsPtr[ n ] );
- End; { For }
- End; { With }
- End; { TPointerArray.SaveToStream }
-
- Procedure TPointerArray.LoadFromStream( Stream: TStream );
- Var
- {$IFDEF WIN32}
- temp: Cardinal;
- {$ELSE}
- temp: LongInt;
- {$ENDIF}
- n: Cardinal;
- P: Pointer;
- Begin
- With Stream Do Begin
- Read( temp, Sizeof( temp ));
- InvalidateItems( 0, Count );
- Redim( temp );
- For n := 0 To MaxIndex Do Begin
- LoadItemfromStream( Stream, P );
- (* we use PutItem here because otherwise we would end up
- with a _copy_ of the data in P^ beeing stored, if
- CopyItem implements deep copy! *)
- PutItem( n, P );
- End; { For }
- End; { With }
- End; { TPointerArray.LoadFromStream }
-
- Procedure TPointerArray.SaveItemToStream( S: TStream; Item: Pointer );
- Begin
- raise
- Exception.Create(
- 'Call to abstract method: TPointerArray.SaveItemToStream');
- (* depends on data stored *)
- End; { TPointerArray.SaveItemToStream }
-
- Procedure TPointerArray.LoadItemFromStream( S: TStream; Var Item: Pointer );
- Begin
- raise
- Exception.Create(
- 'Call to abstract method: TPointerArray.LoadItemFromStream');
- End; { TPointerArray.LoadItemFromStream }
-
- {+--------------------------
- | Methods of TPcharArray
- +-------------------------}
- Constructor TPcharArray.Create( itemcount, dummy: Cardinal );
- Begin
- inherited Create( itemcount, Sizeof( Pointer ));
- Flags := [ AF_OwnsData, AF_AutoSize, AF_CanCompare ];
- CompareProc := CmpPChars;
- End; { TPcharArray.Create }
-
- Procedure TPcharArray.PutData( index: Cardinal; value: PChar );
- Begin
- inherited PutData( index, Pointer( value ));
- End; { TPcharArray.PutData }
-
- Function TPcharArray.GetData(index: Cardinal): PChar;
- Begin
- Result := inherited GetData( index );
- End; { TPcharArray.GetData }
-
- Function TPcharArray.CloneItem( item: Pointer ): Pointer;
- Begin
- If HasFlag( AF_OwnsData ) Then
- If item <> Nil Then
- Result := StrNew( item )
- Else
- Result := Nil
- Else
- Result := item;
- End; { TPcharArray.CloneItem }
-
- Procedure TPcharArray.FreeItem( item: Pointer );
- Begin
- If HasFlag( AF_OwnsData ) Then
- StrDispose( item );
- End; { TPcharArray.FreeItem }
-
- Procedure TPcharArray.SaveItemToStream( S: TStream; Item: Pointer );
- Var
- pStr: PChar absolute Item;
- len: Cardinal;
- Begin
- (* we write the pchar with length in front and including the
- terminating zero! *)
- If item = Nil Then
- len := 0
- else
- len := StrLen( pStr );
- S.Write( len, Sizeof( Len ));
- If len > 0 Then
- S.Write( pStr^, len+1 );
- End; { TPcharArray.SaveItemToStream }
-
- Procedure TPcharArray.LoadItemFromStream( S: TStream; Var Item: Pointer );
- Var
- len: Cardinal;
- Begin
- S.Read( len, Sizeof( len ));
- If len > 0 Then Begin
- Item := StrAlloc( len+1 );
- S.Read( Item^, len+1 );
- End { If }
- Else
- Item := Nil;
- End; { TPcharArray.LoadItemFromStream }
-
- Procedure TPcharArray.PutAsString( index: Cardinal; Const value: String );
- Var
- pStr: PChar;
- Begin
- pStr := StrAlloc( Length( value )+1 );
- try
- StrPCopy( pStr, value );
- FreeItem( GetData( index ));
- PutItem( index, pStr );
- except
- StrDispose( pStr );
- raise
- end;
- End; { TPcharArray.PutAsString }
-
- Function TPcharArray.GetAsString(index: Cardinal): String;
- Var
- pStr: PChar;
- Begin
- pStr := GetData( index );
- If pStr <> Nil Then
- Result := StrPas( pStr )
- Else
- Result := EmptyStr;
- End; { TPcharArray.GetAsString }
-
- Procedure TPcharArray.PutAsInteger( index: Cardinal; value: LongInt );
- Begin
- PutAsString( index, IntToStr( value ));
- End; { TPcharArray.PutAsInteger }
-
- Function TPcharArray.GetAsInteger(index: Cardinal): LongInt;
- Begin
- try
- Result := StrToInt( GetAsString( index ));
- except
- Result := 0
- end;
- End; { TPcharArray.GetAsInteger }
-
- Procedure TPcharArray.PutAsReal( index: Cardinal; value: Extended );
- Begin
- PutAsString( index, FloatToStr( value ));
- End; { TPcharArray.PutAsReal }
-
- Function TPcharArray.GetAsReal(index: Cardinal): Extended;
- Begin
- try
- Result := StrToFloat( GetAsString( index ));
- except
- Result := 0.0
- end;
- End; { TPcharArray.GetAsReal }
-
- Function GetFileSize( Const Filename: String): LongInt;
- Var
- SRec: TSearchRec;
- Begin
- If FindFirst( Filename, faAnyfile, SRec ) = 0 Then
- Result := SRec.Size
- Else
- Result := 0;
- FindClose(SRec);
- End;
-
- Procedure TPcharArray.LoadFromTextfile( Const Filename: String;
- appendData: Boolean;
- reporter: TProgressReporter );
- Type
- TLine = Array [ 0..$8000 ] Of Char;
- TBuf = Array [ 0..$3fff ] of Char;
- Var
- pBuf: ^TBuf;
- F: TextFile;
- lines, currpos: Cardinal;
- line: ^TLine;
- fsize, sum: LongInt;
- retain: Boolean;
- Begin
- (* open file for read *)
- fsize := GetFilesize(Filename);
- If fsize = 0 Then Exit;
-
- AssignFile( F, Filename );
- pBuf := Nil;
- New(pBuf);
- try
- System.SetTextBuf( F, pBuf^, Sizeof( pBuf^ ));
- Reset( F );
- line := Nil;
- try
- New( line );
- (* prepare array by blasting all items in it if we are not
- asked to append the new data, set currpos to the first
- index we put new data in *)
- If not appendData Then Begin
- Zap;
- currpos := 0;
- End { If }
- Else
- currpos := Count;
- (* get a very rough estimate of the number of lines in the file *)
- If (LongInt(MaxCapacity)*20) < FSize Then
- lines := MaxCapacity
- Else
- lines := FSize div 20;
-
- (* resize the array so the new lines will ( hopefully ) fit without
- to many redims in between *)
- If appendData Then
- Redim( Count+lines )
- Else
- Redim( lines );
-
- (* now start reading lines *)
- sum := 0;
- While not Eof( F ) Do Begin
- ReadLn( F, line^ );
- If currpos = Capacity Then
- If currpos = MaxCapacity Then
- raise EFileTooLarge.CreateFmt( ErrFileTooLarge, [filename] )
- Else
- Redim( Capacity+100 );
- PutData( currpos, PChar(line) );
- If @reporter <> Nil Then Begin
- sum := sum+StrLen( PChar(line) )+2;
- If not reporter( sum, fsize, retain ) Then Begin
- If not retain Then
- Delete( 0, currpos+1 );
- Break;
- End;
- End;
- Inc( currpos );
- End; { While }
- If currpos < Capacity Then
- Redim( currpos );
- finally
- CloseFile( F );
- If line <> Nil Then
- Dispose( line );
- end;
- finally
- Dispose( pBuf );
- end;
- End; { TPcharArray.LoadFromTextfile }
-
- Procedure TPcharArray.SaveToTextfile( Const Filename: String;
- appendData: Boolean;
- reporter: TProgressReporter );
- Type
- TBuf = Array [ 0..$3fff ] of Char;
- Var
- pBuf: ^TBuf;
- F: TextFile;
- n: Cardinal;
- total, sum: LongInt;
- retain: Boolean;
- p: PChar;
- Begin
- (* calculate total size of text to save, including CR-LF lineends *)
- total := 0;
- For n := 0 To Count-1 Do Begin
- p := Data[ n ];
- If p <> Nil Then
- total := total + StrLen( p ) + 2
- Else
- Inc( total, 2 ); (* nil strings produce an empty line in the file *)
- End; { For }
- (* assign the file and give it a text buffer to speed up file I/O *)
- AssignFile( F, Filename );
- pBuf := Nil;
- New(pBuf);
- try
- System.SetTextBuf( F, pBuf^, Sizeof( pBuf^ ));
- (* open the file *)
- If appendData Then
- System.Append( F )
- Else
- System.Rewrite( F );
- try
- (* write the text *)
- sum := 0;
- retain := True;
- For n := 0 To Count-1 Do Begin
- p := Data[ n ];
- If p <> Nil Then
- WriteLn( F, p )
- Else
- WriteLn( F );
- (* report progress if someone is listening *)
- If @reporter <> Nil Then Begin
- If p <> Nil Then
- sum := sum+StrLen( p )+2
- Else
- Inc( sum, 2 );
- If not reporter( sum, total, retain ) Then
- break;
- End; { If }
- End; { For }
- finally
- CloseFile( F );
- If not retain Then
- Erase( F );
- end;
- finally
- Dispose( pBuf );
- end;
- End; { TPcharArray.SaveToTextfile }
-
- {+--------------------------
- | Methods of TPStringArray
- +-------------------------}
- Constructor TPStringArray.Create( itemcount, dummy: Cardinal );
- Begin
- inherited Create( itemcount, Sizeof( Pointer ));
- Flags := [ AF_OwnsData, AF_AutoSize, AF_CanCompare ];
- CompareProc := CmpPStrings;
- End; { TPStringArray.Create }
-
- Procedure TPStringArray.PutData( index: Cardinal; Const value: String );
- Begin
- inherited PutData( index, @value )
- End; { TPStringArray.PutData }
-
- Function TPStringArray.GetData(index: Cardinal): String;
- Var
- p: Pointer;
- Begin
- p := inherited GetData( index );
- If p = Nil Then
- Result := EmptyStr
- Else
- Result := PString( p )^;
- End; { TPStringArray.GetData }
-
- Function TPStringArray.GetAsPtr(index: Cardinal): PString;
- Begin
- Result := PString( inherited GetData( index ));
- End; { TPStringArray.GetAsPtr }
-
-
- Function TPStringArray.CloneItem( item: Pointer ): Pointer;
- Begin
- If HasFlag( AF_OwnsData ) Then
- If item <> Nil Then
- Result := NewStr( PString( item )^ )
- Else
- Result := Nil
- Else
- Result := item;
- End; { TPStringArray.CloneItem }
-
- Procedure TPStringArray.FreeItem( item: Pointer );
- Begin
- If HasFlag( AF_OwnsData ) Then
- DisposeStr( PString( item ));
- End; { TPStringArray.FreeItem }
-
- Procedure TPStringArray.SaveItemToStream( S: TStream; Item: Pointer );
- Var
- len: Cardinal;
- Begin
- If item = Nil Then
- len := 0
- else
- len := Length( PString( item )^ );
- If len > 0 Then
- S.Write( Item^, len+1 )
- Else
- S.Write( len, 1 );
- End; { TPStringArray.SaveItemToStream }
-
- Procedure TPStringArray.LoadItemFromStream( S: TStream; Var Item: Pointer );
- Var
- Str : String;
- Begin
- S.Read( Str, 1 );
- If Length( Str ) > 0 Then
- S.Read( Str[ 1 ], Length( Str ));
- Item := NewStr( Str );
- End; { TPStringArray.LoadItemFromStream }
-
- Procedure TPStringArray.PutAsPChar( index: Cardinal; value: PChar );
- Begin
- If value = Nil Then
- PutData( index, EmptyStr )
- Else
- PutData( index, StrPas( value ));
- End; { TPStringArray.PutAsPChar }
-
- Function TPStringArray.GetAsPChar(index: Cardinal): PChar;
- Var
- pStr: PString;
- Begin
- pStr := GetAsPtr( index );
- If pStr = Nil Then
- Result := Nil
- Else Begin
- Result := StrAlloc( Length( pStr^ )+1 );
- StrPCopy( Result, pStr^ );
- End;
- End; { TPStringArray.GetAsPChar }
-
- Procedure TPStringArray.PutAsInteger( index: Cardinal; value: LongInt );
- Begin
- PutData( index, IntToStr( value ));
- End; { TPStringArray.PutAsInteger }
-
- Function TPStringArray.GetAsInteger(index: Cardinal): LongInt;
- Begin
- try
- Result := StrToInt( GetData( index ));
- except
- Result := 0;
- end;
- End; { TPStringArray.GetAsInteger }
-
- Procedure TPStringArray.PutAsReal( index: Cardinal; value: Extended );
- Begin
- PutData( index, FloatToStr( value ));
- End; { TPStringArray.PutAsReal }
-
- Function TPStringArray.GetAsReal(index: Cardinal): Extended;
- Begin
- try
- Result := StrToFloat( GetData( index ));
- except
- Result := 0.0;
- end;
- End; { TPStringArray.GetAsReal }
-
- Procedure TPStringArray.LoadFromTextfile( Const Filename: String;
- appendData: Boolean;
- reporter: TProgressReporter );
- Type
- TBuf = Array [ 0..$3fff ] of Char;
- Var
- pBuf: ^TBuf;
- F: TextFile;
- lines, currpos: Cardinal;
- line: String;
- fsize: LongInt;
- sum: LongInt;
- retain: Boolean;
- Begin
- (* open file for read *)
- fsize := GetFilesize(Filename);
- If fsize = 0 Then Exit;
-
- AssignFile( F, Filename );
- pBuf := Nil;
- New(pBuf);
- try
- System.SetTextBuf( F, pBuf^, Sizeof( pBuf^ ));
- Reset( F );
- try
- (* prepare array by blasting all items in it if we are not
- asked to append the new data, set currpos to the first
- index we put new data in *)
- If not appendData Then Begin
- Zap;
- currpos := 0;
- End { If }
- Else
- currpos := Count;
-
- (* get a very rough estimate of the number of lines in the file. *)
- If (LongInt(MaxCapacity)*20) < FSize Then
- lines := MaxCapacity
- Else
- lines := FSize div 20;
-
- (* resize the array so the new lines will ( hopefully ) fit without
- to many redims in between *)
- If appendData Then
- Redim( Count+lines )
- Else
- Redim( lines );
-
- (* now start reading lines *)
- sum := 0;
- While not Eof( F ) Do Begin
- ReadLn( F, line );
- If currpos = Capacity Then
- If currpos = MaxCapacity Then
- raise EFileTooLarge.CreateFmt( ErrFileTooLarge, [filename] )
- Else
- Redim( Capacity+100 );
- PutData( currpos, line );
- If @reporter <> Nil Then Begin
- sum := sum+Length( line )+2;
- If not reporter( sum, fsize, retain ) Then Begin
- If not retain Then
- Delete( 0, currpos+1 );
- Break;
- End;
- End;
- Inc( currpos );
- End; { While }
- If currpos < Capacity Then
- Redim( currpos );
- finally
- CloseFile( F );
- end;
- finally
- Dispose(pBuf);
- end;
- End; { TPStringArray.LoadFromTextfile }
-
- Procedure TPStringArray.SaveToTextfile( Const Filename: String;
- appendData: Boolean;
- reporter: TProgressReporter );
- Type
- TBuf = Array [ 0..$3fff ] of Char;
- Var
- pBuf: ^TBuf;
- F: TextFile;
- n: Cardinal;
- total, sum: LongInt;
- retain: Boolean;
- p: PString;
- Begin
- (* calculate total size of text to save, including CR-LF lineends *)
- total := 0;
- For n := 0 To Count-1 Do Begin
- p := AsPString[n];
- If p <> Nil Then
- total := total + Length( p^ ) + 2
- Else
- Inc( total, 2 ); (* nil strings produce an empty line in the file *)
- End; { For }
- AssignFile( F, Filename );
- pBuf := Nil;
- New(pBuf);
- try
- System.SetTextBuf( F, pBuf^, Sizeof( pBuf^ ));
- If appendData Then
- System.Append( F )
- Else
- System.Rewrite( F );
- try
- (* write the text *)
- sum := 0;
- retain := True;
- For n := 0 To Count-1 Do Begin
- p := AsPString[n];
- If p <> Nil Then
- WriteLn( F, p^ )
- Else
- WriteLn( F );
- (* report progress if someone is listening *)
- If @reporter <> Nil Then Begin
- If p <> Nil Then
- sum := sum+Length( p^ )+2
- Else
- Inc( sum, 2 );
- If not reporter( sum, total, retain ) Then
- break;
- End; { If }
- End; { For }
- finally
- CloseFile( F );
- If not retain Then
- Erase( F );
- end;
- finally
- Dispose( pBuf );
- end;
- End; { TPStringArray.SaveToTextfile }
- {+----------------------
- | Auxillary procedures
- +----------------------}
- Function CmpIntegers( Var item1, item2 ): Integer;
- Var
- i1: Integer absolute item1;
- i2: Integer absolute item2;
- Begin
- Result := i1-i2;
- End;
-
- Function CmpCardinals( Var item1, item2 ): Integer;
- Var
- i1: Cardinal absolute item1;
- i2: Cardinal absolute item2;
- Begin
- If i1 < i2 Then
- Result := -1
- Else
- If i1 > i2 Then
- Result := 1
- Else
- Result := 0;
- End;
-
- Function CmpLongs( Var item1, item2 ): Integer;
- Var
- i1: LongInt absolute item1;
- i2: LongInt absolute item2;
- Begin
- If i1 < i2 Then
- Result := -1
- Else
- If i1 > i2 Then
- Result := 1
- Else
- Result := 0;
- End;
-
- Function CmpReals( Var item1, item2 ): Integer;
- Var
- i1: Real absolute item1;
- i2: Real absolute item2;
- r: Real;
- Begin
- r := i1-i2;
- If Abs( r ) < 1.0E-30 Then
- result := 0
- Else
- If r < 0 Then
- result := -1
- Else
- result := 1;
- End;
-
- Function CmpSingles(Var item1, item2 ): Integer;
- Var
- i1: Single absolute item1;
- i2: Single absolute item2;
- r: Single;
- Begin
- r := i1-i2;
- If Abs( r ) < 1.0E-30 Then
- result := 0
- Else
- If r < 0 Then
- result := -1
- Else
- result := 1;
- End;
-
- Function CmpDoubles(Var item1, item2 ): Integer;
- Var
- i1: Double absolute item1;
- i2: Double absolute item2;
- r: Double;
- Begin
- r := i1-i2;
- If Abs( r ) < 1.0E-100 Then
- result := 0
- Else
- If r < 0 Then
- result := -1
- Else
- result := 1;
- End;
-
- Function CmpExtendeds( Var item1, item2 ): Integer;
- Var
- i1: Extended absolute item1;
- i2: Extended absolute item2;
- r: Extended;
- Begin
- r := i1-i2;
- If Abs( r ) < 1.0E-3000 Then
- result := 0
- Else
- If r < 0 Then
- result := -1
- Else
- result := 1;
- End;
-
- Function CmpPChars( Var item1, item2 ): Integer;
- Var
- p1: PChar absolute item1;
- p2: PChar absolute item2;
- Begin
- Result := lstrcmp( p1, p2 );
- End;
-
- Function CmpPStrings( Var item1, item2 ): Integer;
- Var
- p1: PString absolute item1;
- p2: PString absolute item2;
- Begin
- Result := AnsiCompareStr( p1^, p2^ );
- End;
-
- End.
-