// Matrix Construct // // Copyright (C) Matrix Construct Developers, Authors & Contributors // Copyright (C) 2016-2018 Jason Volk // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. #pragma once #define HAVE_IRCD_MODS_IMPORT_H namespace ircd::mods { template struct import; struct imports extern imports; std::string make_target_name(const string_view &name, const string_view &demangled); } struct ircd::mods::imports :std::map> {}; /// Representation of a symbol in a loaded shared library /// template struct ircd::mods::import :sym_ptr { string_view mangled_type; std::string demangled_type; std::string module_name; std::string symbol_name; std::string target_name; void reload(); public: template decltype(auto) operator()(args&&...) const; template decltype(auto) operator()(args&&...); const T *operator->() const; const T &operator*() const; operator const T &() const; T *operator->(); T &operator*(); operator T &(); explicit import(const mods::module &, std::string symbol_name); import(std::string module_name, std::string symbol_name); }; template ircd::mods::import::import(std::string module_name, std::string symbol_name) :sym_ptr { // Note sym_ptr is purposely default constructed; this makes the import // "lazy" and will be loaded via miss on first use. This is useful in // the general use-case of static construction. } ,mangled_type { typeid(T).name() } ,demangled_type { demangle(mangled_type) } ,module_name { std::move(module_name) } ,symbol_name { std::move(symbol_name) } ,target_name { make_target_name(this->symbol_name, demangled_type) } {} template ircd::mods::import::import(const mods::module &module, std::string symbol_name) :sym_ptr { } ,mangled_type { typeid(T).name() } ,demangled_type { demangle(mangled_type) } ,module_name { module.name() } ,symbol_name { std::move(symbol_name) } ,target_name { make_target_name(this->symbol_name, demangled_type) } { auto &sp { static_cast(*this) }; sp = { module, !empty(target_name)? target_name : this->symbol_name }; } template ircd::mods::import::operator T &() { return this->operator*(); } template T & ircd::mods::import::operator*() { return *this->operator->(); } template T * ircd::mods::import::operator->() { if(unlikely(!*this)) reload(); return sym_ptr::operator->(); } template template inline decltype(auto) ircd::mods::import::operator()(args&&... a) { if(unlikely(!*this)) reload(); return sym_ptr::operator()(std::forward(a)...); } template ircd::mods::import::operator const T &() const { return this->operator*(); } template const T & ircd::mods::import::operator*() const { return this->operator->(); } template const T * ircd::mods::import::operator->() const { return sym_ptr::operator->(); } template template __attribute__((artificial)) inline decltype(auto) ircd::mods::import::operator()(args&&... a) const { return sym_ptr::operator()(std::forward(a)...); } template void ircd::mods::import::reload() try { auto &module { imports.at(module_name) }; auto &sp { static_cast(*this) }; const auto &symname { !empty(target_name)? target_name : symbol_name }; sp = { module, symname }; } catch(const std::out_of_range &e) { throw unavailable { "Sorry, %s in %s is currently unavailable.", symbol_name, module_name }; }