From 97e42f75ee594ab224b2425cbceb4163db0cd089 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 31 Mar 2017 23:59:22 +0200 Subject: [PATCH] Commands: code up implementation of CommandInstanceManager interesting new twist: we do not even need to decorate with a running number, since we'll get away with an anonymous command instance, thanks to Command being a smart-handle --- src/proc/control/command-instance-manager.hpp | 2 + src/proc/control/command-registry.hpp | 4 +- src/proc/control/command-setup.cpp | 44 +++++++--- src/proc/control/command.cpp | 4 +- wiki/renderengine.html | 5 +- wiki/thinkPad.ichthyo.mm | 84 +++++++++++++++++-- 6 files changed, 123 insertions(+), 20 deletions(-) diff --git a/src/proc/control/command-instance-manager.hpp b/src/proc/control/command-instance-manager.hpp index f4cb60de5..9ed568f46 100644 --- a/src/proc/control/command-instance-manager.hpp +++ b/src/proc/control/command-instance-manager.hpp @@ -58,6 +58,7 @@ //#include "proc/common.hpp" #include +#include #include @@ -79,6 +80,7 @@ namespace control { : boost::noncopyable { CommandDispatch& dispatcher_; + std::unordered_map table_; public: CommandInstanceManager (CommandDispatch&); diff --git a/src/proc/control/command-registry.hpp b/src/proc/control/command-registry.hpp index f3c51c03e..8b6827f7c 100644 --- a/src/proc/control/command-registry.hpp +++ b/src/proc/control/command-registry.hpp @@ -144,7 +144,9 @@ namespace control { /** register a command (Frontend) under the given ID. - * Any previously existing registration is detached from the index + * @throw error::Logic when a registration already exists, + * either under this ID or for the same concrete implementation + * record but with a different ID. */ void track (Symbol cmdID, Command const& commandHandle) diff --git a/src/proc/control/command-setup.cpp b/src/proc/control/command-setup.cpp index 58d45b91f..170b7e893 100644 --- a/src/proc/control/command-setup.cpp +++ b/src/proc/control/command-setup.cpp @@ -39,9 +39,9 @@ #include "proc/control/command-setup.hpp" #include "proc/control/command-instance-manager.hpp" #include "proc/control/command-def.hpp" -//#include "lib/format-string.hpp" -//#include "lib/util.hpp" - +#include "lib/symbol.hpp" +#include "lib/format-string.hpp" +#include "lib/util.hpp" #include #include @@ -53,9 +53,8 @@ using std::move; using lib::Symbol; using lumiera::LifecycleHook; using lumiera::ON_GLOBAL_INIT; -//using std::string; -//using util::cStr; -//using util::_Fmt; +using std::string; +using util::_Fmt; namespace proc { @@ -157,26 +156,51 @@ namespace control { CommandInstanceManager::CommandInstanceManager (CommandDispatch& dispatcher) : dispatcher_{dispatcher} + , table_{2 * Command::definition_count()} { } - /* more to come here...*/ + /** @todo more to come here...*/ Symbol CommandInstanceManager::newInstance (Symbol prototypeID, string invocationID) { - UNIMPLEMENTED ("CommandInstanceManager::newInstance"); + Symbol instanceID{lib::internedString (string{prototypeID}+"."+invocationID)}; + Command& instance = table_[instanceID]; + if (not instance) + { // create new clone from the prototype + table_[instanceID] = move (Command::get(prototypeID).newInstance()); + ENSURE (instance, "cloning of command prototype failed"); + } + return instanceID; } + + /** */ void CommandInstanceManager::dispatch (Symbol instanceID) { - UNIMPLEMENTED ("CommandInstanceManager::dispatch"); + Command& instance = table_[instanceID]; + if (not instance) + throw error::Logic (_Fmt{"attempt to dispatch command instance '%s' " + "without creating a new instance from prototype beforehand"} + % instanceID + , LUMIERA_ERROR_INVALID_COMMAND); + 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); } + bool CommandInstanceManager::contains (Symbol instanceID) const { - UNIMPLEMENTED ("CommandInstanceManager::contains"); + return util::contains (table_, instanceID); } diff --git a/src/proc/control/command.cpp b/src/proc/control/command.cpp index deae66ec4..3c62d8ea2 100644 --- a/src/proc/control/command.cpp +++ b/src/proc/control/command.cpp @@ -154,7 +154,7 @@ namespace control { /** @internal make a command ready for use. Typically to be invoked * through CommandDef during the definition stage, but also used - * for activating clone instances. + * for activating (anonymous) clone instances. * @param cmdID new ID for creating a separate command registration when provided * @throw error::Logic when \c this is already activated. */ void @@ -191,7 +191,7 @@ namespace control { } - /** create independent clone copy of this command */ + /** create independent (anonymous) clone copy of this command */ Command Command::newInstance () const { diff --git a/wiki/renderengine.html b/wiki/renderengine.html index b3bd967b7..34907b0ea 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -2604,7 +2604,7 @@ This contrastive approach attempts to keep knowledge and definition clustered in → CommandSetup -
+
//the process of issuing a session command from the UI//
 Within the Lumiera UI, we distinguish between core concerns and the //local mechanics of the UI.// The latter is addressed in the usual way, based on a variation of the [[MVC-Pattern|http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller]]. The UI toolkit set, here the GTK, affords ample ways to express actions and reactions within this framework, where widgets in the presentation view are wired with the corresponding controllers vice versa (GTK terms these connections as //"signals"//, we rely on {{{libSigC++}}} for implementation).
 A naive approach would extend these mature mechanisms to also cover the actual functionality of the application. This compelling solution allows quickly to get "something tangible" up and running, yet -- on the long run -- inevitably leads to core concerns being tangled into the presentation layer, which in turn becomes hard to maintain and loaded with "code behind". Since we are here "for the long run", we immediately draw the distinction between UI mechanics and core concerns. The latter are, by decree and axiom, required to perform without even an UI layer running. This decision gives rise to the challenge how to form and integrate the invocation of ''core commands'' into the presentation layer.
