Skip to content

Commit

Permalink
add indexOfFirst and indexOfLast to EntityBag and family. Also, add g…
Browse files Browse the repository at this point in the history
…oToFirst and goToLast to EntityBagIterator
  • Loading branch information
Quillraven committed Dec 23, 2024
1 parent c765d1f commit 1246b77
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,32 @@ data class EntityBagIterator(private val bag: EntityBag) {
fun reset() {
currentIdx = 0
}

/**
* Moves the iterator to the first [Entity] matching the given [predicate] and returns it.
* If there is no such [Entity] then the iterator is reset and [Entity.NONE] is returned instead.
*/
fun goToFirst(predicate: (Entity) -> Boolean): Entity {
currentIdx = bag.indexOfFirst(predicate)
if (currentIdx == -1) {
reset()
return Entity.NONE
}

return bag[currentIdx]
}

/**
* Moves the iterator to the last [Entity] matching the given [predicate] and returns it.
* If there is no such [Entity] then the iterator is reset and [Entity.NONE] is returned instead.
*/
fun goToLast(predicate: (Entity) -> Boolean): Entity {
currentIdx = bag.indexOfLast(predicate)
if (currentIdx == -1) {
reset()
return Entity.NONE
}

return bag[currentIdx]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,18 @@ interface EntityBag {
*/
fun count(predicate: (Entity) -> Boolean): Int

/**
* Returns the index of the first [Entity] matching the given [predicate],
* or -1 if the bag does not contain such an [Entity].
*/
fun indexOfFirst(predicate: (Entity) -> Boolean): Int

/**
* Returns the index of the last [Entity] matching the given [predicate],
* or -1 if the bag does not contain such an [Entity].
*/
fun indexOfLast(predicate: (Entity) -> Boolean): Int

/**
* Returns a [List] containing only [entities][Entity] matching the given [predicate].
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,34 @@ class MutableEntityBag(
return result
}

/**
* Returns the index of the first [Entity] matching the given [predicate],
* or -1 if the bag does not contain such an [Entity].
*/
override inline fun indexOfFirst(predicate: (Entity) -> Boolean): Int {
for (i in 0 until size) {
val entity = values[i]
if (predicate(entity)) {
return i
}
}
return -1
}

/**
* Returns the index of the last [Entity] matching the given [predicate],
* or -1 if the bag does not contain such an [Entity].
*/
override inline fun indexOfLast(predicate: (Entity) -> Boolean): Int {
for (i in size - 1 downTo 0) {
val entity = values[i]
if (predicate(entity)) {
return i
}
}
return -1
}

/**
* Returns a [List] containing only [entities][Entity] matching the given [predicate].
*/
Expand Down
18 changes: 18 additions & 0 deletions src/commonMain/kotlin/com/github/quillraven/fleks/family.kt
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,24 @@ data class Family(
*/
fun count(predicate: (Entity) -> Boolean): Int = mutableEntities.count(predicate)

/**
* Returns the index of the first [Entity] matching the given [predicate],
* or -1 if the family does not contain such an [Entity].
*/
fun indexOfFirst(predicate: (Entity) -> Boolean): Int = mutableEntities.indexOfFirst(predicate)

/**
* Returns the index of the last [Entity] matching the given [predicate],
* or -1 if the family does not contain such an [Entity].
*/
fun indexOfLast(predicate: (Entity) -> Boolean): Int = mutableEntities.indexOfLast(predicate)

/**
* Creates an [EntityBagIterator] for the family. If the family gets updated
* during iteration then [EntityBagIterator.reset] must be called to guarantee correct iterator behavior.
*/
fun iterator(): EntityBagIterator = EntityBagIterator(mutableEntities)

/**
* Returns a [Map] containing key-value pairs provided by the [transform] function applied to
* each [entity][Entity] of the family.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -449,4 +449,11 @@ class FamilyBagFunctionsTest {
assertEquals(entityBagOf(testEntity1, testEntity2), testFamily.take(2))
assertEquals(entityBagOf(testEntity1, testEntity2), testFamily.take(3))
}

@Test
fun testIndexOf() {
assertEquals(0, testFamily.indexOfFirst { it.id == 0 })
assertEquals(1, testFamily.indexOfLast { it.id == 1 })
assertEquals(-1, testFamily.indexOfLast { it.id == 99 })
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ class EntityBagIteratorTest {
@Test
fun `test iterator on bag with single entity`() {
val entity = Entity(1, 0u)
val emptyBag = mutableEntityBagOf(entity)
val testBag = mutableEntityBagOf(entity)

val iterator = emptyBag.iterator()
val iterator = testBag.iterator()

assertTrue(iterator.hasNext())
assertFalse(iterator.hasPrevious())
Expand All @@ -49,9 +49,9 @@ class EntityBagIteratorTest {
fun `test iterator on bag with two entities`() {
val entity1 = Entity(1, 0u)
val entity2 = Entity(2, 0u)
val emptyBag = mutableEntityBagOf(entity1, entity2)
val testBag = mutableEntityBagOf(entity1, entity2)

val iterator = emptyBag.iterator()
val iterator = testBag.iterator()

assertTrue(iterator.hasNext())
assertFalse(iterator.hasPrevious())
Expand All @@ -72,4 +72,34 @@ class EntityBagIteratorTest {
assertEquals(entity2, iterator.previous(loop = true))
}

@Test
fun `test goToFirst`() {
val entity1 = Entity(1, 0u)
val entity2 = Entity(2, 0u)
val entity3 = Entity(2, 1u) // same id on purpose to check that goTo stops at first entity
val testBag = mutableEntityBagOf(entity1, entity2, entity3)

val iterator = testBag.iterator()

assertEquals(entity2, iterator.goToFirst { e -> e.id == 2 })
assertEquals(entity1, iterator.previous())
assertEquals(Entity.NONE, iterator.goToFirst { e -> e.id == 3 })
assertEquals(entity1, iterator.next())
}

@Test
fun `test goToLast`() {
val entity1 = Entity(1, 0u)
val entity2 = Entity(2, 0u)
val entity3 = Entity(2, 1u) // same id on purpose to check that goTo stops at first entity
val testBag = mutableEntityBagOf(entity1, entity2, entity3)

val iterator = testBag.iterator()

assertEquals(entity3, iterator.goToLast { e -> e.id == 2 })
assertEquals(entity2, iterator.previous())
assertEquals(Entity.NONE, iterator.goToLast { e -> e.id == 3 })
assertEquals(entity1, iterator.next())
}

}

0 comments on commit 1246b77

Please sign in to comment.