2008-11-04 22:39 UTC+0100 Przemyslaw Czerpak (druzus/at/priv.onet.pl)

* harbour/include/hbapi.h
  * harbour/source/vm/hashfunc.c
  * harbour/source/vm/hashes.c
    + added support for binary key order
    % enable binary internal key order by default for new hash arrays
    + added .prg function to enable/disable/retrive binary order in hash
      items:
         hb_hSetBinary( <hValue>, <lOnOff> ) => <hValue>
         hb_hBinary( <hValue> [, <lBinary> ] ) => <lBinary>
    + added support for hash array resorting. It's activated automatically
      on 1-st key access/assign after changing binary or casematch hash
      array flag
    + added .prg function hb_hSort( <hValue> ) => <hValue> which marks
      hash array for sorting

  * harbour/source/rtl/itemseri.c
    % improved performance of hash array deserialization
      TODO: add support for hash array flags and hash default value
            serialization
This commit is contained in:
Przemyslaw Czerpak
2008-11-04 21:39:10 +00:00
parent f1e3ae30e9
commit bb49e3711a
5 changed files with 182 additions and 28 deletions

View File

@@ -8,6 +8,27 @@
2008-12-31 13:59 UTC+0100 Foo Bar (foo.bar foobar.org)
*/
2008-11-04 22:39 UTC+0100 Przemyslaw Czerpak (druzus/at/priv.onet.pl)
* harbour/include/hbapi.h
* harbour/source/vm/hashfunc.c
* harbour/source/vm/hashes.c
+ added support for binary key order
% enable binary internal key order by default for new hash arrays
+ added .prg function to enable/disable/retrive binary order in hash
items:
hb_hSetBinary( <hValue>, <lOnOff> ) => <hValue>
hb_hBinary( <hValue> [, <lBinary> ] ) => <lBinary>
+ added support for hash array resorting. It's activated automatically
on 1-st key access/assign after changing binary or casematch hash
array flag
+ added .prg function hb_hSort( <hValue> ) => <hValue> which marks
hash array for sorting
* harbour/source/rtl/itemseri.c
% improved performance of hash array deserialization
TODO: add support for hash array flags and hash default value
serialization
2008-11-04 19:59 UTC+0200 Viktor Szakats (harbour.01 syenar hu)
* contrib/hbnf/getenvrn.c
- Removed some obsolete comments.

View File

@@ -756,6 +756,7 @@ extern HB_EXPORT BOOL hb_hashDel( PHB_ITEM pHash, PHB_ITEM pKey );
extern HB_EXPORT BOOL hb_hashAdd( PHB_ITEM pHash, PHB_ITEM pKey, PHB_ITEM pValue );
extern HB_EXPORT BOOL hb_hashAddNew( PHB_ITEM pHash, PHB_ITEM pKey, PHB_ITEM pValue );
extern HB_EXPORT BOOL hb_hashRemove( PHB_ITEM pHash, PHB_ITEM pItem );
extern HB_EXPORT BOOL hb_hashAllocNewPair( PHB_ITEM pHash, PHB_ITEM * pKeyPtr, PHB_ITEM * pValPtr );
extern HB_EXPORT PHB_ITEM hb_hashClone( PHB_ITEM pSource );
extern HB_EXPORT void hb_hashJoin( PHB_ITEM pDest, PHB_ITEM pSource, int iType );
extern HB_EXPORT BOOL hb_hashScan( PHB_ITEM pHash, PHB_ITEM pKey, ULONG * pulPos );
@@ -785,7 +786,13 @@ extern HB_EXPORT BOOL hb_hashDelAt( PHB_ITEM pHash, ULONG ulPos );
#define HB_HASH_AUTOADD_REFERENCE HB_HASH_AUTOADD_ALWAYS
#define HB_HASH_AUTOADD_MASK 0x03
#define HB_HASH_RESORT 0x08
#define HB_HASH_IGNORECASE 0x10
#define HB_HASH_BINARY 0x20
#define HB_HASH_FLAG_MASK 0xFFFF
#define HB_HASH_FLAG_DEFAULT ( HB_HASH_AUTOADD_ASSIGN | HB_HASH_BINARY )
#ifdef _HB_API_INTERNAL_
/* internal hash API not exported */

View File

