Saturday, May 19, 2007

ThreadPools in the VCF

So, the threaded methods post got me thinking: if we can create methods that execute in a thread, could we have something fancier such that a delegate's invoke() can take place asynchronously (much like the .Net design of a delegate's BeginInvoke() and EndInvoke())?

Part of the desire for this is to overcome a current weakness in the VCF's delegate design. Currently we can only accept function signatures of the type:

void MyFunction( Event* e );


A new design would allow us to have arbitrary function signatures, which makes it easier to use.

The first thing I wanted to address is making delegate's work with any kind of function signature instead of just limiting people to passing in a single. My major constraint was that I wanted it to work with version 6 of the Visual C++ compiler, which, while I know it's old now, alot of people still use it (myself included), and I wanted to have a stab at making things compatible with it. With that in mind here's a stab at it:


class CallBack {
public:
virtual ~CallBack(){}

String name;
};



class delegate {
public:

~delegate() {
clear();
}

bool empty() const {
return functions.empty();
}

size_t size() const {
return functions.size();
}


void clear() {
std::vector<CallBack*>::iterator it = functions.begin();
while ( it != functions.end() ) {
delete *it;
++it;
}

functions.clear();
}


void add( CallBack* callback ) {
std::vector<CallBack*>::iterator found =
std::find( functions.begin(), functions.end(), callback );

if ( found == functions.end() ) {
functions.push_back( callback );
}
}

void remove( CallBack* callback ) {
std::vector<CallBack*>::iterator found =
std::find( functions.begin(), functions.end(), callback );

if ( found != functions.end() ) {
functions.erase( found );
}
}

std::vector<CallBack*> functions;
};

This is a base class for our delegate, it handle adding/removing our callbacks. The callback is started be defining a base class for a callback method. It has a single member, a string with the name of the callback method (or some name). This lets us store a generic base pointer to the callbacks. The delegate holds N number of callbacks, and a callback is some specific class that wraps a function pointer of some sort. The specific class of the delegate will then invoke all of it's function callbacks.

Now what we want is the ability to specify the function signature, something like you find on other signal/slot libraries. This means we need to use templates, with definitions for each number of template arguments, i.e. a specific delegate class for function that have 2 arguments, one for no arguments, and so forth. In addition, we need to distinguish between functions that return a value, and functions that don't. Hearkening back to my ObjectPascal days, I'll refer to functions that have no return value as Procedures and functions that do have a return value as Functions. Not only do we need to distinguish between return or no return values, thanks to various quirks in C++, we also need to distinguish between whether the function pointer that we wrap is a static function

void MyFunction( int i, double d );

or a class function (a method, or member function of a class)

void MyClass::MyFunction( int i, double d );


So let's look at an attempt to define a function that 1 argument, and no return type.


template <typename ParamType1>
class NullClassType1 {
public:
void m(ParamType1){}
void m(Thread*, ParamType1){}
};


template
<typename P1>

class
Procedure1 : public CallBack {
public
:
typedef
void (*FuncPtr)(P1);


Procedure1():staticFuncPtr(NULL){}

Procedure1(FuncPtr funcPtr):staticFuncPtr(funcPtr){}



virtual
void invoke( P1 p1 ) {
if
( NULL != staticFuncPtr ) {
(*
staticFuncPtr)( p1 );
}
}


FuncPtr staticFuncPtr;
};



template
<typename P1, typename ClassType=NullClassType1<P1> >

class
ClassProcedure1 : public Procedure1<P1> {
public
:
typedef
void (ClassType::*ClassFuncPtr)(P1);


ClassProcedure1():Procedure1<P1>(),classFuncPtr(NULL),funcSrc(NULL){}


ClassProcedure1(ClassType* src, ClassFuncPtr funcPtr):Procedure1<P1>(),classFuncPtr(funcPtr),funcSrc(src){}

ClassProcedure1(ClassType* src, ClassFuncPtr funcPtr, const String& s):

Procedure1<P1>(),classFuncPtr(funcPtr),funcSrc(src){
name = s;
}




virtual
void invoke( P1 p1 ) {
if
( NULL != classFuncPtr && NULL != funcSrc ) {
(
funcSrc->*classFuncPtr)( p1 );
}
}


ClassFuncPtr classFuncPtr;
ClassType* funcSrc;
};


