Skip to content

Commit bd9d36d

Browse files
committed
Add blockpush!
1 parent fd81415 commit bd9d36d

File tree

4 files changed

+86
-10
lines changed

4 files changed

+86
-10
lines changed

docs/src/lib/public.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ undef_blocks
5151
UndefBlocksInitializer
5252
mortar
5353
blockappend!
54+
blockpush!
5455
Base.append!
5556
Base.push!
5657
Base.pushfirst!

src/BlockArrays.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export undef_blocks, undef, findblock, findblockindex
1616

1717
export khatri_rao
1818

19-
export blockappend!
19+
export blockappend!, blockpush!
2020

2121
import Base: @propagate_inbounds, Array, to_indices, to_index,
2222
unsafe_indices, first, last, size, length, unsafe_length,

src/blockdeque.jl

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ blockappend!(dest::BlockVector, s1, s2, sources...) =
3131
foldl(blockappend!, (s1, s2, sources...); init = dest)
3232

3333
function blockappend!(dest::BlockVector{<:Any,T}, src::BlockVector{<:Any,T}) where {T}
34-
isempty(src) && return dest
3534
append!(dest.blocks, src.blocks)
3635
offset = last(dest.axes[1]) + 1 - src.axes[1].first
3736
append!(dest.axes[1].lasts, (n + offset for n in src.axes[1].lasts))
@@ -43,28 +42,70 @@ function blockappend!(
4342
src::PseudoBlockVector{<:Any,T},
4443
) where {T}
4544
if blocklength(src) == 1
46-
return blockappend!(dest, src.blocks)
45+
return _blockpush!(dest, src.blocks)
4746
else
4847
return blockappend_fallback!(dest, src)
4948
end
5049
end
5150

52-
function blockappend!(
51+
blockappend!(
5352
dest::BlockVector{<:Any,<:AbstractArray{T}},
5453
src::T,
55-
) where {T<:AbstractVector}
56-
isempty(src) && return dest
57-
push!(dest.blocks, src)
58-
push!(dest.axes[1].lasts, last(dest.axes[1]) + length(src))
59-
return dest
60-
end
54+
) where {T<:AbstractVector} = _blockpush!(dest, src)
6155

6256
blockappend!(dest::BlockVector{<:Any,<:Any}, src::AbstractVector) =
6357
blockappend_fallback!(dest, src)
6458

6559
blockappend_fallback!(dest::BlockVector{<:Any,<:AbstractArray{T}}, src) where {T} =
6660
blockappend!(dest, mortar([convert(T, @view src[b]) for b in blockaxes(src, 1)]))
6761

62+
"""
63+
blockpush!(dest::BlockVector, blocks...) -> dest
64+
65+
Push `blocks` to `dest`.
66+
67+
This function avoids copying the elements of the `blocks` when these blocks
68+
are compatible with `dest`. Importantly, this means that mutating `blocks`
69+
afterwards alters the items in `dest` and it may even break the invariance
70+
of `dest` if the length of `blocks` are changed.
71+
72+
# Examples
73+
```jldoctest
74+
julia> using BlockArrays
75+
76+
julia> blockpush!(mortar([[1], [2, 3]]), [4, 5], [6])
77+
4-blocked 6-element BlockArray{Int64,1}:
78+
1
79+
80+
2
81+
3
82+
83+
4
84+
5
85+
86+
6
87+
```
88+
"""
89+
blockpush!(dest::BlockVector, blocks...) = foldl(blockpush!, blocks; init = dest)
90+
91+
blockpush!(dest::BlockVector{<:Any,<:AbstractArray{T}}, block::T) where {T} =
92+
_blockpush!(dest, block)
93+
94+
function blockpush!(dest::BlockVector, block)
95+
if Iterators.IteratorSize(block) isa Union{Base.HasShape,Base.HasLength}
96+
newblock = copyto!(eltype(dest.blocks)(undef, length(block)), block)
97+
else
98+
newblock = foldl(push!, block; init = eltype(dest.blocks)(undef, 0))
99+
end
100+
return _blockpush!(dest, newblock)
101+
end
102+
103+
function _blockpush!(dest, block)
104+
push!(dest.blocks, block)
105+
push!(dest.axes[1].lasts, last(dest.axes[1]) + length(block))
106+
return dest
107+
end
108+
68109
"""
69110
append!(dest::BlockVector, sources...)
70111

test/test_blockdeque.jl

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,40 @@ using BlockArrays, Test
4545
@test dest[6] == 6
4646
end
4747
end
48+
49+
@testset "empty blocks" begin
50+
dest = mortar([[1, 2, 3], [4, 5]])
51+
@test blockappend!(dest, mortar([Int[]])) === dest == 1:5
52+
@test blocklength(dest) == 3
53+
@test blockappend!(dest, mortar([Int[], Int[]])) === dest == 1:5
54+
@test blocklength(dest) == 5
55+
end
56+
end
57+
58+
@testset "blockpush!(::BlockVector, _)" begin
59+
dest = mortar([[1, 2, 3], [4, 5]])
60+
@test blockpush!(dest, [6]) === dest == 1:6
61+
@test blocklength(dest) == 3
62+
63+
dest = mortar([[1, 2, 3], [4, 5]])
64+
@test blockpush!(dest, [6.0]) === dest == 1:6
65+
@test blocklength(dest) == 3
66+
67+
dest = mortar([[1, 2, 3], [4, 5]])
68+
@test blockpush!(dest, Int[]) === dest == 1:5
69+
@test blocklength(dest) == 3
70+
71+
dest = mortar([[1, 2, 3], [4, 5]])
72+
@test blockpush!(dest, (6, 7.0)) === dest == 1:7
73+
@test blocklength(dest) == 3
74+
75+
dest = mortar([[1, 2, 3], [4, 5]])
76+
@test blockpush!(dest, (x for x in 6:7 if iseven(x))) === dest == 1:6
77+
@test blocklength(dest) == 3
78+
79+
dest = mortar([[1, 2, 3], [4, 5]])
80+
@test blockpush!(dest, [6], Int[], 7:8) === dest == 1:8
81+
@test blocklength(dest) == 5
4882
end
4983

5084
@testset "append!(::BlockVector, _)" begin

0 commit comments

Comments
 (0)