You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
AdaptiveArrayPools.jl includes specialized support for `BitArray` (specifically`BitVector`), enabling **~8x memory savings** for boolean arrays compared to standard `Vector{Bool}`.
3
+
AdaptiveArrayPools.jl includes specialized support for `BitArray` (including`BitVector` and N-dimensional `BitArray{N}`), enabling **~8x memory savings** for boolean arrays compared to standard `Vector{Bool}`.
4
4
5
5
## The `Bit` Sentinel Type
6
6
@@ -14,31 +14,34 @@ To distinguish between standard boolean arrays (`Vector{Bool}`, 1 byte/element)
14
14
## Usage
15
15
16
16
### 1D Arrays (BitVector)
17
-
For 1D arrays, `acquire!` returns a view into a pooled `BitVector`.
17
+
For 1D arrays, `acquire!` returns a native `BitVector`. This design choice enables full SIMD optimization, making operations significantly faster (10x~100x) than using views.
18
18
19
19
```julia
20
20
@with_pool pool begin
21
21
# Acquire a BitVector of length 1000
22
22
bv =acquire!(pool, Bit, 1000)
23
-
23
+
24
24
# Use like normal
25
25
bv .=true
26
26
bv[1] =false
27
-
28
-
# Supports standard operations
27
+
28
+
# Supports standard operations with full SIMD acceleration
29
29
count(bv)
30
30
end
31
31
```
32
32
33
-
### N-D Arrays (BitArray / Reshaped)
34
-
For multi-dimensional arrays, `acquire!` returns a `ReshapedArray` wrapper around the linear `BitVector`. This maintains zero-allocation efficiency while providing N-D indexing.
33
+
### N-D Arrays (BitArray)
34
+
For multi-dimensional arrays, `acquire!` returns a `BitArray{N}` (specifically `BitMatrix` for 2D). This preserves the packed memory layout and SIMD benefits while providing N-D indexing.
35
35
36
36
```julia
37
37
@with_pool pool begin
38
-
# 100x100 bit matrix
38
+
# 100x100 bit matrix (returns BitMatrix)
39
39
mask =zeros!(pool, Bit, 100, 100)
40
-
40
+
41
41
mask[5, 5] =true
42
+
43
+
# 3D BitArray
44
+
volume =acquire!(pool, Bit, 10, 10, 10)
42
45
end
43
46
```
44
47
@@ -50,29 +53,66 @@ For specific `BitVector` operations, prefer `trues!` and `falses!` which mirror
50
53
@with_pool pool begin
51
54
# Filled with false (equivalent to `falses(256)`)
52
55
mask =falses!(pool, 256)
53
-
56
+
54
57
# Filled with true (equivalent to `trues(256)`)
55
58
flags =trues!(pool, 256)
56
-
59
+
57
60
# Multidimensional
58
61
grid =trues!(pool, 100, 100)
59
-
62
+
60
63
# Similar to existing BitArray
61
64
A =BitVector(undef, 50)
62
65
B =similar!(pool, A) # Reuses eltype(A) -> Bool
63
-
66
+
64
67
# To explicit get Bit-packed from pool irrespective of source
65
-
C =similar!(pool, A, Bit)
68
+
C =similar!(pool, A, Bit)
66
69
end
70
+
```
67
71
68
72
Note: `zeros!(pool, Bit, ...)` and `ones!(pool, Bit, ...)` are also supported (aliased to `falses!` and `trues!`).
73
+
74
+
## Performance & Safety
75
+
76
+
### Why Native BitArray?
77
+
The pool returns native `BitVector`/`BitArray` types instead of `SubArray` views for **performance**.
78
+
Operations like `count()`, `sum()`, and bitwise broadcasting are **10x~100x faster** on native bit arrays because they utilize SIMD instructions on packed 64-bit chunks.
79
+
80
+
### N-D Caching & Zero Allocation
81
+
82
+
The pool uses an N-way associative cache to efficiently reuse `BitArray{N}` instances:
83
+
84
+
| Scenario | Allocation |
85
+
|----------|------------|
86
+
| First call with new dims |~944 bytes (new `BitArray{N}` created) |
87
+
| Subsequent call with same dims |**0 bytes** (cached instance reused) |
88
+
| Same ndims, different dims |**0 bytes** (dims/len fields modified in-place) |
89
+
| Different ndims |~944 bytes (new `BitArray{N}` created and cached) |
90
+
91
+
Unlike regular `Array` where dimensions are immutable, `BitArray` allows in-place modification of its `dims` and `len` fields. The pool exploits this to achieve **zero allocation** on repeated calls with matching dimensionality.
92
+
93
+
```julia
94
+
@with_pool pool begin
95
+
# First call: allocates BitMatrix wrapper (~944 bytes)
96
+
m1 =acquire!(pool, Bit, 100, 100)
97
+
98
+
# Rewind to reuse the same slot
99
+
rewind!(pool)
100
+
101
+
# Same dims: 0 allocation (exact cache hit)
102
+
m2 =acquire!(pool, Bit, 100, 100)
103
+
104
+
rewind!(pool)
105
+
106
+
# Different dims but same ndims: 0 allocation (dims modified in-place)
107
+
m3 =acquire!(pool, Bit, 50, 200)
108
+
end
69
109
```
70
110
71
-
## How It Works
111
+
### ⚠️ Important: Do Not Resize
112
+
113
+
While the returned arrays are standard `BitVector` types, they share their underlying memory chunks with the pool.
72
114
73
-
The pool maintains a separate `BitTypedPool` specifically for `BitVector` storage.
74
-
-**Sentinel**: `acquire!(..., Bit, ...)` dispatches to this special pool.
-**Reshaping**: N-D returns `ReshapedArray{Bool, N, SubArray{...}}`.
115
+
!!! warning "Do Not Resize"
116
+
**NEVER** resize (`push!`, `pop!`, `resize!`) a pooled `BitVector` or `BitArray`.
77
117
78
-
This ensures that even for complex shapes, the underlying storage is always a compact `BitVector` reused from the pool.
118
+
The underlying memory is owned and managed by the pool. Resizing it will detach it from the pool or potentially corrupt the shared state. Treat these arrays as **fixed-size** scratch buffers only.
0 commit comments