Add enumerate to prepare for 17 and 23

This commit is contained in:
Barend Gehrels 2024-04-21 09:41:50 +02:00
parent 713fe69938
commit 1f8b6e02ec
11 changed files with 333 additions and 109 deletions

View File

@ -59,7 +59,7 @@
#include <boost/geometry/algorithms/detail/sections/section_box_policies.hpp>
#include <boost/geometry/views/detail/closed_clockwise_view.hpp>
#include <boost/geometry/util/for_each_with_index.hpp>
#include <boost/geometry/views/enumerate_view.hpp>
#include <boost/geometry/util/range.hpp>
@ -376,16 +376,18 @@ struct buffered_piece_collection
inline void update_turn_administration()
{
for_each_with_index(m_turns, [this](std::size_t index, auto& turn)
for (auto const& enumerated : util::enumerate(m_turns))
{
turn.turn_index = index;
// enumerated is const, but its value is a non-const reference
auto& turn = enumerated.value;
turn.turn_index = enumerated.index;
// Verify if a turn is a linear endpoint
if (! turn.is_linear_end_point)
{
this->check_linear_endpoints(turn);
}
});
}
}
// Calculate properties of piece borders which are not influenced
@ -1091,30 +1093,32 @@ struct buffered_piece_collection
// Inner rings, for deflate, which do not have intersections, and
// which are outside originals, are skipped
// (other ones should be traversed)
for_each_with_index(offsetted_rings, [&](std::size_t index, auto const& ring)
for (auto const& enumerated : util::enumerate(offsetted_rings))
{
auto const& ring = enumerated.value;
if (! ring.has_intersections()
&& ! ring.is_untouched_outside_original)
{
if (! ring.has_intersections()
&& ! ring.is_untouched_outside_original)
{
properties p = properties(ring, m_strategy);
if (p.valid)
{
ring_identifier id(0, index, -1);
selected[id] = p;
}
}
});
// Select all created rings
for_each_with_index(traversed_rings, [&](std::size_t index, auto const& ring)
{
properties p = properties(ring, m_strategy);
properties const p = properties(ring, m_strategy);
if (p.valid)
{
ring_identifier id(2, index, -1);
ring_identifier id(0, enumerated.index, -1);
selected[id] = p;
}
});
}
}
// Select all created rings
for (auto const& enumerated : util::enumerate(traversed_rings))
{
auto const& ring = enumerated.value;
properties p = properties(ring, m_strategy);
if (p.valid)
{
ring_identifier id(2, enumerated.index, -1);
selected[id] = p;
}
}
detail::overlay::assign_parents<overlay_buffer>(offsetted_rings, traversed_rings,
selected, m_strategy);

View File