@@ -2643,10 +2643,11 @@ from these use cases, we can derive the //crucial activities for command handlin
 * when a command is completely parametrised, it can be invoked. The managing {{{InteractionStateManager}}} knows about this
 * on invocation, the ID of the instance is sent via UI-Bus to the {{{CmdInstanceManager}}}
 * which in turn removes the instance handle from its registration table and hands it over into the ProcDispatcher
+* only the {{{CmdInstanceManager}}} need to know about this actual command instance; there is no global registration
 [<img[Access to Session Commands from UI|uml/Command-ui-access.png]]
 An immediate consequence is that command instances will be formed //per instance// of InteractionStateManager. Each distinct kind of control system has its own instances, which are kept around, until they are ready for invocation. Each invocation "burns" an instance -- on next access, a new instance ID will be allocated, and the next command invocation cycle starts...
 
-Command instances are like prototypes -- thus each additional level of differentiation will create a clone copy and decorate the basic command ID. Yet this extension process is delegated into multiple stages. Already when a specific InvocationTrail is established, the bare command prototype is specialised, and additionally combined with specific context access rules and maybe even a accessor to retrieve some argument value. The {{{CmdInstanceManager}}} internally maintains and tracks a prepared command instance, supplying a distinct instance number to keep concurrently existing instances apart; instances might be around for an extended period, because commands are enqueued with the ProcDispatcher.
+Command instances are like prototypes -- thus each additional level of differentiation will create a clone copy and decorate the basic command ID. Yet this extension process is delegated into multiple stages. Already when a specific InvocationTrail is established, the bare command prototype is specialised, and additionally combined with specific context access rules and maybe even a accessor to retrieve some argument value. The {{{CmdInstanceManager}}} internally maintains and tracks a prepared anonymous command instance within a local registration table. The //smart-handle//-nature of command instance is enough to keep concurrently existing instances apart; instances might be around for an extended period, because commands are enqueued with the ProcDispatcher.
 
 ''command definition'':
 &rarr; Command scripts are defined in translation units in {{{proc/cmd}}}
diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm
index 834e1b898..7921eb924 100644
--- a/wiki/thinkPad.ichthyo.mm
+++ b/wiki/thinkPad.ichthyo.mm
@@ -11706,6 +11706,14 @@
 
 
 
+
+
+
+
+
+
+
+
 
 
 
@@ -11788,6 +11796,23 @@
 
 
 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
 
 
 
@@ -11812,10 +11837,16 @@
 
 
 
-
+
+
+
 
-
-
+
+
+
+
+
+
 
 
 
@@ -11847,6 +11878,25 @@
 
 
 
+
+
+  
+    
+  
+  
+    

+ ...weil es zu jedem InvocationPath +

+

+ zu jeder Zeit nur eine "offene" Instanz gibt. +

+

+ Also genügt es, einen anonymen Klon dieser Instanz zu halten +

+ + +
+
@@ -11923,7 +11973,12 @@
- + + + + + + @@ -12057,7 +12112,8 @@ - + + @@ -12092,11 +12148,29 @@ + + + + + + + + + + + + + + + + + +