// 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_H /// Modules system namespace ircd::mods { IRCD_EXCEPTION(ircd::error, error) IRCD_EXCEPTION(error, filesystem_error) IRCD_EXCEPTION(error, invalid_export) IRCD_EXCEPTION(error, expired_symbol) IRCD_EXCEPTION(error, undefined_symbol) struct mod; struct module; struct sym_ptr; template struct import; template struct import_shared; struct paths extern paths; // Platform (.so|.dll) postfixing std::string postfixed(const std::string &name); std::string unpostfixed(const std::string &name); // Section & Symbol utilites std::vector sections(const std::string &fullpath); std::vector symbols(const std::string &fullpath, const std::string §ion); std::vector symbols(const std::string &fullpath); std::unordered_map mangles(const std::vector &); std::unordered_map mangles(const std::string &fullpath, const std::string §ion); std::unordered_map mangles(const std::string &fullpath); // Find module names where symbol resides bool has_symbol(const std::string &name, const std::string &symbol); std::vector find_symbol(const std::string &symbol); // returns dir/name of first dir containing 'name' (and this will be a loadable module) // Unlike libltdl, the reason each individual candidate failed is presented in a vector. std::string search(const std::string &name, std::vector &why); std::string search(const std::string &name); // Potential modules available to load std::forward_list available(); bool available(const std::string &name); bool loaded(const std::string &name); } // Bring struct module into main ircd:: namespace ircd { using mods::module; using mods::import; using mods::import_shared; } struct ircd::mods::paths :std::vector { bool added(const std::string &dir) const; bool del(const std::string &dir); bool add(const std::string &dir, std::nothrow_t); bool add(const std::string &dir); paths(); }; struct ircd::mods::module :std::shared_ptr { const std::string &name() const; const std::string &path() const; const std::string &mangle(const std::string &) const; bool has(const std::string &name) const; template const T *ptr(const std::string &name) const; template T *ptr(const std::string &name); template const T &get(const std::string &name) const; template T &get(const std::string &name); module(std::shared_ptr ptr = {}) :std::shared_ptr{std::move(ptr)} {} module(const std::string &name); ~module() noexcept; }; namespace ircd::mods { template<> const uint8_t *module::ptr(const std::string &name) const; template<> uint8_t *module::ptr(const std::string &name); } template T & ircd::mods::module::get(const std::string &name) { return *ptr(name); } template const T & ircd::mods::module::get(const std::string &name) const { return *ptr(name); } template T * ircd::mods::module::ptr(const std::string &name) { return reinterpret_cast(ptr(name)); } template const T * ircd::mods::module::ptr(const std::string &name) const { return reinterpret_cast(ptr(name)); } /// Representation of a symbol in a loaded library (non-template; low level). /// class ircd::mods::sym_ptr :std::weak_ptr { void *ptr {nullptr}; public: bool operator!() const; operator bool() const; template const T *get() const; template const T *operator->() const; template const T &operator*() const; template auto operator()(args&&... a) const; template T *get(); template T *operator->(); template T &operator*(); sym_ptr() = default; sym_ptr(module, const std::string &symname); sym_ptr(const std::string &modname, const std::string &symname); ~sym_ptr() noexcept; }; template T & ircd::mods::sym_ptr::operator*() { if(unlikely(expired())) throw expired_symbol("The reference to a symbol in another module is no longer valid"); return *get(); } template T * ircd::mods::sym_ptr::operator->() { return get(); } template T * ircd::mods::sym_ptr::get() { return reinterpret_cast(ptr); } template auto ircd::mods::sym_ptr::operator()(args&&... a) const { return (*get())(std::forward(a)...); } template const T & ircd::mods::sym_ptr::operator*() const { if(unlikely(expired())) throw expired_symbol("The const reference to a symbol in another module is no longer valid"); return *get(); } template const T * ircd::mods::sym_ptr::operator->() const { return get(); } template const T * ircd::mods::sym_ptr::get() const { return reinterpret_cast(ptr); } inline ircd::mods::sym_ptr::operator bool() const { return !bool(*this); } inline bool ircd::mods::sym_ptr::operator!() const { return !ptr || expired(); } /// Representation of a symbol in a loaded shared library /// template struct ircd::mods::import :sym_ptr { template auto operator()(args&&... a) const { return sym_ptr::operator()(std::forward(a)...); } const T *operator->() const { return sym_ptr::operator->(); } const T &operator*() const { return sym_ptr::operator*(); } operator const T &() const { return sym_ptr::operator*(); } T *operator->() { return sym_ptr::operator->(); } T &operator*() { return sym_ptr::operator*(); } operator T &() { return sym_ptr::operator*(); } using sym_ptr::sym_ptr; }; /// Convenience for importing an std::shared_ptr from a loaded lib /// template struct ircd::mods::import_shared :import> ,std::shared_ptr { using std::shared_ptr::get; using std::shared_ptr::operator bool; using std::shared_ptr::operator->; using std::shared_ptr::operator*; operator const T &() const { return std::shared_ptr::operator*(); } operator T &() { return std::shared_ptr::operator*(); } import_shared() = default; import_shared(module, const std::string &symname); import_shared(const std::string &modname, const std::string &symname); }; template ircd::mods::import_shared::import_shared(const std::string &modname, const std::string &symname) :import_shared { module(modname), symname } {} template ircd::mods::import_shared::import_shared(module module, const std::string &symname) :import> { module, symname } ,std::shared_ptr { import>::operator*() }{}