Skip to content

Commit

Permalink
fzf-v2: compute matched ranges
Browse files Browse the repository at this point in the history
  • Loading branch information
noib3 committed Oct 27, 2023
1 parent 8c2b47a commit 6a927c9
Show file tree
Hide file tree
Showing 5 changed files with 256 additions and 39 deletions.
176 changes: 150 additions & 26 deletions src/algos/fzf/slab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ impl CandidateSlab {
Candidate {
chars: &self.chars[..len],
char_offsets: &self.char_indices[..len],
byte_offset: 0,
char_offset: 0,
}
}
Expand All @@ -74,7 +73,6 @@ impl CandidateSlab {
pub(super) struct Candidate<'a> {
chars: &'a [char],
char_offsets: &'a [usize],
byte_offset: usize,
char_offset: usize,
}

Expand All @@ -96,6 +94,12 @@ impl CandidateCharIdx {
}

impl<'a> Candidate<'a> {
/// TODO: docs
#[inline]
pub fn char(&self, idx: CandidateCharIdx) -> char {
self.chars[idx.0 - self.char_offset]
}

/// TODO: docs
#[inline]
pub fn chars(&self) -> impl Iterator<Item = char> + '_ {
Expand All @@ -120,23 +124,17 @@ impl<'a> Candidate<'a> {

/// TODO: docs
#[inline]
pub fn char_offsets(&self) -> impl Iterator<Item = (usize, char)> + '_ {
self.char_offsets
.iter()
.zip(self.chars)
.map(|(&offset, &char)| (offset + self.byte_offset, char))
}

/// TODO: docs
#[inline]
pub fn nth_char(&self, idx: usize) -> char {
self.chars[idx]
pub fn char_offset(&self, idx: CandidateCharIdx) -> usize {
self.char_offsets[idx.0 - self.char_offset]
}

/// TODO: docs
#[inline]
pub fn nth_char_offset(&self, idx: usize) -> usize {
self.char_offsets[idx] + self.byte_offset
pub fn char_offsets(&self) -> impl Iterator<Item = (usize, char)> + '_ {
self.char_offsets
.iter()
.zip(self.chars)
.map(|(&offset, &char)| (offset, char))
}

/// TODO: docs
Expand All @@ -146,8 +144,7 @@ impl<'a> Candidate<'a> {
let chars = &self.chars[range.clone()];
let char_offsets = &self.char_offsets[range.clone()];
let char_offset = self.char_offset + range.start;
let byte_offset = self.byte_offset + self.char_offsets[range.start];
Self { chars, char_offsets, char_offset, byte_offset }
Self { chars, char_offsets, char_offset }
}
}

Expand Down Expand Up @@ -483,7 +480,12 @@ impl<T: MatrixItem> core::fmt::Debug for Matrix<'_, T> {
impl<'a, T: MatrixItem> Matrix<'a, T> {
#[inline]
pub fn cols(&self, starting_from: MatrixCell) -> Cols {
Cols { next: Some(starting_from), matrix_width: self.width }
Cols::new(starting_from, self.width)
}

#[inline]
pub fn col_of(&self, cell: MatrixCell) -> usize {
cell.0 % self.width
}

#[inline]
Expand Down Expand Up @@ -530,11 +532,7 @@ impl<'a, T: MatrixItem> Matrix<'a, T> {

#[inline]
pub fn rows(&self, starting_from: MatrixCell) -> Rows {
Rows {
next: Some(starting_from),
matrix_width: self.width,
matrix_height: self.height,
}
Rows::new(starting_from, self.width, self.height)
}

/// TODO: docs
Expand Down Expand Up @@ -614,8 +612,31 @@ impl MatrixCell {

/// TODO: docs
pub(super) struct Cols {
/// TODO: docs
next: Option<MatrixCell>,

/// TODO: docs
matrix_width: usize,

/// TODO: docs
next_col: ColNext,
}

impl Cols {
#[inline]
fn new(start_from: MatrixCell, matrix_width: usize) -> Self {
Self {
next: Some(start_from),
matrix_width,
next_col: ColNext::default(),
}
}

#[inline]
pub fn reverse(mut self) -> Self {
self.next_col.switch();
self
}
}

impl Iterator for Cols {
Expand All @@ -624,7 +645,8 @@ impl Iterator for Cols {
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let this = self.next.take();
let next = this.and_then(|cell| cell.right(self.matrix_width));
let next =
this.and_then(|cell| self.next_col.call(cell, self.matrix_width));
self.next = next;
this
}
Expand All @@ -635,6 +657,29 @@ pub(super) struct Rows {
next: Option<MatrixCell>,
matrix_height: usize,
matrix_width: usize,
next_row: RowNext,
}

impl Rows {
#[inline]
fn new(
start_from: MatrixCell,
matrix_width: usize,
matrix_height: usize,
) -> Self {
Self {
next: Some(start_from),
matrix_width,
matrix_height,
next_row: RowNext::default(),
}
}

#[inline]
pub fn reverse(mut self) -> Self {
self.next_row.switch();
self
}
}

impl Iterator for Rows {
Expand All @@ -643,9 +688,88 @@ impl Iterator for Rows {
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let this = self.next.take();
let next = this
.and_then(|cell| cell.down(self.matrix_width, self.matrix_height));

let next = this.and_then(|cell| {
self.next_row.call(cell, self.matrix_width, self.matrix_height)
});

self.next = next;

this
}
}

struct RowNext {
fun: fn(MatrixCell, usize, usize) -> Option<MatrixCell>,
is_down: bool,
}

impl Default for RowNext {
#[inline]
fn default() -> Self {
Self { fun: down, is_down: true }
}
}

impl RowNext {
fn call(
&self,
cell: MatrixCell,
matrix_width: usize,
matrix_height: usize,
) -> Option<MatrixCell> {
(self.fun)(cell, matrix_width, matrix_height)
}

fn switch(&mut self) {
self.fun = if self.is_down { up } else { down };
self.is_down = !self.is_down;
}
}

struct ColNext {
fun: fn(MatrixCell, usize) -> Option<MatrixCell>,
is_right: bool,
}

impl Default for ColNext {
#[inline]
fn default() -> Self {
Self { fun: right, is_right: true }
}
}

impl ColNext {
fn call(
&self,
cell: MatrixCell,
matrix_width: usize,
) -> Option<MatrixCell> {
(self.fun)(cell, matrix_width)
}

fn switch(&mut self) {
self.fun = if self.is_right { left } else { right };
self.is_right = !self.is_right;
}
}

#[inline]
fn up(cell: MatrixCell, width: usize, _height: usize) -> Option<MatrixCell> {
cell.up(width)
}

#[inline]
fn down(cell: MatrixCell, width: usize, height: usize) -> Option<MatrixCell> {
cell.down(width, height)
}

#[inline]
fn left(cell: MatrixCell, width: usize) -> Option<MatrixCell> {
cell.left(width)
}

#[inline]
fn right(cell: MatrixCell, width: usize) -> Option<MatrixCell> {
cell.right(width)
}
95 changes: 84 additions & 11 deletions src/algos/fzf/v2.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use core::ops::Range;

use super::{slab::*, *};
use crate::{CaseMatcher, CaseSensitivity, Match, Metric};

Expand Down Expand Up @@ -78,7 +80,7 @@ impl Metric for FzfV2 {
&self.scheme,
)?;

let (scoring_matrix, score, score_cell) = score(
let (scores, consecutive, score, score_cell) = score(
&mut self.slab.scoring_matrix,
&mut self.slab.consecutive_matrix,
query,
Expand All @@ -88,13 +90,15 @@ impl Metric for FzfV2 {
case_matcher,
);

println!("\n{score:?}");

println!("\n{scoring_matrix:?}");
let matched_ranges = if self.with_matched_ranges {
matched_ranges(scores, consecutive, score_cell, candidate)
} else {
Vec::new()
};

let distance = FzfDistance::from_score(score);

Some(Match::new(distance, Vec::new()))
Some(Match::new(distance, matched_ranges))
}
}

Expand Down Expand Up @@ -143,15 +147,16 @@ fn matched_indices<'idx, 'bonus>(

/// TODO: docs
#[inline]
fn score<'scoring>(
fn score<'scoring, 'consecutive>(
scoring_slab: &'scoring mut ScoringMatrixSlab,
consecutive_slab: &mut ConsecutiveMatrixSlab,
consecutive_slab: &'consecutive mut ConsecutiveMatrixSlab,
query: FzfQuery,
candidate: Candidate,
matched_indices: MatchedIndices,
bonus_vector: BonusVector,
case_matcher: CaseMatcher,
) -> (Matrix<'scoring, Score>, Score, MatrixCell) {
) -> (Matrix<'scoring, Score>, Matrix<'consecutive, usize>, Score, MatrixCell)
{
let mut scoring_matrix = scoring_slab.alloc(query, candidate);

let mut consecutive_matrix = consecutive_slab.alloc(query, candidate);
Expand Down Expand Up @@ -194,9 +199,7 @@ fn score<'scoring>(
case_matcher,
);

println!("{consecutive_matrix:?}");

(scoring_matrix, max_score, max_score_cell)
(scoring_matrix, consecutive_matrix, max_score, max_score_cell)
}

/// TODO: docs
Expand Down Expand Up @@ -370,3 +373,73 @@ where

(max_score, max_score_cell)
}

/// TODO: docs
#[inline]
fn matched_ranges(
scores: Matrix<Score>,
consecutives: Matrix<usize>,
max_score_cell: MatrixCell,
candidate: Candidate,
) -> Vec<Range<usize>> {
let mut ranges = Vec::<Range<usize>>::new();

let mut prefer_match = true;

let mut cell = max_score_cell;

loop {
let score = scores[cell];

let cell_left = scores.left(cell);

let cell_up_left = cell_left.and_then(|left| scores.up(left));

let score_left = cell_left.map(|c| scores[c]).unwrap_or(0);

let score_up_left = cell_up_left.map(|c| scores[c]).unwrap_or(0);

let this_prefer_match = prefer_match;

prefer_match = consecutives[cell] > 1
|| consecutives
.right(cell)
.and_then(|right| consecutives.down(right))
.map(|down_right| consecutives[down_right] > 0)
.unwrap_or(false);

if score > score_up_left
&& (score > score_left || score == score_left && this_prefer_match)
{
let char_idx = CandidateCharIdx(scores.col_of(cell));

let char = candidate.char(char_idx);
let offset = candidate.char_offset(char_idx);

let char_len_utf8 = char.len_utf8();

match ranges.last_mut() {
Some(last) if last.start == offset + char_len_utf8 => {
last.start = offset;
},
_ => {
ranges.push(offset..offset + char_len_utf8);
},
}

if let Some(up_left) = cell_up_left {
cell = up_left;
} else {
break;
}
} else {
if let Some(left) = scores.left(cell) {
cell = left;
} else {
break;
}
}
}

ranges
}
Loading

0 comments on commit 6a927c9

Please sign in to comment.