intrusive_collections/
lib.rs

1// Copyright 2016 Amanieu d'Antras
2// Copyright 2020 Amari Robinson
3//
4// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
5// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
6// http://opensource.org/licenses/MIT>, at your option. This file may not be
7// copied, modified, or distributed except according to those terms.
8
9//! Intrusive collections for Rust.
10//!
11//! This library provides a set of high-performance intrusive collections which
12//! can offer better performance and more flexibility than standard collections.
13//!
14//! The main difference between an intrusive collection and a normal one is that
15//! while normal collections allocate memory behind your back to keep track of a
16//! set of *values*, intrusive collections never allocate memory themselves and
17//! instead keep track of a set of *objects*. Such collections are called
18//! intrusive because they requires explicit support in objects to allow them to
19//! be inserted into a collection.
20//!
21//! # Example
22//!
23//! ```
24//! use intrusive_collections::intrusive_adapter;
25//! use intrusive_collections::{LinkedList, LinkedListLink};
26//! use std::cell::Cell;
27//!
28//! // A simple struct containing an instrusive link and a value
29//! struct Test {
30//!     link: LinkedListLink,
31//!     value: Cell<i32>,
32//! }
33//!
34//! // The adapter describes how an object can be inserted into an intrusive
35//! // collection. This is automatically generated using a macro.
36//! intrusive_adapter!(TestAdapter = Box<Test>: Test { link: LinkedListLink });
37//!
38//! // Create a list and some objects
39//! let mut list = LinkedList::new(TestAdapter::new());
40//! let a = Box::new(Test {
41//!     link: LinkedListLink::new(),
42//!     value: Cell::new(1),
43//! });
44//! let b = Box::new(Test {
45//!     link: LinkedListLink::new(),
46//!     value: Cell::new(2),
47//! });
48//! let c = Box::new(Test {
49//!     link: LinkedListLink::new(),
50//!     value: Cell::new(3),
51//! });
52//!
53//! // Insert the objects at the front of the list
54//! list.push_front(a);
55//! list.push_front(b);
56//! list.push_front(c);
57//! assert_eq!(list.iter().map(|x| x.value.get()).collect::<Vec<_>>(), [3, 2, 1]);
58//!
59//! // At this point, the objects are owned by the list, and we can modify
60//! // them through the list.
61//! list.front().get().unwrap().value.set(4);
62//! assert_eq!(list.iter().map(|x| x.value.get()).collect::<Vec<_>>(), [4, 2, 1]);
63//!
64//! // Removing an object from an instrusive collection gives us back the
65//! // Box<Test> that we originally inserted into it.
66//! let a = list.pop_front().unwrap();
67//! assert_eq!(a.value.get(), 4);
68//! assert_eq!(list.iter().map(|x| x.value.get()).collect::<Vec<_>>(), [2, 1]);
69//!
70//! // Dropping the collection will automatically free b and c by
71//! // transforming them back into Box<Test> and dropping them.
72//! drop(list);
73//! ```
74//!
75//! # Links and adapters
76//!
77//! Intrusive collections track objects through links which are embedded within
78//! the objects themselves. It also allows a single object to be part of
79//! multiple intrusive collections at once by having multiple links in it.
80//!
81//! The relationship between an object and a link inside it is described by the
82//! `Adapter` trait. Intrusive collections use an implementation of this trait
83//! to determine which link in an object should be used by the collection. In
84//! most cases you do not need to write an implementation manually: the
85//! `intrusive_adapter!` macro will automatically generate the necessary code.
86//!
87//! For red-black trees, the adapter must also implement the `KeyAdapter` trait
88//! which allows a key to be extracted from an object. This key is then used to
89//! keep all elements in the tree in ascending order.
90//!
91//! ```
92//! use intrusive_collections::intrusive_adapter;
93//! use intrusive_collections::{SinglyLinkedListLink, SinglyLinkedList};
94//! use intrusive_collections::{LinkedListLink, LinkedList};
95//! use intrusive_collections::{XorLinkedList, XorLinkedListLink};
96//! use intrusive_collections::{RBTreeLink, RBTree, KeyAdapter};
97//! use std::rc::Rc;
98//!
99//! // This struct can be inside three lists and one tree simultaneously
100//! #[derive(Default)]
101//! struct Test {
102//!     link: LinkedListLink,
103//!     link2: SinglyLinkedListLink,
104//!     link3: XorLinkedListLink,
105//!     link4: RBTreeLink,
106//!     value: i32,
107//! }
108//!
109//! intrusive_adapter!(MyAdapter = Rc<Test>: Test { link: LinkedListLink });
110//! intrusive_adapter!(MyAdapter2 = Rc<Test>: Test { link2: SinglyLinkedListLink });
111//! intrusive_adapter!(MyAdapter3 = Rc<Test>: Test { link3: XorLinkedListLink });
112//! intrusive_adapter!(MyAdapter4 = Rc<Test>: Test { link4: RBTreeLink });
113//! impl<'a> KeyAdapter<'a> for MyAdapter4 {
114//!     type Key = i32;
115//!     fn get_key(&self, x: &'a Test) -> i32 { x.value }
116//! }
117//!
118//! let mut a = LinkedList::new(MyAdapter::new());
119//! let mut b = SinglyLinkedList::new(MyAdapter2::new());
120//! let mut c = XorLinkedList::new(MyAdapter3::new());
121//! let mut d = RBTree::new(MyAdapter4::new());
122//!
123//! let test = Rc::new(Test::default());
124//! a.push_front(test.clone());
125//! b.push_front(test.clone());
126//! c.push_front(test.clone());
127//! d.insert(test);
128//! ```
129//!
130//! # Cursors
131//!
132//! Intrusive collections are manipulated using cursors. A cursor is similar to
133//! an iterator, except that it can freely seek back-and-forth, and can safely
134//! mutate the list during iteration. This is similar to how a C++ iterator
135//! works.
136//!
137//! A cursor views an intrusive collection as a circular list, with a special
138//! null object between the last and first elements of the collection. A cursor
139//! will either point to a valid object in the collection or to this special
140//! null object.
141//!
142//! Cursors come in two forms: `Cursor` and `CursorMut`. A `Cursor` gives a
143//! read-only view of a collection, but you are allowed to use multiple `Cursor`
144//! objects simultaneously on the same collection. On the other hand,
145//! `CursorMut` can be used to mutate the collection, but you may only use one
146//! of them at a time.
147//!
148//! Cursors are a very powerful abstraction since they allow a collection to be
149//! mutated safely while it is being iterated on. For example, here is a
150//! function which removes all values within a given range from a `RBTree`:
151//!
152//! ```
153//! use intrusive_collections::intrusive_adapter;
154//! use intrusive_collections::{RBTreeLink, RBTree, KeyAdapter, Bound};
155//!
156//! struct Element {
157//!     link: RBTreeLink,
158//!     value: i32,
159//! }
160//!
161//! intrusive_adapter!(ElementAdapter = Box<Element>: Element { link: RBTreeLink });
162//! impl<'a> KeyAdapter<'a> for ElementAdapter {
163//!     type Key = i32;
164//!     fn get_key(&self, e: &'a Element) -> i32 { e.value }
165//! }
166//!
167//! fn remove_range(tree: &mut RBTree<ElementAdapter>, min: i32, max: i32) {
168//!     // Find the first element which is greater than or equal to min
169//!     let mut cursor = tree.lower_bound_mut(Bound::Included(&min));
170//!
171//!     // Iterate over all elements in the range [min, max]
172//!     while cursor.get().map_or(false, |e| e.value <= max) {
173//!         // CursorMut::remove will return a Some(<Box<Element>), which we
174//!         // simply drop here. This will also advance the cursor to the next
175//!         // element.
176//!         cursor.remove();
177//!     }
178//! }
179//! ```
180//!
181//! # Scoped collections
182//!
183//! Instead of taking ownership of objects inserted into them, intrusive
184//! collections can also work with borrowed values. This works by using
185//! lifetimes and the borrow checker to ensure that any objects inserted into an
186//! intrusive collection will outlive the collection itself.
187//!
188//! ```
189//! use intrusive_collections::intrusive_adapter;
190//! use intrusive_collections::{LinkedListLink, LinkedList};
191//! use typed_arena::Arena;
192//! use std::cell::Cell;
193//!
194//! struct Value {
195//!     link: LinkedListLink,
196//!     value: Cell<i32>,
197//! }
198//!
199//! // Note that we use a plain reference as the pointer type for the collection.
200//! intrusive_adapter!(ValueAdapter<'a> = &'a Value: Value { link: LinkedListLink });
201//!
202//! // Create an arena and a list. Note that since stack objects are dropped in
203//! // reverse order, the Arena must be created before the LinkedList. This
204//! // ensures that the list is dropped before the values are freed by the
205//! // arena. This is enforced by the Rust lifetime system.
206//! let arena = Arena::new();
207//! let mut list = LinkedList::new(ValueAdapter::new());
208//!
209//! // We can now insert values allocated from the arena into the linked list
210//! list.push_back(arena.alloc(Value {
211//!     link: LinkedListLink::new(),
212//!     value: Cell::new(1),
213//! }));
214//! list.push_back(arena.alloc(Value {
215//!     link: LinkedListLink::new(),
216//!     value: Cell::new(2),
217//! }));
218//! list.push_back(arena.alloc(Value {
219//!     link: LinkedListLink::new(),
220//!     value: Cell::new(3),
221//! }));
222//! assert_eq!(list.iter().map(|x| x.value.get()).collect::<Vec<_>>(), [1, 2, 3]);
223//!
224//! // We can also insert stack allocated values into an intrusive list.
225//! // Again, the values must outlive the LinkedList.
226//! let a = Value {
227//!     link: LinkedListLink::new(),
228//!     value: Cell::new(4),
229//! };
230//! let b = Value {
231//!     link: LinkedListLink::new(),
232//!     value: Cell::new(5),
233//! };
234//! let c = Value {
235//!     link: LinkedListLink::new(),
236//!     value: Cell::new(6),
237//! };
238//! let mut list2 = LinkedList::new(ValueAdapter::new());
239//! list2.push_back(&a);
240//! list2.push_back(&b);
241//! list2.push_back(&c);
242//! assert_eq!(list2.iter().map(|x| x.value.get()).collect::<Vec<_>>(), [4, 5, 6]);
243//!
244//! // Since these are shared references, any changes in the values are reflected in
245//! // the list.
246//! a.value.set(7);
247//! assert_eq!(list2.iter().map(|x| x.value.get()).collect::<Vec<_>>(), [7, 5, 6]);
248//! ```
249//!
250//! # Safety
251//!
252//! While it is possible to use intrusive collections without any unsafe code,
253//! this crate also exposes a few unsafe features.
254//!
255//! The `cursor_from_ptr` and `cursor_mut_from_ptr` allow you to create a
256//! cursor pointing to a specific element in the collection from a pointer to
257//! that element. This is unsafe because it assumes that the objected pointed to
258//! is currently inserted in the collection.
259//!
260//! The `UnsafeRef` type acts like `Rc`, except without the reference count.
261//! Instead, you are responsible for keeping track of the number of active
262//! references to an object and for freeing it once the last reference is
263//! dropped. The advantage of `UnsafeRef` over `Rc` is that it reduces the size
264//! of the allocation by two `usize` and avoids the overhead of maintaining
265//! reference counts.
266
267#![warn(missing_docs)]
268#![warn(rust_2018_idioms)]
269#![no_std]
270#![cfg_attr(feature = "nightly", feature(const_fn_trait_bound))]
271#![allow(
272    clippy::declare_interior_mutable_const,
273    clippy::collapsible_if,
274    clippy::collapsible_else_if
275)]
276
277#[cfg(feature = "alloc")]
278extern crate alloc;
279
280#[cfg(test)]
281extern crate std;
282
283mod unsafe_ref;
284#[macro_use]
285mod adapter;
286mod key_adapter;
287mod link_ops;
288mod pointer_ops;
289mod unchecked_option;
290
291pub mod linked_list;
292pub mod rbtree;
293pub mod singly_linked_list;
294pub mod xor_linked_list;
295
296pub use crate::adapter::Adapter;
297pub use crate::key_adapter::KeyAdapter;
298pub use crate::link_ops::{DefaultLinkOps, LinkOps};
299pub use crate::linked_list::AtomicLink as LinkedListAtomicLink;
300pub use crate::linked_list::Link as LinkedListLink;
301pub use crate::linked_list::LinkedList;
302pub use crate::pointer_ops::{DefaultPointerOps, PointerOps};
303pub use crate::rbtree::AtomicLink as RBTreeAtomicLink;
304pub use crate::rbtree::Link as RBTreeLink;
305pub use crate::rbtree::RBTree;
306pub use crate::singly_linked_list::AtomicLink as SinglyLinkedListAtomicLink;
307pub use crate::singly_linked_list::Link as SinglyLinkedListLink;
308pub use crate::singly_linked_list::SinglyLinkedList;
309pub use crate::unsafe_ref::UnsafeRef;
310pub use crate::xor_linked_list::AtomicLink as XorLinkedListAtomicLink;
311pub use crate::xor_linked_list::Link as XorLinkedListLink;
312pub use crate::xor_linked_list::XorLinkedList;
313pub use memoffset::offset_of;
314
315/// An endpoint of a range of keys.
316#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
317pub enum Bound<T> {
318    /// An inclusive bound.
319    Included(T),
320    /// An exclusive bound.
321    Excluded(T),
322    /// An infinite endpoint. Indicates that there is no bound in this direction.
323    Unbounded,
324}