From 0bcbf7fee071315d74a204400a436dda32bb0fb1 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 9 Oct 2009 04:32:22 +0200 Subject: [PATCH] fix further problems uncovered by test; allow for anonymous cloning --- src/proc/control/argument-erasure.hpp | 6 ++-- src/proc/control/command-def.hpp | 11 +++--- src/proc/control/command.cpp | 34 ++++++++++++++++--- src/proc/control/command.hpp | 3 +- .../proc/control/command-use1-test.cpp | 14 ++++---- 5 files changed, 48 insertions(+), 20 deletions(-) diff --git a/src/proc/control/argument-erasure.hpp b/src/proc/control/argument-erasure.hpp index fc825024d..c903605c9 100644 --- a/src/proc/control/argument-erasure.hpp +++ b/src/proc/control/argument-erasure.hpp @@ -32,8 +32,7 @@ namespace control { - - + LUMIERA_ERROR_DECLARE (INVALID_ARGUMENTS); ///< Arguments provided for binding doesn't match stored command function parameters @@ -63,7 +62,8 @@ namespace control { { TypedArguments* dest = dynamic_cast*> (this); if (!dest) - throw lumiera::error::Invalid("Wrong type or number of arguments"); + throw lumiera::error::Invalid("Wrong type or number of arguments" + , LUMIERA_ERROR_INVALID_ARGUMENTS); return dest->args_; } diff --git a/src/proc/control/command-def.hpp b/src/proc/control/command-def.hpp index a2d8f95c1..5f4eb19af 100644 --- a/src/proc/control/command-def.hpp +++ b/src/proc/control/command-def.hpp @@ -92,13 +92,13 @@ namespace control { using lumiera::typelist::NullType; using lumiera::typelist::Tuple; - typedef shared_ptr ImplInstance; - typedef function Activation; namespace stage { ///< helpers for building up a command definition + typedef shared_ptr ImplInstance; + typedef function Activation; template @@ -245,6 +245,9 @@ namespace control { Symbol id_; Command prototype_; + typedef stage::ImplInstance PImpl; + typedef stage::Activation Activation; + public: CommandDef (Symbol cmdID) : id_(cmdID) @@ -275,9 +278,9 @@ namespace control { /** callback from completed command definition stage: * "arm up" the command handle object and register it * with the CommandRegistry. */ - Command& activate (ImplInstance const& completedDef) + Command& activate (PImpl const& completedDef) { - prototype_.activate (id_,completedDef); + prototype_.activate (completedDef, id_); ENSURE (prototype_); return prototype_; } diff --git a/src/proc/control/command.cpp b/src/proc/control/command.cpp index 770a37f21..4313ec0c6 100644 --- a/src/proc/control/command.cpp +++ b/src/proc/control/command.cpp @@ -117,10 +117,13 @@ namespace control { } - /** @internal to be invoked through CommandDef to make a command ready for use - * @throw error::Logic when this is already activated. */ + /** @internal make a command ready for use. Typically to be invoked + * through CommandDef during the definition stage, but also used + * for activating clone instances. + * @param cmdID new ID for creating a separate command registration when provided + * @throw error::Logic when \c this is already activated. */ void - Command::activate (Symbol cmdID, shared_ptr const& implFrame) + Command::activate (shared_ptr const& implFrame, Symbol cmdID) { REQUIRE (implFrame); static format fmt("Command \"%s\" already defined"); @@ -129,12 +132,15 @@ namespace control { duplicate_detected (cmdID); _Handle::activate (implFrame); - CommandRegistry::instance().track (cmdID, *this); + if (cmdID) + CommandRegistry::instance().track (cmdID, *this); INFO (command, "Command \"%s\" defined OK", cStr(*this)); } + /** create an independent clone copy of this command + * and register it as new command definition under a different ID */ Command Command::storeDef (Symbol newCmdID) const { @@ -144,12 +150,26 @@ namespace control { duplicate_detected (newCmdID); Command cloneDefinition; - cloneDefinition.activate (newCmdID, registry.createCloneImpl(impl())); + cloneDefinition.activate (registry.createCloneImpl(this->impl()), newCmdID); ENSURE (cloneDefinition); return cloneDefinition; } + /** create independent clone copy of this command */ + Command + Command::newInstance () const + { + CommandRegistry& registry = CommandRegistry::instance(); + shared_ptr cloneImpl = registry.createCloneImpl(this->impl()); + + Command clone; + clone.activate (cloneImpl); + ENSURE (clone); + return clone; + } + + void Command::duplicate_detected (Symbol newCmdID) const { @@ -305,6 +325,10 @@ namespace control { ExecResult Command::exec (HandlingPattern const& execPattern) { + if (!canExec()) + throw error::State ("Lifecycle error: command arguments not bound", + LUMIERA_ERROR_UNBOUND_ARGUMENTS); + CommandImpl& thisCommand (_Handle::impl()); return execPattern.invoke (thisCommand, cStr(*this)); } diff --git a/src/proc/control/command.hpp b/src/proc/control/command.hpp index 56bfc056a..93733baa4 100644 --- a/src/proc/control/command.hpp +++ b/src/proc/control/command.hpp @@ -119,6 +119,7 @@ namespace control { /** create a clone definition */ Command storeDef (Symbol newCmdID) const; + Command newInstance () const; Command() { } ///< undefined command ~Command(); @@ -175,7 +176,7 @@ namespace control { protected: static Command fetchDef (Symbol cmdID); - void activate (Symbol cmdID, shared_ptr const&); + void activate (shared_ptr const&, Symbol cmdID =0); friend class CommandDef; //...invoking those two functions during definition stage diff --git a/tests/components/proc/control/command-use1-test.cpp b/tests/components/proc/control/command-use1-test.cpp index 1bec155a2..09cb23596 100644 --- a/tests/components/proc/control/command-use1-test.cpp +++ b/tests/components/proc/control/command-use1-test.cpp @@ -155,7 +155,7 @@ namespace test { def.operation (command1::operate) .captureUndo (command1::capture); ASSERT (!def); // undo functor still missing - ASSERT (!Command::get("test.command1.2")); + VERIFY_ERROR (INVALID_COMMAND, Command::get("test.command1.2") ); def.operation (command1::operate) .captureUndo (command1::capture) @@ -213,10 +213,10 @@ namespace test { ASSERT (c1.canExec()); ASSERT (!c1.canUndo()); - Command c2 = Command::get("test.command1.3"); - ASSERT (c1); - ASSERT (c1.canExec()); - ASSERT (!c1.canUndo()); + Command c2 = c1.newInstance(); + ASSERT (c2); + ASSERT (c2.canExec()); + ASSERT (!c2.canUndo()); ASSERT (c1 == c2); ASSERT (!isSameObject(c1, c2)); @@ -226,9 +226,9 @@ namespace test { c1(); ASSERT (randVal == command1::check_); - ASSERT (c1.canUndo()); - ASSERT (c1 != c2); + ASSERT ( c1.canUndo()); ASSERT (!c2.canUndo()); + ASSERT (c1 != c2); c2(); ASSERT (randVal + randVal == command1::check_);