1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/*
 * Copyright (C) 2021 taylor.fish <contact@taylor.fish>
 *
 * This file is part of fixed-bump.
 *
 * fixed-bump is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * fixed-bump is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with fixed-bump. If not, see <https://www.gnu.org/licenses/>.
 */

#![no_std]
#![cfg_attr(feature = "allocator_api", feature(allocator_api))]
#![cfg_attr(not(feature = "unstable"), allow(unused_unsafe))]
#![cfg_attr(
    feature = "unstable",
    feature(unsafe_block_in_unsafe_fn),
    deny(unsafe_op_in_unsafe_fn)
)]
#![warn(clippy::pedantic)]
#![allow(clippy::default_trait_access)]
#![allow(clippy::module_name_repetitions)]
#![allow(clippy::must_use_candidate)]

//! A bump allocator (like [bumpalo]) that internally uses fixed-size chunks
//! of memory.
//!
//! Other bump allocators, like [bumpalo], are optimized for throughput: they
//! allocate chunks of memory with exponentially increasing sizes, which
//! results in *amortized* constant-time allocations.
//!
//! [bumpalo]: https://docs.rs/bumpalo
//!
//! **fixed-bump** is optimized for latency: it internally allocates chunks of
//! memory with a fixed, configurable size, and individual value allocations
//! are performed in non-amortized constant time. However, a trade-off with
//! using this crate is that it may not be able to allocate certain types or
//! memory layouts if the specified chunk size or alignment is too small. See
//! [`Bump::allocate`] for the conditions under which allocation may fail.
//!
//! This crate depends only on [`core`] and [`alloc`], so it can be used in
//! `no_std` environments that support [`alloc`].
//!
//! [`core`]: https://doc.rust-lang.org/core/
//! [`alloc`]: https://doc.rust-lang.org/alloc/
//!
//! Example
//! -------
//!
//! ```rust
//! # #![cfg_attr(feature = "allocator_api", feature(allocator_api))]
//! use fixed_bump::Bump;
//! struct Item(u64);
//!
//! // Use chunks large and aligned enough to hold 128 `Item`s.
//! let bump = Bump::<[Item; 128]>::new();
//! let item1: &mut Item = bump.alloc_value(Item(1));
//! let item2: &mut Item = bump.alloc_value(Item(2));
//! item1.0 += item2.0;
//!
//! assert_eq!(item1.0, 3);
//! assert_eq!(item2.0, 2);
//!
//! // Can also allocate different types:
//! let array: &mut [u8; 8] = bump.alloc_value([0, 1, 2, 3, 4, 5, 6, 7]);
//! assert_eq!(array.iter().sum::<u8>(), 28);
//!
//! // Can also use `&Bump` as an `Allocator` (requires "allocator_api"):
//! # #[cfg(feature = "allocator_api")]
//! # {
//! # extern crate alloc;
//! # use alloc::vec::Vec;
//! // To avoid resizing, we create these `Vec`s with the maximum capacity
//! // we want them ever to have. Resizing would waste memory, since bump
//! // allocators don't reclaim or reuse memory until the entire allocator
//! // is dropped.
//! let mut vec1: Vec<u32, _> = Vec::with_capacity_in(8, &bump);
//! let mut vec2: Vec<u32, _> = Vec::with_capacity_in(4, &bump);
//! for i in 0..4 {
//!     vec1.push(i * 2);
//!     vec1.push(i * 2 + 1);
//!     vec2.push(i * 2);
//! }
//!
//! assert_eq!(vec1, [0, 1, 2, 3, 4, 5, 6, 7]);
//! assert_eq!(vec2, [0, 2, 4, 6]);
//! # }
//! ```
//!
//! Dropping
//! --------
//!
//! [`Bump`] can either return raw memory (see [`Bump::allocate`]) or allocate
//! a value of a specific type and return a reference (see
//! [`Bump::alloc_value`] and [`Bump::try_alloc_value`]). In the latter case
//! where references are returned, note that destructors will not be
//! automatically run. If this is an issue, you can do one of the following:
//!
//! * Drop those values manually with [`ptr::drop_in_place`].
//! * Enable the `"allocator_api"` feature, which lets you use [`Bump`],
//!   `&Bump`, and [`RcBump`] as allocators for various data structures like
//!   [`Box`] and [`Vec`]. Note that this requires Rust nightly.
//!
//! Note that, as with other bump allocators, the memory used by an allocated
//! object will not be reclaimed or reused until the entire bump allocator
//! is dropped.
//!
//! Crate features
//! --------------
//!
//! If the crate feature `"allocator_api"` is enabled, [`Bump`], `&Bump` (due
//! to the impl of [`Allocator`] for all `&A` where `A: Allocator`), and
//! [`RcBump`] will implement the unstable [`Allocator`] trait. This lets you
//! use those types as allocators for various data structures like [`Box`] and
//! [`Vec`]. Note that this feature requires Rust nightly.
//!
//! [`ptr::drop_in_place`]: core::ptr::drop_in_place
//! [`Box`]: alloc::boxed::Box
//! [`Vec`]: alloc::vec::Vec
//! [`Allocator`]: alloc::alloc::Allocator

extern crate alloc;

mod bump;
mod chunk;
mod inner;
mod rc;
#[cfg(test)]
mod tests;

pub use bump::Bump;
pub use rc::RcBump;