diff --git a/src/models/storm_report.cpp b/src/models/storm_report.cpp index 17cfc02..7e16129 100644 --- a/src/models/storm_report.cpp +++ b/src/models/storm_report.cpp @@ -6,6 +6,8 @@ #include "models/from_tree.hpp" #include "models/json.hpp" +#include +#include #include namespace spc { @@ -19,8 +21,10 @@ StormReportPayload detail::storm_reports_from_tree(const Json& root) { return payload; } const Json::array_t& features = features_node->get_array(); - // Every IEM feature has properties, so this sizes the list exactly. - payload.reports.reserve(features.size()); + // Count first so a body padded with values that aren't features can't make + // the list reserve room for reports it never gets. + payload.reports.reserve(static_cast(std::ranges::count_if( + features, [](const Json& feat) { return detail::lookup(feat, "properties") != nullptr; }))); for (const Json& feat : features) { const Json* props = detail::lookup(feat, "properties"); if (props == nullptr) { diff --git a/tests/test_arcgis.cpp b/tests/test_arcgis.cpp index cce57e7..f9d7479 100644 --- a/tests/test_arcgis.cpp +++ b/tests/test_arcgis.cpp @@ -467,6 +467,18 @@ TEST(Models, WatchNumbersThatAreNotFiniteIntegersBecomeZero) { } } +TEST(Models, StormReportsReserveOnlyForReports) { + // Values that aren't features become no reports, so they reserve nothing. + std::string body = R"({"type":"FeatureCollection","features":[)"; + for (int i = 0; i < 10000; ++i) { + body += i == 0 ? "0" : ",0"; + } + body += "]}"; + const StormReportPayload p = parse_storm_reports(body); + EXPECT_TRUE(p.reports.empty()); + EXPECT_EQ(p.reports.capacity(), std::vector{}.capacity()); +} + TEST(Models, StormReportsParseIemLsr) { const StormReportPayload p = parse_storm_reports(read_fixture("iem_storm_reports.json")); ASSERT_GT(p.reports.size(), 0u);