From 883c5fd35b783d56561aabfcbe7473887d448cc0 Mon Sep 17 00:00:00 2001 From: Nicolai Syvertsen Date: Thu, 9 May 2024 15:25:46 +0200 Subject: [PATCH] Use optimized implementation of filter list using ordered hash set. --- src/backend/pwroutefiltermodel.rs | 64 +++++++++++++++---------------- 1 file changed, 30 insertions(+), 34 deletions(-) diff --git a/src/backend/pwroutefiltermodel.rs b/src/backend/pwroutefiltermodel.rs index d798288..92c6060 100644 --- a/src/backend/pwroutefiltermodel.rs +++ b/src/backend/pwroutefiltermodel.rs @@ -1,10 +1,10 @@ // SPDX-License-Identifier: GPL-3.0-or-later +use super::{ParamAvailability, PwRouteObject, RouteDirection}; use glib::{closure_local, subclass::prelude::*, Properties}; use gtk::{gio, prelude::*, subclass::prelude::*}; use std::cell::{Cell, RefCell}; -use im_rc::Vector; -use super::{ParamAvailability, PwRouteObject, RouteDirection}; +use std::collections::BTreeSet; mod imp { use super::*; @@ -13,7 +13,7 @@ mod imp { #[properties(wrapper_type = super::PwRouteFilterModel)] pub struct PwRouteFilterModel { /// Contains the items that matches the filter predicate. - pub(super) filtered_model: RefCell>, + pub(super) hashset: RefCell>, #[property(get, set, construct_only, builder(RouteDirection::Unknown))] pub(super) direction: Cell, @@ -31,48 +31,47 @@ mod imp { } #[glib::derived_properties] - impl ObjectImpl for PwRouteFilterModel { - } + impl ObjectImpl for PwRouteFilterModel {} impl ListModelImpl for PwRouteFilterModel { fn item_type(&self) -> glib::Type { PwRouteObject::static_type() } fn n_items(&self) -> u32 { - self.filtered_model.borrow().len() as u32 + self.hashset.borrow().len() as u32 } fn item(&self, position: u32) -> Option { - self.filtered_model - .borrow() - .get(position as usize) - .map(|o| o.clone().upcast::()) + if let Some(pos) = self.hashset.borrow().iter().nth(position as usize) { + if let Some(model) = self.model.borrow().as_ref() { + return model.item(*pos); + }; + }; + + None } } impl PwRouteFilterModel { pub fn set_model(&self, new_model: Option<&gio::ListModel>) { - let removed = self.filtered_model.borrow().len() as u32; - if let Some(new_model) = new_model { - assert!(self.item_type().is_a(new_model.item_type())); let widget = self.obj(); - let handler = closure_local!(@watch widget => move |listmodel: &gio::ListModel, _position: u32, _removed: u32, _added: u32| { - let u: Vector = listmodel.iter::() + let handler = closure_local!(@watch widget => move |listmodel: &gio::ListModel, position: u32, _removed: u32, _added: u32| { + let removed = widget.imp().hashset.borrow().len() as u32; + + widget.imp().hashset.borrow_mut().clear(); + + for (a, routeobject) in listmodel.iter::() + .skip(position as usize) .map_while(Result::ok) - .filter(|routeobject| { - routeobject.direction() == widget.direction() && routeobject.availability() == ParamAvailability::Yes - }) - .collect(); - - let removed = widget.imp().filtered_model.borrow().len() as u32; - let added = { - let mut filtered_model = widget.imp().filtered_model.borrow_mut(); - filtered_model.clear(); - filtered_model.append(u); - filtered_model.len() as u32 - }; + .enumerate() { + if routeobject.direction() == widget.direction() && routeobject.availability() == ParamAvailability::Yes { + widget.imp().hashset.borrow_mut().insert(a as u32); + } + } + + let added = widget.imp().hashset.borrow().len() as u32; widget.items_changed(0, removed, added); }); handler.invoke::<()>(&[&new_model, &0u32, &0u32, &0u32]); @@ -80,7 +79,8 @@ mod imp { self.model.replace(Some(new_model.clone().upcast())); } else { - self.filtered_model.borrow_mut().clear(); + self.hashset.borrow_mut().clear(); + let removed = self.hashset.borrow().len() as u32; self.obj().items_changed(0, removed, 0); } } @@ -92,11 +92,7 @@ glib::wrapper! { } impl PwRouteFilterModel { - pub(crate) fn new(direction: RouteDirection, model: Option<&impl glib::IsA>) -> Self - { - glib::Object::builder() - .property("model", model) - .property("direction", direction) - .build() + pub(crate) fn new(direction: RouteDirection, model: Option<&impl glib::IsA>) -> Self { + glib::Object::builder().property("model", model).property("direction", direction).build() } }