aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/util/range.rs
diff options
context:
space:
mode:
authorBrendan Zabarauskas <bjzaba@yahoo.com.au>2014-05-08 10:52:54 -0700
committerBrendan Zabarauskas <bjzaba@yahoo.com.au>2014-05-12 11:57:29 -0700
commit49df943649fec64a80b56bd26f0fb6454dc281bd (patch)
treea2246be072540a2bda307fecc3a9a8fccc7478af /src/components/util/range.rs
parent68f9aad883fb7335b9e2dddb24e96fb61c5653bc (diff)
downloadservo-49df943649fec64a80b56bd26f0fb6454dc281bd.tar.gz
servo-49df943649fec64a80b56bd26f0fb6454dc281bd.zip
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.
Diffstat (limited to 'src/components/util/range.rs')
-rw-r--r--src/components/util/range.rs175
1 files changed, 139 insertions, 36 deletions
diff --git a/src/components/util/range.rs b/src/components/util/range.rs
index 0acf6343dab..05421d9af87 100644
--- a/src/components/util/range.rs
+++ b/src/components/util/range.rs
@@ -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> {
+/// 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 new(off: T, len: T) -> Range<T> {
- Range {
- off: off,
- len: len,
- }
+ 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<T> {
+ 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);
}
};