From 1de142487f27d472daf22c04a4eebd38fd7f8758 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20=E2=80=9CCLOVIS=E2=80=9D=20Canet?= Date: Sat, 7 Feb 2026 22:19:17 +0100 Subject: [PATCH] fix(enumset): Fix the iterator().remove() method According to the specification, it wasn't always removing the correct element. --- enumset/src/commonMain/kotlin/Bit32.kt | 9 +++-- .../kotlin/datatypes/EnumSetSuite.kt | 3 +- .../commonTest/kotlin/datatypes/SetSuite.kt | 33 ++++++++++++++++++- 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/enumset/src/commonMain/kotlin/Bit32.kt b/enumset/src/commonMain/kotlin/Bit32.kt index 4430d83..52198ff 100644 --- a/enumset/src/commonMain/kotlin/Bit32.kt +++ b/enumset/src/commonMain/kotlin/Bit32.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, OpenSavvy and contributors. + * Copyright (c) 2025-2026, OpenSavvy and contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -209,6 +209,7 @@ class MutableBitSet32 internal constructor(private var storage: BitSet32) : Muta private val set: MutableBitSet32, ) : MutableIterator { private var index = 0 + private var lastIndexReturned = -1 override fun hasNext(): Boolean { while (index < 32) { @@ -227,11 +228,15 @@ class MutableBitSet32 internal constructor(private var storage: BitSet32) : Muta throw NoSuchElementException() } + lastIndexReturned = index return index++ } override fun remove() { - set.remove(index) + check(lastIndexReturned != -1) { "Cannot remove an item before next() is called at least once" } + check(lastIndexReturned != -2) { "Cannot remove an item multiple times. remove() removes the last item viewed by next(), but it has already been removed" } + set.remove(lastIndexReturned) + lastIndexReturned = -2 } } diff --git a/enumset/src/commonTest/kotlin/datatypes/EnumSetSuite.kt b/enumset/src/commonTest/kotlin/datatypes/EnumSetSuite.kt index 02c3613..ecd6f9f 100644 --- a/enumset/src/commonTest/kotlin/datatypes/EnumSetSuite.kt +++ b/enumset/src/commonTest/kotlin/datatypes/EnumSetSuite.kt @@ -488,9 +488,10 @@ fun > SuiteDsl.testMutableEnumSetValidity( check(iter.hasNext()) check(iter.next() == entries[0]) + iter.remove() check(iter.hasNext()) - iter.remove() + check(iter.next() == entries[1]) println("After removal: $set") diff --git a/enumset/src/commonTest/kotlin/datatypes/SetSuite.kt b/enumset/src/commonTest/kotlin/datatypes/SetSuite.kt index e27362a..8316e69 100644 --- a/enumset/src/commonTest/kotlin/datatypes/SetSuite.kt +++ b/enumset/src/commonTest/kotlin/datatypes/SetSuite.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, OpenSavvy and contributors. + * Copyright (c) 2025-2026, OpenSavvy and contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -405,9 +405,40 @@ fun SuiteDsl.testMutableSetValidity( check(iter.hasNext()) iter.remove() + // 'remove' deletes the last item returned by 'next', NOT the last item as seen by hasNext + check(5 !in set) + check(7 in set) + check(9 in set) + check(set.size == 2) + + check(iter.next() == 7) + check(iter.hasNext()) check(iter.next() == 9) } + + test("Cannot remove an item before reading the first element") { + val set = create(arrayOf(5, 7, 9)) + val iter = set.iterator() + check(iter.hasNext()) + checkThrows { + iter.remove() + } + } + + test("Cannot remove an item twice") { + val set = create(arrayOf(5, 7, 9)) + println("Iterating through set $set") + val iter = set.iterator() + + check(iter.hasNext()) + check(iter.next() == 5) + iter.remove() + + checkThrows { + iter.remove() + } + } } suite("retainAll") { -- 2.51.2