@ -27,10 +27,10 @@
#include <boost/geometry/algorithms/detail/partition.hpp>
#include <boost/geometry/algorithms/detail/overlay/get_ring.hpp>
#include <boost/geometry/algorithms/detail/overlay/range_in_geometry.hpp>
#include <boost/geometry/views/enumerate_view.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/util/for_each_with_index.hpp>
namespace boost { namespace geometry
{
@ -271,25 +271,28 @@ inline void assign_parents(Geometry1 const& geometry1,
std::size_t index_positive = 0; // only used if count_positive>0
// Copy to vector (this might be obsolete, using the map directly)
// The index in the map is also the index in the vector.
using helper = ring_info_helper<point_type, area_result_type>;
std::vector<helper> vector(count_total);
for_each_with_index(ring_map, [&](std::size_t index, auto const& pair)
for (auto const& enumerated : util::enumerate(ring_map))
{
vector[index] = helper(pair.first, pair.second.get_area());
helper& item = vector[index];
switch(pair.first.source_index)
auto const& ring_id = enumerated.value.first;
auto const& info = enumerated.value.second;
vector[enumerated.index] = helper(ring_id, info.get_area());
helper& item = vector[enumerated.index];
switch(ring_id.source_index)
{
case 0 :
geometry::envelope(get_ring<tag1>::apply(pair.first, geometry1),
geometry::envelope(get_ring<tag1>::apply(ring_id, geometry1),
item.envelope, strategy);
break;
case 1 :
geometry::envelope(get_ring<tag2>::apply(pair.first, geometry2),
geometry::envelope(get_ring<tag2>::apply(ring_id, geometry2),
item.envelope, strategy);
break;
case 2 :
geometry::envelope(get_ring<void>::apply(pair.first, collection),
geometry::envelope(get_ring<void>::apply(ring_id, collection),
item.envelope, strategy);
break;
}
@ -300,9 +303,9 @@ inline void assign_parents(Geometry1 const& geometry1,
if (item.real_area > 0)
{
count_positive++;
index_positive = index;
index_positive = enumerated.index;
}
});
}
if (! check_for_orientation)
{
@ -323,15 +326,16 @@ inline void assign_parents(Geometry1 const& geometry1,
// located outside the outer ring, this cannot be done
ring_identifier id_of_positive = vector[index_positive].id;
ring_info_type& outer = ring_map[id_of_positive];
for_each_with_index(vector, [&](std::size_t index, auto const& item)
for (auto const& item : util::enumerate(vector))
{
if (index != index_positive)
if (item.index != index_positive)
{
ring_info_type& inner = ring_map[item.id];
auto const id = item.value.id;
ring_info_type& inner = ring_map[id];
inner.parent = id_of_positive;
outer.children.push_back(item.id);
outer.children.push_back(id);
}
});
}
return;
}
}

View File

@ -26,6 +26,7 @@
#include <boost/range/value_type.hpp>
#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
#include <boost/geometry/views/enumerate_view.hpp>
namespace boost { namespace geometry
@ -122,17 +123,17 @@ inline void check_detailed(MetaTurns& meta_turns, MetaTurn const& meta_turn,
template <typename TurnPoints>
inline bool check_graph(TurnPoints& turn_points, operation_type for_operation)
inline bool check_graph(TurnPoints const& turn_points, operation_type for_operation)
{
typedef typename boost::range_value<TurnPoints>::type turn_point_type;
using turn_point_type = typename boost::range_value<TurnPoints>::type;
bool error = false;
std::vector<meta_turn<turn_point_type> > meta_turns;
for_each_with_index(turn_points, [&](std::size_t index, auto const& point)
for (auto const& item : util::enumerate(turn_points))
{
meta_turns.push_back(meta_turn<turn_point_type>(index, point));
});
meta_turns.push_back(meta_turn<turn_point_type>(item.index, item.value));
}
int cycle = 0;
for (auto& meta_turn : meta_turns)

View File

@ -34,6 +34,7 @@
#include <boost/range/value_type.hpp>
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
#include <boost/geometry/algorithms/detail/overlay/check_enrich.hpp>
#include <boost/geometry/algorithms/detail/overlay/discard_duplicate_turns.hpp>
#include <boost/geometry/algorithms/detail/overlay/handle_colocations.hpp>
#include <boost/geometry/algorithms/detail/overlay/handle_self_turns.hpp>
@ -42,11 +43,8 @@
#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
#include <boost/geometry/policies/robustness/robust_type.hpp>
#include <boost/geometry/util/constexpr.hpp>
#include <boost/geometry/util/for_each_with_index.hpp>
#include <boost/geometry/views/enumerate_view.hpp>
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
# include <boost/geometry/algorithms/detail/overlay/check_enrich.hpp>
#endif
namespace boost { namespace geometry
@ -112,8 +110,10 @@ template <typename Operations, typename Turns>
inline void enrich_assign(Operations& operations, Turns& turns,
bool check_consecutive_turns)
{
for_each_with_index(operations, [&](std::size_t index, auto const& indexed)
for (auto const& item : util::enumerate(operations))
{
auto const& index = item.index;
auto const& indexed = item.value;
auto& turn = turns[indexed.turn_index];
auto& op = turn.operations[indexed.operation_index];
@ -185,7 +185,7 @@ inline void enrich_assign(Operations& operations, Turns& turns,
// Next turn is located further on same segment: assign next_ip_index
op.enriched.next_ip_index = static_cast<signed_size_type>(operations[next_index].turn_index);
}
});
}
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
for (auto const& indexed_op : operations)
@ -223,8 +223,10 @@ inline void enrich_adapt(Operations& operations, Turns& turns)
bool next_phase = false;
std::size_t previous_index = operations.size() - 1;
for_each_with_index(operations, [&](std::size_t index, auto const& indexed)
for (auto const& item : util::enumerate(operations))
{
auto const& index = item.index;
auto const& indexed = item.value;
auto& turn = turns[indexed.turn_index];
auto& op = turn.operations[indexed.operation_index];
@ -243,7 +245,7 @@ inline void enrich_adapt(Operations& operations, Turns& turns)
}
}
previous_index = index;
});
}
if (! next_phase)
{
@ -290,12 +292,16 @@ template <typename Turns, typename MappedVector, typename IncludePolicy>
inline void create_map(Turns const& turns, MappedVector& mapped_vector,
IncludePolicy const& include_policy)
{
for_each_with_index(turns, [&](std::size_t index, auto const& turn)
for (auto const& turn_item : util::enumerate(turns))
{
auto const& index = turn_item.index;
auto const& turn = turn_item.value;
if (! turn.discarded)
{
for_each_with_index(turn.operations, [&](std::size_t op_index, auto const& op)
for (auto const& op_item : util::enumerate(turn.operations))
{
auto const& op_index = op_item.index;
auto const& op = op_item.value;
if (include_policy.include(op.operation))
{
ring_identifier const ring_id
@ -309,9 +315,9 @@ inline void create_map(Turns const& turns, MappedVector& mapped_vector,
index, op_index, op, turn.operations[1 - op_index].seg_id
);
}
});
}
}
});
}
}
template <typename Point1, typename Point2>
@ -534,9 +540,15 @@ inline void enrich_intersection_points(Turns& turns,
}
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
//detail::overlay::check_graph(turns, for_operation);
constexpr bool do_check_graph = true;
#else
constexpr bool do_check_graph = false;
#endif
if BOOST_GEOMETRY_CONSTEXPR (do_check_graph)
{
detail::overlay::check_graph(turns, target_operation);
}
}
}} // namespace boost::geometry

View File

@ -59,7 +59,7 @@
#if defined(BOOST_GEOMETRY_DEBUG_FOLLOW)
#include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
#include <boost/geometry/io/wkt/wkt.hpp>
#include <boost/geometry/util/for_each_with_index.hpp>
#include <boost/geometry/views/enumerate_view.hpp>
#endif
namespace boost { namespace geometry
@ -379,10 +379,11 @@ struct intersection_of_linestring_with_areal
}
#if defined(BOOST_GEOMETRY_DEBUG_FOLLOW)
for_each_with_index(turns, [](auto index, auto const& turn)
for (auto const& item : util::enumerate(turns))
{
debug_follow(turn, turn.operations[0], index);
});
auto const& turn = item.value;
debug_follow(turn, turn.operations[0], item.index);
}
#endif
return follower::apply

View File

@ -1,49 +0,0 @@
// Boost.Geometry
// Copyright (c) 2023 Barend Gehrels, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_UTIL_FOR_EACH_WITH_INDEX_HPP
#define BOOST_GEOMETRY_UTIL_FOR_EACH_WITH_INDEX_HPP
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/size_type.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail
{
// Utility function to implement a Kotlin like range based for loop
template <typename Container, typename Function>
inline void for_each_with_index(Container const& container, Function func)
{
typename boost::range_size<Container>::type index = 0;
for (auto it = boost::begin(container); it != boost::end(container); ++it, ++index)
{
func(index, *it);
}
}
template <typename Container, typename Function>
inline void for_each_with_index(Container& container, Function func)
{
typename boost::range_size<Container>::type index = 0;
for (auto it = boost::begin(container); it != boost::end(container); ++it, ++index)
{
func(index, *it);
}
}
} // namespace detail
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_UTIL_FOR_EACH_WITH_INDEX_HPP

View File

@ -0,0 +1,159 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2024 Barend Gehrels, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_VIEWS_ENUMERATE_VIEW_HPP
#define BOOST_GEOMETRY_VIEWS_ENUMERATE_VIEW_HPP
#include <boost/iterator/iterator_facade.hpp>
#include <boost/iterator/iterator_categories.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/difference_type.hpp>
#include <boost/range/reference.hpp>
#include <boost/range/value_type.hpp>
#include <boost/geometry/util/type_traits_std.hpp>
namespace boost { namespace geometry
{
namespace util
{
// This view is a range of values, each with an index
// It is used to iterate over a range, and to get the index of the value
// It is used in the enumerate function
// The typename Range can either be const or non-const
template <typename Range>
struct enumerated_view
{
// The return value of the iterator
struct value_with_index
{
using type = util::transcribe_const_t
<
Range,
typename boost::range_value<Range>::type
>;
// Member variable index contains the zero-based index of the value in the range
std::size_t const index;
// Member variable value contains a const or non-const reference to the value itself
type& value;
};
private:
// Iterator implementation, not exposed.
struct enumerating_iterator
: public boost::iterator_facade
<
enumerating_iterator,
value_with_index const,
boost::random_access_traversal_tag,
value_with_index const,
typename boost::range_difference<Range>::type
>
{
using reference = value_with_index;
using difference_type = typename boost::range_difference<Range>::type;
// Constructor with the range it handles
explicit inline enumerating_iterator(Range& range)
: m_begin(boost::begin(range))
, m_end(boost::end(range))
, m_iterator(boost::begin(range))
{}
// Constructor to indicate the end of a range
explicit inline enumerating_iterator(Range& range, bool)
: m_begin(boost::begin(range))
, m_end(boost::end(range))
, m_iterator(boost::end(range))
{}
// There is no default constructor
enumerating_iterator() = delete;
inline reference dereference() const
{
constexpr difference_type zero = 0;
const std::size_t index = (std::max)(zero, std::distance(m_begin, m_iterator));
const value_with_index result{index, *m_iterator};
return result;
}
inline difference_type distance_to(enumerating_iterator const& other) const
{
return std::distance(other.m_iterator, m_iterator);
}
inline bool equal(enumerating_iterator const& other) const
{
return
m_begin == other.m_begin
&& m_end == other.m_end
&& m_iterator == other.m_iterator;
}
inline void increment()
{
++m_iterator;
}
inline void decrement()
{
--m_iterator;
}
inline void advance(difference_type n)
{
std::advance(m_iterator, n);
}
const typename boost::range_iterator<Range>::type m_begin;
const typename boost::range_iterator<Range>::type m_end;
typename boost::range_iterator<Range>::type m_iterator;
};
public:
using iterator = enumerating_iterator;
using const_iterator = enumerating_iterator;
explicit inline enumerated_view(Range& range)
: m_begin(range)
, m_end(range, true)
{}
inline iterator begin() const { return m_begin; }
inline iterator end() const { return m_end; }
private:
const iterator m_begin;
const iterator m_end;
};
// Helper function to create the enumerated view, for a const range
template <typename Range>
inline auto enumerate(Range const& range)
{
return util::enumerated_view<Range const>(range);
}
// Helper function to create the enumerated view, for a non-const range
template <typename Range>
inline auto enumerate(Range& range)
{
return util::enumerated_view<Range>(range);
}
}}} // boost::geometry::util
#endif // BOOST_GEOMETRY_VIEWS_ENUMERATE_VIEW_HPP

