0
0
Fork 0
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:
Jason Volk 2018-05-06 21:53:23 -07:00
parent 671622d778
commit 4c71ab8fd0
3 changed files with 74 additions and 134 deletions

View file

@ -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;
};

View file

@ -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

View file

@ -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;