// 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; } 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_name; std::string demangled_name; std::string target_name; std::string module_name; std::string symbol_name; void reload(); public: template decltype(auto) operator()(args&&... a) const; template decltype(auto) operator()(args&&... a); 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_name { typeid(T).name() } ,demangled_name { demangle(mangled_name) } ,target_name{fmt::snstringf { 1024, "%s(%s", symbol_name, split(demangled_name, "(").second }} ,module_name { std::move(module_name) } ,symbol_name { std::move(symbol_name) } {} template ircd::mods::import::import(const mods::module &module, std::string symbol_name) :sym_ptr { module, symbol_name } ,mangled_name { typeid(T).name() } ,demangled_name { demangle(mangled_name) } ,module_name { module.name() } ,symbol_name { std::move(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 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 decltype(auto) ircd::mods::import::operator()(args&&... a) { if(unlikely(!*this)) reload(); using R = decltype(get()(a...)); return sym_ptr::operator()(std::forward(a)...); } template template decltype(auto) ircd::mods::import::operator()(args&&... a) const { using R = decltype(get()(a...)); 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 { ircd::has(symbol_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 }; }