DRTVWR-564: WIP: add LLEventPumps::registerPumpFactory()

and registerTypeFactory().

Untested.

This will support registering just-in-time LLEventAPI instances, instantiated
on demand.
master
Nat Goodspeed 2022-06-15 19:43:53 -04:00
parent cdbd06e8ed
commit a4ff9caf69
2 changed files with 76 additions and 7 deletions

View File

@ -68,19 +68,51 @@
LLEventPumps::LLEventPumps():
mFactories
{
{ "LLEventStream", [](const std::string& name, bool tweak)
{ "LLEventStream", [](const std::string& name, bool tweak, const std::string& /*type*/)
{ return new LLEventStream(name, tweak); } },
{ "LLEventMailDrop", [](const std::string& name, bool tweak)
{ "LLEventMailDrop", [](const std::string& name, bool tweak, const std::string& /*type*/)
{ return new LLEventMailDrop(name, tweak); } }
},
mTypes
{
// LLEventStream is the default for obtain(), so even if somebody DOES
// call obtain("placeholder"), this sample entry won't break anything.
{ "placeholder", "LLEventStream" }
// { "placeholder", "LLEventStream" }
}
{}
bool LLEventPumps::registerTypeFactory(const std::string& type, const TypeFactory& factory)
{
auto found = mFactories.find(type);
// can't re-register a TypeFactory for a type name that's already registered
if (found != mFactories.end())
return false;
// doesn't already exist, go ahead and register
mFactories[type] = factory;
return true;
}
bool LLEventPumps::registerPumpFactory(const std::string& name, const PumpFactory& factory)
{
// Do we already have a pump by this name?
if (mPumpMap.find(name) != mPumpMap.end())
return false;
// Do we already have an override for this pump name?
if (mTypes.find(name) != mTypes.end())
return false;
// Leverage the two-level lookup implemented by mTypes (pump name -> type
// name) and mFactories (type name -> factory). We could instead create a
// whole separate (pump name -> factory) map, and look in both; or we
// could change mTypes to (pump name -> factory) and, for typical type-
// based lookups, use a "factory" that looks up the real factory in
// mFactories. But this works, and we don't expect many calls to make() -
// either explicit or implicit via obtain().
// Create a bogus type name extremely unlikely to collide with an actual type.
static std::string nul(1, '\0');
std::string type_name{ nul + name };
mTypes[name] = type_name;
mFactories[type_name] = factory;
return true;
}
LLEventPump& LLEventPumps::obtain(const std::string& name)
{
PumpMap::iterator found = mPumpMap.find(name);
@ -114,7 +146,7 @@ LLEventPump& LLEventPumps::make(const std::string& name, bool tweak,
// Passing an unrecognized type name is a no-no
LLTHROW(BadType(type));
}
auto newInstance = (found->second)(name, tweak);
auto newInstance = (found->second)(name, tweak, type);
// LLEventPump's constructor implicitly registers each new instance in
// mPumpMap. But remember that we instantiated it (in mOurPumps) so we'll
// delete it later.

View File

@ -268,6 +268,43 @@ public:
LLEventPump& make(const std::string& name, bool tweak=false,
const std::string& type=std::string());
/// function passed to registerTypeFactory()
typedef std::function<LLEventPump*(const std::string& name, bool tweak, const std::string& type)> TypeFactory;
/**
* Register a TypeFactory for use with make(). When make() is called with
* the specified @a type string, call @a factory(name, tweak, type) to
* instantiate it.
*
* Returns true if successfully registered, false if there already exists
* a TypeFactory for the specified @a type name.
*/
bool registerTypeFactory(const std::string& type, const TypeFactory& factory);
/// function passed to registerPumpFactory()
typedef std::function<LLEventPump*(const std::string&)> PumpFactory;
/**
* Register a PumpFactory for use with obtain(). When obtain() is called
* with the specified @a name string, if an LLEventPump with the specified
* @a name doesn't already exist, call @a factory(name) to instantiate it.
*
* Returns true if successfully registered, false if there already exists
* a factory override for the specified @a name.
*
* PumpFactory does not support @a tweak because it's only called when
* <i>that particular</i> @a name is passed to obtain(). Bear in mind that
* <tt>obtain(name)</tt> might still bypass the caller's PumpFactory for a
* couple different reasons:
*
* * registerPumpFactory() returns false because there's already a factory
* override for the specified @name
* * between a successful <tt>registerPumpFactory(name)</tt> call (returns
* true) and a call to <tt>obtain(name)</tt>, someone explicitly
* instantiated an LLEventPump(name), so obtain(name) returned that.
*/
bool registerPumpFactory(const std::string& name, const PumpFactory& factory);
/**
* Find the named LLEventPump instance. If it exists post the message to it.
* If the pump does not exist, do nothing.
@ -325,7 +362,7 @@ testable:
typedef std::set<LLEventPump*> PumpSet;
PumpSet mOurPumps;
// for make(), map string type name to LLEventPump subclass factory function
typedef std::map<std::string, std::function<LLEventPump*(const std::string&, bool)>> PumpFactories;
typedef std::map<std::string, PumpFactory> PumpFactories;
// Data used by make().
// One might think mFactories and mTypes could reasonably be static. So
// they could -- if not for the fact that make() or obtain() might be