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( <hValue> [, <lNewSetting> ] ) -> <lPrevSetting>
         HB_HSETORDER( <hValue> [, <lNewSetting> ] ) -> <hValue>
      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
This commit is contained in:
Przemyslaw Czerpak
2010-05-25 11:20:34 +00:00
parent 6fce1cd697
commit 91cf12d405
7 changed files with 211 additions and 18 deletions

View File

@@ -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( <hValue> [, <lNewSetting> ] ) -> <lPrevSetting>
HB_HSETORDER( <hValue> [, <lNewSetting> ] ) -> <hValue>
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

View File

@@ -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;

View File

@@ -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 );

View File

@@ -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,

View File

@@ -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 )

View File

@@ -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 )

View File

@@ -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 ) ); }