Koryn's Units
Koryn Grant, Macintosh Developer



pascalflavouredmac picture

KGLists

Author: Koryn Grant
Copyright: 1998 Koryn Grant
Email: koryn@kagi.com
Date: 10 June 1998

Summary

KGLists is an Object Pascal unit for CodeWarrior that implements unsorted, singly-linked lists in an object-oriented style. The lists are designed to store any form of handle-based data, and are intended to be subclassed for use with a particular type of data. The ListObjects in KGLists are used extensively in SlashMUD http://www.ukc.ac.uk/IMS/maths/people/K.D.Grant/SlashMUD/ and have been thoroughly tested. KGLists requires MyAssertions from Peter Lewis' PNL Libraries, available from http://www.stairways.com/ .

Environment

Although KGLists is provided as a unit, it is still environment-dependent. In particular, I use the Metrowerks scope keywords (public/protected/private) in object declarations.

Conditions of use

You may use KGLists in any project you wish, provided that an acknowledgement is made in your application's AboutBox and ReadMe. A suitable acknowledgement would be

"YourApplication uses KGLists, written by and copyright 1997-1998 Koryn Grant."

Complimentary copies of any freeware, shareware or commercial applications that use KGLists would be appreciated but are not required.

Unmodified copies of "KGLists.p" may be freely distributed provided that they are accompanied by the file "About KGLists". Modified copies may not be distributed without the author's permission.

Disclaimer: KGLists is provided as is, with no warranties about its suitability for any purpose whatsoever.

How to use KGLists

ListObjects are not intended to be used as is. They are intended to be subclassed and the subclasses used to access the members of the list, with ListObject providing general list capabilities (iterating over members, adding members, removing members, testing for list membership etc). A concrete example of this is provided below.

One feature of ListObjects is that they can "preflight" member allocation. Consider the list as consisting of a number of containers (ListMembers) for the handle-based data. Normally there is a one-to-one correspondence between the containers and their data; when a handle is added to the list a new container is created and when a handle is removed from the list the associated container is destroyed. However, when the ListObject is told to use preflighting, this is no longer the case: when a handle is removed from the list the associated container is kept, and when a new handle is added to the list an empty container is used (if possible). The purpose of this is to minimise the number of times new containers must be created. This is completely transparent to routines making use of ListObjects - for example the method that returns the number of members in the list does not count empty containers, and if the ListObject is asked for the second member it will return the handle in the second non-empty container. By default preflighting is enabled.

If the variable kListDebugging is true additional checking is performed via assertions that drop into a debugger. Projects that include KGLists can choose the setting of kListDebugging by setting _KGListDebugging_ to be 1 (true) or 0 (false). If _KGListDebugging_ is not defined then kListDebugging defaults to true.

KGLists interface

ListMember = object
	{ Private data fields. }
	private Data : Handle;
	private Next : ListMember;
	
	{ Methods. }
	procedure Initialise;
	procedure Finished;
	procedure SetData(theData : univ Handle);
	function  GetData : Handle;
	procedure SetNext(theMember : ListMember);
	function  GetNext : ListMember;
	end;
		{ of ListMember }
	
ListObject = object
	{ Private data fields. }
	private Head : ListMember;
	private Preflight : boolean;
	
	{ Methods. }
	procedure Initialise;
	function  AddMember(theData : univ Handle) : boolean;
	function  GetNumberOfMembers : integer;
	function  GetMemberNumber(number : integer) : Handle;
	procedure RemoveMember(theData : univ Handle);
	function  IsMember(theData : univ Handle) : boolean;
	procedure SetPreflight(theBool : boolean);
	function  GetPreflight : boolean;
	procedure VerifyList;
	procedure Finished;
	end;
		{ of ListObject }

ListMember methods

These descriptions are presented here for completion only. Most list operations are handled by calling methods belonging to the ListObject rather than by manipulating the ListMembers directly.

procedure Initialise;

Initialise the ListMember fields to nil.

procedure Finished;

Disposes of the handle referenced by Data and then disposes of the ListMember itself.

procedure SetData(theData : univ Handle);

Stores theData in the ListMember.

function GetData : Handle;

Returns the ListMember's Data as a handle.

procedure SetNext(theMember : ListMember);

Sets the Next field of the ListMember to the given ListMember.

function GetNext : ListMember;

Returns the Next field of the ListMember.

ListObject methods

procedure Initialise;

Initialises the list. This sets the head of the list to nil and Preflight to true.

function AddMember(theData : univ Handle) : boolean;

This method adds theData to the list. It returns true if the addition was successful, false if it failed.

function GetNumberOfMembers : integer;

This method returns the number of members in the list.

function GetMemberNumber(number : integer) : Handle;

This method returns the requested member as a handle.

procedure RemoveMember(theData : univ Handle);

This method removes theData from the list. It does not dispose of or change theData in any way, merely removes the reference to theData from the list.

function IsMember(theData : univ Handle) : boolean;

This method returns true if the list contains theData, false if it does not.

procedure SetPreflight(theBool : boolean);

This method sets the Preflight field of the ListObject.

function GetPreflight : boolean;

This method returns the Preflight field of the ListObject.

procedure VerifyList;

This method checks that each member of the list is valid and contains valid handles. It asserts if an error is detected.

procedure Finished;

This method disposes of all entries in the list. Unlike RemoveMember, Finished does dispose the handles in the list.

Example use (from SlashMUD)

This is a list of rooms used within SlashMUD. RoomListObject is a subclass of ListObject; the chief reason for subclassing ListObject and adding the two extra methods is that RoomListObject has more information about the handles in its list. RoomListObject knows that the data in its list are RoomObjects, whereas ListObject only knows that its data are handles.

Thus RoomListObject has the GetRoomNumber method, which returns the desired member of the list as a RoomObject and the GetRoom method, which searches for a room by name.

RoomListObject = object(ListObject)
	{ Methods. }
	procedure GetRoom(name : ConstStr31Param; var returnRoom : RoomObject);
	function  GetRoomNumber(number : SInt16) : RoomObject;
	end;

procedure RoomListObject.GetRoom(name : ConstStr31Param; var returnRoom : RoomObject);
	var
	theRoom : RoomObject;
	theCount : SInt16;
	index : SInt16;
	
	begin
	returnRoom := nil;
	theCount := GetNumberOfMembers;
	
	if (theCount = 0) then
		begin
		Exit(GetRoom);
		end;
		
	index := 1;
	while ((returnRoom = nil) and (index <= theCount)) do
		begin
		theRoom := RoomObject(GetMemberNumber(index));
		
		if (theRoom.GetName = name) then
			begin
			returnRoom := theRoom;
			end;
		
		index := index + 1;
		end;
	end;
		{ of procedure RoomListObject.GetRoom }

function RoomListObject.GetRoomNumber(number : SInt16) : RoomObject;
	begin
	GetRoomNumber := RoomObject(GetMemberNumber(number));
	end;
		{ of procedure RoomListObject.GetRoomNumber }

For further examples of how ListObjects can be used in an application, check out the source code to SlashMUD, available at http://www.ukc.ac.uk/IMS/maths/people/K.D.Grant/SlashMUD/.

Credits

KGLists uses MyAssertions by Peter N Lewis.

Download KGLists



Copyright ©1998 Koryn Grant.