Skip to content
Snippets Groups Projects
Commit bdafe9f5 authored by Carsten Gräser's avatar Carsten Gräser
Browse files

Merge branch 'feature/iteratorrange-with-sentinel' into 'master'

Add sentinel support to IteratorRange

See merge request core/dune-common!1515
parents 58d72453 2dcd75e5
No related branches found
No related tags found
1 merge request!1515Add sentinel support to IteratorRange
Pipeline #77558 waiting for manual action
...@@ -28,6 +28,9 @@ SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception ...@@ -28,6 +28,9 @@ SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception
## C++: Changelog ## C++: Changelog
- `Dune::IteratorRange` now supports different types for begin and end iterator
to model C++20's sentinel terminated ranges.
- Add preprocessor macro `DUNE_FORCE_INLINE` as a portable attribute to force inlining of functions (if supported). - Add preprocessor macro `DUNE_FORCE_INLINE` as a portable attribute to force inlining of functions (if supported).
- Add `bit_width` and `countl_zero` overloads for `bigunsignedint` objects. - Add `bit_width` and `countl_zero` overloads for `bigunsignedint` objects.
......
...@@ -14,10 +14,14 @@ namespace Dune { ...@@ -14,10 +14,14 @@ namespace Dune {
* existing containers that lack a standard begin(), end() * existing containers that lack a standard begin(), end()
* pair of member functions. * pair of member functions.
* *
* This supports to use a different type for the end iterator
* (a so called sentinel).
*
* \tparam Iterator The type of iterator * \tparam Iterator The type of iterator
* \tparam Sentinel The type of the end iterator (default=Iterator)
* \ingroup CxxUtilities * \ingroup CxxUtilities
*/ */
template<typename Iterator> template<typename Iterator, typename Sentinel=Iterator>
class IteratorRange class IteratorRange
{ {
...@@ -26,6 +30,9 @@ namespace Dune { ...@@ -26,6 +30,9 @@ namespace Dune {
//! The iterator belonging to this range. //! The iterator belonging to this range.
typedef Iterator iterator; typedef Iterator iterator;
//! The iterator belonging to this range.
typedef Sentinel sentinel;
//! The iterator belonging to this range. //! The iterator belonging to this range.
/** /**
* This typedef is here mainly for compatibility reasons. * This typedef is here mainly for compatibility reasons.
...@@ -33,9 +40,9 @@ namespace Dune { ...@@ -33,9 +40,9 @@ namespace Dune {
typedef Iterator const_iterator; typedef Iterator const_iterator;
//! Constructs an iterator range on [begin,end). //! Constructs an iterator range on [begin,end).
IteratorRange(const Iterator& begin, const Iterator& end) IteratorRange(const Iterator& begin, const Sentinel& end)
: _begin(begin) : begin_(begin)
, _end(end) , end_(end)
{} {}
//! Default constructor, relies on iterators being default-constructible. //! Default constructor, relies on iterators being default-constructible.
...@@ -45,19 +52,19 @@ namespace Dune { ...@@ -45,19 +52,19 @@ namespace Dune {
//! Returns an iterator pointing to the begin of the range. //! Returns an iterator pointing to the begin of the range.
iterator begin() const iterator begin() const
{ {
return _begin; return begin_;
} }
//! Returns an iterator pointing past the end of the range. //! Returns an iterator pointing past the end of the range.
iterator end() const sentinel end() const
{ {
return _end; return end_;
} }
private: private:
Iterator _begin; Iterator begin_;
Iterator _end; Sentinel end_;
}; };
......
...@@ -92,7 +92,7 @@ auto checkSameRange(R1&& r1, BeginIt2&& it2, EndIt2&& end2) ...@@ -92,7 +92,7 @@ auto checkSameRange(R1&& r1, BeginIt2&& it2, EndIt2&& end2)
{ {
auto it1 = r1.begin(); auto it1 = r1.begin();
auto end1 = r1.end(); auto end1 = r1.end();
for(; (it1 < end1) and (it2 < end2); ++it1, ++it2) for(; (it1 != end1) and (it2 != end2); ++it1, ++it2)
if (*it1 != *it2) if (*it1 != *it2)
return false; return false;
if ((it1 != end1) or (it2 != end2)) if ((it1 != end1) or (it2 != end2))
...@@ -387,11 +387,64 @@ auto testSparseRange() ...@@ -387,11 +387,64 @@ auto testSparseRange()
// An empty class tagging the end of a range
class SentinelIterator
{};
// Classical use case for sentinels: An iterator for
// a null-terminated string. Using a sentinel allows
// to implement a range without a linear scan to find
// the end or storing an additional isEnd flag in the
// iterator.
class NullTerminatedStringIterator
{
public:
NullTerminatedStringIterator(char* p)
: p_(p)
{}
NullTerminatedStringIterator& operator++()
{
++p_;
return *this;
}
char& operator*()
{
return *p_;
}
friend bool operator==(const NullTerminatedStringIterator& it, const SentinelIterator& end)
{
return (*it.p_) == 0;
}
private:
char* p_;
};
Dune::TestSuite testIteratorRange()
{
Dune::TestSuite suite("Check IteratorRange with sentinel");
// Check sentinel terminated range for null-terminated string
char testStr[] = "FooBar";
auto range_sentinel = Dune::IteratorRange(NullTerminatedStringIterator(testStr), SentinelIterator());
suite.check(checkSameRange(range_sentinel, std::string_view(testStr)));
return suite;
}
int main() int main()
{ {
// Check IsIterable<> for https://gitlab.dune-project.org/core/dune-common/issues/58 // Check IsIterable<> for https://gitlab.dune-project.org/core/dune-common/issues/58
static_assert(Dune::IsIterable< std::array<int, 3> >::value, "std::array<int> must be a range"); static_assert(Dune::IsIterable< std::array<int, 3> >::value, "std::array<int> must be a range");
static_assert(Dune::IsIterable< Dune::IteratorRange<int*> >::value, "IteratorRange must be a range"); static_assert(Dune::IsIterable< Dune::IteratorRange<int*> >::value, "IteratorRange must be a range");
// static_assert(Dune::IsIterable< Dune::IteratorRange<int*, void*> >::value, "IteratorRange must be a range");
static_assert(!Dune::IsIterable< int >::value, "int must not be a range"); static_assert(!Dune::IsIterable< int >::value, "int must not be a range");
Dune::TestSuite suite; Dune::TestSuite suite;
...@@ -505,6 +558,8 @@ int main() ...@@ -505,6 +558,8 @@ int main()
suite.subTest(testSparseRange()); suite.subTest(testSparseRange());
suite.subTest(testIteratorRange());
return suite.exit(); return suite.exit();
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment