Snap! Websites
An Open Source CMS System in C++
IMPORTANT NOTE
This feature was not implemented. We instead went with the fully dynamic signals using boost::signals2 which allows you to grow plugins without having to recompile everything (and thus offer users a way to install additional plugins by simply installing a package on your Linux system.)
As I have been researching for the fastest signal system, I came up with what follows.
There is one draw back: all the modules must all be statically compiled (i.e. no independent "plug-in" type of functionality. Under Linux, that means no .so and under Windows no .dll)
The C++ language is an object oriented language. When you learn about objects you learn about signals being emitted and received. A class that defines a function named void set_title(const std::string& title) can receive the message set_title.
When you want to set the title of object o, you write:
o->set_title("My Title");
Now, when the user sets the title, we want to emit an event that is captured by other modules. The even tells these other modules that the title changed: title_changed.
This event gives modules a chance to tweak the title to their liking. For example one could add the date the page was published on at the end of the title (2011-09-08).
In this case the page object would implement the title_changed event and do something like this:
void page::title_changed(std::string& title)
{
// TODO: replace time() with actual page creation time
title += strftime(" (Y-m-d)", time());
}
As we can see, the function simply changes the title variable and returns.
So... now, what we'd need in a standard C++ program is this:
void website::set_title(const std::string& title) { std::string t(title); page::instance()->title_changed(t); m_title = t; }
Here we can see that we call the title_changed even of the page. An immediate call is fantastically fast.
But... unfortunately, at the time you are writing the website::set_title() function you have no idea that the page::title_changed() function even exists.
Instead, you create an interface and call the title_changed() on that interface and the page class derives from the interface. Up to here, good...
Now we need to find out which plugin implements the title_changed(). In a static environment, this can be done at compile time by changing the call to the title_changed() with an emit instruction:
emit title_changed(t);
Then create a precompiler that finds all the emit calls and the classes that derive from the corresponding callback. Finally, the precompiler can generate the calls we've just see and for all the modules that re-implement the title_changed event.
Note: to find the callback definitions we can have them all derive from a given class that has a very specific name:
class snap_callbacks { // ... }; class website_callbacks : public snap_callbacks { // ... virtual void title_changed(std::string& title); };
Another way is to create a special header file that has the event listed in a "special" class and the precompiler generates the necessary C++ header and C++ files. However, that seems to generate more problems.
The result is that the emit <something> becomes a long list of direct calls to all the <something> functions defined in your entire environment. For example:
// from emit title_changed(t); page::instance()->title_changed(t); user::instance()->title_changed(t); statistics::instance()->title_changed(t); website::instance()->title_changed(t); layout::instance()->title_changed(t); filter::instance()->title_changed(t); password::instance()->title_changed(t);
This is transformed to roughly 50 lines of assembly code (2 calls with many PUSH/POP of the registers) per call. It is very fast.
Snap! Websites
An Open Source CMS System in C++