harbour hb_ functions

Harbour, MingW related news.

Moderator: Rathinagiri

User avatar
AUGE_OHR
Posts: 2061
Joined: Sun Aug 25, 2019 3:12 pm
DBs Used: DBF, PostgreSQL, MySQL, SQLite
Location: Hamburg, Germany

Re: harbour hb_ functions

Post by AUGE_OHR »

hi,

i wrote a small App to "extract" HB_FUNC

from HMG Source and got this (now as ZIP)
HMG_HB_FUNC.ZIP
(10.21 KiB) Downloaded 305 times
Last edited by AUGE_OHR on Tue Jan 07, 2020 12:01 am, edited 2 times in total.
have fun
Jimmy
KDJ
Posts: 243
Joined: Mon Sep 05, 2016 3:04 am
Location: Poland

Re: harbour hb_ functions

Post by KDJ »

Hi Jimmy

This topic applies to Harbour functions and not HMG functions.
So please move your post to another location.
And long text you can put between tags: [code][/code]
User avatar
AUGE_OHR
Posts: 2061
Joined: Sun Aug 25, 2019 3:12 pm
DBs Used: DBF, PostgreSQL, MySQL, SQLite
Location: Hamburg, Germany

Re: harbour hb_ functions

Post by AUGE_OHR »

hi,
KDJ wrote: Mon Jan 06, 2020 10:25 pm This topic applies to Harbour functions and not HMG functions.
So please move your post to another location.
hm ... if i search for a Function i did not know if it is a Harbour or HMG / MiniGUI HB_Func

that why i make those List too where i can search so i think it belong to this Thread
KDJ wrote:And long text you can put between tags:
Yes, sorry

from MiniGUI Source as ZIP
MiniGUI_HB_FUNC.ZIP
(25.13 KiB) Downloaded 281 times
have fun
Jimmy
PeteWG
Posts: 176
Joined: Sun Mar 21, 2010 5:45 pm

Re: harbour hb_ functions

Post by PeteWG »

KDJ wrote: Mon Jan 06, 2020 9:05 pm I found a bug in Harbour function:

hb_ForNext( nStart, nEnd | bEnd, bCode [, nStep ] )

If nStart > nEnd, the loop is not executed.
Hi,
I think it is a "feature", which means, it is so by design.
(well, not very efficient design, perhaps, but not exactly a bug.)
The truth is that this behavior should be documented, so, thank you for pointing it out!
By the way, another more severe issue can arise by `nStep` argument,
which must never (!) be assigned a negative value, otherwise an (uninterruptible)
infinite loop will be produced!
these lines of code:

Code: Select all

LOCAL nStep := -1
hb_ForNext(  1, 10, {|i| QQout(i)}, nStep )
will flood the monitor with (negative) numbers, continuously and until the running process
be somehow "killed" or the CPU be burned. ;)

regards,
Pete
KDJ
Posts: 243
Joined: Mon Sep 05, 2016 3:04 am
Location: Poland

Re: harbour hb_ functions

Post by KDJ »

Hi Pete

I do not think it was intentional.
What sense would introduce a function which performs only half of what traditional loop FOR...NEXT?

This is a piece of function code from source (eval.c):

Code: Select all

         while( nStart <= nEnd )
         {
            hb_vmPushEvalSym();
            hb_vmPush( pCodeBlock );
            hb_vmPushNumInt( nStart );
            hb_vmSend( 1 );

            nStart += nStep;
         }
This can do somehow like as below:

Code: Select all

         if (nStep != 0)
         {
            if (nStep > 0)
            {
               while( nStart <= nEnd )
               {
                  hb_vmPushEvalSym();
                  hb_vmPush( pCodeBlock );
                  hb_vmPushNumInt( nStart );
                  hb_vmSend( 1 );
               
                  nStart += nStep;
               }
            }
            else
            {
               while( nStart >= nEnd )
               {
                  hb_vmPushEvalSym();
                  hb_vmPush( pCodeBlock );
                  hb_vmPushNumInt( nStart );
                  hb_vmSend( 1 );
               
                  nStart += nStep;
               }
            }
         }
PeteWG
Posts: 176
Joined: Sun Mar 21, 2010 5:45 pm

