Add RangeIndex trait and iterator

This will allow for the definition of typesafe range units in the future, for example for glyph indices. This also adds a macro that allows for the easy implementation of new range index types.
This commit is contained in:
Brendan Zabarauskas 2014-05-08 10:52:54 -07:00
parent 68f9aad883
commit 49df943649
5 changed files with 152 additions and 49 deletions

View file

@ -3,7 +3,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use servo_util::vec::*; use servo_util::vec::*;
use servo_util::range::Range; use servo_util::range;
use servo_util::range::{Range, EachIndex};
use servo_util::geometry::Au; use servo_util::geometry::Au;
use std::cmp::{Ord, Eq}; use std::cmp::{Ord, Eq};
@ -11,7 +12,6 @@ use std::num::{NumCast, Zero};
use std::mem; use std::mem;
use std::u16; use std::u16;
use std::slice; use std::slice;
use std::iter;
use geom::point::Point2D; use geom::point::Point2D;
/// GlyphEntry is a port of Gecko's CompressedGlyph scheme for storing glyph data compactly. /// GlyphEntry is a port of Gecko's CompressedGlyph scheme for storing glyph data compactly.
@ -609,7 +609,7 @@ impl<'a> GlyphStore {
GlyphIterator { GlyphIterator {
store: self, store: self,
char_index: rang.begin(), char_index: rang.begin(),
char_range: rang.eachi(), char_range: rang.each_index(),
glyph_range: None glyph_range: None
} }
} }
@ -674,8 +674,8 @@ impl<'a> GlyphStore {
pub struct GlyphIterator<'a> { pub struct GlyphIterator<'a> {
store: &'a GlyphStore, store: &'a GlyphStore,
char_index: int, char_index: int,
char_range: iter::Range<int>, char_range: EachIndex<int, int>,
glyph_range: Option<iter::Range<int>>, glyph_range: Option<EachIndex<int, int>>,
} }
impl<'a> GlyphIterator<'a> { impl<'a> GlyphIterator<'a> {
@ -698,7 +698,7 @@ impl<'a> GlyphIterator<'a> {
fn next_complex_glyph(&mut self, entry: &GlyphEntry, i: int) fn next_complex_glyph(&mut self, entry: &GlyphEntry, i: int)
-> Option<(int, GlyphInfo<'a>)> { -> Option<(int, GlyphInfo<'a>)> {
let glyphs = self.store.detail_store.get_detailed_glyphs_for_entry(i, entry.glyph_count()); let glyphs = self.store.detail_store.get_detailed_glyphs_for_entry(i, entry.glyph_count());
self.glyph_range = Some(range(0, glyphs.len() as int)); self.glyph_range = Some(range::each_index(0, glyphs.len() as int));
self.next() self.next()
} }
} }

View file

