vendredi 28 novembre 2014

Abusing static initialization

What we'll be seeing today is a way to (ab)use static initialization to register some classes.

That might come useful when implementing a RTTI (runtime type information) system or when adding scripting capabilities to a framework.

Static initialization


What's static initialization ? Well, basically, when you start a C++ program, main() is not the first thing to happen.

Just before that, a portion of the memory is allocated, which is to contain all the variables that are declared static in your code. Then this memory portion is filled with zeroes, and lastly all the variables declared as static are initialized in there, in a somewhat shady fashion : In a single compilation unit (each .o or .obj file your compiler generates is a compilation unit, so that's more or less be related to a single .cpp file, including all the headers it includes), static variables are initialized in declaration order, but the processing order of the compilation units is undefined.

This means two things :

  • Because of the initialization order, you can't really count on other static variables, or actually on any other variable at all, because main() hasn't started. There is one exception, though : when declaring a static variable inside a function, this variable is initialized on the first call to this function. That will come in useful later.
  • Because the memory is zero-filled before static initialization, you are guaranteed that every single pointer you declare as static will point to NULL when static initialization starts. That could be useful when dealing with linked lists, for example.

Abusing static initialization


The fun thing with static initialization is that you could execute pretty much everything before main happens, even a whole game if you wanted to - though debugging might become a nightmare then.

But let's say we want to add scripting capabilities to our game engine. Let's say we want to be able to declare a class as accessible in the script API and just like that it's useable in, for example, Lua.

I've decided that having to call a function to register the Lua API for every single class in my engine is not only way too verbose for my taste, but also error-prone : if I ever dare to forget this call, the class does not show up in the Lua API, and I'm in for a few tens minutes of debugging, then for a facepalm.

So, basically, using polymorphism to mark a class as available in the script API could be a good start :

class Scriptable {};
class Clock : public Scriptable { /* ... */ };

This doesn't do anything, though. What we want is to call a function that would expose the class' API to Lua :

class Clock : public Scriptable
{
/* ... */
static void ExposeAPI(lua_State* L)
{
    /* Use Lua C API, LuaBridge, Selene... to expose class API */
}
/* ... */
};

We now have the function we want to call on startup, but it's not called yet.

With a bit of help from templates, we will create a class that will act as a proxy. We'll then be able to declare a static instance of this proxy, which will be created at static initialization - and this will call our function automagically ! Let's review some more code :

template<class T> class Scriptable
{
protected:
    struct Proxy
    {
        Proxy() { T::ExposeAPI( /* what to put here ? */ ); }
    };
    static Proxy proxy_;
}
template<class T> typename Scriptable<T>::Proxy Scriptable<T>::proxy_;

Notice the last line. the static Proxy instance is declared inside the class, but we still have to define it - that's what this line does.
Also notice the use of the typename keyword. Because the real type of the Proxy struct depends on the type of T, it is called a dependent type. We need to clarify this for the C++ compiler, thus the keyword.

Now Scriptable is a template class, Clock will need to see its header modified just a bit :

class Clock : public Scriptable<Clock>


This way, we'll have a static Scriptable<Clock>::Proxy instance, that will call Clock::ExposeAPI when initialized at static initialization.

But there's a catch. We need a Lua state to be initialized when exposing a class, and we know that static initialization happens in a somewhat hectic order. How then ? Well, we'll use the fact that static variables in a function are initialized at the function's first call to make a singleton that will initialize our Lua state right when we need it. Let's go !


class Environment
{
    public:
        ~Environment()
        {
            lua_close(L_);
        }

        static Environment& Get()
        {
            static Environment inst;
            return inst;
        }

        lua_State* State() { return L_; }

    private:
        Environment()
        {
            L_ = luaL_newstate();
            luaL_openlibs(L_);
        }

    lua_State* L_;
};


So what happens there ? When we first call Get(), the Environment instance is created, effectively creating and initializing the lua_State - exactly what we wanted.

Let's modify our Scriptable class once again to pass the lua_State to the ExposeAPI calls :

template<typename T> class Scriptable
{
protected:
    struct Proxy
    {
        Proxy() { T::ExposeAPI(Environment::Get().State()); }
    };
    static Proxy proxy_;
}

Now the only thing left is to fill the Clock::ExposeAPI function to expose the Clock API to Lua.

Conclusion


We've used static initialization in such a manner that when the execution of main() begins, your Lua state is already initialized and all the scripting API exposed to Lua. Be warned, though, that doing this could have some unwanted side-effects, in which case, you'd have to resort to more standard manners.

A complete documentation on static initialization is quite hard to find on the internet, and I had to find my way through bits of forum posts and a lot of trial and error to get the wanted result. I hope this article will help document this interesting part of a program's execution :)

You could use this method for anything : exposing a scripting API is an example, declaring metatypes for your classes is another.

The method described here happens to have an interesting compile-time side-effect : if you declare a class as scriptable but forget to create the ExposeAPI static class method, Scriptable<T>::Proxy's constructor will try to call T::ExposeAPI which, of course, doesn't exist, and compilation will fail telling you exactly what's the problem - a rare case when dealing with templates !

jeudi 20 novembre 2014

Signal / slots implementation using C++11 variadic templates

Hello and welcome on this blog :)

