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