Page 1 of 1

Manu Exposito's pearls

Posted: Sat Aug 10, 2019 6:06 am
by Antonio Linares

Code: Select all

HB_FUNC( PARAM2HASH )
{
    PHB_ITEM pHash = hb_hashNew( NULL );
    PHB_DYNS pFuncSym = hb_dynsymFindName( "HB_ATOKENS" );

    if( pFuncSym && hb_dynsymIsFunction( pFuncSym ) )
    {
        HB_SIZE nLen;
        PHB_ITEM aTokens = hb_stackReturnItem();

        hb_itemSetNil( aTokens );

        hb_vmPushDynSym( pFuncSym );
        hb_vmPushNil();
        hb_vmPush( hb_param( 1, HB_IT_STRING ) );
        hb_vmPushString( "&", 1 );
        hb_vmProc( 2 );

        if( ( nLen = hb_arrayLen( aTokens ) ) > 0 )
        {
            HB_SIZE i, nPos;
            const char *szText;
            PHB_ITEM pKey = hb_itemNew( NULL );
            PHB_ITEM pValue = hb_itemNew( NULL );

            hb_hashPreallocate( pHash, nLen );

            for( i = 0; i < nLen; i++ )
            {
                szText = hb_arrayGetCPtr( aTokens, i + 1 );
                nPos = hb_strAt( "=", 1, szText, strlen( szText ) );

                hb_hashAdd( pHash, hb_itemPutCL( pKey,  szText, nPos - 1 ), hb_itemPutC( pValue, szText + nPos ) );
            }

            hb_itemRelease( pKey );
            hb_itemRelease( pValue );
        }
    }

    hb_itemReturnRelease( pHash );
}

Re: Manu Exposito's pearls

Posted: Wed Aug 14, 2019 7:05 am
by AntoninoP
Why don't write it in harbour?
Why don't write it in C?
Why don't use strtok instead of use HB_ATokens?
It is a strange mix, that I don't like, it looks like he takes the harbour code and translate it in C++ automatically...

In harbour is:

Code: Select all

proc main()
   LOCAL test := Param2Hash("param1=23&param2=Pippo")
   LOCAL i
   for i:=1 to len(test)
      ? i, hb_HKeyAt(test,i), "=", hb_HValueAt(test,i)
   next

func Param2Hash(cParam)
   LOCAL aTokens := HB_ATokens(cParam,"&")
   LOCAL i, nLen := len(aTokens)
   LOCAL szText, nPos, pHash := {=>}
   for i:=1 to nLen
      szText := aTokens[i]
      nPos = at("=",szText)
      pHash[left(szText,nPos-1)] := substr(szText,nPos+1)
   next
return pHash

Re: Manu Exposito's pearls

Posted: Wed Aug 14, 2019 8:18 pm
by xmanuel
En primer lugar te doy las gracias por hacer tu crítica...
Aprendo más de ellas que de los halagos.
Paso a contestarte cada pregunta...
Why don't write it in harbour?
Me gusta explorar todos recursos que tiene Harbour y el sistema extendido es lo mejor que tiene. Podría haber optado por hacerlo en Harbour pero creo que hay ciertos procesos que pueden mejorar el rendimiento y este podría ser uno de ellos. Es cuestión de hacer algún test.
Why don't write it in C?
Bueno ambas preguntas son autoexcluyentes, obviamente está escrita en lenguaje C, pero usando los recursos que Harbour pone a nuestro alcance, como por ejemplo correr una función (HB_ATOKENS) escrita para usarla desde PRG ejecutarla usando la pila de Harbour, si te refieres a eso,

