aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMartin Fischer <martin@push-f.com>2023-08-16 12:00:29 +0200
committerMartin Fischer <martin@push-f.com>2023-08-19 13:41:55 +0200
commit180f6d6111b966627aa00a4017b6fb9751f7386c (patch)
tree4a0b638eebf352761da3425370ba3ac8dbad73c5 /src
parent78c2066021deda483a4f0a1bb575543d98d27dca (diff)
perf: only store start offsets for attribute spans
This spares us two usizes per AttrInternal<Range<usize>>. So on a 64 bit target where a usize is 8 bytes this spares us 16 bytes of memory per attribute (if spans are enabled, ... for Token<()> this obviously doesn't change anything). And the DefaultEmitter now also no longer has to update the spans on each Emitter::push_attribute_(name|value) call. The spans are now calculated on demand by the Attribute methods, which is fine since the assumption is that API users are only interested in a few specific spans (rather than all spans).
Diffstat (limited to 'src')
-rw-r--r--src/attr.rs24
-rw-r--r--src/emitter.rs20
2 files changed, 26 insertions, 18 deletions
diff --git a/src/attr.rs b/src/attr.rs
index a56eb95..4c7e330 100644
--- a/src/attr.rs
+++ b/src/attr.rs
@@ -30,8 +30,10 @@ pub struct AttributeMap<O> {
#[derive(Debug, Eq, PartialEq)]
pub(crate) struct AttrInternal<O> {
pub value: String,
- pub name_span: Range<O>,
- pub value_span: Range<O>,
+ /// The start offset of the attribute name.
+ pub name_offset: O,
+ /// The start offset of the attribute value.
+ pub value_offset: O,
}
/// An HTML attribute borrowed from an [`AttributeMap`].
@@ -74,14 +76,14 @@ impl<'a, O: Offset> Attribute<'a, O> {
&self.map_val.value
}
- /// Returns the span of the attribute name.
+ /// Calculates the span of the attribute name and returns it.
pub fn name_span(&self) -> Range<O> {
- self.map_val.name_span.clone()
+ self.map_val.name_offset..self.map_val.name_offset + self.name.len()
}
- /// Returns the span of the attribute value.
+ /// Calculates the span of the attribute value and returns it.
pub fn value_span(&self) -> Range<O> {
- self.map_val.value_span.clone()
+ self.map_val.value_offset..self.map_val.value_offset + self.map_val.value.len()
}
}
@@ -154,8 +156,8 @@ impl<O: Default> FromIterator<(String, String)> for AttributeMap<O> {
name,
AttrInternal {
value,
- name_span: O::default()..O::default(),
- value_span: O::default()..O::default(),
+ name_offset: O::default(),
+ value_offset: O::default(),
},
)
})
@@ -163,3 +165,9 @@ impl<O: Default> FromIterator<(String, String)> for AttributeMap<O> {
}
}
}
+
+impl<O: Offset> AttrInternal<O> {
+ pub(crate) fn name_span(&self, name_len: usize) -> Range<O> {
+ self.name_offset..self.name_offset + name_len
+ }
+}
diff --git a/src/emitter.rs b/src/emitter.rs
index 9dfb363..17a4882 100644
--- a/src/emitter.rs
+++ b/src/emitter.rs
@@ -205,7 +205,7 @@ impl<O> DefaultEmitter<O> {
fn flush_current_attribute(&mut self)
where
- O: Clone,
+ O: Offset,
{
if let Some((name, map_val)) = self.current_attribute.take() {
match self.current_token {
@@ -213,14 +213,16 @@ impl<O> DefaultEmitter<O> {
Entry::Vacant(vacant) => {
vacant.insert(map_val);
}
- Entry::Occupied(_) => {
- self.push_error(Error::DuplicateAttribute, map_val.name_span);
+ Entry::Occupied(entry) => {
+ let name_len = entry.key().len();
+ self.push_error(Error::DuplicateAttribute, map_val.name_span(name_len));
}
},
Some(Token::EndTag(_)) => {
- self.attr_in_end_tag_span = Some(map_val.name_span.clone());
+ let name_span = map_val.name_span(name.len());
+ self.attr_in_end_tag_span = Some(name_span.clone());
if !self.seen_attributes.insert(name) {
- self.push_error(Error::DuplicateAttribute, map_val.name_span);
+ self.push_error(Error::DuplicateAttribute, name_span);
}
}
_ => {
@@ -380,25 +382,23 @@ impl<O: Offset> Emitter<O> for DefaultEmitter<O> {
self.current_attribute = Some((
String::new(),
crate::attr::AttrInternal {
- name_span: offset..offset,
+ name_offset: offset,
value: String::new(),
- value_span: Range::default(),
+ value_offset: O::default(),
},
));
}
fn init_attribute_value(&mut self, offset: O, _quoted: bool) {
- self.current_attribute.as_mut().unwrap().1.value_span = offset..offset;
+ self.current_attribute.as_mut().unwrap().1.value_offset = offset;
}
fn push_attribute_name(&mut self, s: &str) {
let current_attr = self.current_attribute.as_mut().unwrap();
current_attr.0.push_str(s);
- current_attr.1.name_span.end += s.len();
}
fn push_attribute_value(&mut self, s: &str) {
let current_attr = self.current_attribute.as_mut().unwrap();
current_attr.1.value.push_str(s);
- current_attr.1.value_span.end += s.len();
}
fn set_doctype_public_identifier(&mut self, value: &str) {
if let Some(Token::Doctype(Doctype {