mirror of
https://github.com/matrix-construct/construct
synced 2024-11-25 00:02:34 +01:00
225 lines
3.9 KiB
C++
225 lines
3.9 KiB
C++
// Matrix Construct
|
|
//
|
|
// Copyright (C) Matrix Construct Developers, Authors & Contributors
|
|
// Copyright (C) 2016-2018 Jason Volk <jason@zemos.net>
|
|
//
|
|
// 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<class T> 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<std::string, mods::module, std::less<>>
|
|
{};
|
|
|
|
/// Representation of a symbol in a loaded shared library
|
|
///
|
|
template<class T>
|
|
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<class... args> decltype(auto) operator()(args&&...) const;
|
|
template<class... args> 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<class T>
|
|
ircd::mods::import<T>::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<class T>
|
|
ircd::mods::import<T>::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<sym_ptr &>(*this)
|
|
};
|
|
|
|
sp =
|
|
{
|
|
module, !empty(target_name)? target_name : this->symbol_name
|
|
};
|
|
}
|
|
|
|
template<class T>
|
|
ircd::mods::import<T>::operator
|
|
T &()
|
|
{
|
|
return this->operator*();
|
|
}
|
|
|
|
template<class T>
|
|
T &
|
|
ircd::mods::import<T>::operator*()
|
|
{
|
|
return *this->operator->();
|
|
}
|
|
|
|
template<class T>
|
|
T *
|
|
ircd::mods::import<T>::operator->()
|
|
{
|
|
if(unlikely(!*this))
|
|
reload();
|
|
|
|
return sym_ptr::operator-><T>();
|
|
}
|
|
|
|
template<class T>
|
|
template<class... args>
|
|
inline decltype(auto)
|
|
ircd::mods::import<T>::operator()(args&&... a)
|
|
{
|
|
if(unlikely(!*this))
|
|
reload();
|
|
|
|
return sym_ptr::operator()<T>(std::forward<args>(a)...);
|
|
}
|
|
|
|
template<class T>
|
|
ircd::mods::import<T>::operator
|
|
const T &()
|
|
const
|
|
{
|
|
return this->operator*();
|
|
}
|
|
|
|
template<class T>
|
|
const T &
|
|
ircd::mods::import<T>::operator*()
|
|
const
|
|
{
|
|
return this->operator->();
|
|
}
|
|
|
|
template<class T>
|
|
const T *
|
|
ircd::mods::import<T>::operator->()
|
|
const
|
|
{
|
|
return sym_ptr::operator-><T>();
|
|
}
|
|
|
|
template<class T>
|
|
template<class... args>
|
|
__attribute__((artificial))
|
|
inline decltype(auto)
|
|
ircd::mods::import<T>::operator()(args&&... a)
|
|
const
|
|
{
|
|
return sym_ptr::operator()<T>(std::forward<args>(a)...);
|
|
}
|
|
|
|
template<class T>
|
|
void
|
|
ircd::mods::import<T>::reload()
|
|
try
|
|
{
|
|
auto &module
|
|
{
|
|
imports.at(module_name)
|
|
};
|
|
|
|
auto &sp
|
|
{
|
|
static_cast<sym_ptr &>(*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
|
|
};
|
|
}
|