Hi, all!

i just came across something which may end up completely changing the way i
write bindings for v8, and i wanted to take a moment to share it...

i just created a template which uses predicates (composed in arbitrary
combinations) to determine how a given InvocationCallback (InCa) call should
be dispatched in native code. e.g. we can dispatch to different native
functions based on the runtime type of any given argument(s).

This is of course all first-draft, ugly, verbose, and whatnot, but the proof
of concept is now here (this is probably the most-requested feature
from v8-juice users)...

PredicatedInCa<> is a Pair type of (Predicate, InvocationCallback (in a
structified/type-rich form)). They are (currently) composed like this:

// The native functions i want to overload:
void bogo_callback_int16( v8::Arguments const & argv );
void bogo_callback_int32( v8::Arguments const & argv );
void bogo_callback_double( v8::Arguments const & argv );
void bogo_callback_array( v8::Arguments const & argv );
void bogo_callback_object( v8::Arguments const & argv );

Create 5 rules which dispatch to a different native function depending on
the runtime type of the first argument to the function:

    typedef PredicatedInCa< ArgAt_IsA<0,int16_t>, InCaLikeFunc<void,
bogo_callback_int16> > PredIsaInt16;
    typedef PredicatedInCa< ArgAt_IsA<0,int32_t>, InCaLikeFunc<void,
bogo_callback_int32> > PredIsaInt32;
    typedef PredicatedInCa< ArgAt_IsA<0,double>, InCaLikeFunc<void,
bogo_callback_double> > PredIsaDouble;
    typedef PredicatedInCa< ArgAt_IsArray<0>, InCaLikeFunc<void,
bogo_callback_array> > PredIsaArray;
    typedef PredicatedInCa< ArgAt_IsObject<0>, InCaLikeFunc<void,
bogo_callback_object> > PredIsaObject;

This last template combines multiple predicates into a chain and creates an
InCa which will perform the dispatching logic:

    typedef PredicatedInCaOverloader< tmp::TypeList<
        PredIsaArray, PredIsaObject, PredIsaInt16, PredIsaInt32,
PredIsaDouble
        // the order is important for the numeric Int/Double predicates, for
reasons we'll see shortly...
    > > Overloads;

And now we have an InCa function which will perform the above analysis:

    v8::InvocationCallback cb = Overloads::Call;

Easy!!! (And all done at compile-time, though the type-based dispatching is
of course done at runtime.)

As a demonstration i bound the above overloads to a function cleverly called
"bogo" and then called it from script code:

        b.bogo(1 << 8);
        b.bogo(1 << 17);
        b.bogo((1<<31) * (1 << 10)); // js reportedly uses only 32-bit
bitshifts
        b.bogo([1,2,3]);
        b.bogo({});

Passing functions which no predicate matches will lead to a JS exception
(though we can use a fallback overload to perform arbitrary other
behaviour):

    Uncaught Error: No predicates in the argument dispatcher matched the
given arguments (arg count=1).

The (debug) output (one line per call made above):

ConvertDemo.cpp:127:bogo_callback_int16(): int_16 overload.
ConvertDemo.cpp:131:bogo_callback_int32(): int_32 overload.
ConvertDemo.cpp:135:bogo_callback_double(): double overload.
ConvertDemo.cpp:139:bogo_callback_array(): array overload.
ConvertDemo.cpp:143:bogo_callback_object(): object overload.

Notice in particular how the predicates distinguish small numbers from large
numbers: the "is-a int16?" predicate will return false if the value given is
not in the range (std::numeric_limits<int16_t>::min(), max()). That's why
the increasingly large numbers entered above resulted in different native
overloads being called.

This code is far, far from complete, but now that the concept has been shown
i think there are some really cool things we can do with this. (i'm excited,
anyway.)

Happy Hacking!

-- 
----- stephan beal
http://wanderinghorse.net/home/stephan/

-- 
v8-users mailing list
[email protected]
http://groups.google.com/group/v8-users

Reply via email to