Commands: change semantics of command instance management (#1089)
in accordance to the design changes concluded yesterday. - in the standard cases we now check the global registry first - automatically create anonymous clone copy from global commands - reorganise code internally to use common tail implementation
This commit is contained in:
parent
079ad715b0
commit
410c36d2c3
7 changed files with 129 additions and 42 deletions
|
|
@ -62,6 +62,7 @@
|
|||
#include "lib/util.hpp"
|
||||
|
||||
#include <deque>
|
||||
#include <utility>
|
||||
|
||||
|
||||
namespace lib {
|
||||
|
|
@ -131,9 +132,9 @@ namespace lib {
|
|||
}
|
||||
|
||||
IterStack&
|
||||
push (TY&& movedElm)
|
||||
push (TY&& elm)
|
||||
{
|
||||
this->stateCore().emplace_back (movedElm);
|
||||
this->stateCore().emplace_back (std::move (elm));
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
@ -185,9 +186,9 @@ namespace lib {
|
|||
}
|
||||
|
||||
IterQueue&
|
||||
feed (TY&& movedElm)
|
||||
feed (TY&& elm)
|
||||
{
|
||||
this->stateCore().emplace_front (movedElm);
|
||||
this->stateCore().emplace_front (std::move (elm));
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -112,6 +112,10 @@ namespace control {
|
|||
void bindAndDispatch (Symbol instanceID, Rec const& argSeq);
|
||||
|
||||
bool contains (Symbol instanceID) const;
|
||||
|
||||
private:
|
||||
Command getCloneOrInstance (Symbol);
|
||||
void handOver (Command&&, Symbol);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -219,36 +219,64 @@ namespace control {
|
|||
}
|
||||
|
||||
|
||||
/** @internal retrieve either global or local command instance
|
||||
* When matching a globally defined command, an anonymous clone instance
|
||||
* will be created. Otherwise a lookup in the local instance table is performed
|
||||
* and a matching entry is _moved out of the table_.
|
||||
*/
|
||||
Command
|
||||
CommandInstanceManager::getCloneOrInstance (Symbol instanceID)
|
||||
{
|
||||
Command instance = Command::maybeGetNewInstance (instanceID);
|
||||
if (not instance)
|
||||
{ // second attempt: search of a locally "opened" instance
|
||||
auto entry = table_.find(instanceID);
|
||||
if (entry == table_.end())
|
||||
throw error::Invalid(_Fmt("Command-ID \"%s\" refers neither to a "
|
||||
"globally registered command definition, "
|
||||
"nor to an previously opened command instance")
|
||||
% instanceID
|
||||
, LUMIERA_ERROR_INVALID_COMMAND);
|
||||
instance = move(entry->second);
|
||||
}
|
||||
ENSURE (instance);
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
/** @internal hand a command over to the dispatcher */
|
||||
void
|
||||
CommandInstanceManager::handOver (Command&& toDispatch, Symbol cmdID)
|
||||
{
|
||||
if (not toDispatch)
|
||||
throw error::Logic (_Fmt{"attempt to dispatch command instance '%s' "
|
||||
"without creating a new instance from prototype beforehand"}
|
||||
% cmdID
|
||||
, error::LUMIERA_ERROR_LIFECYCLE);
|
||||
if (not toDispatch.canExec())
|
||||
throw error::State (_Fmt{"attempt to dispatch command instance '%s' "
|
||||
"without binding all arguments properly beforehand"}
|
||||
% cmdID
|
||||
, LUMIERA_ERROR_UNBOUND_ARGUMENTS);
|
||||
|
||||
REQUIRE (toDispatch and toDispatch.canExec());
|
||||
dispatcher_.enqueue(move (toDispatch));
|
||||
ENSURE (not toDispatch);
|
||||
}
|
||||
|
||||
|
||||
/** hand over the designated command instance to the dispatcher installed
|
||||
* on construction. Either the given ID corresponds to a previously "opened"
|
||||
* local instance (known only to this instance manager). In this case, the
|
||||
* instance will really be _moved_ over into the dispatcher, which also means
|
||||
* this instance is no longer "open" for parametrisation. In the other case
|
||||
* we try to retrieve the given ID from the global CommandRegistry and
|
||||
* dispatch it, _without removing_ it from the global registry of course.
|
||||
* on construction. Either the given ID corresponds to a global command definition,
|
||||
* in which case an anonymous clone copy is created from this command. Alternatively
|
||||
* the given ID matches a previously "opened" local instance (known only to this
|
||||
* instance manager). In this case, the instance will really be _moved_ over into
|
||||
* the dispatcher, which also means this instance is no longer "open" for
|
||||
* parametrisation.
|
||||
*/
|
||||
void
|
||||
CommandInstanceManager::dispatch (Symbol instanceID)
|
||||
{
|
||||
auto entry = table_.find(instanceID);
|
||||
Command fallback;
|
||||
Command& instance{entry == table_.end()? fallback = Command::get(instanceID)
|
||||
: entry->second
|
||||
};
|
||||
if (not instance)
|
||||
throw error::Logic (_Fmt{"attempt to dispatch command instance '%s' "
|
||||
"without creating a new instance from prototype beforehand"}
|
||||
% instanceID
|
||||
, error::LUMIERA_ERROR_LIFECYCLE);
|
||||
if (not instance.canExec())
|
||||
throw error::State (_Fmt{"attempt to dispatch command instance '%s' "
|
||||
"without binding all arguments properly beforehand"}
|
||||
% instanceID
|
||||
, LUMIERA_ERROR_UNBOUND_ARGUMENTS);
|
||||
|
||||
REQUIRE (instance and instance.canExec());
|
||||
dispatcher_.enqueue(move (instance));
|
||||
ENSURE (not instance);
|
||||
handOver (getCloneOrInstance (instanceID), instanceID);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -266,7 +294,11 @@ namespace control {
|
|||
void
|
||||
CommandInstanceManager::bindAndDispatch (Symbol instanceID, Rec const& argSeq)
|
||||
{
|
||||
UNIMPLEMENTED ("fire and forget anonymous instance");
|
||||
Command instance{getCloneOrInstance (instanceID)};
|
||||
REQUIRE (instance);
|
||||
instance.bindArg (argSeq);
|
||||
ENSURE (instance.canExec());
|
||||
handOver (move (instance), instanceID);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -149,6 +149,22 @@ namespace control {
|
|||
}
|
||||
|
||||
|
||||
/** try to access an existing command definition and immediately
|
||||
* create a new clone copy by calling #newInstance()
|
||||
* @return when search for this ID was successful, a new anonymous
|
||||
* command instance based on the same definition, but not registered
|
||||
* in the global CommandRegistry. Otherwise, when search fails,
|
||||
* an empty Command instance (as can be tested with `bool` conversion
|
||||
*/
|
||||
Command
|
||||
Command::maybeGetNewInstance (Symbol cmdID)
|
||||
{
|
||||
Command cmd = CommandRegistry::instance().queryIndex (cmdID);
|
||||
return cmd? cmd.newInstance()
|
||||
: Command{};
|
||||
}
|
||||
|
||||
|
||||
/** @internal just query an existing instance, if any. */
|
||||
Command
|
||||
Command::fetchDef (Symbol cmdID)
|
||||
|
|
|
|||
|
|
@ -118,12 +118,15 @@ namespace control {
|
|||
/* === command registry === */
|
||||
static Command get (Symbol cmdID);
|
||||
static Command get (FuncPtr func);
|
||||
static bool remove (Symbol cmdID);
|
||||
static bool remove (Symbol cmdID);
|
||||
|
||||
/** create a clone definition */
|
||||
Command storeDef (Symbol newCmdID) const;
|
||||
Command newInstance () const;
|
||||
|
||||
static Command maybeGetNewInstance (Symbol cmdID);
|
||||
|
||||
|
||||
Command (Symbol cmdID) { *this = get (cmdID); }
|
||||
Command() { } ///< undefined command
|
||||
~Command();
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ namespace test {
|
|||
void
|
||||
enqueue (Command&& cmd) override
|
||||
{
|
||||
queue_.emplace_front (cmd);
|
||||
queue_.emplace_front (move (cmd));
|
||||
}
|
||||
|
||||
public:
|
||||
|
|
@ -147,7 +147,7 @@ namespace test {
|
|||
int r1{rand()%1000}, r2{rand()%2000};
|
||||
command1::check_ = 0; // commands will add to this on invocation
|
||||
|
||||
iManager.bindAndDispatch (COMMAND_PROTOTYPE, {23});
|
||||
iManager.bindAndDispatch (COMMAND_PROTOTYPE, Rec{r1});
|
||||
CHECK (not iManager.contains (COMMAND_PROTOTYPE));
|
||||
|
||||
Command com{COMMAND_PROTOTYPE};
|
||||
|
|
@ -174,6 +174,7 @@ namespace test {
|
|||
Fixture fixture;
|
||||
CommandInstanceManager iManager{fixture};
|
||||
Symbol instanceID = iManager.newInstance (COMMAND_PROTOTYPE, INVOCATION_ID);
|
||||
CHECK (iManager.contains (instanceID));
|
||||
|
||||
Command cmd = iManager.getInstance (instanceID);
|
||||
CHECK (cmd);
|
||||
|
|
@ -323,7 +324,7 @@ namespace test {
|
|||
VERIFY_ERROR (DUPLICATE_COMMAND, iManager.newInstance (COMMAND_PROTOTYPE, "i1"));
|
||||
VERIFY_ERROR (DUPLICATE_COMMAND, iManager.newInstance (COMMAND_PROTOTYPE, "i2"));
|
||||
|
||||
iManager.bindAndDispatch (i1, Rec{-1}); // bind and dispatch i1, thus i1 is ready for new cycle
|
||||
iManager.bindAndDispatch (i1, {-1}); // bind and dispatch i1, thus i1 is ready for new cycle
|
||||
|
||||
iManager.newInstance (COMMAND_PROTOTYPE, "i1"); // open new cycle for i1
|
||||
VERIFY_ERROR (DUPLICATE_COMMAND, iManager.newInstance (COMMAND_PROTOTYPE, "i2"));
|
||||
|
|
|
|||
|
|
@ -12129,7 +12129,7 @@
|
|||
</node>
|
||||
</node>
|
||||
<node CREATED="1492294356319" ID="ID_1877638479" MODIFIED="1492294363265" TEXT="Semantik-Änderung">
|
||||
<node CREATED="1492294454001" ID="ID_356186975" MODIFIED="1492294483149">
|
||||
<node CREATED="1492294454001" ID="ID_356186975" MODIFIED="1492359481843">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
|
|
@ -12141,6 +12141,7 @@
|
|||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1492295091826" ID="ID_96156600" MODIFIED="1492295093557" TEXT="bisher">
|
||||
<node CREATED="1492295094337" ID="ID_420834348" MODIFIED="1492295103364" TEXT="Instanz nur wenn vorher angelegt"/>
|
||||
<node CREATED="1492295104096" ID="ID_104008616" MODIFIED="1492295116282" TEXT="Sonst wird einfach globales Command genomen"/>
|
||||
|
|
@ -12150,9 +12151,10 @@
|
|||
<node CREATED="1492295137387" ID="ID_1142805823" MODIFIED="1492295146318" TEXT="offene Instanz wird genommen"/>
|
||||
<node CREATED="1492295146794" ID="ID_715268835" MODIFIED="1492295159372" TEXT="Sonst wird anonyme Instanz gebildet"/>
|
||||
<node CREATED="1492295160320" ID="ID_289465814" MODIFIED="1492295164348" TEXT="gebunden und gefeuert"/>
|
||||
<node CREATED="1492350125119" ID="ID_1349289727" MODIFIED="1492350141681" TEXT="Suche zuerst in der globalen Registry"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1492294454001" ID="ID_1498558942" MODIFIED="1492295827074">
|
||||
<node CREATED="1492294454001" ID="ID_1498558942" MODIFIED="1492359486258">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
|
|
@ -12164,9 +12166,10 @@
|
|||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<icon BUILTIN="info"/>
|
||||
<node CREATED="1492295834844" ID="ID_1373400691" MODIFIED="1492295839063" TEXT="Semantik nicht geändert"/>
|
||||
</node>
|
||||
<node CREATED="1492294454001" ID="ID_48228210" MODIFIED="1492295872142">
|
||||
<node CREATED="1492294454001" ID="ID_48228210" MODIFIED="1492359489563">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
|
|
@ -12178,16 +12181,20 @@
|
|||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1492295834844" ID="ID_1465048391" MODIFIED="1492295855364" TEXT="bisher">
|
||||
<node CREATED="1492295891844" ID="ID_219295848" MODIFIED="1492295983675" TEXT="offene Instanz wird zum Dispatcher verschoben"/>
|
||||
<node CREATED="1492295914304" ID="ID_196991118" MODIFIED="1492295939921" TEXT="globales Command wird direkt an den Dispatcher übergeben"/>
|
||||
</node>
|
||||
<node CREATED="1492295855881" ID="ID_1570343929" MODIFIED="1492295857092" TEXT="jetzt">
|
||||
<node CREATED="1492295965170" ID="ID_647547612" MODIFIED="1492350377230" TEXT="globales Command wird geklont"/>
|
||||
<node CREATED="1492295941981" ID="ID_265372200" MODIFIED="1492295962382" TEXT="offene Instanz wird verschoben (unverändert)"/>
|
||||
<node CREATED="1492295965170" ID="ID_647547612" MODIFIED="1492295973020" TEXT="globales Command wird geklont"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1492359501220" ID="ID_1889001956" MODIFIED="1492359517024" TEXT="Test anpassen">
|
||||
<icon BUILTIN="pencil"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1489191252503" ID="ID_1621107057" MODIFIED="1492293466151" TEXT="#1090 Command access for UI-Elements">
|
||||
|
|
@ -12370,8 +12377,8 @@
|
|||
<node CREATED="1492281599624" HGAP="22" ID="ID_1089419591" MODIFIED="1492281870856" TEXT="einfache Lösung" VSHIFT="10">
|
||||
<linktarget COLOR="#5f758e" DESTINATION="ID_1089419591" ENDARROW="Default" ENDINCLINATION="40;300;" ID="Arrow_ID_1986823533" SOURCE="ID_813754826" STARTARROW="None" STARTINCLINATION="1031;0;"/>
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1492281610286" ID="ID_1217333147" MODIFIED="1492281872795" TEXT="automatische Instanz-Erzeugung">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node COLOR="#338800" CREATED="1492281610286" ID="ID_1217333147" MODIFIED="1492359761121" TEXT="automatische Instanz-Erzeugung">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1492281619901" ID="ID_887103826" MODIFIED="1492281874171" TEXT="direkter Aufruf mit CommandDef-ID">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
|
|
@ -13047,7 +13054,9 @@
|
|||
<node CREATED="1492281599624" ID="ID_813754826" MODIFIED="1492281859482" TEXT="einfache Lösung">
|
||||
<arrowlink COLOR="#5f758e" DESTINATION="ID_1089419591" ENDARROW="Default" ENDINCLINATION="40;300;" ID="Arrow_ID_1986823533" STARTARROW="None" STARTINCLINATION="1031;0;"/>
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1492281610286" ID="ID_1542647024" MODIFIED="1492281619169" TEXT="automatische Instanz-Erzeugung"/>
|
||||
<node COLOR="#338800" CREATED="1492281610286" ID="ID_1542647024" MODIFIED="1492359767992" TEXT="automatische Instanz-Erzeugung">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node CREATED="1492281619901" ID="ID_423372741" MODIFIED="1492281631495" TEXT="direkter Aufruf mit CommandDef-ID"/>
|
||||
<node CREATED="1492281659520" ID="ID_1742758477" MODIFIED="1492281669306" TEXT="Argument-Resolver für Kontext-Zugriff"/>
|
||||
<node CREATED="1492281675557" ID="ID_1809773326" MODIFIED="1492281681224" TEXT="InvocationState mit Callbacks"/>
|
||||
|
|
@ -13263,7 +13272,28 @@
|
|||
<node CREATED="1490985748207" ID="ID_1314513556" MODIFIED="1490985751457" TEXT="Instanzbildung">
|
||||
<node CREATED="1490985756381" ID="ID_1346029720" MODIFIED="1490985767448" TEXT="wird durch ID-Dekoration getrieben"/>
|
||||
<node CREATED="1491656301121" ID="ID_566719122" MODIFIED="1491656320281" TEXT="es ist stets nur eine Instanz offen"/>
|
||||
<node CREATED="1491656321252" ID="ID_1903067692" MODIFIED="1491656336277" TEXT="Widersprüche sind Hiweis auf Fehlfunktion"/>
|
||||
<node CREATED="1492359658654" ID="ID_712987844" MODIFIED="1492359667329" TEXT="erfolgt weitgehend automatisch/transparent">
|
||||
<node CREATED="1492359686938" ID="ID_1447317770" MODIFIED="1492359700986" TEXT="anonyme Klon-Kopie von CommandDef">
|
||||
<icon BUILTIN="forward"/>
|
||||
</node>
|
||||
<node CREATED="1492359678835" ID="ID_608610767" MODIFIED="1492359736655" TEXT="explizite Instanzbildung ist optional">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
...implementiert "für die Zukunft",
|
||||
</p>
|
||||
<p>
|
||||
wenn wir context-bound -Commands verwenden
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<icon BUILTIN="info"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1491694174845" ID="ID_344801148" MODIFIED="1491694242610" TEXT="Instanzbildung gehört nicht in das Tangible">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
|
|
|||
Loading…
Reference in a new issue