#ifndef _plugin_H_ #define _plugin_H_ #include #include #include #include #include #include #include #include #include namespace sc { template class plugin { public: static void scan_plugins(const std::string& dir, const std::string& ext) { DIR* plugins_dir = opendir(dir.c_str()); throw_if_null_msg(plugins_dir, (dir + " could not be opened").c_str()); struct dirent* info; while ((info = readdir(plugins_dir)) != nullptr) { if (info->d_name[0] != '.') { std::string plugname {info->d_name}; std::string::size_type lastdot = plugname.rfind("."); if (plugname.substr(lastdot + 1) == ext) { plugin plugin {dir + '/' + plugname}; plugin.name(plugname.substr(0, lastdot)); plugins.emplace(plugin.name(), std::move(plugin)); } } } throw_if_min1(closedir(plugins_dir)); } using processor = std::function; static void foreach(processor proc) { for (const auto& elem : plugins) { proc(elem.second); } } static plugin& get(const std::string& name) { return plugins.at(name); } static std::vector names() { std::vector result; for (const auto& elem : plugins) { result.emplace_back(elem.first); } return result; } static size_t count() { return plugins.size(); } static const std::map>& all() { return plugins; } plugin(const std::string& path) : _path {path} { _plugin = dlopen(path.c_str(), RTLD_LAZY); const char* err {dlerror()}; if (err) std::cerr << err << '\n'; if (_plugin) { _factory = reinterpret_cast(dlsym(_plugin, "create_instance")); if (!_factory) { std::cerr << "create_instance() function not found in " << path << '\n'; } } } ~plugin() { if (_plugin) { dlclose(_plugin); _plugin = nullptr; } } plugin(const plugin&) = delete; plugin& operator=(const plugin&) = delete; plugin(plugin&& other) { _path = other._path; _plugin = other._plugin; _factory = other._factory; other._plugin = nullptr; } plugin& operator=(plugin&& other) { if (this != &other) { _path = other._path; _plugin = other._plugin; _factory = other._factory; other._plugin = nullptr; } return *this; } const std::string& path() const { return _path; } const std::string& name() const { return _name; } void name(const std::string& nm) { _name = nm; } std::unique_ptr operator()() const { std::unique_ptr obj; if (_factory) { obj.reset(_factory()); } return obj; } private: static std::map> plugins; std::string _path; std::string _name; void* _plugin {nullptr}; using factory = T*(*)(); factory _factory {nullptr}; }; template std::map> plugin::plugins; } #endif // _plugin_H_