Reading the post How to loop over a queue and delete SOME entries reminded me that Clarion lacks an instruction to loop over all the values of a queue without using an index. Most languages do, even Clarion# (FOREACH
) and the Template language (#FOR
).
Using indexes forces you to declare index variables or, if you are lazy, to use implicit variables. I used to declare a few variables (I LONG
, J LONG
, etc.) in all procedures where I used queues, but this got me when by mistake I reused a variable in another routine. Using implicit variables is worst.
Now, for safety, I declare an index variable for each queue:
myQ QUEUE
...
END
ImyQ LONG
...
LOOP ImyQ = 1 TO RECORDS(myQ)
GET(myQ,ImyQ)
!Some code
.
But I decided to look for a “better” way, and it turns out it is possible to loop over a queue without an index in Clarion:
GET(myQ,0)
LOOP
GET(myQ,POINTER(myQ)+1)
IF ERRORCODE() THEN BREAK.
.
And adding a few trivial global procedures like these:
SET PROCEDURE(QUEUE q)
CODE
GET(q,0)
NEXT PROCEDURE(QUEUE q)!,LONG
CODE
GET(q,POINTER(q)+1)
RETURN ERRORCODE()
PREVIOUS PROCEDURE(QUEUE q)!,LONG
ptr LONG
CODE
ptr = POINTER(q)
IF ptr
GET(q,ptr-1)
ELSE
GET(q,RECORDS(q))
.
RETURN ERRORCODE()
It is possible to write:
SET(myQ)
LOOP
NEXT(myQ)
IF ERRORCODE() THEN BREAK.
!Some code
.
Or even:
SET(myQ)
LOOP UNTIL NEXT(myQ)
!Some code
.
SET(myQ)
LOOP UNTIL PREVIOUS(myQ)
DELETE(myQ)
.
Of course, there is a performance impact. I wrote a small benchmark and got these results:
LOOP I: 2.33
LOOP GET/ERRORCODE: 2.61 12.02%
LOOP SET/NEXT: 2.65 13.73%
LOOP DELETE I: 2.93
LOOP DELETE SET/PREVIOUS: 3.6 22.87%
Meaning that there is an increase of about 13% when using SET/NEXT
and about 22% when using SET/PREVIOUS
. But depending on what you are doing inside the loop (printing, saving to disk, etc.), the difference may be negligible.
Here’s a project with all the code: SET/NEXT/PREVIOUS for queues (github.com)
HTH somebody.