/* Title : Actions Author: Edward R. Gonzalez Description: This was a little experiment of mine to mess with action binding... Allows for non-member functions to be binded to an action, implements a functioning queue as well. TODO: Possibly add support for member functions. Have it so that deduction of delegate typef is not required to add to queue properly (right now it does, see input procedure for example); */ #pragma once #include "Cpp_Alias.hpp" namespace Actions { struct IAction { virtual void DoAction() = NULL; }; template struct AAction : IAction { public: using ActionType = function< FunctionType >; AAction(const ActionType& _actionToAssign, const ActionParams&... _params) : action(_actionToAssign), params(_params... ), done (false ) {}; bool Used() { return done; } bool IsSame(const ActionType& _action, const ActionParams&... _paramsForAction) { tuple paramsToCheck(_paramsForAction...); if (params == paramsToCheck && SameAction(_action)) { return true; } else { return false; } } bool SameAction(const ActionType& _action) { if (action.target() == _action.target()) { return true; } else { return false; } } void ReInitalize(const ActionParams&... _params) { params = tuple(_params...); done = false; } protected: virtual void DoAction_Implementation(const ActionParams&... _params) { action(_params...); } template // TuplePackSequence void ExpandTuple_CallDoActionImplementaiton(const tuple& _paramsToExpand, std::index_sequence ) { // ExpandTuplePack DoAction_Implementation(std::get(_paramsToExpand)...); } tuple params; const ActionType& action; bool done; public: // IAction virtual void DoAction() override { ExpandTuple_CallDoActionImplementaiton ( params, // MakeTuplePackSequence () std::index_sequence_for() ); done = true; }; }; // TODO: This doesn't work yet... template class AAction_ObjectBound : public AAction { public: using Base = AAction; using ActionType = function; AAction_ObjectBound(ObjectType& _objectRef, const ActionType& _actionToAssign, const ActionParams&... _params) : AAction::action(_actionToAssign), AAction::params(_params... ), object (_objectRef ) {} bool IsSame(const ObjectType& _object, const ActionType& _action, const ActionParams&... _params) { if (SameObject(_object) && SameAction(_action)) { tuple paramsToCheck(_params...); if (AAction::params == paramsToCheck) { return true; } else { return false; } } } bool SameObject(const ObjectType& _object) { if (Address(object) == Address(_object)) { return true; } else { return false; } } protected: virtual void DoAction_Implementation(const ActionParams&... _params) override { (&object).*AAction::action(_params...); } template // TuplePackSequence void ExpandTuple_CallDoActionImplementaiton(const tuple& _paramsToExpand, std::index_sequence ) { // ExpandTuplePack DoAction_Implementation(std::get(_paramsToExpand)...); } ObjectType& object; public: // IAction virtual void DoAction() override { ExpandTuple_CallDoActionImplementaiton ( AAction::params, // MakeTuplePackSequence () std::index_sequence_for() ); AAction::params::done = true; }; }; struct ActionPool_Dynamic { template using AllocationsOf = std::forward_list; using Managed_AAction = shared_ptr < IAction >; using Managed_AActions = AllocationsOf < Managed_AAction >; using AActions_Registry = std::map ; public: template bool Contains(Entry& _entry) { return _entry != aActions_Available.end() ? true : false; } Managed_AActions& Make_Managed_Actions() { mAAaction_Allocations.push_front(make_shared()); return *(mAAaction_Allocations.front().get()); } template IAction* Request_AAction(const function< FunctionType>& _actionToQueue, const ActionParams&... _paramsForAction) { using ActionType = AAction < FunctionType, ActionParams...>; type_index AActionID = typeid(ActionType); auto possibleEntry = aActions_Available.find(AActionID); if (Contains(possibleEntry)) { using Element = decltype(possibleEntry->second.begin()); for (Element possibleAction = possibleEntry->second.begin(); possibleAction != possibleEntry->second.end(); possibleAction++) { ActionType* castedEntry = static_cast(possibleAction->get()); if (castedEntry->IsSame(_actionToQueue, _paramsForAction...)) { return castedEntry; } else if (castedEntry->Used() && castedEntry->SameAction(_actionToQueue)) { castedEntry->ReInitalize(_paramsForAction...); return castedEntry; } } shared_ptr< IAction> newAction = make_shared< AAction>(_actionToQueue, _paramsForAction...); IAction* returnRef = newAction.get (); aActions_Available.at(AActionID).push_front(newAction); return returnRef; } shared_ptr< IAction> newAction = make_shared< AAction>(_actionToQueue, _paramsForAction...); IAction* returnRef = newAction.get (); aActions_Available.insert(make_pair(AActionID, Make_Managed_Actions())); aActions_Available.at(AActionID).push_front(newAction); return returnRef; } // TODO: Not yet working template IAction* Request_AAction(const ObjectType& _objectRef, const function< FunctionType>& _actionToQueue, const ActionParams&... _paramsForAction) { using ActionType = AAction_ObjectBound; type_index AActionID = typeid(ActionType); auto possibleEntry = aActions_Available.find(AActionID); if (Contains(possibleEntry)) { using Element = decltype(possibleEntry->second.begin()); for (Element possibleAction = possibleEntry->second.begin(); possibleAction != possibleEntry->second.end(); possibleAction++) { ActionType* castedEntry = static_cast(possibleAction->get()); if (castedEntry->IsSame(_objectRef, _actionToQueue, _paramsForAction...)) { return castedEntry; } else if (castedEntry->Used() && castedEntry->SameAction(_actionToQueue) && castedEntry->SameObject(_objectRef)) { castedEntry->ReInitalize(_paramsForAction...); return castedEntry; } } shared_ptr< IAction> newAction = make_shared< AAction_ObjectBound>(_actionToQueue, _paramsForAction...); IAction* returnRef = newAction.get (); aActions_Available.at(AActionID).push_front(newAction); return returnRef; } shared_ptr< IAction> newAction = make_shared< AAction_ObjectBound>(_actionToQueue, _paramsForAction...); IAction* returnRef = newAction.get (); aActions_Available.insert(std::make_pair(AActionID, Make_Managed_Actions())); aActions_Available.at(AActionID).push_front(newAction); return returnRef; } private: AllocationsOf< shared_ptr > mAAaction_Allocations; AActions_Registry aActions_Available; }; ActionPool_Dynamic DefaultActionPool_Dynamic; struct ActionQueue { using QueueType = std::deque< IAction*>; public: template void AddToQueue(const function< FunctionType>& _actionToQueue, const ActionParams&... _paramsForAction) { using GeneratedActionType = AAction; IAction* actionRequested = DefaultActionPool_Dynamic.Request_AAction(_actionToQueue, _paramsForAction...); if (HasAction()) { bool found = false; using Element = decltype(actionQueue.begin()); for (Element element = actionQueue.begin(); element != actionQueue.end(); element++) { if ( (*element) == actionRequested ) { found = true; } } if (not found) { actionQueue.push_front(actionRequested); } } else { actionQueue.push_front(actionRequested); } } template void AddToQueue(const ObjectType& _objectRef, const function< FunctionType>& _actionToQueue, const ActionParams&... _paramsForAction) { using GeneratedActionType = AAction_ObjectBound; IAction* actionRequested = DefaultActionPool_Dynamic.Request_AAction(_objectRef, _actionToQueue, _paramsForAction...); if (HasAction()) { bool found = false; using Element = decltype(actionQueue.begin()); for (Element element = actionQueue.begin(); element != actionQueue.end(); element++) { if ((*element) == actionRequested) { found = true; } } if (not found) { actionQueue.push_front(actionRequested); } } else { actionQueue.push_front(actionRequested); } } void DoNextAction() { if (actionQueue.size() > 0) { actionQueue.back()->DoAction(); actionQueue.pop_back(); } } bool HasAction() { return actionQueue.size() > 0; } private: QueueType actionQueue; }; }