diff --git a/components/util/lib.rs b/components/util/lib.rs index 364a7e92712..46e8b0b60df 100644 --- a/components/util/lib.rs +++ b/components/util/lib.rs @@ -45,6 +45,7 @@ pub mod logical_geometry; pub mod memory; pub mod namespace; pub mod opts; +pub mod persistent_list; pub mod range; pub mod resource_files; pub mod rtinstrument; diff --git a/components/util/persistent_list.rs b/components/util/persistent_list.rs new file mode 100644 index 00000000000..7aae2bf030c --- /dev/null +++ b/components/util/persistent_list.rs @@ -0,0 +1,100 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//! A persistent, thread-safe singly-linked list. + +use std::mem; +use sync::Arc; + +pub struct PersistentList { + head: PersistentListLink, + length: uint, +} + +struct PersistentListEntry { + value: T, + next: PersistentListLink, +} + +type PersistentListLink = Option>>; + +impl PersistentList where T: Send + Sync { + #[inline] + pub fn new() -> PersistentList { + PersistentList { + head: None, + length: 0, + } + } + + #[inline] + pub fn len(&self) -> uint { + self.length + } + + #[inline] + pub fn front(&self) -> Option<&T> { + self.head.as_ref().map(|head| &head.value) + } + + #[inline] + pub fn prepend_elem(&self, value: T) -> PersistentList { + PersistentList { + head: Some(Arc::new(PersistentListEntry { + value: value, + next: self.head.clone(), + })), + length: self.length + 1, + } + } + + #[inline] + pub fn iter<'a>(&'a self) -> PersistentListIterator<'a,T> { + // This could clone (and would not need the lifetime if it did), but then it would incur + // atomic operations on every call to `.next()`. Bad. + PersistentListIterator { + entry: self.head.as_ref().map(|head| &**head), + } + } +} + +impl Clone for PersistentList where T: Send + Sync { + fn clone(&self) -> PersistentList { + // This establishes the persistent nature of this list: we can clone a list by just cloning + // its head. + PersistentList { + head: self.head.clone(), + length: self.length, + } + } +} + +pub struct PersistentListIterator<'a,T> where T: 'a + Send + Sync { + entry: Option<&'a PersistentListEntry>, +} + +impl<'a,T> Iterator<&'a T> for PersistentListIterator<'a,T> where T: Send + Sync { + #[inline] + fn next(&mut self) -> Option<&'a T> { + let entry = match self.entry { + None => return None, + Some(entry) => { + // This `transmute` is necessary to ensure that the lifetimes of the next entry and + // this entry match up; the compiler doesn't know this, but we do because of the + // reference counting behavior of `Arc`. + unsafe { + mem::transmute::<&'a PersistentListEntry, + &'static PersistentListEntry>(entry) + } + } + }; + let value = &entry.value; + self.entry = match entry.next { + None => None, + Some(ref entry) => Some(&**entry), + }; + Some(value) + } +} +