/* COMMAND-SIMPLE-CLOSURE.hpp - demo implementation of command closure Copyright (C) Lumiera.org 2016, Hermann Vosseler This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /** @file command-simple-closure.hpp ** Proof-of-concept implementation of CmdClosure. ** This is used for test only, to invoke an arbitrary matching functor with ** arguments stored embedded within this closure. In the real system, a more ** [elaborate version](\ref StorageHolder) of the same concept is used, with ** the additional complication of managing the UNDO operation as well. ** ** \par historical note ** This proof-of-concept variation was split off in an attempt to improve the ** overall design of the command / closure system. The original design had the ** embedded argument holder also implement the CmdClosure interface, which is ** a clever implementation and code-reuse trick, but otherwise caused confusion. ** ** @see Ticket #301 ** @see CommandMutation_test ** @see StorageHolder ** @see OpClosure ** */ #ifndef CONTROL_COMMAND_SIMPLE_CLOSURE_H #define CONTROL_COMMAND_SIMPLE_CLOSURE_H #include "lib/typed-allocation-manager.hpp" #include "proc/control/command-op-closure.hpp" #include "lib/opaque-holder.hpp" #include namespace proc { namespace control { using lib::InPlaceBuffer; using std::string; /** * Dummy / proof-of-concept implementation of CmdClosure. * It is a specifically typed subclass, which serves to hold * storage for the concrete invocation arguments within an * inline buffer. * @note for demonstration and unit testing * @see StorageHolder real world implementation */ template class SimpleClosure : public CmdClosure { using ArgHolder = OpClosure; using ArgumentBuff = InPlaceBuffer; using ArgTuple = typename ArgHolder::ArgTuple; using Args = typename Types::Seq; /* ====== in-place argument storage ====== */ ArgumentBuff arguments_; /* ==== proxied CmdClosure interface ==== */ public: virtual bool isValid () const override { return arguments_->isValid(); } virtual bool isCaptured() const override { return false; } /** assign a new parameter tuple to this */ virtual void bindArguments (Arguments& args) override { storeTuple (args.get()); } /** assign a new set of parameter values to this. * @note the values are passed packaged into a sequence * of GenNode elements. This is the usual way * arguments are passed from the UI-Bus */ virtual void bindArguments (lib::diff::Rec const& paramData) override { storeTuple (buildTuple (paramData)); } virtual void invoke (CmdFunctor const& func) override { if (!isValid()) throw lumiera::error::State ("Lifecycle error: can't bind functor, " "command arguments not yet provided", LUMIERA_ERROR_UNBOUND_ARGUMENTS); arguments_->invoke(func); } virtual operator string() const override { return "Command-Closure{ arguments=" + (arguments_->isValid()? string(*arguments_) : "unbound") + " }" ; } /** per default, all data within StorageHolder * is set up in \em empty state. Later on, the * command arguments are to be provided by #bind , * whereas the undo functions will be wired by #tie */ SimpleClosure () : arguments_() { } explicit SimpleClosure (ArgTuple const& args) : arguments_() { storeTuple (args); } SimpleClosure (SimpleClosure const& oAh) : arguments_() { if (oAh.arguments_->isValid()) // don't clone garbage from invalid arguments arguments_.template create (*oAh.arguments_); } void accept (CommandImplCloneBuilder&) const override { NOTREACHED(); } /** has undo state capturing been invoked? */ bool canUndo () const { return false; } bool empty () const { return !arguments_->isValid(); } /** store a new argument tuple within this StorageHolder, * discarding any previously stored arguments */ void storeTuple (ArgTuple const& argTup) { arguments_.template create (argTup); } bool equals (CmdClosure const& other) const override { const SimpleClosure* toCompare = dynamic_cast (&other); return (toCompare) and (*this == *toCompare); } /// Supporting equality comparisons... friend bool operator== (SimpleClosure const& a1, SimpleClosure const& a2) { return (a1.arguments_->isValid() == a2.arguments_->isValid()) and (*a1.arguments_ == *a2.arguments_) ; } friend bool operator!= (SimpleClosure const& a1, SimpleClosure const& a2) { return not (a1 == a2); } }; }} // namespace proc::control #endif /*CONTROL_COMMAND_SIMPLE_CLOSURE_H*/