Welcome, Guest. Please login or register.

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

Description:

0 Members and 1 Guest are viewing this topic.

Offline Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16882
  • Country: gb
  • Thanked: 6 times
    • Show all replies
Re: jump tables
« 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 all replies
Re: jump tables
« Reply #1 on: February 21, 2005, 12:33:42 PM »
@bloodline

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

Offline Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16882
  • Country: gb
  • Thanked: 6 times
    • Show all replies
Re: jump tables
« Reply #2 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 Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16882
  • Country: gb
  • Thanked: 6 times
    • Show all replies
Re: jump tables
« Reply #3 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 all replies
Re: jump tables
« Reply #4 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 Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16882
  • Country: gb
  • Thanked: 6 times
    • Show all replies
Re: jump tables
« Reply #5 on: February 21, 2005, 01:40:39 PM »
@bloodline

Not that I can show you right now as I'm at work.

Basically the example I posted before the C++ thing is it really

typedef (*)();

So, imagine you were writing a z80 emulation...

typedef struct Z80_t {
/* register set, etc etc */
} Z80;

typedef void (*Z80InstFn)(Z80*); /* z80 instruction handler */

/* z80 instruction handling functions */
static void z80_NOP(Z80* cpu)
{
cpu->regPC++;
}

static void z80_LD_BC_NN(Z80* cpu)
{
cpu->regB = cpu->regPC[2];
cpu->regC = cpu->regPC[1];
cpu->regPC+=3;
}

/* and lots more! */

static Z80InstFn instTable[256] = {
/* all the function names (& is optional) */
&z80_NOP,
&z80_LD_BC_NN,

....all the others...

&z80_RST_38H
};

...and you might have an execute function like this...

void execute(Z80* cpu, int maxInsts)
{
while (maxInsts--) {
instTable[cpu->regPC](cpu);
}
}

int p; // A
 

Offline Karlos

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

falemagn wrote:
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.


I have seen hundreds of instances to the contrary with gcc on about 4 different platforms. It depends on far too many variables outside your control wether or not a partuclar switch/case will be reduced to a jump table or not.
int p; // A
 

Offline Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16882
  • Country: gb
  • Thanked: 6 times
    • Show all replies
Re: jump tables
« Reply #7 on: February 21, 2005, 01:54:59 PM »
Quote

LP wrote:
True, Karlos true, but you'll have to design it damn efficient to make it really fly.. Were IMHO, C is easier to make efective and faster.. were if you use some of the more heavy mechanisms in c++ you often enter the badlands at first.. But well any god programmer can make anything fly on asorted platforms in different languages... :-)


Steer clear of RTTI, template and STL abuse and you are fine ;-)
int p; // A
 

Offline Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16882
  • Country: gb
  • Thanked: 6 times
    • Show all replies
Re: jump tables
« Reply #8 on: February 21, 2005, 01:56:45 PM »
Quote

bloodline wrote:
that fits in well with my thoughts.


I thought it might ;-)
int p; // A
 

Offline Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16882
  • Country: gb
  • Thanked: 6 times
    • Show all replies
Re: jump tables
« Reply #9 on: February 21, 2005, 02:06:45 PM »
Templates are great - used properly. Used improperly (and the STL itself in places is a prime example) it's a bloatmongers nightmare...
int p; // A
 

Offline Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16882
  • Country: gb
  • Thanked: 6 times
    • Show all replies
Re: jump tables
« Reply #10 on: February 21, 2005, 02:23:59 PM »
No likey mutex/semaphore?

Check the totally piece of p*ss multithreading example here

/self->trumpet->blow();
int p; // A
 

Offline Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16882
  • Country: gb
  • Thanked: 6 times
    • Show all replies
Re: jump tables
« Reply #11 on: February 21, 2005, 02:36:02 PM »
Someone needs to do the AROS version of the framework core. And by that, I mean really low level, using the most direct API's possible....

If only I knew someone insanely into AROS...

-edit-

Quote
I'm still not convinced that the amount of effort I put in is worth what I'd get out!


Thanks... I think :lol:
int p; // A
 

Offline Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16882
  • Country: gb
  • Thanked: 6 times
    • Show all replies
Re: jump tables
« Reply #12 on: February 21, 2005, 03:09:40 PM »
Quote

falemagn wrote:

If the compiler has the option to use a jump table and it choses not to, obviously it must have some good reasons.


Agreed, but it is not always the case that it's reasons are correct.

GCC is touted as the best code generator etc, but frankly it isn't even remotely true. It is a great compiler, with many source and RTL level optimisations, but the implementation quality of the codegenerator itself varies considerably from platform to platform. This is the trade off you pay for massive portability.

Quote
You'll find that indirect jumps often are worth, in terms of cpu cycles, as much as 2 or 3 consecutive if/else statements.


Again this totally depends on the platform.
int p; // A
 

Offline Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16882
  • Country: gb
  • Thanked: 6 times
    • Show all replies
Re: jump tables
« Reply #13 on: February 21, 2005, 03:13:34 PM »
Anyway, we are getting off topic ;-)

Getting back to bloodlines case

If he is doing what I think he is doing, a manual jump table makes more sense given the number of cases he will have. It's easier to manage a large jump table than it is to manage a large switch statement...
int p; // A
 

Offline Karlos

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16882
  • Country: gb
  • Thanked: 6 times
    • Show all replies
Re: jump tables
« Reply #14 on: February 21, 2005, 03:38:05 PM »
Whichever route you choose, a good compiler can only manage bad code so far ;-)

If you use a large case/switch, make sure your handling code is nicely inline and not just trampolining into functions, otherwise you have the overhead of the switch/case (regardless of how it is implemented by the compiler) and the function call overhead on top. If you do start to find you are writing more and more functions for handling the cases, then a jump table is better in the first instance.

As I said at the start, use a switch/case when the range is unbroken and the code required to perform the operation for each option is small compared to the overhead of calling a function. This way, as falemagan says, the compiler will be able to best optimise your code.
int p; // A