Skip to content

Commit

Permalink
perf(semantic): give AstNodeId a niche (#4469)
Browse files Browse the repository at this point in the history
Make `AstNodeId` a type with a niche, using `NonMaxU32` as its internal storage. This makes `Option<AstNodeId>` 4 bytes instead of 8. That halves the size of the `Vec` for parent IDs in `AstNodes` (which gets pretty big).
  • Loading branch information
overlookmotel committed Jul 26, 2024
1 parent c99b3eb commit 24beaeb
Showing 1 changed file with 52 additions and 5 deletions.
57 changes: 52 additions & 5 deletions crates/oxc_syntax/src/node.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,59 @@
use bitflags::bitflags;
use oxc_index::define_index_type;

define_index_type! {
pub struct AstNodeId = u32;
}
use nonmax::NonMaxU32;
#[cfg(feature = "serialize")]
use serde::{Serialize, Serializer};

use oxc_index::Idx;

#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct AstNodeId(NonMaxU32);

impl AstNodeId {
pub const DUMMY: Self = AstNodeId::from_raw_unchecked(0);
pub const DUMMY: Self = AstNodeId::new(0);

/// Create `AstNodeId` from `u32`.
///
/// # Panics
/// Panics if `idx` is `u32::MAX`.
pub const fn new(idx: u32) -> Self {
// We could use `NonMaxU32::new(idx).unwrap()` but `Option::unwrap` is not a const function
// and we want this function to be
assert!(idx != u32::MAX);
// SAFETY: We have checked that `idx` is not `u32::MAX`
unsafe { Self::new_unchecked(idx) }
}

/// Create `AstNodeId` from `u32` unchecked.
///
/// # SAFETY
/// `idx` must not be `u32::MAX`.
#[allow(clippy::missing_safety_doc, clippy::unnecessary_safety_comment)]
pub const unsafe fn new_unchecked(idx: u32) -> Self {
// SAFETY: Caller must ensure `idx` is not `u32::MAX`
Self(NonMaxU32::new_unchecked(idx))
}
}

impl Idx for AstNodeId {
#[allow(clippy::cast_possible_truncation)]
fn from_usize(idx: usize) -> Self {
Self(NonMaxU32::new(idx as u32).unwrap())
}

fn index(self) -> usize {
self.0.get() as usize
}
}

#[cfg(feature = "serialize")]
impl Serialize for AstNodeId {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_u32(self.0.get())
}
}

#[cfg(feature = "serialize")]
Expand Down

0 comments on commit 24beaeb

Please sign in to comment.