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 =