How to loop over a queue and delete SOME entries


#1

On Skype @Andre asked how to safely loop through a queue and selectively delete one or more entries.
The simplest answer is, loop backwards but if you wish to loop forwards then you need to manage the Pointers

The reason you need to manage the pointers is when we loop over a queue, we use GET(Q, Pointer) to read the rows. The problem is that the when you delete a row, the pointers decrement for rows later in the list. So simple looping forwards will wind up missing some rows.

Notice how when we looped forward rows G,I,K survived, even though we didn’t want them to.
That’s because those rows were never checked.


Source Code

  PROGRAM
  MAP
  END

Q     QUEUE
ID      LONG
Descr   STRING(20)
      END 

  INCLUDE('debuger.inc'),ONCE
DBG        debuger

RemoveRows EQUATE('FGHIJKL')
  CODE
                       DBG.mg_init('DeleteQ')
  DO FillQ           ; DBG.DumpQue('Filled', Q) 
  DO RemoveForwards  ; DBG.DumpQue('Remove Forwards', Q) 

  FREE(Q)
  DO FillQ
  DO RemoveBackwards ; DBG.DumpQue('Remove Backwards', Q) 

  FREE(Q)
  DO FillQ
  DO RemoveFowardsCorrectly ; DBG.DumpQue('Remove Fwd Correct', Q) 


FillQ ROUTINE
  LOOP 20 TIMES
    Q.ID = RECORDS(Q) + 1 
    Q.Descr = ALL( CHR(Q.ID + 64) )
    ADD(Q)
  END 

RemoveForwards  ROUTINE      ! NOTE: this routine is wrong, it will miss some rows
  DATA
QPtr LONG,AUTO
  CODE
  LOOP QPtr = 1 TO RECORDS(Q) 
    GET(Q,QPtr)
    IF INSTRING( Q.Descr[1], RemoveRows,1,1) <> 0
       DELETE(Q)
    END 
  END    

RemoveBackwards  ROUTINE 
  DATA
QPtr LONG,AUTO
  CODE
  LOOP QPtr = RECORDS(Q) TO 1 BY -1    !<--- the difference
    GET(Q,QPtr)
    IF INSTRING( Q.Descr[1], RemoveRows,1,1) <> 0
       DELETE(Q)
    END 
  END    

RemoveFowardsCorrectly ROUTINE
   DATA
qPtr  LONG(1)
   CODE
   LOOP UNTIL qPtr > RECORDS(Q)    !<--- RECORDS(Q) will change during this loop
      GET(Q,QPtr)
      IF INSTRING( Q.Descr[1], RemoveRows,1,1) <> 0
         DELETE(Q)
      ELSE
         QPtr += 1     ! <--- only move the pointer when a row was NOT deleted
      END 
   END

Output

