Valor por defecto en una DATA de una clase

Re: Valor por defecto en una DATA de una clase

Postby xmanuel » Sat Sep 12, 2015 5:06 pm

O tal vez lo que quieras es modificar una cadena a partir de un lugar concreto...

En Eagle1 lo hice así:
Code: Select all  Expand view  RUN

//----------------------------------------------------------------------------//
// Funciones para usar desde xBase
//----------------------------------------------------------------------------//
// ChgAtEnd( a, b, n )
// Sustituye en 'a' los ultimos 'n' digitos por la cadena 'b'

HB_FUNC( CHGATEND )
{
    const char * szStr1 = hb_parc( 1 );
    const char * szStr2 = hb_parc( 2 );
    unsigned int uiLen = hb_parclen( 1 ) - hb_parni( 3 );
    unsigned int uiTotalLen = uiLen + hb_parclen( 2 );
    char * szRet = (char *) hb_xgrab( uiTotalLen + 1 );

    hb_xmemcpy( szRet, szStr1, uiLen );
    szRet[ uiLen ] = '\0';
    hb_xstrcat( szRet, szStr2, NULL );

    hb_retclen_buffer( szRet, uiTotalLen );
}

//----------------------------------------------------------------------------//


 
______________________________________________________________________________
Sevilla - Andalucía
xmanuel
 
Posts: 763
Joined: Sun Jun 15, 2008 7:47 pm
Location: Sevilla

Re: Valor por defecto en una DATA de una clase

Postby Carlos Mora » Mon Sep 14, 2015 7:27 pm

Hola Manu,
gracias por las ideas. Ninguna de las dos me sirve, digamos que mi problema pasa por evitar que se realoque la string en cada operación, por lo que en el primer ejemplo, haciendo un HB_itePutC estoy asignando unnuevo valor, y lo que quiero es modificar el existente. El segundo ejemplo alloca memoria para crear la respuesta, con lo que sigue el problema.
Creo que ya tengo la respuesta: En Clipper se usaba un hb_xlock() para acceder al contenido de una string, ahora la funcion es otra,

PHB_ITEM pBuffer = hb_param( x, HB_IT_STRING ); // x es el numero de parametro
hb_itemGetWriteCL( pBuffer, &buffer, &nSize ) // Buffer es el char*, nSize tiene el tamaño actual.
le pasas como primer parámetro el item de tipo Char, y te devuelve el puntero a la cadena y la longitud actual de la cadena. Lo vi escarbando en el codigo fuente de Harbour, aun no lo he probado pero mañana haré algunas pruebas.