You'll be able to follow the development of my various projects related to computer graphics as well as occasional ramblings about quantum physics. So let's get started straight away :)

One of my projects is a 3D graphics engine oriented towards non-interactive realtime animations - demos. For more informations about that, just google Demoscene, or go to pouet.net or demozoo.org.

Introduction


DemoKit uses C++11 extensively, and the feature I'll be talking about in this post is called "variadic templates".

In C++, you can use templates to abstract a type when writing a class. You might already be familiar with these because that's the way the STL container works. Let's take an example :

template<typename T>
class Foo
{
public:
    Foo(const T& t) : t_(t) {}
    T GetT() const { return t_; }

private:
    T t_;
};

Here, the Foo class is a very simple container that can be of any type. For instance,

Foo<int> f(42);

is an instance of the Foo class using int as its template parameter, meaning that everytime the type T is seen in Foo, it is replaced with int.

This also means that Foo<int> is not the same class as Foo<float>, because the template parameter alters the implementation of the class itself.
I won't get into details about template classes as it's outside the scope of this article, but just note that it also is possible to specify different implementations of a template class depending on the template parameter - it's called explicit template specialization.


Now, you might also be familiar with the concept of variadic functions, which allows you to pass as many arguments as you want to to a function. printf is an example.

Signals and slots


Those of you that have used Qt should know their system of signals/slots.
A signal is a fake function for which you do not define a body. Instead, you plug one or more slots to it, so that when you do call the signal (this is also called emitting the signal), what you actually do is call the slots that have been connected before.
What's even more interesting is that the slot does not have to be a static function - it can also be an object's member function.

Qt imposes the usage of their moc - meta-object compiler - to use these, though, and C++11 enables a very simple way to implement signals/slots - variadic templates.

Variadic templates


C++11 introduces a feature that kind of mixes variadic functions with templates - somewhat logically, it's called variadic templates. The principle is to allow someone to pass an indefinite number of template arguments. For example, Foo<int> and Foo<bool, float, std::string> could both be legal using variadic templates.

We can easily implement a simple signal using those variadic templates :

template<typename... Args> class Signal
{
public:
    typedef void(*FunctionPointer)(Args...);

    Signal() {}

    void Connect(FunctionPointer fptr)
    {
        ptrs_.push_back(fptr);
    }

    void emit(Args... args)
    {
        for(FunctionPointer& fp : ptrs_)
            fp(args...);
    }

    void operator()(Args... args)
    {
        emit(args...);
    }

private:
    std::vector<FunctionPointer> ptrs_;
};


A few words on this before moving on. What we are passing as template parameter is the list of arguments that will be passed to the function pointer. Also, I'm using a simple function pointer here... More on that later.

Now you could do this :

void Foo(int x, float y) { /* ... */ }
void Bar(int x, float y) { /* ... */ }


int main(int argc, char** argv)
{
    Signal<int, float> s;
    s.Connect(Foo);    s.Connect(Bar);
    s(42, 13.37f); // Calls both Foo(42, 13.37f) and Bar(42, 13.37f)
    s.emit(42, 13.37f); // Does the same
}

Of course this example isn't quite useful but it does illustrate the point. Trying to pass to s a function that does not take int and float, in that order, as arguments would result in a compile error.

STL function objects


There still is room for improvement, though. We'd need to be able to use anonymous functions, as well as connect member methods. Let's rewrite that class !

template<typename... Args> class Signal
{
public:
    Signal() {}

    void Connect(std::function<Foo(Args...)> fptr)
    {
        ptrs_.push_back(fptr);
    }

    void operator()(Args... args)
    {
        for(std::function<Foo(Args...)>& fp : ptrs_)
            fp(args);
    }

private:
    std::vector< std::function<Foo(Args...)> > ptrs_;
};


Now using an anonymous function would work too :

int main(int argc, char** argv)
{
    Signal<int, float> s;
    s.Connect([](int i, float f) {
        /* ... */
    });
    s(42, 13.37f);
}

We still have a last challenge to work out. Now we want to be able to call a member method on a class instance. To do that, we'll need some kind of proxy that will pass back the this parameter, effectively making it possible to call a member method :

template<class O, typename R, typename ... A>
std;;function<R(A...)> Bind(O* o, R(O::*f)(A...))
{
    return [=](A... args) { return (o->*f)(args...); };
}

Let's analyze this obscure piece of code =)
This is a function that, given :
  • an object instance of type O*,
  • a pointer to a member function that takes A as parameters and returns R
returns a function object calling the member function on the object O. But let's take an example :

class Foo
{
public:
    Foo() {}
    void BarMethod(int i, float f) { /* ... */ }
};

Foo* f = new Foo();
Signal<int, float> s;
s.Connect(Bind(f, &Foo::BarMethod));

s(42, 13.37f); // Calls f->BarMethod(42, 13.37f);

Conclusion


We have been able to construct a Signal class which is able to store connections to either anonymous functions, static functions and, with the help of the Bind function, to any member function. The slot definition is here implicit, any function or method can be a slot.

You might have noticed that there's no definition for a Signal with no argument. You'd need to use explicit template specialization to define a Signal<void> ; this is left as an exercise to the reader.

I hope this article isn't too dull to read - next stop is a policy-based variant type. :)