diff --git a/SimoxUtility/iterator.h b/SimoxUtility/iterator.h new file mode 100644 index 0000000000000000000000000000000000000000..14e76f038456894270581e2346fe4c50c00c1c9e --- /dev/null +++ b/SimoxUtility/iterator.h @@ -0,0 +1,5 @@ +#pragma once + +// This file is generated! + +#include "iterator/xy_index_range_iterator.h" diff --git a/SimoxUtility/iterator/xy_index_range_iterator.h b/SimoxUtility/iterator/xy_index_range_iterator.h new file mode 100644 index 0000000000000000000000000000000000000000..d20d5c2290410ba41cdad0822ccfe35c7fa81573 --- /dev/null +++ b/SimoxUtility/iterator/xy_index_range_iterator.h @@ -0,0 +1,87 @@ +#pragma once + +#include <iterator> + +namespace simox::iterator { + + +struct Point { + int x; + int y; + + Point(int x, int y) : x(x), y(y) {} + Point() = default; + + bool operator==(const Point &rhs) const { return x == rhs.x && y == rhs.y; } + + static Point zero() { return {0, 0}; } +}; + +/** +* The XYIndexRangeIterator class. +* +* The aim of this class is to provide a convenient way to iterate over 2D arrays +* This class provides a 2D iterator that returns all indices to the 2D array, e.g. +* +* My2DArray arr(10, 20); +* for(auto [x,y] : XYIndexRangeIterator(arr)){ +* auto val = arr.at(x,y); +* // do the magic +* } +* +* This is hightly inspired by cartographer::mapping::XYIndexRangeIterator +* see: https://github.com/cartographer-project/cartographer/blob/master/cartographer/mapping/2d/xy_index.h +*/ +template <typename IndexType = Point> +class XYIndexRangeIterator + : public std::iterator<std::input_iterator_tag, IndexType> { +public: + // Constructs a new iterator for the specified range. + XYIndexRangeIterator(const IndexType &min_xy_index, + const IndexType &max_xy_index) + : min_xy_index(min_xy_index), max_xy_index(max_xy_index), + xy_index(min_xy_index) {} + + // Constructs a new iterator for everything contained in 'cell_limits'. + explicit XYIndexRangeIterator(const IndexType &cell_limits) + : XYIndexRangeIterator(IndexType::zero(), + IndexType(cell_limits.x - 1, cell_limits.y - 1)) {} + + XYIndexRangeIterator &operator++() { + if (xy_index.x < max_xy_index.x) { + ++xy_index.x; + } else { + xy_index.x = min_xy_index.x; + ++xy_index.y; + } + return *this; + } + + IndexType &operator*() { return xy_index; } + + bool operator==(const XYIndexRangeIterator &other) const { + return xy_index == other.xy_index; + } + + bool operator!=(const XYIndexRangeIterator &other) const { + return !operator==(other); + } + + XYIndexRangeIterator begin() const { + return XYIndexRangeIterator(min_xy_index, max_xy_index); + } + + XYIndexRangeIterator end() const { + XYIndexRangeIterator it = begin(); + it.xy_index = IndexType(min_xy_index.x, max_xy_index.y + 1); + return it; + } + +private: + IndexType min_xy_index; + IndexType max_xy_index; + IndexType xy_index; +}; + + +} // namespace simox::iterator diff --git a/SimoxUtility/tests/CMakeLists.txt b/SimoxUtility/tests/CMakeLists.txt index 426368c785fafa3be8733dfda996f24b14a70d82..b9a06183286cbbb0171b4fb31bd89420042a8707 100644 --- a/SimoxUtility/tests/CMakeLists.txt +++ b/SimoxUtility/tests/CMakeLists.txt @@ -48,3 +48,4 @@ ADD_SUBDIRECTORY(meta) ADD_SUBDIRECTORY(shapes) ADD_SUBDIRECTORY(simox) ADD_SUBDIRECTORY(backport) +ADD_SUBDIRECTORY(iterator) diff --git a/SimoxUtility/tests/iterator/CMakeLists.txt b/SimoxUtility/tests/iterator/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..a05124858fdaae3198f0efd6bce3f58c74de39d4 --- /dev/null +++ b/SimoxUtility/tests/iterator/CMakeLists.txt @@ -0,0 +1,2 @@ + +ADD_SU_TEST( XYIndexRangeIterator ) diff --git a/SimoxUtility/tests/iterator/XYIndexRangeIterator.cpp b/SimoxUtility/tests/iterator/XYIndexRangeIterator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bd4a58169a097e8f5ac0f51263c9adc34c2ce34d --- /dev/null +++ b/SimoxUtility/tests/iterator/XYIndexRangeIterator.cpp @@ -0,0 +1,102 @@ +/* + * This file is part of ArmarX. + * + * ArmarX is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ArmarX is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * @package + * @author Fabian Reister ( fabian dot reister at kit dot edu ) + * @date 2021 + * @copyright http://www.gnu.org/licenses/gpl-2.0.txt + * GNU General Public License + */ + +#define BOOST_TEST_MODULE SimoxUtility/iterator/XYIndexRangeIterator + +#include <vector> +#include <iostream> +#include <numeric> +#include <algorithm> + +#include <boost/test/included/unit_test.hpp> +#include <boost/test/unit_test_suite.hpp> + +#include <SimoxUtility/iterator.h> + + +// BOOST_AUTO_TEST_SUITE(XYIndexRangeIterator) + + +BOOST_AUTO_TEST_CASE(test_loop) +{ + // dimensions + constexpr int N = 10; + constexpr int M = 20; + + // create 2D vector of size N*M + const auto v = std::vector<std::vector<int>>(M, std::vector<int>(N, 1)); + + const auto range_it = simox::iterator::XYIndexRangeIterator(simox::iterator::Point{N, M}); + + // max counters for test checks + int x_max = 0; + int y_max = 0; + int cnt = 0; + + for(const auto& [x,y] : range_it){ + x_max = std::max(x, x_max); + y_max = std::max(y, y_max); + + // TODO(fabian.reister): access v + + cnt++; + } + + BOOST_CHECK_EQUAL(x_max, N-1); + BOOST_CHECK_EQUAL(y_max, M-1); + BOOST_CHECK_EQUAL(cnt, N*M); +} + + +BOOST_AUTO_TEST_CASE(test_foreach) +{ + // dimensions + constexpr int N = 10; + constexpr int M = 20; + + // create 2D vector of size N*M + const auto v = std::vector<std::vector<int>>(M, std::vector<int>(N, 1)); + + const auto range_it = simox::iterator::XYIndexRangeIterator(simox::iterator::Point{N, M}); + + int x_max = 0; + int y_max = 0; + int cnt = 0; + + std::for_each(range_it.begin(), range_it.end(), [&](const auto& pnt){ + const auto& [x,y] = pnt; + + x_max = std::max(x, x_max); + y_max = std::max(y, y_max); + + // TODO(fabian.reister): access v + + + cnt++; + }); + + BOOST_CHECK_EQUAL(x_max, N-1); + BOOST_CHECK_EQUAL(y_max, M-1); + BOOST_CHECK_EQUAL(cnt, N*M); +} + +// BOOST_AUTO_TEST_SUITE_END()