pluginiter.h File Reference

Simplify 'plugin' classes to be discovered and/or loaded at runtime. More...

#include <openbabel/babelconfig.h>

Include dependency graph for pluginiter.h:

This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Namespaces

namespace  OpenBabel

Classes

class  PluginIter
 Template class used to simplify dynamic classes discovered at runtime. More...

Defines

#define FOR_EACH(plugintype, f)   for(PluginIter<plugintype>& f=plugintype::Iter(); f; ++f )
#define MAKE_PLUGIN(BaseClass)


Detailed Description

Simplify 'plugin' classes to be discovered and/or loaded at runtime.

The code in this file makes it easy to make 'plugin' classes. These classes are derived from an abstract base class, like OBFingerprint. The derived classes ('sub-types' like fingerprint2) usually have a single instance. Plugin classes are only discovered at runtime, so no existing code needs to be changed when adding a new derived class. In some builds the new code can be added or removed by just moving a DLL or so file.

Step-by-Step Instructions

1) In the header file for YourBaseClass. Make sure to include the plugininter.h header and in the definition of YourBaseClass add the MAKE_PLUGIN macro and a pure virtual function Description().

#include <openbabel/plugininter.h>
class YourBaseClass
{
  MAKE_PLUGIN(YourBaseClass)
  virtual string Description()=0;

  ...rest of implementation, probably involving virtual functions redefined
  in the sub-type classes
};
See below for what this macro contains.

2) Declare each sub-type in a class derived from the base class and give it a constructor which calls the base class constructor as shown:

class YourSubType1 : public YourBaseClass
{
public:
  YourSubtype1(string ID, bool IsDefault=false) 
    : YourBaseClass(ID, IsDefault){}

  virtual string Description()
  { return "A short useful description";};

  ...rest ofimplementation
};

3) Declare a global instance of the sub-type class which specifies its ID. and, optionally, whether it is to be regarded as the default type of YourBaseClass.

YourSubType1 theType1("FP2",true);

4) The following functions are available: YourBaseClass* YourBaseClass::FindType(const string& ID); YourBaseClass* YourBaseClass::FindDefaultType();

PluginIter<YourBaseClass>& YourBaseClass::Iter(); This returns an object which looks like a pointer to YourBaseClass when used with * or -> . It initially points to the first sub-type and can be subsequently made to point to all the rest using the prefix ++ operator. When tested as a bool it returns false when there are no more subtypes.

But the easiest way to access all the subtypes is to use the macro FOR_EACH. For example to print out all the subtypes with their descriptions:

FOR_EACH(YourBaseClass, iter)
{
   cout << iter.ID() << ' ' << iter->Description() << endl;
}
Note the . for the ID and the -> for the Description.

How it works

MAKE_PLUGIN(YourBaseClass) inserts the following code into YourBaseClass:

//This static function returns a reference to the PluginIter object,
//which contains the map of sub-types and the default sub-type.
//Because it is a static local variable it is constructed only once.
//This avoids the "static initialization order fiasco",
//see www.parashift.com/c++-faq-lite/.
//Every time this function is used it sets the iterator to the start of the map.
static PluginIter<YourBaseClass>& Iter()
{
  static PluginIter<YourBaseClass>* p = NULL;
  if(!p)
    p = new PluginIter<YourBaseClass>*;
  p->ToStart();
  return *p;
}

Each sub-type is registered from its constructor as it is loaded, which 
could be at program start up, or later.
YourBaseClass(std::string ID, bool IsDefault=false)
{
  Iter().Register(this, ID, IsDefault);
}

//The following just pass on the work to the PluginIter object.
YourBaseClass* FindDefaultType(){ return Iter().FindDefault();}
YourBaseClass* FindType(const string& ID){ return Iter().FindType(const string& ID);}

Define Documentation

#define FOR_EACH ( plugintype,
 )     for(PluginIter<plugintype>& f=plugintype::Iter(); f; ++f )

#define MAKE_PLUGIN ( BaseClass   ) 

Value:

public:\
BaseClass(std::string ID, bool IsDefault=false)\
{Iter().Register(this, ID, IsDefault);}\
static PluginIter<BaseClass>& Iter()\
{static PluginIter<BaseClass>* p = NULL;\
if(!p) p = new PluginIter<BaseClass>;\
p->ToStart();\
return *p;}\
static BaseClass* FindDefaultType(){ return Iter().FindDefaultType();}\
  static BaseClass* FindType(const std::string& ID){ return Iter().FindType(ID);}