Optimize .nth() and .last() for event iterators (#7530)
# Objective Motivated by #7469. `EventReader` iterators use the default implementations for `.nth()` and `.last()`, which includes iterating over and throwing out all events before the desired one. ## Solution Add specialized implementations for these methods that directly updates the unread event counter and returns a reference to the desired event. TODO: - [x] Add a unit test. - [x] ~~Add a benchmark, to see if the compiler was doing this automatically already.~~ *On second thought, this doesn't feel like a very useful thing to include in the benchmark suite.*
This commit is contained in:
parent
b1646e9cee
commit
a95033b288
@ -378,6 +378,17 @@ impl<'a, E: Event> Iterator for ManualEventIterator<'a, E> {
|
|||||||
self.iter.next().map(|(event, _)| event)
|
self.iter.next().map(|(event, _)| event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn nth(&mut self, n: usize) -> Option<Self::Item> {
|
||||||
|
self.iter.nth(n).map(|(event, _)| event)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn last(self) -> Option<Self::Item>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
self.iter.last().map(|(event, _)| event)
|
||||||
|
}
|
||||||
|
|
||||||
fn count(self) -> usize {
|
fn count(self) -> usize {
|
||||||
self.iter.count()
|
self.iter.count()
|
||||||
}
|
}
|
||||||
@ -449,6 +460,27 @@ impl<'a, E: Event> Iterator for ManualEventIteratorWithId<'a, E> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn nth(&mut self, n: usize) -> Option<Self::Item> {
|
||||||
|
if let Some(EventInstance { event_id, event }) = self.chain.nth(n) {
|
||||||
|
self.reader.last_event_count += n + 1;
|
||||||
|
self.unread -= n + 1;
|
||||||
|
Some((event, *event_id))
|
||||||
|
} else {
|
||||||
|
self.reader.last_event_count += self.unread;
|
||||||
|
self.unread = 0;
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn last(self) -> Option<Self::Item>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let EventInstance { event_id, event } = self.chain.last()?;
|
||||||
|
self.reader.last_event_count += self.unread;
|
||||||
|
Some((event, *event_id))
|
||||||
|
}
|
||||||
|
|
||||||
fn count(self) -> usize {
|
fn count(self) -> usize {
|
||||||
self.reader.last_event_count += self.unread;
|
self.reader.last_event_count += self.unread;
|
||||||
self.unread
|
self.unread
|
||||||
@ -880,6 +912,63 @@ mod tests {
|
|||||||
assert!(is_empty, "EventReader should be empty");
|
assert!(is_empty, "EventReader should be empty");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::iter_nth_zero)]
|
||||||
|
#[test]
|
||||||
|
fn test_event_iter_nth() {
|
||||||
|
use bevy_ecs::prelude::*;
|
||||||
|
|
||||||
|
let mut world = World::new();
|
||||||
|
world.init_resource::<Events<TestEvent>>();
|
||||||
|
|
||||||
|
world.send_event(TestEvent { i: 0 });
|
||||||
|
world.send_event(TestEvent { i: 1 });
|
||||||
|
world.send_event(TestEvent { i: 2 });
|
||||||
|
world.send_event(TestEvent { i: 3 });
|
||||||
|
world.send_event(TestEvent { i: 4 });
|
||||||
|
|
||||||
|
let mut schedule = Schedule::new();
|
||||||
|
schedule.add_system(|mut events: EventReader<TestEvent>| {
|
||||||
|
let mut iter = events.iter();
|
||||||
|
|
||||||
|
assert_eq!(iter.next(), Some(&TestEvent { i: 0 }));
|
||||||
|
assert_eq!(iter.nth(2), Some(&TestEvent { i: 3 }));
|
||||||
|
assert_eq!(iter.nth(1), None);
|
||||||
|
|
||||||
|
assert!(events.is_empty());
|
||||||
|
});
|
||||||
|
schedule.run(&mut world);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_event_iter_last() {
|
||||||
|
use bevy_ecs::prelude::*;
|
||||||
|
|
||||||
|
let mut world = World::new();
|
||||||
|
world.init_resource::<Events<TestEvent>>();
|
||||||
|
|
||||||
|
let mut reader =
|
||||||
|
IntoSystem::into_system(|mut events: EventReader<TestEvent>| -> Option<TestEvent> {
|
||||||
|
events.iter().last().copied()
|
||||||
|
});
|
||||||
|
reader.initialize(&mut world);
|
||||||
|
|
||||||
|
let last = reader.run((), &mut world);
|
||||||
|
assert!(last.is_none(), "EventReader should be empty");
|
||||||
|
|
||||||
|
world.send_event(TestEvent { i: 0 });
|
||||||
|
let last = reader.run((), &mut world);
|
||||||
|
assert_eq!(last, Some(TestEvent { i: 0 }));
|
||||||
|
|
||||||
|
world.send_event(TestEvent { i: 1 });
|
||||||
|
world.send_event(TestEvent { i: 2 });
|
||||||
|
world.send_event(TestEvent { i: 3 });
|
||||||
|
let last = reader.run((), &mut world);
|
||||||
|
assert_eq!(last, Some(TestEvent { i: 3 }));
|
||||||
|
|
||||||
|
let last = reader.run((), &mut world);
|
||||||
|
assert!(last.is_none(), "EventReader should be empty");
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug, Default)]
|
#[derive(Clone, PartialEq, Debug, Default)]
|
||||||
struct EmptyTestEvent;
|
struct EmptyTestEvent;
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user