MCPcopy Index your code
hub / github.com/bluurryy/bump-scope

github.com/bluurryy/bump-scope @v2.3.1

Chat with this repo
repository ↗ · DeepWiki ↗ · release v2.3.1 ↗ · + Follow
3,008 symbols 8,529 edges 210 files 237 documented · 8%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

bump-scope

Crates.io Documentation Changelog Rust License Build Status

A fast bump allocator that supports allocation scopes / checkpoints. Aka an arena for values of arbitrary types.

Table of Contents

What is bump allocation?

A bump allocator owns a big chunk of memory. It has a pointer that starts at one end of that chunk. When an allocation is made that pointer gets aligned and bumped towards the other end of the chunk. When its chunk is full, this allocator allocates another chunk with twice the size.

This makes allocations very fast. The drawback is that you can't reclaim memory like you do with a more general allocator. Memory for the most recent allocation can be reclaimed. You can also use scopes, checkpoints and reset to reclaim memory.

A bump allocator is great for phase-oriented allocations where you allocate objects in a loop and free them at the end of every iteration.

use bump_scope::Bump;
let mut bump: Bump = Bump::new();

loop {
    // use bump ...
    bump.reset();
}

The fact that the bump allocator allocates ever larger chunks and reset only keeps around the largest one means that after a few iterations, every bump allocation will be done on the same chunk and no more chunks need to be allocated.

The introduction of scopes makes this bump allocator also great for temporary allocations and stack-like usage.

Comparison to bumpalo

Bumpalo is a popular crate for bump allocation. This crate was inspired by bumpalo and Always Bump Downwards (but ignores the title).

Unlike bumpalo, this crate... - Supports scopes and checkpoints. - Drop is always called for allocated values unless explicitly leaked or forgotten. - alloc* methods return a BumpBox<T> which owns and drops T. Types that don't need dropping can be turned into references with into_ref and into_mut. - You can allocate a slice from any Iterator with alloc_iter. - Bump's base allocator is generic. - Won't try to allocate a smaller chunk if allocation failed. - No built-in allocation limit. You can provide an allocator that enforces an allocation limit (see examples/limit_memory_usage.rs). - Allocations are a tiny bit more optimized. See [./crates/callgrind-benches][benches]. - You can choose the bump direction. Bumps upwards by default.

Allocator Methods

The bump allocator provides many methods to conveniently allocate values, strings, and slices. Have a look at the documentation of [Bump] for a method overview.

Scopes and Checkpoints

You can create scopes to make allocations that live only for a part of its parent scope. Entering and exiting scopes is virtually free. Allocating within a scope has no overhead.

You can create a new scope either with a scoped closure or with a scope_guard:

use bump_scope::Bump;

let mut bump: Bump = Bump::new();

// you can use a closure
bump.scoped(|mut bump| {
    let hello = bump.alloc_str("hello");
    assert_eq!(bump.stats().allocated(), 5);

    bump.scoped(|bump| {
        let world = bump.alloc_str("world");

        println!("{hello} and {world} are both live");
        assert_eq!(bump.stats().allocated(), 10);
    });

    println!("{hello} is still live");
    assert_eq!(bump.stats().allocated(), 5);
});

assert_eq!(bump.stats().allocated(), 0);

// or you can use scope guards
{
    let mut guard = bump.scope_guard();
    let mut bump = guard.scope();

    let hello = bump.alloc_str("hello");
    assert_eq!(bump.stats().allocated(), 5);

    {
        let mut guard = bump.scope_guard();
        let bump = guard.scope();

        let world = bump.alloc_str("world");

        println!("{hello} and {world} are both live");
        assert_eq!(bump.stats().allocated(), 10);
    }

    println!("{hello} is still live");
    assert_eq!(bump.stats().allocated(), 5);
}

assert_eq!(bump.stats().allocated(), 0);

You can also use the unsafe checkpoint api to reset the bump pointer to a previous position.

let bump: Bump = Bump::new();
let checkpoint = bump.checkpoint();

{
    let hello = bump.alloc_str("hello");
    assert_eq!(bump.stats().allocated(), 5);
}

unsafe { bump.reset_to(checkpoint); }
assert_eq!(bump.stats().allocated(), 0);

When using a Bump(Scope) as an allocator for collections you will find that you can no longer call scoped or scope_guard because those functions require &mut self which does not allow any outstanding references to the allocator.

As a workaround you can use the [claim] method on a &Bump(Scope) to return a BumpClaimGuard which mutably dereferences to a BumpScope, allowing you to call .scoped() and .scope_guard().

A bump.claim() call replaces the allocator referred to by bump with a dummy allocator while the returned BumpClaimGuard is live. This dummy allocator errors on allocate / grow, does nothing on deallocate / shrink and reports an empty bump allocator from the stats api.

This makes it possible to enter scopes while a there are still outstanding references to that bump allocator:

let bump: Bump = Bump::new();
let mut vec: Vec<u8, &Bump> = Vec::new_in(&bump);

bump.claim().scoped(|bump_scope| {
    // you can allocate in the scope as usual
    let mut vec2: Vec<u8, &BumpScope> = Vec::new_in(bump_scope);
    vec2.reserve(456);

    // allocating on the `bump` outside the scope will fail
    assert!(vec.try_reserve(123).is_err());
});

// now allocating on `bump` is possible again
vec.reserve(123);

Collections

bump-scope provides bump allocated versions of Vec and String called [BumpVec] and [BumpString]. They are also available in the following variants: - Fixed* for fixed capacity collections - Mut* for collections optimized for a mutable bump allocator

API changes

The collections are designed to have the same api as their std counterparts with these exceptions: - split_off — splits the collection in place without allocation; the parameter is a range instead of a single index - retain — takes a closure with a &mut T parameter like Vec::retain_mut

