From 90fb28b4b6146ca8eace35d33102cca202d5d544 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Fri, 4 Feb 2022 21:32:14 +0100 Subject: [PATCH] Add `group` in addition to `group_by_key` --- src/library/par.rs | 4 ++-- src/util/mod.rs | 54 +++++++++++++++++++++++++++++++--------------- 2 files changed, 39 insertions(+), 19 deletions(-) diff --git a/src/library/par.rs b/src/library/par.rs index e87d5f671..4568a2144 100644 --- a/src/library/par.rs +++ b/src/library/par.rs @@ -239,9 +239,9 @@ impl<'a> ParLayouter<'a> { ParChild::Text(_) => { // TODO: Also split by language and script. let mut cursor = range.start; - for (level, group) in bidi.levels[range].group_by_key(|&lvl| lvl) { + for (level, count) in bidi.levels[range].group() { let start = cursor; - cursor += group.len(); + cursor += count; let subrange = start .. cursor; let text = &bidi.text[subrange.clone()]; let shaped = shape(ctx.fonts, text, styles, level.dir()); diff --git a/src/util/mod.rs b/src/util/mod.rs index de37354e7..2f91100f0 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -82,9 +82,14 @@ where /// Additional methods for slices. pub trait SliceExt { - /// Split a slice into consecutive groups with the same key. - /// - /// Returns an iterator of pairs of a key and the group with that key. + /// Find consecutive runs of the same elements in a slice and yield for + /// each such run the element and number of times it appears. + fn group(&self) -> Group<'_, T> + where + T: PartialEq; + + /// Split a slice into consecutive runs with the same key and yield for + /// each such run the key and the slice of elements with that key. fn group_by_key(&self, f: F) -> GroupByKey<'_, T, F> where F: FnMut(&T) -> K, @@ -92,15 +97,35 @@ pub trait SliceExt { } impl SliceExt for [T] { - fn group_by_key(&self, f: F) -> GroupByKey<'_, T, F> - where - F: FnMut(&T) -> K, - K: PartialEq, - { + fn group(&self) -> Group<'_, T> { + Group { slice: self } + } + + fn group_by_key(&self, f: F) -> GroupByKey<'_, T, F> { GroupByKey { slice: self, f } } } +/// This struct is created by [`SliceExt::group`]. +pub struct Group<'a, T> { + slice: &'a [T], +} + +impl<'a, T> Iterator for Group<'a, T> +where + T: PartialEq, +{ + type Item = (&'a T, usize); + + fn next(&mut self) -> Option { + let mut iter = self.slice.iter(); + let first = iter.next()?; + let count = 1 + iter.take_while(|&t| t == first).count(); + self.slice = &self.slice[count ..]; + Some((first, count)) + } +} + /// This struct is created by [`SliceExt::group_by_key`]. pub struct GroupByKey<'a, T, F> { slice: &'a [T], @@ -115,15 +140,10 @@ where type Item = (K, &'a [T]); fn next(&mut self) -> Option { - let first = self.slice.first()?; - let key = (self.f)(first); - - let mut i = 1; - while self.slice.get(i).map_or(false, |t| (self.f)(t) == key) { - i += 1; - } - - let (head, tail) = self.slice.split_at(i); + let mut iter = self.slice.iter(); + let key = (self.f)(iter.next()?); + let count = 1 + iter.take_while(|t| (self.f)(t) == key).count(); + let (head, tail) = self.slice.split_at(count); self.slice = tail; Some((key, head)) }