On Fri, 25 Apr 2008, Szakáts Viktor wrote:
> I used 5.2 for this comparison.
> I've now tried with 5.3 which behaves differently
> in a few places, but overall I cannot easily see
> improvements over 5.2, at least not in these tests.

If you want to see the difference add few additional rows
two the table and test sth like:

   TEST_CALL( o:goTop() )
   TEST_CALL( o:forceStable() )
   TEST_CALL( o:down() )
   TEST_CALL( o:forceStable() )
   TEST_CALL( o:down() )
   TEST_CALL( o:down() )
   TEST_CALL( o:forceStable() )
   TEST_CALL( o:down() )
   TEST_CALL( o:down() )
   TEST_CALL( o:down() )
   TEST_CALL( o:forceStable() )
   TEST_CALL( o:pageDown() )
   TEST_CALL( o:forceStable() )

BTW I changed a little bit your code for easier comparison the results
with diff. I'm attaching it.
As I can see the differences are not such huge. There are in fact
three differences:
1. dividing :stable() steps
   I decided that only one position repositioning is allowed in one
   step and looks like Clipper makes some screen/internal parameters
   updates in separated steps. It probably can be tuned to make it
   similar to Clipper though it's not very important.
2. after :goTop() and :goBottom Clipper repeats the forward skipping
   test in the 1-st call to :stablize(). In this test internal :rosPos
   is not yet update and it later causes some small differences in
   repositioning. It's exactly the same what CL5.3 makes for _ALL_
   forward repositioning I was writing about.
   It can be replicated but with the cost of performance and in fact
   it does not guaranties that it will be good protection for concurrent
   access. It's a race condition which cannot be resolved. It can be
   reduced later inside record movement for update but this part seems
   to be missing in Clipper so I guess it was rather workaround for
   concurrent access added to already existed code which probably comes
   from S87 or even earlier Clipper versions. In CL52 it was added only
   in few places but in CL53 in practice to all forward skips. Probably
   it was easier to add such hack instead of updating repositioning code
   and make it safe for concurrent modifications in source data. These
   forward skip tests only reduce the time when sth wrong may happen
   but they not eliminate the race condition. I strongly prefer to update
   repositioning code and fully respect value returned from user skip
   block in all places.
3. Mixed direct (:rowPos:=<x>/:goTop()/:goBottom()) and relative
   (:up()/:down()/:pageUp()/...) repositioning. In such case the
   results can be really strange. It was not easy to detect the
   exact rule when I was checking it few days ago but I haven't made
   careful and deep tests. I do not know if it worth to invest time
   for sth what probably will not effect 99.9% of code.

best regards,
Przemek
STATIC s_nCount := 0
STATIC s_cCurrBlock := ""
STATIC s_cResult1
STATIC s_cResult2

#translate TEST_CALL( <x> ) => TEST_C_CALL( o, #<x>, {|| <x> } )

FUNCTION Main()
   LOCAL o
   LOCAL nOldRecNo
   LOCAL tmp

// AltD()

   dbCreate( "_test", {{ "ID", "C", 10, 0 }} )

   USE _test NEW EXCLUSIVE ALIAS w_TEST

   dbAppend() ; w_TEST->ID := "01"
   dbAppend() ; w_TEST->ID := "02"
   dbAppend() ; w_TEST->ID := "03"
   dbAppend() ; w_TEST->ID := "04"

   o := TBrowseNew( 0, 0, 6, 8 )
   o:GoTopBlock    := { || nOldRecNo := RecNo(), dbGoTop(), my_QOut( o, { 
"TOP", RecNo(), nOldRecNo } ) }
   o:GoBottomBlock := { || nOldRecNo := RecNo(), dbGoBottom(), my_QOut( o, { 
"BOT", RecNo(), nOldRecNo } ) }
   o:SkipBlock     := { | nRecs | nOldRecNo := RecNo(), tmp := Skipped( nRecs 
), my_QOut( o, { "SKP", RecNo(), nOldRecNo, nRecs, tmp } ), tmp }
   o:AddColumn( TBColumnNew( "#", {|| my_QOut( NIL, { "BLK", RecNo() } ), 
StrZero( RecNo(), 3 ) } ) )

   #define Inkey(x)

   CLS
   TEST_CALL( o:leftVisible )
   TEST_CALL( o:goTop() )
   TEST_CALL( ForceStable( o ) )
   TEST_CALL( o:goTop() )
   TEST_CALL( o:pageUp() )
   TEST_CALL( ForceStable( o ) )
   TEST_CALL( o:goTop() )
   TEST_CALL( o:pageDown() )
   TEST_CALL( ForceStable( o ) )
   TEST_CALL( o:goBottom() )
   TEST_CALL( ForceStable( o ) )

   TEST_CALL( o:goBottom() )
   TEST_CALL( o:pageUp() )
   TEST_CALL( ForceStable( o ) )
   TEST_CALL( o:goBottom() )
   TEST_CALL( o:pageDown() )
   TEST_CALL( ForceStable( o ) )
   TEST_CALL( o:leftVisible )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:rowPos )
   TEST_CALL( o:rowPos )

   TEST_CALL( dbGoTop() )
   TEST_CALL( ForceStable( o ) )
   TEST_CALL( o:goTop() )
   TEST_CALL( o:goBottom() )
   TEST_CALL( ForceStable( o ) )
   TEST_CALL( o:up() )
   TEST_CALL( o:up() )
   TEST_CALL( o:down() )
// dbGoTop()
   TEST_CALL( ForceStable( o ) )
   TEST_CALL( o:PageUp() )
   TEST_CALL( ForceStable( o ) )
   o:goTop()
   o:forceStable()
   TEST_CALL( o:down() )
   TEST_CALL( o:down() )
   TEST_CALL( o:PageDown() )
   TEST_CALL( o:PageDown() )
   TEST_CALL( o:PageUp() )
   TEST_CALL( ForceStable( o ) )
   Inkey(0)
   TEST_CALL( o:goTop() )
   TEST_CALL( o:PageDown() )
   TEST_CALL( ForceStable( o ) )
   Inkey(0)
   TEST_CALL( o:goTop() )
   TEST_CALL( o:down() )
   TEST_CALL( ForceStable( o ) )
   Inkey(0)
   TEST_CALL( o:goTop() )
   TEST_CALL( o:down() )
   TEST_CALL( o:down() )
   TEST_CALL( o:down() )
   TEST_CALL( o:down() )
   TEST_CALL( o:down() )
   TEST_CALL( o:down() )
   TEST_CALL( ForceStable( o ) )
   Inkey(0)
   TEST_CALL( o:goBottom() )
   TEST_CALL( ForceStable( o ) )
   Inkey(0)
   TEST_CALL( o:goBottom() )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   Inkey(0)
   TEST_CALL( o:goBottom() )
   TEST_CALL( o:pageDown() )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   Inkey(0)
   TEST_CALL( o:goTop() )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   Inkey(0)
   TEST_CALL( o:goTop() )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:down() )
   TEST_CALL( o:stabilize )
   Inkey(0)
   TEST_CALL( o:goTop() )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:down() )
   TEST_CALL( o:down() )
   TEST_CALL( o:down() )
   TEST_CALL( o:down() )
   TEST_CALL( o:down() )
   TEST_CALL( o:down() )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   TEST_CALL( o:stabilize )
   Inkey(0)

/*
   o:Stabilize()
   o:Up()
   o:Down()
   o:PageUp()
   o:PageDown()
   o:GoTop()
   o:GoBottom()
*/

   RETURN NIL

STATIC FUNCTION Skipped( nRecs )

   LOCAL nSkipped := 0

   IF LastRec() != 0
      IF nRecs == 0
         dbSkip( 0 )
      ELSEIF nRecs > 0 .AND. RecNo() != LastRec() + 1
         DO WHILE nSkipped < nRecs
            dbSkip()
            IF Eof()
               dbSkip( -1 )
               EXIT
            ENDIF
            nSkipped++
         ENDDO
      ELSEIF nRecs < 0
         DO WHILE nSkipped > nRecs
            dbSkip( -1 )
            IF Bof()
               EXIT
            ENDIF
            nSkipped--
         ENDDO
      ENDIF
   ENDIF

   RETURN nSkipped

FUNCTION XToStrE( xValue )
   LOCAL cType := ValType( xValue )

   DO CASE
   CASE cType == "C"

      xValue := StrTran( xValue, Chr(0), '"+Chr(0)+"' )
      xValue := StrTran( xValue, Chr(9), '"+Chr(9)+"' )
      xValue := StrTran( xValue, Chr(10), '"+Chr(10)+"' )
      xValue := StrTran( xValue, Chr(13), '"+Chr(13)+"' )
      xValue := StrTran( xValue, Chr(26), '"+Chr(26)+"' )

      RETURN xValue

   CASE cType == "N" ; RETURN LTrim( Str( xValue ) )
   CASE cType == "D" ; RETURN DToS( xValue )
   CASE cType == "L" ; RETURN iif( xValue, ".T.", ".F." )
   CASE cType == "O" ; RETURN xValue:className() + " Object"
   CASE cType == "U" ; RETURN "NIL"
   CASE cType == "B" ; RETURN '{||...} -> ' + XToStrE( Eval( xValue ) )
   CASE cType == "A" ; RETURN '{ ' + ArrayToEList( xValue ) + ' }'
   CASE cType == "M" ; RETURN 'M:' + xValue
   ENDCASE

   RETURN ""

FUNCTION ArrayToEList( a )
   LOCAL tmp
   LOCAL cString := ""

   FOR tmp := 1 TO Len( a )
      cString += XToStrE( a[ tmp ] )
      IF tmp < Len( a )
         cString += ", "
      ENDIF
   NEXT

   RETURN cString

FUNCTION ForceStable( o )

   DO WHILE !TEST_CALL( o:stabilize )
   ENDDO

   RETURN NIL

FUNCTION TEST_C_CALL( o, cBlock, bBlock )
   LOCAL xRetVal
   LOCAL cOldBlock := s_cCurrBlock

   s_cCurrBlock := cBlock

   LOGSTUFF( o, .T., "BEGIN" )
   xRetVal := Eval( bBlock )
   LOGSTUFF( o, .T., "END" )

   s_cCurrBlock := cOldBlock

   RETURN xRetVal

FUNCTION LOGSTUFF( o, l, cText )

   STATIC s_nRow := 0

   IF s_nRow == MaxRow()
      Scroll( 0, 16, MaxRow(), MaxCol(), 1, 0 )
      DispOutAt( MaxRow(), 0, Space( MaxCol() + 1 ) )
   ELSE
      s_nRow++
   ENDIF

   #define DispOut( x ) OutStd( x )

   SetPos( s_nRow, 16 + iif( l, 0, 3 ) )
   DispOut( ++s_nCount ) ; DispOut( " " )
   DispOut( PadR( iif( l, s_cCurrBlock, "" ), 11 ) ) ; DispOut( " " )
   DispOut( iif( o != NIL, o:rowPos, PadL( "", 10 ) ) ) ; DispOut( " " )
   DispOut( cText ) ; DispOut( " " )
   DispOut( Chr( 13 ) + Chr( 10 ) )

   RETURN NIL

FUNCTION my_QOut( o, a )

   LOGSTUFF( o, .F., ArrayToEList( a ) )

   RETURN NIL
_______________________________________________
Harbour mailing list
[email protected]
http://lists.harbour-project.org/mailman/listinfo/harbour

Reply via email to