263 lines
8.1 KiB
C++
263 lines
8.1 KiB
C++
/*
|
|
COMMAND-STORAGE-HOLDER.hpp - specifically typed container for storage of command arguments
|
|
|
|
Copyright (C) Lumiera.org
|
|
2009, Hermann Vosseler <Ichthyostega@web.de>
|
|
|
|
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-storage-holder.hpp
|
|
** A passive container record holding the actual command arguments & UNDO state.
|
|
** Effectively, this is the top level CmdClosure Implementation, which in turn
|
|
** delegates to sub-closures for the operation arguments and for UNDO management.
|
|
** While all command objects themselves have a common type (type erasure),
|
|
** the actual argument tuple and the state memento for UNDO can't. Especially,
|
|
** the size of arguments and memento will depend on their respective types.
|
|
** Thus, to manage somehow the storage of this data, we create a common holder,
|
|
** which can than be managed by a custom allocator / object pool.
|
|
**
|
|
** @see Command
|
|
** @see CmdClosure storage of command arguments
|
|
** @see MementoTie wiring of UNDO functions & memento
|
|
** @see UndoMutation execution of UNDO
|
|
** @see command-argument-test.cpp
|
|
**
|
|
*/
|
|
|
|
|
|
|
|
#ifndef CONTROL_COMMAND_STORAGE_HOLDER_H
|
|
#define CONTROL_COMMAND_STORAGE_HOLDER_H
|
|
|
|
#include "lib/typed-allocation-manager.hpp"
|
|
#include "steam/control/command-op-closure.hpp"
|
|
#include "steam/control/memento-tie.hpp"
|
|
#include "steam/control/command-impl-clone-builder.hpp"
|
|
#include "lib/opaque-holder.hpp"
|
|
|
|
#include <string>
|
|
|
|
|
|
|
|
namespace steam {
|
|
namespace control {
|
|
|
|
using lib::InPlaceBuffer;
|
|
using std::string;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
* This is "the" top level CmdClosure implementation.
|
|
* It is a specifically typed CmdClosure, which serves for
|
|
* actually allocating storage to hold the command arguments
|
|
* and the UNDO state (memento) for Steam-Layer commands.
|
|
* Both the contained components within StorageHolder
|
|
* can be in \em empty state; there are no distinct
|
|
* lifecycle limitations. StorageHolder is part
|
|
* of Steam-Layer command's implementation
|
|
* and should not be used standalone.
|
|
*/
|
|
template<typename SIG, typename MEM>
|
|
class StorageHolder
|
|
: public CmdClosure
|
|
{
|
|
using ArgHolder = OpClosure<SIG>;
|
|
using MemHolder = MementoTie<SIG,MEM>;
|
|
|
|
using ArgumentBuff = InPlaceBuffer<ArgHolder>;
|
|
using MementoBuff = InPlaceBuffer<MemHolder>;
|
|
|
|
using ArgTuple = typename ArgHolder::ArgTuple;
|
|
using Args = typename lib::meta::RebindTySeq<ArgTuple>::Seq; // std::tuple<ARGS...> to Types<ARGS...>
|
|
|
|
|
|
/* ====== in-place storage buffers ====== */
|
|
|
|
ArgumentBuff arguments_;
|
|
MementoBuff memento_;
|
|
|
|
|
|
|
|
/* ==== proxied CmdClosure interface ==== */
|
|
|
|
public:
|
|
virtual bool
|
|
isValid () const override
|
|
{
|
|
return arguments_->isValid();
|
|
}
|
|
|
|
virtual bool
|
|
isCaptured() const override
|
|
{
|
|
return memento_->isValid();
|
|
}
|
|
|
|
|
|
|
|
/** assign a new parameter tuple to this */
|
|
virtual void
|
|
bindArguments (Arguments& args) override
|
|
{
|
|
storeTuple (args.get<ArgTuple>());
|
|
}
|
|
|
|
/** 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<Args> (paramData));
|
|
}
|
|
|
|
/** discard any argument data and return to _empty_ state */
|
|
virtual void
|
|
unbindArguments() override
|
|
{
|
|
clearStorage();
|
|
}
|
|
|
|
|
|
virtual void
|
|
invoke (CmdFunctor const& func) override
|
|
{
|
|
if (!isValid())
|
|
throw lumiera::error::State ("Lifecycle error: can't bind functor, "
|
|
"command arguments not yet provided",
|
|
LERR_(UNBOUND_ARGUMENTS));
|
|
|
|
arguments_->invoke(func);
|
|
}
|
|
|
|
|
|
virtual
|
|
operator string() const override
|
|
{
|
|
return "Command-State{ arguments="
|
|
+ (arguments_->isValid()? string(*arguments_) : "unbound")
|
|
+ ", "+string(*memento_)+"}"
|
|
;
|
|
}
|
|
|
|
|
|
|
|
/** 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
|
|
*/
|
|
StorageHolder ()
|
|
: arguments_()
|
|
, memento_()
|
|
{ }
|
|
|
|
/** copy construction allowed(but no assignment).
|
|
* @remarks rationale is to support immutable argument values,
|
|
* which means default/copy construction is OK
|
|
*/
|
|
StorageHolder (StorageHolder const& oAh)
|
|
: arguments_()
|
|
, memento_()
|
|
{
|
|
if (oAh.arguments_->isValid()) // don't clone garbage from invalid arguments
|
|
arguments_.template create<ArgHolder> (*oAh.arguments_);
|
|
|
|
// memento can be cloned as-is, irrespective of activation state
|
|
memento_.template create<MemHolder> (*oAh.memento_);
|
|
}
|
|
|
|
|
|
/** copy construction allowed(but no assignment)*/
|
|
StorageHolder& operator= (StorageHolder const&) = delete;
|
|
|
|
|
|
|
|
/** assist with creating a clone copy;
|
|
* this results in invocation of the copy ctor */
|
|
void
|
|
accept (CommandImplCloneBuilder& visitor) const override
|
|
{
|
|
visitor.buildCloneContext (*this);
|
|
}
|
|
|
|
|
|
/** has undo state capturing been invoked? */
|
|
bool canUndo () const { return memento_->isValid(); }
|
|
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<ArgHolder> (argTup);
|
|
}
|
|
|
|
void
|
|
clearStorage ()
|
|
{
|
|
arguments_.template create<ArgHolder>();
|
|
memento_->clear();
|
|
}
|
|
|
|
|
|
typedef typename CommandSignature<SIG,MEM>::OperateSig SIG_op;
|
|
typedef typename CommandSignature<SIG,MEM>::CaptureSig SIG_cap;
|
|
typedef typename CommandSignature<SIG,MEM>::UndoOp_Sig SIG_undo;
|
|
|
|
/** create a new memento storage wiring, discarding existing memento state.
|
|
* @note any bound undo/capture functions based on the previously held MementoTie
|
|
* are silently invalidated; using them will likely cause memory corruption! */
|
|
MementoTie<SIG,MEM>&
|
|
tie (function<SIG_undo> const& undoFunc,
|
|
function<SIG_cap> const& captureFunc)
|
|
{
|
|
return memento_.template create<MemHolder> (undoFunc,captureFunc);
|
|
}
|
|
|
|
/** just re-access an existing memento storage wiring.
|
|
* Used when cloning the closure */
|
|
MementoTie<SIG,MEM>&
|
|
getMementoWiring ()
|
|
{
|
|
return *memento_;
|
|
}
|
|
|
|
|
|
|
|
/** direct "backdoor" access to stored memento value.
|
|
* @throw LUMIERA_ERROR_MISSING_MEMENTO when invoked
|
|
* prior to \c tie(..) and capturing any state */
|
|
MEM&
|
|
memento ()
|
|
{
|
|
return memento_->getState();
|
|
}
|
|
};
|
|
|
|
|
|
|
|
}} // namespace steam::control
|
|
#endif /*CONTROL_COMMAND_STORAGE_HOLDER_H*/
|