From b97ba772134e2729b2d27d6b0818af0dfa190c3f Mon Sep 17 00:00:00 2001 From: yuiseki Date: Sat, 25 Apr 2026 15:03:16 +0900 Subject: [PATCH] extract: scan way nodes once across all extracts in complete_ways pass 1 --- src/extract/strategy.hpp | 13 +++++-- src/extract/strategy_complete_ways.cpp | 50 ++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/src/extract/strategy.hpp b/src/extract/strategy.hpp index e9fe60a1..47188749 100644 --- a/src/extract/strategy.hpp +++ b/src/extract/strategy.hpp @@ -104,9 +104,7 @@ class Pass { break; case osmium::item_type::way: self().way(static_cast(object)); - for (auto& e : extracts()) { - self().eway(&e, static_cast(object)); - } + self().eway_all(extracts(), static_cast(object)); break; case osmium::item_type::relation: self().relation(static_cast(object)); @@ -155,6 +153,15 @@ class Pass { void erelation(extract_data*, const osmium::Relation&) { } + // Default implementation: call eway() for each extract separately. + // Subclasses may override this to process all extracts in a single + // pass over way.nodes(). + void eway_all(std::vector& exts, const osmium::Way& way) { + for (auto& e : exts) { + self().eway(&e, way); + } + } + public: explicit Pass(TStrategy* strategy) : diff --git a/src/extract/strategy_complete_ways.cpp b/src/extract/strategy_complete_ways.cpp index 96a65594..f9ad2b24 100644 --- a/src/extract/strategy_complete_ways.cpp +++ b/src/extract/strategy_complete_ways.cpp @@ -27,6 +27,7 @@ along with this program. If not, see . #include #include +#include #include #include #include @@ -100,6 +101,55 @@ namespace strategy_complete_ways { } } + // Override that scans way.nodes() at most twice for all extracts + // combined instead of up to twice per extract as the default does. + // Uses a uint64_t bitmask so falls back to the default per-extract + // eway() loop when there are more than 64 extracts. + // Pass A finds which extracts claim this way. + // Pass B records all node refs into extra_node_ids for matched extracts. + void eway_all(std::vector& exts, const osmium::Way& way) { + const std::size_t n = exts.size(); + + if (n > 64) { + for (auto& e : exts) { + self().eway(&e, way); + } + return; + } + std::uint64_t found_mask = 0; + std::size_t remaining = n; + + for (const auto& nr : way.nodes()) { + const auto node_id = nr.positive_ref(); + for (std::size_t i = 0; i < n; ++i) { + if (!(found_mask & (std::uint64_t{1} << i)) && + exts[i].node_ids.get(node_id)) { + found_mask |= std::uint64_t{1} << i; + exts[i].way_ids.set(way.positive_id()); + if (--remaining == 0) { + break; + } + } + } + if (remaining == 0) { + break; + } + } + + if (found_mask == 0) { + return; + } + + for (const auto& nr : way.nodes()) { + const auto node_ref = nr.ref(); + for (std::size_t i = 0; i < n; ++i) { + if (found_mask & (std::uint64_t{1} << i)) { + exts[i].extra_node_ids.set(node_ref); + } + } + } + } + void relation(const osmium::Relation& relation) { m_check_order.relation(relation); m_relations_map_stash.add_members(relation);