Optimize some span operations
Decode span data only once
This commit is contained in:
parent
2e6a1a9fb4
commit
06f7f1f68b
2 changed files with 58 additions and 30 deletions
|
@ -370,17 +370,18 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for Span {
|
||||||
// If this is not an empty or invalid span, we want to hash the last
|
// If this is not an empty or invalid span, we want to hash the last
|
||||||
// position that belongs to it, as opposed to hashing the first
|
// position that belongs to it, as opposed to hashing the first
|
||||||
// position past it.
|
// position past it.
|
||||||
let span_hi = if self.hi() > self.lo() {
|
let span = self.data();
|
||||||
|
let span_hi = if span.hi > span.lo {
|
||||||
// We might end up in the middle of a multibyte character here,
|
// We might end up in the middle of a multibyte character here,
|
||||||
// but that's OK, since we are not trying to decode anything at
|
// but that's OK, since we are not trying to decode anything at
|
||||||
// this position.
|
// this position.
|
||||||
self.hi() - ::syntax_pos::BytePos(1)
|
span.hi - ::syntax_pos::BytePos(1)
|
||||||
} else {
|
} else {
|
||||||
self.hi()
|
span.hi
|
||||||
};
|
};
|
||||||
|
|
||||||
{
|
{
|
||||||
let loc1 = hcx.codemap().byte_pos_to_line_and_col(self.lo());
|
let loc1 = hcx.codemap().byte_pos_to_line_and_col(span.lo);
|
||||||
let loc1 = loc1.as_ref()
|
let loc1 = loc1.as_ref()
|
||||||
.map(|&(ref fm, line, col)| (&fm.name[..], line, col.to_usize()))
|
.map(|&(ref fm, line, col)| (&fm.name[..], line, col.to_usize()))
|
||||||
.unwrap_or(("???", 0, 0));
|
.unwrap_or(("???", 0, 0));
|
||||||
|
@ -413,7 +414,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for Span {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.ctxt() == SyntaxContext::empty() {
|
if span.ctxt == SyntaxContext::empty() {
|
||||||
0u8.hash_stable(hcx, hasher);
|
0u8.hash_stable(hcx, hasher);
|
||||||
} else {
|
} else {
|
||||||
1u8.hash_stable(hcx, hasher);
|
1u8.hash_stable(hcx, hasher);
|
||||||
|
|
|
@ -75,6 +75,21 @@ pub struct SpanData {
|
||||||
pub ctxt: SyntaxContext,
|
pub ctxt: SyntaxContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl SpanData {
|
||||||
|
#[inline]
|
||||||
|
pub fn with_lo(&self, lo: BytePos) -> Span {
|
||||||
|
Span::new(lo, self.hi, self.ctxt)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn with_hi(&self, hi: BytePos) -> Span {
|
||||||
|
Span::new(self.lo, hi, self.ctxt)
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub fn with_ctxt(&self, ctxt: SyntaxContext) -> Span {
|
||||||
|
Span::new(self.lo, self.hi, ctxt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// The interner in thread-local, so `Span` shouldn't move between threads.
|
// The interner in thread-local, so `Span` shouldn't move between threads.
|
||||||
impl !Send for Span {}
|
impl !Send for Span {}
|
||||||
impl !Sync for Span {}
|
impl !Sync for Span {}
|
||||||
|
@ -109,8 +124,7 @@ impl Span {
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn with_lo(self, lo: BytePos) -> Span {
|
pub fn with_lo(self, lo: BytePos) -> Span {
|
||||||
let base = self.data();
|
self.data().with_lo(lo)
|
||||||
Span::new(lo, base.hi, base.ctxt)
|
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn hi(self) -> BytePos {
|
pub fn hi(self) -> BytePos {
|
||||||
|
@ -118,8 +132,7 @@ impl Span {
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn with_hi(self, hi: BytePos) -> Span {
|
pub fn with_hi(self, hi: BytePos) -> Span {
|
||||||
let base = self.data();
|
self.data().with_hi(hi)
|
||||||
Span::new(base.lo, hi, base.ctxt)
|
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn ctxt(self) -> SyntaxContext {
|
pub fn ctxt(self) -> SyntaxContext {
|
||||||
|
@ -127,20 +140,21 @@ impl Span {
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn with_ctxt(self, ctxt: SyntaxContext) -> Span {
|
pub fn with_ctxt(self, ctxt: SyntaxContext) -> Span {
|
||||||
let base = self.data();
|
self.data().with_ctxt(ctxt)
|
||||||
Span::new(base.lo, base.hi, ctxt)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a new span representing just the end-point of this span
|
/// Returns a new span representing just the end-point of this span
|
||||||
pub fn end_point(self) -> Span {
|
pub fn end_point(self) -> Span {
|
||||||
let lo = cmp::max(self.hi().0 - 1, self.lo().0);
|
let span = self.data();
|
||||||
self.with_lo(BytePos(lo))
|
let lo = cmp::max(span.hi.0 - 1, span.lo.0);
|
||||||
|
span.with_lo(BytePos(lo))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a new span representing the next character after the end-point of this span
|
/// Returns a new span representing the next character after the end-point of this span
|
||||||
pub fn next_point(self) -> Span {
|
pub fn next_point(self) -> Span {
|
||||||
let lo = cmp::max(self.hi().0, self.lo().0 + 1);
|
let span = self.data();
|
||||||
Span::new(BytePos(lo), BytePos(lo), self.ctxt())
|
let lo = cmp::max(span.hi.0, span.lo.0 + 1);
|
||||||
|
Span::new(BytePos(lo), BytePos(lo), span.ctxt)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `self` if `self` is not the dummy span, and `other` otherwise.
|
/// Returns `self` if `self` is not the dummy span, and `other` otherwise.
|
||||||
|
@ -150,7 +164,9 @@ impl Span {
|
||||||
|
|
||||||
/// Return true if `self` fully encloses `other`.
|
/// Return true if `self` fully encloses `other`.
|
||||||
pub fn contains(self, other: Span) -> bool {
|
pub fn contains(self, other: Span) -> bool {
|
||||||
self.lo() <= other.lo() && other.hi() <= self.hi()
|
let span = self.data();
|
||||||
|
let other = other.data();
|
||||||
|
span.lo <= other.lo && other.hi <= span.hi
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return true if the spans are equal with regards to the source text.
|
/// Return true if the spans are equal with regards to the source text.
|
||||||
|
@ -158,13 +174,17 @@ impl Span {
|
||||||
/// Use this instead of `==` when either span could be generated code,
|
/// Use this instead of `==` when either span could be generated code,
|
||||||
/// and you only care that they point to the same bytes of source text.
|
/// and you only care that they point to the same bytes of source text.
|
||||||
pub fn source_equal(&self, other: &Span) -> bool {
|
pub fn source_equal(&self, other: &Span) -> bool {
|
||||||
self.lo() == other.lo() && self.hi() == other.hi()
|
let span = self.data();
|
||||||
|
let other = other.data();
|
||||||
|
span.lo == other.lo && span.hi == other.hi
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `Some(span)`, where the start is trimmed by the end of `other`
|
/// Returns `Some(span)`, where the start is trimmed by the end of `other`
|
||||||
pub fn trim_start(self, other: Span) -> Option<Span> {
|
pub fn trim_start(self, other: Span) -> Option<Span> {
|
||||||
if self.hi() > other.hi() {
|
let span = self.data();
|
||||||
Some(self.with_lo(cmp::max(self.lo(), other.hi())))
|
let other = other.data();
|
||||||
|
if span.hi > other.hi {
|
||||||
|
Some(span.with_lo(cmp::max(span.lo, other.hi)))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -268,29 +288,35 @@ impl Span {
|
||||||
|
|
||||||
/// Return a `Span` that would enclose both `self` and `end`.
|
/// Return a `Span` that would enclose both `self` and `end`.
|
||||||
pub fn to(self, end: Span) -> Span {
|
pub fn to(self, end: Span) -> Span {
|
||||||
|
let span = self.data();
|
||||||
|
let end = end.data();
|
||||||
Span::new(
|
Span::new(
|
||||||
cmp::min(self.lo(), end.lo()),
|
cmp::min(span.lo, end.lo),
|
||||||
cmp::max(self.hi(), end.hi()),
|
cmp::max(span.hi, end.hi),
|
||||||
// FIXME(jseyfried): self.ctxt should always equal end.ctxt here (c.f. issue #23480)
|
// FIXME(jseyfried): self.ctxt should always equal end.ctxt here (c.f. issue #23480)
|
||||||
if self.ctxt() == SyntaxContext::empty() { end.ctxt() } else { self.ctxt() },
|
if span.ctxt == SyntaxContext::empty() { end.ctxt } else { span.ctxt },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a `Span` between the end of `self` to the beginning of `end`.
|
/// Return a `Span` between the end of `self` to the beginning of `end`.
|
||||||
pub fn between(self, end: Span) -> Span {
|
pub fn between(self, end: Span) -> Span {
|
||||||
|
let span = self.data();
|
||||||
|
let end = end.data();
|
||||||
Span::new(
|
Span::new(
|
||||||
self.hi(),
|
span.hi,
|
||||||
end.lo(),
|
end.lo,
|
||||||
if end.ctxt() == SyntaxContext::empty() { end.ctxt() } else { self.ctxt() },
|
if end.ctxt == SyntaxContext::empty() { end.ctxt } else { span.ctxt },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a `Span` between the beginning of `self` to the beginning of `end`.
|
/// Return a `Span` between the beginning of `self` to the beginning of `end`.
|
||||||
pub fn until(self, end: Span) -> Span {
|
pub fn until(self, end: Span) -> Span {
|
||||||
|
let span = self.data();
|
||||||
|
let end = end.data();
|
||||||
Span::new(
|
Span::new(
|
||||||
self.lo(),
|
span.lo,
|
||||||
end.lo(),
|
end.lo,
|
||||||
if end.ctxt() == SyntaxContext::empty() { end.ctxt() } else { self.ctxt() },
|
if end.ctxt == SyntaxContext::empty() { end.ctxt } else { span.ctxt },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -316,13 +342,14 @@ impl Default for Span {
|
||||||
|
|
||||||
impl serialize::UseSpecializedEncodable for Span {
|
impl serialize::UseSpecializedEncodable for Span {
|
||||||
fn default_encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
|
fn default_encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
|
||||||
|
let span = self.data();
|
||||||
s.emit_struct("Span", 2, |s| {
|
s.emit_struct("Span", 2, |s| {
|
||||||
s.emit_struct_field("lo", 0, |s| {
|
s.emit_struct_field("lo", 0, |s| {
|
||||||
self.lo().encode(s)
|
span.lo.encode(s)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
s.emit_struct_field("hi", 1, |s| {
|
s.emit_struct_field("hi", 1, |s| {
|
||||||
self.hi().encode(s)
|
span.hi.encode(s)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue