From 9e318add44ec844a54bc15f4e475e7d74e0f294f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20Czerpak?= Date: Fri, 31 Jul 2015 16:01:33 +0200 Subject: [PATCH] 2015-07-31 16:01 UTC+0200 Przemyslaw Czerpak (druzus/at/poczta.onet.pl) * src/vm/asort.c % added new code for ASort() Warning: new sorting algorithm is stable (does not change the order of equal items). It means is not strictly Cl*pper compatible and it can be seen some dummy ASort() tests in HBTEST results. --- ChangeLog.txt | 9 ++- src/vm/asort.c | 155 ++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 141 insertions(+), 23 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index 0f614d7cc9..f3db6a93db 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -10,7 +10,14 @@ * Change, ! Fix, % Optimization, + Addition, - Removal, ; Comment */ -2015-07-31 14:51 UTC+0200 Przemyslaw Czerpak (druzus/at/poczta.onet.pl) +2015-07-31 16:01 UTC+0200 Przemyslaw Czerpak (druzus/at/poczta.onet.pl) + * src/vm/asort.c + % added new code for ASort() + Warning: new sorting algorithm is stable (does not change the + order of equal items). It means is not strictly Cl*pper + compatible and it can be seen some dummy ASort() tests + in HBTEST results. + 2015-07-31 14:04 UTC+0200 Viktor Szakats (vszakats users.noreply.github.com) * include/hbapifs.h * src/rtl/filebuf.c diff --git a/src/vm/asort.c b/src/vm/asort.c index 9131604443..f32c79f608 100644 --- a/src/vm/asort.c +++ b/src/vm/asort.c @@ -57,33 +57,34 @@ #include "hbvmint.h" #include "hbapiitm.h" #include "hbvm.h" -#include "hbstack.h" -static HB_BOOL hb_itemIsLess( PHB_ITEM pItem1, PHB_ITEM pItem2, PHB_ITEM pBlock, PHB_BASEARRAY pBaseArray, HB_SIZE nLast ) +static HB_BOOL hb_itemIsLess( PHB_BASEARRAY pBaseArray, PHB_ITEM pBlock, + HB_SIZE nItem1, HB_SIZE nItem2 ) { + PHB_ITEM pItem1 = pBaseArray->pItems + nItem1, + pItem2 = pBaseArray->pItems + nItem2; + if( pBlock ) { + PHB_ITEM pRet; + + /* protection against array resizing by user codeblock */ + if( pBaseArray->nLen <= nItem1 || pBaseArray->nLen <= nItem2 ) + return HB_FALSE; + hb_vmPushEvalSym(); hb_vmPush( pBlock ); hb_vmPush( pItem1 ); hb_vmPush( pItem2 ); hb_vmSend( 2 ); - if( pBaseArray->nLen <= nLast ) - return HB_FALSE; - else - { - PHB_ITEM pRet = hb_param( -1, HB_IT_ANY ); + pRet = hb_param( -1, HB_IT_ANY ); - /* CA-Cl*pper always takes return value as logical item - * accepting 0, 1 as numeric representation of HB_FALSE/HB_TRUE - */ - if( HB_IS_LOGICAL( pRet ) || - HB_IS_NUMERIC( pRet ) ) - return hb_itemGetL( pRet ); - else - return HB_TRUE; - } + /* CA-Cl*pper always takes return value as logical item + * accepting 0, 1 as numeric representation of HB_FALSE/HB_TRUE + */ + return ( HB_IS_LOGICAL( pRet ) || HB_IS_NUMERIC( pRet ) ) ? + hb_itemGetL( pRet ) : HB_TRUE; } /* Do native compare when no codeblock is supplied */ @@ -137,6 +138,8 @@ static HB_BOOL hb_itemIsLess( PHB_ITEM pItem1, PHB_ITEM pItem2, PHB_ITEM pBlock, } } +#ifdef HB_CLP_STRICT + /* partition array pItems[lb..ub] */ static HB_ISIZ hb_arraySortQuickPartition( PHB_BASEARRAY pBaseArray, HB_ISIZ lb, HB_ISIZ ub, PHB_ITEM pBlock ) @@ -154,10 +157,10 @@ static HB_ISIZ hb_arraySortQuickPartition( PHB_BASEARRAY pBaseArray, HB_ISIZ lb, for( ;; ) { - while( j >= i && ! hb_itemIsLess( pBaseArray->pItems + j, pBaseArray->pItems + lb, pBlock, pBaseArray, j ) ) + while( j >= i && ! hb_itemIsLess( pBaseArray, pBlock, j, lb ) ) j--; - while( i < j && ! hb_itemIsLess( pBaseArray->pItems + lb, pBaseArray->pItems + i, pBlock, pBaseArray, i ) ) + while( i < j && ! hb_itemIsLess( pBaseArray, pBlock, lb, i ) ) i++; if( i >= j ) @@ -208,6 +211,117 @@ static void hb_arraySortQuick( PHB_BASEARRAY pBaseArray, HB_ISIZ lb, HB_ISIZ ub, } } +static void hb_arraySortStart( PHB_BASEARRAY pBaseArray, PHB_ITEM pBlock, + HB_SIZE nStart, HB_SIZE nCount ) +{ + hb_arraySortQuick( pBaseArray, nStart, nStart + nCount - 1, pBlock ); +} + +#else + +static HB_BOOL hb_arraySortDO( PHB_BASEARRAY pBaseArray, PHB_ITEM pBlock, + HB_SIZE * pSrc, HB_SIZE * pBuf, HB_SIZE nCount ) +{ + if( nCount > 1 ) + { + HB_SIZE nCnt1, nCnt2, * pPtr1, * pPtr2, * pDst; + HB_BOOL fBuf1, fBuf2; + + nCnt1 = nCount >> 1; + nCnt2 = nCount - nCnt1; + pPtr1 = &pSrc[ 0 ]; + pPtr2 = &pSrc[ nCnt1 ]; + + fBuf1 = hb_arraySortDO( pBaseArray, pBlock, pPtr1, &pBuf[ 0 ], nCnt1 ); + fBuf2 = hb_arraySortDO( pBaseArray, pBlock, pPtr2, &pBuf[ nCnt1 ], nCnt2 ); + if( fBuf1 ) + pDst = pBuf; + else + { + pDst = pSrc; + pPtr1 = &pBuf[ 0 ]; + } + if( ! fBuf2 ) + pPtr2 = &pBuf[ nCnt1 ]; + + while( nCnt1 > 0 && nCnt2 > 0 ) + { + if( hb_itemIsLess( pBaseArray, pBlock, *pPtr2, *pPtr1 ) ) + { + *pDst++ = *pPtr2++; + nCnt2--; + } + else + { + *pDst++ = *pPtr1++; + nCnt1--; + } + } + if( nCnt1 > 0 ) + { + do + *pDst++ = *pPtr1++; + while( --nCnt1 ); + } + else if( nCnt2 > 0 && fBuf1 == fBuf2 ) + { + do + *pDst++ = *pPtr2++; + while( --nCnt2 ); + } + return ! fBuf1; + } + return HB_TRUE; +} + +static void hb_arraySortStart( PHB_BASEARRAY pBaseArray, PHB_ITEM pBlock, + HB_SIZE nStart, HB_SIZE nCount ) +{ + HB_SIZE * pBuffer, * pDest, * pPos, nPos, nTo; + + pBuffer = ( HB_SIZE * ) hb_xgrab( sizeof( HB_SIZE ) * 2 * nCount ); + for( nPos = 0; nPos < nCount; ++nPos ) + pBuffer[ nPos ] = nStart + nPos; + + if( hb_arraySortDO( pBaseArray, pBlock, pBuffer, &pBuffer[ nCount ], nCount ) ) + pPos = ( pDest = pBuffer ) + nCount; + else + pDest = ( pPos = pBuffer ) + nCount; + + /* protection against array resizing by user codeblock */ + if( nStart + nCount >= pBaseArray->nLen ) + { + if( pBaseArray->nLen > nStart ) + { + for( nPos = nTo = 0; nPos < nCount; ++nPos ) + { + if( pDest[ nPos ] < pBaseArray->nLen ) + pDest[ nTo++ ] = pDest[ nPos ]; + } + nCount = nTo; + } + else + nCount = 0; + } + + for( nPos = 0; nPos < nCount; ++nPos ) + pPos[ pDest[ nPos ] - nStart ] = nPos; + + for( nPos = 0; nPos < nCount; ++nPos ) + { + if( nPos != pDest[ nPos ] ) + { + hb_itemSwap( pBaseArray->pItems + nPos, + pBaseArray->pItems + pDest[ nPos ] ); + pDest[ pPos[ nPos ] ] = pDest[ nPos ]; + pPos[ pDest[ nPos ] - nStart ] = pPos[ nPos ]; + } + } + + hb_xfree( pBuffer ); +} +#endif /* HB_CLP_STRICT */ + HB_BOOL hb_arraySort( PHB_ITEM pArray, HB_SIZE * pnStart, HB_SIZE * pnCount, PHB_ITEM pBlock ) { HB_TRACE( HB_TR_DEBUG, ( "hb_arraySort(%p, %p, %p, %p)", pArray, pnStart, pnCount, pBlock ) ); @@ -218,7 +332,6 @@ HB_BOOL hb_arraySort( PHB_ITEM pArray, HB_SIZE * pnStart, HB_SIZE * pnCount, PHB HB_SIZE nLen = pBaseArray->nLen; HB_SIZE nStart; HB_SIZE nCount; - HB_SIZE nEnd; if( pnStart && *pnStart >= 1 ) nStart = *pnStart; @@ -235,11 +348,9 @@ HB_BOOL hb_arraySort( PHB_ITEM pArray, HB_SIZE * pnStart, HB_SIZE * pnCount, PHB if( nStart + nCount > nLen ) /* check range */ nCount = nLen - nStart + 1; - nEnd = nCount + nStart - 2; - /* Optimize when only one or no element is to be sorted */ if( nCount > 1 ) - hb_arraySortQuick( pBaseArray, nStart - 1, nEnd, pBlock ); + hb_arraySortStart( pBaseArray, pBlock, nStart - 1, nCount ); } return HB_TRUE;