diff --git a/.JuliaFormatter.toml b/.JuliaFormatter.toml deleted file mode 100644 index a86de4d..0000000 --- a/.JuliaFormatter.toml +++ /dev/null @@ -1,12 +0,0 @@ -always_for_in = true -whitespace_typedefs = true -whitespace_ops_in_indices = true -remove_extra_newlines = true -import_to_using = true -normalize_line_endings = "unix" -separate_kwargs_with_semicolon = true -whitespace_in_kwargs = false -short_to_long_function_def = true -long_to_short_function_def = false -conditional_to_if = true -trailing_comma = true diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..cc6c085 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,41 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +MemoryViews.jl provides `MemoryView`, a low-level view into `Memory{T}` for Julia ≥ 1.11. It's a `DenseVector{T}` subtype representing a `MemoryRef{T}` + length, with static mutability tracking via type parameter (`Mutable`/`Immutable`). The package also defines the `MemoryKind` trait for dispatch on memory-backed types. + +## Commands + +```bash +# Run tests +JULIA_TEST_FAILFAST=true julia --project -e 'using Pkg; Pkg.test()' + +# Format code +runic -i . +``` + +## Architecture + +**Core types** (defined in `src/MemoryViews.jl`): +- `MemoryView{T, M}` where `M ∈ {Mutable, Immutable}` — the main type +- `MemoryKind` trait: `IsMemory{T}` / `NotMemory` for dispatch + +**Source files**: +- `construction.jl` — constructors from Array, Memory, String, SubArray, CodeUnits +- `basic.jl` — indexing, slicing (returns views, not copies), copying, find operations with memchr/memrchr C calls, comparison via memcmp +- `experimental.jl` — `split_first`, `split_last`, `split_at`, `split_unaligned` +- `delimited.jl` — `split_each` delimiter iterator +- `base_arrays.jl` — Vector/Memory conversion, append +- `io.jl` — `readbytes!` + +**Extensions** (`ext/`): StringViews, FixedSizeArrays, LibDeflate integration. + +## Key Patterns + +- Slicing creates views into the same memory (no allocation) +- Performance-critical paths use `@ccall` to libc (`memset`, `memcmp`, `memchr`, `memrchr`) with `GC.@preserve` +- Version-conditional code for Julia 1.12+ vs 1.13+ (e.g., `Base.memoryindex` for `parentindices`) +- Trait-based dispatch pattern: define `foo(x)` → `foo(MemoryKind(typeof(x)), x)` → specialized on `IsMemory`/`NotMemory` +- `@boundscheck`/`@inbounds` used throughout for safe-by-default with opt-in elision diff --git a/Project.toml b/Project.toml index 2ba328f..ab7b079 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "MemoryViews" uuid = "a791c907-b98b-4e44-8f4d-e4c2362c6b2f" -version = "0.3.6" +version = "0.3.7" authors = ["Jakob Nybo Nissen "] [weakdeps] diff --git a/src/basic.jl b/src/basic.jl index 86b3755..5ce8666 100644 --- a/src/basic.jl +++ b/src/basic.jl @@ -332,10 +332,11 @@ function Base.:(==)(a::Mem, b::Mem) where {Mem <: BitMemory} length(a) == length(b) || return false (eltype(a) === Union{} || Base.issingletontype(eltype(a))) && return true a.ref === b.ref && return true + nbytes = length(a) * sizeof(eltype(a)) GC.@preserve a b begin aptr = Ptr{Nothing}(pointer(a)) bptr = Ptr{Nothing}(pointer(b)) - y = @ccall memcmp(aptr::Ptr{Nothing}, bptr::Ptr{Nothing}, length(a)::Int)::Cint + y = @ccall memcmp(aptr::Ptr{Nothing}, bptr::Ptr{Nothing}, nbytes::Csize_t)::Cint end return iszero(y) end diff --git a/src/io.jl b/src/io.jl index 4d3551b..623c4cb 100644 --- a/src/io.jl +++ b/src/io.jl @@ -14,5 +14,5 @@ function Base.readbytes!(io::IO, v::MutableMemoryView{UInt8}, nb::Integer = leng GC.@preserve v unsafe_read(io, Base.unsafe_convert(Ptr{UInt8}, remaining), ba % UInt) remaining = remaining[(ba + 1):end] end - return length(v) - length(remaining) + return min(nb, length(v) - length(remaining)) end diff --git a/test/runtests.jl b/test/runtests.jl index aa11510..870422f 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -659,7 +659,7 @@ end data = b"Hello, world!" buf = IOBuffer(data) v = fill(0xaa, 25) - readbytes!(buf, MemoryView(v), 7) + @test readbytes!(buf, MemoryView(v), 7) == 7 @test v[1:8] == b"Hello, \xaa" # With nb being higher than the vector length