The above code declares two main classes. The first works as a wrapper around procedures (or functions that return no value/void). It has one method used to invoke the function pointer the class wraps. The method is declared as virtual so that in can be overridden in a subclass.

The next class provides a wrapper around a class function, and re-implements the virtual invoke method of it's parent class. This let's us have a base pointer which can be used for either type of function pointer, and makes the delegate implementation easier to handle because now it can handle either type of function wrapper seamlessly.

So, we have functions wrapped up, lets look at our delegate class:


template
<typename P1>

class
Delagate1 : public delegate {
public
:
typedef
void (*FuncPtr)(P1);
typedef
Procedure1<P1> CallbackType;

Delagate1<P1>& operator+= ( FuncPtr rhs ) {
CallbackType* cb = new CallbackType(rhs);

add( cb );
return
*this;
}


Delagate1<P1>& operator+= ( CallBack* rhs ) {
add( rhs );

return
*this;
}



void
invoke( P1 p1 ) {

std::vector<CallBack*>::iterator it = functions.begin();
while
( it != functions.end() ) {

CallBack* cb = *it;
CallbackType* callBack = (CallbackType*)cb;

callBack->invoke( p1 );

++
it;
}
}
};


The main features of the delegate class are that it lets us add functions in two ways: by a direct function pointer, or by as class instance of a callback. The first method let's us write code like this:

void MyCallback( int i )
{


printf( "Hello from MyCallback. i = %d\n", i );
}



Delagate1<int> d1;

d1 += MyCallback;

The other way we can add callbacks, especially callbacks that wrap a class function/method, is like so:

class Snarfy {

public
:
void
thisBlows( int g ) {
printf( "Hello from thisBlows! i: %d, this ptr: %p\n", g, this );
}
};


Snarfy sn;

Delagate1<int> d2;
d2 += new ClassProcedure1<int,Snarfy>(&sn,&Snarfy::thisBlows,"Snarfy::thisBlows");

Previously we wanted to have callbacks as a general class, something that we could identify by name, without having to know the specific class type. However we still need to invoke the callback methods. Because our delegate class has the same function signature template types, we can safely cast the generic callback type to the right template function class type. You can see this occur in the implementation of the delegate's invoke() method. Because we made the function class's invoke method virtual, the correct method will be called for either type, static or class function.

Now we have delegates and callbacks, that can be invoked like so:
d2.invoke( 100 );

A fancier implementation allows us to have delegates that take functions that return values, like this example:
bool funcWithReturnVal( const String& str, double d )
{


bool
result = true;
printf( "duhDoIt() %s, %0.5f, returning %d\n", str.ansi_c_str(), d, result );

return
result;
}


Delagate2R<bool,const String&,double> d3;

d3 += funcWithReturnVal;

bool
result = d3.invoke("Hola", 120.456);

This returns the result of the last callback that was invoked in the delegate's list of callbacks. We can get all the results that were returned like so:

for ( int i=0;i<d3.results.size();i++ ) {

printf( "d2 results[%d]: %d\n", i, (int)d3.results[i] );
}


Now we have delegates reasonably defined, and they should work on most compilers, VC6 or better, GCC, Borland, et al. Now lets look at async delegate invocation.

To fire off the callbacks asynchronously

Next was to try and implement a specific type


Thanks to the site http://www.bedaux.net/cpp2html/ for C++ to HTML formatting.

Wednesday, May 2, 2007

Visual Form File format

XAML this, XAML that, blah, blah, blah. I get so sick of hearing about how great XAML is, as if this were the most mind altering, earth shaking technology to hit the streets in years. Bah Humbug!

