diff --git a/harbour/ChangeLog b/harbour/ChangeLog index aba55065b6..dcd46fafd5 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -17,6 +17,47 @@ past entries belonging to author(s): Viktor Szakats. */ +2010-05-25 13:20 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl) + * harbour/include/hbapi.h + * harbour/src/vm/hashes.c + * harbour/src/vm/hashfunc.c + + added support for keeping strict assign order in hash arrays. It's + enabled optionally by setting HB_HASH_KEEPORDER hash array flag. + It gives the same functionality as associative arrays in xHarbour + (enabled by HSETAACOMPATIBILITY()) but this implementation is + internally completely different. It does not introduce linear + scan in add operation so enabling it should not reduce the + performance in this operation. It can even improve it on some + hardware reducing number of memory bytes which have to be moved. + Only delete operation will force linear index scan. The most + important in this implementation is that it does not need any + additional functions like HAA*() in xHarbour. Just simply all + existing functions operating on position indexes like HB_HPOS(), + HB_HKEYAT(), HB_HVALUEAT(), HB_HPAIRAT(), HB_HDELAT(), HB_HSCAN() + use as index natural order in which items were added to hash array. + Also HB_HKEYS(), HB_HVALUES() and FOR EACH iterations respect it. + + added new PRG functions + HB_HKEEPORDER( [, ] ) -> + HB_HSETORDER( [, ] ) -> + which cam be used to enable/disable strict order in hash array. + Enabling strict order for non empty hash arrays accept the order + created after sorting existing item not the original assign order. + Disabling strict order for non empty hash arrays may change the + items order. + ; TODO: add translation for xHarbour's HAA*() functions to hbcompat.ch + and/or xhb library. + + * harbour/contrib/hbnetio/netiocli.c + * harbour/contrib/hbnetio/netiosrv.c + % reenabled TCP_NODELAY on client and server side + I had to be really tired when I was making tests and I mixed + hb_socketSetNoDelay() with hb_socketSetBlockingIO(). + Thanks to Aleksander Czajczynski who noticed the delay in his + tests. + + * harbour/contrib/hbwin/olecore.c + * minor cleanup + 2010-05-25 09:21 UTC+0200 Viktor Szakats (harbour.01 syenar.hu) * contrib/hbct/ctrand.prg * contrib/hbct/getsecrt.prg diff --git a/harbour/contrib/hbnetio/netiocli.c b/harbour/contrib/hbnetio/netiocli.c index 22e48a769a..5f8b60977e 100644 --- a/harbour/contrib/hbnetio/netiocli.c +++ b/harbour/contrib/hbnetio/netiocli.c @@ -860,7 +860,7 @@ static PHB_CONCLI s_fileConnect( const char ** pFilename, HB_PUT_LE_UINT16( &msgbuf[ 4 ], len ); memset( msgbuf + 6, '\0', sizeof( msgbuf ) - 6 ); - hb_socketSetNoDelay( sd, HB_FALSE ); + hb_socketSetNoDelay( sd, HB_TRUE ); conn = s_fileConNew( sd, pszIpAddres, iPort, iTimeOut, pszPasswd, iPassLen, iLevel, iStrategy ); sd = HB_NO_SOCKET; diff --git a/harbour/contrib/hbnetio/netiosrv.c b/harbour/contrib/hbnetio/netiosrv.c index ff614ad530..2fc66f875f 100644 --- a/harbour/contrib/hbnetio/netiosrv.c +++ b/harbour/contrib/hbnetio/netiosrv.c @@ -618,7 +618,7 @@ HB_FUNC( NETIO_ACCEPT ) if( connsd != HB_NO_SOCKET ) { hb_socketSetKeepAlive( connsd, HB_TRUE ); - hb_socketSetNoDelay( connsd, HB_FALSE ); + hb_socketSetNoDelay( connsd, HB_TRUE ); conn = s_consrvNew( connsd, lsd->rootPath, lsd->rpc ); diff --git a/harbour/contrib/hbwin/olecore.c b/harbour/contrib/hbwin/olecore.c index 6baae1ff4e..a8bbf0307e 100644 --- a/harbour/contrib/hbwin/olecore.c +++ b/harbour/contrib/hbwin/olecore.c @@ -1460,7 +1460,7 @@ HB_FUNC( WIN_OLEAUTO___ONERROR ) /* Try property put */ - if( szMethod[ 0 ] == '_' && hb_pcount() > 0 ) + if( szMethod[ 0 ] == '_' && hb_pcount() == 1 ) { pMemberArray = &szMethodWide[ 1 ]; lOleError = HB_VTBL( pDisp )->GetIDsOfNames( HB_THIS_( pDisp ) HB_ID_REF( IID_NULL ), &pMemberArray, diff --git a/harbour/include/hbapi.h b/harbour/include/hbapi.h index 7ffc4c8d59..692bf44d0c 100644 --- a/harbour/include/hbapi.h +++ b/harbour/include/hbapi.h @@ -891,6 +891,7 @@ extern HB_EXPORT HB_BOOL hb_hashDelAt( PHB_ITEM pHash, HB_SIZE ulPos ); #define HB_HASH_IGNORECASE 0x10 #define HB_HASH_BINARY 0x20 +#define HB_HASH_KEEPORDER 0x40 #define HB_HASH_FLAG_MASK 0xFFFF #define HB_HASH_FLAG_DEFAULT ( HB_HASH_AUTOADD_ASSIGN | HB_HASH_BINARY ) diff --git a/harbour/src/vm/hashes.c b/harbour/src/vm/hashes.c index 7503dbc1d9..49e9057e2f 100644 --- a/harbour/src/vm/hashes.c +++ b/harbour/src/vm/hashes.c @@ -76,6 +76,7 @@ typedef struct _HB_BASEHASH { PHB_HASHPAIR pPairs; /* pointer to the array of key/value pairs */ PHB_ITEM pDefault; /* default autoadd value */ + HB_SIZE * pulPos; /* the sort order for HB_HASH_KEEPORDER */ HB_SIZE ulSize; /* size of allocated pair array */ HB_SIZE ulLen; /* number of used items in pair array */ int iFlags; /* hash item flags */ @@ -102,6 +103,12 @@ static HB_GARBAGE_FUNC( hb_hashGarbageRelease ) pBaseHash->pPairs = NULL; pBaseHash->ulLen = 0; + if( pBaseHash->pulPos ) + { + hb_xfree( pBaseHash->pulPos ); + pBaseHash->pulPos = NULL; + } + while( ulLen-- ) { if( HB_IS_COMPLEX( &pPairs[ ulLen ].key ) ) @@ -212,18 +219,38 @@ static void hb_hashResort( PHB_BASEHASH pBaseHash ) /* The hash array is probably quite well sorted so this trivial * algorithm is the most efficient one [druzus] */ - for( ulFrom = 1; ulFrom < pBaseHash->ulLen; ++ulFrom ) + + if( pBaseHash->pulPos ) { - ulPos = ulFrom; - while( ulPos > 0 && hb_hashItemCmp( &pBaseHash->pPairs[ ulPos - 1 ].key, - &pBaseHash->pPairs[ ulPos ].key, - iFlags ) > 0 ) + for( ulFrom = 1; ulFrom < pBaseHash->ulLen; ++ulFrom ) { - HB_HASHPAIR pair; - memcpy( &pair, pBaseHash->pPairs + ulPos - 1, sizeof( HB_HASHPAIR ) ); - memcpy( pBaseHash->pPairs + ulPos - 1, pBaseHash->pPairs + ulPos, sizeof( HB_HASHPAIR ) ); - memcpy( pBaseHash->pPairs + ulPos, &pair, sizeof( HB_HASHPAIR ) ); - --ulPos; + ulPos = ulFrom; + while( ulPos > 0 && hb_hashItemCmp( &pBaseHash->pPairs[ pBaseHash->pulPos[ ulPos - 1 ] ].key, + &pBaseHash->pPairs[ pBaseHash->pulPos[ ulPos ] ].key, + iFlags ) > 0 ) + { + HB_SIZE ulTemp = pBaseHash->pulPos[ ulPos - 1 ]; + pBaseHash->pulPos[ ulPos - 1 ] = pBaseHash->pulPos[ ulPos ]; + pBaseHash->pulPos[ ulPos ] = ulTemp; + --ulPos; + } + } + } + else + { + for( ulFrom = 1; ulFrom < pBaseHash->ulLen; ++ulFrom ) + { + ulPos = ulFrom; + while( ulPos > 0 && hb_hashItemCmp( &pBaseHash->pPairs[ ulPos - 1 ].key, + &pBaseHash->pPairs[ ulPos ].key, + iFlags ) > 0 ) + { + HB_HASHPAIR pair; + memcpy( &pair, pBaseHash->pPairs + ulPos - 1, sizeof( HB_HASHPAIR ) ); + memcpy( pBaseHash->pPairs + ulPos - 1, pBaseHash->pPairs + ulPos, sizeof( HB_HASHPAIR ) ); + memcpy( pBaseHash->pPairs + ulPos, &pair, sizeof( HB_HASHPAIR ) ); + --ulPos; + } } } @@ -245,11 +272,13 @@ static HB_BOOL hb_hashFind( PHB_BASEHASH pBaseHash, PHB_ITEM pKey, HB_SIZE * pul while( ulLeft < ulRight ) { ulMiddle = ( ulLeft + ulRight ) >> 1; - i = hb_hashItemCmp( &pBaseHash->pPairs[ ulMiddle ].key, pKey, iFlags ); + i = hb_hashItemCmp( &pBaseHash->pPairs[ pBaseHash->pulPos ? + pBaseHash->pulPos[ ulMiddle ] : ulMiddle ].key, + pKey, iFlags ); if( i == 0 ) { if( pulPos ) - *pulPos = ulMiddle; + *pulPos = pBaseHash->pulPos ? pBaseHash->pulPos[ ulMiddle ] : ulMiddle; return HB_TRUE; } else if( i < 0 ) @@ -268,10 +297,19 @@ static void hb_hashResize( PHB_BASEHASH pBaseHash, HB_SIZE ulNewSize ) if( pBaseHash->ulSize < ulNewSize ) { if( pBaseHash->ulSize ) + { pBaseHash->pPairs = ( PHB_HASHPAIR ) hb_xrealloc( pBaseHash->pPairs, ulNewSize * sizeof( HB_HASHPAIR ) ); + if( pBaseHash->pulPos ) + pBaseHash->pulPos = ( HB_SIZE * ) hb_xrealloc( pBaseHash->pulPos, + ulNewSize * sizeof( HB_SIZE ) ); + } else + { pBaseHash->pPairs = ( PHB_HASHPAIR ) hb_xgrab( ulNewSize * sizeof( HB_HASHPAIR ) ); + if( pBaseHash->iFlags & HB_HASH_KEEPORDER ) + pBaseHash->pulPos = ( HB_SIZE * ) hb_xgrab( ulNewSize * sizeof( HB_SIZE ) ); + } do { @@ -284,12 +322,22 @@ static void hb_hashResize( PHB_BASEHASH pBaseHash, HB_SIZE ulNewSize ) { pBaseHash->ulSize = ulNewSize; if( ulNewSize ) + { pBaseHash->pPairs = ( PHB_HASHPAIR ) hb_xrealloc( pBaseHash->pPairs, ulNewSize * sizeof( HB_HASHPAIR ) ); + if( pBaseHash->pulPos ) + pBaseHash->pulPos = ( HB_SIZE * ) hb_xrealloc( pBaseHash->pulPos, + ulNewSize * sizeof( HB_SIZE ) ); + } else { hb_xfree( pBaseHash->pPairs ); pBaseHash->pPairs = NULL; + if( pBaseHash->pulPos ) + { + hb_xfree( pBaseHash->pulPos ); + pBaseHash->pulPos = NULL; + } } } } @@ -306,7 +354,13 @@ static PHB_ITEM hb_hashValuePtr( PHB_BASEHASH pBaseHash, PHB_ITEM pKey, HB_BOOL if( pBaseHash->ulSize == pBaseHash->ulLen ) hb_hashResize( pBaseHash, pBaseHash->ulSize + HB_HASH_ITEM_ALLOC ); - if( ulPos < pBaseHash->ulLen ) + if( pBaseHash->pulPos ) + { + memmove( pBaseHash->pulPos + ulPos + 1, pBaseHash->pulPos + ulPos, + ( pBaseHash->ulLen - ulPos ) * sizeof( HB_SIZE ) ); + ulPos = ( pBaseHash->pulPos[ ulPos ] = pBaseHash->ulLen ); + } + else if( ulPos < pBaseHash->ulLen ) { memmove( pBaseHash->pPairs + ulPos + 1, pBaseHash->pPairs + ulPos, ( pBaseHash->ulLen - ulPos ) * sizeof( HB_HASHPAIR ) ); @@ -331,7 +385,13 @@ static HB_BOOL hb_hashNewValue( PHB_BASEHASH pBaseHash, PHB_ITEM pKey, PHB_ITEM if( pBaseHash->ulSize == pBaseHash->ulLen ) hb_hashResize( pBaseHash, pBaseHash->ulSize + HB_HASH_ITEM_ALLOC ); - if( ulPos < pBaseHash->ulLen ) + if( pBaseHash->pulPos ) + { + memmove( pBaseHash->pulPos + ulPos + 1, pBaseHash->pulPos + ulPos, + ( pBaseHash->ulLen - ulPos ) * sizeof( HB_SIZE ) ); + ulPos = ( pBaseHash->pulPos[ ulPos ] = pBaseHash->ulLen ); + } + else if( ulPos < pBaseHash->ulLen ) { memmove( pBaseHash->pPairs + ulPos + 1, pBaseHash->pPairs + ulPos, ( pBaseHash->ulLen - ulPos ) * sizeof( HB_HASHPAIR ) ); @@ -354,8 +414,12 @@ static void hb_hashNewPair( PHB_BASEHASH pBaseHash, PHB_ITEM * pKeyPtr, PHB_ITEM if( pBaseHash->ulSize == pBaseHash->ulLen ) hb_hashResize( pBaseHash, pBaseHash->ulSize + HB_HASH_ITEM_ALLOC ); + if( pBaseHash->pulPos ) + pBaseHash->pulPos[ pBaseHash->ulLen ] = pBaseHash->ulLen; + * pKeyPtr = &pBaseHash->pPairs[ pBaseHash->ulLen ].key; * pValPtr = &pBaseHash->pPairs[ pBaseHash->ulLen ].value; + pBaseHash->ulLen++; } @@ -366,6 +430,11 @@ static void hb_hashDelPair( PHB_BASEHASH pBaseHash, HB_SIZE ulPos ) PHB_HASHPAIR pPairs = pBaseHash->pPairs; pBaseHash->pPairs = NULL; pBaseHash->ulSize = 0; + if( pBaseHash->pulPos ) + { + hb_xfree( pBaseHash->pulPos ); + pBaseHash->pulPos = NULL; + } if( HB_IS_COMPLEX( &pPairs->key ) ) hb_itemClear( &pPairs->key ); if( HB_IS_COMPLEX( &pPairs->value ) ) @@ -374,6 +443,21 @@ static void hb_hashDelPair( PHB_BASEHASH pBaseHash, HB_SIZE ulPos ) } else { + if( pBaseHash->pulPos ) + { + HB_SIZE ul = 0; + while( ul < pBaseHash->ulLen ) + { + if( pBaseHash->pulPos[ ul ] > ulPos ) + pBaseHash->pulPos[ ul++ ]--; + else if( pBaseHash->pulPos[ ul ] == ulPos ) + memmove( &pBaseHash->pulPos[ ul ], &pBaseHash->pulPos[ ul + 1 ], + ( pBaseHash->ulLen - ul ) * sizeof( HB_SIZE ) ); + else + ++ul; + } + } + if( ulPos != pBaseHash->ulLen ) { HB_HASHPAIR pair; @@ -383,6 +467,7 @@ static void hb_hashDelPair( PHB_BASEHASH pBaseHash, HB_SIZE ulPos ) ulPos = pBaseHash->ulLen; memcpy( pBaseHash->pPairs + ulPos, &pair, sizeof( HB_HASHPAIR ) ); } + hb_itemSetNil( &pBaseHash->pPairs[ ulPos ].key ); hb_itemSetNil( &pBaseHash->pPairs[ ulPos ].value ); if( pBaseHash->ulSize - pBaseHash->ulLen > ( HB_HASH_ITEM_ALLOC << 1 ) ) @@ -390,6 +475,9 @@ static void hb_hashDelPair( PHB_BASEHASH pBaseHash, HB_SIZE ulPos ) pBaseHash->ulSize -= HB_HASH_ITEM_ALLOC; pBaseHash->pPairs = ( PHB_HASHPAIR ) hb_xrealloc( pBaseHash->pPairs, pBaseHash->ulSize * sizeof( HB_HASHPAIR ) ); + if( pBaseHash->pulPos ) + pBaseHash->pulPos = ( HB_SIZE * ) hb_xrealloc( pBaseHash->pulPos, + pBaseHash->ulSize * sizeof( HB_SIZE ) ); } } } @@ -407,6 +495,7 @@ PHB_ITEM hb_hashNew( PHB_ITEM pItem ) pBaseHash = ( PHB_BASEHASH ) hb_gcAllocRaw( sizeof( HB_BASEHASH ), &s_gcHashFuncs ); pBaseHash->pPairs = NULL; + pBaseHash->pulPos = NULL; pBaseHash->ulSize = 0; pBaseHash->ulLen = 0; pBaseHash->iFlags = HB_HASH_FLAG_DEFAULT; @@ -620,6 +709,11 @@ static HB_BOOL hb_hashClear( PHB_ITEM pHash ) hb_xfree( pHash->item.asHash.value->pPairs ); pHash->item.asHash.value->pPairs = NULL; pHash->item.asHash.value->ulSize = 0; + if( pHash->item.asHash.value->pulPos ) + { + hb_xfree( pHash->item.asHash.value->pulPos ); + pHash->item.asHash.value->pulPos = NULL; + } } } return HB_TRUE; @@ -768,14 +862,18 @@ void hb_hashCloneBody( PHB_ITEM pHash, PHB_ITEM pDest, PHB_NESTED_CLONED pCloned HB_TRACE(HB_TR_DEBUG, ("hb_hashCloneBody(%p,%p,%p)", pHash, pDest, pClonedList)); hb_hashNew( pDest ); - hb_hashResize( pDest->item.asHash.value, pHash->item.asHash.value->ulLen ); pDest->item.asHash.value->iFlags = pHash->item.asHash.value->iFlags; + hb_hashResize( pDest->item.asHash.value, pHash->item.asHash.value->ulLen ); if( pHash->item.asHash.value->pDefault ) { pDest->item.asHash.value->pDefault = hb_itemNew( pHash->item.asHash.value->pDefault ); hb_gcUnlock( pDest->item.asHash.value->pDefault ); } + if( pHash->item.asHash.value->pulPos ) + memcpy( pDest->item.asHash.value->pulPos, + pHash->item.asHash.value->pulPos, + pHash->item.asHash.value->ulLen * sizeof( HB_SIZE ) ); for( ulPos = 0; ulPos < pHash->item.asHash.value->ulLen; ++ulPos ) { PHB_ITEM pValue = &pHash->item.asHash.value->pPairs[ ulPos ].value; @@ -962,7 +1060,24 @@ void hb_hashSetFlags( PHB_ITEM pHash, int iFlags ) HB_TRACE(HB_TR_DEBUG, ("hb_hashSetFlags(%p,%d)", pHash, iFlags)); if( HB_IS_HASH( pHash ) ) + { pHash->item.asHash.value->iFlags |= iFlags; + if( pHash->item.asHash.value->pulPos == NULL && + pHash->item.asHash.value->ulSize && + ( pHash->item.asHash.value->iFlags & HB_HASH_KEEPORDER ) != 0 ) + { + HB_SIZE ul = pHash->item.asHash.value->ulSize; + + pHash->item.asHash.value->pulPos = ( HB_SIZE * ) + hb_xgrab( pHash->item.asHash.value->ulSize * sizeof( HB_SIZE ) ); + do + { + --ul; + pHash->item.asHash.value->pulPos[ ul ] = ul; + } + while( ul ); + } + } } void hb_hashClearFlags( PHB_ITEM pHash, int iFlags ) @@ -970,7 +1085,15 @@ void hb_hashClearFlags( PHB_ITEM pHash, int iFlags ) HB_TRACE(HB_TR_DEBUG, ("hb_hashClearFlags(%p,%d)", pHash, iFlags)); if( HB_IS_HASH( pHash ) ) + { pHash->item.asHash.value->iFlags &= ~iFlags; + if( pHash->item.asHash.value->pulPos != NULL && + ( pHash->item.asHash.value->iFlags & HB_HASH_KEEPORDER ) == 0 ) + { + hb_xfree( pHash->item.asHash.value->pulPos ); + pHash->item.asHash.value->pulPos = NULL; + } + } } int hb_hashGetFlags( PHB_ITEM pHash ) diff --git a/harbour/src/vm/hashfunc.c b/harbour/src/vm/hashfunc.c index 3eb618f95a..afe132220e 100644 --- a/harbour/src/vm/hashfunc.c +++ b/harbour/src/vm/hashfunc.c @@ -736,6 +736,33 @@ HB_FUNC( HB_HAUTOADD ) hb_errRT_BASE( EG_ARG, 2017, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); } +HB_FUNC( HB_HKEEPORDER ) +{ + PHB_ITEM pHash = hb_param( 1, HB_IT_HASH ); + PHB_ITEM pValue = hb_param( 2, HB_IT_LOGICAL ); + + if( pHash ) + { + int iFlags = hb_hashGetFlags( pHash ); + hb_retl( ( iFlags & HB_HASH_KEEPORDER ) != 0 ); + if( pValue ) + { + if( hb_itemGetL( pValue ) ) + { + if( ( iFlags & HB_HASH_KEEPORDER ) == 0 ) + hb_hashSetFlags( pHash, HB_HASH_KEEPORDER ); + } + else if( ( iFlags & HB_HASH_KEEPORDER ) != 0 ) + { + hb_hashClearFlags( pHash, HB_HASH_KEEPORDER ); + hb_hashSetFlags( pHash, HB_HASH_RESORT ); + } + } + } + else + hb_errRT_BASE( EG_ARG, 2017, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS ); +} + HB_FUNC( HB_HALLOCATE ) { PHB_ITEM pHash = hb_param( 1, HB_IT_HASH ); @@ -768,3 +795,4 @@ HB_FUNC( HB_HDEFAULT ) HB_FUNC( HB_HSETAUTOADD ) { HB_FUNC_EXEC( HB_HAUTOADD ); hb_itemReturn( hb_param( 1, HB_IT_HASH ) ); } HB_FUNC( HB_HSETCASEMATCH ) { HB_FUNC_EXEC( HB_HCASEMATCH ); hb_itemReturn( hb_param( 1, HB_IT_HASH ) ); } HB_FUNC( HB_HSETBINARY ) { HB_FUNC_EXEC( HB_HBINARY ); hb_itemReturn( hb_param( 1, HB_IT_HASH ) ); } +HB_FUNC( HB_HSETORDER ) { HB_FUNC_EXEC( HB_HKEEPORDER ); hb_itemReturn( hb_param( 1, HB_IT_HASH ) ); }