Welcome, Guest. Please login or register.

Author Topic: jump tables (-Edit- Eliminating conditional statements :-))  (Read 13638 times)

Description:

0 Members and 1 Guest are viewing this topic.

Offline bloodlineTopic starter

  • Master Sock Abuser
  • Hero Member
  • *****
  • Join Date: Mar 2002
  • Posts: 12114
    • Show only replies by bloodline
    • http://www.troubled-mind.com
jump tables (-Edit- Eliminating conditional statements :-))
« on: February 21, 2005, 12:10:25 PM »
Is there any "nice" way to do this in C, pointer magic etc?

Imagine I have an array of pointers to allow me to jump to a subroutine based on the index stored in a variable:

int* jump[3];

jump[0]= &task1;
jump[1]= &task2;
jump[2]= &task3;

a=user_input(); // where the user could enter 1, 2 or 3

Goto jump(a);
task_return:


task1:
Do Something;
goto task_return;

task2:
Do Something else;
goto task_return;

task3:
Do Something different;
goto task_return;


I have no idea why I'm asking this... :crazy:

Offline Piru

  • \' union select name,pwd--
  • Hero Member
  • *****
  • Join Date: Aug 2002
  • Posts: 6946
    • Show only replies by Piru
    • http://www.iki.fi/sintonen/
Re: jump tables
« Reply #1 on: February 21, 2005, 12:18:10 PM »
I won't give you the exact solution, but this should help still:

Code: [Select]

#include <stdio.h>

typedef int (*funcptr_t)(int, char *);

int func1(int x, char *str);
int func2(int x, char *str);
int func3(int x, char *str);

int main(void)
{
  funcptr_t funcarray[3] =
  {
    func1,
    func2,
    func3
  };
  int i;

  for (i = 0; i < 3; i++)
  {
    int ret;

    ret = funcarray[i](i * i + 2, &quot;moo&quot;);
    printf(&quot;ret %d\n&quot;, ret);
  }

  return 0;
}

int func1(int x, char *str)
{
  printf(&quot;func1 x=%d, str=<%s>\n&quot;, x, str);
  return 1;
}

int func2(int x, char *str)
{
  printf(&quot;func2 x=%d, str=<%s>\n&quot;, x, str);
  return 2;
}

int func3(int x, char *str)
{
  printf(&quot;func3 x=%d, str=<%s>\n&quot;, x, str);
  return 3;
}


[EDIT]changed i*i to i*i+2 to make it more obvious the input isn't always the index ;-)[/EDIT]
 

Offline bloodlineTopic starter

  • Master Sock Abuser
  • Hero Member
  • *****
  • Join Date: Mar 2002
  • Posts: 12114
    • Show only replies by bloodline
    • http://www.troubled-mind.com
Re: jump tables
« Reply #2 on: February 21, 2005, 12:20:15 PM »
Quote

Piru wrote:
I won't give you the exact solution, but this should help still:

Code: [Select]

#include <stdio.h>

typedef int (*funcptr_t)(int, char *);

int func1(int x, char *str);
int func2(int x, char *str);
int func3(int x, char *str);

int main(void)
{
  funcptr_t funcarray[3] =
  {
    func1,
    func2,
    func3
  };
  int i;

  for (i = 0; i < 3; i++)
  {
    int ret;

    ret = funcarray[i](i*i, &quot;moo&quot;);
    printf(&quot;ret %d\n&quot;, ret);
  }

  return 0;
}

int func1(int x, char *str)
{
  printf(&quot;func1 x=%d, str=<%s>\n&quot;, x, str);
  return 1;
}

int func2(int x, char *str)
{
  printf(&quot;func2 x=%d, str=<%s>\n&quot;, x, str);
  return 2;
}

int func3(int x, char *str)
{
  printf(&quot;func3 x=%d, str=<%s>\n&quot;, x, str);
  return 3;
}


Hmmm, yeah that actually makes more sense than what I was trying to achive!! Cheers :-D

Offline Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16882
  • Country: gb
  • Thanked: 6 times
    • Show only replies by Karlos
Re: jump tables
« Reply #3 on: February 21, 2005, 12:31:38 PM »
Function lookup is great :-)

Generally, the syntax for a function pointer is ugly, but typedefs help a lot

eg

typedef (*)();

So, suppose you want a pointer to function of the signature "int func(const char* blah);"

you would use

typedef int (*MyFuncPtrType)(const char*);

and then you can do stuff like

int foo(const char* blah);
int moo(const char* blah);
int poo(const char* blah);

...

MyFuncPtr p = &foo; /* the & is optional here btw */

p("hello!");

Or create arrays of pointers of this kind,

MyFuncPtr jumpTable[] = { &foo, &moo, &poo };

and do

jumpTable[1]("Hello");

etc...
int p; // A
 

Offline Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16882
  • Country: gb
  • Thanked: 6 times
    • Show only replies by Karlos
Re: jump tables
« Reply #4 on: February 21, 2005, 12:33:42 PM »
@bloodline

Of course C++ virtual functions are a bit nicer to use ;-)
int p; // A
 

Offline bloodlineTopic starter

  • Master Sock Abuser
  • Hero Member
  • *****
  • Join Date: Mar 2002
  • Posts: 12114
    • Show only replies by bloodline
    • http://www.troubled-mind.com
Re: jump tables
« Reply #5 on: February 21, 2005, 12:35:47 PM »
Quote

Karlos wrote:
@bloodline

Of course C++ virtual functions are a bit nicer to use ;-)


Que?

Offline Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16882
  • Country: gb
  • Thanked: 6 times
    • Show only replies by Karlos
Re: jump tables
« Reply #6 on: February 21, 2005, 12:49:21 PM »
@bloodline

Consider

class GameMonsterAI {
public:
virtual void huntTarget(); // AI behaviours
virtual void foundTarget();
virutal void attackTarget();
//..
};

Then later

class UglyMonster : public GameMosterAI {
public:
void huntTarget(); // unique implementation for this monster
void foundTarget(); // ditto
void attackTarget(); // ditto
//...
};

class FlyingMonster : public GameMosterAI {
public:
void huntTarget(); // unique implementation for this monster
void foundTarget(); // ditto
void attackTarget(); // ditto
//...
};

...and you might have loads of different monsters types.

You don't need to know exactly what monster you have to tell it how to huntTarget(), you just need to know that it has that method. This is the root of your "polymorphic" behaviour.

Whatever real monster type you have, simply handling it as an instance of GameMonsterAI and calling the huntTarget() method will invoke the appropriate behavour for the actual monster at hand.

That's about it for virtual functions. Each class that implements a set of virtual functions generally uses a jump table internally, so they're the same thing really.

It's just a nicer syntax :-)
int p; // A
 

Offline LP

  • Sr. Member
  • ****
  • Join Date: Jan 2003
  • Posts: 358
    • Show only replies by LP
    • http://bailout.dk
Re: jump tables
« Reply #7 on: February 21, 2005, 12:54:14 PM »
yeah.. polymorphism rules, just too bad c++ is such a killer on the 68k's :(
 

Offline bloodlineTopic starter

  • Master Sock Abuser
  • Hero Member
  • *****
  • Join Date: Mar 2002
  • Posts: 12114
    • Show only replies by bloodline
    • http://www.troubled-mind.com
Re: jump tables
« Reply #8 on: February 21, 2005, 12:54:39 PM »
Hmmm, But I can't see how virtual functions are applicable to my initial problem, which is to speed up a conditional path... (I've only realised that is what I was trying to achive after I saw Piru's example).

-Edit-
If you look at my original post, I could have written:

switch(a) {


    case 1 : Do_something;
    case 2 : Do_Something_else;
    case 3 : Do_something_different;

}

I'm not sure why I chose to do it the other way... except maybe to eliminate any conditionality from the code.

Offline bloodlineTopic starter

  • Master Sock Abuser
  • Hero Member
  • *****
  • Join Date: Mar 2002
  • Posts: 12114
    • Show only replies by bloodline
    • http://www.troubled-mind.com
Re: jump tables
« Reply #9 on: February 21, 2005, 01:11:08 PM »
So I suppose my question is, How does one eliminate uncertainty from a program :-D

Offline Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16882
  • Country: gb
  • Thanked: 6 times
    • Show only replies by Karlos
Re: jump tables
« Reply #10 on: February 21, 2005, 01:16:43 PM »
Jump tables can be much faster than switch/case constructs. The latter often end up like large nested if/else if, especially when the blocks of code are different sizes or if the range has gaps. The further down the switch  you go, the longer it takes.

A function lookup table can be written instead. It totally doesnt matter if the functions are different sizes or if there are holes in the range of cases - provided your overall table is big enough for every known case value.

The function lookup table effectively takes a constant time to evaluate for any case.

I use them in quite a few places where you might think a switch/case would do (I only use the switch/case when the range is small and the code for each case is so small that physically calling the function would take longer).
int p; // A
 

Offline Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16882
  • Country: gb
  • Thanked: 6 times
    • Show only replies by Karlos
Re: jump tables
« Reply #11 on: February 21, 2005, 01:19:39 PM »
Quote

LP wrote:
yeah.. polymorphism rules, just too bad c++ is such a killer on the 68k's :(


It isn't that bad. It all depends on how you design your code - C++ can be more efficient than C code even on 680x0, provided you designed it properly in the first instance (no pun intended).
int p; // A
 

Offline bloodlineTopic starter

  • Master Sock Abuser
  • Hero Member
  • *****
  • Join Date: Mar 2002
  • Posts: 12114
    • Show only replies by bloodline
    • http://www.troubled-mind.com
Re: jump tables
« Reply #12 on: February 21, 2005, 01:25:26 PM »
Quote

Karlos wrote:
Jump tables can be much faster than switch/case constructs. The latter often end up like large nested if/else if, especially when the blocks of code are different sizes or if the range has gaps. The further down the switch  you go, the longer it takes.


Yup, I though I was on the right path... the idea of having to evaluate 60000 odd possible conditions made me panic... The Jumptable/function look up table is the best option!

Quote

A function lookup table can be written instead. It totally doesnt matter if the functions are different sizes or if there are holes in the range of cases - provided your overall table is big enough for every known case value.

The function lookup table effectively takes a constant time to evaluate for any case.


"Constant time to evaluate" are the magic words here :-)

Quote

I use them in quite a few places where you might think a switch/case would do (I only use the switch/case when the range is small and the code for each case is so small that physically calling the function would take longer).


Have you go any nice and simple, I mean really dumb, examples of function look up's that I can compare and contrast with Piru's? I've never seen these before and I want to get a few in to my brain :-D

Offline falemagn

  • Sr. Member
  • ****
  • Join Date: May 2002
  • Posts: 269
    • Show only replies by falemagn
    • http://www.aros.org/
Re: jump tables
« Reply #13 on: February 21, 2005, 01:28:37 PM »
Quote

 Jump tables can be much faster than switch/case constructs. The latter often end up like large nested if/else if, especially when the blocks of code are different sizes or if the range has gaps. The further down the switch you go, the longer it takes.


Decent compilers (and gcc is one such), compile switch/case statements down to a jump table for when there are no holes in the range of possibilities, or to a binary search tree in the other case (it prefers saving space, if the range is very sparse).

Therefore, you go from costant time to O(log n) time.

@bloodline

Using functions is perhaps cleaner, but can be overkill for the functions prologue/epilogue. If you are using gcc, you may want to use its "computed goto's" extension.

It works like this (notice the double ampersand!):

Code: [Select]

    void *jmptable[] =
    {
        &&lab1,
        &&lab2,
        &&lab3,
         ...
        &&labN
    };

    ...
    ...

    goto jmptable[foo];
    returnpoint:
    ...

    lab1:
    ...
    goto returnpoint;

    lab2:
    ...
    goto returnpoint;

    lab3:
    ...
    goto returnpoint;

    ...

    labN:
    ...
    goto returnpoint;


This is pretty much like the GOSUB statement from BASIC.
 

Offline falemagn

  • Sr. Member
  • ****
  • Join Date: May 2002
  • Posts: 269
    • Show only replies by falemagn
    • http://www.aros.org/
Re: jump tables
« Reply #14 on: February 21, 2005, 01:32:24 PM »
Quote

bloodline wrote:
If you look at my original post, I could have written:

switch(a) {


    case 1 : Do_something;
    case 2 : Do_Something_else;
    case 3 : Do_something_different;

}

I'm not sure why I chose to do it the other way... except maybe to eliminate any conditionality from the code.


If that's really what it would look like, save your efforts for other parts of the code :) Gcc will compile that down to  a jumptable.