From 2812a8c77a09f18f91a3896f9bb6a6dfdc963e31 Mon Sep 17 00:00:00 2001 From: "Dustin J. Mitchell" Date: Thu, 18 Nov 2021 02:48:14 +0000 Subject: [PATCH] Refactor getDOM to use a pointer for the optional context It's possible to call getDOM without a contextual task. Previously, this was done by referencing a "dummy" task which necessitated a way to distinguish such dummy tasks. This switches to using a pointer and treating the NULL value as meaning there is no context. Note that this cannot use `std::optional<&Task>`, as optional does not support reference types. --- src/DOM.cpp | 114 +++++++++++++++----------------- src/DOM.h | 2 +- src/Filter.cpp | 11 ++- src/columns/ColProject.cpp | 4 +- src/columns/ColRecur.cpp | 4 +- src/columns/ColTags.cpp | 4 +- src/columns/ColTypeDate.cpp | 4 +- src/columns/ColTypeDuration.cpp | 4 +- src/columns/ColTypeNumeric.cpp | 4 +- src/columns/ColTypeString.cpp | 4 +- src/commands/CmdGet.cpp | 3 +- 11 files changed, 76 insertions(+), 82 deletions(-) diff --git a/src/DOM.cpp b/src/DOM.cpp index a22145b29..7db5826e0 100644 --- a/src/DOM.cpp +++ b/src/DOM.cpp @@ -239,24 +239,25 @@ bool getDOM (const std::string& name, Variant& value) // // This code emphasizes speed, hence 'id' and 'urgency' being evaluated first // as special cases. -bool getDOM (const std::string& name, const Task& task, Variant& value) +// +// If task is NULL, then the contextual task will be determined from the DOM +// string, if any exists. +bool getDOM (const std::string& name, const Task* task, Variant& value) { // Special case, blank refs cause problems. if (name == "") return false; - auto have_task = !task.is_empty(); - // Quickly deal with the most common cases. - if (have_task && name == "id") + if (task && name == "id") { - value = Variant (static_cast (task.id)); + value = Variant (static_cast (task->id)); return true; } - if (have_task && name == "urgency") + if (task && name == "urgency") { - value = Variant (task.urgency_c ()); + value = Variant (task->urgency_c ()); return true; } @@ -264,60 +265,55 @@ bool getDOM (const std::string& name, const Task& task, Variant& value) auto elements = split (name, '.'); Task loaded_task; - // Use a lambda to decide whether the reference is going to be the passed + // decide whether the reference is going to be the passed // "task" or whether it's going to be a newly loaded task (if id/uuid was // given). - const Task& ref = [&]() -> const Task& + const Task* ref = task; + Lexer lexer (elements[0]); + std::string token; + Lexer::Type type; + + // If this can be ID/UUID reference (the name contains '.'), + // lex it to figure out. Otherwise don't lex, as lexing can be slow. + if ((elements.size() > 1) and lexer.token (token, type)) { - Lexer lexer (elements[0]); - std::string token; - Lexer::Type type; + bool reloaded = false; - // If this can be ID/UUID reference (the name contains '.'), - // lex it to figure out. Otherwise don't lex, as lexing can be slow. - if ((elements.size() > 1) and lexer.token (token, type)) + if (type == Lexer::Type::uuid && + token.length () == elements[0].length ()) { - bool reloaded = false; - - if (type == Lexer::Type::uuid && - token.length () == elements[0].length ()) + if (!task || token != task->get ("uuid")) { - if (token != task.get ("uuid")) - { - Context::getContext ().tdb2.get (token, loaded_task); + if (Context::getContext ().tdb2.get (token, loaded_task)) reloaded = true; - } - - // Eat elements[0]/UUID. - elements.erase (elements.begin ()); - } - else if (type == Lexer::Type::number && - token.find ('.') == std::string::npos) - { - auto id = strtol (token.c_str (), nullptr, 10); - if (id && id != task.id) - { - Context::getContext ().tdb2.get (id, loaded_task); - reloaded = true; - } - - // Eat elements[0]/ID. - elements.erase (elements.begin ()); } - if (reloaded) - return loaded_task; + // Eat elements[0]/UUID. + elements.erase (elements.begin ()); + } + else if (type == Lexer::Type::number && + token.find ('.') == std::string::npos) + { + auto id = strtol (token.c_str (), nullptr, 10); + if (id && (!task || id != task->id)) + { + if (Context::getContext ().tdb2.get (id, loaded_task)) + reloaded = true; + } + + // Eat elements[0]/ID. + elements.erase (elements.begin ()); } - return task; + if (reloaded) + ref = &loaded_task; + } - } (); // The remainder of this method requires a contextual task, so if we do not // have one, delegate to the two-argument getDOM - if (ref.is_empty ()) { + if (!ref) return getDOM (name, value); - } auto size = elements.size (); @@ -328,13 +324,13 @@ bool getDOM (const std::string& name, const Task& task, Variant& value) // elements vector, DOM resolution is now simple. if (size == 1 && canonical == "id") { - value = Variant (static_cast (ref.id)); + value = Variant (static_cast (ref->id)); return true; } if (size == 1 && canonical == "urgency") { - value = Variant (ref.urgency_c ()); + value = Variant (ref->urgency_c ()); return true; } @@ -342,7 +338,7 @@ bool getDOM (const std::string& name, const Task& task, Variant& value) // implementation. Remove in 3.0.0. if (size == 1 && canonical == "status") { - value = Variant (ref.statusToText (ref.getStatus ())); + value = Variant (ref->statusToText (ref->getStatus ())); return true; } @@ -350,7 +346,7 @@ bool getDOM (const std::string& name, const Task& task, Variant& value) if (size == 1 && column) { - if (column->is_uda () && ! ref.has (canonical)) + if (column->is_uda () && ! ref->has (canonical)) { value = Variant (""); return true; @@ -358,7 +354,7 @@ bool getDOM (const std::string& name, const Task& task, Variant& value) if (column->type () == "date") { - auto numeric = ref.get_date (canonical); + auto numeric = ref->get_date (canonical); if (numeric == 0) value = Variant (""); else @@ -366,32 +362,32 @@ bool getDOM (const std::string& name, const Task& task, Variant& value) } else if (column->type () == "duration" || canonical == "recur") { - auto period = ref.get (canonical); + auto period = ref->get (canonical); Duration iso; std::string::size_type cursor = 0; if (iso.parse (period, cursor)) value = Variant (iso.toTime_t (), Variant::type_duration); else - value = Variant (Duration (ref.get (canonical)).toTime_t (), Variant::type_duration); + value = Variant (Duration (ref->get (canonical)).toTime_t (), Variant::type_duration); } else if (column->type () == "numeric") - value = Variant (ref.get_float (canonical)); + value = Variant (ref->get_float (canonical)); else - value = Variant (ref.get (canonical)); + value = Variant (ref->get (canonical)); return true; } if (size == 2 && canonical == "tags") { - value = Variant (ref.hasTag (elements[1]) ? elements[1] : ""); + value = Variant (ref->hasTag (elements[1]) ? elements[1] : ""); return true; } if (size == 2 && column && column->type () == "date") { - Datetime date (ref.get_date (canonical)); + Datetime date (ref->get_date (canonical)); if (elements[1] == "year") { value = Variant (static_cast (date.year ())); return true; } else if (elements[1] == "month") { value = Variant (static_cast (date.month ())); return true; } else if (elements[1] == "day") { value = Variant (static_cast (date.day ())); return true; } @@ -406,13 +402,13 @@ bool getDOM (const std::string& name, const Task& task, Variant& value) if (size == 2 && elements[0] == "annotations" && elements[1] == "count") { - value = Variant (static_cast (ref.getAnnotationCount ())); + value = Variant (static_cast (ref->getAnnotationCount ())); return true; } if (size == 3 && elements[0] == "annotations") { - auto annos = ref.getAnnotations (); + auto annos = ref->getAnnotations (); int a = strtol (elements[1].c_str (), nullptr, 10); int count = 0; @@ -440,7 +436,7 @@ bool getDOM (const std::string& name, const Task& task, Variant& value) if (size == 4 && elements[0] == "annotations" && elements[2] == "entry") { - auto annos = ref.getAnnotations (); + auto annos = ref->getAnnotations (); int a = strtol (elements[1].c_str (), nullptr, 10); int count = 0; diff --git a/src/DOM.h b/src/DOM.h index dd6e09473..e3595e411 100644 --- a/src/DOM.h +++ b/src/DOM.h @@ -33,7 +33,7 @@ // 2017-04-22 Deprecated, use DOM::get. bool getDOM (const std::string&, Variant&); -bool getDOM (const std::string&, const Task&, Variant&); +bool getDOM (const std::string&, const Task*, Variant&); class DOM { diff --git a/src/Filter.cpp b/src/Filter.cpp index f81d4e895..0f9fcd2e1 100644 --- a/src/Filter.cpp +++ b/src/Filter.cpp @@ -36,9 +36,8 @@ #include //////////////////////////////////////////////////////////////////////////////// -// Const iterator that can be derefenced into a Task by domSource. -static Task dummy; -Task& contextTask = dummy; +// Context for DOM evaluations +const Task* contextTask = NULL; //////////////////////////////////////////////////////////////////////////////// bool domSource (const std::string& identifier, Variant& value) @@ -79,7 +78,7 @@ void Filter::subset (const std::vector & input, std::vector & output for (auto& task : input) { // Set up context for any DOM references. - contextTask = task; + contextTask = &task; Variant var; eval.evaluateCompiledExpression (var); @@ -131,7 +130,7 @@ void Filter::subset (std::vector & output) for (auto& task : pending) { // Set up context for any DOM references. - contextTask = task; + contextTask = &task; Variant var; eval.evaluateCompiledExpression (var); @@ -150,7 +149,7 @@ void Filter::subset (std::vector & output) for (auto& task : completed) { // Set up context for any DOM references. - contextTask = task; + contextTask = &task; Variant var; eval.evaluateCompiledExpression (var); diff --git a/src/columns/ColProject.cpp b/src/columns/ColProject.cpp index 80c10bb70..f414ea3a0 100644 --- a/src/columns/ColProject.cpp +++ b/src/columns/ColProject.cpp @@ -36,7 +36,7 @@ #include #include -extern Task& contextTask; +extern Task* contextTask; //////////////////////////////////////////////////////////////////////////////// ColumnProject::ColumnProject () @@ -121,7 +121,7 @@ void ColumnProject::modify (Task& task, const std::string& value) { Eval e; e.addSource (domSource); - contextTask = task; + contextTask = &task; Variant v; e.evaluateInfixExpression (value, v); diff --git a/src/columns/ColRecur.cpp b/src/columns/ColRecur.cpp index 6bf470647..22623cdce 100644 --- a/src/columns/ColRecur.cpp +++ b/src/columns/ColRecur.cpp @@ -36,7 +36,7 @@ #include #include -extern Task& contextTask; +extern Task* contextTask; //////////////////////////////////////////////////////////////////////////////// ColumnRecur::ColumnRecur () @@ -108,7 +108,7 @@ void ColumnRecur::modify (Task& task, const std::string& value) { Eval e; e.addSource (domSource); - contextTask = task; + contextTask = &task; e.evaluateInfixExpression (value, evaluatedValue); } diff --git a/src/columns/ColTags.cpp b/src/columns/ColTags.cpp index 61303bcb4..16fea0e86 100644 --- a/src/columns/ColTags.cpp +++ b/src/columns/ColTags.cpp @@ -36,7 +36,7 @@ #include #include -extern Task& contextTask; +extern Task* contextTask; //////////////////////////////////////////////////////////////////////////////// ColumnTags::ColumnTags () @@ -162,7 +162,7 @@ void ColumnTags::modify (Task& task, const std::string& value) { Eval e; e.addSource (domSource); - contextTask = task; + contextTask = &task; Variant v; e.evaluateInfixExpression (value, v); diff --git a/src/columns/ColTypeDate.cpp b/src/columns/ColTypeDate.cpp index d92eb3ed8..af8ea1e25 100644 --- a/src/columns/ColTypeDate.cpp +++ b/src/columns/ColTypeDate.cpp @@ -34,7 +34,7 @@ #include #include -extern Task& contextTask; +extern Task* contextTask; //////////////////////////////////////////////////////////////////////////////// ColumnTypeDate::ColumnTypeDate () @@ -213,7 +213,7 @@ void ColumnTypeDate::modify (Task& task, const std::string& value) { Eval e; e.addSource (domSource); - contextTask = task; + contextTask = &task; e.evaluateInfixExpression (value, evaluatedValue); } diff --git a/src/columns/ColTypeDuration.cpp b/src/columns/ColTypeDuration.cpp index 1de5160da..126d7adc9 100644 --- a/src/columns/ColTypeDuration.cpp +++ b/src/columns/ColTypeDuration.cpp @@ -32,7 +32,7 @@ #include #include -extern Task& contextTask; +extern Task* contextTask; //////////////////////////////////////////////////////////////////////////////// ColumnTypeDuration::ColumnTypeDuration () @@ -55,7 +55,7 @@ void ColumnTypeDuration::modify (Task& task, const std::string& value) { Eval e; e.addSource (domSource); - contextTask = task; + contextTask = &task; e.evaluateInfixExpression (value, evaluatedValue); } diff --git a/src/columns/ColTypeNumeric.cpp b/src/columns/ColTypeNumeric.cpp index f01b4d33a..986470b4c 100644 --- a/src/columns/ColTypeNumeric.cpp +++ b/src/columns/ColTypeNumeric.cpp @@ -32,7 +32,7 @@ #include #include -extern Task& contextTask; +extern Task* contextTask; //////////////////////////////////////////////////////////////////////////////// ColumnTypeNumeric::ColumnTypeNumeric () @@ -55,7 +55,7 @@ void ColumnTypeNumeric::modify (Task& task, const std::string& value) { Eval e; e.addSource (domSource); - contextTask = task; + contextTask = &task; e.evaluateInfixExpression (value, evaluatedValue); } diff --git a/src/columns/ColTypeString.cpp b/src/columns/ColTypeString.cpp index 5e932866a..89552ce14 100644 --- a/src/columns/ColTypeString.cpp +++ b/src/columns/ColTypeString.cpp @@ -34,7 +34,7 @@ #define STRING_INVALID_MOD "The '{1}' attribute does not allow a value of '{2}'." -extern Task& contextTask; +extern Task* contextTask; //////////////////////////////////////////////////////////////////////////////// ColumnTypeString::ColumnTypeString () @@ -67,7 +67,7 @@ void ColumnTypeString::modify (Task& task, const std::string& value) { Eval e; e.addSource (domSource); - contextTask = task; + contextTask = &task; Variant v; e.evaluateInfixExpression (value, v); diff --git a/src/commands/CmdGet.cpp b/src/commands/CmdGet.cpp index c35f112b0..38aae7c35 100644 --- a/src/commands/CmdGet.cpp +++ b/src/commands/CmdGet.cpp @@ -64,9 +64,8 @@ int CmdGet::execute (std::string& output) { case Lexer::Type::dom: { - Task t; Variant result; - if (getDOM (arg.attribute ("raw"), t, result)) + if (getDOM (arg.attribute ("raw"), NULL, result)) results.emplace_back (result); else results.emplace_back ("");