file_model: Use binary search to find index
Binary search is a fast method to sort for an item within a sorted list. We have a sorted list, so we can take advantage of binary search instead of having a linear traversal through the list. Because binary search requires a sorted list, we need to use the same logic for sorting and searching. Here we factor out the filename comparison logic into `util::compare_by_name()`. In the future we may want to have a module for sorting algorithm logic and checking what sorting algortihm Nautilus uses.
This commit is contained in:
parent
d609c4e0b2
commit
5f7aa595db
2 changed files with 18 additions and 13 deletions
|
|
@ -101,13 +101,7 @@ impl LpFileModel {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Then sort by name.
|
// Then sort by name.
|
||||||
vec.sort_by(|file_a, file_b| {
|
vec.sort_by(util::compare_by_name);
|
||||||
let name_a = util::get_file_display_name(file_a).unwrap_or_default();
|
|
||||||
let name_b = util::get_file_display_name(file_b).unwrap_or_default();
|
|
||||||
|
|
||||||
util::utf8_collate_key_for_filename(&name_a)
|
|
||||||
.cmp(&util::utf8_collate_key_for_filename(&name_b))
|
|
||||||
});
|
|
||||||
|
|
||||||
model.imp().directory.set(directory.clone()).unwrap();
|
model.imp().directory.set(directory.clone()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
@ -127,6 +121,8 @@ impl LpFileModel {
|
||||||
pub fn index_of(&self, file: &gio::File) -> Option<u32> {
|
pub fn index_of(&self, file: &gio::File) -> Option<u32> {
|
||||||
let imp = self.imp();
|
let imp = self.imp();
|
||||||
let vec = imp.inner.borrow();
|
let vec = imp.inner.borrow();
|
||||||
vec.iter().position(|f| f.equal(file)).map(|p| p as u32)
|
vec.binary_search_by(|a| util::compare_by_name(a, file))
|
||||||
|
.ok()
|
||||||
|
.map(|i| i as u32)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
19
src/util.rs
19
src/util.rs
|
|
@ -3,6 +3,10 @@ use crate::deps::*;
|
||||||
use gio::prelude::*;
|
use gio::prelude::*;
|
||||||
use glib::translate::*;
|
use glib::translate::*;
|
||||||
|
|
||||||
|
use anyhow::Context;
|
||||||
|
|
||||||
|
use std::fmt::Write;
|
||||||
|
|
||||||
pub fn utf8_collate_key_for_filename(filename: &str) -> String {
|
pub fn utf8_collate_key_for_filename(filename: &str) -> String {
|
||||||
unsafe {
|
unsafe {
|
||||||
from_glib_full(glib::ffi::g_utf8_collate_key_for_filename(
|
from_glib_full(glib::ffi::g_utf8_collate_key_for_filename(
|
||||||
|
|
@ -18,14 +22,11 @@ pub fn get_file_display_name(file: &gio::File) -> Option<String> {
|
||||||
Some(info.display_name().to_string())
|
Some(info.display_name().to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn query_attributes(
|
pub fn query_attributes(file: &gio::File, attributes: Vec<&str>) -> anyhow::Result<gio::FileInfo> {
|
||||||
file: &gio::File,
|
|
||||||
attributes: Vec<&str>,
|
|
||||||
) -> Result<gio::FileInfo, glib::Error> {
|
|
||||||
let mut attributes = attributes;
|
let mut attributes = attributes;
|
||||||
let mut attr_str = String::from(attributes.remove(0));
|
let mut attr_str = String::from(attributes.remove(0));
|
||||||
for attr in attributes {
|
for attr in attributes {
|
||||||
attr_str.push_str(&format!(",{}", attr));
|
write!(attr_str, ",{}", attr)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
file.query_info(
|
file.query_info(
|
||||||
|
|
@ -33,4 +34,12 @@ pub fn query_attributes(
|
||||||
gio::FileQueryInfoFlags::empty(),
|
gio::FileQueryInfoFlags::empty(),
|
||||||
gio::Cancellable::NONE,
|
gio::Cancellable::NONE,
|
||||||
)
|
)
|
||||||
|
.context("Failed to query string")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compare_by_name(file_a: &gio::File, file_b: &gio::File) -> std::cmp::Ordering {
|
||||||
|
let name_a = get_file_display_name(file_a).unwrap_or_default();
|
||||||
|
let name_b = get_file_display_name(file_b).unwrap_or_default();
|
||||||
|
|
||||||
|
utf8_collate_key_for_filename(&name_a).cmp(&utf8_collate_key_for_filename(&name_b))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue