home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Education
/
collectionofeducationcarat1997.iso
/
COMPUSCI
/
TOT11.ZIP
/
TOTDOC11.ZIP
/
CHAPT19.TXT
< prev
next >
Wrap
Text File
|
1991-02-11
|
20KB
|
456 lines
Customizing
Linked
Lists
"As we acquire knowledge, things do not become more comprehensible, but
more mysterious."
Will Durant
Doubly-linked lists are ideal for managing large lists of data, they
are memory efficient and fast. The only problem is they are compli-
cated! Fortunately, the Toolkit provides a very easy to use doubly-
linked list object called DLLOBJ. DLLOBJ is an abstract object designed
specifically to simplify the task of extending the object. In this
chapter, techniques for developing a custom doubly-linked list for
managing records is discussed.
You might want to consider re-reading the section on linked list theory
(page 9-1) before proceeding.
DLLOBJ
Unlike many objects, you do not need to understand very much about
DLLOBJ to create descendant objects. All the following methods (which
were described in chapter 9) are unaffected by the type of data stored
in the list, and do not need to be modified in descendant objects:
procedure Advance(Amount:longint);
procedure Retreat(Amount:longint);
function NodePtr(NodeNumber:longint): DLLNodePtr;
procedure Jump(NodeNumber:longint);
procedure ShiftActiveNode(NewNode: DLLNodePtr; NodeNumber: longint);
procedure DelNode(Node:DLLNodePtr);
procedure DelAllStatus(BitPos:byte;On:boolean);
function TotalNodes: longint;
function ActiveNodeNumber: longint;
function ActiveNodePtr: DLLNodePtr;
function StartNodePtr: DLLNodePtr;
function EndNodePtr: DLLNodePtr;
procedure EmptyList;
procedure Sort(SortID:shortint;Ascending:boolean);
procedure SwapNodes(Node1,Node2:DLLNodePtr);
The DLLOBJ stores un-typed data in binary format. You can literally
stored any type of data in a DLLOBJ list. The following methods add and
modify data in a list:
19-2 Extending the Toolkit
--------------------------------------------------------------------------------
function Add(var TheData;Size:longint): integer;
function Change(Node:DLLNodePtr;var TheData;Size:longint): integer;
function InsertBefore(Node:DLLNodePtr;var TheData;Size:longint): inte-
ger;
Each of these three methods are passed an untyped parameter and a lon-
gint indicating the size of the data. In descendant objects, you will
call these methods to manipulate the data in the list. The following
methods return information about the data stored in the list:
procedure Get(var TheData);
procedure GetNodeData(Node:DLLNodePtr;Var TheData);
function GetNodeDataSize(Node:DLLNodePtr):longint;
function GetMaxNodeSize: longint;
The most used method is GetNodeData, which will update a passed un-
typed parameter with the data stored in the list. It is the fundamental
way for a descendant object to get data from the list.
Extending DLLOBJ
The main reason for extending DLLOBJ is to make the new object manage a
specific type of data. The Toolkit includes the descendant StrDLLOBJ,
which is specifically designed to store strings, and FileDLLOBJ, which
stores DOS file details.
In this section, DLLOBJ will be extended and customized to store a
record. To illustrate the principles involved, we will create a new
object RecordDLLOBJ to store the following record data:
RecordInfo = record
FirstName: string[15];
LastName: string[15];
Company: string[20];
Tel: string[10];
CumDollarsSpent: real;
LastOrder: longint;
Comments: string[40];
end;
The main methods that need to be customized are the data manipulation
methods, i.e. Add, Change and InsertBefore. If you want to display the
object in a Browse or List window you must also customize the GetStr
virtual method. GetStr is called by the browse and list objects, and is
simply a function which returns the data stored at a node in string
form. The fifth method which usually needs to be customized is Wron-
Customizing Linked Lists 19-3
--------------------------------------------------------------------------------
gOrder. This method provides the Sort method with the information
needed to sort the data, and is discussed in a later section. The new
object would therefore be declared as follows:
RecordListOBJ = object (DLLOBJ)
constructor Init;
function Add(Rec:RecordInfo): integer;
function Change(Node:DLLNodePtr;Rec:RecordInfo): integer;
function InsertBefore(Node:DLLNodePtr;Rec:RecordInfo): integer;
function WrongOrder(Node1,Node2:DLLNodePtr;
Asc:boolean): boolean; VIRTUAL;
function GetStr(Node:DLLNodePtr;
Start,Finish: longint):string; VIRTUAL;
destructor Done; VIRTUAL;
end; {RecordListOBJ}
Notice that Add, Change and InsertBefore are each passed a variable of
type RecordInfo. All these methods need to do is call their correspond-
ing DLLOBJ method and pass the record as an untyped parameter together
with the record size. The three methods would be implemented as
follows:
function RecordDLLOBJ.Add(Rec:RecordInfo): integer;
begin
Add := DLLOBJ.Add(Rec,sizeof(Rec));
end; {RecordDLLOBJ.Add}
function RecordDLLOBJ.Change(Node:DLLNodePtr;
Rec:RecordInfo): integer;
begin
Change := DLLOBJ.Change(Node,Rec,sizeof(Rec));
end; {RecordDLLOBJ.Change}
function RecordDLLOBJ.InsertBefore(Node:DLLNodePtr;
Rec:RecordInfo): integer;
{}
begin
InsertBefore := DLLOBJ.InsertBefore(Node,Rec,sizeof(Rec));
end; {RecordDLLOBJ.InsertBefore}
It's really as simple as that.
The function method GetStr is passed three parameters; a node pointer
indicating which data to access, and the Start and Finish parameters of
type longint. Start and Finish identify the first and last character
positions of the sub-string to be returned by the function. The DLLOBJ
method GetNodeData can be used to retrieve the node data, and then the
data must be converted into string form. The requested portion of this
string can then be returned. GetStr could be implemented as follows:
19-4 Extending the Toolkit
--------------------------------------------------------------------------------
function RecordDLLOBJ.GetStr(Node:DLLNodePtr;Start,Finish: lon-
gint):string;
{Returns string representation of record}
var
Temp: string;
Rec: RecordInfo;
begin
if Node = nil then
GetStr := 'Not found'
else
begin
GetNodeData(Node,Rec); {inherited method}
with Rec do
begin
Temp := inttostr(ActiveNo