mirror of
https://github.com/matrix-construct/construct
synced 2024-11-29 10:12:39 +01:00
ircd:Ⓜ️🪝 Simplify collections with instance_lists.
This commit is contained in:
parent
671622d778
commit
4c71ab8fd0
3 changed files with 74 additions and 134 deletions
|
@ -17,21 +17,21 @@ namespace ircd::m
|
|||
}
|
||||
|
||||
struct ircd::m::hook
|
||||
:instance_list<hook>
|
||||
{
|
||||
struct site;
|
||||
struct list;
|
||||
|
||||
IRCD_EXCEPTION(ircd::error, error)
|
||||
|
||||
struct list static list;
|
||||
|
||||
json::strung _feature;
|
||||
json::object feature;
|
||||
m::event matching;
|
||||
std::function<void (const m::event &)> function;
|
||||
bool registered;
|
||||
bool registered {false};
|
||||
|
||||
string_view site_name() const;
|
||||
site *find_site() const;
|
||||
|
||||
bool match(const m::event &) const;
|
||||
|
||||
public:
|
||||
|
@ -43,7 +43,7 @@ struct ircd::m::hook
|
|||
};
|
||||
|
||||
/// The hook::site is the call-site for a hook. Each hook site is named
|
||||
/// and registers itself with the master extern hook::list. Each hook
|
||||
/// and registers itself with the master extern hook::site::list. Each hook
|
||||
/// then registers itself with a hook::site. The site contains internal
|
||||
/// state to manage the efficient calling of the participating hooks.
|
||||
///
|
||||
|
@ -51,10 +51,10 @@ struct ircd::m::hook
|
|||
/// in a module which is reloaded) while being agnostic to the hooks it
|
||||
/// cooperates with.
|
||||
struct ircd::m::hook::site
|
||||
:instance_list<site>
|
||||
{
|
||||
json::strung _feature;
|
||||
json::object feature;
|
||||
bool registered;
|
||||
size_t count {0};
|
||||
|
||||
string_view name() const;
|
||||
|
@ -80,25 +80,3 @@ struct ircd::m::hook::site
|
|||
site(const site &) = delete;
|
||||
~site() noexcept;
|
||||
};
|
||||
|
||||
/// The hook list is the registry of all of the hook sites. This is a singleton
|
||||
/// class with an extern instance. Each hook::site will register itself here
|
||||
/// by human readable name.
|
||||
struct ircd::m::hook::list
|
||||
{
|
||||
std::map<string_view, hook::site *> sites;
|
||||
std::set<hook *> hooks;
|
||||
|
||||
friend class site;
|
||||
bool add(site &);
|
||||
bool del(site &);
|
||||
|
||||
friend class hook;
|
||||
bool add(hook &);
|
||||
bool del(hook &);
|
||||
|
||||
public:
|
||||
list() = default;
|
||||
list(list &&) = delete;
|
||||
list(const list &) = delete;
|
||||
};
|
||||
|
|
165
ircd/m/m.cc
165
ircd/m/m.cc
|
@ -2609,6 +2609,12 @@ ircd::m::txn::create_id(const mutable_buffer &out,
|
|||
// m/hook.h
|
||||
//
|
||||
|
||||
/// Instance list linkage for all hooks
|
||||
template<>
|
||||
decltype(ircd::util::instance_list<ircd::m::hook>::list)
|
||||
ircd::util::instance_list<ircd::m::hook>::list
|
||||
{};
|
||||
|
||||
/// Alternative hook ctor simply allowing the the function argument
|
||||
/// first and description after.
|
||||
ircd::m::hook::hook(decltype(function) function,
|
||||
|
@ -2699,23 +2705,49 @@ try
|
|||
{
|
||||
std::move(function)
|
||||
}
|
||||
,registered
|
||||
{
|
||||
list.add(*this)
|
||||
}
|
||||
{
|
||||
site *site;
|
||||
if((site = find_site()))
|
||||
site->add(*this);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
if(registered)
|
||||
list.del(*this);
|
||||
{
|
||||
auto *const site(find_site());
|
||||
assert(site != nullptr);
|
||||
site->del(*this);
|
||||
}
|
||||
}
|
||||
|
||||
ircd::m::hook::~hook()
|
||||
noexcept
|
||||
{
|
||||
if(registered)
|
||||
list.del(*this);
|
||||
{
|
||||
auto *const site(find_site());
|
||||
assert(site != nullptr);
|
||||
site->del(*this);
|
||||
}
|
||||
}
|
||||
|
||||
ircd::m::hook::site *
|
||||
ircd::m::hook::find_site()
|
||||
const
|
||||
{
|
||||
const auto &site_name
|
||||
{
|
||||
this->site_name()
|
||||
};
|
||||
|
||||
if(!site_name)
|
||||
return nullptr;
|
||||
|
||||
for(auto *const &site : m::hook::site::list)
|
||||
if(site->name() == site_name)
|
||||
return site;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ircd::string_view
|
||||
|
@ -2773,8 +2805,13 @@ const
|
|||
// hook::site
|
||||
//
|
||||
|
||||
/// Instance list linkage for all hook sites
|
||||
template<>
|
||||
decltype(ircd::util::instance_list<ircd::m::hook::site>::list)
|
||||
ircd::util::instance_list<ircd::m::hook::site>::list
|
||||
{};
|
||||
|
||||
ircd::m::hook::site::site(const json::members &members)
|
||||
try
|
||||
:_feature
|
||||
{
|
||||
members
|
||||
|
@ -2783,28 +2820,28 @@ try
|
|||
{
|
||||
_feature
|
||||
}
|
||||
,registered
|
||||
{
|
||||
list.add(*this)
|
||||
}
|
||||
{
|
||||
for(const auto &site : list)
|
||||
if(site->name() == name() && site != this)
|
||||
throw error
|
||||
{
|
||||
"Hook site '%s' already registered at %p",
|
||||
name(),
|
||||
site
|
||||
};
|
||||
|
||||
// Find and register all of the orphan hooks which were constructed before
|
||||
// this site was constructed.
|
||||
for(auto *const &hook : list.hooks)
|
||||
for(auto *const &hook : m::hook::list)
|
||||
if(hook->site_name() == name())
|
||||
add(*hook);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
if(registered)
|
||||
list.del(*this);
|
||||
}
|
||||
|
||||
ircd::m::hook::site::~site()
|
||||
noexcept
|
||||
{
|
||||
if(registered)
|
||||
list.del(*this);
|
||||
for(auto *const hook : hooks)
|
||||
del(*hook);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2869,6 +2906,9 @@ catch(const std::exception &e)
|
|||
bool
|
||||
ircd::m::hook::site::add(hook &hook)
|
||||
{
|
||||
assert(!hook.registered);
|
||||
assert(hook.site_name() == name());
|
||||
|
||||
if(!hooks.emplace(&hook).second)
|
||||
{
|
||||
log::warning
|
||||
|
@ -2895,12 +2935,16 @@ ircd::m::hook::site::add(hook &hook)
|
|||
type.emplace(at<"type"_>(hook.matching), &hook);
|
||||
|
||||
++count;
|
||||
hook.registered = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::hook::site::del(hook &hook)
|
||||
{
|
||||
assert(hook.registered);
|
||||
assert(hook.site_name() == name());
|
||||
|
||||
const auto unmap{[&hook]
|
||||
(auto &map, const string_view &key)
|
||||
{
|
||||
|
@ -2935,6 +2979,7 @@ ircd::m::hook::site::del(hook &hook)
|
|||
|
||||
assert(erased);
|
||||
--count;
|
||||
hook.registered = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2952,88 +2997,6 @@ catch(const std::out_of_range &e)
|
|||
};
|
||||
}
|
||||
|
||||
//
|
||||
// hook::list
|
||||
//
|
||||
|
||||
decltype(ircd::m::hook::list)
|
||||
ircd::m::hook::list
|
||||
{};
|
||||
|
||||
bool
|
||||
ircd::m::hook::list::del(hook &hook)
|
||||
{
|
||||
const auto erased
|
||||
{
|
||||
hooks.erase(&hook)
|
||||
};
|
||||
assert(erased);
|
||||
|
||||
const auto it
|
||||
{
|
||||
sites.find(hook.site_name())
|
||||
};
|
||||
|
||||
if(it == end(sites))
|
||||
return false;
|
||||
|
||||
auto *const &site(it->second);
|
||||
assert(site != nullptr);
|
||||
return site->del(hook);
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::hook::list::add(hook &hook)
|
||||
{
|
||||
if(!hooks.emplace(&hook).second)
|
||||
log::warning
|
||||
{
|
||||
"Hook %p already registered", &hook
|
||||
};
|
||||
|
||||
const auto it
|
||||
{
|
||||
sites.find(hook.site_name())
|
||||
};
|
||||
|
||||
if(it == end(sites))
|
||||
{
|
||||
log::dwarning
|
||||
{
|
||||
"Hook %p found no site for '%s'", &hook, hook.site_name()
|
||||
};
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
auto *const &site(it->second);
|
||||
assert(site != nullptr);
|
||||
return site->add(hook);
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::hook::list::del(site &site)
|
||||
{
|
||||
return sites.erase(site.name());
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::m::hook::list::add(site &site)
|
||||
{
|
||||
const auto iit
|
||||
{
|
||||
sites.emplace(site.name(), &site)
|
||||
};
|
||||
|
||||
if(unlikely(!iit.second))
|
||||
throw error
|
||||
{
|
||||
"Hook site name '%s' already in use", site.name()
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// m/import.h
|
||||
|
|
|
@ -577,16 +577,15 @@ console_cmd__conf__get(opt &out, const string_view &line)
|
|||
bool
|
||||
console_cmd__hook__list(opt &out, const string_view &line)
|
||||
{
|
||||
for(const auto &p : m::hook::list.sites)
|
||||
for(const auto &site : m::hook::site::list)
|
||||
{
|
||||
const auto &site(*p.second);
|
||||
out << std::setw(24) << std::left << p.first
|
||||
out << std::setw(24) << std::left << site->name()
|
||||
<< std::endl;
|
||||
|
||||
out << string_view{site.feature}
|
||||
out << string_view{site->feature}
|
||||
<< std::endl;
|
||||
|
||||
for(const auto &hookp : site.hooks)
|
||||
for(const auto &hookp : site->hooks)
|
||||
out << (hookp->registered? '+' : '-')
|
||||
<< " " << string_view{hookp->feature}
|
||||
<< std::endl;
|
||||
|
|
Loading…
Reference in a new issue