mirror of
https://github.com/servo/servo.git
synced 2025-06-22 16:18:59 +01:00
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:
parent
68f9aad883
commit
49df943649
5 changed files with 152 additions and 49 deletions
|
@ -3,7 +3,8 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
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 std::cmp::{Ord, Eq};
|
||||
|
@ -11,7 +12,6 @@ use std::num::{NumCast, Zero};
|
|||
use std::mem;
|
||||
use std::u16;
|
||||
use std::slice;
|
||||
use std::iter;
|
||||
use geom::point::Point2D;
|
||||
|
||||
/// GlyphEntry is a port of Gecko's CompressedGlyph scheme for storing glyph data compactly.
|
||||
|
@ -609,7 +609,7 @@ impl<'a> GlyphStore {
|
|||
GlyphIterator {
|
||||
store: self,
|
||||
char_index: rang.begin(),
|
||||
char_range: rang.eachi(),
|
||||
char_range: rang.each_index(),
|
||||
glyph_range: None
|
||||
}
|
||||
}
|
||||
|
@ -674,8 +674,8 @@ impl<'a> GlyphStore {
|
|||
pub struct GlyphIterator<'a> {
|
||||
store: &'a GlyphStore,
|
||||
char_index: int,
|
||||
char_range: iter::Range<int>,
|
||||
glyph_range: Option<iter::Range<int>>,
|
||||
char_range: EachIndex<int, int>,
|
||||
glyph_range: Option<EachIndex<int, int>>,
|
||||
}
|
||||
|
||||
impl<'a> GlyphIterator<'a> {
|
||||
|
@ -698,7 +698,7 @@ impl<'a> GlyphIterator<'a> {
|
|||
fn next_complex_glyph(&mut self, entry: &GlyphEntry, i: int)
|
||||
-> Option<(int, GlyphInfo<'a>)> {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -316,7 +316,7 @@ impl Shaper {
|
|||
// extend glyph range to max glyph index covered by char_span,
|
||||
// in cases where one char made several glyphs and left some unassociated chars.
|
||||
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 {
|
||||
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.");
|
||||
|
||||
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);
|
||||
if !char_byte_span.contains(loc) {
|
||||
all_glyphs_are_within_cluster = false;
|
||||
|
@ -414,7 +414,7 @@ impl Shaper {
|
|||
// collect all glyphs to be assigned to the first character.
|
||||
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);
|
||||
datas.push(GlyphData::new(shape.codepoint,
|
||||
shape.advance,
|
||||
|
|
|
@ -713,7 +713,7 @@ impl InlineFlow {
|
|||
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 size = box_.border_box.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) =
|
||||
(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 InlineMetrics {
|
||||
|
@ -920,7 +920,7 @@ impl Flow for InlineFlow {
|
|||
|
||||
// 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.
|
||||
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);
|
||||
match fragment.vertical_align() {
|
||||
vertical_align::top => {
|
||||
|
|
|
@ -232,7 +232,7 @@ impl TextRunScanner {
|
|||
|
||||
// Make new boxes with the run and adjusted text indices.
|
||||
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 range = new_ranges.get(logical_offset as uint);
|
||||
if range.length() == 0 {
|
||||
|
|
|
@ -6,12 +6,85 @@ use std::cmp::{max, min};
|
|||
use std::iter;
|
||||
use std::fmt;
|
||||
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)]
|
||||
pub enum RangeRelation<T> {
|
||||
OverlapsBegin(/* overlap */ T),
|
||||
OverlapsEnd(/* overlap */ T),
|
||||
pub enum RangeRelation<I> {
|
||||
OverlapsBegin(/* overlap */ I),
|
||||
OverlapsEnd(/* overlap */ I),
|
||||
ContainedBy,
|
||||
Contains,
|
||||
Coincides,
|
||||
|
@ -19,59 +92,88 @@ pub enum RangeRelation<T> {
|
|||
EntirelyAfter
|
||||
}
|
||||
|
||||
/// A range of indices
|
||||
#[deriving(Clone)]
|
||||
pub struct Range<T> {
|
||||
off: T,
|
||||
len: T,
|
||||
pub struct Range<I> {
|
||||
off: I,
|
||||
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 {
|
||||
write!(f.buf, "[{} .. {})", self.begin(), self.end())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Int + TotalOrd + Signed> Range<T> {
|
||||
#[inline]
|
||||
pub fn new(off: T, len: T) -> Range<T> {
|
||||
Range {
|
||||
off: off,
|
||||
len: len,
|
||||
/// 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]
|
||||
pub fn empty() -> Range<T> {
|
||||
fn next(&mut self) -> Option<I> {
|
||||
self.it.next().map(|i| RangeIndex::new(i))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
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())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn begin(&self) -> T { self.off }
|
||||
pub fn begin(&self) -> I { self.off }
|
||||
#[inline]
|
||||
pub fn length(&self) -> T { self.len }
|
||||
pub fn length(&self) -> I { self.len }
|
||||
#[inline]
|
||||
pub fn end(&self) -> T { self.off + self.len }
|
||||
pub fn end(&self) -> I { self.off + self.len }
|
||||
|
||||
#[inline]
|
||||
pub fn eachi(&self) -> iter::Range<T> {
|
||||
range(self.off, self.off + self.len)
|
||||
pub fn each_index(&self) -> EachIndex<T, I> {
|
||||
each_index(self.off, self.off + self.len)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn contains(&self, i: T) -> bool {
|
||||
pub fn contains(&self, i: I) -> bool {
|
||||
i >= self.begin() && i < self.end()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_valid_for_string(&self, s: &str) -> bool {
|
||||
let s_len = s.len();
|
||||
match num::cast(s_len) {
|
||||
match num::cast::<uint, T>(s_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 => {
|
||||
debug!("Range<T>::is_valid_for_string: string length (len={}) is longer than the max \
|
||||
value for T (max={})", s_len, { let val: T = Bounded::max_value(); val });
|
||||
debug!("Range<T>::is_valid_for_string: string length (len={}) is longer than the \
|
||||
max value for the range index (max={})", s_len,
|
||||
{
|
||||
let max: T = Bounded::max_value();
|
||||
let val: I = RangeIndex::new(max);
|
||||
val
|
||||
});
|
||||
false
|
||||
},
|
||||
}
|
||||
|
@ -83,34 +185,34 @@ impl<T: Int + TotalOrd + Signed> Range<T> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn shift_by(&mut self, i: T) {
|
||||
pub fn shift_by(&mut self, i: I) {
|
||||
self.off = self.off + i;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn extend_by(&mut self, i: T) {
|
||||
pub fn extend_by(&mut self, i: I) {
|
||||
self.len = self.len + i;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn extend_to(&mut self, i: T) {
|
||||
pub fn extend_to(&mut self, i: I) {
|
||||
self.len = i - self.off;
|
||||
}
|
||||
|
||||
#[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.len = self.len + len_i;
|
||||
}
|
||||
|
||||
#[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.len = len_i;
|
||||
}
|
||||
|
||||
#[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 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
|
||||
/// that the `self` range is entirely before `other` range.
|
||||
#[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() {
|
||||
return EntirelyBefore;
|
||||
}
|
||||
|
@ -154,19 +256,20 @@ impl<T: Int + TotalOrd + Signed> Range<T> {
|
|||
}
|
||||
|
||||
#[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);
|
||||
debug!("repair_after_coalesced_range: possibly repairing range {}", *self);
|
||||
debug!("repair_after_coalesced_range: relation of original range and coalesced range {}: {}",
|
||||
*other, relation);
|
||||
let _1: I = RangeIndex::new(num::one::<T>());
|
||||
match relation {
|
||||
EntirelyBefore => {},
|
||||
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()); },
|
||||
OverlapsBegin(overlap) => { self.extend_by(num::one::<T>() - overlap); },
|
||||
OverlapsBegin(overlap) => { self.extend_by(_1 - overlap); },
|
||||
OverlapsEnd(overlap) => {
|
||||
let len = self.length() - overlap + num::one();
|
||||
let len = self.length() - overlap + _1;
|
||||
self.reset(other.begin(), len);
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue