Clara-Doc - Programmer Reference

Module: CTLST

Methods

MethodDescription
CTLST_ClearRemoves all items from the list
CTLST_ConstructorCreates a list (an instance of type CTLST).
CTLST_CountReturns the number of items in the list.
CTLST_DestructorReleases all the items held in the list and the list itself.
CTLST_GetRetrieves an item from the list at a specified location.
CTLST_InsertAdds an item in the list at a specified index.
CTLST_ItemSizeReturns the size of an item's value held at a specified location.
CTLST_IterNextRetrieves the next available item from the iteration loop.
CTLST_IterNextSizeReturns the size of the next available item from the iteration loop.
CTLST_IterStartPrepares the list for iterating through its items.
CTLST_RemoveRemoves an item from the list at a specified location.
CTLST_SetSets the value of an existing list item at a specified location.



Description

The CTLST class implements a linked list. A linked list is a collection that has the following properties:

  • Individual items can be of any type (size)
  • The linked list can grow and shrink at runtime
  • Items can be removed or inserted at any position within the list
The number of items is limited by system resources. List items can be accessed via their index position within the list. Index positions start at 1; The first item is at index position 1. However, an item's index can change as items are inserted and removed. Consider the following situation of a linked list with 3 items:
In the above list, the node A is at index 1, the node B at index 2 and node C at index 3. The CTLST class has the CTLST_Insert method which enables insertions at any index position. If CTLST_Insert is called to insert an item (let's call it Z) at index 2, then the list will look like:
Item A is still at index 1 but the indices at items B and C have been shifted by 1 after the insertion of item Z at index 2 (item B is now at index 3 and item C is now at index 4). The same thing happens if you remove items from the list. For example, if node B is removed, then node C will move down from index position 4 to index position 3. The other nodes will retain their index positions.
Creating and disposing CTLST instances
Before using a CTLST, a CTLST instance has to be created (constructed). This is done by calling the CTLST_Constructor method. A pointer to a CTLST instance will be returned to the caller. This pointer will be used in calls to other CTLST methods. Every time CTLST_Constructor is called, a new CTLST instance is created and accessible through the pointer that is returned. This allows for several CTLST instances within the same porgram. Be sure to pass the appropriate pointer when calling CTLST methods. Once a CTLST instance is no longer needed, its resources have to be reclaimed via a call the the CTLST_Destructor method (you must pass the pointer to the CTLST instance that will be garbage collected). Call the CTLST_Destructor method on every CTLST instance once they are no longer needed. In between calls to the constructor and the destructor for a given CTLST instance, you may call any CTLST method on that CTLST instance.
                                       
 /INCLUDE QINCSRC,CTBASE               
                                       
DRc               S             10I 0  
DpList            S               *    
                                       
 /Free                                 
                                       
    pList = CTLST_Constructor();      
                     
                     
    // Use CTLST instance via methods by using the pList pointer                                   
    //
    // ...
    
    
    // We are done and need to gargabe collect CTLST resources
    
    CTLST_Destructor(pList);          
                                       
    *InLR = *On;                       
    Return;                            
                                       
 /End-Free                             

Implementation
A linked list instance is made up of a control node and zero or more data items (data nodes):
A list instance keeps track of the first and last data items. The number of data nodes is also kept in the control node. Notice also that the list is a doubly linked list, meaning individual data nodes point to the one preceding it and the one following it (the first node has a null predecessor and the last node has a null successor). The CTLST instance manages the control node as data nodes ara added and removed. Calling the CTLST_Constructor method will allocate the control node:
The list is empty (it has no data nodes). Inserting the first data node will update the control node values accordingly. The first, current and last fields all point to the only data node (the count becomes 1):
Inserting (or removing) additional nodes will also update the control node fields to reflect the changes. The "Current" field in the control node is used for performance reasons when performing insertions, retrievals and removals. The control node fields are update by calls to methods that change the number of items in the list (such as calling CTLST_Insert or CTLST_Remove).
Inserting data in a linked list
Data is inserted into a data node. The linked list user does not have to provide a data node; only the actual data is provided by a list user. The data provided is copied; this means data nodes keep a copy of the provided data such that if the user makes changes to the original data, these changes will not be reflected in the data the node contains:
Assume the list user inserted a second data item (a 4 byte integer (10I 0)) at the end of the list. The internal structure would look something like the following:
Other items could be inserted and the list as shown in our first illustration would actually look like:
The buffer provided to a lis will only be copied up to the specified size. This size will be the only information on the data that a data node will hold. The type of data is not held in the data node so don't make assumptions about how the data will be used within the list. Also, since the data node only knows the size a user intends to copy, then it is possible to copy less data than the input buffer actually holds (which can be desirable in certain scenarios). Here is an example:
In the above, we copy a portion of the buffer starting at 4 bytes from its starting position and we want to copy 4 bytes. The data node will allocate a 4 byte buffer and copy the 4 bytes starting at the specified buffer address that was provided by the list user.
Retrieving data from a linked list
Inserting data in a linked list is straightforward but retrieving data is a bit more subtle. The main thing to remember is that the linked list data node DOES NOT KNOW the data type of its data item. It keeps only the size of the data. When retrieveing data, the linked list will copy back what it holds over to a buffer that is provided by the list user. Actually, the list user provides the address of a buffer. The list will simply copy the data it contains. The list user must also provide the index of the data node and the maximum size to copy into the target (output) buffer. Here is an example:
A list user wants to retrieve data held in a data node within the list (the data node index would be provided by the list user and is not shown here). The list user provides the address of the target buffer and the maximum number of bytes to copy into that buffer. The target buffer already held data (the string Hello World). On return from the CTLST_Get method, the target buffer's first four bytes were replaced with the data node's first 4 bytes (which incidently happens to be the size of the node's data). The point here is to illustrate that the list does not keep type information. It will only store buffers and copy buffers back. In this example, the data node DID NOT CLEAR the target buffer; it only copied 4 bytes into that buffer. Had the list user wanted to replace the data with the data node's data, the list user HAD to clear the buffer PRIOR to calling the CTLST_Get function. This is a crucial point to understand. Had the data been a packed decimal, 4 bytes of that packed decimal would have been moved into the target ALPHA buffer. List users must show care and consistence when using a CTLST (linked list) instance to avoid unpredictable behaviour. Although this may set up for traps, it does payoff in a big way by providing the flexibility to come up with imaginative solutions. As long as one understands that a linked list deals with BUFFERS rather than Variables, then everything should go well. We will however illustrate some cases. The first case we will examine deals with when a list user specifies a buffer size larger than the data node's data size:
In the above example, the list user has a 50 byte buffer. She wants to get the data from a list node. Also, she doesn't know the size of the data held in the node. She will set the size parameter to 50 bytes; this tells the linked list to copy up to but no more than 50 bytes. Since the actual data size is 4 bytes, all the data will be copied into the target buffer. Also, the size parameter to the CTLST_Get method is an IN/OUT parameter. On return, the size parameter will hold the true size of the data. This way, the list user will be able to tell how much data was copied. We will now see a case where the target data buffer is smaller thant the size of the list node data:
Above, the target buffer can hold 5 bytes but the data value in the list is 8 bytes long. The linked list will copy the first 5 bytes into the target buffer and will also return the real size of the data in the size parameter. This way, the list user can know if it has retrieved all of the data. The user can call the CTLST_ItemSize method to know in advance the size of a data item before calling CTLST_Get. The next case illustrates what happens when the list user specifies a size that is actually larger than the target buffer:
Here, the list user caused a buffer overrun by specifying a target buffer size larger than the actual size. The list will simply move 8 bytes (up to the size of the node's data, even if caller specifies more) into the target buffer. This will cause 3 bytes to be moved into another variable (of type 10I 0 in the example). The integer's value has now been changed and this will likely create obscur bugs and unpredictable behaviour. In some cases, it could crash the program. Always keep in mind that the linked list handles BUFFERS, not variables and it only copies buffers back and forth.
Navigating sequentially over a list's data nodes
The CTLST class provides the means to iterate over the list nodes. This CTLST_StartIter method positions a node pointer to the first node in the list. You can then call CTLST_IterNext to get the node's data where the node pointer points. Calling CTLST_IterNext automatically updates the current node pointer, such that the next call to CTLST_IterNext returns the data of the next available node, until there are no more nodes (the CTLST_IterNext method returns a failure code when there are no more nodes to read). Since node data can be of any size, calling the CTLST_IterNextSize method returns the size of the next data item to be read.