New features
  • append — allows appending all kinds of owned slice types like [T; N], Box<[T]>, Vec<T>, vec::Drain<T> etc.
  • map — maps the elements, potentially reusing the existing allocation
  • map_in_place — maps the elements without allocation, failing to compile if not possible
  • conversions between the regular collections, their Fixed* variants and BumpBox<[T]> / BumpBox<str>

Parallel Allocation

[Bump] is !Sync which means it can't be shared between threads.

To bump allocate in parallel you can use a [BumpPool].

Allocator API

Bump and BumpScope implement bump-scope's own [Allocator] trait and with the respective feature flags also implement allocator_api2 version 0.2, 0.3, 0.4 and nightly's Allocator trait.

This allows you to bump allocate collections.

A bump allocator can grow, shrink and deallocate the most recent allocation. When bumping upwards it can even do so in place. Growing allocations other than the most recent one will require a new allocation and the old memory block becomes wasted space. Shrinking or deallocating allocations other than the most recent one does nothing, which means wasted space.

A bump allocator does not require deallocate or shrink to free memory. After all, memory will be reclaimed when exiting a scope, calling reset or dropping the Bump. You can set the DEALLOCATES and SHRINKS parameters to false or use the [WithoutDealloc] and [WithoutShrink] wrappers to make deallocating and shrinking a no-op.

Feature Flags

  • std (enabled by default) — Adds BumpPool and implementations of std::io traits.
  • alloc (enabled by default) — Adds Global as the default base allocator and some interactions with alloc collections.
  • panic-on-alloc (enabled by default) — Adds functions and traits that will panic when allocations fail. Without this feature, allocation failures cannot cause panics, and only try_-prefixed allocation methods will be available.
  • serde — Adds Serialize implementations for BumpBox, strings and vectors, and DeserializeSeed for strings and vectors.
  • bytemuck — Adds bytemuck::* extension traits for alloc_zeroed(_slice), init_zeroed, extend_zeroed and resize_zeroed.
  • zerocopy-08 — Adds zerocopy_08::* extension traits for alloc_zeroed(_slice), init_zeroed, extend_zeroed and resize_zeroed.
  • allocator-api2-02 — Makes Bump(Scope) implement allocator_api2 version 0.2's Allocator and makes it possible to use an allocator_api2::alloc::Allocator as a base allocator via AllocatorApi2V02Compat.
  • allocator-api2-03 — Makes Bump(Scope) implement allocator_api2 version 0.3's Allocator and makes it possible to use an allocator_api2::alloc::Allocator as a base allocator via AllocatorApi2V03Compat.
  • allocator-api2-04 — Makes Bump(Scope) implement allocator_api2 version 0.4's Allocator and makes it possible to use an allocator_api2::alloc::Allocator as a base allocator via AllocatorApi2V04Compat.

Nightly features

These nightly features are not subject to the same semver guarantees as the rest of the library. Breaking changes to these features might be introduced in minor releases to keep up with changes in the nightly channel.

  • nightly — Enables all other nightly feature flags.
  • nightly-allocator-api — Makes Bump(Scope) implement alloc's Allocator and allows using an core::alloc::Allocator as a base allocator via AllocatorNightlyCompat.

Thi

Extension points exported contracts — how you extend this code

NoDrop (Interface)
This trait marks types that don't need dropping. This trait is a best effort for modeling such a constraint. It is not [10 …
src/no_drop.rs
TakeOwnedSlice (Interface)
A trait for objects which own a slice and can relinquish their ownership of all its elements at once. Implementors of t [13 …
src/owned_slice.rs
Allocator (Interface)
An implementation of `Allocator` can allocate, grow, shrink, and deallocate arbitrary blocks of data described via [`Lay [22 …
src/alloc.rs
BumpAllocatorCoreScope (Interface)
A bump allocator scope. This is a [`BumpAllocatorCore`] which can make allocations that outlive itself. Specifically, i [7 …
src/traits/bump_allocator_core_scope.rs
BaseAllocator (Interface)
Trait that the base allocator of a `Bump` is required to implement to make allocations. Every [`Allocator`] that implem [2 …
src/lib.rs
Append (Interface)
(no doc) [4 implementers]
tests/append.rs
LayoutProps (Interface)
(no doc) [3 implementers]
src/layout.rs
ErrorBehavior (Interface)
(no doc) [2 implementers]
src/error_behavior.rs

Core symbols most depended-on inside this repo

new
called by 540
tests/bump_vec_doc.rs
add
called by 169
src/bump_string.rs
push
called by 155
crates/fuzzing-support/src/bump_vec.rs
panic_on_error
called by 138
src/lib.rs
new_in
called by 133
tests/other.rs
get
called by 125
src/bump_pool.rs
size
called by 110
src/stats.rs
write_str
called by 103
src/bump_string.rs

Shape

Method 1,645
Function 1,088
Class 212
Interface 40
Enum 23

Languages

Rust100%

Modules by API surface

crates/tests-from-std/src/mut_bump_vec.rs181 symbols
crates/tests-from-std/src/bump_vec.rs181 symbols
crates/tests-from-std/src/mut_bump_vec_rev.rs176 symbols
src/bump_vec.rs137 symbols
src/bump_box.rs136 symbols
src/mut_bump_vec.rs120 symbols
src/mut_bump_vec_rev.rs114 symbols
src/fixed_bump_vec.rs114 symbols
src/bump_string.rs105 symbols
src/mut_bump_string.rs95 symbols
src/fixed_bump_string.rs81 symbols
tests/other.rs79 symbols

For agents

$ claude mcp add bump-scope \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact

Ask about this repo answers extend the page