Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

SRP Lists are an alternative replacement to BASIC+ lists and can greatly enhance performance for large processes.

_
MethodDescription
SRP_List_AddAdds an element to the end of an SRP List.
SRP_List_CreateCreates an SRP List.SRP
_List_CreateFromFastArrayCreates an SRP List initialized to a list within the given SRP Fast Array.
SRP_List_CountGets the number of elements in the list.
SRP_List_GetAtGets the element from an SRP List at the given index.
SRP_List_GetVariableConverts an SRP List back into a BASIC+ variable.
SRP_List_InsertAtInserts an element into an SRP List at the given index position.
LocateLocates a value in an SRP List.
_MatchFinds the index of the first element from the starting index that matches the given string.
SRP_List_ReduceCreates a new list containing only those elements that match the given string.
ReleaseReleases the handle to SRP_List_LocateLocates a value in an SRP List.
SRP_List_ReleaseReleases the handle to an SRP List.
SRP_List_RemoveAtRemoves an element from an SRP List at the given index position.
SRP_List_SetAtSets an element into an SRP List at the given index position.

...

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(ListHandle", 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)

Lists Sizes

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 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(Handle("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.5.4 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
Declare 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

...