From 4958a83ddb9b7d5ba676e710b8b63d435c6323cc Mon Sep 17 00:00:00 2001 From: King_DuckZ Date: Thu, 2 Apr 2020 02:26:44 +0200 Subject: [PATCH] Trying to get default value filling fixed. I'm not sure it always works, but the idea is that this should find the maximum size of all arrays resulting from a scraplang struct query and make all entries the same length filling them with: 1) the default value if one was given in scraplang 2) the value of the last entry in the array being filled 3) just empty values It seems to work but I can't say I ran very extensive tests. I'll test more in the future and fix as needed. --- src/scraplang/apply.cpp | 87 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 2 deletions(-) diff --git a/src/scraplang/apply.cpp b/src/scraplang/apply.cpp index fe9ad54..280958e 100644 --- a/src/scraplang/apply.cpp +++ b/src/scraplang/apply.cpp @@ -30,6 +30,8 @@ #include #include #include +#include +#include namespace duck { namespace sl { #if defined(APPLY_VERBOSE) @@ -48,6 +50,7 @@ namespace duck { namespace sl { EntryNode >>; using MustacheEntryMap = std::map; + typedef std::function FixLengthCommand; struct EntryNode { explicit EntryNode (const std::string_view& parName) : @@ -106,6 +109,72 @@ namespace duck { namespace sl { EntryNode& m_root; }; + class FillWithClonesVisitor : public boost::static_visitor { + public: + explicit FillWithClonesVisitor (std::size_t exp_size) : + m_expected_size(exp_size) + { } + virtual mstch::node&& operator()(mstch::array&& parOut) { + if (parOut.empty()) { + parOut.resize(m_expected_size); + } + else { + std::fill_n( + std::back_inserter(parOut), + std::max(m_expected_size, parOut.size()) - parOut.size(), + parOut.front() + ); + } + m_retval = std::move(parOut); + return std::move(m_retval); + } + + template + mstch::node&& operator()(T&& parOut) { + mstch::array retval; + retval.reserve(m_expected_size); + retval.push_back(std::move(parOut)); + return (*this)(std::move(retval)); + } + + protected: + mstch::node m_retval; + std::size_t m_expected_size; + }; + + class FillWithStringsVisitor : public FillWithClonesVisitor { + public: + FillWithStringsVisitor (const std::string& parVal, std::size_t exp_size) : + FillWithClonesVisitor(exp_size), + m_value(parVal) + { } + + mstch::node&& operator()(mstch::array&& parOut) override { + std::fill_n( + std::back_inserter(parOut), + std::max(m_expected_size, parOut.size()) - parOut.size(), + m_value.get() + ); + m_retval = std::move(parOut); + return std::move(m_retval); + } + + using FillWithClonesVisitor::operator(); + + private: + std::reference_wrapper m_value; + }; + + void fill_with_defaults (mstch::map& parMap, std::size_t parTotal, const std::string& parKey, const std::string& parDefault) { + FillWithStringsVisitor visitor(parDefault, parTotal); + parMap[parKey] = boost::apply_visitor(visitor, std::move(parMap[parKey])); + } + + void fill_with_last_item_clones (mstch::map& parMap, std::size_t parTotal, const std::string& parKey) { + FillWithClonesVisitor visitor(parTotal); + parMap[parKey] = boost::apply_visitor(visitor, std::move(parMap[parKey])); + } + mstch::map to_mustache_dict_recursive ( const EntryNode& parNode, std::string_view parSrc, @@ -266,7 +335,7 @@ namespace duck { namespace sl { return empty_retval; } - std::size_t largest_array_size_in (mstch::map& parMap) { + std::size_t largest_array_size_in (const mstch::map& parMap) { typedef ItemCountingVisitor ITC; using boost::apply_visitor; @@ -283,10 +352,13 @@ namespace duck { namespace sl { void fill_with_xpaths ( mstch::map& parOut, + std::vector& parFixCommands, const EntryNode& parNode, std::string_view parSrc, XPathRunner& parRunner ) { + using std::placeholders::_1; + for (const XPathElement* xpath : parNode.xpaths) { assert(xpath); std::cout << "Running query for \"" << xpath->name << "\"\n"; @@ -306,6 +378,11 @@ namespace duck { namespace sl { else { parOut[xpath->name] = std::string(); } + + if (xpath->def_val) + parFixCommands.push_back(std::bind(&fill_with_defaults, std::ref(parOut), _1, std::cref(xpath->name), std::cref(*xpath->def_val))); + else + parFixCommands.push_back(std::bind(&fill_with_last_item_clones, std::ref(parOut), _1, std::cref(xpath->name))); } } @@ -337,10 +414,16 @@ namespace duck { namespace sl { XPathRunner& parRunner ) { mstch::map retval; + std::vector fix_commands; - fill_with_xpaths(retval, parNode, parSrc, parRunner); + fill_with_xpaths(retval, fix_commands, parNode, parSrc, parRunner); fill_with_structs(retval, parNode, parSrc, parRunner); + const std::size_t largest = largest_array_size_in(retval); + for (const auto& command : fix_commands) { + command(largest); + } + return retval; }