From 5f7b714ec339cced3780b74740babbdcdb3ab31d Mon Sep 17 00:00:00 2001 From: Przemyslaw Czerpak Date: Tue, 5 Feb 2013 22:04:55 +0000 Subject: [PATCH] 2013-02-05 23:04 UTC+0100 Przemyslaw Czerpak (druzus/at/poczta.onet.pl) * harbour/include/hboo.ch * added small comment * harbour/include/hbapirdd.h * harbour/src/rdd/workarea.c * fixed typo in parameter name * harbour/include/hbapi.h * harbour/src/vm/arrays.c + added to new C functions: hb_arraySetCPtr() and hb_arraySetCConst() * harbour/src/vm/classes.c + added support for passing assign type restrictions to in HB_OO_MSG_PROPERTY and HB_OO_MSG_CLASSPROPERTY in __clsAddMsg() It can be done by new option 7-th parameter. + added support for super class casting in __objGetIVars() and __objSetIVars(). Now this functions can be used to serialize all object instance variables also overloaded by other classes so they can be accessed only with super class casting or by nonvirtual messages. It means that above functions create fully functional serialization system and can be used as backed for HB_SERIALIZE() and HB_VALTOEXP() when objects are serialized. Such serialization consumes more time and needs more memory but objects can be deserialized by modified code which uses slightly different raw object representation. The original HB_SERIALIZE()/ HB_VALTOEXP() format is very fast and compact but it needs exactly the same raw object representation in the program which serialized object and in the program which later desrialize it. It may create serious problems if programmer modify the code, i.e adding new instance variables or changing their order in the object class or or in one of its ancestors and then tries to restore some objects serialized by previous program version. * updated some comments and few typos in local names * harbour/src/rtl/valtoexp.prg * modified HB_VALTOEXP() to use be default __objGetIVars() and __objSetIVars() to serialize objects. + added 2-nd parameter to HB_VALTOEXP(). By default it's .F. Setting it to .T. forces all raw serialization format. --- harbour/ChangeLog.txt | 41 ++++ harbour/include/hbapi.h | 2 + harbour/include/hbapirdd.h | 2 +- harbour/include/hboo.ch | 2 +- harbour/src/rdd/workarea.c | 18 +- harbour/src/rtl/valtoexp.prg | 30 ++- harbour/src/vm/arrays.c | 26 +++ harbour/src/vm/classes.c | 372 ++++++++++++++++++++++------------- 8 files changed, 332 insertions(+), 161 deletions(-) diff --git a/harbour/ChangeLog.txt b/harbour/ChangeLog.txt index 7f65c19152..c0a48bb455 100644 --- a/harbour/ChangeLog.txt +++ b/harbour/ChangeLog.txt @@ -10,6 +10,47 @@ * Change, ! Fix, % Optimization, + Addition, - Removal, ; Comment */ +2013-02-05 23:04 UTC+0100 Przemyslaw Czerpak (druzus/at/poczta.onet.pl) + * harbour/include/hboo.ch + * added small comment + + * harbour/include/hbapirdd.h + * harbour/src/rdd/workarea.c + * fixed typo in parameter name + + * harbour/include/hbapi.h + * harbour/src/vm/arrays.c + + added to new C functions: hb_arraySetCPtr() and hb_arraySetCConst() + + * harbour/src/vm/classes.c + + added support for passing assign type restrictions to in + HB_OO_MSG_PROPERTY and HB_OO_MSG_CLASSPROPERTY in __clsAddMsg() + It can be done by new option 7-th parameter. + + added support for super class casting in __objGetIVars() and + __objSetIVars(). Now this functions can be used to serialize + all object instance variables also overloaded by other classes + so they can be accessed only with super class casting or by + nonvirtual messages. It means that above functions create fully + functional serialization system and can be used as backed for + HB_SERIALIZE() and HB_VALTOEXP() when objects are serialized. + Such serialization consumes more time and needs more memory but + objects can be deserialized by modified code which uses slightly + different raw object representation. The original HB_SERIALIZE()/ + HB_VALTOEXP() format is very fast and compact but it needs exactly + the same raw object representation in the program which serialized + object and in the program which later desrialize it. It may create + serious problems if programmer modify the code, i.e adding new + instance variables or changing their order in the object class or + or in one of its ancestors and then tries to restore some objects + serialized by previous program version. + * updated some comments and few typos in local names + + * harbour/src/rtl/valtoexp.prg + * modified HB_VALTOEXP() to use be default __objGetIVars() and + __objSetIVars() to serialize objects. + + added 2-nd parameter to HB_VALTOEXP(). By default it's .F. + Setting it to .T. forces all raw serialization format. + 2013-02-05 13:01 UTC+0100 Viktor Szakats (harbour syenar.net) * utils/hbmk2/hbmk2.prg * utils/hbmk2/hbmk2.es_PE.po diff --git a/harbour/include/hbapi.h b/harbour/include/hbapi.h index c2dc64cbbb..ffca725e94 100644 --- a/harbour/include/hbapi.h +++ b/harbour/include/hbapi.h @@ -840,7 +840,9 @@ extern HB_EXPORT HB_BOOL hb_arraySetNInt( PHB_ITEM pArray, HB_SIZE nIndex, extern HB_EXPORT HB_BOOL hb_arraySetND( PHB_ITEM pArray, HB_SIZE nIndex, double dNumber ); extern HB_EXPORT HB_BOOL hb_arraySetC( PHB_ITEM pArray, HB_SIZE nIndex, const char * szText ); extern HB_EXPORT HB_BOOL hb_arraySetCL( PHB_ITEM pArray, HB_SIZE nIndex, const char * szText, HB_SIZE nLen ); +extern HB_EXPORT HB_BOOL hb_arraySetCPtr( PHB_ITEM pArray, HB_SIZE nIndex, char * szText ); extern HB_EXPORT HB_BOOL hb_arraySetCLPtr( PHB_ITEM pArray, HB_SIZE nIndex, char * szText, HB_SIZE nLen ); +extern HB_EXPORT HB_BOOL hb_arraySetCConst( PHB_ITEM pArray, HB_SIZE nIndex, const char * szText ); extern HB_EXPORT HB_BOOL hb_arraySetPtr( PHB_ITEM pArray, HB_SIZE nIndex, void * pValue ); extern HB_EXPORT HB_BOOL hb_arraySetPtrGC( PHB_ITEM pArray, HB_SIZE nIndex, void * pValue ); extern HB_EXPORT HB_BOOL hb_arraySetSymbol( PHB_ITEM pArray, HB_SIZE nIndex, PHB_SYMB pSymbol ); diff --git a/harbour/include/hbapirdd.h b/harbour/include/hbapirdd.h index 87fa3aa756..d772e085cb 100644 --- a/harbour/include/hbapirdd.h +++ b/harbour/include/hbapirdd.h @@ -1178,7 +1178,7 @@ extern HB_EXPORT void hb_rddReleaseCurrentArea( void ); extern HB_EXPORT int hb_rddRegister( const char * szDriver, HB_USHORT uiType ); extern HB_EXPORT HB_ERRCODE hb_rddInherit( RDDFUNCS * pTable, const RDDFUNCS * pSubTable, RDDFUNCS * pSuperTable, const char * szDrvName ); extern HB_EXPORT HB_ERRCODE hb_rddInheritEx( RDDFUNCS * pTable, const RDDFUNCS * pSubTable, RDDFUNCS * pSuperTable, const char * szDrvName, HB_USHORT * puiSuperRddId ); -extern HB_EXPORT HB_BOOL hb_rddIsDerivedFrom( HB_USHORT uiRddID, HB_USHORT uiSupperRddID ); +extern HB_EXPORT HB_BOOL hb_rddIsDerivedFrom( HB_USHORT uiRddID, HB_USHORT uiSuperRddID ); extern HB_EXPORT LPRDDNODE hb_rddGetNode( HB_USHORT uiNode ); extern HB_EXPORT LPRDDNODE hb_rddFindNode( const char * szDriver, HB_USHORT * uiIndex ); extern HB_EXPORT HB_USHORT hb_rddFieldIndex( AREAP pArea, const char * szName ); diff --git a/harbour/include/hboo.ch b/harbour/include/hboo.ch index 5e67e5c5d0..7124a864b7 100644 --- a/harbour/include/hboo.ch +++ b/harbour/include/hboo.ch @@ -103,7 +103,7 @@ #define HB_OO_MSG_CLSACCESS 11 #define HB_OO_MSG_REALCLASS 12 #define HB_OO_MSG_DESTRUCTOR 13 -#define HB_OO_MSG_INITIALIZED 14 +#define HB_OO_MSG_INITIALIZED 14 /* initialized class data: HB_OO_MSG_CLASSDATA */ #define HB_OO_MSG_PERFORM 15 #define HB_OO_MSG_DELEGATE 16 diff --git a/harbour/src/rdd/workarea.c b/harbour/src/rdd/workarea.c index b19c6adf17..53255083c0 100644 --- a/harbour/src/rdd/workarea.c +++ b/harbour/src/rdd/workarea.c @@ -2204,14 +2204,14 @@ int hb_rddRegister( const char * szDriver, HB_USHORT uiType ) */ HB_ERRCODE hb_rddInheritEx( RDDFUNCS * pTable, const RDDFUNCS * pSubTable, RDDFUNCS * pSuperTable, const char * szDrvName, - HB_USHORT * puiSupperRddId ) + HB_USHORT * puiSuperRddId ) { LPRDDNODE pRddNode; HB_USHORT uiCount; DBENTRYP_V * pFunction; const DBENTRYP_V * pSubFunction; - HB_TRACE( HB_TR_DEBUG, ( "hb_rddInheritEx(%p, %p, %p, %s, %p)", pTable, pSubTable, pSuperTable, szDrvName, puiSupperRddId ) ); + HB_TRACE( HB_TR_DEBUG, ( "hb_rddInheritEx(%p, %p, %p, %s, %p)", pTable, pSubTable, pSuperTable, szDrvName, puiSuperRddId ) ); if( ! pTable ) { @@ -2224,8 +2224,8 @@ HB_ERRCODE hb_rddInheritEx( RDDFUNCS * pTable, const RDDFUNCS * pSubTable, /* no name for inherited driver - use the default one */ memcpy( pTable, &waTable, sizeof( RDDFUNCS ) ); memcpy( pSuperTable, &waTable, sizeof( RDDFUNCS ) ); - if( puiSupperRddId ) - *puiSupperRddId = ( HB_USHORT ) -1; + if( puiSuperRddId ) + *puiSuperRddId = ( HB_USHORT ) -1; } else { @@ -2238,8 +2238,8 @@ HB_ERRCODE hb_rddInheritEx( RDDFUNCS * pTable, const RDDFUNCS * pSubTable, memcpy( pTable, &pRddNode->pTable, sizeof( RDDFUNCS ) ); memcpy( pSuperTable, &pRddNode->pTable, sizeof( RDDFUNCS ) ); - if( puiSupperRddId ) - *puiSupperRddId = pRddNode->rddID; + if( puiSuperRddId ) + *puiSuperRddId = pRddNode->rddID; } /* Copy the non NULL entries from pSubTable into pTable */ @@ -2263,15 +2263,15 @@ HB_ERRCODE hb_rddInherit( RDDFUNCS * pTable, const RDDFUNCS * pSubTable, return hb_rddInheritEx( pTable, pSubTable, pSuperTable, szDrvName, NULL ); } -HB_BOOL hb_rddIsDerivedFrom( HB_USHORT uiRddID, HB_USHORT uiSupperRddID ) +HB_BOOL hb_rddIsDerivedFrom( HB_USHORT uiRddID, HB_USHORT uiSuperRddID ) { - if( uiRddID == uiSupperRddID ) + if( uiRddID == uiSuperRddID ) return HB_TRUE; while( uiRddID < s_uiRddCount ) { uiRddID = s_RddList[ uiRddID ]->rddSuperID; - if( uiRddID == uiSupperRddID ) + if( uiRddID == uiSuperRddID ) return HB_TRUE; } return HB_FALSE; diff --git a/harbour/src/rtl/valtoexp.prg b/harbour/src/rtl/valtoexp.prg index 83c9604bfd..e461c01a5c 100644 --- a/harbour/src/rtl/valtoexp.prg +++ b/harbour/src/rtl/valtoexp.prg @@ -75,15 +75,17 @@ FUNCTION hb_CStr( xVal ) RETURN "???:" + v -REQUEST __objSetClass +REQUEST __objSetClass, __objGetIVars, __objSetIVars -FUNCTION hb_ValToExp( xVal ) +FUNCTION hb_ValToExp( xVal, lRaw ) - RETURN s_valToExp( xVal ) + hb_default( @lRaw, .F. ) -STATIC FUNCTION s_valToExp( xVal, cInd, hRefs, cRefs ) + RETURN s_valToExp( xVal, lRaw ) - LOCAL cVal, cKey +STATIC FUNCTION s_valToExp( xVal, lRaw, cInd, hRefs, cRefs ) + + LOCAL cVal, cKey, cClass LOCAL tmp LOCAL v := ValType( xVal ) @@ -95,8 +97,12 @@ STATIC FUNCTION s_valToExp( xVal, cInd, hRefs, cRefs ) CASE "T" ; RETURN 't"' + hb_TSToStr( xVal, .T. ) + '"' CASE "L" ; RETURN iif( xVal, ".T.", ".F." ) CASE "S" ; RETURN "@" + xVal:name + "()" - CASE "A" CASE "O" + cClass := xVal:className() + IF !lRaw + xVal := __objGetIVars( xVal ) + ENDIF + CASE "A" CASE "H" tmp := __vmItemID( xVal ) IF cInd == NIL @@ -119,10 +125,10 @@ STATIC FUNCTION s_valToExp( xVal, cInd, hRefs, cRefs ) ELSE cVal := "{" FOR EACH tmp IN xVal - cKey := s_valToExp( tmp:__enumKey() ) + cKey := s_valToExp( tmp:__enumKey(), lRaw ) cVal += iif( tmp:__enumIndex() == 1, "", ", " ) + ; cKey + "=>" + ; - s_valToExp( tmp, cInd + cKey, hRefs, @cRefs ) + s_valToExp( tmp, lRaw, cInd + cKey, hRefs, @cRefs ) NEXT cVal += "}" ENDIF @@ -130,7 +136,7 @@ STATIC FUNCTION s_valToExp( xVal, cInd, hRefs, cRefs ) cVal := "{" FOR EACH tmp IN xVal cVal += iif( tmp:__enumIndex() == 1, "", ", " ) + ; - s_valToExp( tmp, cInd + hb_ntos( tmp:__enumIndex() ), hRefs, @cRefs ) + s_valToExp( tmp, lRaw, cInd + hb_ntos( tmp:__enumIndex() ), hRefs, @cRefs ) NEXT cVal += "}" ENDIF @@ -139,7 +145,11 @@ STATIC FUNCTION s_valToExp( xVal, cInd, hRefs, cRefs ) cVal := "__itemSetRef( " + cVal + ", {" + cRefs + "} )" ENDIF IF v == "O" - cVal := "__objSetClass( " + cVal + ", '" + xVal:className() + "' )" + IF lRaw + cVal := "__objSetClass( " + cVal + ", '" + cClass + "' )" + ELSE + cVal := "__objSetIVars( '" + cClass + "', " + cVal + " )" + ENDIF ENDIF EXIT CASE "P" ; RETURN "" diff --git a/harbour/src/vm/arrays.c b/harbour/src/vm/arrays.c index 615effd981..8af5987350 100644 --- a/harbour/src/vm/arrays.c +++ b/harbour/src/vm/arrays.c @@ -891,6 +891,19 @@ HB_BOOL hb_arraySetCL( PHB_ITEM pArray, HB_SIZE nIndex, const char * szText, HB_ return HB_FALSE; } +HB_BOOL hb_arraySetCPtr( PHB_ITEM pArray, HB_SIZE nIndex, char * szText ) +{ + HB_TRACE( HB_TR_DEBUG, ( "hb_arraySetCLPtr(%p, %" HB_PFS "u, %p)", pArray, nIndex, szText ) ); + + if( HB_IS_ARRAY( pArray ) && nIndex > 0 && nIndex <= pArray->item.asArray.value->nLen ) + { + hb_itemPutCPtr( pArray->item.asArray.value->pItems + nIndex - 1, szText ); + return HB_TRUE; + } + else + return HB_FALSE; +} + HB_BOOL hb_arraySetCLPtr( PHB_ITEM pArray, HB_SIZE nIndex, char * szText, HB_SIZE nLen ) { HB_TRACE( HB_TR_DEBUG, ( "hb_arraySetCLPtr(%p, %" HB_PFS "u, %p, %" HB_PFS "u)", pArray, nIndex, szText, nLen ) ); @@ -904,6 +917,19 @@ HB_BOOL hb_arraySetCLPtr( PHB_ITEM pArray, HB_SIZE nIndex, char * szText, HB_SIZ return HB_FALSE; } +HB_BOOL hb_arraySetCConst( PHB_ITEM pArray, HB_SIZE nIndex, const char * szText ) +{ + HB_TRACE( HB_TR_DEBUG, ( "hb_arraySetCConst(%p, %" HB_PFS "u, %p)", pArray, nIndex, szText ) ); + + if( HB_IS_ARRAY( pArray ) && nIndex > 0 && nIndex <= pArray->item.asArray.value->nLen ) + { + hb_itemPutCConst( pArray->item.asArray.value->pItems + nIndex - 1, szText ); + return HB_TRUE; + } + else + return HB_FALSE; +} + HB_BOOL hb_arraySetPtr( PHB_ITEM pArray, HB_SIZE nIndex, void * pValue ) { HB_TRACE( HB_TR_DEBUG, ( "hb_arraySetPtr(%p, %" HB_PFS "u, %p)", pArray, nIndex, pValue ) ); diff --git a/harbour/src/vm/classes.c b/harbour/src/vm/classes.c index 55080a0a3a..6a3e3775ab 100644 --- a/harbour/src/vm/classes.c +++ b/harbour/src/vm/classes.c @@ -764,16 +764,17 @@ static HB_BOOL hb_clsHasParentClass( PCLASS pClass, HB_USHORT uiParentCls ) */ } -static HB_BOOL hb_clsHasParent( PCLASS pClass, PHB_DYNS pParentSym ) +static HB_USHORT hb_clsGetParent( PCLASS pClass, PHB_DYNS pParentSym ) { HB_USHORT uiCount = pClass->uiSuperClasses; while( uiCount ) { - if( s_pClasses[ pClass->pSuperClasses[ --uiCount ].uiClass ]->pClassSym == pParentSym ) - return HB_TRUE; + HB_USHORT uiClass = pClass->pSuperClasses[ --uiCount ].uiClass; + if( s_pClasses[ uiClass ]->pClassSym == pParentSym ) + return uiClass; } - return HB_FALSE; + return 0; /* alternative method but can give wrong results * if user overloads super casting method, [druzus]. @@ -948,6 +949,9 @@ static HB_BOOL hb_clsUpdateHiddenMessages( PMETHOD pSrcMethod, PMETHOD pDstMetho PCLASS pSrcClass = s_pClasses[ pDstMethod->uiSprClass ]; HB_USHORT uiData; + /* check if we already have corresponding access or assign + * message for this class var to reuse its index + */ uiData = hb_clsFindClassDataOffset( pDstClass, pDstMethod ); if( uiData == 0 ) @@ -970,9 +974,9 @@ static HB_BOOL hb_clsUpdateHiddenMessages( PMETHOD pSrcMethod, PMETHOD pDstMetho return HB_FALSE; } -static void hb_clsAddSupperClass( PCLASS pClass, HB_USHORT uiSuperCls, HB_USHORT uiOffset ) +static void hb_clsAddSuperClass( PCLASS pClass, HB_USHORT uiSuperCls, HB_USHORT uiOffset ) { - HB_TRACE( HB_TR_DEBUG, ( "hb_clsAddSupperClass(%p,%hu,%hu)", pClass, uiSuperCls, uiOffset ) ); + HB_TRACE( HB_TR_DEBUG, ( "hb_clsAddSuperClass(%p,%hu,%hu)", pClass, uiSuperCls, uiOffset ) ); pClass->pSuperClasses = ( PHB_CLSCAST ) hb_xrealloc( pClass->pSuperClasses, ( pClass->uiSuperClasses + 1 ) * sizeof( HB_CLSCAST ) ); @@ -980,12 +984,12 @@ static void hb_clsAddSupperClass( PCLASS pClass, HB_USHORT uiSuperCls, HB_USHORT pClass->pSuperClasses[ pClass->uiSuperClasses++ ].uiOffset = uiOffset; } -static void hb_clsDefineSupperClass( PCLASS pClass, HB_USHORT uiSuperCls, HB_BOOL fNew ) +static void hb_clsDefineSuperClass( PCLASS pClass, HB_USHORT uiSuperCls, HB_BOOL fNew ) { PMETHOD pMethod; PCLASS pSprCls; - HB_TRACE( HB_TR_DEBUG, ( "hb_clsDefineSupperClass(%p,%hu,%d)", pClass, uiSuperCls, fNew ) ); + HB_TRACE( HB_TR_DEBUG, ( "hb_clsDefineSuperClass(%p,%hu,%d)", pClass, uiSuperCls, fNew ) ); pSprCls = s_pClasses[ uiSuperCls ]; @@ -993,11 +997,11 @@ static void hb_clsDefineSupperClass( PCLASS pClass, HB_USHORT uiSuperCls, HB_BOO { if( fNew ) { - hb_clsAddSupperClass( pClass, uiSuperCls, pClass->uiDatas ); + hb_clsAddSuperClass( pClass, uiSuperCls, pClass->uiDatas ); pClass->uiDatas += pSprCls->uiDatas - pSprCls->uiDataFirst; } else - hb_clsAddSupperClass( pClass, uiSuperCls, pSprCls->uiDataFirst ); + hb_clsAddSuperClass( pClass, uiSuperCls, pSprCls->uiDataFirst ); } pMethod = hb_clsAllocMsg( pClass, pSprCls->pClassSym ); @@ -1088,7 +1092,7 @@ static void hb_clsCopyClass( PCLASS pClsDst, PCLASS pClsSrc ) memcpy( pClsDst->pSuperClasses, pClsSrc->pSuperClasses, pClsSrc->uiSuperClasses * sizeof( HB_CLSCAST ) ); } - hb_clsDefineSupperClass( pClsDst, pClsSrc->uiClass, HB_FALSE ); + hb_clsDefineSuperClass( pClsDst, pClsSrc->uiClass, HB_FALSE ); pMethod = pClsDst->pMethods; do @@ -1376,7 +1380,7 @@ HB_BOOL hb_clsIsParent( HB_USHORT uiClass, const char * szParentName ) PHB_DYNS pMsg = hb_dynsymFindName( szParentName ); if( pMsg ) - return hb_clsHasParent( pClass, pMsg ); + return hb_clsGetParent( pClass, pMsg ) != 0; } } @@ -1542,25 +1546,35 @@ const char * hb_clsMethodName( HB_USHORT uiClass, HB_USHORT uiMethod ) return NULL; } -HB_SIZE hb_clsGetVarIndex( HB_USHORT uiClass, PHB_DYNS pVarSym ) +static HB_SIZE hb_clsGetVarIndexEx( HB_USHORT uiClass, PHB_DYNS pVarSym, + HB_USHORT uiSuper ) { - if( uiClass && uiClass <= s_uiClasses ) + PMETHOD pMethod = hb_clsFindMsg( s_pClasses[ uiSuper ], pVarSym ); + if( pMethod ) { - PMETHOD pMethod = hb_clsFindMsg( s_pClasses[ uiClass ], pVarSym ); - if( pMethod ) + PHB_SYMB pFuncSym = pMethod->pFuncSym; + + if( pFuncSym == &s___msgSync || pFuncSym == &s___msgSyncClass ) + pFuncSym = pMethod->pRealSym; + + if( pFuncSym == &s___msgSetData || pFuncSym == &s___msgGetData ) { - PHB_SYMB pFuncSym = pMethod->pFuncSym; - - if( pFuncSym == &s___msgSync || pFuncSym == &s___msgSyncClass ) - pFuncSym = pMethod->pRealSym; - - if( pFuncSym == &s___msgSetData || pFuncSym == &s___msgGetData ) - return pMethod->uiData + pMethod->uiOffset; + return ( HB_SIZE ) pMethod->uiData + ( uiClass != uiSuper ? + hb_clsParentInstanceOffset( s_pClasses[ uiClass ], uiSuper ) : + pMethod->uiOffset ); } } return 0; } +HB_SIZE hb_clsGetVarIndex( HB_USHORT uiClass, PHB_DYNS pVarSym ) +{ + if( uiClass && uiClass <= s_uiClasses ) + return hb_clsGetVarIndexEx( uiClass, pVarSym, uiClass ); + else + return 0; +} + HB_USHORT hb_clsFindClass( const char * szClass, const char * szFunc ) { HB_USHORT uiClass; @@ -2317,9 +2331,9 @@ HB_BOOL hb_clsHasDestructor( HB_USHORT uiClass ) } /* - * Call all known supper destructors + * Call all known super destructors */ -static void hb_objSupperDestructorCall( PHB_ITEM pObject, PCLASS pClass ) +static void hb_objSuperDestructorCall( PHB_ITEM pObject, PCLASS pClass ) { #if 0 HB_STACK_TLS_PRELOAD @@ -2337,8 +2351,8 @@ static void hb_objSupperDestructorCall( PHB_ITEM pObject, PCLASS pClass ) { if( pMethod->pFuncSym == &s___msgSuper ) { - PCLASS pSupperClass = s_pClasses[ pMethod->uiData ]; - if( pSupperClass->fHasDestructor && pSupperClass != pClass ) + PCLASS pSuperClass = s_pClasses[ pMethod->uiData ]; + if( pSuperClass->fHasDestructor && pSuperClass != pClass ) pcClasses[ pMethod->uiData ] |= 1; } else if( pMethod->pMessage == s___msgDestructor.pDynSym ) @@ -2382,9 +2396,9 @@ static void hb_objSupperDestructorCall( PHB_ITEM pObject, PCLASS pClass ) if( uiParentCls != uiDtorClass && uiParentCls != pClass->uiClass ) { - PCLASS pSupperClass = s_pClasses[ uiParentCls ]; + PCLASS pSuperClass = s_pClasses[ uiParentCls ]; - if( pSupperClass->fHasDestructor ) + if( pSuperClass->fHasDestructor ) { PMETHOD pDestructor = hb_clsFindMsg( s_pClasses[ uiParentCls ], s___msgDestructor.pDynSym ); @@ -2420,7 +2434,7 @@ void hb_objDestructorCall( PHB_ITEM pObject ) hb_vmPush( pObject ); hb_vmSend( 0 ); if( hb_vmRequestQuery() == 0 ) - hb_objSupperDestructorCall( pObject, pClass ); + hb_objSuperDestructorCall( pObject, pClass ); hb_vmRequestRestore(); } } @@ -2877,11 +2891,11 @@ static HB_TYPE hb_clsGetItemType( PHB_ITEM pItem, HB_TYPE nDefault ) * HB_OO_MSG_ONERROR : > Pointer to function * HB_OO_MSG_DESTRUCTOR : / * HB_OO_MSG_INLINE : Code block - * HB_OO_MSG_ASSIGN : Index to instance area array + * HB_OO_MSG_ASSIGN : Index to instance area array 1 based (without offset) * HB_OO_MSG_ACCESS : / * HB_OO_MSG_CLSASSIGN : Index class data array * HB_OO_MSG_CLSACCESS : / - * HB_OO_MSG_SUPER : Handle of super class + * HB_OO_MSG_SUPER : Instance area offset for class casting * HB_OO_MSG_DELEGATE : Delegated message symbol * * HB_OO_MSG_ACCESS : Optional initializer for (Class)DATA @@ -3175,6 +3189,9 @@ static HB_BOOL hb_clsAddMsg( HB_USHORT uiClass, const char * szMessage, { if( hb_arrayLen( pClass->pClassDatas ) < ( HB_SIZE ) pNewMeth->uiData ) hb_arraySize( pClass->pClassDatas, pNewMeth->uiData ); + /* uiOffset is used to copy ancestor class data initializaers when + * new class is created + */ pNewMeth->uiOffset = hb_clsAddInitValue( pClass, pInit, HB_OO_MSG_CLASSDATA, pNewMeth->uiData, 0, uiClass ); pNewMeth->pFuncSym = &s___msgGetClsData; @@ -3262,7 +3279,7 @@ static HB_BOOL hb_clsAddMsg( HB_USHORT uiClass, const char * szMessage, } /* - * __clsAddMsg( , , , , [xInit], ) + * __clsAddMsg( , , , , [xInit], , [xType] ) * * Add a message to the class. * @@ -3308,6 +3325,9 @@ static HB_BOOL hb_clsAddMsg( HB_USHORT uiClass, const char * szMessage, * HB_OO_CLSTP_NONVIRTUAL 512 : Class method constructor * HB_OO_CLSTP_OVERLOADED 1024 : Class method constructor * HB_OO_CLSTP_SYNC 2048 : message synchronized by object or class mutex + * + * HB_OO_MSG_PROPERTY : > optional item type restriction in assignment + * HB_OO_MSG_CLASSPROPERTY : / */ HB_FUNC( __CLSADDMSG ) @@ -3335,6 +3355,7 @@ HB_FUNC( __CLSADDMSG ) else if( nType == HB_OO_MSG_PROPERTY || nType == HB_OO_MSG_CLASSPROPERTY ) { + PHB_ITEM pType = hb_param( 7, HB_IT_ANY ); char szAssign[ HB_SYMBOL_NAME_LEN + 1 ]; int iLen = ( int ) hb_parclen( 2 ); if( iLen >= HB_SYMBOL_NAME_LEN ) @@ -3349,14 +3370,14 @@ HB_FUNC( __CLSADDMSG ) { hb_clsAddMsg( uiClass, szAssign, HB_OO_MSG_ASSIGN, ( HB_USHORT ) ( uiScope & ~HB_OO_CLSTP_PERSIST ), - pFunction, pInit ); + pFunction, pType ); nType = HB_OO_MSG_ACCESS; } else { hb_clsAddMsg( uiClass, szAssign, HB_OO_MSG_CLSASSIGN, ( HB_USHORT ) ( uiScope & ~HB_OO_CLSTP_PERSIST ), - pFunction, pInit ); + pFunction, pType ); nType = HB_OO_MSG_CLSACCESS; } } @@ -3452,8 +3473,8 @@ static HB_USHORT hb_clsNew( const char * szClassName, HB_USHORT uiDatas, /* Copy super class handles */ for( uiCount = 0; uiCount < pSprCls->uiSuperClasses; ++uiCount ) - hb_clsDefineSupperClass( pNewCls, pSprCls->pSuperClasses[ uiCount ].uiClass, HB_TRUE ); - hb_clsDefineSupperClass( pNewCls, uiSuperCls, HB_TRUE ); + hb_clsDefineSuperClass( pNewCls, pSprCls->pSuperClasses[ uiCount ].uiClass, HB_TRUE ); + hb_clsDefineSuperClass( pNewCls, uiSuperCls, HB_TRUE ); /* Copy instance area init data */ if( pSprCls->uiInitDatas ) @@ -3571,7 +3592,7 @@ static HB_USHORT hb_clsNew( const char * szClassName, HB_USHORT uiDatas, /* add self class casting */ pNewCls->uiDataFirst = pNewCls->uiDatas; - hb_clsDefineSupperClass( pNewCls, pNewCls->uiClass, HB_FALSE ); + hb_clsDefineSuperClass( pNewCls, pNewCls->uiClass, HB_FALSE ); pNewCls->uiDatas += uiDatas; if( pNewCls->uiMutexOffset ) pNewCls->uiMutexOffset = pNewCls->uiDatas + 1; @@ -5085,110 +5106,157 @@ HB_FUNC( __GETMSGPRF ) /* profiler: returns a method called and consumed times * hb_storvnl( 0, -1, 2 ); } +typedef struct +{ + PMETHOD pMethod; + HB_USHORT uiClass; + HB_USHORT uiStatus; +} +HB_IVARINFO, * PHB_IVARINFO; + +static PHB_ITEM hb_objGetIVars( PHB_ITEM pObject, + HB_USHORT uiScope, HB_BOOL fChanged ) +{ + PHB_IVARINFO pIndex, pInfo; + PCLASS pClass; + PMETHOD pMethod; + PHB_ITEM pReturn, pItem; + HB_SIZE nLimit, nLen, nCount, nSize, nIndex, nOffset; + HB_USHORT uiClass, uiSuperClasses; + + if( !pObject || !HB_IS_OBJECT( pObject ) ) + return NULL; + + uiClass = pObject->item.asArray.value->uiClass; + pClass = s_pClasses[ uiClass ]; + nLen = nCount = hb_arrayLen( pObject ); + nSize = 0; + pIndex = ( PHB_IVARINFO ) hb_xgrab( nLen * sizeof( HB_IVARINFO ) ); + memset( pIndex, 0, nLen * sizeof( HB_IVARINFO ) ); + + if( fChanged && pClass->uiInitDatas ) + { + PINITDATA pInitData = pClass->pInitData; + + nLimit = pClass->uiInitDatas; + do + { + if( pInitData->uiType == HB_OO_MSG_DATA ) + { + nIndex = pInitData->uiData + pInitData->uiOffset; + pItem = hb_arrayGetItemPtr( pObject, nIndex ); + if( pItem ) + { + if( hb_itemEqual( pItem, pInitData->pInitValue ) ) + { + pIndex[ nIndex - 1 ].uiStatus = 3; + --nCount; + } + else + pIndex[ nIndex - 1 ].uiStatus = 1; + } + } + ++pInitData; + } + while( --nLimit ); + } + + uiSuperClasses = pClass->uiSuperClasses; + nOffset = hb_clsParentInstanceOffset( pClass, uiClass ); + nLimit = hb_clsMthNum( pClass ); + pMethod = pClass->pMethods; + while( nCount && nLimit ) + { + if( pMethod->pMessage && + ( uiScope == 0 || ( pMethod->uiScope & uiScope ) != 0 ) && + ( uiClass == pClass->uiClass || pMethod->uiSprClass == uiClass ) ) + { + PHB_SYMB pFuncSym = pMethod->pFuncSym; + + if( pFuncSym == &s___msgSync || pFuncSym == &s___msgSyncClass ) + pFuncSym = pMethod->pRealSym; + + if( pFuncSym == &s___msgGetData || pFuncSym == &s___msgSetData ) + { + HB_USHORT uiStatus = pFuncSym == &s___msgGetData ? 3 : 2; + + nIndex = ( uiClass == pClass->uiClass ? + ( HB_SIZE ) pMethod->uiOffset : nOffset ) + pMethod->uiData; + if( nIndex == 0 || nIndex > nLen ) + hb_errInternal( HB_EI_CLSINVMETHOD, NULL, "__objGetIVars()", NULL ); + + pInfo = &pIndex[ nIndex - 1 ]; + if( pInfo->uiStatus < uiStatus ) + { + pItem = hb_arrayGetItemPtr( pObject, nIndex ); + if( !pItem || ( pInfo->uiStatus == 0 && HB_IS_NIL( pItem ) ) ) + uiStatus = 3; + else + { + if( !pInfo->pMethod ) + ++nSize; + pInfo->pMethod = pMethod; + pInfo->uiClass = uiClass; + } + pInfo->uiStatus = uiStatus; + if( uiStatus == 3 ) + --nCount; + } + } + } + ++pMethod; + if( --nLimit == 0 ) + { + if( uiSuperClasses ) + { + uiClass = pClass->pSuperClasses[ --uiSuperClasses ].uiClass; + nOffset = hb_clsParentInstanceOffset( pClass, uiClass ); + nLimit = hb_clsMthNum( s_pClasses[ uiClass ] ); + pMethod = s_pClasses[ uiClass ]->pMethods; + } + } + } + + nCount = 0; + pReturn = hb_itemArrayNew( nSize ); + for( nIndex = 1; nIndex <= nLen && nCount < nSize; ++nIndex ) + { + pInfo = &pIndex[ nIndex - 1 ]; + if( pInfo->pMethod ) + { + const char * pszVar = pInfo->pMethod->pMessage->pSymbol->szName; + PHB_ITEM pValue = hb_arrayGetItemPtr( pReturn, ++nCount ); + + pItem = hb_arrayGetItemPtr( pObject, nIndex ); + hb_arrayNew( pValue, 2 ); + if( pInfo->uiClass != pClass->uiClass ) + { + char * pszCast = hb_xstrcpy( NULL, s_pClasses[ pInfo->uiClass ]->szName, + ":", pszVar, NULL ); + hb_arraySetCPtr( pValue, 1, pszCast ); + } + else + hb_arraySetCConst( pValue, 1, pszVar ); + hb_arraySet( pValue, 2, pItem ); + } + } + + hb_xfree( pIndex ); + + return pReturn; +} + + /* __objGetIVars( , [], [] ) * -> { { , }, ... } */ HB_FUNC( __OBJGETIVARS ) { PHB_ITEM pObject = hb_param( 1, HB_IT_OBJECT ); + HB_USHORT uiScope = ( HB_USHORT ) hb_parni( 2 ); + HB_BOOL fChanged = hb_parldef( 3, HB_TRUE ); - if( pObject && pObject->item.asArray.value->uiClass != 0 ) - { - HB_STACK_TLS_PRELOAD - PHB_ITEM pReturn = hb_stackReturnItem(), pItem; - PCLASS pClass = s_pClasses[ pObject->item.asArray.value->uiClass ]; - PMETHOD pMethod; - PHB_SYMB pDataSym; - HB_USHORT uiScope = ( HB_USHORT ) hb_parni( 2 ); - HB_BOOL fChanged = hb_parldef( 3, HB_TRUE ); - HB_SIZE nLen, nLimit, nIndex; - - nLen = hb_arrayLen( pObject ); - hb_arrayNew( pReturn, nLen ); - if( nLen > 0 ) - { - char * pnIndex; - - pnIndex = ( char * ) hb_xgrab( nLen ); - memset( pnIndex, fChanged ? 0 : 1, nLen ); - - if( fChanged && pClass->uiInitDatas ) - { - PINITDATA pInitData = pClass->pInitData; - - nLimit = pClass->uiInitDatas; - do - { - if( pInitData->uiType == HB_OO_MSG_DATA ) - { - nIndex = pInitData->uiData + pInitData->uiOffset; - pItem = hb_arrayGetItemPtr( pObject, nIndex ); - if( pItem ) - { - pnIndex[ nIndex - 1 ] = - hb_itemEqual( pItem, pInitData->pInitValue ) ? 2 : 1; - } - } - ++pInitData; - } - while( --nLimit ); - } - - nLen = 0; - nLimit = hb_clsMthNum( pClass ); - pMethod = pClass->pMethods; - pDataSym = &s___msgGetData; - do - { - if( pMethod->pMessage && - ( uiScope == 0 || ( pMethod->uiScope & uiScope ) != 0 ) ) - { - PHB_SYMB pFuncSym = pMethod->pFuncSym; - - if( pFuncSym == &s___msgSync || pFuncSym == &s___msgSyncClass ) - pFuncSym = pMethod->pRealSym; - - if( pFuncSym == pDataSym ) - { - /* TODO: add support for nonvirtual members */ - nIndex = pMethod->uiData + pMethod->uiOffset; - pItem = hb_arrayGetItemPtr( pObject, nIndex ); - if( pItem && pnIndex[ nIndex - 1 ] != 2 && - ( pnIndex[ nIndex - 1 ] == 1 || !HB_IS_NIL( pItem ) ) ) - { - PHB_ITEM pValue = hb_arrayGetItemPtr( pReturn, nLen + 1 ); - if( pValue ) - { - hb_arrayNew( pValue, 2 ); - hb_arraySetC( pValue, 1, pMethod->pMessage->pSymbol->szName + - ( pFuncSym == &s___msgSetData ? 1 : 0 ) ); - hb_arraySet( pValue, 2, pItem ); - pnIndex[ nIndex - 1 ] = 2; - ++nLen; - } - else - break; - } - } - } - ++pMethod; - if( --nLimit == 0 ) - { - if( pDataSym == &s___msgGetData ) - { - nLimit = hb_clsMthNum( pClass ); - pMethod = pClass->pMethods; - pDataSym = &s___msgSetData; - } - } - } - while( nLimit ); - - hb_xfree( pnIndex ); - - hb_arraySize( pReturn, nLen ); - } - } + hb_itemReturnRelease( hb_objGetIVars( pObject, uiScope, fChanged ) ); } /* __objSetIVars( | | | , @@ -5215,16 +5283,40 @@ HB_FUNC( __OBJSETIVARS ) if( pObject && pArray && pArray->item.asArray.value->uiClass == 0 ) { HB_USHORT uiClass = pObject->item.asArray.value->uiClass; - HB_SIZE nPos, nIndex; + HB_SIZE nPos, nIndex, nLen; nPos = 0; while( ( pValue = hb_arrayGetItemPtr( pArray, ++nPos ) ) != NULL ) { - PHB_DYNS pVarSym = hb_dynsymFindName( hb_arrayGetCPtr( pValue, 1 ) ); + const char * pszMethod = hb_arrayGetCPtr( pValue, 1 ); + PHB_DYNS pVarSym = hb_dynsymFind( pszMethod ); PHB_ITEM pNewVal = hb_arrayGetItemPtr( pValue, 2 ); + HB_USHORT uiSuper = uiClass; - if( pNewVal && pVarSym && - ( nIndex = hb_clsGetVarIndex( uiClass, pVarSym ) ) != 0 ) + if( !pVarSym ) + { + const char * pszClass = strchr( pszMethod, ':' ); + if( pszClass ) + { + nLen = pszClass - pszMethod; + if( nLen ) + { + PHB_DYNS pParentSym; + char szClassName[ HB_SYMBOL_NAME_LEN + 1 ]; + + memcpy( szClassName, pszMethod, nLen ); + szClassName[ nLen ] = '\0'; + pParentSym = hb_dynsymFindName( szClassName ); + uiSuper = pParentSym == NULL ? 0 : + hb_clsGetParent( s_pClasses[ uiClass ], pParentSym ); + } + pVarSym = hb_dynsymFindName( pszClass + 1 ); + } + else + pVarSym = hb_dynsymFindName( pszMethod ); + } + if( uiSuper && pNewVal && pVarSym && + ( nIndex = hb_clsGetVarIndexEx( uiClass, pVarSym, uiSuper ) ) != 0 ) { hb_arraySet( pObject, nIndex, pNewVal ); } @@ -5309,7 +5401,7 @@ HB_FUNC( __CLSGETPROPERTIES ) hb_itemReturnRelease( pReturn ); } -/* __clsGetAncestors( ) -> { , , ... } +/* __clsGetAncestors( ) -> { , , ... } */ HB_FUNC( __CLSGETANCESTORS ) {