blender/intern/cycles/util/random_access_iterator_mixin.h
Jacques Lucke cefe09dc2d Refactor: Cycles: use more complete random access iterator for unique_ptr_vector
Cycles has `unique_ptr_vector` which is a vector of `unique_ptr` with the
special property that when iterating over it, it actually iterates over `T *`
instead of `unique_ptr<T>`. For that it implements a custom iterator. While this
works fine currently, there are problems with C++20. That's because when C++20
concepts are used, the implementation of the iterator is checked more thoroughly
(i.e. it checks if all the expected methods are available). Currently, they are
not.

The solution in this patch is to copy over `BLI_random_access_iterator_mixin.hh`
into cycles code and use that to build the custom iterator with all the required
methods available. This also reduces the boilerplate that is specific to
`unique_ptr_vector`.

Pull Request: https://projects.blender.org/blender/blender/pulls/152940
2026-01-16 18:15:11 +01:00

133 lines
3.3 KiB
C++

/* SPDX-FileCopyrightText: 2026 Blender Authors
*
* SPDX-License-Identifier: Apache-2.0 */
#pragma once
#include <iterator>
CCL_NAMESPACE_BEGIN
/**
* 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 random_access_iterator_mixin {
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);
}
};
CCL_NAMESPACE_END