@ -316,7 +316,7 @@ impl Shaper {
// extend glyph range to max glyph index covered by char_span, // extend glyph range to max glyph index covered by char_span,
// in cases where one char made several glyphs and left some unassociated chars. // in cases where one char made several glyphs and left some unassociated chars.
let mut max_glyph_idx = glyph_span.end(); let mut max_glyph_idx = glyph_span.end();
for i in char_byte_span.eachi() { for i in char_byte_span.each_index() {
if byteToGlyph[i as uint] > NO_GLYPH { if byteToGlyph[i as uint] > NO_GLYPH {
max_glyph_idx = cmp::max(byteToGlyph[i as uint] as int + 1, max_glyph_idx); max_glyph_idx = cmp::max(byteToGlyph[i as uint] as int + 1, max_glyph_idx);
} }
@ -340,7 +340,7 @@ impl Shaper {
probably doesn't work."); probably doesn't work.");
let mut all_glyphs_are_within_cluster: bool = true; let mut all_glyphs_are_within_cluster: bool = true;
for j in glyph_span.eachi() { for j in glyph_span.each_index() {
let loc = glyph_data.byte_offset_of_glyph(j); let loc = glyph_data.byte_offset_of_glyph(j);
if !char_byte_span.contains(loc) { if !char_byte_span.contains(loc) {
all_glyphs_are_within_cluster = false; all_glyphs_are_within_cluster = false;
@ -414,7 +414,7 @@ impl Shaper {
// collect all glyphs to be assigned to the first character. // collect all glyphs to be assigned to the first character.
let mut datas = vec!(); let mut datas = vec!();
for glyph_i in glyph_span.eachi() { for glyph_i in glyph_span.each_index() {
let shape = glyph_data.get_entry_for_glyph(glyph_i, &mut y_pos); let shape = glyph_data.get_entry_for_glyph(glyph_i, &mut y_pos);
datas.push(GlyphData::new(shape.codepoint, datas.push(GlyphData::new(shape.codepoint,
shape.advance, shape.advance,

View file

@ -713,7 +713,7 @@ impl InlineFlow {
text_align::right => slack_width, text_align::right => slack_width,
}; };
for i in line.range.eachi() { for i in line.range.each_index() {
let box_ = boxes.get_mut(i as uint); let box_ = boxes.get_mut(i as uint);
let size = box_.border_box.size; let size = box_.border_box.size;
box_.border_box = Rect(Point2D(offset_x, box_.border_box.origin.y), size); box_.border_box = Rect(Point2D(offset_x, box_.border_box.origin.y), size);
@ -844,7 +844,7 @@ impl Flow for InlineFlow {
let (mut largest_height_for_top_fragments, mut largest_height_for_bottom_fragments) = let (mut largest_height_for_top_fragments, mut largest_height_for_bottom_fragments) =
(Au(0), Au(0)); (Au(0), Au(0));
for box_i in line.range.eachi() { for box_i in line.range.each_index() {
let fragment = self.boxes.boxes.get_mut(box_i as uint); let fragment = self.boxes.boxes.get_mut(box_i as uint);
let InlineMetrics { let InlineMetrics {
@ -920,7 +920,7 @@ impl Flow for InlineFlow {
// Compute the final positions in the block direction of each fragment. Recall that // Compute the final positions in the block direction of each fragment. Recall that
// `fragment.border_box.origin.y` was set to the distance from the baseline above. // `fragment.border_box.origin.y` was set to the distance from the baseline above.
for box_i in line.range.eachi() { for box_i in line.range.each_index() {
let fragment = self.boxes.get_mut(box_i as uint); let fragment = self.boxes.get_mut(box_i as uint);
match fragment.vertical_align() { match fragment.vertical_align() {
vertical_align::top => { vertical_align::top => {

View file

@ -232,7 +232,7 @@ impl TextRunScanner {
// Make new boxes with the run and adjusted text indices. // Make new boxes with the run and adjusted text indices.
debug!("TextRunScanner: pushing box(es) in range: {}", self.clump); debug!("TextRunScanner: pushing box(es) in range: {}", self.clump);
for i in clump.eachi() { for i in clump.each_index() {
let logical_offset = i - self.clump.begin(); let logical_offset = i - self.clump.begin();
let range = new_ranges.get(logical_offset as uint); let range = new_ranges.get(logical_offset as uint);
if range.length() == 0 { if range.length() == 0 {

View file

@ -6,12 +6,85 @@ use std::cmp::{max, min};
use std::iter; use std::iter;
use std::fmt; use std::fmt;
use std::num; use std::num;
use std::num::Bounded; use std::num::{Bounded, Zero};
/// An index type to be used by a `Range`
pub trait RangeIndex<T>: Eq + Ord
+ Clone
+ Copy
+ Zero
+ TotalEq
+ TotalOrd
+ Add<Self, Self>
+ Sub<Self, Self>
+ Neg<Self>
+ fmt::Show {
fn new(x: T) -> Self;
fn get(self) -> T;
}
impl RangeIndex<int> for int {
#[inline]
fn new(x: int) -> int { x }
#[inline]
fn get(self) -> int { self }
}
/// Implements a range index type with operator overloads
#[macro_export]
macro_rules! range_index {
($(#[$attr:meta])* struct $Self:ident($T:ty)) => (
#[deriving(Clone, Eq, Ord, TotalEq, TotalOrd, Show, Zero)]
$(#[$attr])*
pub struct $Self(pub $T);
impl $Self {
#[inline]
pub fn to_uint(self) -> uint {
self.get() as uint
}
}
impl RangeIndex<$T> for $Self {
#[inline]
fn new(x: $T) -> $Self {
$Self(x)
}
#[inline]
fn get(self) -> $T {
match self { $Self(x) => x }
}
}
impl Add<$Self, $Self> for $Self {
#[inline]
fn add(&self, other: &$Self) -> $Self {
$Self(self.get() + other.get())
}
}
impl Sub<$Self, $Self> for $Self {
#[inline]
fn sub(&self, other: &$Self) -> $Self {
$Self(self.get() - other.get())
}
}
impl Neg<$Self> for $Self {
#[inline]
fn neg(&self) -> $Self {
$Self(-self.get())
}
}
)
}
#[deriving(Show)] #[deriving(Show)]
pub enum RangeRelation<T> { pub enum RangeRelation<I> {
OverlapsBegin(/* overlap */ T), OverlapsBegin(/* overlap */ I),
OverlapsEnd(/* overlap */ T), OverlapsEnd(/* overlap */ I),
ContainedBy, ContainedBy,
Contains, Contains,
Coincides, Coincides,
@ -19,59 +92,88 @@ pub enum RangeRelation<T> {
EntirelyAfter EntirelyAfter
} }
/// A range of indices
#[deriving(Clone)] #[deriving(Clone)]
pub struct Range<T> { pub struct Range<I> {
off: T, off: I,
len: T, len: I,
} }
impl<T: Int + TotalOrd + Signed> fmt::Show for Range<T> { impl<T: Int, I: fmt::Show + RangeIndex<T>> fmt::Show for Range<I> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f.buf, "[{} .. {})", self.begin(), self.end()) write!(f.buf, "[{} .. {})", self.begin(), self.end())
} }
} }
impl<T: Int + TotalOrd + Signed> Range<T> { /// An iterator over each index in a range
pub struct EachIndex<T, I> {
it: iter::Range<T>,
}
pub fn each_index<T: Int, I: RangeIndex<T>>(start: I, stop: I) -> EachIndex<T, I> {
EachIndex {
it: iter::range(start.get(), stop.get())
}
}
impl<T: Int, I: RangeIndex<T>> Iterator<I> for EachIndex<T, I> {
#[inline] #[inline]
pub fn new(off: T, len: T) -> Range<T> { fn next(&mut self) -> Option<I> {
Range { self.it.next().map(|i| RangeIndex::new(i))
off: off,
len: len,
}
} }
#[inline] #[inline]
pub fn empty() -> Range<T> { fn size_hint(&self) -> (uint, Option<uint>) {
self.it.size_hint()
}
}
impl<T: Int, I: RangeIndex<T>> Range<I> {
#[inline]
pub fn new(off: I, len: I) -> Range<I> {
Range { off: off, len: len }
}
#[inline]
pub fn empty() -> Range<I> {
Range::new(num::zero(), num::zero()) Range::new(num::zero(), num::zero())
} }
#[inline] #[inline]
pub fn begin(&self) -> T { self.off } pub fn begin(&self) -> I { self.off }
#[inline] #[inline]
pub fn length(&self) -> T { self.len } pub fn length(&self) -> I { self.len }
#[inline] #[inline]
pub fn end(&self) -> T { self.off + self.len } pub fn end(&self) -> I { self.off + self.len }
#[inline] #[inline]
pub fn eachi(&self) -> iter::Range<T> { pub fn each_index(&self) -> EachIndex<T, I> {
range(self.off, self.off + self.len) each_index(self.off, self.off + self.len)
} }
#[inline] #[inline]
pub fn contains(&self, i: T) -> bool { pub fn contains(&self, i: I) -> bool {
i >= self.begin() && i < self.end() i >= self.begin() && i < self.end()
} }
#[inline] #[inline]
pub fn is_valid_for_string(&self, s: &str) -> bool { pub fn is_valid_for_string(&self, s: &str) -> bool {
let s_len = s.len(); let s_len = s.len();
match num::cast(s_len) { match num::cast::<uint, T>(s_len) {
Some(len) => { Some(len) => {
self.begin() < len && self.end() <= len && self.length() <= len let len = RangeIndex::new(len);
self.begin() < len
&& self.end() <= len
&& self.length() <= len
}, },
None => { None => {
debug!("Range<T>::is_valid_for_string: string length (len={}) is longer than the max \ debug!("Range<T>::is_valid_for_string: string length (len={}) is longer than the \
value for T (max={})", s_len, { let val: T = Bounded::max_value(); val }); max value for the range index (max={})", s_len,
{
let max: T = Bounded::max_value();
let val: I = RangeIndex::new(max);
val
});
false false
}, },
} }
@ -83,34 +185,34 @@ impl<T: Int + TotalOrd + Signed> Range<T> {
} }
#[inline] #[inline]
pub fn shift_by(&mut self, i: T) { pub fn shift_by(&mut self, i: I) {
self.off = self.off + i; self.off = self.off + i;
} }
#[inline] #[inline]
pub fn extend_by(&mut self, i: T) { pub fn extend_by(&mut self, i: I) {
self.len = self.len + i; self.len = self.len + i;
} }
#[inline] #[inline]
pub fn extend_to(&mut self, i: T) { pub fn extend_to(&mut self, i: I) {
self.len = i - self.off; self.len = i - self.off;
} }
#[inline] #[inline]
pub fn adjust_by(&mut self, off_i: T, len_i: T) { pub fn adjust_by(&mut self, off_i: I, len_i: I) {
self.off = self.off + off_i; self.off = self.off + off_i;
self.len = self.len + len_i; self.len = self.len + len_i;
} }
#[inline] #[inline]
pub fn reset(&mut self, off_i: T, len_i: T) { pub fn reset(&mut self, off_i: I, len_i: I) {
self.off = off_i; self.off = off_i;
self.len = len_i; self.len = len_i;
} }
#[inline] #[inline]
pub fn intersect(&self, other: &Range<T>) -> Range<T> { pub fn intersect(&self, other: &Range<I>) -> Range<I> {
let begin = max(self.begin(), other.begin()); let begin = max(self.begin(), other.begin());
let end = min(self.end(), other.end()); let end = min(self.end(), other.end());
@ -125,7 +227,7 @@ impl<T: Int + TotalOrd + Signed> Range<T> {
/// from the point of view of `self`. So, 'EntirelyBefore' means /// from the point of view of `self`. So, 'EntirelyBefore' means
/// that the `self` range is entirely before `other` range. /// that the `self` range is entirely before `other` range.
#[inline] #[inline]
pub fn relation_to_range(&self, other: &Range<T>) -> RangeRelation<T> { pub fn relation_to_range(&self, other: &Range<I>) -> RangeRelation<I> {
if other.begin() > self.end() { if other.begin() > self.end() {
return EntirelyBefore; return EntirelyBefore;
} }
@ -154,19 +256,20 @@ impl<T: Int + TotalOrd + Signed> Range<T> {
} }
#[inline] #[inline]
pub fn repair_after_coalesced_range(&mut self, other: &Range<T>) { pub fn repair_after_coalesced_range(&mut self, other: &Range<I>) {
let relation = self.relation_to_range(other); let relation = self.relation_to_range(other);
debug!("repair_after_coalesced_range: possibly repairing range {}", *self); debug!("repair_after_coalesced_range: possibly repairing range {}", *self);
debug!("repair_after_coalesced_range: relation of original range and coalesced range {}: {}", debug!("repair_after_coalesced_range: relation of original range and coalesced range {}: {}",
*other, relation); *other, relation);
let _1: I = RangeIndex::new(num::one::<T>());
match relation { match relation {
EntirelyBefore => {}, EntirelyBefore => {},
EntirelyAfter => { self.shift_by(-other.length()); }, EntirelyAfter => { self.shift_by(-other.length()); },
Coincides | ContainedBy => { self.reset(other.begin(), num::one()); }, Coincides | ContainedBy => { self.reset(other.begin(), _1); },
Contains => { self.extend_by(-other.length()); }, Contains => { self.extend_by(-other.length()); },
OverlapsBegin(overlap) => { self.extend_by(num::one::<T>() - overlap); }, OverlapsBegin(overlap) => { self.extend_by(_1 - overlap); },
OverlapsEnd(overlap) => { OverlapsEnd(overlap) => {
let len = self.length() - overlap + num::one(); let len = self.length() - overlap + _1;
self.reset(other.begin(), len); self.reset(other.begin(), len);
} }
}; };