Skip to content

Commit

Permalink
Optimize syntax tree size of Punctuated
Browse files Browse the repository at this point in the history
  • Loading branch information
dtolnay committed Mar 17, 2023
1 parent 30287e3 commit 0844a62
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 68 deletions.
35 changes: 18 additions & 17 deletions src/expr.rs
Expand Up @@ -673,16 +673,6 @@ ast_struct! {
}

impl Expr {
#[cfg(feature = "parsing")]
const DUMMY: Self = Expr::Path(ExprPath {
attrs: Vec::new(),
qself: None,
path: Path {
leading_colon: None,
segments: Punctuated::new(),
},
});

#[cfg(all(feature = "parsing", feature = "full"))]
pub(crate) fn replace_attrs(&mut self, new: Vec<Attribute>) -> Vec<Attribute> {
match self {
Expand Down Expand Up @@ -2710,15 +2700,26 @@ pub(crate) mod parsing {
if trailing_dot {
float_repr.truncate(float_repr.len() - 1);
}
let mut dummy = Expr::Path(ExprPath {
attrs: Vec::new(),
qself: None,
path: Path {
leading_colon: None,
segments: Punctuated::new(),
},
});
for part in float_repr.split('.') {
let index = crate::parse_str(part).map_err(|err| Error::new(float.span(), err))?;
let base = mem::replace(e, Expr::DUMMY);
*e = Expr::Field(ExprField {
attrs: Vec::new(),
base: Box::new(base),
dot_token: Token![.](dot_token.span),
member: Member::Unnamed(index),
});
let base = mem::replace(e, dummy);
dummy = mem::replace(
e,
Expr::Field(ExprField {
attrs: Vec::new(),
base: Box::new(base),
dot_token: Token![.](dot_token.span),
member: Member::Unnamed(index),
}),
);
*dot_token = Token![.](float.span());
}
Ok(!trailing_dot)
Expand Down
96 changes: 49 additions & 47 deletions src/punctuated.rs
Expand Up @@ -43,32 +43,34 @@ use crate::token::Token;
/// Refer to the [module documentation] for details about punctuated sequences.
///
/// [module documentation]: self
pub struct Punctuated<T, P> {
pub struct Punctuated<T, P>(Box<PunctuatedInner<T, P>>);

struct PunctuatedInner<T, P> {
inner: Vec<(T, P)>,
last: Option<Box<T>>,
}

impl<T, P> Punctuated<T, P> {
/// Creates an empty punctuated sequence.
pub const fn new() -> Self {
Punctuated {
pub fn new() -> Self {
Punctuated(Box::new(PunctuatedInner {
inner: Vec::new(),
last: None,
}
}))
}

/// Determines whether this punctuated sequence is empty, meaning it
/// contains no syntax tree nodes or punctuation.
pub fn is_empty(&self) -> bool {
self.inner.len() == 0 && self.last.is_none()
self.0.inner.len() == 0 && self.0.last.is_none()
}

/// Returns the number of syntax tree nodes in this punctuated sequence.
///
/// This is the number of nodes of type `T`, not counting the punctuation of
/// type `P`.
pub fn len(&self) -> usize {
self.inner.len() + if self.last.is_some() { 1 } else { 0 }
self.0.inner.len() + if self.0.last.is_some() { 1 } else { 0 }
}

/// Borrows the first element in this sequence.
Expand All @@ -95,8 +97,8 @@ impl<T, P> Punctuated<T, P> {
pub fn iter(&self) -> Iter<T> {
Iter {
inner: Box::new(NoDrop::new(PrivateIter {
inner: self.inner.iter(),
last: self.last.as_ref().map(Box::as_ref).into_iter(),
inner: self.0.inner.iter(),
last: self.0.last.as_ref().map(Box::as_ref).into_iter(),
})),
}
}
Expand All @@ -106,8 +108,8 @@ impl<T, P> Punctuated<T, P> {
pub fn iter_mut(&mut self) -> IterMut<T> {
IterMut {
inner: Box::new(NoDrop::new(PrivateIterMut {
inner: self.inner.iter_mut(),
last: self.last.as_mut().map(Box::as_mut).into_iter(),
inner: self.0.inner.iter_mut(),
last: self.0.last.as_mut().map(Box::as_mut).into_iter(),
})),
}
}
Expand All @@ -116,26 +118,26 @@ impl<T, P> Punctuated<T, P> {
/// punctuated pairs.
pub fn pairs(&self) -> Pairs<T, P> {
Pairs {
inner: self.inner.iter(),
last: self.last.as_ref().map(Box::as_ref).into_iter(),
inner: self.0.inner.iter(),
last: self.0.last.as_ref().map(Box::as_ref).into_iter(),
}
}

/// Returns an iterator over the contents of this sequence as mutably
/// borrowed punctuated pairs.
pub fn pairs_mut(&mut self) -> PairsMut<T, P> {
PairsMut {
inner: self.inner.iter_mut(),
last: self.last.as_mut().map(Box::as_mut).into_iter(),
inner: self.0.inner.iter_mut(),
last: self.0.last.as_mut().map(Box::as_mut).into_iter(),
}
}

/// Returns an iterator over the contents of this sequence as owned
/// punctuated pairs.
pub fn into_pairs(self) -> IntoPairs<T, P> {
IntoPairs {
inner: self.inner.into_iter(),
last: self.last.map(|t| *t).into_iter(),
inner: self.0.inner.into_iter(),
last: self.0.last.map(|t| *t).into_iter(),
}
}

Expand All @@ -157,7 +159,7 @@ impl<T, P> Punctuated<T, P> {
"Punctuated::push_value: cannot push value if Punctuated is missing trailing punctuation",
);

self.last = Some(Box::new(value));
self.0.last = Some(Box::new(value));
}

/// Appends a trailing punctuation onto the end of this punctuated sequence.
Expand All @@ -169,36 +171,36 @@ impl<T, P> Punctuated<T, P> {
/// Panics if the sequence is empty or already has a trailing punctuation.
pub fn push_punct(&mut self, punctuation: P) {
assert!(
self.last.is_some(),
self.0.last.is_some(),
"Punctuated::push_punct: cannot push punctuation if Punctuated is empty or already has trailing punctuation",
);

let last = self.last.take().unwrap();
self.inner.push((*last, punctuation));
let last = self.0.last.take().unwrap();
self.0.inner.push((*last, punctuation));
}

/// Removes the last punctuated pair from this sequence, or `None` if the
/// sequence is empty.
pub fn pop(&mut self) -> Option<Pair<T, P>> {
if self.last.is_some() {
self.last.take().map(|t| Pair::End(*t))
if self.0.last.is_some() {
self.0.last.take().map(|t| Pair::End(*t))
} else {
self.inner.pop().map(|(t, p)| Pair::Punctuated(t, p))
self.0.inner.pop().map(|(t, p)| Pair::Punctuated(t, p))
}
}

/// Determines whether this punctuated sequence ends with a trailing
/// punctuation.
pub fn trailing_punct(&self) -> bool {
self.last.is_none() && !self.is_empty()
self.0.last.is_none() && !self.is_empty()
}

/// Returns true if either this `Punctuated` is empty, or it has a trailing
/// punctuation.
///
/// Equivalent to `punctuated.is_empty() || punctuated.trailing_punct()`.
pub fn empty_or_trailing(&self) -> bool {
self.last.is_none()
self.0.last.is_none()
}

/// Appends a syntax tree node onto the end of this punctuated sequence.
Expand Down Expand Up @@ -234,14 +236,14 @@ impl<T, P> Punctuated<T, P> {
if index == self.len() {
self.push(value);
} else {
self.inner.insert(index, (value, Default::default()));
self.0.inner.insert(index, (value, Default::default()));
}
}

/// Clears the sequence of all values and punctuation, making it empty.
pub fn clear(&mut self) {
self.inner.clear();
self.last = None;
self.0.inner.clear();
self.0.last = None;
}

/// Parses zero or more occurrences of `T` separated by punctuation of type
Expand Down Expand Up @@ -352,10 +354,10 @@ where
P: Clone,
{
fn clone(&self) -> Self {
Punctuated {
inner: self.inner.clone(),
last: self.last.clone(),
}
Punctuated(Box::new(PunctuatedInner {
inner: self.0.inner.clone(),
last: self.0.last.clone(),
}))
}
}

Expand All @@ -376,8 +378,8 @@ where
P: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
let Punctuated { inner, last } = self;
*inner == other.inner && *last == other.last
let PunctuatedInner { inner, last } = self.0.as_ref();
*inner == other.0.inner && *last == other.0.last
}
}

Expand All @@ -389,7 +391,7 @@ where
P: Hash,
{
fn hash<H: Hasher>(&self, state: &mut H) {
let Punctuated { inner, last } = self;
let PunctuatedInner { inner, last } = self.0.as_ref();
inner.hash(state);
last.hash(state);
}
Expand All @@ -400,11 +402,11 @@ where
impl<T: Debug, P: Debug> Debug for Punctuated<T, P> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let mut list = f.debug_list();
for (t, p) in &self.inner {
for (t, p) in &self.0.inner {
list.entry(t);
list.entry(p);
}
if let Some(last) = &self.last {
if let Some(last) = &self.0.last {
list.entry(last);
}
list.finish()
Expand Down Expand Up @@ -463,9 +465,9 @@ where
panic!("Punctuated extended with items after a Pair::End");
}
match pair {
Pair::Punctuated(a, b) => punctuated.inner.push((a, b)),
Pair::Punctuated(a, b) => punctuated.0.inner.push((a, b)),
Pair::End(a) => {
punctuated.last = Some(Box::new(a));
punctuated.0.last = Some(Box::new(a));
nomore = true;
}
}
Expand All @@ -478,8 +480,8 @@ impl<T, P> IntoIterator for Punctuated<T, P> {

fn into_iter(self) -> Self::IntoIter {
let mut elements = Vec::with_capacity(self.len());
elements.extend(self.inner.into_iter().map(|pair| pair.0));
elements.extend(self.last.map(|t| *t));
elements.extend(self.0.inner.into_iter().map(|pair| pair.0));
elements.extend(self.0.last.map(|t| *t));

IntoIter {
inner: elements.into_iter(),
Expand Down Expand Up @@ -1032,25 +1034,25 @@ impl<T, P> Index<usize> for Punctuated<T, P> {

fn index(&self, index: usize) -> &Self::Output {
if index == self.len() - 1 {
match &self.last {
match &self.0.last {
Some(t) => t,
None => &self.inner[index].0,
None => &self.0.inner[index].0,
}
} else {
&self.inner[index].0
&self.0.inner[index].0
}
}
}

impl<T, P> IndexMut<usize> for Punctuated<T, P> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
if index == self.len() - 1 {
match &mut self.last {
match &mut self.0.last {
Some(t) => t,
None => &mut self.inner[index].0,
None => &mut self.0.inner[index].0,
}
} else {
&mut self.inner[index].0
&mut self.0.inner[index].0
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions tests/test_size.rs
Expand Up @@ -8,25 +8,25 @@ use syn::{Expr, Item, Lit, Pat, Type};
#[rustversion::attr(before(2022-11-24), ignore)]
#[test]
fn test_expr_size() {
assert_eq!(mem::size_of::<Expr>(), 176);
assert_eq!(mem::size_of::<Expr>(), 144);
}

#[rustversion::attr(before(2022-09-09), ignore)]
#[test]
fn test_item_size() {
assert_eq!(mem::size_of::<Item>(), 360);
assert_eq!(mem::size_of::<Item>(), 288);
}

#[rustversion::attr(before(2022-11-24), ignore)]
#[test]
fn test_type_size() {
assert_eq!(mem::size_of::<Type>(), 240);
assert_eq!(mem::size_of::<Type>(), 192);
}

#[rustversion::attr(before(2021-10-11), ignore)]
#[test]
fn test_pat_size() {
assert_eq!(mem::size_of::<Pat>(), 192);
assert_eq!(mem::size_of::<Pat>(), 136);
}

#[rustversion::attr(before(2022-09-09), ignore)]
Expand Down

0 comments on commit 0844a62

Please sign in to comment.