Logo Search packages:      
Sourcecode: performous version File versions  Download package

plugin.hpp

//  plugin.hpp - C++ plugin framework

//  Copyright Lasse Karkkainen 2007-2008

//  Use, modification, and distribution is subject to the Boost Software
//  License, Version 1.0 or later. (See accompanying file LICENSE_1_0.txt or
//  copy at http://www.boost.org/LICENSE_1_0.txt)

//  See library home page at http://www.boost.org/libs/plugin

#ifndef PLUGIN_HPP_INCLUDED
#define PLUGIN_HPP_INCLUDED

#include <map>
#include <stdexcept>
#include <string>
#include <vector>
#include <set>

#include <iostream>
#include <sstream>
#include <boost/filesystem.hpp>
#include <boost/ptr_container/ptr_vector.hpp>
#include <dlfcn.h>

namespace plugin {
    namespace fs = boost::filesystem;

    class dll {
        void* lib;
      public:
        dll(fs::path const& filename): lib(dlopen(filename.string().c_str(), RTLD_LAZY | RTLD_GLOBAL)) {
            if (!lib) throw std::runtime_error(dlerror());
        }
        ~dll() {
            dlclose(lib);
        }
    };

    class loader {
        boost::ptr_vector<dll> dlls;
        void parse(std::set<fs::path>& paths, char const* var, fs::path const& folder = fs::path()) {
            if (!var) return;
            std::istringstream iss(var);
            std::string elem;
            while (std::getline(iss, elem, ':')) {
                fs::path p = elem;
                if (!folder.empty()) p /= folder;
                if (fs::is_directory(p)) paths.insert(p);
            }
        }
        /** Try to load all libraries in the given folder. **/
        void load(fs::path const& path) {
            for (fs::directory_iterator it(path), end; it != end; ++it) {
                try {
                    dlls.push_back(new dll(*it));
                } catch (std::runtime_error const& e) {
                    std::cerr << e.what() << std::endl;
                }
            }
        }
      public:
        loader(fs::path const& folder) {
            std::set<fs::path> paths;
            parse(paths, std::getenv("PLUGIN_PATH"));
            if (!folder.empty()) {
                parse(paths, std::getenv("LD_LIBRARY_PATH"), folder);
                parse(paths, "/usr/lib:/usr/local/lib", folder);
            }
            for (std::set<fs::path>::const_iterator it = paths.begin(); it != paths.end(); ++it) load(*it);
            if (dlls.empty()) std::cerr << "No plugins found. Try setting PLUGIN_PATH or LD_LIBRARY_PATH." << std::endl;
        }    
    };
    /**
    * @short A polymorphic plugin factory.
    *
    * This class provides facilities for registering implementations of Base
    * and for requesting instances of implementations by their names (of
    * type Key), passing an argument of type Arg to the constructor of the
    * implementation.
    *
    * More generically, a Base* is returned using a handler previously
    * registered with a specific Key, calling handler's operator()(Arg arg).
    *
    * See documentation for usage examples.
    **/
    template <typename Base,
      typename Arg = std::string const&,
      typename Key = std::string>
00090     class registry {
      public:
        typedef Base base_type;
        typedef Arg arg_type;
        typedef Key key_type;
        struct invalid_key_error: public std::logic_error {
            invalid_key_error(std::string const& msg): logic_error(msg) {}
        };
        class handler;
      private:
        typedef std::multimap<Key, handler*> map_t;
        // Important: the map has to be wrapped inside a function instead of it
        // being a static member variable of this class to ensure that it gets
        // initialized when it is used the first time. If it were static member,
        // the initialization (on program startup) might occur too late.
        static map_t& map() {
            static map_t m;
            return m;
        }
      public:
        /** An iterator for browsing the available keys. **/
00111         class iterator:
          public std::iterator<std::bidirectional_iterator_tag, Key>
        {
            typename map_t::const_iterator m_it;
          public:
            iterator(typename map_t::iterator it): m_it(it) {}
            iterator(typename map_t::const_iterator it): m_it(it) {}
            /** Access the key. **/
00119             Key const& operator*() const { return m_it->first; }
            /** Access a member of the key. **/
00121             Key const* operator->() const { return &m_it->first; }
            /**
            * Activate the handler attached to the current key.
            * Normally new's an object passing arg to its constructor.
            **/
00126             Base* operator()(Arg arg) { return (*m_it->second)(arg); }
            bool operator==(iterator const& r) const { return m_it == r.m_it; }
            bool operator!=(iterator const& r) const { return m_it != r.m_it; }
            iterator& operator++() { ++m_it; return *this; }
            iterator& operator--() { --m_it; return *this; }
            iterator operator++(int) { return iterator(m_it++); }
            iterator operator--(int) { return iterator(m_it--); }
        };
        /** Get an iterator to the first key. **/
00135         static iterator begin() { return map().begin(); }
        /** Get the end iterator. **/
00137         static iterator end() { return map().end(); }
        /**
        * Find a specific key.
        * @throw plugin::invalid_key_error if the key is not found
        * @return iterator to the option matching the key
        **/
00143         static iterator find(Key const& key) {
            map_t const& m = map();
            typename map_t::const_iterator it = m.find(key);
            if (it == m.end())
              throw invalid_key_error("plugin::find: Requested key not found");
            return it;
        }
        /** Get the number of options. **/
00151         static typename map_t::size_type size() { return map().size(); }
        /** Test if there are any options. **/
00153         static bool empty() { return map().empty(); }
        /**
        * @short An abstract base for handler classes.
        * Registers itself on construct, unregisters on destruct.
        **/
00158         class handler {
            typename map_t::iterator m_it;
          public:
            handler(Key const& key):
              m_it(map().insert(std::pair<Key, handler*>(key, this)))
            {}
            virtual ~handler() { map().erase(m_it); }
            virtual Base* operator()(Arg) const = 0;
        };
    };
    /**
    * @short A handler that returns new Class(arg).
    * An instance of this class is normally created as a static (file scope)
    * variable so that the constructor gets called on program startup and
    * that the destructor gets called on program exit, or similarly on
    * dynamic library load/unload.
    **/
    template <typename Plugin, typename Class>
00176     struct simple: public Plugin::handler {
        simple(typename Plugin::key_type const& key): Plugin::handler(key) {}
        typename Plugin::base_type* operator()(typename Plugin::arg_type arg) const {
            return new Class(arg);
        }
    };
    template <typename Plugin, typename Class>
    struct type0: public Plugin::handler {
        type0(typename Plugin::key_type const& key): Plugin::handler(key) {}
        typename Plugin::base_type* operator()(typename Plugin::arg_type) const {
            return new Class();
        }
    };
}

#endif


Generated by  Doxygen 1.6.0   Back to index