3 // Copyright (c) 2021, Oracle and/or its affiliates.
5 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
7 // Licensed under the Boost Software License version 1.0.
8 // http://www.boost.org/users/license.html
10 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_VISIT_HPP
11 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_VISIT_HPP
17 #include <boost/range/begin.hpp>
18 #include <boost/range/end.hpp>
20 #include <boost/geometry/core/static_assert.hpp>
21 #include <boost/geometry/core/tag.hpp>
22 #include <boost/geometry/core/tags.hpp>
23 #include <boost/geometry/core/visit.hpp>
24 #include <boost/geometry/util/type_traits.hpp>
26 namespace boost { namespace geometry
29 #ifndef DOXYGEN_NO_DISPATCH
33 template <typename Geometry, typename Tag = typename tag<Geometry>::type>
36 template <typename F, typename G>
37 static void apply(F && f, G && g)
39 f(std::forward<G>(g));
43 template <typename Geometry>
44 struct visit_one<Geometry, void>
46 BOOST_GEOMETRY_STATIC_ASSERT_FALSE(
47 "Not implemented for this Geometry type.",
51 template <typename Geometry>
52 struct visit_one<Geometry, dynamic_geometry_tag>
54 template <typename F, typename Geom>
55 static void apply(F && function, Geom && geom)
59 util::remove_cref_t<Geom>
60 >::apply(std::forward<F>(function), std::forward<Geom>(geom));
67 typename Geometry1, typename Geometry2,
68 typename Tag1 = typename tag<Geometry1>::type,
69 typename Tag2 = typename tag<Geometry2>::type
73 template <typename F, typename G1, typename G2>
74 static void apply(F && f, G1 && geom1, G2 && geom2)
76 f(std::forward<G1>(geom1), std::forward<G2>(geom2));
80 template <typename Geometry1, typename Geometry2, typename Tag2>
81 struct visit_two<Geometry1, Geometry2, void, Tag2>
83 BOOST_GEOMETRY_STATIC_ASSERT_FALSE(
84 "Not implemented for this Geometry1 type.",
88 template <typename Geometry1, typename Geometry2, typename Tag1>
89 struct visit_two<Geometry1, Geometry2, Tag1, void>
91 BOOST_GEOMETRY_STATIC_ASSERT_FALSE(
92 "Not implemented for this Geometry2 type.",
96 template <typename Geometry1, typename Geometry2>
97 struct visit_two<Geometry1, Geometry2, void, void>
99 BOOST_GEOMETRY_STATIC_ASSERT_FALSE(
100 "Not implemented for these types.",
101 Geometry1, Geometry2);
104 template <typename Geometry1, typename Geometry2, typename Tag2>
105 struct visit_two<Geometry1, Geometry2, dynamic_geometry_tag, Tag2>
107 template <typename F, typename G1, typename G2>
108 static void apply(F && f, G1 && geom1, G2 && geom2)
110 traits::visit<util::remove_cref_t<G1>>::apply([&](auto && g1)
112 f(std::forward<decltype(g1)>(g1), std::forward<G2>(geom2));
113 }, std::forward<G1>(geom1));
117 template <typename Geometry1, typename Geometry2, typename Tag1>
118 struct visit_two<Geometry1, Geometry2, Tag1, dynamic_geometry_tag>
120 template <typename F, typename G1, typename G2>
121 static void apply(F && f, G1 && geom1, G2 && geom2)
123 traits::visit<util::remove_cref_t<G2>>::apply([&](auto && g2)
125 f(std::forward<G1>(geom1), std::forward<decltype(g2)>(g2));
126 }, std::forward<G2>(geom2));
130 template <typename Geometry1, typename Geometry2>
131 struct visit_two<Geometry1, Geometry2, dynamic_geometry_tag, dynamic_geometry_tag>
133 template <typename F, typename G1, typename G2>
134 static void apply(F && f, G1 && geom1, G2 && geom2)
138 util::remove_cref_t<G1>, util::remove_cref_t<G2>
139 >::apply([&](auto && g1, auto && g2)
141 f(std::forward<decltype(g1)>(g1), std::forward<decltype(g2)>(g2));
142 }, std::forward<G1>(geom1), std::forward<G2>(geom2));
147 template <typename Geometry, typename Tag = typename tag<Geometry>::type>
148 struct visit_breadth_first
150 template <typename F, typename G>
151 static bool apply(F f, G && g)
153 return f(std::forward<G>(g));
157 template <typename Geometry>
158 struct visit_breadth_first<Geometry, void>
160 BOOST_GEOMETRY_STATIC_ASSERT_FALSE(
161 "Not implemented for this Geometry type.",
165 template <typename Geometry>
166 struct visit_breadth_first<Geometry, dynamic_geometry_tag>
168 template <typename Geom, typename F>
169 static bool apply(F function, Geom && geom)
172 traits::visit<util::remove_cref_t<Geom>>::apply([&](auto && g)
174 result = visit_breadth_first
176 std::remove_reference_t<decltype(g)>
178 std::forward<decltype(g)>(g));
179 }, std::forward<Geom>(geom));
184 } // namespace dispatch
185 #endif // DOXYGEN_NO_DISPATCH
188 #ifndef DOXYGEN_NO_DETAIL
192 template <bool PassIterator = false>
193 struct visit_breadth_first_impl
195 template <typename F, typename Geom>
196 static bool apply(F function, Geom && geom)
198 using iter_t = std::conditional_t
200 std::is_rvalue_reference<decltype(geom)>::value,
201 std::move_iterator<typename boost::range_iterator<Geom>::type>,
202 typename boost::range_iterator<Geom>::type
205 std::deque<iter_t> queue;
207 iter_t it = iter_t{ boost::begin(geom) };
208 iter_t end = iter_t{ boost::end(geom) };
211 for (; it != end; ++it)
214 traits::iter_visit<util::remove_cref_t<Geom>>::apply([&](auto && g)
216 result = visit_breadth_first_impl::visit_or_enqueue<PassIterator>(
217 function, std::forward<decltype(g)>(g), queue, it);
231 // Alternatively store a pointer to GeometryCollection
232 // so this call can be avoided.
233 traits::iter_visit<util::remove_cref_t<Geom>>::apply([&](auto && g)
235 visit_breadth_first_impl::set_iterators(std::forward<decltype(g)>(g), it, end);
246 bool PassIter, typename F, typename Geom, typename Iterator,
247 std::enable_if_t<util::is_geometry_collection<Geom>::value, int> = 0
249 static bool visit_or_enqueue(F &, Geom &&, std::deque<Iterator> & queue, Iterator iter)
251 queue.push_back(iter);
256 bool PassIter, typename F, typename Geom, typename Iterator,
257 std::enable_if_t<! util::is_geometry_collection<Geom>::value && ! PassIter, int> = 0
259 static bool visit_or_enqueue(F & f, Geom && g, std::deque<Iterator> & , Iterator)
261 return f(std::forward<Geom>(g));
265 bool PassIter, typename F, typename Geom, typename Iterator,
266 std::enable_if_t<! util::is_geometry_collection<Geom>::value && PassIter, int> = 0
268 static bool visit_or_enqueue(F & f, Geom && g, std::deque<Iterator> & , Iterator iter)
270 return f(std::forward<Geom>(g), iter);
275 typename Geom, typename Iterator,
276 std::enable_if_t<util::is_geometry_collection<Geom>::value, int> = 0
278 static void set_iterators(Geom && g, Iterator & first, Iterator & last)
280 first = Iterator{ boost::begin(g) };
281 last = Iterator{ boost::end(g) };
285 typename Geom, typename Iterator,
286 std::enable_if_t<! util::is_geometry_collection<Geom>::value, int> = 0
288 static void set_iterators(Geom &&, Iterator &, Iterator &)
292 } // namespace detail
293 #endif // DOXYGEN_NO_DETAIL
296 #ifndef DOXYGEN_NO_DISPATCH
300 // NOTE: This specialization works partially like std::visit and partially like
301 // std::ranges::for_each. If the argument is rvalue reference then the elements
302 // are passed into the function as rvalue references as well. This is consistent
303 // with std::visit but different than std::ranges::for_each. It's done this way
304 // because visit_breadth_first is also specialized for static and dynamic geometries
305 // and references for them has to be propagated like that. If this is not
306 // desireable then the support for other kinds of geometries should be dropped and
307 // this algorithm should work only for geometry collection. Or forwarding of rvalue
308 // references should simply be dropped entirely.
309 // This is not a problem right now because only non-rvalue references are passed
310 // but in the future there might be some issues. Consider e.g. passing a temporary
311 // mutable proxy range as geometry collection. In such case the elements would be
312 // passed as rvalue references which would be incorrect.
313 template <typename Geometry>
314 struct visit_breadth_first<Geometry, geometry_collection_tag>
315 : detail::visit_breadth_first_impl<>
319 } // namespace dispatch
320 #endif // DOXYGEN_NO_DISPATCH
323 #ifndef DOXYGEN_NO_DETAIL
327 template <typename UnaryFunction, typename Geometry>
328 inline void visit(UnaryFunction && function, Geometry && geometry)
332 std::remove_reference_t<Geometry>
333 >::apply(std::forward<UnaryFunction>(function), std::forward<Geometry>(geometry));
337 template <typename UnaryFunction, typename Geometry1, typename Geometry2>
338 inline void visit(UnaryFunction && function, Geometry1 && geometry1, Geometry2 && geometry2)
342 std::remove_reference_t<Geometry1>,
343 std::remove_reference_t<Geometry2>
344 >::apply(std::forward<UnaryFunction>(function),
345 std::forward<Geometry1>(geometry1),
346 std::forward<Geometry2>(geometry2));
350 template <typename UnaryFunction, typename Geometry>
351 inline void visit_breadth_first(UnaryFunction function, Geometry && geometry)
353 dispatch::visit_breadth_first
355 std::remove_reference_t<Geometry>
356 >::apply(function, std::forward<Geometry>(geometry));
359 } // namespace detail
360 #endif // DOXYGEN_NO_DETAIL
362 }} // namespace boost::geometry
364 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_VISIT_HPP