`DeleteQ - Program[C:\Users\Win8M\OneDrive\Dev\cla\Src\DeleteQ\DeleteQ.Exe]DebugerOn[Always]
`Debuger.DumpQue UseSelf[1]  SELF.debugactive[1] argforce[0]
Debuger.DumpQue argFormat()
`DeleteQ - DumpQ - ==========================================
`DeleteQ - DumpQ - Filled
`DeleteQ - DumpQ - ID,DESCR
`DeleteQ - DumpQ - Rec[ 1] 1,"AAAAAAAAAAAAAAAAAAAA" 
`DeleteQ - DumpQ - Rec[ 2] 2,"BBBBBBBBBBBBBBBBBBBB" 
`DeleteQ - DumpQ - Rec[ 3] 3,"CCCCCCCCCCCCCCCCCCCC" 
`DeleteQ - DumpQ - Rec[ 4] 4,"DDDDDDDDDDDDDDDDDDDD" 
`DeleteQ - DumpQ - Rec[ 5] 5,"EEEEEEEEEEEEEEEEEEEE" 
`DeleteQ - DumpQ - Rec[ 6] 6,"FFFFFFFFFFFFFFFFFFFF" 
`DeleteQ - DumpQ - Rec[ 7] 7,"GGGGGGGGGGGGGGGGGGGG" 
`DeleteQ - DumpQ - Rec[ 8] 8,"HHHHHHHHHHHHHHHHHHHH" 
`DeleteQ - DumpQ - Rec[ 9] 9,"IIIIIIIIIIIIIIIIIIII" 
`DeleteQ - DumpQ - Rec[10] 10,"JJJJJJJJJJJJJJJJJJJJ" 
`DeleteQ - DumpQ - Rec[11] 11,"KKKKKKKKKKKKKKKKKKKK" 
`DeleteQ - DumpQ - Rec[12] 12,"LLLLLLLLLLLLLLLLLLLL" 
`DeleteQ - DumpQ - Rec[13] 13,"MMMMMMMMMMMMMMMMMMMM" 
`DeleteQ - DumpQ - Rec[14] 14,"NNNNNNNNNNNNNNNNNNNN" 
`DeleteQ - DumpQ - Rec[15] 15,"OOOOOOOOOOOOOOOOOOOO" 
`DeleteQ - DumpQ - Rec[16] 16,"PPPPPPPPPPPPPPPPPPPP" 
`DeleteQ - DumpQ - Rec[17] 17,"QQQQQQQQQQQQQQQQQQQQ" 
`DeleteQ - DumpQ - Rec[18] 18,"RRRRRRRRRRRRRRRRRRRR" 
`DeleteQ - DumpQ - Rec[19] 19,"SSSSSSSSSSSSSSSSSSSS" 
`DeleteQ - DumpQ - Rec[20] 20,"TTTTTTTTTTTTTTTTTTTT" 
`DeleteQ - DumpQ - Filled - RetVal()
`DeleteQ - DumpQ - ==========================================
`Debuger.DumpQue UseSelf[1]  SELF.debugactive[1] argforce[0]
Debuger.DumpQue argFormat()
`DeleteQ - DumpQ - ==========================================
`DeleteQ - DumpQ - Remove Forwards
`DeleteQ - DumpQ - ID,DESCR
`DeleteQ - DumpQ - Rec[ 1] 1,"AAAAAAAAAAAAAAAAAAAA" 
`DeleteQ - DumpQ - Rec[ 2] 2,"BBBBBBBBBBBBBBBBBBBB" 
`DeleteQ - DumpQ - Rec[ 3] 3,"CCCCCCCCCCCCCCCCCCCC" 
`DeleteQ - DumpQ - Rec[ 4] 4,"DDDDDDDDDDDDDDDDDDDD" 
`DeleteQ - DumpQ - Rec[ 5] 5,"EEEEEEEEEEEEEEEEEEEE" 
`DeleteQ - DumpQ - Rec[ 6] 7,"GGGGGGGGGGGGGGGGGGGG" 
`DeleteQ - DumpQ - Rec[ 7] 9,"IIIIIIIIIIIIIIIIIIII" 
`DeleteQ - DumpQ - Rec[ 8] 11,"KKKKKKKKKKKKKKKKKKKK" 
`DeleteQ - DumpQ - Rec[ 9] 13,"MMMMMMMMMMMMMMMMMMMM" 
`DeleteQ - DumpQ - Rec[10] 14,"NNNNNNNNNNNNNNNNNNNN" 
`DeleteQ - DumpQ - Rec[11] 15,"OOOOOOOOOOOOOOOOOOOO" 
`DeleteQ - DumpQ - Rec[12] 16,"PPPPPPPPPPPPPPPPPPPP" 
`DeleteQ - DumpQ - Rec[13] 17,"QQQQQQQQQQQQQQQQQQQQ" 
`DeleteQ - DumpQ - Rec[14] 18,"RRRRRRRRRRRRRRRRRRRR" 
`DeleteQ - DumpQ - Rec[15] 19,"SSSSSSSSSSSSSSSSSSSS" 
`DeleteQ - DumpQ - Rec[16] 20,"TTTTTTTTTTTTTTTTTTTT" 
`DeleteQ - DumpQ - Remove Forwards - RetVal()
`DeleteQ - DumpQ - ==========================================
`Debuger.DumpQue UseSelf[1]  SELF.debugactive[1] argforce[0]
Debuger.DumpQue argFormat()
`DeleteQ - DumpQ - ==========================================
`DeleteQ - DumpQ - Remove Backwards
`DeleteQ - DumpQ - ID,DESCR
`DeleteQ - DumpQ - Rec[ 1] 1,"AAAAAAAAAAAAAAAAAAAA" 
`DeleteQ - DumpQ - Rec[ 2] 2,"BBBBBBBBBBBBBBBBBBBB" 
`DeleteQ - DumpQ - Rec[ 3] 3,"CCCCCCCCCCCCCCCCCCCC" 
`DeleteQ - DumpQ - Rec[ 4] 4,"DDDDDDDDDDDDDDDDDDDD" 
`DeleteQ - DumpQ - Rec[ 5] 5,"EEEEEEEEEEEEEEEEEEEE" 
`DeleteQ - DumpQ - Rec[ 6] 13,"MMMMMMMMMMMMMMMMMMMM" 
`DeleteQ - DumpQ - Rec[ 7] 14,"NNNNNNNNNNNNNNNNNNNN" 
`DeleteQ - DumpQ - Rec[ 8] 15,"OOOOOOOOOOOOOOOOOOOO" 
`DeleteQ - DumpQ - Rec[ 9] 16,"PPPPPPPPPPPPPPPPPPPP" 
`DeleteQ - DumpQ - Rec[10] 17,"QQQQQQQQQQQQQQQQQQQQ" 
`DeleteQ - DumpQ - Rec[11] 18,"RRRRRRRRRRRRRRRRRRRR" 
`DeleteQ - DumpQ - Rec[12] 19,"SSSSSSSSSSSSSSSSSSSS" 
`DeleteQ - DumpQ - Rec[13] 20,"TTTTTTTTTTTTTTTTTTTT" 
`DeleteQ - DumpQ - Remove Backwards - RetVal()
`DeleteQ - DumpQ - ==========================================
`Debuger.DumpQue UseSelf[1]  SELF.debugactive[1] argforce[0]
Debuger.DumpQue argFormat()
`DeleteQ - DumpQ - ==========================================
`DeleteQ - DumpQ - Remove Fwd Correct
`DeleteQ - DumpQ - ID,DESCR
`DeleteQ - DumpQ - Rec[ 1] 1,"AAAAAAAAAAAAAAAAAAAA" 
`DeleteQ - DumpQ - Rec[ 2] 2,"BBBBBBBBBBBBBBBBBBBB" 
`DeleteQ - DumpQ - Rec[ 3] 3,"CCCCCCCCCCCCCCCCCCCC" 
`DeleteQ - DumpQ - Rec[ 4] 4,"DDDDDDDDDDDDDDDDDDDD" 
`DeleteQ - DumpQ - Rec[ 5] 5,"EEEEEEEEEEEEEEEEEEEE" 
`DeleteQ - DumpQ - Rec[ 6] 13,"MMMMMMMMMMMMMMMMMMMM" 
`DeleteQ - DumpQ - Rec[ 7] 14,"NNNNNNNNNNNNNNNNNNNN" 
`DeleteQ - DumpQ - Rec[ 8] 15,"OOOOOOOOOOOOOOOOOOOO" 
`DeleteQ - DumpQ - Rec[ 9] 16,"PPPPPPPPPPPPPPPPPPPP" 
`DeleteQ - DumpQ - Rec[10] 17,"QQQQQQQQQQQQQQQQQQQQ" 
`DeleteQ - DumpQ - Rec[11] 18,"RRRRRRRRRRRRRRRRRRRR" 
`DeleteQ - DumpQ - Rec[12] 19,"SSSSSSSSSSSSSSSSSSSS" 
`DeleteQ - DumpQ - Rec[13] 20,"TTTTTTTTTTTTTTTTTTTT" 
`DeleteQ - DumpQ - Remove Fwd Correct - RetVal()
`DeleteQ - DumpQ - ==========================================
`DeleteQ - Program[C:\Users\Win8M\OneDrive\Dev\cla\Src\DeleteQ\DeleteQ.Exe] Ended [August 25, 2017  8:38:13 AM]
<process started at 08:38:13.087 has terminated with exit code 0>

#2

Thanks Mark

it is probably just personal preference or habit but I would tend to do this instead:

LOOP
GET(Q,QPtr)
if errorcode() then break.

well it is another option anyway…

cheers

Geoff R