Skip to content

Commit

Permalink
Add enumerate to prepare for 17 and 23
Browse files Browse the repository at this point in the history
  • Loading branch information
barendgehrels committed Apr 21, 2024
1 parent 713fe69 commit 3dbee5d
Show file tree
Hide file tree
Showing 6 changed files with 276 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
#include <boost/geometry/algorithms/detail/sections/section_box_policies.hpp>

#include <boost/geometry/views/detail/closed_clockwise_view.hpp>
#include <boost/geometry/views/enumerate_view.hpp>
#include <boost/geometry/util/for_each_with_index.hpp>
#include <boost/geometry/util/range.hpp>

Expand Down Expand Up @@ -376,16 +377,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
Expand Down Expand Up @@ -1091,30 +1094,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 const p = properties(ring, m_strategy);
if (p.valid)
{
properties p = properties(ring, m_strategy);
if (p.valid)
{
ring_identifier id(0, index, -1);
selected[id] = p;
}
ring_identifier id(0, enumerated.index, -1);
selected[id] = p;
}
});
}
}

// Select all created rings
for_each_with_index(traversed_rings, [&](std::size_t index, auto const& ring)
for (auto const& enumerated : util::enumerate(traversed_rings))
{
auto const& ring = enumerated.value;
properties p = properties(ring, m_strategy);
if (p.valid)
{
properties p = properties(ring, m_strategy);
if (p.valid)
{
ring_identifier id(2, index, -1);
selected[id] = p;
}
});
ring_identifier id(2, enumerated.index, -1);
selected[id] = p;
}
}

detail::overlay::assign_parents<overlay_buffer>(offsetted_rings, traversed_rings,
selected, m_strategy);
Expand Down
158 changes: 158 additions & 0 deletions include/boost/geometry/views/enumerate_view.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
// 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:
// Private iterator implementation
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 should include the range it handles
explicit inline enumerating_iterator(Range& range)
: m_iterator(boost::begin(range))
, m_begin(boost::begin(range))
, m_end(boost::end(range))
{}

// Constructor to indicate the end of a range
explicit inline enumerating_iterator(Range& range, bool)
: m_iterator(boost::end(range))
, m_begin(boost::begin(range))
, m_end(boost::end(range))
{}

// There is no default constructor
enumerating_iterator() = delete;

inline reference dereference() const
{
const std::size_t index = std::max(0L, 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>
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>
auto enumerate(Range& range)
{
return util::enumerated_view<Range>(range);
}

}}} // boost::geometry::util


#endif // BOOST_GEOMETRY_VIEWS_ENUMERATE_VIEW_HPP
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,4 @@ endif()

add_subdirectory(algorithms)
add_subdirectory(util)
add_subdirectory(views)
16 changes: 16 additions & 0 deletions test/views/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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()
1 change: 1 addition & 0 deletions test/views/Jamfile
Original file line number Diff line number Diff line change
Expand Up @@ -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 ]
Expand Down
74 changes: 74 additions & 0 deletions test/views/enumerate_view.cpp
Original file line number Diff line number Diff line change
@@ -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;
}

0 comments on commit 3dbee5d

Please sign in to comment.