Re: harbour hb_ functions

Post by PeteWG »

Hi KDJ

I remember, when I tried to create some documentation for this function, I had
also examined the sources (and I did it again now).
My impression is the code is a little "quick and (if not dirty) incomplete".
- it is error prone, since it has no error detection (neither during compile-time nor run-time),
- it returns inconsistent value and , as you correctly saying,
- "performs only half of what traditional loop..."

I cannot guess the intention of the developer who created the function but I can imagine an excuse:
this function mimics the `for(...)` loop of C-language and mimics it very well, in the sense,
that just like in C, the programmer is equally responsible and free either to create good,
bug-free code or to "shoot his foot!" ;-)
Besides, the open source code is open not only for use but also open to improvements!
Certainly, the code you suggest is in this direction and, if you wish, please integrate it
in the initial function and post the final result.

regards,
Pete
KDJ
Posts: 243
Joined: Mon Sep 05, 2016 3:04 am
Location: Poland

Re: harbour hb_ functions

Post by KDJ »

Hi, Pete

Yes, I agree with you, code of this function looks "quick and ... incomplete".

Below is my implementation of a function that should work like "for loop" in C (coded in Harbour).
This code is also "quick" and only a little tested.

Syntax "for loop" in C:

Code: Select all

for ( [Init] ; [Condition] ; [Update] )
{
  [Code]
  [continue;]
  [Code]
  [break;]
  [Code]
}
hb_ForLikeC() function:

Code: Select all

/*
  hb_ForLikeC([bInit], [bCondition], [bUpdate], [bCode]) --> NIL
    - if bCondition or bCode return .F. -> EXIT loop, otherwise loop is continued
*/
FUNCTION hb_ForLikeC(bInit, bCondition, bUpdate, bCode)
  LOCAL lCondition := .T.
  LOCAL lContinue

  IF hb_IsBlock(bInit)
    Eval(bInit)
  ENDIF

  IF hb_IsBlock(bCondition)
    lCondition := Eval(bCondition)

    IF ! hb_IsLogical(lCondition)
      lCondition := .T.
    ENDIF
  ENDIF

  DO WHILE lCondition
    IF hb_IsBlock(bCode)
      lContinue := Eval(bCode)

      IF hb_IsLogical(lContinue) .and. (! lContinue)
        EXIT
      ENDIF
    ENDIF

    IF hb_IsBlock(bUpdate)
      Eval(bUpdate)
    ENDIF

    IF hb_IsBlock(bCondition)
      lCondition := Eval(bCondition)

      IF ! hb_IsLogical(lCondition)
        lCondition := .T.
      ENDIF
    ENDIF
  ENDDO

RETURN NIL
Example of use:

Code: Select all

FUNCTION Main()
  LOCAL aArr[10]
  LOCAL n

  hb_ForLikeC({ || n := 1 }, { || n <= Len(aArr) }, { || ++n }, { || aArr[n] := n })
  MsgBox(n)
  MsgBox(aArr)

  hb_ForLikeC({ || n := Len(aArr) }, { || n >= 5 }, { || --n }, { || aArr[n] *= 10 })
  MsgBox(n)
  MsgBox(aArr)

RETURN NIL
Best regards
Krzysztof (aka KDJ)

PS:
Thank you very much for the excellent documentation: https://github.com/Petewg/harbour-core/wiki
PeteWG
Posts: 176
Joined: Sun Mar 21, 2010 5:45 pm

Re: harbour hb_ functions

Post by PeteWG »

Hi Krzysztof,
Though not heavily tested, your code works as expected. (btw, you must be a fan of code-blocks ;-))
Good Harbour-code! I won't stop saying that this language/compiler is an ideal tool
for general purpose programming (particularly for desktop appls and data processing;
you can write excellent code with it.)

My approach regarding the initial hb_ForNex() was to modify the code in C-level
(aiming better speed, but mainly for learning and fun.. -- C is really fun!).
Is not so much sophisticated but hope it's more closer than the original to C `for()` loop
and that it works ok! (please see/try attached source file).
forNext.zip
(978 Bytes) Downloaded 223 times
Anyhow, since this function is not in a great demand and/or widely used,
I don't know how much useful for users could it be.

regards,
Pete
KDJ
Posts: 243
Joined: Mon Sep 05, 2016 3:04 am
Location: Poland

Re: harbour hb_ functions

Post by KDJ »

PeteWG wrote: Thu Jan 09, 2020 5:45 pm ... you must be a fan of code-blocks ...
I guess I'm not a fan of code blocks.
Simply, in this case code blocks are needed to emulate for() loop of C language.

I created hb_ForLoop() function (in C) that can emulate FOR...NEXT HARBOUR statement or for() loop of C:

Code: Select all

/*
  hb_ForLoop()

  2020-01-11 Krzysztof Janicki (aka KDJ)
*/

#include "hbapi.h"
#include "hbapiitm.h"
#include "hbvm.h"

/*
if first and second parameters are numbers:
  works like FOR...NEXT loop in HARBOUR:
    hb_ForLoop(nStart, nEnd, [nStep], [bCode]) --> nCounter
      - to bCode block is passed loop counter as parameter: { |nCounter| ... }
      - if bCode return .F. -> EXIT loop, otherwise loop is continued
else:
  works like for() loop in C:
    hb_ForLoop([bInit], [bCondition], [bUpdate], [bCode]) --> NIL
      - if bCondition or bCode return .F. -> EXIT loop, otherwise loop is continued
*/
HB_FUNC( HB_FORLOOP )
{
  PHB_ITEM pCode = hb_param(4, HB_IT_BLOCK);

  if (HB_ISNUM(1) && HB_ISNUM(2))
  {
    HB_MAXINT nStart = hb_parnint(1);
    HB_MAXINT nEnd   = hb_parnint(2);
    HB_MAXINT nStep  = hb_parnintdef(3, 1);

    while ((nStep < 0) ? (nStart >= nEnd) : (nStart <= nEnd))
    {
      if (pCode)
      {
        hb_vmPushEvalSym();
        hb_vmPush(pCode);
        hb_vmPushNumInt(nStart);
        hb_vmSend(1);

        if (HB_ISLOG(-1) && (! hb_parl(-1)))
          break;
      }

      nStart += nStep;
    }

    hb_retnint(nStart);
  }
  else
  {
    PHB_ITEM pInit      = hb_param(1, HB_IT_BLOCK);
    PHB_ITEM pCondition = hb_param(2, HB_IT_BLOCK);
    PHB_ITEM pUpdate    = hb_param(3, HB_IT_BLOCK);
    HB_BOOL  Condition  = HB_TRUE;

    if (pInit)
      hb_evalBlock0(pInit);

    if (pCondition)
    {
      hb_evalBlock0(pCondition);

      if (HB_ISLOG(-1))
        Condition = hb_parl(-1);
    }

    while (Condition)
    {
      if (pCode)
      {
        hb_evalBlock0(pCode);

        if (HB_ISLOG(-1) && (! hb_parl(-1)))
          break;
      }

      if (pUpdate)
        hb_evalBlock0(pUpdate);

      if (pCondition)
      {
        hb_evalBlock0(pCondition);

        if (HB_ISLOG(-1))
          Condition = hb_parl(-1);
      }
    }

    hb_ret();
  }
}
Here is example of use and speed test of different variants:
ForLoop.7z
(2.25 KiB) Downloaded 232 times
PeteWG
Posts: 176
Joined: Sun Mar 21, 2010 5:45 pm

Re: harbour hb_ functions

Post by PeteWG »

I created hb_ForLoop() function (in C) that can emulate FOR...NEXT HARBOUR statement or for() loop of C:
Very good implementation!
You might consider to push your code to Harbour repository and if so,
you could start by creating an issue in GitHub

BTW, an alternative way to measure time of code execution
is to use relevant hbwin functions (see below):

Code: Select all

wapi_QueryPerformanceCounter( @nCounterStart )
  hb_ForNext(nStart, nEnd, bCodeH, nStep)
wapi_QueryPerformanceCounter( @nCounterEnd )
  ? "Execution time elapsed: ", win_QPCounter2Sec( nCounterEnd - nCounterStart ), " sec."
regards,
Pete
Post Reply