diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 5844edf000a..e4d0bc596cb 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -77,6 +77,7 @@ pub mod sync; pub mod owning_ref; pub mod tiny_list; pub mod sorted_map; +pub mod work_queue; pub struct OnDrop(pub F); diff --git a/src/librustc_data_structures/work_queue.rs b/src/librustc_data_structures/work_queue.rs new file mode 100644 index 00000000000..b8e8b249bb5 --- /dev/null +++ b/src/librustc_data_structures/work_queue.rs @@ -0,0 +1,72 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use indexed_set::IdxSetBuf; +use indexed_vec::Idx; +use std::collections::VecDeque; + +/// A work queue is a handy data structure for tracking work left to +/// do. (For example, basic blocks left to process.) It is basically a +/// de-duplicating queue; so attempting to insert X if X is already +/// enqueued has no effect. This implementation assumes that the +/// elements are dense indices, so it can allocate the queue to size +/// and also use a bit set to track occupancy. +pub struct WorkQueue { + deque: VecDeque, + set: IdxSetBuf, +} + +impl WorkQueue { + /// Create a new work queue with all the elements from (0..len). + #[inline] + pub fn with_all(len: usize) -> Self { + WorkQueue { + deque: (0..len).map(T::new).collect(), + set: IdxSetBuf::new_filled(len), + } + } + + /// Create a new work queue that starts empty, where elements range from (0..len). + #[inline] + pub fn with_none(len: usize) -> Self { + WorkQueue { + deque: VecDeque::with_capacity(len), + set: IdxSetBuf::new_empty(len), + } + } + + /// Attempt to enqueue `element` in the work queue. Returns false if it was already present. + #[inline] + pub fn insert(&mut self, element: T) -> bool { + if self.set.add(&element) { + self.deque.push_back(element); + true + } else { + false + } + } + + /// Attempt to enqueue `element` in the work queue. Returns false if it was already present. + #[inline] + pub fn pop(&mut self) -> Option { + if let Some(element) = self.deque.pop_front() { + self.set.remove(&element); + Some(element) + } else { + None + } + } + + /// True if nothing is enqueued. + #[inline] + pub fn is_empty(&self) -> bool { + self.deque.is_empty() + } +}