mirror of
https://github.com/bevyengine/bevy
synced 2024-11-26 06:30:19 +00:00
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
1 changed files with 89 additions and 0 deletions
|
@ -378,6 +378,17 @@ impl<'a, E: Event> Iterator for ManualEventIterator<'a, E> {
|
|||
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 {
|
||||
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 {
|
||||
self.reader.last_event_count += self.unread;
|
||||
self.unread
|
||||
|
@ -880,6 +912,63 @@ mod tests {
|
|||
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)]
|
||||
struct EmptyTestEvent;
|
||||
|
||||
|
|
Loading…
Reference in a new issue