mirror of
https://github.com/servo/servo.git
synced 2025-08-06 22:15:33 +01:00
auto merge of #2443 : bjz/servo/linebox_range, r=pcwalton
Glyph indices are currently not tracked, once they are, they will allow us to implement faster line breaks in the future. cc. @pcwalton
This commit is contained in:
commit
e5eac5b538
3 changed files with 306 additions and 91 deletions
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
use servo_util::vec::*;
|
use servo_util::vec::*;
|
||||||
use servo_util::range;
|
use servo_util::range;
|
||||||
use servo_util::range::{Range, RangeIndex, EachIndex};
|
use servo_util::range::{Range, RangeIndex, IntRangeIndex, EachIndex};
|
||||||
use servo_util::geometry::Au;
|
use servo_util::geometry::Au;
|
||||||
|
|
||||||
use std::cmp::{Ord, Eq};
|
use std::cmp::{Ord, Eq};
|
||||||
|
@ -526,7 +526,7 @@ pub struct GlyphStore {
|
||||||
is_whitespace: bool,
|
is_whitespace: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
range_index! {
|
int_range_index! {
|
||||||
#[doc = "An index that refers to a character in a text run. This could \
|
#[doc = "An index that refers to a character in a text run. This could \
|
||||||
point to the middle of a glyph."]
|
point to the middle of a glyph."]
|
||||||
struct CharIndex(int)
|
struct CharIndex(int)
|
||||||
|
|
|
@ -20,10 +20,12 @@ use gfx::font::FontMetrics;
|
||||||
use gfx::font_context::FontContext;
|
use gfx::font_context::FontContext;
|
||||||
use servo_util::geometry::Au;
|
use servo_util::geometry::Au;
|
||||||
use servo_util::geometry;
|
use servo_util::geometry;
|
||||||
use servo_util::range::{Range, RangeIndex};
|
use servo_util::range;
|
||||||
|
use servo_util::range::{EachIndex, Range, RangeIndex, IntRangeIndex};
|
||||||
use std::iter::Enumerate;
|
use std::iter::Enumerate;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
use std::num;
|
||||||
use std::slice::{Items, MutItems};
|
use std::slice::{Items, MutItems};
|
||||||
use std::u16;
|
use std::u16;
|
||||||
use style::computed_values::{text_align, vertical_align, white_space};
|
use style::computed_values::{text_align, vertical_align, white_space};
|
||||||
|
@ -56,13 +58,145 @@ use sync::Arc;
|
||||||
/// left corner of the green zone is the same as that of the line, but
|
/// left corner of the green zone is the same as that of the line, but
|
||||||
/// the green zone can be taller and wider than the line itself.
|
/// the green zone can be taller and wider than the line itself.
|
||||||
pub struct LineBox {
|
pub struct LineBox {
|
||||||
pub range: Range<BoxIndex>,
|
/// Consider the following HTML and rendered element with linebreaks:
|
||||||
|
///
|
||||||
|
/// ~~~html
|
||||||
|
/// <span>I <span>like truffles,</span> yes I do.</span>
|
||||||
|
/// ~~~
|
||||||
|
///
|
||||||
|
/// ~~~
|
||||||
|
/// +-----------+
|
||||||
|
/// | I like |
|
||||||
|
/// | truffles, |
|
||||||
|
/// | yes I do. |
|
||||||
|
/// +-----------+
|
||||||
|
/// ~~~
|
||||||
|
///
|
||||||
|
/// The ranges that describe these lines would be:
|
||||||
|
///
|
||||||
|
/// ~~~
|
||||||
|
/// | [0.0, 1.4) | [1.5, 2.0) | [2.1, 3.0) |
|
||||||
|
/// |------------|-------------|-------------|
|
||||||
|
/// | 'I like' | 'truffles,' | 'yes I do.' |
|
||||||
|
/// ~~~
|
||||||
|
pub range: Range<LineIndices>,
|
||||||
pub bounds: Rect<Au>,
|
pub bounds: Rect<Au>,
|
||||||
pub green_zone: Size2D<Au>
|
pub green_zone: Size2D<Au>
|
||||||
}
|
}
|
||||||
|
|
||||||
range_index! {
|
int_range_index! {
|
||||||
struct BoxIndex(int)
|
#[doc = "The index of a box fragment into the flattened vector of DOM"]
|
||||||
|
#[doc = "elements."]
|
||||||
|
#[doc = ""]
|
||||||
|
#[doc = "For example, given the HTML below:"]
|
||||||
|
#[doc = ""]
|
||||||
|
#[doc = "~~~"]
|
||||||
|
#[doc = "<span>I <span>like truffles,</span> yes I do.</span>"]
|
||||||
|
#[doc = "~~~"]
|
||||||
|
#[doc = ""]
|
||||||
|
#[doc = "The fragments would be indexed as follows:"]
|
||||||
|
#[doc = ""]
|
||||||
|
#[doc = "~~~"]
|
||||||
|
#[doc = "| 0 | 1 | 2 |"]
|
||||||
|
#[doc = "|------|------------------|--------------|"]
|
||||||
|
#[doc = "| 'I ' | 'like truffles,' | ' yes I do.' |"]
|
||||||
|
#[doc = "~~~"]
|
||||||
|
struct FragmentIndex(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
int_range_index! {
|
||||||
|
#[doc = "The index of a glyph in a single DOM fragment. Ligatures and"]
|
||||||
|
#[doc = "continuous runs of whitespace are treated as single glyphs."]
|
||||||
|
#[doc = "Non-breakable DOM fragments such as images are treated as"]
|
||||||
|
#[doc = "having a range length of `1`."]
|
||||||
|
#[doc = ""]
|
||||||
|
#[doc = "For example, given the HTML below:"]
|
||||||
|
#[doc = ""]
|
||||||
|
#[doc = "~~~"]
|
||||||
|
#[doc = "<span>like truffles,</span>"]
|
||||||
|
#[doc = "~~~"]
|
||||||
|
#[doc = ""]
|
||||||
|
#[doc = "The glyphs would be indexed as follows:"]
|
||||||
|
#[doc = ""]
|
||||||
|
#[doc = "~~~"]
|
||||||
|
#[doc = "| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |"]
|
||||||
|
#[doc = "|---|---|---|---|---|---|---|---|-----|---|----|----|"]
|
||||||
|
#[doc = "| l | i | k | e | | t | r | u | ffl | e | s | , |"]
|
||||||
|
#[doc = "~~~"]
|
||||||
|
struct GlyphIndex(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A line index consists of two indices: a fragment index that refers to the
|
||||||
|
/// index of a DOM fragment within a flattened inline element; and a glyph index
|
||||||
|
/// where the 0th glyph refers to the first glyph of that fragment.
|
||||||
|
#[deriving(Clone, Eq, Ord, TotalEq, TotalOrd, Zero)]
|
||||||
|
pub struct LineIndices {
|
||||||
|
pub fragment_index: FragmentIndex,
|
||||||
|
pub glyph_index: GlyphIndex,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RangeIndex for LineIndices {}
|
||||||
|
|
||||||
|
impl Add<LineIndices, LineIndices> for LineIndices {
|
||||||
|
fn add(&self, other: &LineIndices) -> LineIndices {
|
||||||
|
// TODO: use debug_assert! after rustc upgrade
|
||||||
|
if cfg!(not(ndebug)) {
|
||||||
|
assert!(other.fragment_index == num::zero() || other.glyph_index == num::zero(),
|
||||||
|
"Attempted to add {} to {}. Both the fragment_index and \
|
||||||
|
glyph_index of the RHS are non-zero. This probably \
|
||||||
|
was a mistake!", self, other);
|
||||||
|
}
|
||||||
|
LineIndices {
|
||||||
|
fragment_index: self.fragment_index + other.fragment_index,
|
||||||
|
glyph_index: self.glyph_index + other.glyph_index,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sub<LineIndices, LineIndices> for LineIndices {
|
||||||
|
fn sub(&self, other: &LineIndices) -> LineIndices {
|
||||||
|
// TODO: use debug_assert! after rustc upgrade
|
||||||
|
if cfg!(not(ndebug)) {
|
||||||
|
assert!(other.fragment_index == num::zero() || other.glyph_index == num::zero(),
|
||||||
|
"Attempted to subtract {} from {}. Both the \
|
||||||
|
fragment_index and glyph_index of the RHS are non-zero. \
|
||||||
|
This probably was a mistake!", self, other);
|
||||||
|
}
|
||||||
|
LineIndices {
|
||||||
|
fragment_index: self.fragment_index - other.fragment_index,
|
||||||
|
glyph_index: self.glyph_index - other.glyph_index,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Neg<LineIndices> for LineIndices {
|
||||||
|
fn neg(&self) -> LineIndices {
|
||||||
|
// TODO: use debug_assert! after rustc upgrade
|
||||||
|
if cfg!(not(ndebug)) {
|
||||||
|
assert!(self.fragment_index == num::zero() || self.glyph_index == num::zero(),
|
||||||
|
"Attempted to negate {}. Both the fragment_index and \
|
||||||
|
glyph_index are non-zero. This probably was a mistake!",
|
||||||
|
self);
|
||||||
|
}
|
||||||
|
LineIndices {
|
||||||
|
fragment_index: -self.fragment_index,
|
||||||
|
glyph_index: -self.glyph_index,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Show for LineIndices {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f.buf, "{}.{}", self.fragment_index, self.glyph_index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn each_fragment_index(range: &Range<LineIndices>) -> EachIndex<int, FragmentIndex> {
|
||||||
|
range::each_index(range.begin().fragment_index, range.length().fragment_index)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn each_glyph_index(range: &Range<LineIndices>) -> EachIndex<int, GlyphIndex> {
|
||||||
|
range::each_index(range.begin().glyph_index, range.length().glyph_index)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LineboxScanner {
|
struct LineboxScanner {
|
||||||
|
@ -103,7 +237,7 @@ impl LineboxScanner {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reset_linebox(&mut self) {
|
fn reset_linebox(&mut self) {
|
||||||
self.pending_line.range.reset(BoxIndex(0), BoxIndex(0));
|
self.pending_line.range.reset(num::zero(), num::zero());
|
||||||
self.pending_line.bounds = Rect(Point2D(Au::new(0), self.cur_y), Size2D(Au::new(0), Au::new(0)));
|
self.pending_line.bounds = Rect(Point2D(Au::new(0), self.cur_y), Size2D(Au::new(0), Au::new(0)));
|
||||||
self.pending_line.green_zone = Size2D(Au::new(0), Au::new(0))
|
self.pending_line.green_zone = Size2D(Au::new(0), Au::new(0))
|
||||||
}
|
}
|
||||||
|
@ -150,7 +284,7 @@ impl LineboxScanner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.pending_line.range.length() > BoxIndex(0) {
|
if self.pending_line.range.length() > num::zero() {
|
||||||
debug!("LineboxScanner: Partially full linebox {:u} left at end of scanning.",
|
debug!("LineboxScanner: Partially full linebox {:u} left at end of scanning.",
|
||||||
self.lines.len());
|
self.lines.len());
|
||||||
self.flush_current_line();
|
self.flush_current_line();
|
||||||
|
@ -197,7 +331,7 @@ impl LineboxScanner {
|
||||||
let first_box_size = first_box.border_box.size;
|
let first_box_size = first_box.border_box.size;
|
||||||
let splittable = first_box.can_split();
|
let splittable = first_box.can_split();
|
||||||
debug!("LineboxScanner: box size: {}, splittable: {}", first_box_size, splittable);
|
debug!("LineboxScanner: box size: {}, splittable: {}", first_box_size, splittable);
|
||||||
let line_is_empty: bool = self.pending_line.range.length() == BoxIndex(0);
|
let line_is_empty: bool = self.pending_line.range.length() == num::zero();
|
||||||
|
|
||||||
// Initally, pretend a splittable box has 0 width.
|
// Initally, pretend a splittable box has 0 width.
|
||||||
// We will move it later if it has nonzero width
|
// We will move it later if it has nonzero width
|
||||||
|
@ -353,7 +487,7 @@ impl LineboxScanner {
|
||||||
/// Tries to append the given box to the line, splitting it if necessary. Returns false only if
|
/// Tries to append the given box to the line, splitting it if necessary. Returns false only if
|
||||||
/// we should break the line.
|
/// we should break the line.
|
||||||
fn try_append_to_line(&mut self, in_box: Box, flow: &mut InlineFlow) -> bool {
|
fn try_append_to_line(&mut self, in_box: Box, flow: &mut InlineFlow) -> bool {
|
||||||
let line_is_empty = self.pending_line.range.length() == BoxIndex(0);
|
let line_is_empty = self.pending_line.range.length() == num::zero();
|
||||||
if line_is_empty {
|
if line_is_empty {
|
||||||
let (line_bounds, _) = self.initial_line_placement(&in_box, self.cur_y, flow);
|
let (line_bounds, _) = self.initial_line_placement(&in_box, self.cur_y, flow);
|
||||||
self.pending_line.bounds.origin = line_bounds.origin;
|
self.pending_line.bounds.origin = line_bounds.origin;
|
||||||
|
@ -448,11 +582,20 @@ impl LineboxScanner {
|
||||||
fn push_box_to_line(&mut self, box_: Box) {
|
fn push_box_to_line(&mut self, box_: Box) {
|
||||||
debug!("LineboxScanner: Pushing box {} to line {:u}", box_.debug_id(), self.lines.len());
|
debug!("LineboxScanner: Pushing box {} to line {:u}", box_.debug_id(), self.lines.len());
|
||||||
|
|
||||||
if self.pending_line.range.length() == BoxIndex(0) {
|
if self.pending_line.range.length() == num::zero() {
|
||||||
assert!(self.new_boxes.len() <= (u16::MAX as uint));
|
assert!(self.new_boxes.len() <= (u16::MAX as uint));
|
||||||
self.pending_line.range.reset(BoxIndex(self.new_boxes.len() as int), BoxIndex(0));
|
self.pending_line.range.reset(
|
||||||
|
LineIndices {
|
||||||
|
fragment_index: FragmentIndex(self.new_boxes.len() as int),
|
||||||
|
glyph_index: GlyphIndex(0) /* unused for now */,
|
||||||
|
},
|
||||||
|
num::zero()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
self.pending_line.range.extend_by(BoxIndex(1));
|
self.pending_line.range.extend_by(LineIndices {
|
||||||
|
fragment_index: FragmentIndex(1),
|
||||||
|
glyph_index: GlyphIndex(0) /* unused for now */ ,
|
||||||
|
});
|
||||||
self.pending_line.bounds.size.width = self.pending_line.bounds.size.width +
|
self.pending_line.bounds.size.width = self.pending_line.bounds.size.width +
|
||||||
box_.border_box.size.width;
|
box_.border_box.size.width;
|
||||||
self.pending_line.bounds.size.height = Au::max(self.pending_line.bounds.size.height,
|
self.pending_line.bounds.size.height = Au::max(self.pending_line.bounds.size.height,
|
||||||
|
@ -723,7 +866,7 @@ impl InlineFlow {
|
||||||
text_align::right => slack_width,
|
text_align::right => slack_width,
|
||||||
};
|
};
|
||||||
|
|
||||||
for i in line.range.each_index() {
|
for i in each_fragment_index(&line.range) {
|
||||||
let box_ = boxes.get_mut(i.to_uint());
|
let box_ = boxes.get_mut(i.to_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);
|
||||||
|
@ -854,7 +997,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.each_index() {
|
for box_i in each_fragment_index(&line.range) {
|
||||||
let fragment = self.boxes.boxes.get_mut(box_i.to_uint());
|
let fragment = self.boxes.boxes.get_mut(box_i.to_uint());
|
||||||
|
|
||||||
let InlineMetrics {
|
let InlineMetrics {
|
||||||
|
@ -930,7 +1073,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.each_index() {
|
for box_i in each_fragment_index(&line.range) {
|
||||||
let fragment = self.boxes.get_mut(box_i.to_uint());
|
let fragment = self.boxes.get_mut(box_i.to_uint());
|
||||||
match fragment.vertical_align() {
|
match fragment.vertical_align() {
|
||||||
vertical_align::top => {
|
vertical_align::top => {
|
||||||
|
@ -981,11 +1124,6 @@ impl fmt::Show for InlineFlow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
range_index! {
|
|
||||||
#[doc = "The index of a DOM element into the flat list of fragments."]
|
|
||||||
struct FragmentIndex(int)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Information that inline flows keep about a single nested element. This is used to recover the
|
/// Information that inline flows keep about a single nested element. This is used to recover the
|
||||||
/// DOM structure from the flat box list when it's needed.
|
/// DOM structure from the flat box list when it's needed.
|
||||||
pub struct FragmentRange {
|
pub struct FragmentRange {
|
||||||
|
|
|
@ -9,21 +9,26 @@ use std::num;
|
||||||
use std::num::{Bounded, Zero};
|
use std::num::{Bounded, Zero};
|
||||||
|
|
||||||
/// An index type to be used by a `Range`
|
/// An index type to be used by a `Range`
|
||||||
pub trait RangeIndex<T>: Eq + Ord
|
pub trait RangeIndex: Copy
|
||||||
+ Clone
|
+ Clone
|
||||||
+ Copy
|
+ fmt::Show
|
||||||
+ Zero
|
+ Eq
|
||||||
+ TotalEq
|
+ Ord
|
||||||
+ TotalOrd
|
+ TotalEq
|
||||||
+ Add<Self, Self>
|
+ TotalOrd
|
||||||
+ Sub<Self, Self>
|
+ Add<Self, Self>
|
||||||
+ Neg<Self>
|
+ Sub<Self, Self>
|
||||||
+ fmt::Show {
|
+ Neg<Self>
|
||||||
|
+ Zero {}
|
||||||
|
|
||||||
|
pub trait IntRangeIndex<T>: RangeIndex + Copy {
|
||||||
fn new(x: T) -> Self;
|
fn new(x: T) -> Self;
|
||||||
fn get(self) -> T;
|
fn get(self) -> T;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RangeIndex<int> for int {
|
impl RangeIndex for int {}
|
||||||
|
|
||||||
|
impl IntRangeIndex<int> for int {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn new(x: int) -> int { x }
|
fn new(x: int) -> int { x }
|
||||||
|
|
||||||
|
@ -33,7 +38,7 @@ impl RangeIndex<int> for int {
|
||||||
|
|
||||||
/// Implements a range index type with operator overloads
|
/// Implements a range index type with operator overloads
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! range_index {
|
macro_rules! int_range_index {
|
||||||
($(#[$attr:meta])* struct $Self:ident($T:ty)) => (
|
($(#[$attr:meta])* struct $Self:ident($T:ty)) => (
|
||||||
#[deriving(Clone, Eq, Ord, TotalEq, TotalOrd, Show, Zero)]
|
#[deriving(Clone, Eq, Ord, TotalEq, TotalOrd, Show, Zero)]
|
||||||
$(#[$attr])*
|
$(#[$attr])*
|
||||||
|
@ -46,7 +51,9 @@ macro_rules! range_index {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RangeIndex<$T> for $Self {
|
impl RangeIndex for $Self {}
|
||||||
|
|
||||||
|
impl IntRangeIndex<$T> for $Self {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn new(x: $T) -> $Self {
|
fn new(x: $T) -> $Self {
|
||||||
$Self(x)
|
$Self(x)
|
||||||
|
@ -95,11 +102,11 @@ pub enum RangeRelation<I> {
|
||||||
/// A range of indices
|
/// A range of indices
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone)]
|
||||||
pub struct Range<I> {
|
pub struct Range<I> {
|
||||||
off: I,
|
begin: I,
|
||||||
len: I,
|
length: I,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Int, I: fmt::Show + RangeIndex<T>> fmt::Show for Range<I> {
|
impl<I: RangeIndex> 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())
|
||||||
}
|
}
|
||||||
|
@ -110,16 +117,14 @@ pub struct EachIndex<T, I> {
|
||||||
it: iter::Range<T>,
|
it: iter::Range<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn each_index<T: Int, I: RangeIndex<T>>(start: I, stop: I) -> EachIndex<T, I> {
|
pub fn each_index<T: Int, I: IntRangeIndex<T>>(start: I, stop: I) -> EachIndex<T, I> {
|
||||||
EachIndex {
|
EachIndex { it: iter::range(start.get(), stop.get()) }
|
||||||
it: iter::range(start.get(), stop.get())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Int, I: RangeIndex<T>> Iterator<I> for EachIndex<T, I> {
|
impl<T: Int, I: IntRangeIndex<T>> Iterator<I> for EachIndex<T, I> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn next(&mut self) -> Option<I> {
|
fn next(&mut self) -> Option<I> {
|
||||||
self.it.next().map(|i| RangeIndex::new(i))
|
self.it.next().map(|i| IntRangeIndex::new(i))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -128,10 +133,18 @@ impl<T: Int, I: RangeIndex<T>> Iterator<I> for EachIndex<T, I> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Int, I: RangeIndex<T>> Range<I> {
|
impl<I: RangeIndex> Range<I> {
|
||||||
|
/// Create a new range from beginning and length offsets. This could be
|
||||||
|
/// denoted as `[begin, begin + length)`.
|
||||||
|
///
|
||||||
|
/// ~~~
|
||||||
|
/// |-- begin ->|-- length ->|
|
||||||
|
/// | | |
|
||||||
|
/// <- o - - - - - +============+ - - - ->
|
||||||
|
/// ~~~
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn new(off: I, len: I) -> Range<I> {
|
pub fn new(begin: I, length: I) -> Range<I> {
|
||||||
Range { off: off, len: len }
|
Range { begin: begin, length: length }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -139,76 +152,108 @@ impl<T: Int, I: RangeIndex<T>> Range<I> {
|
||||||
Range::new(num::zero(), num::zero())
|
Range::new(num::zero(), num::zero())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The index offset to the beginning of the range.
|
||||||
|
///
|
||||||
|
/// ~~~
|
||||||
|
/// |-- begin ->|
|
||||||
|
/// | |
|
||||||
|
/// <- o - - - - - +============+ - - - ->
|
||||||
|
/// ~~~
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn begin(&self) -> I { self.off }
|
pub fn begin(&self) -> I { self.begin }
|
||||||
#[inline]
|
|
||||||
pub fn length(&self) -> I { self.len }
|
|
||||||
#[inline]
|
|
||||||
pub fn end(&self) -> I { self.off + self.len }
|
|
||||||
|
|
||||||
|
/// The index offset from the beginning to the end of the range.
|
||||||
|
///
|
||||||
|
/// ~~~
|
||||||
|
/// |-- length ->|
|
||||||
|
/// | |
|
||||||
|
/// <- o - - - - - +============+ - - - ->
|
||||||
|
/// ~~~
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn each_index(&self) -> EachIndex<T, I> {
|
pub fn length(&self) -> I { self.length }
|
||||||
each_index(self.off, self.off + self.len)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/// The index offset to the end of the range.
|
||||||
|
///
|
||||||
|
/// ~~~
|
||||||
|
/// |--------- end --------->|
|
||||||
|
/// | |
|
||||||
|
/// <- o - - - - - +============+ - - - ->
|
||||||
|
/// ~~~
|
||||||
|
#[inline]
|
||||||
|
pub fn end(&self) -> I { self.begin + self.length }
|
||||||
|
|
||||||
|
/// `true` if the index is between the beginning and the end of the range.
|
||||||
|
///
|
||||||
|
/// ~~~
|
||||||
|
/// false true false
|
||||||
|
/// | | |
|
||||||
|
/// <- o - - + - - +=====+======+ - + - ->
|
||||||
|
/// ~~~
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn contains(&self, i: I) -> bool {
|
pub fn contains(&self, i: I) -> bool {
|
||||||
i >= self.begin() && i < self.end()
|
i >= self.begin() && i < self.end()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
/// `true` if the offset from the beginning to the end of the range is zero.
|
||||||
pub fn is_valid_for_string(&self, s: &str) -> bool {
|
|
||||||
let s_len = s.len();
|
|
||||||
match num::cast::<uint, T>(s_len) {
|
|
||||||
Some(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 the range index (max={})", s_len,
|
|
||||||
{
|
|
||||||
let max: T = Bounded::max_value();
|
|
||||||
let val: I = RangeIndex::new(max);
|
|
||||||
val
|
|
||||||
});
|
|
||||||
false
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.len.is_zero()
|
self.length().is_zero()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Shift the entire range by the supplied index delta.
|
||||||
|
///
|
||||||
|
/// ~~~
|
||||||
|
/// |-- delta ->|
|
||||||
|
/// | |
|
||||||
|
/// <- o - +============+ - - - - - | - - - ->
|
||||||
|
/// |
|
||||||
|
/// <- o - - - - - - - +============+ - - - ->
|
||||||
|
/// ~~~
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn shift_by(&mut self, i: I) {
|
pub fn shift_by(&mut self, delta: I) {
|
||||||
self.off = self.off + i;
|
self.begin = self.begin + delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extend the end of the range by the supplied index delta.
|
||||||
|
///
|
||||||
|
/// ~~~
|
||||||
|
/// |-- delta ->|
|
||||||
|
/// | |
|
||||||
|
/// <- o - - - - - +====+ - - - - - | - - - ->
|
||||||
|
/// |
|
||||||
|
/// <- o - - - - - +================+ - - - ->
|
||||||
|
/// ~~~
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn extend_by(&mut self, i: I) {
|
pub fn extend_by(&mut self, delta: I) {
|
||||||
self.len = self.len + i;
|
self.length = self.length + delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Move the end of the range to the target index.
|
||||||
|
///
|
||||||
|
/// ~~~
|
||||||
|
/// target
|
||||||
|
/// |
|
||||||
|
/// <- o - - - - - +====+ - - - - - | - - - ->
|
||||||
|
/// |
|
||||||
|
/// <- o - - - - - +================+ - - - ->
|
||||||
|
/// ~~~
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn extend_to(&mut self, i: I) {
|
pub fn extend_to(&mut self, target: I) {
|
||||||
self.len = i - self.off;
|
self.length = target - self.begin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adjust the beginning offset and the length by the supplied deltas.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn adjust_by(&mut self, off_i: I, len_i: I) {
|
pub fn adjust_by(&mut self, begin_delta: I, length_delta: I) {
|
||||||
self.off = self.off + off_i;
|
self.begin = self.begin + begin_delta;
|
||||||
self.len = self.len + len_i;
|
self.length = self.length + length_delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the begin and length values.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn reset(&mut self, off_i: I, len_i: I) {
|
pub fn reset(&mut self, begin: I, length: I) {
|
||||||
self.off = off_i;
|
self.begin = begin;
|
||||||
self.len = len_i;
|
self.length = length;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -254,6 +299,38 @@ impl<T: Int, I: RangeIndex<T>> Range<I> {
|
||||||
fail!("relation_to_range(): didn't classify self={}, other={}",
|
fail!("relation_to_range(): didn't classify self={}, other={}",
|
||||||
self, other);
|
self, other);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Methods for `Range`s with indices based on integer values
|
||||||
|
impl<T: Int, I: IntRangeIndex<T>> Range<I> {
|
||||||
|
/// Returns an iterater that increments over `[begin, end)`.
|
||||||
|
#[inline]
|
||||||
|
pub fn each_index(&self) -> EachIndex<T, I> {
|
||||||
|
each_index(self.begin(), self.end())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn is_valid_for_string(&self, s: &str) -> bool {
|
||||||
|
let s_len = s.len();
|
||||||
|
match num::cast::<uint, T>(s_len) {
|
||||||
|
Some(len) => {
|
||||||
|
let len = IntRangeIndex::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 the range index (max={})", s_len,
|
||||||
|
{
|
||||||
|
let max: T = Bounded::max_value();
|
||||||
|
let val: I = IntRangeIndex::new(max);
|
||||||
|
val
|
||||||
|
});
|
||||||
|
false
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn repair_after_coalesced_range(&mut self, other: &Range<I>) {
|
pub fn repair_after_coalesced_range(&mut self, other: &Range<I>) {
|
||||||
|
@ -261,7 +338,7 @@ impl<T: Int, I: RangeIndex<T>> Range<I> {
|
||||||
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>());
|
let _1: I = IntRangeIndex::new(num::one::<T>());
|
||||||
match relation {
|
match relation {
|
||||||
EntirelyBefore => {},
|
EntirelyBefore => {},
|
||||||
EntirelyAfter => { self.shift_by(-other.length()); },
|
EntirelyAfter => { self.shift_by(-other.length()); },
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue