BLI: add utility to simplify creating proper random access iterator #118113
|
@ -41,6 +41,7 @@
|
|||
#include <iosfwd>
|
||||
|
||||
#include "BLI_assert.h"
|
||||
#include "BLI_random_access_iterator_mixin.hh"
|
||||
|
||||
namespace blender {
|
||||
|
||||
|
@ -65,13 +66,11 @@ class IndexRange {
|
|||
BLI_assert(size >= 0);
|
||||
}
|
||||
|
||||
class Iterator {
|
||||
class Iterator : public iterator::RandomAccessIteratorMixin<Iterator> {
|
||||
public:
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = int64_t;
|
||||
using pointer = const int64_t *;
|
||||
using reference = const int64_t &;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using reference = int64_t;
|
||||
|
||||
private:
|
||||
int64_t current_;
|
||||
|
@ -79,38 +78,15 @@ class IndexRange {
|
|||
public:
|
||||
constexpr explicit Iterator(int64_t current) : current_(current) {}
|
||||
|
||||
constexpr Iterator &operator++()
|
||||
{
|
||||
current_++;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr Iterator operator++(int)
|
||||
{
|
||||
Iterator copied_iterator = *this;
|
||||
++(*this);
|
||||
return copied_iterator;
|
||||
}
|
||||
|
||||
constexpr friend bool operator!=(const Iterator &a, const Iterator &b)
|
||||
{
|
||||
return a.current_ != b.current_;
|
||||
}
|
||||
|
||||
constexpr friend bool operator==(const Iterator &a, const Iterator &b)
|
||||
{
|
||||
return a.current_ == b.current_;
|
||||
}
|
||||
|
||||
constexpr friend int64_t operator-(const Iterator &a, const Iterator &b)
|
||||
{
|
||||
return a.current_ - b.current_;
|
||||
}
|
||||
|
||||
constexpr int64_t operator*() const
|
||||
{
|
||||
return current_;
|
||||
}
|
||||
|
||||
const int64_t &iter_prop() const
|
||||
{
|
||||
return current_;
|
||||
}
|
||||
};
|
||||
|
||||
constexpr Iterator begin() const
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "BLI_random_access_iterator_mixin.hh"
|
||||
#include "BLI_span.hh"
|
||||
|
||||
namespace blender {
|
||||
|
@ -70,7 +71,12 @@ template<typename T, typename BaseT> class OffsetSpan {
|
|||
return {offset_, data_.slice(start, size)};
|
||||
}
|
||||
|
||||
class Iterator {
|
||||
class Iterator : public iterator::RandomAccessIteratorMixin<Iterator> {
|
||||
public:
|
||||
using value_type = T;
|
||||
using pointer = const T *;
|
||||
using reference = T;
|
||||
|
||||
private:
|
||||
T offset_;
|
||||
const BaseT *data_;
|
||||
|
@ -78,21 +84,14 @@ template<typename T, typename BaseT> class OffsetSpan {
|
|||
public:
|
||||
Iterator(const T offset, const BaseT *data) : offset_(offset), data_(data) {}
|
||||
|
||||
Iterator &operator++()
|
||||
{
|
||||
data_++;
|
||||
return *this;
|
||||
}
|
||||
|
||||
T operator*() const
|
||||
{
|
||||
return T(*data_) + offset_;
|
||||
}
|
||||
|
||||
friend bool operator!=(const Iterator &a, const Iterator &b)
|
||||
const BaseT *const &iter_prop() const
|
||||
{
|
||||
BLI_assert(a.offset_ == b.offset_);
|
||||
return a.data_ != b.data_;
|
||||
return data_;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,133 @@
|
|||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iterator>
|
||||
|
||||
namespace blender::iterator {
|
||||
|
||||
/**
|
||||
* Simplifies implementing a random-access-iterator.
|
||||
*
|
||||
* The actual iterator should derive from this class publicly. Additionally, it has to provide a
|
||||
* const `iter_prop` method which returns a reference to the internal property that corresponds to
|
||||
* the current position. This is typically a pointer or an index.
|
||||
*
|
||||
* Implementing some random-access-iterator is generally quite simple but requires a lot of
|
||||
* boilerplate code because algorithms expect many operators to work on the iterator type.
|
||||
* They are expected to behave similarly to pointers and thus have to implement many of the same
|
||||
* operators.
|
||||
*/
|
||||
template<typename Derived> class RandomAccessIteratorMixin {
|
||||
public:
|
||||
using iterator_category = std::random_access_iterator_tag;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
|
||||
constexpr friend Derived &operator++(Derived &a)
|
||||
{
|
||||
++a.iter_prop_mutable();
|
||||
return a;
|
||||
}
|
||||
|
||||
constexpr friend Derived operator++(Derived &a, int)
|
||||
{
|
||||
Derived copy = a;
|
||||
++a;
|
||||
return copy;
|
||||
}
|
||||
|
||||
constexpr friend Derived &operator--(Derived &a)
|
||||
{
|
||||
--a.iter_prop_mutable();
|
||||
return a;
|
||||
}
|
||||
|
||||
constexpr friend Derived operator--(Derived &a, int)
|
||||
{
|
||||
Derived copy = a;
|
||||
--a;
|
||||
return copy;
|
||||
}
|
||||
|
||||
constexpr friend Derived &operator+=(Derived &a, const std::ptrdiff_t n)
|
||||
{
|
||||
a.iter_prop_mutable() += n;
|
||||
return a;
|
||||
}
|
||||
|
||||
constexpr friend Derived &operator-=(Derived &a, const std::ptrdiff_t n)
|
||||
{
|
||||
a.iter_prop_mutable() -= n;
|
||||
return a;
|
||||
}
|
||||
|
||||
constexpr friend Derived operator+(const Derived &a, const std::ptrdiff_t n)
|
||||
{
|
||||
Derived copy = a;
|
||||
copy.iter_prop_mutable() += n;
|
||||
return copy;
|
||||
}
|
||||
|
||||
constexpr friend Derived operator-(const Derived &a, const std::ptrdiff_t n)
|
||||
{
|
||||
Derived copy = a;
|
||||
copy.iter_prop_mutable() -= n;
|
||||
return copy;
|
||||
}
|
||||
|
||||
constexpr friend auto operator-(const Derived &a, const Derived &b)
|
||||
{
|
||||
return a.iter_prop() - b.iter_prop();
|
||||
}
|
||||
|
||||
constexpr friend bool operator!=(const Derived &a, const Derived &b)
|
||||
{
|
||||
return a.iter_prop() != b.iter_prop();
|
||||
}
|
||||
|
||||
constexpr friend bool operator==(const Derived &a, const Derived &b)
|
||||
{
|
||||
return a.iter_prop() == b.iter_prop();
|
||||
}
|
||||
|
||||
constexpr friend bool operator<(const Derived &a, const Derived &b)
|
||||
{
|
||||
return a.iter_prop() < b.iter_prop();
|
||||
}
|
||||
|
||||
constexpr friend bool operator>(const Derived &a, const Derived &b)
|
||||
{
|
||||
return a.iter_prop() > b.iter_prop();
|
||||
}
|
||||
|
||||
constexpr friend bool operator<=(const Derived &a, const Derived &b)
|
||||
{
|
||||
return a.iter_prop() <= b.iter_prop();
|
||||
}
|
||||
|
||||
constexpr friend bool operator>=(const Derived &a, const Derived &b)
|
||||
{
|
||||
return a.iter_prop() >= b.iter_prop();
|
||||
}
|
||||
|
||||
constexpr decltype(auto) operator[](const std::ptrdiff_t i)
|
||||
{
|
||||
return *(*static_cast<Derived *>(this) + i);
|
||||
}
|
||||
|
||||
constexpr decltype(auto) operator[](const std::ptrdiff_t i) const
|
||||
{
|
||||
return *(*static_cast<const Derived *>(this) + i);
|
||||
}
|
||||
|
||||
auto &iter_prop_mutable()
|
||||
{
|
||||
const auto &const_iter_prop = static_cast<const Derived *>(this)->iter_prop();
|
||||
return const_cast<std::remove_const_t<std::remove_reference_t<decltype(const_iter_prop)>> &>(
|
||||
const_iter_prop);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace blender::iterator
|
|
@ -330,6 +330,7 @@ set(SRC
|
|||
BLI_quadric.h
|
||||
BLI_rand.h
|
||||
BLI_rand.hh
|
||||
BLI_random_access_iterator_mixin.hh
|
||||
BLI_range.h
|
||||
BLI_rect.h
|
||||
BLI_resource_scope.hh
|
||||
|
@ -545,6 +546,7 @@ if(WITH_GTESTS)
|
|||
tests/BLI_path_util_test.cc
|
||||
tests/BLI_polyfill_2d_test.cc
|
||||
tests/BLI_pool_test.cc
|
||||
tests/BLI_random_access_iterator_mixin_test.cc
|
||||
tests/BLI_ressource_strings.h
|
||||
tests/BLI_serialize_test.cc
|
||||
tests/BLI_session_uid_test.cc
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
JacquesLucke marked this conversation as resolved
Outdated
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "testing/testing.h"
|
||||
|
||||
#include "BLI_random_access_iterator_mixin.hh"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
namespace blender::iterator::tests {
|
||||
|
||||
template<typename T>
|
||||
struct DoublingIterator : public RandomAccessIteratorMixin<DoublingIterator<T>> {
|
||||
private:
|
||||
const T *data_;
|
||||
|
||||
public:
|
||||
DoublingIterator(const T *data) : data_(data) {}
|
||||
|
||||
T operator*() const
|
||||
{
|
||||
return *data_ * 2;
|
||||
}
|
||||
|
||||
const T *const &iter_prop() const
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
};
|
||||
|
||||
TEST(random_access_iterator_mixin, DoublingIterator)
|
||||
{
|
||||
std::array<int, 4> my_array = {3, 6, 1, 2};
|
||||
|
||||
const DoublingIterator<int> begin = DoublingIterator<int>(&*my_array.begin());
|
||||
const DoublingIterator<int> end = begin + my_array.size();
|
||||
|
||||
Vector<int> values;
|
||||
for (DoublingIterator<int> it = begin; it != end; ++it) {
|
||||
values.append(*it);
|
||||
}
|
||||
|
||||
EXPECT_EQ(values.size(), 4);
|
||||
EXPECT_EQ(values[0], 6);
|
||||
EXPECT_EQ(values[1], 12);
|
||||
EXPECT_EQ(values[2], 2);
|
||||
EXPECT_EQ(values[3], 4);
|
||||
}
|
||||
|
||||
} // namespace blender::iterator::tests
|
Loading…
Reference in New Issue
2024