Why don't use strtok instead of use HB_ATokens?
Para mi hubiera sido fácil usar strtok pero me encanta estudiar como está hecho Harbour y leo su código fuente con mucha atención, seguramente no habrás reparado en las diferentes entradas que hay en el changelog.txt ad virtiendo que está función de C no se debe usar ya que es incompatible con el sistema MT. Mira esto:
-----------------------
2006-12-15 16:55 UTC+0100 Przemyslaw Czerpak (druzus/at/priv.onet.pl)
* general PCODE cleanup and address most of TODO/FIXME notes in
source code:
! removed all strtok() functions
----------------------
2011-09-20 13:56 UTC+0200 Viktor Szakats (vszakats.net/harbour)
* contrib/hbqt/qtcore/hbqt_pointer.cpp
! fixed to avoid non-MT compatible strtok() C RTL call.
NOTE: Please continue to avoid strtok() usage in any further Harbour patches,
it is avoided for good reason.
----------------------
2011-08-27 13:49 UTC-0800 Pritpal Bedi (bedipritpal@hotmail.com)
* contrib/hbqt/hbmk2_qt.hbs
* contrib/hbqt/qtcore/hbqt.h
+ Implemented: C level class creation is now thread-safe.
With this only pending issue with hbQT remains to replace
usage of strtok() function with Harbour's implementation.
------------------------
Por eso no uso esa funcion de C :(

It is a strange mix, that I don't like, it looks like he takes the harbour code and translate it in C++ automatically...

Admito que no te guste... en mi tierra hay un dicho que dice que para gusto colores...
Pero el tema es que no te entiendo que quieres decir. La mezcla para nada es extraña, el código de Harbour está llena de esto. Yo no traduzco lo que hace Harbour en C, más bien me parece que tu has traducido lo que yo he hecho en C en PRG. Eso demuestra lo grande que es Harbour. Practicamente cualquier cosa que se pueda hacer en C se puede hacer en Harbour y en algunas incluso supera la velocidad de procesado, pero no es este el caso.

"Yo hago lo imposible, porque lo posible lo hace cualquiera", lo dijo alguien al que yo admiro, Pablo Picasso, por cierto paisano de A. Linares.
Y como soy un romántico informático también pongo en mi puño esta otra frase de Ernesto Guevara:
"Seamos realistas y hagamos lo imposible"

Termino reiterando mi agradecimiento a tu crítica.

Pongo aquí una nueva versión más optimizada de la función que me gusta más:

Code: Select all

/***
 * Convierte un cadena como esta "esto=123&es=una&prueba=de&token=999" a u
 * Hash asi { esto => 123, es => una, prueba => de, token => 999 }
 */
HB_FUNC( PARAM2HASH )
{
    PHB_ITEM pHash = hb_hashNew( NULL );
    static PHB_DYNS s_pFuncATokens;

    if( !s_pFuncATokens )
    {
        s_pFuncATokens = hb_dynsymFind( "HB_ATOKENS" );
    }

    if( s_pFuncATokens )
    {
        HB_SIZE nLen;
        PHB_ITEM aTokens = hb_stackReturnItem();

        hb_itemSetNil( aTokens );

        hb_vmPushDynSym( s_pFuncATokens );
        hb_vmPushNil();
        hb_vmPush( hb_param( 1, HB_IT_STRING ) );
        hb_vmPushString( "&", 1 );
        hb_vmProc( 2 );

        if( ( nLen = hb_arrayLen( aTokens ) ) > 0 )
        {
            const char *szText;
            HB_SIZE i = 0, nPos, nStrLen;
            PHB_ITEM pKey = hb_itemNew( NULL );
            PHB_ITEM pValue = hb_itemNew( NULL );

            hb_hashPreallocate( pHash, nLen );

            while( i < nLen )
            {
                i++;
                szText = hb_arrayGetCPtr( aTokens, i );
                nStrLen = hb_arrayGetCLen( aTokens, i );
                nPos = hb_strAt( "=", 1, szText, nStrLen );

                hb_hashAdd( pHash, hb_itemPutCL( pKey, szText, nPos - 1 ),
                                   hb_itemPutCL( pValue, szText + nPos, nStrLen - nPos ) );
            }

            hb_itemRelease( pKey );
            hb_itemRelease( pValue );
        }
    }

    hb_itemReturnRelease( pHash );
}

 
Antonio traduce si puedes :-)

Re: Manu Exposito's pearls

Posted: Fri Aug 16, 2019 4:24 pm
by Carlos Mora
Hey Manu,

antes de que te enfríes, una pregunta para que te piques :D ... He visto que en la versión nueva resuelves el símbolo hb_dynsymFind( "HB_ATOKENS" ) una vez. ¿No hay forma de usarlo invocándolo de forma estática, como hace el propio Harbour cuando genera pcode? No solo sería un enlace estático con la ventaja de velocidad que eso supone, sino también la referencia al símbolo generaría un "require" y obligaría al enlazador a incluir la función.

Abrazo!

Re: Manu Exposito's pearls

Posted: Mon Aug 19, 2019 10:30 am
by xmanuel
SI SE PUEDE!!!
:D
Harbour te da mecanismos para hacerlo...
Miráte hbinit.h...

De cualquier modo con esta versión última solo busca en la tabla de símbolos una vez... :P pero tiene que estar definida previamente por haberla usado o con un request ya que de lo contrario el compilador por optimización ni siquiera la mete en la tabla...

Re: Manu Exposito's pearls

Posted: Mon Aug 19, 2019 2:56 pm
by Antonio Linares
harbour -gc3 -n test.prg

test.prg

Code: Select all

function Main()

   local aLines := hb_aTokens()

return nil
test.c

Code: Select all

/*
 * Harbour 3.2.0dev (r1904111533)
 * LLVM/Clang C 10.0.1 (clang-1001.0.46.4) (64-bit)
 * Generated C source from "test.prg"
 */

#include "hbvmpub.h"
#include "hbpcode.h"
#include "hbinit.h"
#include "hbxvm.h"


HB_FUNC( MAIN );
HB_FUNC_EXTERN( HB_ATOKENS );


HB_INIT_SYMBOLS_BEGIN( hb_vm_SymbolInit_TEST )
{ "MAIN", {HB_FS_PUBLIC | HB_FS_FIRST | HB_FS_LOCAL}, {HB_FUNCNAME( MAIN )}, NULL },
{ "HB_ATOKENS", {HB_FS_PUBLIC}, {HB_FUNCNAME( HB_ATOKENS )}, NULL }
HB_INIT_SYMBOLS_EX_END( hb_vm_SymbolInit_TEST, "test.prg", 0x0, 0x0003 )

#if defined( HB_PRAGMA_STARTUP )
   #pragma startup hb_vm_SymbolInit_TEST
#elif defined( HB_DATASEG_STARTUP )
   #define HB_DATASEG_BODY    HB_DATASEG_FUNC( hb_vm_SymbolInit_TEST )
   #include "hbiniseg.h"
#endif

HB_FUNC( MAIN )
{
   do {
    hb_xvmFrame( 1, 0 );
    hb_xvmSetLine( 3 );
    hb_xvmPushFuncSymbol( symbols + 1 );
    if( hb_xvmFunction( 0 ) ) break;
    hb_xvmPopLocal( 1 );
    hb_xvmSetLine( 5 );
    hb_xvmRetNil();
    /* *** END PROC *** */
   } while( 0 );
}

 

Re: Manu Exposito's pearls

Posted: Tue Aug 20, 2019 12:52 pm
by xmanuel
Esto es parte de HDO:

Code: Select all

HB_INIT_SYMBOLS_BEGIN( LIST__InitSymbols )
{ "THASHLIST", { HB_FS_PUBLIC | HB_FS_LOCAL }, { HB_FUNCNAME( THASHLIST ) }, NULL },
{ "TMEMLIST",  { HB_FS_PUBLIC | HB_FS_LOCAL }, { HB_FUNCNAME( TMEMLIST ) },  NULL }
HB_INIT_SYMBOLS_END( LIST__InitSymbols )

#if defined( HB_PRAGMA_STARTUP )
    #pragma startup LIST__InitSymbols
#elif defined( HB_DATASEG_STARTUP )
    #define HB_DATASEG_BODY HB_DATASEG_FUNC( LIST__InitSymbols )
    #include "hbiniseg.h"
#endif
 
Así declaro esos dos símbolos que son dos clases hechas en C y serán usadas en PRG con herencia incluso :-)

Re: Manu Exposito's pearls

Posted: Tue Aug 20, 2019 4:40 pm
by Verhoven
Buenas tardes Manu,
He leido en tus mensajes que Harbour indica la sustitución de strtok de C por HB_ATokens de Harbour, pero sustituir la primera por la segunda no se puede hacer directamente ya que strtok admite como parámetro una cadena con una serie de delimitadores, es decir, más de un delimitador para los tokens, mientras que HB_ATokens solo admite un delimitador.

¿Cómo se puede entonces hacer la sustitución de strtok en las rutinas donde los hayamos incorporado?.

Desde hace años vengo utlizando strtok en alguna función en C para agilizar al máximo el tratamiento de archivos grandes donde los distintos tokens pueden estar separados por más de un delimitador y me gustaría poder dejar de utilizar strtok de C por los problemas anunciados de compatibilidad.

Re: Manu Exposito's pearls

Posted: Tue Aug 20, 2019 6:03 pm
by xmanuel
Hola.
Realmente no son totalmente compatibles hay que hacer retoques :? .
Fíjate en la definición de la función de C:

Code: Select all

char *strtok(char *str, const char *delim)
 
No sé de donde sacas que puede admitir varios separadores, o tal vez te refieres que el separador puede ser mas de un caracter, por ejempo: "=>"?
Lo que esta claro es que va devolviendo tokens (trozos de cadena) mientras no llegue a '\0' o sea fin de cadena pasada.
Aquí tienes un ejemplo: https://www.tutorialspoint.com/compile_c_online.php

En cambio la sintaxis de hb_ATokens es:

Code: Select all

hb_ATokens( <cString>, [<cDelim>|<lEOL>], [<lSkipStrings>], ;
            [<lDoubleQuoteOnly>] ) → aTokens
 
O sea que es más versátil que la de C con la ventaja de que nos devuelve un item de tipo array con item de tipo caracteres que desde el sistema extendido de harbour es más fácil su manejo.
Seguro que la sustitución de la primera por la segunda te resultará más fácil y provechosa :-)

Re: Manu Exposito's pearls

Posted: Wed Aug 21, 2019 12:47 pm
by Verhoven
Buenas tardes Antonio,
Ciertamente creo que no me expresé con suficiente rigor:

strtok admite como segundo parámetro una cadena de caracteres, de tal manera que cada caracter de esa cadena lo interpreta como un delimitador, devolviendo nuevos elementos hasta que llega al final de la cadena pasada como primer parámetro. Sin embargo la función de Harbour, aunque coloquemos la misma cadena conteniendo esos delimitadores, solo interpreta como delimitador de los distintos elementos (items) el primero de _ de la misma, el resto no los tiene en cuenta.

Por ello para sustituir la función strtok por la función hb_ATokens de Harbour habría que construir bucles anidados que fueran pasando por cada elemento del array devuelto en el bucle anterior por el siguiente caracter de la cadena que contenga los delimitadores. Lo cual parece que va a complicar las cosas y va a añadir líneas de código al proceso que relentizarán algo el procesado de los archivos de datos a analizar.

El problema de incompatibilidad de strtok podríais explicar exactamente en qué consiste porque he visto el código fuente de hb_ATokens pero no me atrevo a retocarlo con seguridad para incluir la posibilidad de "varios delimitadores".

Re: Manu Exposito's pearls

Posted: Wed Aug 21, 2019 7:50 pm
by xmanuel
Así es...
Ese comportamiento es diferente :-(

Re: Manu Exposito's pearls

Posted: Thu Aug 22, 2019 6:34 am
by AntoninoP
we can move this thread to Spanish forum :(

Re: Manu Exposito's pearls

Posted: Thu Aug 22, 2019 10:45 pm
by Lailton
Hi Manu,

Keep doing your excellent job and code.
I am a big fan your job, I like style how you make your codes

WHO write equal always? everybody here have your way to write code :)

Thanks for share the function good job. :D