{"id":13671620,"url":"https://github.com/zakarumych/blink-alloc","last_synced_at":"2025-04-06T19:13:04.851Z","repository":{"id":89338513,"uuid":"591602365","full_name":"zakarumych/blink-alloc","owner":"zakarumych","description":"Fast, concurrent, arena-based allocator with drop support","archived":false,"fork":false,"pushed_at":"2024-03-03T10:52:30.000Z","size":144,"stargazers_count":125,"open_issues_count":0,"forks_count":3,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-03-30T17:11:18.317Z","etag":null,"topics":["allocator","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zakarumych.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"COPYING","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-01-21T08:39:28.000Z","updated_at":"2025-03-25T11:22:17.000Z","dependencies_parsed_at":"2024-03-03T11:47:00.612Z","dependency_job_id":null,"html_url":"https://github.com/zakarumych/blink-alloc","commit_stats":{"total_commits":43,"total_committers":2,"mean_commits":21.5,"dds":"0.023255813953488413","last_synced_commit":"06de89690c7d15bb5748ad187b47974e0359cf24"},"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zakarumych%2Fblink-alloc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zakarumych%2Fblink-alloc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zakarumych%2Fblink-alloc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zakarumych%2Fblink-alloc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zakarumych","download_url":"https://codeload.github.com/zakarumych/blink-alloc/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247535519,"owners_count":20954576,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["allocator","rust"],"created_at":"2024-08-02T09:01:14.642Z","updated_at":"2025-04-06T19:13:04.828Z","avatar_url":"https://github.com/zakarumych.png","language":"Rust","funding_links":[],"categories":["Rust"],"sub_categories":[],"readme":"# blink-alloc\n\n[![crates](https://img.shields.io/crates/v/blink-alloc.svg?style=for-the-badge\u0026label=blink-alloc)](https://crates.io/crates/blink-alloc)\n[![docs](https://img.shields.io/badge/docs.rs-blink--alloc-66c2a5?style=for-the-badge\u0026labelColor=555555\u0026logoColor=white)](https://docs.rs/blink-alloc)\n[![actions](https://img.shields.io/github/actions/workflow/status/zakarumych/blink-alloc/badge.yml?branch=main\u0026style=for-the-badge)](https://github.com/zakarumych/blink-alloc/actions/workflows/badge.yml)\n[![MIT/Apache](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?style=for-the-badge)](./COPYING)\n![loc](https://img.shields.io/tokei/lines/github/zakarumych/blink-alloc?style=for-the-badge)\n\nBlink-alloc is [extremely fast](./BENCHMARKS.md) allocator based on the common idea of\nallocating linearly zipping a cursor through memory chunk and\nreset everything at once by setting cursor back to start.\n\nWith Rust's borrow checker this idea can be implemented safely,\npreventing resets to occur while allocated memory is in use.\n\n### [Jump to examples](#examples)\n\n# Design\n\nThe blink-allocator acts as an adaptor to some lower-level allocator.\nGrabs chunks of memory from underlying allocator\nand serves allocations from them.\nWhen chunk is exhausted blink-allocator requests new larger chunk of memory\nfrom lower-level allocator.\n\nOn reset all but last chunks are returned back to underlying allocator.\nThe goal is to allocate a single chunk large enough to serve all allocations\nbetween resets, so that lower-level allocator is not touched after\ninitial warm-up phase. Making allocations and resets almost free.\n\nThe way blink-allocators are implemented offers cheap allocation shrinks when\nnew layout fits into currently allocated memory block.\nWhich is certainly the case for things like [`Vec::shrink_to`] and [`Vec::shrink_to_fit`].\nWhen done on the tip of allocation it also frees the memory for reuse.\n\nAdditionally fast allocation grows is possible when done on the tip of allocation.\nWhich is easy to control when using thread-local version.\nThis opens a way for blazing fast [`Vec::push`] call even at full [`Vec`] capacity.\n\nThe simple implementation uses unsynchronized interior mutability\nand thus only works in single-thread scenario.\nIt can be send to another thread but not shared.\n\nMaintaining an instance per thread is one way to tackle this problem.\nYet not always possible or desireable.\n\nThis crate provides additional implementation for multi-threaded\nscenario with slight performance penalty. To negate it, a local copy\nof single-threaded blink-allocator can be created to take memory from\nshared multi-threaded blink-allocator, allowing reusing memory across threads\nwhile keeping blazing fast allocations of single-threaded version.\nIt works best for fork-join type of parallelism since it requires\na point where the multi-threaded blink-allocator is not shared\nto reset it.\n\nFor task-based parallelism a cache of blink-allocators\ncan be constructed.\nTask may borrow single-threaded blink-allocator and return it when its done.\nThis will keep cache full of pre-warmed blink-allocators.\n\n# Single-threaded\n\n[`BlinkAlloc`] is a single-threaded version of the allocator.\nIt uses unsynchronized interior mutability for fastest performance.\n[`BlinkAlloc`] can be sent to other threads but not shared.\n\nFor multi-threading an instance of [`BlinkAlloc`] per thread/task\ncan be created.\nThough it may be not possible or practical in some ways, so consider\nalternatives below.\n\n# Multi-threaded\n\n[`SyncBlinkAlloc`] works in multithreaded environment and shares memory\nfrom one chunk between threads. Reduces overall memory usage,\nskips warm-up phase for new threads and tasks.\n[`SyncBlinkAlloc`] can spawn [`LocalBlinkAlloc`] instances\nthat work similarly to [`BlinkAlloc`].\n[`LocalBlinkAlloc`] instances fetch memory chunks from shared [`SyncBlinkAlloc`].\n[`SyncBlinkAlloc`] still requires exclusive access to reset.\nWorks best for fork-join style of parallelism, where reset happens\nafter joining all threads.\n\nFor task/based parallelism this crate provides [`BlinkAllocCache`] type\nwhich is a cache of [`BlinkAlloc`] instances.\nTasks may fetch blink allocator from cache,\nuse it and then return it back to cache.\nCache keeps [`BlinkAlloc`] instances warmed up.\n\n# Allocator API\n\nAllocators implement [`Allocator`] interface from [`alloc`] crate\nor a copy of it when feature `\"nightly\"` is not enabled.\n`\"nightly\"` requires Rust feature [`allocator_api`]\nand works only on nightly.\nOnce [`Allocator`] trait is stable the feature will do nothing and\nremoved in next major release.\n\n# Blink without collections\n\n[`BlinkAlloc`] and friends implement [`Allocator`] from [`allocator_api`]\nunstable feature. It is only available when `\"nightly\"` feature is enabled\nfor this crate. Otherwise [`Allocator`] is not [`core::alloc::Allocator`]\nbut a duplicate defined in the crate.\nWith [`allocator_api`] it is possible to use [`BlinkAlloc`] and others\nfor allocator type in collection types that support one.\nCurrently [`Vec`], [`VecDeque`], [`BTreeMap`] and [`BTreeSet`] can use\nuser-provided allocator.\nAlso [`hashbrown::HashMap`] and [`hashbrown::HashSet`] support it with\n`\"nightly\"` feature.\n\nHowever on stable it cannot be used right now.\n\nIt is still possible to use blink-allocators in safe manner -\nmeet [`Blink`] allocator adaptor.\nPut anything into memory allocated by [`Blink`].\nValues, iterators, closures to construct a value,\nslices and strings.\nIt works with everything*.\nUses underlying blink-allocator and returns mutable reference\nto values placed into allocated memory.\nBy default it drops placed values on reset.\n\n\\* Ask for API extension if doesn't work for your use case.\n\n# Examples\n\nUsage of [`Blink`] allocator adaptor.\nInitialize and start putting values there.\n\n```rust\nuse blink_alloc::Blink;\n\n#[cfg(feature = \"alloc\")]\nfn main() {\n    // `Blink::new` uses `BlinkAlloc\u003cGlobal\u003e`\n    let mut blink = Blink::new();\n\n    // Allocates memory and moves value there.\n    // Returns mutable reference to it.\n    let x = blink.put(42);\n    assert_eq!(*x, 42);\n    *x = 11;\n\n    // Copies string slice to the blink-allocated memory.\n    let string = blink.copy_str(\"Hello world\");\n\n    // Mutable reference allows string mutation\n    string.make_ascii_lowercase();\n    assert_eq!(string, \"hello world\");\n\n    // Consumes iterator and returns all values from it in slice.\n    // Works fine on problematic iterators with terrible size hint.\n    let slice = blink.emplace().from_iter((0..10).filter(|x| x % 3 != 0));\n    assert_eq!(\u0026*slice, \u0026[1, 2, 4, 5, 7, 8]);\n    blink.reset();\n}\n#[cfg(not(feature = \"alloc\"))] fn main() {}\n```\n\n```rust\n#![cfg_attr(feature = \"nightly\", feature(allocator_api))]\nuse blink_alloc::BlinkAlloc;\n\n#[cfg(feature = \"alloc\")]\nfn main() {\n    use allocator_api2::vec::Vec;\n\n    let mut blink = BlinkAlloc::new();\n    let mut vec = Vec::new_in(\u0026blink);\n    vec.extend((1..10).map(|x| x * 3 - 2));\n\n    drop(vec);\n    blink.reset();\n}\n#[cfg(not(feature = \"alloc\"))] fn main() {}\n```\n\n# No-std\n\nThis crate supports `no_std` environment.\n`\"alloc\"` feature is enabled by default and adds\ndependency on [`alloc`] crate.\n\n## License\n\nLicensed under either of\n\n* Apache License, Version 2.0, ([license/APACHE](license/APACHE) or \u003chttp://www.apache.org/licenses/LICENSE-2.0\u003e)\n* MIT license ([license/MIT](license/MIT) or \u003chttp://opensource.org/licenses/MIT\u003e)\n\nat your option.\n\n## Contributions\n\nUnless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.\n\n[`Vec::shrink_to`]: https://doc.rust-lang.org/alloc/vec/struct.Vec.html#method.shrink_to\n[`Vec::shrink_to_fit`]: https://doc.rust-lang.org/alloc/vec/struct.Vec.html#method.shrink_to_fit\n[`Vec::push`]: https://doc.rust-lang.org/alloc/vec/struct.Vec.html#method.push\n[`Vec`]: https://doc.rust-lang.org/alloc/vec/struct.Vec.html\n[`BlinkAlloc`]: https://docs.rs/blink-alloc/latest/blink_alloc/struct.BlinkAlloc.html\n[`SyncBlinkAlloc`]: https://docs.rs/blink-alloc/latest/blink_alloc/struct.SyncBlinkAlloc.html\n[`LocalBlinkAlloc`]: https://docs.rs/blink-alloc/latest/blink_alloc/struct.LocalBlinkAlloc.html\n[`BlinkAllocCache`]: https://docs.rs/blink-alloc/latest/blink_alloc/struct.BlinkAllocCache.html\n[`Blink`]: https://docs.rs/blink-alloc/latest/blink_alloc/struct.Blink.html\n[`Allocator`]: https://docs.rs/allocator-api2/latest/allocator_api2/\n[`allocator_api`]: https://doc.rust-lang.org/beta/unstable-book/library-features/allocator-api.html\n[`core::alloc::Allocator`]: https://doc.rust-lang.org/core/alloc/trait.Allocator.html\n[`Vec`]: https://doc.rust-lang.org/alloc/vec/struct.Vec.html\n[`VecDeque`]: https://doc.rust-lang.org/alloc/collections/vec_deque/struct.VecDeque.html\n[`BTreeMap`]: https://doc.rust-lang.org/alloc/collections/btree_map/struct.BTreeMap.html\n[`BTreeSet`]: https://doc.rust-lang.org/alloc/collections/btree_set/struct.BTreeSet.html\n[`hashbrown::HashMap`]: https://docs.rs/hashbrown/latest/hashbrown/hash_map/struct.HashMap.html\n[`hashbrown::HashSet`]: https://docs.rs/hashbrown/latest/hashbrown/hash_set/struct.HashSet.html\n[`alloc`]: https://doc.rust-lang.org/alloc/index.html\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzakarumych%2Fblink-alloc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzakarumych%2Fblink-alloc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzakarumych%2Fblink-alloc/lists"}