#include #include #include #ifndef ctx_HEADER #define ctx_HEADER template class ctx_Controller { std::list > callbacks; std::list > functions; std::queue queue; public: T context; bool isProcessingQueue = false; ctx_Controller(const T &c) { context = c; } void executeFunctions() { auto c = queue.front(); queue.pop(); for (const auto &f : functions) { auto ctx = f(c); if (ctx.recentField != "none") { queue.push(ctx); } } context.recentField = c.recentField; context.setField(c.recentField, c.field(c.recentField)); reportContext(); } void processQueue() { // Decline recursion. if (isProcessingQueue) { return; } isProcessingQueue = true; while (!queue.empty()) { executeFunctions(); } isProcessingQueue = false; } void registerCallback(std::function cb) { callbacks.push_back(cb); } void registerFieldCallback( const std::string &fieldName, std::function cb ) { auto execCB = [fieldName, cb](T c) { if (c.recentField == fieldName) { cb(c); } }; callbacks.push_back(execCB); } void registerFunction(std::function f) { functions.push_back(f); } void registerFunctions(std::list > funcs) { for (const auto &f : funcs) { functions.push_back(f); } } void reportContext() { for (const auto &cb : callbacks) { cb(context); } } template void set( const std::string &fieldName, const U &value ) { auto c = context; c.setField(fieldName, value); c.recentField = fieldName; queue.push(c); processQueue(); } }; #endif // ctx_HEADER