@@ -263,9 +263,9 @@ static void hb_itemSerialRefFree( PHB_CYCLIC_REF pRef )
{
while( pRef )
{
PHB_CYCLIC_REF pNext = pRef->pNext;
hb_xfree( pRef );
pRef = pNext;
PHB_CYCLIC_REF pFree = pRef;
pRef = pRef->pNext;
hb_xfree( pFree );
}
}
@@ -708,6 +708,7 @@ static ULONG hb_deserializeHash( PHB_ITEM pItem, UCHAR * pBuffer, ULONG ulOffset
if( ulLen )
{
#if 0
PHB_ITEM pKey = hb_itemNew( NULL );
PHB_ITEM pVal = hb_itemNew( NULL );
@@ -720,6 +721,20 @@ static ULONG hb_deserializeHash( PHB_ITEM pItem, UCHAR * pBuffer, ULONG ulOffset
}
hb_itemRelease( pKey );
hb_itemRelease( pVal );
#else
PHB_ITEM pKey, pVal;
hb_hashSetFlags( pItem, HB_HASH_BINARY | HB_HASH_RESORT );
hb_hashPreallocate( pItem, ulLen );
while( ulLen-- )
{
if( hb_hashAllocNewPair( pItem, &pKey, &pVal ) )
{
ulOffset = hb_deserializeItem( pKey, pBuffer, ulOffset, pRef );
ulOffset = hb_deserializeItem( pVal, pBuffer, ulOffset, pRef );
}
}
#endif
}
return ulOffset;

View File

@@ -136,13 +136,19 @@ static HB_GARBAGE_FUNC( hb_hashReleaseGarbage )
}
}
static int hb_hashItemCmp( PHB_ITEM pKey1, PHB_ITEM pKey2, BOOL fIgnoreCase )
static int hb_hashItemCmp( PHB_ITEM pKey1, PHB_ITEM pKey2, int iFlags )
{
if( HB_IS_STRING( pKey1 ) )
{
if( HB_IS_STRING( pKey2 ) )
{
if( fIgnoreCase )
if( iFlags & HB_HASH_BINARY )
return pKey1->item.asString.length < pKey2->item.asString.length ? -1 :
( pKey1->item.asString.length > pKey2->item.asString.length ? 1 :
memcmp( pKey1->item.asString.value,
pKey2->item.asString.value,
pKey1->item.asString.length ) );
else if( iFlags & HB_HASH_IGNORECASE )
return hb_itemStrICmp( pKey1, pKey2, TRUE );
else
return hb_itemStrCmp( pKey1, pKey2, TRUE );
@@ -184,16 +190,48 @@ static int hb_hashItemCmp( PHB_ITEM pKey1, PHB_ITEM pKey2, BOOL fIgnoreCase )
return -1;
}
static void hb_hashResort( PHB_BASEHASH pBaseHash )
{
ULONG ulPos, ulFrom;
int iFlags = pBaseHash->iFlags;
/* 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 )
{
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;
}
}
pBaseHash->iFlags &= ~HB_HASH_RESORT;
}
static BOOL hb_hashFind( PHB_BASEHASH pBaseHash, PHB_ITEM pKey, ULONG * pulPos )
{
ULONG ulLeft = 0, ulRight = pBaseHash->ulLen, ulMiddle;
BOOL fIgnoreCase = ( pBaseHash->iFlags & HB_HASH_IGNORECASE ) != 0;
ULONG ulLeft, ulRight, ulMiddle;
int iFlags = pBaseHash->iFlags;
int i;
if( iFlags & HB_HASH_RESORT )
hb_hashResort( pBaseHash );
ulLeft = 0;
ulRight = pBaseHash->ulLen;
while( ulLeft < ulRight )
{
ulMiddle = ( ulLeft + ulRight ) >> 1;
i = hb_hashItemCmp( &pBaseHash->pPairs[ ulMiddle ].key, pKey, fIgnoreCase );
i = hb_hashItemCmp( &pBaseHash->pPairs[ ulMiddle ].key, pKey, iFlags );
if( i == 0 )
{
if( pulPos )
@@ -301,6 +339,16 @@ static BOOL hb_hashNewValue( PHB_BASEHASH pBaseHash, PHB_ITEM pKey, PHB_ITEM pVa
return FALSE;
}
static void hb_hashNewPair( PHB_BASEHASH pBaseHash, PHB_ITEM * pKeyPtr, PHB_ITEM * pValPtr )
{
if( pBaseHash->ulSize == pBaseHash->ulLen )
hb_hashResize( pBaseHash, pBaseHash->ulSize + HB_HASH_ITEM_ALLOC );
* pKeyPtr = &pBaseHash->pPairs[ pBaseHash->ulLen ].key;
* pValPtr = &pBaseHash->pPairs[ pBaseHash->ulLen ].value;
pBaseHash->ulLen++;
}
static void hb_hashDelPair( PHB_BASEHASH pBaseHash, ULONG ulPos )
{
if( --pBaseHash->ulLen == 0 )
@@ -314,23 +362,19 @@ static void hb_hashDelPair( PHB_BASEHASH pBaseHash, ULONG ulPos )
hb_itemClear( &pPairs->value );
hb_xfree( pPairs );
}
else if( ulPos == pBaseHash->ulLen )
{
hb_itemSetNil( &pBaseHash->pPairs[ ulPos ].key );
hb_itemSetNil( &pBaseHash->pPairs[ ulPos ].value );
}
else
{
HB_HASHPAIR pair;
memcpy( &pair, pBaseHash->pPairs + ulPos, sizeof( HB_HASHPAIR ) );
memmove( pBaseHash->pPairs + ulPos, pBaseHash->pPairs + ulPos + 1,
( pBaseHash->ulLen - ulPos ) * sizeof( HB_HASHPAIR ) );
pBaseHash->pPairs[ pBaseHash->ulLen ].key.type = HB_IT_NIL;
pBaseHash->pPairs[ pBaseHash->ulLen ].value.type = HB_IT_NIL;
if( HB_IS_COMPLEX( &pair.key ) )
hb_itemClear( &pair.key );
if( HB_IS_COMPLEX( &pair.value ) )
hb_itemClear( &pair.value );
if( ulPos != pBaseHash->ulLen )
{
HB_HASHPAIR pair;
memcpy( &pair, pBaseHash->pPairs + ulPos, sizeof( HB_HASHPAIR ) );
memmove( pBaseHash->pPairs + ulPos, pBaseHash->pPairs + ulPos + 1,
( pBaseHash->ulLen - ulPos ) * sizeof( HB_HASHPAIR ) );
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 ) )
{
pBaseHash->ulSize -= HB_HASH_ITEM_ALLOC;
@@ -355,7 +399,7 @@ HB_EXPORT PHB_ITEM hb_hashNew( PHB_ITEM pItem )
pBaseHash->pPairs = NULL;
pBaseHash->ulSize = 0;
pBaseHash->ulLen = 0;
pBaseHash->iFlags = HB_HASH_AUTOADD_ASSIGN;
pBaseHash->iFlags = HB_HASH_FLAG_DEFAULT;
pBaseHash->pDefault = NULL;
pItem->type = HB_IT_HASH;
@@ -380,6 +424,19 @@ HB_EXPORT void hb_hashPreallocate( PHB_ITEM pHash, ULONG ulNewSize )
hb_hashResize( pHash->item.asHash.value, ulNewSize );
}
HB_EXPORT BOOL hb_hashAllocNewPair( PHB_ITEM pHash, PHB_ITEM * pKeyPtr, PHB_ITEM * pValPtr )
{
HB_TRACE(HB_TR_DEBUG, ("hb_hashAllocNewPair(%p,%p,%p)", pHash, pKeyPtr, pValPtr));
if( HB_IS_HASH( pHash ) )
{
hb_hashNewPair( pHash->item.asHash.value, pKeyPtr, pValPtr );
return TRUE;
}
else
return FALSE;
}
HB_EXPORT PHB_ITEM hb_hashGetItemPtr( PHB_ITEM pHash, PHB_ITEM pKey, int iFlags )
{
HB_TRACE(HB_TR_DEBUG, ("hb_hashGetItemPtr(%p,%p,%d)", pHash, pKey, iFlags));

View File

@@ -604,6 +604,19 @@ HB_FUNC( HB_HSCAN )
hb_errRT_BASE( EG_ARG, 1123, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
HB_FUNC( HB_HSORT )
{
PHB_ITEM pHash = hb_param( 1, HB_IT_HASH );
if( pHash )
{
hb_hashSetFlags( pHash, HB_HASH_RESORT );
hb_itemReturn( pHash );
}
else
hb_errRT_BASE( EG_ARG, 2017, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
HB_FUNC( HB_HCASEMATCH )
{
PHB_ITEM pHash = hb_param( 1, HB_IT_HASH );
@@ -611,13 +624,53 @@ HB_FUNC( HB_HCASEMATCH )
if( pHash )
{
hb_retl( ( hb_hashGetFlags( pHash ) & HB_HASH_IGNORECASE ) == 0 );
int iFlags = hb_hashGetFlags( pHash );
hb_retl( ( iFlags & HB_HASH_IGNORECASE ) == 0 );
if( pValue )
{
if( hb_itemGetL( pValue ) )
hb_hashClearFlags( pHash, HB_HASH_IGNORECASE );
else
hb_hashSetFlags( pHash, HB_HASH_IGNORECASE );
{
if( ( iFlags & HB_HASH_IGNORECASE ) != 0 )
{
hb_hashClearFlags( pHash, HB_HASH_IGNORECASE );
hb_hashSetFlags( pHash, HB_HASH_RESORT );
}
}
else if( ( iFlags & HB_HASH_IGNORECASE ) == 0 )
{
hb_hashClearFlags( pHash, HB_HASH_BINARY );
hb_hashSetFlags( pHash, HB_HASH_IGNORECASE | HB_HASH_RESORT );
}
}
}
else
hb_errRT_BASE( EG_ARG, 2017, NULL, HB_ERR_FUNCNAME, HB_ERR_ARGS_BASEPARAMS );
}
HB_FUNC( HB_HBINARY )
{
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_BINARY ) != 0 );
if( pValue )
{
if( hb_itemGetL( pValue ) )
{
if( ( iFlags & HB_HASH_BINARY ) == 0 )
{
hb_hashClearFlags( pHash, HB_HASH_IGNORECASE );
hb_hashSetFlags( pHash, HB_HASH_BINARY | HB_HASH_RESORT );
}
}
else if( ( iFlags & HB_HASH_BINARY ) != 0 )
{
hb_hashClearFlags( pHash, HB_HASH_BINARY );
hb_hashSetFlags( pHash, HB_HASH_RESORT );
}
}
}
else
@@ -688,3 +741,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 ) ); }