Skip to content

v0.2.52..v0.2.53 changeset CountCmd.cpp

Garret Voltz edited this page Feb 12, 2020 · 1 revision
diff --git a/hoot-core/src/main/cpp/hoot/core/cmd/CountCmd.cpp b/hoot-core/src/main/cpp/hoot/core/cmd/CountCmd.cpp
index d296697..ad81b3e 100644
--- a/hoot-core/src/main/cpp/hoot/core/cmd/CountCmd.cpp
+++ b/hoot-core/src/main/cpp/hoot/core/cmd/CountCmd.cpp
@@ -22,7 +22,7 @@
  * This will properly maintain the copyright information. DigitalGlobe
  * copyrights will be updated automatically.
  *
- * @copyright Copyright (C) 2018, 2019 DigitalGlobe (http://www.digitalglobe.com/)
+ * @copyright Copyright (C) 2018, 2019, 2020 DigitalGlobe (http://www.digitalglobe.com/)
  */
 
 // Hoot
@@ -41,6 +41,8 @@
 #include <hoot/core/io/ElementCriterionVisitorInputStream.h>
 #include <hoot/core/io/ElementVisitorInputStream.h>
 #include <hoot/core/util/StringUtils.h>
+#include <hoot/core/io/IoUtils.h>
+#include <hoot/core/visitors/FilteredVisitor.h>
 
 namespace hoot
 {
@@ -80,24 +82,39 @@ public:
     }
     LOG_VARD(countFeaturesOnly);
 
-    const QStringList inputs = args[0].split(";");
+    const QStringList inputs = args[0].trimmed().split(";");
     LOG_VART(inputs.size());
 
     QString criterionClassName = "";
     if (args.size() > 1)
     {
-      criterionClassName = args[1];
+      criterionClassName = args[1].trimmed();
     }
     LOG_VARD(criterionClassName);
 
+    // test crit here to see if I/O can be streamed or not; if it requires a map, then it can't be
+    // streamed
+    bool isStreamableCrit = false;
+    ElementCriterionPtr crit =
+      _getCriterion(
+        criterionClassName, ConfigOptions().getElementCriterionNegate(), isStreamableCrit);
+
     const QString dataType = countFeaturesOnly ? "features" : "elements";
-    for (int i = 0; i < inputs.size(); i++)
+    if (isStreamableCrit)
     {
-      LOG_INFO(
-        "Counting " << dataType << " satisfying " << criterionClassName << " from " <<
-        inputs.at(i).right(25) << "...");
-      _total += _count(inputs.at(i), countFeaturesOnly, criterionClassName);
+      for (int i = 0; i < inputs.size(); i++)
+      {
+        LOG_INFO(
+          "Counting " << dataType << " satisfying " << criterionClassName << " from " <<
+          inputs.at(i).right(25) << "...");
+        _total += _countStreaming(inputs.at(i), countFeaturesOnly, crit);
+      }
     }
+    else
+    {
+      _total += _countMemoryBound(inputs, countFeaturesOnly, crit);
+    }
+
     LOG_VART(_total);
 
     //putting a preceding endline in here since PROGRESS_INFO doesn't clear itself out at the end
@@ -111,7 +128,7 @@ private:
   long _total;
   int _taskStatusUpdateInterval;
 
-  std::shared_ptr<PartialOsmMapReader> _getReader(const QString& input)
+  std::shared_ptr<PartialOsmMapReader> _getStreamingReader(const QString& input)
   {
     LOG_TRACE("Getting reader...");
 
@@ -124,9 +141,15 @@ private:
     return reader;
   }
 
-  ElementCriterionPtr _getCriterion(const QString& criterionClassName, const bool negate)
+  ElementCriterionPtr _getCriterion(const QString& criterionClassName, const bool negate,
+                                    bool& isStreamable)
   {
-    LOG_TRACE("Getting criterion...");
+    LOG_TRACE("Getting criterion: " << criterionClassName << "...");
+
+    if (criterionClassName.isEmpty())
+    {
+      return ElementCriterionPtr();
+    }
 
     ElementCriterionPtr crit;
 
@@ -140,6 +163,16 @@ private:
       throw IllegalArgumentException("Invalid criterion: " + criterionClassName);
     }
 
+    OsmMapConsumer* omc = dynamic_cast<OsmMapConsumer*>(crit.get());
+    if (omc)
+    {
+      isStreamable = false;
+    }
+    else
+    {
+      isStreamable = true;
+    }
+
     if (negate)
     {
       crit.reset(new NotCriterion(crit));
@@ -161,20 +194,22 @@ private:
   }
 
   ElementInputStreamPtr _getFilteredInputStream(ElementInputStreamPtr inputStream,
-                                                const QString& criterionClassName,
-                                                ElementVisitorPtr countVis)
+                                                const ElementCriterionPtr& criterion,
+                                                ConstElementVisitorPtr countVis)
   {
     LOG_TRACE("Getting filtered input stream...");
+    if (criterion)
+    {
+      LOG_VARD(criterion->toString());
+    }
 
     ElementInputStreamPtr filteredInputStream;
 
     LOG_TRACE("Creating stream...");
-    if (!criterionClassName.trimmed().isEmpty())
+    if (criterion)
     {
-      ElementCriterionPtr crit =
-        _getCriterion(criterionClassName, ConfigOptions().getElementCriterionNegate());
       filteredInputStream.reset(
-        new ElementCriterionVisitorInputStream(inputStream, crit, countVis));
+        new ElementCriterionVisitorInputStream(inputStream, criterion, countVis));
     }
     else
     {
@@ -184,11 +219,11 @@ private:
     return filteredInputStream;
   }
 
-  ElementVisitorPtr _getCountVis(const bool countFeaturesOnly)
+  ConstElementVisitorPtr _getCountVis(const bool countFeaturesOnly)
   {
     LOG_TRACE("Getting count vis...");
 
-    ElementVisitorPtr countVis;
+    ConstElementVisitorPtr countVis;
     if (countFeaturesOnly)
     {
       countVis.reset(new FeatureCountVisitor());
@@ -200,18 +235,48 @@ private:
     return countVis;
   }
 
-  long _count(const QString& input, const bool countFeaturesOnly, const QString& criterionClassName)
+  long _countMemoryBound(const QStringList& inputs, const bool countFeaturesOnly,
+                         const ElementCriterionPtr& criterion)
+  {
+    OsmMapPtr map(new OsmMap());
+    IoUtils::loadMaps(map, inputs, true);
+
+    OsmMapConsumer* omc = dynamic_cast<OsmMapConsumer*>(criterion.get());
+    if (omc)
+    {
+      omc->setOsmMap(map.get());
+    }
+
+    ConstElementVisitorPtr countVis = _getCountVis(countFeaturesOnly);
+    ConstElementVisitorPtr vis;
+    if (criterion)
+    {
+      vis.reset(new FilteredVisitor(criterion, countVis));
+    }
+    else
+    {
+      vis = countVis;
+    }
+    map->visitRo(*vis);
+
+    std::shared_ptr<SingleStatistic> counter =
+      std::dynamic_pointer_cast<SingleStatistic>(countVis);
+    return (long)counter->getStat();
+  }
+
+  long _countStreaming(const QString& input, const bool countFeaturesOnly,
+                       const ElementCriterionPtr& criterion)
   {
     long inputTotal = 0;
 
-    std::shared_ptr<PartialOsmMapReader> reader = _getReader(input);
+    std::shared_ptr<PartialOsmMapReader> reader = _getStreamingReader(input);
 
-    ElementVisitorPtr countVis = _getCountVis(countFeaturesOnly);
+    ConstElementVisitorPtr countVis = _getCountVis(countFeaturesOnly);
 
     ElementInputStreamPtr filteredInputStream =
       _getFilteredInputStream(
         std::dynamic_pointer_cast<ElementInputStream>(reader),
-        criterionClassName,
+        criterion,
         countVis);
 
     std::shared_ptr<SingleStatistic> counter =
Clone this wiki locally