From f0328d687a4e9eace1a57a7ad38bb37a8f9634c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tin=20=C5=A0vagelj?= Date: Wed, 6 Nov 2024 19:14:01 +0100 Subject: [PATCH] Improve tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Cleanup documentation. - Fix some minor bugs. Signed-off-by: Tin Švagelj --- .idea/.gitignore | 8 - .idea/codeStyles/codeStyleConfig.xml | 5 - .idea/contiguous_mem.iml | 12 -- .idea/modules.xml | 8 - .idea/vcs.xml | 6 - .vscode/launch.json | 249 --------------------- Cargo.toml | 4 +- LICENSE_MIT | 2 +- LICENSE_ZLIB | 2 +- README.md | 72 +++---- build.rs | 3 + doc/crate.md | 7 +- doc/layout.png | Bin 0 -> 32317 bytes doc/layout.svg | 312 +++++++++++++++++++++++++++ doc/layout.typ | 83 +++++++ examples/default_impl.rs | 2 +- examples/game_loading.rs | 2 +- examples/unsafe_impl.rs | 2 +- src/lib.rs | 270 ++++++++++++++++------- src/memory.rs | 78 ++++++- src/raw.rs | 3 - src/types.rs | 23 +- 22 files changed, 712 insertions(+), 441 deletions(-) delete mode 100644 .idea/.gitignore delete mode 100644 .idea/codeStyles/codeStyleConfig.xml delete mode 100644 .idea/contiguous_mem.iml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/vcs.xml delete mode 100644 .vscode/launch.json create mode 100644 doc/layout.png create mode 100644 doc/layout.svg create mode 100644 doc/layout.typ diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 13566b8..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Editor-based HTTP Client requests -/httpRequests/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml deleted file mode 100644 index a55e7a1..0000000 --- a/.idea/codeStyles/codeStyleConfig.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/contiguous_mem.iml b/.idea/contiguous_mem.iml deleted file mode 100644 index 7c12fe5..0000000 --- a/.idea/contiguous_mem.iml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index afaa2b5..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1dd..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 028b592..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,249 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "type": "lldb", - "request": "launch", - "name": "Debug unit tests in library 'contiguous-mem'", - "cargo": { - "args": [ - "test", - "--no-run", - "--lib", - "--package=contiguous-mem" - ], - "filter": { - "name": "contiguous-mem", - "kind": "lib" - } - }, - "args": [], - "cwd": "${workspaceFolder}" - }, - { - "type": "lldb", - "request": "launch", - "name": "Debug example 'ptr_metadata'", - "cargo": { - "args": [ - "build", - "--example=ptr_metadata", - "--package=contiguous-mem" - ], - "filter": { - "name": "ptr_metadata", - "kind": "example" - } - }, - "args": [], - "cwd": "${workspaceFolder}" - }, - { - "type": "lldb", - "request": "launch", - "name": "Debug unit tests in example 'ptr_metadata'", - "cargo": { - "args": [ - "test", - "--no-run", - "--example=ptr_metadata", - "--package=contiguous-mem" - ], - "filter": { - "name": "ptr_metadata", - "kind": "example" - } - }, - "args": [], - "cwd": "${workspaceFolder}" - }, - { - "type": "lldb", - "request": "launch", - "name": "Debug example 'failing'", - "cargo": { - "args": [ - "build", - "--example=failing", - "--package=contiguous-mem" - ], - "filter": { - "name": "failing", - "kind": "example" - } - }, - "args": [], - "cwd": "${workspaceFolder}" - }, - { - "type": "lldb", - "request": "launch", - "name": "Debug unit tests in example 'failing'", - "cargo": { - "args": [ - "test", - "--no-run", - "--example=failing", - "--package=contiguous-mem" - ], - "filter": { - "name": "failing", - "kind": "example" - } - }, - "args": [], - "cwd": "${workspaceFolder}" - }, - { - "type": "lldb", - "request": "launch", - "name": "Debug example 'default_impl'", - "cargo": { - "args": [ - "build", - "--example=default_impl", - "--package=contiguous-mem" - ], - "filter": { - "name": "default_impl", - "kind": "example" - } - }, - "args": [], - "cwd": "${workspaceFolder}" - }, - { - "type": "lldb", - "request": "launch", - "name": "Debug unit tests in example 'default_impl'", - "cargo": { - "args": [ - "test", - "--no-run", - "--example=default_impl", - "--package=contiguous-mem" - ], - "filter": { - "name": "default_impl", - "kind": "example" - } - }, - "args": [], - "cwd": "${workspaceFolder}" - }, - { - "type": "lldb", - "request": "launch", - "name": "Debug example 'game_loading'", - "cargo": { - "args": [ - "build", - "--example=game_loading", - "--package=contiguous-mem" - ], - "filter": { - "name": "game_loading", - "kind": "example" - } - }, - "args": [], - "cwd": "${workspaceFolder}" - }, - { - "type": "lldb", - "request": "launch", - "name": "Debug unit tests in example 'game_loading'", - "cargo": { - "args": [ - "test", - "--no-run", - "--example=game_loading", - "--package=contiguous-mem" - ], - "filter": { - "name": "game_loading", - "kind": "example" - } - }, - "args": [], - "cwd": "${workspaceFolder}" - }, - { - "type": "lldb", - "request": "launch", - "name": "Debug example 'sync_impl'", - "cargo": { - "args": [ - "build", - "--example=sync_impl", - "--package=contiguous-mem" - ], - "filter": { - "name": "sync_impl", - "kind": "example" - } - }, - "args": [], - "cwd": "${workspaceFolder}" - }, - { - "type": "lldb", - "request": "launch", - "name": "Debug unit tests in example 'sync_impl'", - "cargo": { - "args": [ - "test", - "--no-run", - "--example=sync_impl", - "--package=contiguous-mem" - ], - "filter": { - "name": "sync_impl", - "kind": "example" - } - }, - "args": [], - "cwd": "${workspaceFolder}" - }, - { - "type": "lldb", - "request": "launch", - "name": "Debug example 'unsafe_impl'", - "cargo": { - "args": [ - "build", - "--example=unsafe_impl", - "--package=contiguous-mem" - ], - "filter": { - "name": "unsafe_impl", - "kind": "example" - } - }, - "args": [], - "cwd": "${workspaceFolder}" - }, - { - "type": "lldb", - "request": "launch", - "name": "Debug unit tests in example 'unsafe_impl'", - "cargo": { - "args": [ - "test", - "--no-run", - "--example=unsafe_impl", - "--package=contiguous-mem" - ], - "filter": { - "name": "unsafe_impl", - "kind": "example" - } - }, - "args": [], - "cwd": "${workspaceFolder}" - } - ] -} \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 5c339ff..2482738 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "contiguous-mem" version = "0.5.0" edition = "2021" -description = "A contiguous memory storage" +description = "A contiguous memory container" authors = ["Tin Švagelj "] license = "MIT OR Apache-2.0 OR Zlib" keywords = ["memory", "contiguous", "storage", "container", "nostd"] @@ -42,7 +42,7 @@ allocator_api = [] sptr = "0.3.2" [dev-dependencies] -byteorder = "1.4" +byteorder = "1.5" [package.metadata.docs.rs] all-features = true diff --git a/LICENSE_MIT b/LICENSE_MIT index 7ff07df..e54032e 100644 --- a/LICENSE_MIT +++ b/LICENSE_MIT @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 Tin Švagelj +Copyright (c) 2024 Tin Švagelj Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/LICENSE_ZLIB b/LICENSE_ZLIB index c0afaab..4f094f2 100644 --- a/LICENSE_ZLIB +++ b/LICENSE_ZLIB @@ -1,4 +1,4 @@ -Copyright (c) 2023 Tin Švagelj +Copyright (c) 2024 Tin Švagelj This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/README.md b/README.md index c566764..b8e1c14 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,32 @@ # contiguous_mem -contiguous_mem is a vector like collection that can store entries with -heterogeneous layouts while retaining type information at the reference level. +contiguous_mem is space optimized a vector like collection that can store +entries of **varying layouts** **close in memory** while retaining type +information at the reference level. [![Crate](https://img.shields.io/crates/v/contiguous_mem?style=for-the-badge&logo=docs.rs)](https://crates.io/crates/contiguous_mem) [![Documentation](https://img.shields.io/docsrs/contiguous-mem?style=for-the-badge&logo=rust)](https://docs.rs/contiguous-mem) [![CI Status](https://img.shields.io/github/actions/workflow/status/Caellian/contiguous_mem/rust.yml?style=for-the-badge&logo=githubactions&logoColor=%23fff&label=CI)](https://github.com/Caellian/contiguous_mem/actions/workflows/rust.yml) [![Zlib or MIT or Apache 2.0 license](https://img.shields.io/crates/l/contiguous-mem?style=for-the-badge)](https://github.com/Caellian/contiguous_mem#license) -## Key Features +## Use Case -- `no_std` support! -- Simple and straightforward interface similar to standard containers. -- Support for dynamic resizing of allocated memory keeping the created - references functional (for safe implementations). - -### Specialized implementations - -This crate provides alternative implementations for: - -- thread-safe code: `SyncContiguousMemory` -- low level, unsafe code: `UnsafeContiguousMemory` +![quick preview showing layout advantage](./doc/layout.png)
+* Both Vec and ContiguousMemory have one +level of indirection that's not shown for sake of simplicity. -Default implementation (`ContiguousMemory`) and `SyncContiguousMemory` return -smart references with relative offsets of stored data, while the -`UnsafeContiguousMemory` returns raw pointers. +You need to store several different types and ensure their close proximity on +the heap to reduce cache misses, but which/how many is determined at runtime. -All implementations use a similar interface which makes it convenient to switch -over when your scope and requirements shift. +### Key Features -## Use cases - -- Storing differently typed/sized data. ([example](./examples/default_impl.rs)) -- Ensuring stored data is placed adjacently in memory. - ([example](./examples/game_loading.rs)) - - Note that returned references are **not** contiguous, only data they refer - to is. +- `no_std` support! +- Interface similar to `Vec`. +- Support for dynamic resizing of allocated memory while keeping the existing + references functional (for safe implementations). +- Exhaustively tested with Miri. +- No downstream dependencies. + - ...almost, only [sptr](https://crates.io/crates/sptr) is used to ensure safety. ## Getting Started @@ -64,8 +55,6 @@ contiguous_mem = { version = "0.5", features = ["no_std"] } environment - [`allocator_api`](https://dev-doc.rust-lang.org/stable/unstable-book/library-features/allocator-api.html) <_nightly_> - enables automatic support for custom allocators -- `sync_impl` (default) - enables `SyncContiguousMemory` and related error code - implementation - `unsafe_impl` (default) - enables `UnsafeContiguousMemory` ### Usage @@ -92,33 +81,29 @@ fn main() { assert_eq!(*stored_number.get(), 22); } ``` +* Note that reference types returned by store are inferred and only shown +here for demonstration purposes. -- References have a similar API as - [`RefCell`](https://doc.rust-lang.org/stable/std/cell/struct.RefCell.html) - -Note that reference types returned by store are inferred and only shown -here for demonstration purposes. +References have a similar API as [`RefCell`](https://doc.rust-lang.org/stable/std/cell/struct.RefCell.html). For more usage examples see the -[`examples`](https://github.com/Caellian/contiguous_mem/tree/trunk/examples) +[examples](https://github.com/Caellian/contiguous_mem/tree/trunk/examples) directory. ## Stability -All versions prior to 1.0.0 are not considered production ready. This is my -first crate and there's still a lot of edge cases I didn't get a chance to -consider yet. +This crate has almost complete test coverage and is tested with Miri. It doesn't +rely on any weird language quirks, but it _does_ deal with memory management. -Prelimenary tests are in place but I don't consider them sufficient to guarantee -full correctness of behavior. I am however using this crate for development of -another crate which allows me to do some integration testing besides just -examples. +There's a lot of unsafe code due to the nature of the crate, but again, it's +covered by tests and Miri. ## Alternatives - manually managing memory to ensure contiguous placement of data - prone to errors and requires unsafe code -- for storing types with uniform `Layout`, when you only need to erase their +- multiple levels of indirection (`Vec>`) +- for storing types with **uniform** `Layout`, when you only need to erase their types at the container level see: - [`any_vec`](https://crates.io/crates/any_vec) - [`type_erased_vec`](https://crates.io/crates/type_erased_vec) @@ -144,4 +129,5 @@ license unless you explicitly state otherwise. ## License This project is licensed under [Zlib](./LICENSE_ZLIB), [MIT](./LICENSE_MIT), or -[Apache-2.0](./LICENSE_APACHE) license, choose whichever suits you most. +[Apache-2.0](./LICENSE_APACHE) license, choose whichever suits your use case the +best. diff --git a/build.rs b/build.rs index 0bce83d..e79e958 100644 --- a/build.rs +++ b/build.rs @@ -1,12 +1,15 @@ use std::process::Command; fn main() { + println!("cargo::rustc-check-cfg=cfg(nightly)"); + let output = Command::new("rustc") .args(["--version"]) .output() .expect("unable to get rustc version") .stdout; let version = String::from_utf8_lossy(&output); + if version.contains("nightly") { println!("cargo:rustc-cfg=nightly") } diff --git a/doc/crate.md b/doc/crate.md index e16a2b6..c8678fd 100644 --- a/doc/crate.md +++ b/doc/crate.md @@ -1,5 +1,6 @@ -contiguous_mem is a vector like collection that can store entries with -heterogeneous layouts while retaining type information at the reference level. +contiguous_mem is space optimized a vector like collection that can store +entries of varying layouts close in memory while retaining type information at +the reference level. ## Features @@ -12,8 +13,6 @@ heterogeneous layouts while retaining type information at the reference level. environment - [`allocator_api`](https://dev-doc.rust-lang.org/stable/unstable-book/library-features/allocator-api.html) <_nightly_> - enables automatic support for custom allocators -- `sync_impl` (default) - enables `SyncContiguousMemory` and related error code - implementation - `unsafe_impl` (default) - enables `UnsafeContiguousMemory` ## Contributions diff --git a/doc/layout.png b/doc/layout.png new file mode 100644 index 0000000000000000000000000000000000000000..ce2029a481d9a52426c2518d412180ba417ce156 GIT binary patch literal 32317 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/layout.typ b/doc/layout.typ new file mode 100644 index 0000000..01cd07c --- /dev/null +++ b/doc/layout.typ @@ -0,0 +1,83 @@ +#import "@preview/tablex:0.0.8": * + +#set page( + margin: 1cm, + width: 600pt, + height: 210pt, +) +#set text(size: 15pt, font: "Ubuntu") + +#let rounded(color, width: auto, content) = box( + radius: 2pt, + fill: color, + stroke: ( + thickness: 2pt, + paint: color.darken(30%).desaturate(50%) + ), + inset: 5pt, + width: width, + content +) + +#let container(color, name, ..items) = rounded( + color, + align(left, stack(dir: ttb, + spacing: 5pt, + box( + fill: color.lighten(80%).saturate(90%), + radius: 2pt, + inset: 2pt, + { + set text(size: 20pt) + raw(lang: "rust", name) + } + ), + stack(dir: ltr, spacing: 5pt, ..items) + )) +) + +#let byte-size = 20pt; +#let largest = byte-size * 4; + +#let vec-layout = container( + color.hsl(100.68deg, 46.46%, 75.1%), + "Vec", + rounded(color.hsl(215.49deg, 53.38%, 73.92%), width: largest, "Enum::A"), + rounded(color.hsl(276.34deg, 53.38%, 73.92%), width: largest, "Enum::B"), + rounded(color.hsl(330.42deg, 53.38%, 73.92%), width: largest, "Enum::C"), + rounded(color.hsl(64deg, 100%, 79.41%), width: largest, "Enum::D"), + rounded(color.hsl(124.92deg, 85.92%, 72.16%), width: largest, "Enum::E"), +) + +#let cmem-layout = container( + color.hsl(171.86deg, 46.46%, 75.1%), + "ContiguousMemory", + rounded(color.hsl(215.49deg, 53.38%, 73.92%), width: largest, "A"), + rounded(color.hsl(276.34deg, 53.38%, 73.92%), width: byte-size, "B"), + h(byte-size + 4pt), + rounded(color.hsl(330.42deg, 53.38%, 73.92%), width: byte-size * 2, "C"), + rounded(color.hsl(64deg, 100%, 79.41%), width: byte-size * 2, "D"), +) + +#let cmem-layout-after = container( + color.hsl(171.86deg, 46.46%, 75.1%), + "ContiguousMemory", + rounded(color.hsl(215.49deg, 53.38%, 73.92%), width: largest, "A"), + rounded(color.hsl(276.34deg, 53.38%, 73.92%), width: byte-size, "B"), + rounded(color.hsl(124.92deg, 85.92%, 72.16%), width: byte-size, "E"), + rounded(color.hsl(330.42deg, 53.38%, 73.92%), width: byte-size * 2, "C"), + rounded(color.hsl(64deg, 100%, 79.41%), width: byte-size * 2, "D"), +) + +#stack( + dir: ttb, + vec-layout, + v(10pt), + align(horizon, stack(dir: ltr, spacing: 1pt, + cmem-layout, raw(lang: "rust", ".push(E)"), $ arrow.filled $, h(5pt), cmem-layout-after + )), + v(5pt), + move(dx: 100pt, text(size: 10pt)[ + #table(align: center, stroke: none, inset: 0pt, $arrow.filled.t$, v(5pt), [_alignment_], v(2pt), [_padding_]) + ]) +) \ No newline at end of file diff --git a/examples/default_impl.rs b/examples/default_impl.rs index d99d243..1ec8731 100644 --- a/examples/default_impl.rs +++ b/examples/default_impl.rs @@ -20,5 +20,5 @@ fn main() { // All stored data gets cleaned up once `memory` goes out of scope, or we // can forget it existed: - // memory.forget(); + // memory.leak(); } diff --git a/examples/game_loading.rs b/examples/game_loading.rs index 4b83ff2..4557fed 100644 --- a/examples/game_loading.rs +++ b/examples/game_loading.rs @@ -196,7 +196,7 @@ fn main() { // data won't go out of scope while we're using it in this example, but in // your use case it might. This is here for completeness. - data.forget(); + data.leak(); // now we can assume all created pointers are 'static // prepare levels for use diff --git a/examples/unsafe_impl.rs b/examples/unsafe_impl.rs index e0e2407..fab15ea 100644 --- a/examples/unsafe_impl.rs +++ b/examples/unsafe_impl.rs @@ -26,5 +26,5 @@ fn main() { // All stored data gets cleaned up once `memory` goes out of scope, or we // can forget it existed: - // memory.forget(); + // memory.leak(); } diff --git a/src/lib.rs b/src/lib.rs index 39bd166..43266ba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -123,7 +123,7 @@ impl> ContiguousMemory { /// # Examples /// ``` /// # #![allow(unused_mut)] - /// use core::mem::align_of; + /// # use core::mem::align_of; /// use core::alloc::Layout; /// use contiguous_mem::ContiguousMemory; /// @@ -468,6 +468,7 @@ impl, A: ManageMemory> ContiguousMemory { /// let mut s: ContiguousMemory = ContiguousMemory::new(); /// /// assert!(s.try_grow_to(1024).is_ok()); + /// assert_eq!(s.capacity(), 1024); /// ``` /// /// The method returns an error if the system can't reserve requested @@ -475,7 +476,6 @@ impl, A: ManageMemory> ContiguousMemory { /// ```should_panic /// # use contiguous_mem::ContiguousMemory; /// # let mut s: ContiguousMemory = ContiguousMemory::new(); - /// /// let required_size: usize = usize::MAX; // bad read? /// // can't allocate all addressable memory /// assert!(s.try_grow_to(required_size).is_ok()); // PANIC! @@ -562,21 +562,35 @@ impl, A: ManageMemory> ContiguousMemory { self.try_grow_to(capacity + additional) } - /// Grows the underlying memory to ensure container has a free segment that - /// can store `capacity`. This function might allocate more than requested - /// amount of memory to reduce number of reallocations. + /// Like [`try_reserve`](ContiguousMemory::try_reserve), grows the + /// underlying memory to ensure container has a free segment that can store + /// `capacity`, but panics if that's not possible. /// - /// If the base address changed due to reallocation, new [`BasePtr`] is - /// returned as `Ok(Some(BasePtr))`, if base address stayed the same the - /// result is `Ok(None)`. - /// - /// After calling this function, new capacity will be greater than: - /// `self.size() + capacity`. + /// See the [base implementation](ContiguousMemory::try_reserve_layout) for + /// more details. /// /// # Panics /// /// Panics if attempting to grow the container to a capacity larger than /// `isize::MAX` or the allocator can't allocate required memory. + /// + /// # Examples + /// ``` + /// # use contiguous_mem::ContiguousMemory; + /// # use core::alloc::Layout; + /// let layout = Layout::from_size_align(4, 8).unwrap(); + /// let mut s: ContiguousMemory = ContiguousMemory::with_layout(layout); + /// + /// # assert_eq!(s.size(), 0); + /// assert_eq!(s.capacity(), 4); + /// + /// let r1 = s.push(1u8); + /// assert_eq!(s.size(), 1); + /// assert_eq!(s.capacity(), 4); + /// + /// s.reserve(8); + /// assert_eq!(s.capacity(), 9); + /// ``` #[inline] pub fn reserve(&mut self, capacity: usize) -> Option { match self.try_reserve(capacity) { @@ -587,18 +601,30 @@ impl, A: ManageMemory> ContiguousMemory { } /// Tries growing the underlying memory to ensure container has a free - /// segment that can store `capacity`. This function might allocate more - /// than requested amount of memory to reduce number of reallocations. + /// segment that can store `capacity`. /// - /// If the base address changed due to reallocation, new [`BasePtr`] is - /// returned as `Ok(Some(BasePtr))`, if base address stayed the same the - /// result is `Ok(None)`. + /// Works like [`try_reserve_layout`](ContiguousMemory::try_reserve_layout), + /// but doesn't account for specific alignment of the reserved segment. + /// Check its documentation for more details. /// - /// If the new capacity exceeds `isize::MAX` or the allocator couldn't - /// allocate required memory, a [`MemoryError`] is returned. + /// # Examples + /// ``` + /// # use contiguous_mem::ContiguousMemory; + /// # use core::alloc::Layout; + /// let layout = Layout::from_size_align(4, 8).unwrap(); + /// let mut s: ContiguousMemory = ContiguousMemory::with_layout(layout); + /// # assert_eq!(s.size(), 0); + /// assert_eq!(s.capacity(), 4); /// - /// After calling this function, new capacity will be greater than: - /// `self.size() + capacity`. + /// let r1 = s.push(1u8); + /// assert_eq!(s.size(), 1); + /// assert_eq!(s.capacity(), 4); + /// + /// s.try_reserve(8).expect("should have enough memory"); + /// assert_eq!(s.capacity(), 9); + /// + /// assert!(s.try_reserve(usize::MAX).is_err()); + /// ``` pub fn try_reserve(&mut self, capacity: usize) -> Result, MemoryError> { if capacity == 0 { return Ok(None); @@ -607,14 +633,10 @@ impl, A: ManageMemory> ContiguousMemory { } /// Grows the underlying memory to ensure container has a free segment that - /// can store `capacity`. + /// can store `capacity`, or panics. /// - /// If the base address changed due to reallocation, new [`BasePtr`] is - /// returned as `Ok(Some(BasePtr))`, if base address stayed the same the - /// result is `Ok(None)`. - /// - /// After calling this function, new capacity will be equal to: `self.size() - /// + capacity`. + /// See the [base implementation](ContiguousMemory::try_reserve_layout) for + /// more details. /// /// # Panics /// @@ -648,20 +670,16 @@ impl, A: ManageMemory> ContiguousMemory { /// Tries growing the underlying memory to ensure container has a free /// segment that can store `capacity`. /// - /// If the base address changed due to reallocation, new [`BasePtr`] is - /// returned as `Ok(Some(BasePtr))`, if base address stayed the same the - /// result is `Ok(None)`. - /// - /// If the new capacity exceeds `isize::MAX` or the allocator couldn't - /// allocate required memory, a [`MemoryError`] is returned. + /// Works much like + /// [`try_reserve_layout_exact`](ContiguousMemory::try_reserve_layout_exact), + /// but doesn't ensure a specific alignment of the reserved segment. /// - /// After calling this function, new capacity will be equal to: `self.size() - /// + capacity`. + /// See the [base implementation](ContiguousMemory::try_reserve_layout) for + /// more details. /// /// # Examples /// ``` - /// use contiguous_mem::ContiguousMemory; - /// + /// # use contiguous_mem::ContiguousMemory; /// let mut s: ContiguousMemory = ContiguousMemory::new(); /// /// assert!(s.try_reserve_exact(1024).is_ok()); @@ -673,7 +691,6 @@ impl, A: ManageMemory> ContiguousMemory { /// ```should_panic /// # use contiguous_mem::ContiguousMemory; /// # let mut s: ContiguousMemory = ContiguousMemory::new(); - /// /// let required_size: usize = usize::MAX; // bad read? /// // can't allocate all addressable memory /// assert!(s.try_reserve_exact(required_size).is_ok()); // PANIC! @@ -688,16 +705,12 @@ impl, A: ManageMemory> ContiguousMemory { self.ensure_free_section::(capacity, None) } - /// Grows the underlying memory to ensure container has a free segment that - /// can store a value with provided `layout`. This function might allocate - /// more than requested amount of memory to reduce number of reallocations. + /// Like [`try_reserve_layout`](ContiguousMemory::try_reserve_layout), grows + /// the underlying memory to ensure container has a free segment that can + /// store a value with provided `layout`, or panics if that's not possible. /// - /// If the base address changed due to reallocation, new [`BasePtr`] is - /// returned as `Ok(Some(BasePtr))`, if base address stayed the same the - /// result is `Ok(None)`. - /// - /// After calling this function, new capacity will be greater than: - /// `self.size() + padding + size_of::()`. + /// See the [base implementation](ContiguousMemory::try_reserve_layout) for + /// more details. /// /// # Panics /// @@ -713,19 +726,44 @@ impl, A: ManageMemory> ContiguousMemory { } /// Tries growing the underlying memory to ensure container has a free - /// segment that can store a value with provided `layout`. This function - /// might allocate more than requested amount of memory to reduce number of - /// reallocations. + /// segment that can store a value with provided `layout`. /// /// If the base address changed due to reallocation, new [`BasePtr`] is - /// returned as `Ok(Some(BasePtr))`, if base address stayed the same the - /// result is `Ok(None)`. + /// returned as `Ok(Some(BasePtr))`, if base address remained the same + /// `Ok(None)` is returned. /// /// If the new capacity exceeds `isize::MAX` or the allocator couldn't - /// allocate required memory, a [`MemoryError`] is returned. + /// allocate required memory, a [`MemoryError`] is returned. If allocating + /// the required capacity is expected to succeed, use the function variant + /// without the `try_` prefix. + /// + /// `layout` argument [type](HasLayout) can either be a [`Layout`] value + /// _or_ a reference to any `Sized` type. /// /// After calling this function, new capacity will be greater than: - /// `self.size() + padding + size_of::()`. + /// `self.size() + padding + layout.size()`.
+ /// `padding` is preceding blank space necessary to ensure the proper + /// alignment of the provided layout. If ensuring alignment is not needed + /// (because the data is unaligned), use variants without the `_layout` + /// suffix. + /// + /// This function might allocate more than requested amount of memory to + /// reduce number of reallocations. If exact allocation is needed instead, + /// use variants with `_exact` suffix. + /// + /// In total, this function has 8 different variants. Use the one which best + /// suits your specific requirements: + /// + /// | Variant | `Err` / panic | alignment | amortized growth | + /// |:-|:-:|:-:|:-:| + /// |[`reserve`](ContiguousMemory::reserve) |panic|✗|✓| + /// |[`try_reserve`](ContiguousMemory::try_reserve) |`Err`|✗|✓| + /// |[`reserve_exact`](ContiguousMemory::reserve_exact) |panic|✗|✗| + /// |[`try_reserve_exact`](ContiguousMemory::try_reserve_exact) |`Err`|✗|✗| + /// |[`reserve_layout`](ContiguousMemory::reserve_layout) |panic|✓|✓| + /// |[`try_reserve_layout`](ContiguousMemory::try_reserve_layout) |`Err`|✓|✓| + /// |[`reserve_layout_exact`](ContiguousMemory::reserve_layout_exact) |panic|✓|✗| + /// |[`try_reserve_layout_exact`](ContiguousMemory::try_reserve_layout_exact)|`Err`|✓|✗| pub fn try_reserve_layout( &mut self, layout: impl HasLayout, @@ -737,15 +775,14 @@ impl, A: ManageMemory> ContiguousMemory { self.ensure_free_section::(layout.size(), Some(layout.align())) } - /// Grows the underlying memory to ensure container has a free segment that - /// can store a value with provided `layout`. - /// - /// If the base address changed due to reallocation, new [`BasePtr`] is - /// returned as `Ok(Some(BasePtr))`, if base address stayed the same the - /// result is `Ok(None)`. + /// Like + /// [`try_reserve_layout_exact`](ContiguousMemory::try_reserve_layout_exact), + /// tries growing the underlying memory to ensure container has a free + /// segment that can store a value with provided `layout`, but panics if + /// that's not possible instead of returning an error value. /// - /// After calling this function, new capacity will be equal to: - /// `self.size() + padding + size_of::()`. + /// See the [base implementation](ContiguousMemory::try_reserve_layout) for + /// more details. /// /// # Panics /// @@ -763,15 +800,12 @@ impl, A: ManageMemory> ContiguousMemory { /// Tries growing the underlying memory to ensure container has a free /// segment that can store a value with provided `layout`. /// - /// If the base address changed due to reallocation, new [`BasePtr`] is - /// returned as `Ok(Some(BasePtr))`, if base address stayed the same the - /// result is `Ok(None)`. + /// Unlike [`try_reserve_layout`](ContiguousMemory::try_reserve_layout), + /// this function will only reserve memory necessary to accommodate the + /// provided layout and not more. /// - /// If the new capacity exceeds `isize::MAX` or the allocator couldn't - /// allocate required memory, a [`MemoryError`] is returned. - /// - /// After calling this function, new capacity will be equal to: `self.size() - /// + padding + layout.size()`. + /// See [base implementation](ContiguousMemory::try_reserve_layout) for + /// more details. pub fn try_reserve_layout_exact( &mut self, layout: impl HasLayout, @@ -783,12 +817,39 @@ impl, A: ManageMemory> ContiguousMemory { self.ensure_free_section::(layout.size(), Some(layout.align())) } - /// Shrinks the capacity with a lower bound and returns the base pointer. + /// Tries shrinking the capacity of the container to provided + /// `new_capacity`, or smallest larger one if provided `new_capacity` can't + /// accomodate stored data, and returns the [`MemoryBase`]. + /// + /// `MemoryBase` result will generally stay the same for shrinking + /// operations, but that depends on the used [allocator `A`](ManageMemory). /// /// # Panics /// /// Panics if the allocator wasn't able to shrink the allocated memory - /// region. + /// region. This should almost never happen unless the allocator doesn't + /// support deallocation. + /// + /// # Examples + /// ``` + /// # use contiguous_mem::ContiguousMemory; + /// let mut s: ContiguousMemory = ContiguousMemory::with_capacity(32); + /// assert_eq!(s.capacity(), 32); + /// + /// let r = s.push(1u16); + /// + /// // can't grow capacity + /// s.shrink_to(64); + /// assert_eq!(s.capacity(), 32); + /// + /// // can shrink capacity to more than is currently used + /// s.shrink_to(8); + /// assert_eq!(s.capacity(), 8); + /// + /// // but it won't shrink it past the minimum required + /// s.shrink_to(0); + /// assert_eq!(s.capacity(), 2); + /// ``` pub fn shrink_to(&mut self, new_capacity: usize) -> MemoryBase { let mut tracker = WritableInner::write(&self.inner.tracker).unwrap(); let new_capacity = tracker.shrink(new_capacity); @@ -804,7 +865,29 @@ impl, A: ManageMemory> ContiguousMemory { } /// Shrinks the capacity to fit the currently stored data and returns the - /// base pointer. + /// new [`MemoryBase`]. + /// + /// Bytes between stored objects will remain allocated to reduce + /// fragmentation. + /// + /// # Panics + /// + /// Panics if the allocator wasn't able to shrink the allocated memory + /// region. This should almost never happen unless the allocator doesn't + /// support deallocation. + /// + /// # Examples + /// + /// ``` + /// # use contiguous_mem::ContiguousMemory; + /// let mut s: ContiguousMemory = ContiguousMemory::with_capacity(1024); + /// + /// assert_eq!(s.capacity(), 1024); + /// let r = s.push(1u16); + /// + /// s.shrink_to_fit(); + /// assert_eq!(s.capacity(), 2); + /// ``` pub fn shrink_to_fit(&mut self) -> MemoryBase { let mut base = WritableInner::write(&self.inner.base).unwrap(); let new_capacity = match WritableInner::write(&self.inner.tracker) @@ -826,10 +909,40 @@ impl, A: ManageMemory> ContiguousMemory { /// Value type argument `T` is used to infer type size and returned /// reference dropping behavior. /// + /// Use [`push_persisted`](ContiguousMemory::push_persisted) if you want to + /// push data that shouldn't be cleared once the reference is dropped. + /// + /// Use [`push_raw`](ContiguousMemory::push_raw) if you want to take full + /// control over details of push the pushed type (memory location and + /// `Layout` ). + /// + /// There's also a [`push_raw_persisted`](ContiguousMemory::push_persisted) + /// variant that combines functionality of both. + /// /// # Panics /// - /// Panics if the collection needs to grow and new capacity exceeds - /// `isize::MAX` bytes or allocation of additional memory fails. + /// Panics if: + /// - the collection needs to grow and new capacity exceeds `isize::MAX` + /// bytes, or + /// - allocation of additional memory fails. + /// + /// # Examples + /// + /// ``` + /// # use contiguous_mem::ContiguousMemory; + /// let mut s: ContiguousMemory = ContiguousMemory::new(); + /// + /// let r1 = s.push(1u16); + /// let mut r2 = s.push(2u32); + /// let r3 = s.push("hello"); + /// + /// println!("{} world", *r3.get()); + /// assert_eq!(*r1.get() as u32 + *r2.get(), 3u32); + /// + /// let r1 = s.push(3u32); + /// r2 = s.push(4u32); + /// assert_eq!(*r1.get() + *r2.get(), 7u32); + /// ``` pub fn push(&mut self, value: T) -> Impl::PushResult { let mut data = ManuallyDrop::new(value); let layout = Layout::for_value(&data); @@ -1026,7 +1139,7 @@ impl, A: ManageMemory> ContiguousMemory { .release(region); } - /// Forgets this container without dropping it and returns its base address + /// Forgets this container without dropping it, returning its base address /// and [`Layout`]. /// /// # Safety @@ -1039,9 +1152,8 @@ impl, A: ManageMemory> ContiguousMemory { /// guaranteed to be safe. /// /// This method isn't unsafe as leaking data doesn't cause undefined - /// behavior. ([_see - /// details_](https://doc.rust-lang.org/nomicon/leaking.html)) - pub fn forget(self) -> MemoryBase { + /// behavior. ([_why_](https://doc.rust-lang.org/nomicon/leaking.html)) + pub fn leak(self) -> MemoryBase { let base = self.base(); core::mem::forget(self); base diff --git a/src/memory.rs b/src/memory.rs index 59e8d40..47c6a18 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -71,21 +71,88 @@ impl SegmentTracker { } /// Returns the total memory size being tracked. + /// + /// # Examples + /// ``` + /// # use contiguous_mem::memory::SegmentTracker; + /// let mut tracker = SegmentTracker::new(1024); + /// + /// assert_eq!(tracker.size(), 1024); + /// + /// tracker.grow(2048); + /// + /// assert_eq!(tracker.size(), 2048); + /// ``` pub fn size(&self) -> usize { self.size } /// Returns the sum of unoccupied bytes of all unused memory segments. + /// + /// # Examples + /// ``` + /// # use contiguous_mem::memory::SegmentTracker; + /// # use contiguous_mem::range::ByteRange; + /// # use core::alloc::Layout; + /// let mut tracker = SegmentTracker::new(1024); + /// + /// assert_eq!(tracker.count_free(), 1024); + /// + /// let layout = Layout::from_size_align(512, 8).unwrap(); + /// let _ = tracker.take_next(4, layout).unwrap(); + /// + /// // both preceding 8 bytes and subsequent 504 bytes are counted towards + /// // the total: + /// assert_eq!(tracker.count_free(), 512); + /// ``` pub fn count_free(&self) -> usize { self.unoccupied.iter().fold(0, |acc, it| acc + it.len()) } /// Returns `true` if there is no empty space left in the tracked region. + /// + /// # Examples + /// ``` + /// # use contiguous_mem::memory::SegmentTracker; + /// # use contiguous_mem::range::ByteRange; + /// # use core::alloc::Layout; + /// let mut tracker = SegmentTracker::new(1024); + /// + /// let layout = Layout::from_size_align(512, 8).unwrap(); + /// let _ = tracker.take_next(4, layout).unwrap(); + /// + /// assert!(!tracker.is_full()); + /// + /// let layout = Layout::from_size_align(504, 8).unwrap(); + /// let _ = tracker.take_next(4, layout).unwrap(); + /// + /// assert!(!tracker.is_full()); + /// + /// let layout = Layout::from_size_align(8, 4).unwrap(); + /// let _ = tracker.take_next(4, layout).unwrap(); + /// + /// assert!(tracker.is_full()); + /// ``` pub fn is_full(&self) -> bool { self.unoccupied.is_empty() } /// Returns a [`ByteRange`] encompassing the entire tracked memory region. + /// + /// # Examples + /// ``` + /// # use contiguous_mem::memory::SegmentTracker; + /// # use contiguous_mem::range::ByteRange; + /// # use core::alloc::Layout; + /// let mut tracker = SegmentTracker::new(1024); + /// + /// assert_eq!(tracker.whole_range(), ByteRange(0, 1024)); + /// + /// let layout = Layout::from_size_align(512, 8).unwrap(); + /// let _ = tracker.take_next(4, layout).unwrap(); + /// + /// assert_eq!(tracker.whole_range(), ByteRange(0, 1024)); + /// ``` pub fn whole_range(&self) -> ByteRange { ByteRange(0, self.size) } @@ -93,7 +160,7 @@ impl SegmentTracker { /// Grows the available memory range represented by this structure to /// provided `new_size` and returns the new size. pub fn grow(&mut self, new_size: usize) -> usize { - if new_size < self.size { + if new_size <= self.size { return self.size; } @@ -114,6 +181,10 @@ impl SegmentTracker { /// Tries shrinking the available memory range represented by this structure /// to provided `new_size` and returns the new size. pub fn shrink(&mut self, new_size: usize) -> usize { + if new_size >= self.size { + return self.size; + } + let last = match self.unoccupied.last_mut() { Some(it) => it, None => return self.size, @@ -157,7 +228,7 @@ impl SegmentTracker { return false; } - self.unoccupied.iter().enumerate().any(|(_, it)| { + self.unoccupied.iter().any(|it| { it.offset(base.pos_or_align()) // absolute range .aligned(layout.align()) // aligned to value .len() @@ -307,8 +378,9 @@ impl SegmentTracker { } } + /// Clears all regions marked as occupied. #[inline] - pub(crate) fn clear(&mut self) { + pub fn clear(&mut self) { self.unoccupied.clear(); self.unoccupied.push(self.whole_range()) } diff --git a/src/raw.rs b/src/raw.rs index f7fd2c5..92a3ff8 100644 --- a/src/raw.rs +++ b/src/raw.rs @@ -77,9 +77,6 @@ impl, A: ManageMemory> Drop for MemoryState { /// Unlike a fat pointer, this struct also stores information on expected /// alignment the slice was allocated with, unifying [`Layout`] and pointer /// types. -/// -/// It contains _any_ information required for allocation and deallocation, the -/// exact details and layout of that data is an internal implementation detail. #[cfg_attr(feature = "debug", derive(Debug))] #[derive(Clone, Copy, PartialEq, Eq)] pub struct MemoryBase { diff --git a/src/types.rs b/src/types.rs index 9ca05e0..4420d79 100644 --- a/src/types.rs +++ b/src/types.rs @@ -6,7 +6,7 @@ mod std_imports { } #[cfg(not(feature = "no_std"))] -pub use std_imports::*; +pub(crate) use std_imports::*; #[cfg(feature = "no_std")] mod nostd_imports { @@ -16,7 +16,7 @@ mod nostd_imports { pub use ::alloc::vec::Vec; } #[cfg(feature = "no_std")] -pub use nostd_imports::*; +pub(crate) use nostd_imports::*; #[cfg(feature = "error_in_core")] pub use core::error::Error; @@ -202,11 +202,8 @@ impl WritableInner for UnsafeCell { } } -/// A fake [`Reference`]-like wrapper for [unsafe implementation](ImplUnsafe) -/// state and [`Cell`](core::cell::Cell). -/// -/// As an owned value `T` doesn't implement a [`Deref`], this wrapper fills that -/// gap in order to unify implementation details. +/// A wrapper to allow using owned values in [unsafe implementation](ImplUnsafe) +/// state and [cells](core::cell::Cell) via [`Deref`]. #[derive(Debug)] #[repr(transparent)] pub struct Owned(pub(crate) T); @@ -377,11 +374,7 @@ where pub(crate) type DropFn = fn(*mut ()); pub(crate) const fn drop_fn() -> fn(*mut ()) { - if core::mem::needs_drop::() { - |ptr: *mut ()| unsafe { core::ptr::drop_in_place(ptr as *mut T) } - } else { - |_: *mut ()| {} - } + |ptr: *mut ()| unsafe { core::ptr::drop_in_place(ptr as *mut T) } } pub(crate) const fn is_layout_valid(size: usize, align: usize) -> bool { @@ -396,12 +389,13 @@ pub(crate) const fn is_layout_valid(size: usize, align: usize) -> bool { /// Sized` as an argument to a function which requires a type layout. /// /// This trait is sealed to prevent users from implementing it for arbitrary -/// types which would voilate its intention and cause bloat. +/// types which could voilate its purpose. pub trait HasLayout: Sealed { - /// Returns a layout of the reference or a copy of the layout directly. + /// Returns a layout of the reference or a copy of the layout. fn as_layout(&self) -> Layout; } +/// Base implementation, allowing direct use of `Layout`. impl HasLayout for Layout { #[inline] fn as_layout(&self) -> Layout { @@ -409,6 +403,7 @@ impl HasLayout for Layout { } } +/// Layout can be inferred from any reference to a [`Sized`] type. impl HasLayout for &T { #[inline] fn as_layout(&self) -> Layout {