Skip to content

Commit 42af8b0

Browse files
committed
give up on increment/decrement: requires friend class
Signed-off-by: Martijn Govers <[email protected]>
1 parent bc61883 commit 42af8b0

File tree

3 files changed

+102
-11
lines changed

3 files changed

+102
-11
lines changed

power_grid_model_c/power_grid_model/include/power_grid_model/common/grouped_index_vector.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,8 @@ class SparseGroupedIdxVector {
177177
class DenseGroupedIdxVector {
178178
private:
179179
class GroupIterator : public IteratorFacade {
180+
friend class IteratorFacade; // to expose increment and decrement
181+
180182
public:
181183
using iterator = GroupIterator;
182184
using const_iterator = std::add_const_t<GroupIterator>;

power_grid_model_c/power_grid_model/include/power_grid_model/common/iterator_facade.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,15 @@ class IteratorFacade {
4646
}
4747

4848
template <typename Self> constexpr std::add_lvalue_reference_t<Self> operator++(this Self& self) {
49-
if constexpr (requires { self.increment(); }) {
49+
if constexpr (requires { self.increment(); }) { // NOTE: IteratorFacade should be a friend class
5050
self.increment();
5151
} else {
5252
return (self += 1);
5353
}
5454
return self;
5555
}
5656
template <typename Self> constexpr std::add_lvalue_reference_t<Self> operator--(this Self& self) {
57-
if constexpr (requires { self.decrement(); }) {
57+
if constexpr (requires { self.decrement(); }) { // NOTE: IteratorFacade should be a friend class
5858
self.decrement();
5959
} else {
6060
return (self += -1);

tests/cpp_unit_tests/test_iterator_facade.cpp

Lines changed: 98 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,33 @@
77

88
#include <doctest/doctest.h>
99

10+
#include <optional>
11+
1012
namespace {
1113
using power_grid_model::Idx;
1214
using power_grid_model::IdxRange;
1315
using power_grid_model::IdxVector;
1416
using power_grid_model::IteratorFacade;
1517
using power_grid_model::detail::iterator_facadeable_c;
1618

17-
template <typename UnderlyingType> class BaseTestIterator : public IteratorFacade {
19+
enum class IteratorFacadeableCalls : Idx {
20+
none = 0,
21+
dereference = 1,
22+
advance = 2,
23+
distance_to = 3,
24+
increment = 4,
25+
decrement = 5,
26+
};
27+
28+
struct without_increment_decrement_t {};
29+
struct with_increment_decrement_t {};
30+
31+
template <typename T>
32+
concept advance_type_c = std::same_as<T, without_increment_decrement_t> || std::same_as<T, with_increment_decrement_t>;
33+
34+
template <advance_type_c advance_type_t, typename UnderlyingType> class BaseTestIterator : public IteratorFacade {
35+
friend class IteratorFacade;
36+
1837
public:
1938
using underlying = UnderlyingType;
2039

@@ -23,38 +42,84 @@ template <typename UnderlyingType> class BaseTestIterator : public IteratorFacad
2342
using pointer = underlying::pointer;
2443
using reference = underlying::reference;
2544

45+
static constexpr auto increment_style = std::same_as<advance_type_t, with_increment_decrement_t>
46+
? IteratorFacadeableCalls::increment
47+
: IteratorFacadeableCalls::advance;
48+
static constexpr auto decrement_style = std::same_as<advance_type_t, with_increment_decrement_t>
49+
? IteratorFacadeableCalls::decrement
50+
: IteratorFacadeableCalls::advance;
51+
52+
mutable std::optional<IteratorFacadeableCalls> last_call;
53+
2654
constexpr BaseTestIterator(std::remove_cvref_t<underlying> it) : IteratorFacade{*this}, it_{std::move(it)} {}
2755

28-
constexpr auto operator*() -> reference { return *it_; }
29-
constexpr auto operator*() const -> std::add_lvalue_reference_t<std::add_const_t<value_type>> { return *it_; }
56+
constexpr auto operator*() -> reference {
57+
last_call = IteratorFacadeableCalls::dereference;
58+
return *it_;
59+
}
60+
constexpr auto operator*() const -> std::add_lvalue_reference_t<std::add_const_t<value_type>> {
61+
last_call = IteratorFacadeableCalls::dereference;
62+
return *it_;
63+
}
3064

3165
friend constexpr auto operator<=>(BaseTestIterator const& first,
3266
BaseTestIterator const& second) -> std::strong_ordering {
67+
first.last_call = IteratorFacadeableCalls::distance_to;
3368
return *first.it_ <=> *second.it_;
3469
}
3570

36-
constexpr auto operator+=(difference_type n) -> std::add_lvalue_reference_t<BaseTestIterator> {
71+
constexpr decltype(auto) operator+=(difference_type n) {
72+
last_call = IteratorFacadeableCalls::advance;
3773
it_ += n;
3874
return *this;
3975
}
4076
friend constexpr auto operator-(BaseTestIterator const& first, BaseTestIterator const& second) -> difference_type {
77+
first.last_call = IteratorFacadeableCalls::distance_to;
4178
return first.it_ - second.it_;
4279
}
4380

4481
private:
4582
underlying it_;
83+
84+
constexpr void increment()
85+
requires std::same_as<advance_type_t, with_increment_decrement_t>
86+
{
87+
last_call = IteratorFacadeableCalls::increment;
88+
++it_;
89+
}
90+
constexpr void decrement()
91+
requires std::same_as<advance_type_t, with_increment_decrement_t>
92+
{
93+
last_call = IteratorFacadeableCalls::decrement;
94+
--it_;
95+
}
4696
};
4797

48-
using TestIdxVectorIterator = BaseTestIterator<typename IdxVector::iterator>;
49-
using TestIdxVectorConstIterator = BaseTestIterator<typename IdxVector::const_iterator>;
98+
using TestIdxVectorIterator = BaseTestIterator<without_increment_decrement_t, typename IdxVector::iterator>;
99+
using TestIdxVectorConstIterator = BaseTestIterator<without_increment_decrement_t, typename IdxVector::const_iterator>;
100+
using TestIdxVectorIteratorWithIncDec = BaseTestIterator<with_increment_decrement_t, typename IdxVector::iterator>;
101+
using TestIdxVectorConstIteratorWithIncDec =
102+
BaseTestIterator<with_increment_decrement_t, typename IdxVector::const_iterator>;
50103

51104
static_assert(iterator_facadeable_c<TestIdxVectorIterator>);
52105
static_assert(iterator_facadeable_c<TestIdxVectorConstIterator>);
106+
static_assert(iterator_facadeable_c<TestIdxVectorIteratorWithIncDec>);
107+
static_assert(iterator_facadeable_c<TestIdxVectorConstIteratorWithIncDec>);
108+
53109
static_assert(std::constructible_from<IteratorFacade, TestIdxVectorIterator>);
54110
static_assert(std::constructible_from<IteratorFacade, TestIdxVectorConstIterator>);
111+
static_assert(std::constructible_from<IteratorFacade, TestIdxVectorIteratorWithIncDec>);
112+
static_assert(std::constructible_from<IteratorFacade, TestIdxVectorConstIteratorWithIncDec>);
113+
55114
} // namespace
56115

57-
TEST_CASE_TEMPLATE("Test IteratorFacade", T, TestIdxVectorIterator, TestIdxVectorConstIterator) {
116+
TYPE_TO_STRING_AS("TestIdxVectorIterator", TestIdxVectorIterator);
117+
TYPE_TO_STRING_AS("TestIdxVectorConstIterator", TestIdxVectorConstIterator);
118+
TYPE_TO_STRING_AS("TestIdxVectorIteratorWithIncDec", TestIdxVectorIteratorWithIncDec);
119+
TYPE_TO_STRING_AS("TestIdxVectorConstIteratorWithIncDec", TestIdxVectorConstIteratorWithIncDec);
120+
121+
TEST_CASE_TEMPLATE("Test IteratorFacade", T, TestIdxVectorIterator, TestIdxVectorConstIterator,
122+
TestIdxVectorIteratorWithIncDec, TestIdxVectorConstIteratorWithIncDec) {
58123
using TestIterator = T;
59124

60125
auto vec = IdxRange{40} | std::ranges::to<IdxVector>();
@@ -63,10 +128,10 @@ TEST_CASE_TEMPLATE("Test IteratorFacade", T, TestIdxVectorIterator, TestIdxVecto
63128
auto it = TestIterator{vec.begin() + 5};
64129
CHECK(*it == 5);
65130
CHECK(*(++it) == 6);
66-
CHECK(*it++ == 6);
131+
CHECK(*(it++) == 6);
67132
CHECK(*it == 7);
68133
CHECK(*(--it) == 6);
69-
CHECK(*it-- == 6);
134+
CHECK(*(it--) == 6);
70135
CHECK(*it == 5);
71136
it += 3;
72137
CHECK(*it == 8);
@@ -103,4 +168,28 @@ TEST_CASE_TEMPLATE("Test IteratorFacade", T, TestIdxVectorIterator, TestIdxVecto
103168
CHECK(vec[5] == 42);
104169
}
105170
}
171+
SUBCASE("Incremented/Decremented calls") {
172+
auto it = TestIterator{vec.begin() + 5};
173+
REQUIRE(!it.last_call.has_value());
174+
175+
++it;
176+
REQUIRE(it.last_call.has_value());
177+
CHECK(it.last_call.value() == TestIterator::increment_style);
178+
it.last_call.reset();
179+
180+
it++;
181+
REQUIRE(it.last_call.has_value());
182+
CHECK(it.last_call.value() == TestIterator::increment_style);
183+
it.last_call.reset();
184+
185+
--it;
186+
REQUIRE(it.last_call.has_value());
187+
CHECK(it.last_call.value() == TestIterator::decrement_style);
188+
it.last_call.reset();
189+
190+
it--;
191+
REQUIRE(it.last_call.has_value());
192+
CHECK(it.last_call.value() == TestIterator::decrement_style);
193+
it.last_call.reset();
194+
}
106195
}

0 commit comments

Comments
 (0)