fixed_bump/lib.rs
1/*
2 * Copyright (C) 2021-2022 taylor.fish <contact@taylor.fish>
3 *
4 * This file is part of fixed-bump.
5 *
6 * fixed-bump is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * fixed-bump is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with fixed-bump. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#![no_std]
21#![cfg_attr(has_allocator_api, feature(allocator_api))]
22#![cfg_attr(feature = "doc_cfg", feature(doc_cfg))]
23#![deny(unsafe_op_in_unsafe_fn)]
24#![warn(clippy::pedantic)]
25#![allow(clippy::default_trait_access)]
26#![allow(clippy::doc_markdown)]
27#![allow(clippy::module_name_repetitions)]
28#![allow(clippy::must_use_candidate)]
29
30//! A bump allocator (like [bumpalo]) that internally uses fixed-size chunks
31//! of memory.
32//!
33//! Other bump allocators, like [bumpalo], are optimized for throughput: they
34//! allocate chunks of memory with exponentially increasing sizes, which
35//! results in *amortized* constant-time allocations.
36//!
37//! [bumpalo]: https://docs.rs/bumpalo
38//!
39//! **fixed-bump** is optimized for latency: it internally allocates chunks of
40//! memory with a fixed, configurable size, and individual value allocations
41//! are performed in non-amortized constant time. However, a trade-off with
42//! using this crate is that it may not be able to allocate certain types or
43//! memory layouts if the specified chunk size or alignment is too small. See
44//! [`Bump::allocate`] for the conditions under which allocation may fail.
45//!
46//! This crate depends only on [`core`] and [`alloc`], so it can be used in
47//! `no_std` environments that support [`alloc`].
48//!
49//! [`core`]: https://doc.rust-lang.org/core/
50//! [`alloc`]: https://doc.rust-lang.org/alloc/
51//!
52//! Example
53//! -------
54//!
55//! ```rust
56//! # #![cfg_attr(feature = "allocator_api", feature(allocator_api))]
57//! use fixed_bump::Bump;
58//! struct Item(u64);
59//!
60//! // Use chunks large and aligned enough to hold 128 `Item`s.
61//! let bump = Bump::<[Item; 128]>::new();
62//! let item1: &mut Item = bump.alloc_value(Item(1));
63//! let item2: &mut Item = bump.alloc_value(Item(2));
64//! item1.0 += item2.0;
65//!
66//! assert_eq!(item1.0, 3);
67//! assert_eq!(item2.0, 2);
68//!
69//! // Can also allocate different types:
70//! let array: &mut [u8; 8] = bump.alloc_value([0, 1, 2, 3, 4, 5, 6, 7]);
71//! assert_eq!(array.iter().sum::<u8>(), 28);
72//!
73//! // Can also use `&Bump` as an `Allocator` (requires "allocator_api"):
74//! # #[cfg(feature = "allocator_api")]
75//! # {
76//! # extern crate alloc;
77//! # use alloc::vec::Vec;
78//! // To avoid resizing, we create these `Vec`s with the maximum capacity
79//! // we want them ever to have. Resizing would waste memory, since bump
80//! // allocators don't reclaim or reuse memory until the entire allocator
81//! // is dropped.
82//! let mut vec1: Vec<u32, _> = Vec::with_capacity_in(8, &bump);
83//! let mut vec2: Vec<u32, _> = Vec::with_capacity_in(4, &bump);
84//! for i in 0..4 {
85//! vec1.push(i * 2);
86//! vec1.push(i * 2 + 1);
87//! vec2.push(i * 2);
88//! }
89//!
90//! assert_eq!(vec1, [0, 1, 2, 3, 4, 5, 6, 7]);
91//! assert_eq!(vec2, [0, 2, 4, 6]);
92//! # }
93//! ```
94//!
95//! Dropping
96//! --------
97//!
98//! [`Bump`] can either return raw memory (see [`Bump::allocate`]) or allocate
99//! a value of a specific type and return a reference (see
100//! [`Bump::alloc_value`] and [`Bump::try_alloc_value`]). In the latter case
101//! where references are returned, note that destructors will not be
102//! automatically run. If this is an issue, you can do one of the following:
103//!
104//! * Drop those values manually with [`ptr::drop_in_place`].
105//! * Enable the `allocator_api` feature, which lets you use bump allocators
106//! with various data structures like [`Box`] and [`Vec`]. Note that this
107//! requires Rust nightly.
108//!
109//! Note that, as with other bump allocators, the memory used by an allocated
110//! object will not be reclaimed or reused until the entire bump allocator
111//! is dropped.
112//!
113//! Crate features
114//! --------------
115//!
116//! If the crate feature `allocator_api` is enabled, the unstable [`Allocator`]
117//! trait will be implemented for `T`, `&T`, and [`crate::Rc<T>`], where `T` is
118//! [`Bump`] or [`DynamicBump`]. This lets you use those types as allocators
119//! for various data structures like [`Box`] and [`Vec`]. Note that this
120//! feature requires Rust nightly. Alternatively, if the feature
121//! `allocator-fallback` is enabled, this crate will use the allocator API
122//! provided by [allocator-fallback] instead of the standard library’s.
123//!
124//! [allocator-fallback]: https://docs.rs/allocator-fallback
125//!
126//! [`ptr::drop_in_place`]: core::ptr::drop_in_place
127//! [`Box`]: alloc::boxed::Box
128//! [`Vec`]: alloc::vec::Vec
129//! [`Allocator`]: alloc::alloc::Allocator
130
131#[cfg(feature = "allocator_api")]
132use alloc::alloc::{AllocError, Allocator};
133
134#[cfg(not(feature = "allocator_api"))]
135#[cfg(feature = "allocator-fallback")]
136use allocator_fallback::{AllocError, Allocator};
137
138extern crate alloc;
139
140mod bump;
141mod chunk;
142mod dynamic;
143mod generic;
144mod inner;
145mod rc;
146#[cfg(test)]
147mod tests;
148
149pub use bump::Bump;
150pub use dynamic::DynamicBump;
151pub use rc::Rc;
152#[allow(deprecated)]
153pub use rc::RcBump;