Lo encontré dentro de src/rtl/vfile.c... mogollon de funciones que no se que hacen :(

Un saludo y muchas gracias
Saludos
Carlos Mora
http://harbouradvisor.blogspot.com/
StackOverflow http://stackoverflow.com/users/549761/carlos-mora
“If you think education is expensive, try ignorance"
Carlos Mora
 
Posts: 989
Joined: Thu Nov 24, 2005 3:01 pm
Location: Madrid, España

Re: Valor por defecto en una DATA de una clase

Postby xmanuel » Tue Sep 15, 2015 9:03 am

Creo que esa también hace una nueva reserva de memoria, he mirado el código fuente de la función y fíjate:

Code: Select all  Expand view  RUN

/* Internal API, not standard Clipper */
/* UnShare string buffer of given string item */

PHB_ITEM hb_itemUnShareString( PHB_ITEM pItem )
{
   HB_TRACE( HB_TR_DEBUG, ( "hb_itemUnShareString(%p)", pItem ) );

   if( pItem->item.asString.allocated == 0 ||
       hb_xRefCount( pItem->item.asString.value ) > 1 )
   {
      HB_SIZE nLen = pItem->item.asString.length + 1;
      char * szText = ( char * ) hb_xmemcpy( hb_xgrab( nLen ),
                                             pItem->item.asString.value, nLen );
      if( pItem->item.asString.allocated )
      {
         /* GCLOCK enter */
         hb_xRefFree( pItem->item.asString.value );
         /* GCLOCK leave */
      }
      pItem->item.asString.value = szText;
      pItem->item.asString.allocated = nLen;
   }
   pItem->type &= ~HB_IT_DEFAULT;

   return pItem;
}

// ...

HB_BOOL hb_itemGetWriteCL( PHB_ITEM pItem, char ** pszValue, HB_SIZE * pnLen )
{
   HB_TRACE( HB_TR_DEBUG, ( "hb_itemGetWriteCL(%p,%p,%p)", pItem, pszValue, pnLen ) );

   if( pItem )
   {
      if( HB_IS_BYREF( pItem ) )
         pItem = hb_itemUnRef( pItem );

      if( HB_IS_STRING( pItem ) )
      {
         hb_itemUnShareString( pItem );
         *pnLen = pItem->item.asString.length;
         *pszValue = pItem->item.asString.value;
         return HB_TRUE;
      }
   }
   return HB_FALSE;
}

 


como puedes ver hace una llamada a hb_itemUnShareString en la que se hace un hb_xgrab para reservar memoria y un hb_xRefFree para liberar la anterior.

Si lo que quieres es manipular tú mismo la cadena sólo tienes que obtener el puntero a la misma con hb_itemGetCPtr( PHB_ITEM pItem ).
Tendrás que hacer un cast ya que esa función devuelve "const char *" no se aconseja "toquetear" directamente :-( Ah!! y el tamaño sí importa ;-)
______________________________________________________________________________
Sevilla - Andalucía
xmanuel
 
Posts: 763
Joined: Sun Jun 15, 2008 7:47 pm
Location: Sevilla

Re: Valor por defecto en una DATA de una clase

Postby Carlos Mora » Tue Sep 15, 2015 10:15 am

Menudo nivel el del compañero, je!

Es cierto, hay unas llamadas como tu dices, pero solo cuando es imprescindible: cuando la string es apuntada por más de una variable.

Creo que eso sucede cuando haces algo como

a:= 'XXX'
b:= a
En esta segunda instruccion no crea otro buffer y copia la cadena 'XXX', sino que hace que b apunte tambien al trozo de memoria que contiene 'XXX' de a. Si paso 'a' por referencia e indico que voy a modificarla, en ese momento entra en juego esta funcion que dices: crea el duplicado, separando o independizando a de b para que los cambios que se hagan en a no afecten a b, y luego continúa.

Es muy bueno que lo hayas apuntado, porque así sé que no debo trastear mucho con la variable buffer, crear y asignar a una sola variable y no andar creando copias.

Muchísimas gracias.
Saludos
Carlos Mora
http://harbouradvisor.blogspot.com/
StackOverflow http://stackoverflow.com/users/549761/carlos-mora
“If you think education is expensive, try ignorance"
Carlos Mora
 
Posts: 989
Joined: Thu Nov 24, 2005 3:01 pm
Location: Madrid, España

Re: Valor por defecto en una DATA de una clase

Postby xmanuel » Tue Sep 15, 2015 2:35 pm

Carlos, esa función no vale para modificar el valor de la variable, fijate que lo que hace es meter en el buffer el valor actual del item pasado. Me imagino que se usa para no repetir llamadas al item api. Además tiene su lógica, si metes en el string una modificación con un ancho mayor te va a petar seguro.

Si quieres modificar la variable xbase en C sin crear una nueva copia tienes que usar hb_itemGetCPtr( PHB_ITEM pItem )

Code: Select all  Expand view  RUN

char * szValue =  (char *) hb_itemGetCPtr( hb_param( 1, HB_IT_STRING  );
 


Lo que hagas szValue quedara reflejada en la variable del PRG ya que apuntan a lo mismo. Pero el "tamño importa", la cadena resultante no puede tener un tamaño superior al len de la original. Y posiblemente si es menor tendras que poner un '\0' para que no muestre morralla :(
______________________________________________________________________________
Sevilla - Andalucía
xmanuel
 
Posts: 763
Joined: Sun Jun 15, 2008 7:47 pm
Location: Sevilla

Re: Valor por defecto en una DATA de una clase

Postby Carlos Mora » Wed Sep 16, 2015 10:57 am

Master,
Parafraseando a Matias Prats en el comercial de los seguros: "Permíteme que insista", :)

En el código de la función hb_itemUnShareString, el duplicado se hace solo cuando es realmente necesario, porque hay dos variables apuntando al mimo trozo de memoria. El trozo de código que hace el alloc está dentro de un IF que dice:

Code: Select all  Expand view  RUN
  if( pItem->item.asString.allocated == 0 ||  hb_xRefCount( pItem->item.asString.value ) > 1 )


el hb_xRefCount es el contador de referencias a un determinado bloque, y es lo que te había puesto en el ejemplo de a:' 'XXX'; b:= a : este codigo no genera dos bloques de memoria rellenos con 'XXX', sino uno solo, y a y b apuntan al mismo, y el bloque tiene un refcount de 2.

Las advertencias de modificar los bloques con punteros obtenidos con hb_itemGetCPtr se refieren justo a eso. Supongamos que tenemos una funcion CambiaPorY() que modifica el segundo byte a 'Y' de la cadena pasada por referencia, usando hb_itemGetCPtr . Si hago
a:= 'XXX'
b:= a
CambiaPorY( @a ) // a es ahora 'XYX'
? b // Imprimirá 'XYX', es decir se verá afectada por las modificaciones hechas en otra variable.

Si uso hb_itemUnShareString (supongo que de ahí viene lo de UNSHARE)

a:= 'XXX'
b:= a
CambiaPorYconUnshare( @a ) // a es ahora 'XYX'
? b // Imprimirá 'XXX', porque antes de obtener el puntero separó los buffers, que es el alloc que hacías referencia.

Bueno, te digo para que es todo este rollo: esto es para hacer una clase buffer, para evitar los cBuffer+= texto, por ejemplo cuando generamos ficheros xml o similares.
La sucesiva acumulación de cadenas cortas produce un infierno de reallocs, y si no se hace un garbage collect cada tanto te quedas sin memoria. Bueno, no sin memoria, pero si toda la memoria llena de pequeños bloques y ninguno contínuo suficiente para hacer grandes operaciones. El problema se resuelve frecuentemente escribiendo directamente a disco (si el proceso es generar un fichero), pero escribir muchos trocitos impone una sobrecarga en el sistema de E/S, por lo que habia pensado en hacer algo justamente usando esto del buffer.

Hay un post en el foro en inglés donde hablamos respecto del tema, y uno de los compañeros escribió algo que sirve de idea inicial, y que vamos a tratar de mejorar.
Saludos
Carlos Mora
http://harbouradvisor.blogspot.com/
StackOverflow http://stackoverflow.com/users/549761/carlos-mora
“If you think education is expensive, try ignorance"
Carlos Mora
 
Posts: 989
Joined: Thu Nov 24, 2005 3:01 pm
Location: Madrid, España

Re: Valor por defecto en una DATA de una clase

Postby xmanuel » Wed Sep 16, 2015 1:09 pm

Jejeje ya... pero esa función no vale para modificar el buffer sino para recuperarlo.
El contador de referencias básicamente se usa en el recolector de basura para no quietar de la memoria ningún valor que aún tiene una referencia a ella como por ejemplo lo que tú indicas...

Ya me dirá como te han salido las pruebas :-)
______________________________________________________________________________
Sevilla - Andalucía
xmanuel
 
Posts: 763
Joined: Sun Jun 15, 2008 7:47 pm
Location: Sevilla

Previous

Return to FiveWin para Harbour/xHarbour

Who is online

Users browsing this forum: No registered users and 58 guests