View File

@ -49,3 +49,4 @@ endif()
add_subdirectory(algorithms)
add_subdirectory(util)
add_subdirectory(views)

16
test/views/CMakeLists.txt Normal file
View File

@ -0,0 +1,16 @@
# Boost.Geometry
# Copyright (c) 2024 Barend Gehrels, Amsterdam, the Netherlands.
# Use, modification and distribution is subject to the Boost Software License,
# Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
foreach(item IN ITEMS
box_view
closeable_view
enumerate_view
random_access_view
reversible_closeable
reversible_view
segment_view)
boost_geometry_add_unit_test("views" ${item})
endforeach()

View File

@ -17,6 +17,7 @@ test-suite boost-geometry-views
:
[ run box_view.cpp : : : : views_box_view ]
[ run closeable_view.cpp : : : : views_closeable_view ]
[ run enumerate_view.cpp : : : : views_enumerate_view ]
[ run random_access_view.cpp : : : : views_random_access_view ]
[ run reversible_closeable.cpp : : : : views_reversible_closeable ]
[ run reversible_view.cpp : : : : views_reversible_view ]

View File

@ -0,0 +1,74 @@
// Boost.Geometry
// Unit Test
// Copyright (c) 2024 Barend Gehrels, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <string>
#include <vector>
#include <boost/geometry/views/enumerate_view.hpp>
#include <boost/test/included/test_exec_monitor.hpp>
void test_const()
{
const std::vector<std::string> vec{"cat", "mouse", "squirrel"};
std::size_t test_index = 0;
for (auto const& item : boost::geometry::util::enumerate(vec))
{
BOOST_CHECK_EQUAL(item.index, test_index++);
switch(item.index)
{
case 0 : BOOST_CHECK_EQUAL(item.value, "cat"); break;
case 1 : BOOST_CHECK_EQUAL(item.value, "mouse"); break;
case 2 : BOOST_CHECK_EQUAL(item.value, "squirrel"); break;
}
}
}
void test_non_const()
{
std::vector<std::string> vec{"Amsterdam", "London", "Paris"};
std::size_t index_sum = 0;
for (auto const& item : boost::geometry::util::enumerate(vec))
{
item.value += " is a city";
index_sum += item.index;
}
BOOST_CHECK_EQUAL(vec[0], "Amsterdam is a city");
BOOST_CHECK_EQUAL(vec[1], "London is a city");
BOOST_CHECK_EQUAL(vec[2], "Paris is a city");
BOOST_CHECK_EQUAL(index_sum, 3);
}
// Verifies the usage of the enumerate_view with C++17 structured bindings
// See https://en.cppreference.com/w/cpp/ranges/enumerate_view
void test_cpp17()
{
#if __cplusplus >= 201703L
std::vector<int> numbers{1, 3, 5, 7};
std::size_t sum_indexes = 0;
int sum_numbers = 0;
for (auto const [index, num] : boost::geometry::util::enumerate(numbers))
{
sum_indexes += index;
sum_numbers += num;
// num is mutable even with const, which does not propagate to reference
num++;
}
BOOST_CHECK_EQUAL(sum_indexes, 6);
BOOST_CHECK_EQUAL(sum_numbers, 16);
BOOST_CHECK_EQUAL(numbers[0], 2);
#endif
}
int test_main(int, char* [])
{
test_const();
test_non_const();
test_cpp17();
return 0;
}