Skip to content

Commit 3af0bc9

Browse files
authored
Reverse iterators rework (#217)
1 parent 998e9ec commit 3af0bc9

File tree

2 files changed

+42
-4
lines changed

2 files changed

+42
-4
lines changed

src/pysorteddict/sorted_dict_view_type.cc

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,11 @@ void SortedDictViewIterType<RevIterType>::track(RevIterType it)
5757
}
5858
if (it != this->sd->map->rend())
5959
{
60-
++it->second.known_referrers;
60+
FwdIterType it_base = it.base();
61+
if (it_base != this->sd->map->end())
62+
{
63+
++it_base->second.known_referrers;
64+
}
6165
}
6266
else
6367
{
@@ -68,20 +72,39 @@ void SortedDictViewIterType<RevIterType>::track(RevIterType it)
6872
}
6973

7074
/**
71-
* Do all the necessary bookkeeping required to stop tracking the given
75+
* Do all the necessary bookkeeping required to stop tracking the given forward
7276
* iterator of the underlying sorted dictionary.
7377
*
7478
* The caller should ensure that this method is called immediately after the
7579
* iterator member is updated.
7680
*
7781
* @param it Previous value of the iterator member.
7882
*/
79-
template<typename T>
80-
void SortedDictViewIterType<T>::untrack(T it)
83+
template<>
84+
void SortedDictViewIterType<FwdIterType>::untrack(FwdIterType it)
8185
{
8286
--it->second.known_referrers;
8387
}
8488

89+
/**
90+
* Do all the necessary bookkeeping required to stop tracking the given reverse
91+
* iterator of the underlying sorted dictionary.
92+
*
93+
* The caller should ensure that this method is called immediately after the
94+
* iterator member is updated.
95+
*
96+
* @param it Previous value of the iterator member.
97+
*/
98+
template<>
99+
void SortedDictViewIterType<RevIterType>::untrack(RevIterType it)
100+
{
101+
FwdIterType it_base = it.base();
102+
if (it_base != this->sd->map->end())
103+
{
104+
--it_base->second.known_referrers;
105+
}
106+
}
107+
85108
template<typename T>
86109
void SortedDictViewIterType<T>::Delete(PyObject* self)
87110
{

tests/functional/test_keys_iter.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,18 @@ def test_destructive_forward_iteration(sorted_dict):
7373
del sorted_dict[key]
7474
assert len(sorted_dict) == 0
7575
assert not [*sorted_dict]
76+
77+
78+
@pytest.mark.parametrize("sorted_dict", [*range(10), 100, 1_000, 10_000, 100_000], indirect=True)
79+
def test_destructive_reverse_iteration(sorted_dict):
80+
prev_key = None
81+
for key in reversed(sorted_dict):
82+
# A quirk of the implementation of reverse iterators: the current key
83+
# cannot be deleted.
84+
if prev_key is not None:
85+
del sorted_dict[prev_key]
86+
prev_key = key
87+
if prev_key is not None:
88+
del sorted_dict[prev_key]
89+
assert len(sorted_dict) == 0
90+
assert not [*sorted_dict]

0 commit comments

Comments
 (0)