From 4049cdbd132d27cecf4beee62b5a7557d0e5d698 Mon Sep 17 00:00:00 2001 From: Pascal Kuthe Date: Thu, 3 Aug 2023 21:05:02 +0200 Subject: [PATCH] allow sorting to be canceled this removes all left over UI lag --- src/lib.rs | 1 + src/worker.rs | 71 +++++++++++++++++++++++++++++---------------------- 2 files changed, 42 insertions(+), 30 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 29b1285..8a7be6b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,6 +12,7 @@ use crate::worker::Woker; pub use nucleo_matcher::{chars, Matcher, MatcherConfig, Utf32Str}; mod boxcar; +mod par_sort; mod pattern; mod utf32_string; mod worker; diff --git a/src/worker.rs b/src/worker.rs index 0836b66..8625974 100644 --- a/src/worker.rs +++ b/src/worker.rs @@ -7,6 +7,7 @@ use nucleo_matcher::MatcherConfig; use parking_lot::Mutex; use rayon::{prelude::*, ThreadPool}; +use crate::par_sort::par_quicksort; use crate::pattern::{self, MultiPattern}; use crate::{boxcar, Match}; @@ -200,40 +201,50 @@ impl Woker { }); } - if self.canceled.load(atomic::Ordering::Relaxed) { + let canceled = par_quicksort( + &mut self.matches, + |match1, match2| { + if match1.score > match2.score { + return true; + } + if match1.idx == u32::MAX { + return false; + } + if match2.idx == u32::MAX { + return true; + } + // the tie breaker is comparitevly rarely needed so we keep it + // in a branch especially because we need to access the items + // array here which involves some pointer chasing + let item1 = self.items.get_unchecked(match1.idx); + let item2 = &self.items.get_unchecked(match2.idx); + let len1: u32 = item1 + .matcher_columns + .iter() + .map(|haystack| haystack.len() as u32) + .sum(); + let len2 = item2 + .matcher_columns + .iter() + .map(|haystack| haystack.len() as u32) + .sum(); + if len1 == len2 { + match1.idx < match2.idx + } else { + len1 < len2 + } + }, + &self.canceled, + ); + + if canceled { self.was_canceled = true; } else { - // TODO: cancel sort in progress? - self.matches.par_sort_unstable_by(|match1, match2| { - match2.score.cmp(&match1.score).then_with(|| { - if match1.idx == u32::MAX || match2.idx == u32::MAX { - return match1.idx.cmp(&match2.idx); - } - // the tie breaker is comparitevly rarely needed so we keep it - // in a branch especially because we need to access the items - // array here which involves some pointer chasing - let item1 = self.items.get_unchecked(match1.idx); - let item2 = &self.items.get_unchecked(match2.idx); - let len1: u32 = item1 - .matcher_columns - .iter() - .map(|haystack| haystack.len() as u32) - .sum(); - let len2 = item2 - .matcher_columns - .iter() - .map(|haystack| haystack.len() as u32) - .sum(); - (len1, match1.idx).cmp(&(len2, match2.idx)) - }) - }); - // let old = self.matches.clone(); self.matches .truncate(self.matches.len() - take(self.unmatched.get_mut()) as usize); - } - - if self.should_notify.load(atomic::Ordering::Acquire) { - (self.notify)(); + if self.should_notify.load(atomic::Ordering::Acquire) { + (self.notify)(); + } } } }