Page History
SRP Lists are an alternative replacement to BASIC+ lists and can greatly enhance performance for large processes.
Method | Description |
---|
Added | ||
---|---|---|
Add | Adds an element to the end of an SRP List. | |
Clear | Removes all values from an SRP |
List. | 2.1.10 | |
Count | Gets the number of elements in the list. | |
Create | Creates an SRP List. |
CreateFromFastArray | Creates an SRP List initialized to a list within the given SRP Fast Array. |
GetAt | Gets the |
element from an SRP List at the given index. |
GetVariable | Converts an SRP List back into a BASIC+ variable. |
InsertAt | Inserts an element into an SRP List at the given index position. | |
Locate | Locates a value in an SRP |
List |
. | |
Match | Finds the index of the first element from the starting index that matches the given string. |
Reduce | Creates a new list containing only those elements that match the given string |
. |
Release | Releases the handle to an SRP List. |
RemoveAt | Removes an element from an SRP List at the given index position. |
SetAt | Sets an element into an SRP List at the given index position. |
List Defined
In this documentation, the term List refers to a single-dimensional dynamic array. For multi-dimensional array support, see SRP FastArray.
BASIC+ Lists
Easily one of the best features of the BASIC+ language is its array manipulation. It’s easy, intuitive, and flexible: the trifecta of efficient programming. No need to predetermine the size of your array. No need to worry about going out of bounds. Just set a position and you’re all set.
...
Code Block |
---|
ListHandle = SRP_List_("Create(") |
Or you can create an SRP List initialized to a BASIC+ list, like this:
Code Block |
---|
ListHandle = SRP_List_Create(("Create", "My":@FM:"Dynamic":@FM:"Array") |
...
Code Block |
---|
Value = SRP_List_GetAt(("GetAt", ListHandle, 3) |
SRP_List simply grabs element three and returns it. Inserts, replaces, and deletes are all equally fast for similar reasons. SRP_List never needs to recopy its elements. An insert simply places the new value as a new string right where it needs to go.
Code Block |
---|
SRP_List_InsertAt(("InsertAt", ListHandle, 2, "BASIC+") |
You can imagine how fast this is for lists with thousands of elements being inserted, deleted, and replaced. Of course, you will eventually need your SRP List to become a BASIC+ list again, and this is how you do it:
Code Block |
---|
List = SRP_List_GetVariable(("GetVariable", ListHandle, @FM) |
This function does allocate memory for the entire list and copies each element—with delimiters—into it. Obviously, if you call this method thousands of times, then you're no better off than when you were using a BASIC+ list. The idea is to manipulate your list using SRP List and then writing write it out when you are done.
There is always one more step when using SRP Lists. You have to release the handle.
Code Block |
---|
SRP_List_Release(("Release", ListHandle) |
Sure, it's an extra step, but the performance gains are usually worth it. If you forget to do this, SRP Utilities will clean up all unreleased handles when OpenInsight closes, but if you plan on your application running for hours at a time, you still want to avoid memory getting used up and never freed.
...
Just like all other list manipulation, BASIC+ scans the string from front to back until it finds the target. As usual, if you are doing this hundreds or thousands of times, you can experience some serious slowdowns.
SRP Lists_List, however, have has a special trick up their its sleeve. The entire list is indexed! So, whenever you do a locate against it, it's instant. It doesn't matter if you have ten elements or a million. Moreover, the syntax is easy.
Code Block |
---|
Pos = SRP_List_Locate(("Locate", ListHandle, Target) |
Locates are case sensitive. If you need a more flexible albeit slower means of searching, check out the Match service. And if you want to filter your list into a smaller one based on a search string, see the Reduce sevice.
Lists Sizes
One thing we often do is count the number of elements in an list. In BASIC+ we typically do this with the following code:
...
Code Block |
---|
ListCount = SRP_List_Count(("Count", Handle) |
Counting elements in an SRP List is instantaneous because the list count is always cached.
...
SRP Lists do not care if your original list is field-mark delimited or comma delimited, because internally the list never uses delimiters. Instead, you specific specify a delimiter when you initialize the SRP List and you specify the delimiter when you get the final list. You don't even have to use the same delimiter each time.
Code Block |
---|
// Init with spacecomma as the delimiter ListHandle = SRP_List_Create(("Create", "FirstDay,Sunday,Tuesday,Wednesday,Thoosday,Friday", ",") // Do some inserts, replaces, and additions SRP_List_RemoveAt(("RemoveAt", ListHandle, 1) SRP_List_InsertAt(("InsertAt", ListHandle, 2, "Monday") SRP_List_SetAt(("SetAt", ListHandle, 5, "Thursday") SRP_List_Add(("Add", ListHandle, "Saturday") // Return the list, but make it value-mark delimited List = SRP_List_GetVariable(("GetVariable", ListHandle, @VM) |
...
// Clean up
SRP_Release("Release", ListHandle) |
When to Use SRP_List
As with everything, use the right tool for the right job. There are two factors to consider: the size of the list and the number of operations you intend to perform upon it. The smaller the list, the less amount of time BASIC+ spends scanning, allocating, and copying. Also, even if you have a list that takes up several megabytes in memory, if you are only doing two extracts, SRP List won't make that much of a difference.
Perhaps the best rule of thumb is this: if you have a process that takes a long time to run, look to see how much list manipulation it is doing. If there appears to be a great deal of it, then try out SRP List and see if you get an improvement. Benchmark the differences to see if the increase in code complexity (SRP List methods are, after all, not as pretty as angle bracket operators) seems worth the performance gain.
When Not to Use SRP_List
There is one situation in which SRP List does not seem to offer any significant performance increase: appending values. If your routine is only appending values at the end of your single-dimensional list, then BASIC+ is plenty fast for you. Essentially, BASIC+ dynamic arrays begin to suffer in performance when you perform random access, and merely appending values in a single-dimensioned array is not random.
...
Here is a routine you can copy into OpenInsight and run (after installing SRP Utilities 1.4 5.7 or greater, of course). It inserts and extracts elements into each type of list at random and times it. It also benchmarks repeated locates. Notice that 1000 iterations or less offer pretty negligible gains, but 10,000 or more iterations really start to show the speed difference. Your mileage will vary depending upon your PC specifications.
Code Block |
---|
Compile function Test_List(VOID) $Insert SRPLIST // OI routines Declare function GetTickCount Declare subroutine Msg // SRP Fast Array routines Declare function SRP_List_Create, SRP_List_GetVariable, SRP_List_GetAt, SRP_List_Locate Declare subroutine SRP_List_InsertAt, SRP_FastArray_Release subroutine Msg Iterations = 10000 ; // How many operations to perform MaxPos = 10000 ; // The maximum field, value, or subvalue position InsertText = "SRP Computer Solutions, Inc." ; // The text to insert InitRnd Time():Date() // Insert the text at random field, value, and subvalue positions StartTime = GetTickCount() TestOI = "" For i = 1 to Iterations TestOI = Insert(TestOI, Rnd(MaxPos), 0, 0, InsertText) Next i InsertTimeOI = GetTickCount() - StartTime // Insert the text at random field, value, and subvalue positions using SRP Fast ArrayList StartTime = GetTickCount() Handle = SRP_List_("Create(") For i = 1 to Iterations SRP_List_InsertAt(("InsertAt", Handle, Rnd(MaxPos), InsertText) Next i TestSRP = SRP_List_GetVariable(("GetVariable", Handle) InsertTimeSRP = GetTickCount() - StartTime // Extract values at random field, value, and subvalue field positions StartTime = GetTickCount() For i = 1 to Iterations A = Extract(TestOI, Rnd(MaxPos), Rnd(MaxPos)0, Rnd(MaxPos0)) Next i ExtractTimeOI = GetTickCount() - StartTime // Extract values at random field, value, and subvalue positions user SRP Fast ArrayList StartTime = GetTickCount() For i = 1 to Iterations A = SRP_List_GetAt(("GetAt", Handle, Rnd(MaxPos)) Next i ExtractTimeSRP = GetTickCount() - StartTime // In Insert a unique string into the center of the listlists (to representsimulate average locate times) Target = "LOOK AT ME!" InsertPos = Int(MaxPos / 2) TestOI = Insert(TestOI, InsertPos, 0, 0, Target) SRP_List_InsertAt(("InsertAt", Handle, InsertPos, Target) // Locate the target over and over StartTime = GetTickCount() For i = 1 to Iterations Locate Target in TestOI using @FM setting Pos then null Next i LocateTimeOI = GetTickCount() - StartTime // Extract values atLocate randomthe field,target value,over and subvalueover positionsusing user SRP Fast ArrayList StartTime = GetTickCount() For i = 1 to Iterations Pos = SRP_List_Locate(("Locate", Handle, Target) Next i LocateTimeSRP = GetTickCount() - StartTime // Clean up the memory SRP_FastArray_Release(List("Release", Handle) Msg(@Window, "OI Insert Time: ":InsertTimeOI:"ms|SRP Insert Time: ":InsertTimeSRP:"ms||OI Extract Time: ":ExtractTimeOI:"ms|SRP Extract Time: ":ExtractTimeSRP:"ms||OI Locate Time: ":LocateTimeOI:"ms|SRP Locate Time: ":LocateTimeSRP:"ms") Return 1 |
...
Code Block |
---|
ListHandle = SRP_List_CreateFromFastArray(("CreateFromFastArray", ArrayHandle, 0, 0) |
If you want to initialize the SRP List to a list of values, then only set the value parameter to zero.
Code Block |
---|
ListHandle = SRP_List_CreateFromFastArray(("CreateFromFastArray", ArrayHandle, 7, 0) |
And, of course, if you want to initialize the list to a list of subvalues, then set both the field and the value parameters.
Code Block |
---|
ListHandle = SRP_List_CreateFromFastArray(("CreateFromFastArray", ArrayHandle, 2, 3) |
Points to Remember
...