11 Jul, 2009, Silenus wrote in the 1st comment:
Votes: 0
I have been wrestling again with my operator overloading code. In LPC you have functions which are overloaded as I described in another post depending on the types of the arguments. I have been trying to come up with a succinct and efficient method to resolve these at runtime (since in LPC you cannot completely infer the type statically). The current could I have relies on a runtime data structure which needs to be navigated at runtime. Currently the code I have written is sort of a place holder for something better. My idea however is that I could perhaps use some sort of statically constructed list to get the effect I want. I figure this list should be 2d since you are dispatching on two arguments.

The question I have is:

1) How would one go about implementing a dispatch mechanism based on two arguments to execute some function x statically?
2) Is it worth it? i.e. if you transform the code into a two branches how much speed gain would one see?

Thanks in advance.
12 Jul, 2009, Scandum wrote in the 2nd comment:
Votes: 0
I'm not sure about your terminology. Are you talking about program code to quickly distinguish int foo(int i) from int foo(string j) ?
12 Jul, 2009, Silenus wrote in the 3rd comment:
Votes: 0
My system has tagged types. I.e. I have a type tag associated with each piece of data telling me what it is. This is necessary for LPC since there is an "any" type or mixed type in the system and operators can be heavily overloaded. For example a + b could mean 1) add two ints, 2) concat two strings, 3) concat two arrays and so on. Currently I have this stuff encoded using classes-

class Overloaded { addRule(TypeCode1, TypeCode2, Functor); } // essentially….

which then does a lookup at runtime and selects the relevant functor. Since this information is actually static and known at compile time and I wondering about possible methods for constructing a function or functor which can handle some of this logic statically at compile time. I know that I can probably encode this information as a static list (1D or 2D) but I am not sure if it is possible to efficiently turn this into some sort of if/else type stuff.

// 1d type list
class ListNull;

template <class H, class T, int C1, int C2, class F>
List
{
typedef H Head;
typedef T Tail;
typedef F Functor;
enum { Left(C1), Right(C2) };
};
12 Jul, 2009, Silenus wrote in the 4th comment:
Votes: 0
I think I have got it now. After surfing the web a bit :P. Thanks.
12 Jul, 2009, Scandum wrote in the 5th comment:
Votes: 0
If you don't already you'd probably want to use bitvectors:
int    001
string 010
array 100
mixed 111

There are some algorithms that work well with that.
12 Jul, 2009, David Haley wrote in the 6th comment:
Votes: 0
Bit vectors are useless here, as shown, because you're not combining several values at a time and instead creating many discrete values.

Silenus, what did you end up doing? (so that others can benefit)
13 Jul, 2009, Silenus wrote in the 7th comment:
Votes: 0
Well the solution is pretty ugly at present since I am still just learning the ropes when it comes to metaprogramming. I had to throw away my first try (it should in principle work but would do far to many comparisons since it would generate an if/else if stream). My second take at present though it should be more efficient is much messier. Unfortunately you quickly bump into what I believe are the limits of the current template mechanisms. I will have to manually construct a bunch of templates depending on the number of cases I need in the switch statement.

So far I have only coded the engine as a sketch and due to bugs this code may not work though the idea should be clear. It also relies on some assumptions which are specific to the operator problem I am working on. i.e. that if A op B is in the set S so is B op A so the number of cases in the double switch are |S| x |S|.

template<uint32_t T, class C1, class C2, class C3, class O>
struct Case
{
typedef T Tag;
typedef C1 Case1;
typedef C2 Case2;
typedef C3 Case3;
};


template<class C1, class C2, class F>
struct Overload
{
typedef C1 ConversionOne;
typedef C2 ConversionTwo;
typedef F Functor;
};

template<uint32_t I, class C1, class C2, class C3>
struct
Switch
{
static inline bool eval(basic::Value* a0, basic::Value* a1, basic::Value* r)
{
switch( IndexArg<I>::eval(a0,a1,r)->getTypeTag() )
{
case C1::Tag :
return Switch<T,I-1,C1::Case1,C1::Case2,C1::Case3>::eval(a0,a1,r);
case C2::Tag :
return Switch<T,I-1,C2::Case1,C2::Case2,C2::Case3>::eval(a0,a1,r);
case C3::Tag :
return Switch<T,I-1,C2::Case1,C2::Case2,C2::Case3>::eval(a0,a1,r);
default:
return false;
}
}
};

template<class C1, class C2, class C3>
struct Switch<0,C1,C2,C3>
{
static inline bool eval(basic::Value* a0, basic::Value* a1, basic::Value* r)
{
switch( IndexArg<0>::eval(a0,a1,r)->getTypeTag() )
{
case C1::Tag :
r = C1::Functor::eval( C1::ConversionOne::eval(a0), C1::ConversionTwo::eval(a1) );
return true;
case C2::Tag :
r = C2::Functor::eval( C2::ConversionOne::eval(a0), C2::ConversionTwo::eval(a1) );
return true;
case C3::Tag :
r = C3::Functor::eval( C3::ConversionOne::eval(a0), C3::ConversionTwo::eval(a1), r);
return true;
default:
return false;
}
}
};

int main()
{
Switch<1,
Case<>
Case<>
Case<>
>::eval( … );
}
0.0/7