Program Listing for File factory.hpp

Return to documentation for file (lib/factory/factory.hpp)

// ---------------------------------------------------------------------
// This file is part of falcon-core.
//
// Copyright (C) 2015, 2016, 2017 Neuro-Electronics Research Flanders
//
// Falcon-server is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Falcon-server is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with falcon-core. If not, see <http://www.gnu.org/licenses/>.
// ---------------------------------------------------------------------
#pragma once

#include <map>
#include <vector>
#include <utility>
#include <exception>
#include <iostream>
#include <string>

namespace factory {

// exceptions
class UnknownClass : public std::runtime_error {
 public:
    UnknownClass(std::string const & error) : std::runtime_error(error) {}
};
class DuplicateClass : public std::runtime_error {
 public:
    DuplicateClass(std::string const & error) : std::runtime_error(error) {}
};

template <typename AbstractObject, typename ...Args>
using ObjectCreator = AbstractObject* (*) (Args&& ...);

template <typename AbstractObject,
          typename IdentifierType,
          typename ...Args >
class ObjectFactory {
    typedef ObjectFactory<AbstractObject, IdentifierType, Args...> ThisClass;

 public:
    AbstractObject * create(const IdentifierType & id, Args ...args) {
        typename ObjectMap::const_iterator i = this->objectmap_.find(id);

        if (this->objectmap_.end() != i) {
            return (i->second)(std::forward<Args>(args)...);
        }
        throw UnknownClass("Cannot create object of unregistered class.");
    }

    bool hasClass(const IdentifierType & id) {
        return this->objectmap_.find(id) != this->objectmap_.end();
    }

    bool registerClass(const IdentifierType & id,
                       ObjectCreator<AbstractObject, Args...> creator) {
        if (this->objectmap_.find(id) != this->objectmap_.end()) {
            throw DuplicateClass("Cannot register the same class twice.");
        }
        return this->objectmap_.insert(
                     typename ObjectMap::value_type(id, creator)).second;
    }

    static ThisClass& instance() {
        static ThisClass factory;
        return factory;
    }

    std::vector<IdentifierType> listEntries() const {
        std::vector<IdentifierType> entries;
        for (auto imap : objectmap_) {
            entries.push_back(imap.first);
        }
        return entries;
    }

 private:
    typedef std::map<IdentifierType,
                     ObjectCreator<AbstractObject, Args...>> ObjectMap;
    ObjectMap objectmap_;
};

template <typename Base, typename Derived, typename ...Args>
Base * createInstance(Args&& ...args) {
    return new Derived(std::forward<Args>(args)...);
}

}  // namespace factory