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:
@@ -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.
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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 ) ); }
|
||||
|
||||
Reference in New Issue
Block a user