mirror of
https://github.com/gfx-rs/wgpu.git
synced 2025-02-19 18:33:30 +00:00
[naga] Break naga::arena
up into submodules.
This commit is almost entirely code motion. The only meaningful changes should be: - changes to imports - changes to visibility - changes to use visible associated constructor functions instead of trying to construct values directly using now-invisible fields - moving the crate-level "Arena" docs into the `arena` module
This commit is contained in:
parent
bef9eb4074
commit
a5d57db269
126
naga/src/arena/handle.rs
Normal file
126
naga/src/arena/handle.rs
Normal file
@ -0,0 +1,126 @@
|
||||
//! Well-typed indices into [`Arena`]s and [`UniqueArena`]s.
|
||||
//!
|
||||
//! This module defines [`Handle`] and related types.
|
||||
//!
|
||||
//! [`Arena`]: super::Arena
|
||||
//! [`UniqueArena`]: super::UniqueArena
|
||||
|
||||
use std::{cmp::Ordering, fmt, hash, marker::PhantomData};
|
||||
|
||||
/// An unique index in the arena array that a handle points to.
|
||||
/// The "non-max" part ensures that an `Option<Handle<T>>` has
|
||||
/// the same size and representation as `Handle<T>`.
|
||||
pub type Index = crate::non_max_u32::NonMaxU32;
|
||||
|
||||
#[derive(Clone, Copy, Debug, thiserror::Error, PartialEq)]
|
||||
#[error("Handle {index} of {kind} is either not present, or inaccessible yet")]
|
||||
pub struct BadHandle {
|
||||
pub kind: &'static str,
|
||||
pub index: usize,
|
||||
}
|
||||
|
||||
impl BadHandle {
|
||||
pub fn new<T>(handle: Handle<T>) -> Self {
|
||||
Self {
|
||||
kind: std::any::type_name::<T>(),
|
||||
index: handle.index(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A strongly typed reference to an arena item.
|
||||
///
|
||||
/// A `Handle` value can be used as an index into an [`Arena`] or [`UniqueArena`].
|
||||
///
|
||||
/// [`Arena`]: super::Arena
|
||||
/// [`UniqueArena`]: super::UniqueArena
|
||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
|
||||
#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
|
||||
#[cfg_attr(
|
||||
any(feature = "serialize", feature = "deserialize"),
|
||||
serde(transparent)
|
||||
)]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
pub struct Handle<T> {
|
||||
index: Index,
|
||||
#[cfg_attr(any(feature = "serialize", feature = "deserialize"), serde(skip))]
|
||||
marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> Clone for Handle<T> {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Copy for Handle<T> {}
|
||||
|
||||
impl<T> PartialEq for Handle<T> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.index == other.index
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Eq for Handle<T> {}
|
||||
|
||||
impl<T> PartialOrd for Handle<T> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Ord for Handle<T> {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.index.cmp(&other.index)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> fmt::Debug for Handle<T> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(formatter, "[{}]", self.index)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> hash::Hash for Handle<T> {
|
||||
fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
|
||||
self.index.hash(hasher)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Handle<T> {
|
||||
pub(crate) const fn new(index: Index) -> Self {
|
||||
Handle {
|
||||
index,
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the index of this handle.
|
||||
pub const fn index(self) -> usize {
|
||||
self.index.get() as usize
|
||||
}
|
||||
|
||||
/// Convert a `usize` index into a `Handle<T>`.
|
||||
pub(super) fn from_usize(index: usize) -> Self {
|
||||
let handle_index = u32::try_from(index)
|
||||
.ok()
|
||||
.and_then(Index::new)
|
||||
.expect("Failed to insert into arena. Handle overflows");
|
||||
Handle::new(handle_index)
|
||||
}
|
||||
|
||||
/// Convert a `usize` index into a `Handle<T>`, without range checks.
|
||||
pub(super) const unsafe fn from_usize_unchecked(index: usize) -> Self {
|
||||
Handle::new(Index::new_unchecked(index as u32))
|
||||
}
|
||||
|
||||
/// Write this handle's index to `formatter`, preceded by `prefix`.
|
||||
pub fn write_prefixed(
|
||||
&self,
|
||||
formatter: &mut fmt::Formatter,
|
||||
prefix: &'static str,
|
||||
) -> fmt::Result {
|
||||
formatter.write_str(prefix)?;
|
||||
<usize as fmt::Display>::fmt(&self.index(), formatter)
|
||||
}
|
||||
}
|
105
naga/src/arena/handlevec.rs
Normal file
105
naga/src/arena/handlevec.rs
Normal file
@ -0,0 +1,105 @@
|
||||
//! The [`HandleVec`] type and associated definitions.
|
||||
|
||||
use super::handle::Handle;
|
||||
|
||||
use std::marker::PhantomData;
|
||||
use std::ops;
|
||||
|
||||
/// A [`Vec`] indexed by [`Handle`]s.
|
||||
///
|
||||
/// A `HandleVec<T, U>` is a [`Vec<U>`] indexed by values of type `Handle<T>`,
|
||||
/// rather than `usize`.
|
||||
///
|
||||
/// Rather than a `push` method, `HandleVec` has an [`insert`] method, analogous
|
||||
/// to [`HashMap::insert`], that requires you to provide the handle at which the
|
||||
/// new value should appear. However, since `HandleVec` only supports insertion
|
||||
/// at the end, the given handle's index must be equal to the the `HandleVec`'s
|
||||
/// current length; otherwise, the insertion will panic.
|
||||
///
|
||||
/// [`insert`]: HandleVec::insert
|
||||
/// [`HashMap::insert`]: std::collections::HashMap::insert
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct HandleVec<T, U> {
|
||||
inner: Vec<U>,
|
||||
as_keys: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T, U> Default for HandleVec<T, U> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
inner: vec![],
|
||||
as_keys: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl<T, U> HandleVec<T, U> {
|
||||
pub(crate) const fn new() -> Self {
|
||||
Self {
|
||||
inner: vec![],
|
||||
as_keys: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn with_capacity(capacity: usize) -> Self {
|
||||
Self {
|
||||
inner: Vec::with_capacity(capacity),
|
||||
as_keys: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn len(&self) -> usize {
|
||||
self.inner.len()
|
||||
}
|
||||
|
||||
/// Insert a mapping from `handle` to `value`.
|
||||
///
|
||||
/// Unlike a [`HashMap`], a `HandleVec` can only have new entries inserted at
|
||||
/// the end, like [`Vec::push`]. So the index of `handle` must equal
|
||||
/// [`self.len()`].
|
||||
///
|
||||
/// [`HashMap`]: std::collections::HashMap
|
||||
/// [`self.len()`]: HandleVec::len
|
||||
pub(crate) fn insert(&mut self, handle: Handle<T>, value: U) {
|
||||
assert_eq!(handle.index(), self.inner.len());
|
||||
self.inner.push(value);
|
||||
}
|
||||
|
||||
pub(crate) fn get(&self, handle: Handle<T>) -> Option<&U> {
|
||||
self.inner.get(handle.index())
|
||||
}
|
||||
|
||||
pub(crate) fn clear(&mut self) {
|
||||
self.inner.clear()
|
||||
}
|
||||
|
||||
pub(crate) fn resize(&mut self, len: usize, fill: U)
|
||||
where
|
||||
U: Clone,
|
||||
{
|
||||
self.inner.resize(len, fill);
|
||||
}
|
||||
|
||||
pub(crate) fn iter(&self) -> impl Iterator<Item = &U> {
|
||||
self.inner.iter()
|
||||
}
|
||||
|
||||
pub(crate) fn iter_mut(&mut self) -> impl Iterator<Item = &mut U> {
|
||||
self.inner.iter_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> ops::Index<Handle<T>> for HandleVec<T, U> {
|
||||
type Output = U;
|
||||
|
||||
fn index(&self, handle: Handle<T>) -> &Self::Output {
|
||||
&self.inner[handle.index()]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> ops::IndexMut<Handle<T>> for HandleVec<T, U> {
|
||||
fn index_mut(&mut self, handle: Handle<T>) -> &mut Self::Output {
|
||||
&mut self.inner[handle.index()]
|
||||
}
|
||||
}
|
@ -1,241 +1,40 @@
|
||||
use std::{cmp::Ordering, fmt, hash, marker::PhantomData, ops};
|
||||
/*! The [`Arena`], [`UniqueArena`], and [`Handle`] types.
|
||||
|
||||
use crate::non_max_u32::NonMaxU32;
|
||||
To improve translator performance and reduce memory usage, most structures are
|
||||
stored in an [`Arena`]. An `Arena<T>` stores a series of `T` values, indexed by
|
||||
[`Handle<T>`](Handle) values, which are just wrappers around integer indexes.
|
||||
For example, a `Function`'s expressions are stored in an `Arena<Expression>`,
|
||||
and compound expressions refer to their sub-expressions via `Handle<Expression>`
|
||||
values. (When examining the serialized form of a `Module`, note that the first
|
||||
element of an `Arena` has an index of 1, not 0.)
|
||||
|
||||
/// An unique index in the arena array that a handle points to.
|
||||
/// The "non-max" part ensures that an `Option<Handle<T>>` has
|
||||
/// the same size and representation as `Handle<T>`.
|
||||
type Index = NonMaxU32;
|
||||
A [`UniqueArena`] is just like an `Arena`, except that it stores only a single
|
||||
instance of each value. The value type must implement `Eq` and `Hash`. Like an
|
||||
`Arena`, inserting a value into a `UniqueArena` returns a `Handle` which can be
|
||||
used to efficiently access the value, without a hash lookup. Inserting a value
|
||||
multiple times returns the same `Handle`.
|
||||
|
||||
use crate::{FastIndexSet, Span};
|
||||
If the `span` feature is enabled, both `Arena` and `UniqueArena` can associate a
|
||||
source code span with each element.
|
||||
|
||||
#[derive(Clone, Copy, Debug, thiserror::Error, PartialEq)]
|
||||
#[error("Handle {index} of {kind} is either not present, or inaccessible yet")]
|
||||
pub struct BadHandle {
|
||||
pub kind: &'static str,
|
||||
pub index: usize,
|
||||
}
|
||||
[`Handle<T>`]: Handle
|
||||
*/
|
||||
|
||||
impl BadHandle {
|
||||
fn new<T>(handle: Handle<T>) -> Self {
|
||||
Self {
|
||||
kind: std::any::type_name::<T>(),
|
||||
index: handle.index(),
|
||||
}
|
||||
}
|
||||
}
|
||||
mod handle;
|
||||
mod handlevec;
|
||||
mod range;
|
||||
mod unique_arena;
|
||||
|
||||
/// A strongly typed reference to an arena item.
|
||||
///
|
||||
/// A `Handle` value can be used as an index into an [`Arena`] or [`UniqueArena`].
|
||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
|
||||
#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
|
||||
#[cfg_attr(
|
||||
any(feature = "serialize", feature = "deserialize"),
|
||||
serde(transparent)
|
||||
)]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
pub struct Handle<T> {
|
||||
index: Index,
|
||||
#[cfg_attr(any(feature = "serialize", feature = "deserialize"), serde(skip))]
|
||||
marker: PhantomData<T>,
|
||||
}
|
||||
pub use handle::{BadHandle, Handle};
|
||||
pub(crate) use handlevec::HandleVec;
|
||||
pub use range::{BadRangeError, Range};
|
||||
pub use unique_arena::UniqueArena;
|
||||
|
||||
impl<T> Clone for Handle<T> {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
use crate::Span;
|
||||
|
||||
impl<T> Copy for Handle<T> {}
|
||||
use handle::Index;
|
||||
|
||||
impl<T> PartialEq for Handle<T> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.index == other.index
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Eq for Handle<T> {}
|
||||
|
||||
impl<T> PartialOrd for Handle<T> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Ord for Handle<T> {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.index.cmp(&other.index)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> fmt::Debug for Handle<T> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(formatter, "[{}]", self.index)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> hash::Hash for Handle<T> {
|
||||
fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
|
||||
self.index.hash(hasher)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Handle<T> {
|
||||
pub(crate) const fn new(index: Index) -> Self {
|
||||
Handle {
|
||||
index,
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the index of this handle.
|
||||
pub const fn index(self) -> usize {
|
||||
self.index.get() as usize
|
||||
}
|
||||
|
||||
/// Convert a `usize` index into a `Handle<T>`.
|
||||
fn from_usize(index: usize) -> Self {
|
||||
let handle_index = u32::try_from(index)
|
||||
.ok()
|
||||
.and_then(Index::new)
|
||||
.expect("Failed to insert into arena. Handle overflows");
|
||||
Handle::new(handle_index)
|
||||
}
|
||||
|
||||
/// Convert a `usize` index into a `Handle<T>`, without range checks.
|
||||
const unsafe fn from_usize_unchecked(index: usize) -> Self {
|
||||
Handle::new(Index::new_unchecked(index as u32))
|
||||
}
|
||||
|
||||
/// Write this handle's index to `formatter`, preceded by `prefix`.
|
||||
pub fn write_prefixed(
|
||||
&self,
|
||||
formatter: &mut std::fmt::Formatter,
|
||||
prefix: &'static str,
|
||||
) -> std::fmt::Result {
|
||||
formatter.write_str(prefix)?;
|
||||
<usize as std::fmt::Display>::fmt(&self.index(), formatter)
|
||||
}
|
||||
}
|
||||
|
||||
/// A strongly typed range of handles.
|
||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
|
||||
#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
|
||||
#[cfg_attr(
|
||||
any(feature = "serialize", feature = "deserialize"),
|
||||
serde(transparent)
|
||||
)]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
pub struct Range<T> {
|
||||
inner: ops::Range<u32>,
|
||||
#[cfg_attr(any(feature = "serialize", feature = "deserialize"), serde(skip))]
|
||||
marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> Range<T> {
|
||||
pub(crate) const fn erase_type(self) -> Range<()> {
|
||||
let Self { inner, marker: _ } = self;
|
||||
Range {
|
||||
inner,
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Keep this diagnostic in sync with that of [`BadHandle`].
|
||||
#[derive(Clone, Debug, thiserror::Error)]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
#[error("Handle range {range:?} of {kind} is either not present, or inaccessible yet")]
|
||||
pub struct BadRangeError {
|
||||
// This error is used for many `Handle` types, but there's no point in making this generic, so
|
||||
// we just flatten them all to `Handle<()>` here.
|
||||
kind: &'static str,
|
||||
range: Range<()>,
|
||||
}
|
||||
|
||||
impl BadRangeError {
|
||||
pub fn new<T>(range: Range<T>) -> Self {
|
||||
Self {
|
||||
kind: std::any::type_name::<T>(),
|
||||
range: range.erase_type(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for Range<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Range {
|
||||
inner: self.inner.clone(),
|
||||
marker: self.marker,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> fmt::Debug for Range<T> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(formatter, "[{}..{}]", self.inner.start, self.inner.end - 1)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Iterator for Range<T> {
|
||||
type Item = Handle<T>;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.inner.start < self.inner.end {
|
||||
let next = self.inner.start;
|
||||
self.inner.start += 1;
|
||||
Some(Handle::new(NonMaxU32::new(next).unwrap()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Range<T> {
|
||||
/// Return a range enclosing handles `first` through `last`, inclusive.
|
||||
pub fn new_from_bounds(first: Handle<T>, last: Handle<T>) -> Self {
|
||||
Self {
|
||||
inner: (first.index() as u32)..(last.index() as u32 + 1),
|
||||
marker: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// return the first and last handles included in `self`.
|
||||
///
|
||||
/// If `self` is an empty range, there are no handles included, so
|
||||
/// return `None`.
|
||||
pub fn first_and_last(&self) -> Option<(Handle<T>, Handle<T>)> {
|
||||
if self.inner.start < self.inner.end {
|
||||
Some((
|
||||
// `Range::new_from_bounds` expects a start- and end-inclusive
|
||||
// range, but `self.inner` is an end-exclusive range.
|
||||
Handle::new(Index::new(self.inner.start).unwrap()),
|
||||
Handle::new(Index::new(self.inner.end - 1).unwrap()),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the index range covered by `self`.
|
||||
pub fn index_range(&self) -> ops::Range<u32> {
|
||||
self.inner.clone()
|
||||
}
|
||||
|
||||
/// Construct a `Range` that covers the indices in `inner`.
|
||||
pub fn from_index_range(inner: ops::Range<u32>, arena: &Arena<T>) -> Self {
|
||||
// Since `inner` is a `Range<u32>`, we only need to check that
|
||||
// the start and end are well-ordered, and that the end fits
|
||||
// within `arena`.
|
||||
assert!(inner.start <= inner.end);
|
||||
assert!(inner.end as usize <= arena.len());
|
||||
Self {
|
||||
inner,
|
||||
marker: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
use std::{fmt, ops};
|
||||
|
||||
/// An arena holding some kind of component (e.g., type, constant,
|
||||
/// instruction, etc.) that can be referenced.
|
||||
@ -526,355 +325,3 @@ mod tests {
|
||||
assert!(arena[t1] != arena[t2]);
|
||||
}
|
||||
}
|
||||
|
||||
/// An arena whose elements are guaranteed to be unique.
|
||||
///
|
||||
/// A `UniqueArena` holds a set of unique values of type `T`, each with an
|
||||
/// associated [`Span`]. Inserting a value returns a `Handle<T>`, which can be
|
||||
/// used to index the `UniqueArena` and obtain shared access to the `T` element.
|
||||
/// Access via a `Handle` is an array lookup - no hash lookup is necessary.
|
||||
///
|
||||
/// The element type must implement `Eq` and `Hash`. Insertions of equivalent
|
||||
/// elements, according to `Eq`, all return the same `Handle`.
|
||||
///
|
||||
/// Once inserted, elements may not be mutated.
|
||||
///
|
||||
/// `UniqueArena` is similar to [`Arena`]: If `Arena` is vector-like,
|
||||
/// `UniqueArena` is `HashSet`-like.
|
||||
#[derive(Clone)]
|
||||
pub struct UniqueArena<T> {
|
||||
set: FastIndexSet<T>,
|
||||
|
||||
/// Spans for the elements, indexed by handle.
|
||||
///
|
||||
/// The length of this vector is always equal to `set.len()`. `FastIndexSet`
|
||||
/// promises that its elements "are indexed in a compact range, without
|
||||
/// holes in the range 0..set.len()", so we can always use the indices
|
||||
/// returned by insertion as indices into this vector.
|
||||
span_info: Vec<Span>,
|
||||
}
|
||||
|
||||
impl<T> UniqueArena<T> {
|
||||
/// Create a new arena with no initial capacity allocated.
|
||||
pub fn new() -> Self {
|
||||
UniqueArena {
|
||||
set: FastIndexSet::default(),
|
||||
span_info: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the current number of items stored in this arena.
|
||||
pub fn len(&self) -> usize {
|
||||
self.set.len()
|
||||
}
|
||||
|
||||
/// Return `true` if the arena contains no elements.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.set.is_empty()
|
||||
}
|
||||
|
||||
/// Clears the arena, keeping all allocations.
|
||||
pub fn clear(&mut self) {
|
||||
self.set.clear();
|
||||
self.span_info.clear();
|
||||
}
|
||||
|
||||
/// Return the span associated with `handle`.
|
||||
///
|
||||
/// If a value has been inserted multiple times, the span returned is the
|
||||
/// one provided with the first insertion.
|
||||
pub fn get_span(&self, handle: Handle<T>) -> Span {
|
||||
*self
|
||||
.span_info
|
||||
.get(handle.index())
|
||||
.unwrap_or(&Span::default())
|
||||
}
|
||||
|
||||
#[cfg(feature = "compact")]
|
||||
pub(crate) fn drain_all(&mut self) -> UniqueArenaDrain<T> {
|
||||
UniqueArenaDrain {
|
||||
inner_elts: self.set.drain(..),
|
||||
inner_spans: self.span_info.drain(..),
|
||||
index: Index::new(0).unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "compact")]
|
||||
pub(crate) struct UniqueArenaDrain<'a, T> {
|
||||
inner_elts: indexmap::set::Drain<'a, T>,
|
||||
inner_spans: std::vec::Drain<'a, Span>,
|
||||
index: Index,
|
||||
}
|
||||
|
||||
#[cfg(feature = "compact")]
|
||||
impl<'a, T> Iterator for UniqueArenaDrain<'a, T> {
|
||||
type Item = (Handle<T>, T, Span);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self.inner_elts.next() {
|
||||
Some(elt) => {
|
||||
let handle = Handle::new(self.index);
|
||||
self.index = self.index.checked_add(1).unwrap();
|
||||
let span = self.inner_spans.next().unwrap();
|
||||
Some((handle, elt, span))
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Eq + hash::Hash> UniqueArena<T> {
|
||||
/// Returns an iterator over the items stored in this arena, returning both
|
||||
/// the item's handle and a reference to it.
|
||||
pub fn iter(&self) -> impl DoubleEndedIterator<Item = (Handle<T>, &T)> {
|
||||
self.set.iter().enumerate().map(|(i, v)| {
|
||||
let index = unsafe { Index::new_unchecked(i as u32) };
|
||||
(Handle::new(index), v)
|
||||
})
|
||||
}
|
||||
|
||||
/// Insert a new value into the arena.
|
||||
///
|
||||
/// Return a [`Handle<T>`], which can be used to index this arena to get a
|
||||
/// shared reference to the element.
|
||||
///
|
||||
/// If this arena already contains an element that is `Eq` to `value`,
|
||||
/// return a `Handle` to the existing element, and drop `value`.
|
||||
///
|
||||
/// If `value` is inserted into the arena, associate `span` with
|
||||
/// it. An element's span can be retrieved with the [`get_span`]
|
||||
/// method.
|
||||
///
|
||||
/// [`Handle<T>`]: Handle
|
||||
/// [`get_span`]: UniqueArena::get_span
|
||||
pub fn insert(&mut self, value: T, span: Span) -> Handle<T> {
|
||||
let (index, added) = self.set.insert_full(value);
|
||||
|
||||
if added {
|
||||
debug_assert!(index == self.span_info.len());
|
||||
self.span_info.push(span);
|
||||
}
|
||||
|
||||
debug_assert!(self.set.len() == self.span_info.len());
|
||||
|
||||
Handle::from_usize(index)
|
||||
}
|
||||
|
||||
/// Replace an old value with a new value.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// - if the old value is not in the arena
|
||||
/// - if the new value already exists in the arena
|
||||
pub fn replace(&mut self, old: Handle<T>, new: T) {
|
||||
let (index, added) = self.set.insert_full(new);
|
||||
assert!(added && index == self.set.len() - 1);
|
||||
|
||||
self.set.swap_remove_index(old.index()).unwrap();
|
||||
}
|
||||
|
||||
/// Return this arena's handle for `value`, if present.
|
||||
///
|
||||
/// If this arena already contains an element equal to `value`,
|
||||
/// return its handle. Otherwise, return `None`.
|
||||
pub fn get(&self, value: &T) -> Option<Handle<T>> {
|
||||
self.set
|
||||
.get_index_of(value)
|
||||
.map(|index| unsafe { Handle::from_usize_unchecked(index) })
|
||||
}
|
||||
|
||||
/// Return this arena's value at `handle`, if that is a valid handle.
|
||||
pub fn get_handle(&self, handle: Handle<T>) -> Result<&T, BadHandle> {
|
||||
self.set
|
||||
.get_index(handle.index())
|
||||
.ok_or_else(|| BadHandle::new(handle))
|
||||
}
|
||||
|
||||
/// Assert that `handle` is valid for this arena.
|
||||
pub fn check_contains_handle(&self, handle: Handle<T>) -> Result<(), BadHandle> {
|
||||
if handle.index() < self.set.len() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(BadHandle::new(handle))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Default for UniqueArena<T> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: fmt::Debug + Eq + hash::Hash> fmt::Debug for UniqueArena<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_map().entries(self.iter()).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ops::Index<Handle<T>> for UniqueArena<T> {
|
||||
type Output = T;
|
||||
fn index(&self, handle: Handle<T>) -> &T {
|
||||
&self.set[handle.index()]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
impl<T> serde::Serialize for UniqueArena<T>
|
||||
where
|
||||
T: Eq + hash::Hash + serde::Serialize,
|
||||
{
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
self.set.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "deserialize")]
|
||||
impl<'de, T> serde::Deserialize<'de> for UniqueArena<T>
|
||||
where
|
||||
T: Eq + hash::Hash + serde::Deserialize<'de>,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
let set = FastIndexSet::deserialize(deserializer)?;
|
||||
let span_info = std::iter::repeat(Span::default()).take(set.len()).collect();
|
||||
|
||||
Ok(Self { set, span_info })
|
||||
}
|
||||
}
|
||||
|
||||
//Note: largely borrowed from `HashSet` implementation
|
||||
#[cfg(feature = "arbitrary")]
|
||||
impl<'a, T> arbitrary::Arbitrary<'a> for UniqueArena<T>
|
||||
where
|
||||
T: Eq + hash::Hash + arbitrary::Arbitrary<'a>,
|
||||
{
|
||||
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
|
||||
let mut arena = Self::default();
|
||||
for elem in u.arbitrary_iter()? {
|
||||
arena.set.insert(elem?);
|
||||
arena.span_info.push(Span::UNDEFINED);
|
||||
}
|
||||
Ok(arena)
|
||||
}
|
||||
|
||||
fn arbitrary_take_rest(u: arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
|
||||
let mut arena = Self::default();
|
||||
for elem in u.arbitrary_take_rest_iter()? {
|
||||
arena.set.insert(elem?);
|
||||
arena.span_info.push(Span::UNDEFINED);
|
||||
}
|
||||
Ok(arena)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(depth: usize) -> (usize, Option<usize>) {
|
||||
let depth_hint = <usize as arbitrary::Arbitrary>::size_hint(depth);
|
||||
arbitrary::size_hint::and(depth_hint, (0, None))
|
||||
}
|
||||
}
|
||||
|
||||
/// A [`Vec`] indexed by [`Handle`]s.
|
||||
///
|
||||
/// A `HandleVec<T, U>` is a [`Vec<U>`] indexed by values of type `Handle<T>`,
|
||||
/// rather than `usize`.
|
||||
///
|
||||
/// Rather than a `push` method, `HandleVec` has an [`insert`] method, analogous
|
||||
/// to [`HashMap::insert`], that requires you to provide the handle at which the
|
||||
/// new value should appear. However, since `HandleVec` only supports insertion
|
||||
/// at the end, the given handle's index must be equal to the the `HandleVec`'s
|
||||
/// current length; otherwise, the insertion will panic.
|
||||
///
|
||||
/// [`insert`]: HandleVec::insert
|
||||
/// [`HashMap::insert`]: std::collections::HashMap::insert
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct HandleVec<T, U> {
|
||||
inner: Vec<U>,
|
||||
as_keys: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T, U> Default for HandleVec<T, U> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
inner: vec![],
|
||||
as_keys: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
impl<T, U> HandleVec<T, U> {
|
||||
pub(crate) const fn new() -> Self {
|
||||
Self {
|
||||
inner: vec![],
|
||||
as_keys: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn with_capacity(capacity: usize) -> Self {
|
||||
Self {
|
||||
inner: Vec::with_capacity(capacity),
|
||||
as_keys: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn len(&self) -> usize {
|
||||
self.inner.len()
|
||||
}
|
||||
|
||||
/// Insert a mapping from `handle` to `value`.
|
||||
///
|
||||
/// Unlike a [`HashMap`], a `HandleVec` can only have new entries inserted at
|
||||
/// the end, like [`Vec::push`]. So the index of `handle` must equal
|
||||
/// [`self.len()`].
|
||||
///
|
||||
/// [`HashMap`]: std::collections::HashMap
|
||||
/// [`self.len()`]: HandleVec::len
|
||||
pub(crate) fn insert(&mut self, handle: Handle<T>, value: U) {
|
||||
assert_eq!(handle.index(), self.inner.len());
|
||||
self.inner.push(value);
|
||||
}
|
||||
|
||||
pub(crate) fn get(&self, handle: Handle<T>) -> Option<&U> {
|
||||
self.inner.get(handle.index())
|
||||
}
|
||||
|
||||
pub(crate) fn clear(&mut self) {
|
||||
self.inner.clear()
|
||||
}
|
||||
|
||||
pub(crate) fn resize(&mut self, len: usize, fill: U)
|
||||
where
|
||||
U: Clone,
|
||||
{
|
||||
self.inner.resize(len, fill);
|
||||
}
|
||||
|
||||
pub(crate) fn iter(&self) -> impl Iterator<Item = &U> {
|
||||
self.inner.iter()
|
||||
}
|
||||
|
||||
pub(crate) fn iter_mut(&mut self) -> impl Iterator<Item = &mut U> {
|
||||
self.inner.iter_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> ops::Index<Handle<T>> for HandleVec<T, U> {
|
||||
type Output = U;
|
||||
|
||||
fn index(&self, handle: Handle<T>) -> &Self::Output {
|
||||
&self.inner[handle.index()]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> ops::IndexMut<Handle<T>> for HandleVec<T, U> {
|
||||
fn index_mut(&mut self, handle: Handle<T>) -> &mut Self::Output {
|
||||
&mut self.inner[handle.index()]
|
||||
}
|
||||
}
|
||||
|
131
naga/src/arena/range.rs
Normal file
131
naga/src/arena/range.rs
Normal file
@ -0,0 +1,131 @@
|
||||
//! Well-typed ranges of [`Arena`]s.
|
||||
//!
|
||||
//! This module defines the [`Range`] type, representing a contiguous range of
|
||||
//! entries in an [`Arena`].
|
||||
//!
|
||||
//! [`Arena`]: super::Arena
|
||||
|
||||
use super::{
|
||||
handle::{Handle, Index},
|
||||
Arena,
|
||||
};
|
||||
|
||||
use std::{fmt, marker::PhantomData, ops};
|
||||
|
||||
/// A strongly typed range of handles.
|
||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize))]
|
||||
#[cfg_attr(feature = "deserialize", derive(serde::Deserialize))]
|
||||
#[cfg_attr(
|
||||
any(feature = "serialize", feature = "deserialize"),
|
||||
serde(transparent)
|
||||
)]
|
||||
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
pub struct Range<T> {
|
||||
pub(super) inner: ops::Range<u32>,
|
||||
#[cfg_attr(any(feature = "serialize", feature = "deserialize"), serde(skip))]
|
||||
marker: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> Range<T> {
|
||||
pub(crate) const fn erase_type(self) -> Range<()> {
|
||||
let Self { inner, marker: _ } = self;
|
||||
Range {
|
||||
inner,
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Keep this diagnostic in sync with that of [`BadHandle`].
|
||||
#[derive(Clone, Debug, thiserror::Error)]
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
#[error("Handle range {range:?} of {kind} is either not present, or inaccessible yet")]
|
||||
pub struct BadRangeError {
|
||||
// This error is used for many `Handle` types, but there's no point in making this generic, so
|
||||
// we just flatten them all to `Handle<()>` here.
|
||||
kind: &'static str,
|
||||
range: Range<()>,
|
||||
}
|
||||
|
||||
impl BadRangeError {
|
||||
pub fn new<T>(range: Range<T>) -> Self {
|
||||
Self {
|
||||
kind: std::any::type_name::<T>(),
|
||||
range: range.erase_type(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for Range<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Range {
|
||||
inner: self.inner.clone(),
|
||||
marker: self.marker,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> fmt::Debug for Range<T> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(formatter, "[{}..{}]", self.inner.start, self.inner.end - 1)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Iterator for Range<T> {
|
||||
type Item = Handle<T>;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.inner.start < self.inner.end {
|
||||
let next = self.inner.start;
|
||||
self.inner.start += 1;
|
||||
Some(Handle::new(Index::new(next).unwrap()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Range<T> {
|
||||
/// Return a range enclosing handles `first` through `last`, inclusive.
|
||||
pub fn new_from_bounds(first: Handle<T>, last: Handle<T>) -> Self {
|
||||
Self {
|
||||
inner: (first.index() as u32)..(last.index() as u32 + 1),
|
||||
marker: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// return the first and last handles included in `self`.
|
||||
///
|
||||
/// If `self` is an empty range, there are no handles included, so
|
||||
/// return `None`.
|
||||
pub fn first_and_last(&self) -> Option<(Handle<T>, Handle<T>)> {
|
||||
if self.inner.start < self.inner.end {
|
||||
Some((
|
||||
// `Range::new_from_bounds` expects a start- and end-inclusive
|
||||
// range, but `self.inner` is an end-exclusive range.
|
||||
Handle::new(Index::new(self.inner.start).unwrap()),
|
||||
Handle::new(Index::new(self.inner.end - 1).unwrap()),
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the index range covered by `self`.
|
||||
pub fn index_range(&self) -> ops::Range<u32> {
|
||||
self.inner.clone()
|
||||
}
|
||||
|
||||
/// Construct a `Range` that covers the indices in `inner`.
|
||||
pub fn from_index_range(inner: ops::Range<u32>, arena: &Arena<T>) -> Self {
|
||||
// Since `inner` is a `Range<u32>`, we only need to check that
|
||||
// the start and end are well-ordered, and that the end fits
|
||||
// within `arena`.
|
||||
assert!(inner.start <= inner.end);
|
||||
assert!(inner.end as usize <= arena.len());
|
||||
Self {
|
||||
inner,
|
||||
marker: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
262
naga/src/arena/unique_arena.rs
Normal file
262
naga/src/arena/unique_arena.rs
Normal file
@ -0,0 +1,262 @@
|
||||
//! The [`UniqueArena`] type and supporting definitions.
|
||||
|
||||
use crate::{FastIndexSet, Span};
|
||||
|
||||
use super::handle::{BadHandle, Handle, Index};
|
||||
|
||||
use std::{fmt, hash, ops};
|
||||
|
||||
/// An arena whose elements are guaranteed to be unique.
|
||||
///
|
||||
/// A `UniqueArena` holds a set of unique values of type `T`, each with an
|
||||
/// associated [`Span`]. Inserting a value returns a `Handle<T>`, which can be
|
||||
/// used to index the `UniqueArena` and obtain shared access to the `T` element.
|
||||
/// Access via a `Handle` is an array lookup - no hash lookup is necessary.
|
||||
///
|
||||
/// The element type must implement `Eq` and `Hash`. Insertions of equivalent
|
||||
/// elements, according to `Eq`, all return the same `Handle`.
|
||||
///
|
||||
/// Once inserted, elements may not be mutated.
|
||||
///
|
||||
/// `UniqueArena` is similar to [`Arena`]: If `Arena` is vector-like,
|
||||
/// `UniqueArena` is `HashSet`-like.
|
||||
///
|
||||
/// [`Arena`]: super::Arena
|
||||
#[derive(Clone)]
|
||||
pub struct UniqueArena<T> {
|
||||
set: FastIndexSet<T>,
|
||||
|
||||
/// Spans for the elements, indexed by handle.
|
||||
///
|
||||
/// The length of this vector is always equal to `set.len()`. `FastIndexSet`
|
||||
/// promises that its elements "are indexed in a compact range, without
|
||||
/// holes in the range 0..set.len()", so we can always use the indices
|
||||
/// returned by insertion as indices into this vector.
|
||||
span_info: Vec<Span>,
|
||||
}
|
||||
|
||||
impl<T> UniqueArena<T> {
|
||||
/// Create a new arena with no initial capacity allocated.
|
||||
pub fn new() -> Self {
|
||||
UniqueArena {
|
||||
set: FastIndexSet::default(),
|
||||
span_info: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the current number of items stored in this arena.
|
||||
pub fn len(&self) -> usize {
|
||||
self.set.len()
|
||||
}
|
||||
|
||||
/// Return `true` if the arena contains no elements.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.set.is_empty()
|
||||
}
|
||||
|
||||
/// Clears the arena, keeping all allocations.
|
||||
pub fn clear(&mut self) {
|
||||
self.set.clear();
|
||||
self.span_info.clear();
|
||||
}
|
||||
|
||||
/// Return the span associated with `handle`.
|
||||
///
|
||||
/// If a value has been inserted multiple times, the span returned is the
|
||||
/// one provided with the first insertion.
|
||||
pub fn get_span(&self, handle: Handle<T>) -> Span {
|
||||
*self
|
||||
.span_info
|
||||
.get(handle.index())
|
||||
.unwrap_or(&Span::default())
|
||||
}
|
||||
|
||||
#[cfg(feature = "compact")]
|
||||
pub(crate) fn drain_all(&mut self) -> UniqueArenaDrain<T> {
|
||||
UniqueArenaDrain {
|
||||
inner_elts: self.set.drain(..),
|
||||
inner_spans: self.span_info.drain(..),
|
||||
index: Index::new(0).unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "compact")]
|
||||
pub struct UniqueArenaDrain<'a, T> {
|
||||
inner_elts: indexmap::set::Drain<'a, T>,
|
||||
inner_spans: std::vec::Drain<'a, Span>,
|
||||
index: Index,
|
||||
}
|
||||
|
||||
#[cfg(feature = "compact")]
|
||||
impl<'a, T> Iterator for UniqueArenaDrain<'a, T> {
|
||||
type Item = (Handle<T>, T, Span);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
match self.inner_elts.next() {
|
||||
Some(elt) => {
|
||||
let handle = Handle::new(self.index);
|
||||
self.index = self.index.checked_add(1).unwrap();
|
||||
let span = self.inner_spans.next().unwrap();
|
||||
Some((handle, elt, span))
|
||||
}
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Eq + hash::Hash> UniqueArena<T> {
|
||||
/// Returns an iterator over the items stored in this arena, returning both
|
||||
/// the item's handle and a reference to it.
|
||||
pub fn iter(&self) -> impl DoubleEndedIterator<Item = (Handle<T>, &T)> {
|
||||
self.set.iter().enumerate().map(|(i, v)| {
|
||||
let index = unsafe { Index::new_unchecked(i as u32) };
|
||||
(Handle::new(index), v)
|
||||
})
|
||||
}
|
||||
|
||||
/// Insert a new value into the arena.
|
||||
///
|
||||
/// Return a [`Handle<T>`], which can be used to index this arena to get a
|
||||
/// shared reference to the element.
|
||||
///
|
||||
/// If this arena already contains an element that is `Eq` to `value`,
|
||||
/// return a `Handle` to the existing element, and drop `value`.
|
||||
///
|
||||
/// If `value` is inserted into the arena, associate `span` with
|
||||
/// it. An element's span can be retrieved with the [`get_span`]
|
||||
/// method.
|
||||
///
|
||||
/// [`Handle<T>`]: Handle
|
||||
/// [`get_span`]: UniqueArena::get_span
|
||||
pub fn insert(&mut self, value: T, span: Span) -> Handle<T> {
|
||||
let (index, added) = self.set.insert_full(value);
|
||||
|
||||
if added {
|
||||
debug_assert!(index == self.span_info.len());
|
||||
self.span_info.push(span);
|
||||
}
|
||||
|
||||
debug_assert!(self.set.len() == self.span_info.len());
|
||||
|
||||
Handle::from_usize(index)
|
||||
}
|
||||
|
||||
/// Replace an old value with a new value.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// - if the old value is not in the arena
|
||||
/// - if the new value already exists in the arena
|
||||
pub fn replace(&mut self, old: Handle<T>, new: T) {
|
||||
let (index, added) = self.set.insert_full(new);
|
||||
assert!(added && index == self.set.len() - 1);
|
||||
|
||||
self.set.swap_remove_index(old.index()).unwrap();
|
||||
}
|
||||
|
||||
/// Return this arena's handle for `value`, if present.
|
||||
///
|
||||
/// If this arena already contains an element equal to `value`,
|
||||
/// return its handle. Otherwise, return `None`.
|
||||
pub fn get(&self, value: &T) -> Option<Handle<T>> {
|
||||
self.set
|
||||
.get_index_of(value)
|
||||
.map(|index| unsafe { Handle::from_usize_unchecked(index) })
|
||||
}
|
||||
|
||||
/// Return this arena's value at `handle`, if that is a valid handle.
|
||||
pub fn get_handle(&self, handle: Handle<T>) -> Result<&T, BadHandle> {
|
||||
self.set
|
||||
.get_index(handle.index())
|
||||
.ok_or_else(|| BadHandle::new(handle))
|
||||
}
|
||||
|
||||
/// Assert that `handle` is valid for this arena.
|
||||
pub fn check_contains_handle(&self, handle: Handle<T>) -> Result<(), BadHandle> {
|
||||
if handle.index() < self.set.len() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(BadHandle::new(handle))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Default for UniqueArena<T> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: fmt::Debug + Eq + hash::Hash> fmt::Debug for UniqueArena<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_map().entries(self.iter()).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ops::Index<Handle<T>> for UniqueArena<T> {
|
||||
type Output = T;
|
||||
fn index(&self, handle: Handle<T>) -> &T {
|
||||
&self.set[handle.index()]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "serialize")]
|
||||
impl<T> serde::Serialize for UniqueArena<T>
|
||||
where
|
||||
T: Eq + hash::Hash + serde::Serialize,
|
||||
{
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
self.set.serialize(serializer)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "deserialize")]
|
||||
impl<'de, T> serde::Deserialize<'de> for UniqueArena<T>
|
||||
where
|
||||
T: Eq + hash::Hash + serde::Deserialize<'de>,
|
||||
{
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
let set = FastIndexSet::deserialize(deserializer)?;
|
||||
let span_info = std::iter::repeat(Span::default()).take(set.len()).collect();
|
||||
|
||||
Ok(Self { set, span_info })
|
||||
}
|
||||
}
|
||||
|
||||
//Note: largely borrowed from `HashSet` implementation
|
||||
#[cfg(feature = "arbitrary")]
|
||||
impl<'a, T> arbitrary::Arbitrary<'a> for UniqueArena<T>
|
||||
where
|
||||
T: Eq + hash::Hash + arbitrary::Arbitrary<'a>,
|
||||
{
|
||||
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
|
||||
let mut arena = Self::default();
|
||||
for elem in u.arbitrary_iter()? {
|
||||
arena.set.insert(elem?);
|
||||
arena.span_info.push(Span::UNDEFINED);
|
||||
}
|
||||
Ok(arena)
|
||||
}
|
||||
|
||||
fn arbitrary_take_rest(u: arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
|
||||
let mut arena = Self::default();
|
||||
for elem in u.arbitrary_take_rest_iter()? {
|
||||
arena.set.insert(elem?);
|
||||
arena.span_info.push(Span::UNDEFINED);
|
||||
}
|
||||
Ok(arena)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint(depth: usize) -> (usize, Option<usize>) {
|
||||
let depth_hint = <usize as arbitrary::Arbitrary>::size_hint(depth);
|
||||
arbitrary::size_hint::and(depth_hint, (0, None))
|
||||
}
|
||||
}
|
@ -34,25 +34,6 @@ with optional span info, representing a series of statements executed in order.
|
||||
`EntryPoint`s or `Function` is a `Block`, and `Statement` has a
|
||||
[`Block`][Statement::Block] variant.
|
||||
|
||||
## Arenas
|
||||
|
||||
To improve translator performance and reduce memory usage, most structures are
|
||||
stored in an [`Arena`]. An `Arena<T>` stores a series of `T` values, indexed by
|
||||
[`Handle<T>`](Handle) values, which are just wrappers around integer indexes.
|
||||
For example, a `Function`'s expressions are stored in an `Arena<Expression>`,
|
||||
and compound expressions refer to their sub-expressions via `Handle<Expression>`
|
||||
values. (When examining the serialized form of a `Module`, note that the first
|
||||
element of an `Arena` has an index of 1, not 0.)
|
||||
|
||||
A [`UniqueArena`] is just like an `Arena`, except that it stores only a single
|
||||
instance of each value. The value type must implement `Eq` and `Hash`. Like an
|
||||
`Arena`, inserting a value into a `UniqueArena` returns a `Handle` which can be
|
||||
used to efficiently access the value, without a hash lookup. Inserting a value
|
||||
multiple times returns the same `Handle`.
|
||||
|
||||
If the `span` feature is enabled, both `Arena` and `UniqueArena` can associate a
|
||||
source code span with each element.
|
||||
|
||||
## Function Calls
|
||||
|
||||
Naga's representation of function calls is unusual. Most languages treat
|
||||
|
Loading…
Reference in New Issue
Block a user