We've had something like this for years in the VCF! And the predecessor to XAML dates back even further than that, to Delphi's form files, NeXT's NIB files, and so on. So, I thought I'd post what the format for a Visual Form File (VFF) looks like, in Backus-Naur format:


component-decl ::= "object" component-id component-properties
*(component-decl) [component-delegates] "end"
component-id ::= component-name component-class ["," component-classid]

component-name ::= id
id ::= ALPHA *(ALPHA | DIGIT | '_' )
component-class ::= ALPHA *(ALPHA | DIGIT | '_' | "::" )
component-classid ::= ''' 1*(ALPHA | DIGIT | '-' ) '''

component-properties ::= 1*component-property
component-property ::= property-name '=' property-value
property-name ::= id | property-object-name | property-collection-name
property-object-name ::= id '.' property-name
property-collection-name ::= id '[' property-collection-key ']'
property-collection-key ::= property-number | property-string
property-value ::= property-string | property-number |
property-component-ref | property-enum |
property-enum-mask | property-binary | property-bool


property-string ::= ''' *(ALPHA | DIGIT | 'any printable unicode char' ) '''
property-number ::= 1*DIGIT ['.' 1*(DIGIT) ]
property-component-ref ::= ('@' component-name) | "null"
property-enum ::= id
property-enum-mask ::= '[' property-enum *[',' property-enum] ']'
property-binary ::= '{' binary-data '}'
binary-data ::= 1*(binary-byte)
binary-byte ::= (DIGIT | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' )
(DIGIT | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' )
property-bool ::= "true" | "false"

component-delegates ::= "delegates" *(component-delegate-decl) "end"
component-delegate-decl ::= delegate-name '=' delegate-array
delegate-name ::= id
delegate-array ::= '[' 1*(event-handler-ref) ']'
event-handler-ref ::= component-instance '@' component-callback-method
component-instance ::= id
component-callback-method ::= component-classname "::" component-methodname
component-classname ::= id
component-methodname ::= id


A simple example:

object window1 : VCF::Window
top = 500
left = 500
width = 400
height = 300
end

Note that the class name must be a fully qualified C++ class name, including the namespace the class belongs to.

A more complex example might look like this:

object Form1 : Window, 'ED88C0A1-26AB-11d4-B539-00C04F0196DA'
alignment = AlignNone
anchor = 0
bottom = 555.00000
color.blue = 0.78431
color.green = 0.81569
color.red = 0.83137
height = 537.00000
left = 234.00000
name = 'Form1'
top = 70.00000
visible = true
width = 565.00000

object label1 : VCF::Label, 'ED88C09F-26AB-11d4-B539-00C04F0196DA'
anchor = [AnchorLeft,AnchorRight]
bottom = 100.00000
caption = 'This is a label!'
color.blue = 0.50000
color.green = 1.00000
color.red = 0.00000
height = 45.00000
left = 20.00000
name = 'label1'
textAlignment = taTextLeft
top = 55.00000
verticalAlignment = tvaTextCenter
visible = true
width = 300.00000
wordWrap = false

delegates
end
end

delegates
end

end

This is what we use to load up components dynamically at runtime. So a form can be stored in format, and then loaded at runtime, dynamically no less (!), like so:


Window* window = Frame::createWindow( classid(VisualFormFilesWindow) );


So no one thinks we're using some new fangled version of C++, "classid" is simply a macro that gets the VCF Class instance from a given C++ class type.

When you call Frame::createWindow(), you get a new instance of your window class (called VisualFormFilesWindow), with all the controls and components as you've defined them in your VFF file! Voila!

There's more information on the VFF format here:
Visual Form File format

Something to note - in the latest version, we now support collection properties that can be specified via the RTTI macros, and can also be modified via the VFF format, for example:

object myObj : MyObjectWithItems
items[0] = 10
items[1] = 123
end