|
| 1 | +# Note: Functions surrounded by a comment blocks are there because `Vararg` is sitll allocating. |
| 2 | +# When Vararg is fast enough, they can simply be removed |
| 3 | + |
1 | 4 | ####################
|
2 | 5 | # PseudoBlockArray #
|
3 | 6 | ####################
|
|
39 | 42 | # Indexing #
|
40 | 43 | ############
|
41 | 44 |
|
| 45 | +# vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv # |
| 46 | +function Base.getindex{T, N}(block_arr::PseudoBlockArray{T, N}, i::Int) |
| 47 | + @boundscheck checkbounds(block_arr, ) |
| 48 | + @inbounds v = block_arr.blocks[i] |
| 49 | + return v |
| 50 | +end |
| 51 | + |
| 52 | +function Base.getindex{T, N}(block_arr::PseudoBlockArray{T, N}, i::Int, j::Int) |
| 53 | + @boundscheck checkbounds(block_arr, i, j) |
| 54 | + @inbounds v = block_arr.blocks[i, j] |
| 55 | + return v |
| 56 | +end |
| 57 | +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # |
| 58 | + |
42 | 59 | function Base.getindex{T, N}(block_arr::PseudoBlockArray{T, N}, i::Vararg{Int, N})
|
43 | 60 | @boundscheck checkbounds(block_arr, i...)
|
44 | 61 | @inbounds v = block_arr.blocks[i...]
|
45 | 62 | return v
|
46 | 63 | end
|
47 | 64 |
|
| 65 | +# vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv # |
| 66 | +function Base.setindex!{T, N}(block_arr::PseudoBlockArray{T, N}, v, i::Int) |
| 67 | + @boundscheck checkbounds(block_arr, i) |
| 68 | + @inbounds block_arr.blocks[i] = v |
| 69 | + return block_arr |
| 70 | +end |
| 71 | + |
| 72 | +function Base.setindex!{T, N}(block_arr::PseudoBlockArray{T, N}, v, i::Int, j::Int) |
| 73 | + @boundscheck checkbounds(block_arr, i, j) |
| 74 | + @inbounds block_arr.blocks[i, j] = v |
| 75 | + return block_arr |
| 76 | +end |
| 77 | +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # |
| 78 | + |
48 | 79 | function Base.setindex!{T, N}(block_arr::PseudoBlockArray{T, N}, v, i::Vararg{Int, N})
|
49 | 80 | @boundscheck checkbounds(block_arr, i...)
|
50 | 81 | @inbounds block_arr.blocks[i...] = v
|
51 | 82 | return block_arr
|
52 | 83 | end
|
53 | 84 |
|
| 85 | +# vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv # |
| 86 | +function getblock{T,N}(block_arr::PseudoBlockArray{T,N}, block_i::Int) |
| 87 | + range = globalrange(block_arr.block_sizes, (block_i,)) |
| 88 | + return block_arr.blocks[range[1]] |
| 89 | +end |
| 90 | + |
| 91 | +function getblock{T,N}(block_arr::PseudoBlockArray{T,N}, block_i::Int, block_j::Int) |
| 92 | + range = globalrange(block_arr.block_sizes, (block_i, block_j)) |
| 93 | + return block_arr.blocks[range[1], range[2]] |
| 94 | +end |
| 95 | +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # |
| 96 | + |
54 | 97 | function getblock{T,N}(block_arr::PseudoBlockArray{T,N}, block::Vararg{Int, N})
|
55 | 98 | range = globalrange(block_arr.block_sizes, block)
|
56 | 99 | return block_arr.blocks[range...]
|
57 | 100 | end
|
58 | 101 |
|
59 |
| -# TODO: Can this be written efficiently without a generated function? |
60 |
| -@generated function getblock!{T,N}(x, block_arr::PseudoBlockArray{T,N}, block::Vararg{Int, N}) |
61 |
| - return quote |
| 102 | +function _check_getblock!{T, N}(blockrange, x, block_arr::PseudoBlockArray{T,N}, block::NTuple{N, Int}) |
| 103 | + for i in 1:N |
| 104 | + if size(x, i) != length(blockrange[i]) |
| 105 | + throw(ArgumentError(string("attempt to assign a ", ntuple(i -> block_arr.block_sizes[i, block[i]], Val{N}), " block to a $(size(x)) array"))) |
| 106 | + end |
| 107 | + end |
| 108 | +end |
62 | 109 |
|
63 |
| - blockrange = globalrange(block_arr.block_sizes, block) |
| 110 | +# vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv # |
| 111 | +@propagate_inbounds function getblock!{T}(x, block_arr::PseudoBlockArray{T,1}, block_i::Int) |
| 112 | + blockrange = globalrange(block_arr.block_sizes, (block_i,)) |
| 113 | + @boundscheck _check_getblock!(blockrange, x, block_arr, (block_i,)) |
64 | 114 |
|
65 |
| - @boundscheck begin |
66 |
| - for i in 1:N |
67 |
| - if size(x, i) != length(blockrange[i]) |
68 |
| - throw(ArgumentError(string("attempt to assign a ", ntuple(i -> block_arr.block_sizes[i, block[i]], Val{N}), " block to a $(size(x)) array"))) |
69 |
| - end |
70 |
| - end |
| 115 | + arr = block_arr.blocks |
| 116 | + k_1 = 1 |
| 117 | + @inbounds for i in blockrange[1] |
| 118 | + x[k_1] = arr[i] |
| 119 | + k_1 += 1 |
| 120 | + end |
| 121 | + return x |
| 122 | +end |
| 123 | + |
| 124 | +@propagate_inbounds function getblock!{T}(x, block_arr::PseudoBlockArray{T,2}, block_i::Int, block_j::Int) |
| 125 | + blockrange = globalrange(block_arr.block_sizes, (block_i,block_j)) |
| 126 | + @boundscheck _check_getblock!(blockrange, x, block_arr, (block_i, block_j)) |
| 127 | + |
| 128 | + arr = block_arr.blocks |
| 129 | + k_2 = 1 |
| 130 | + @inbounds for j in blockrange[2] |
| 131 | + k_1 = 1 |
| 132 | + for i in blockrange[1] |
| 133 | + x[k_1, k_2] = arr[i, j] |
| 134 | + k_1 += 1 |
71 | 135 | end
|
| 136 | + k_2 += 1 |
| 137 | + end |
| 138 | + return x |
| 139 | +end |
| 140 | +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # |
| 141 | + |
| 142 | +@generated function getblock!{T,N}(x, block_arr::PseudoBlockArray{T,N}, block::Vararg{Int, N}) |
| 143 | + return quote |
| 144 | + blockrange = globalrange(block_arr.block_sizes, block) |
| 145 | + @boundscheck _check_getblock!(blockrange, x, block_arr, block) |
72 | 146 |
|
73 | 147 | arr = block_arr.blocks
|
74 | 148 | @nexprs $N d -> k_d = 1
|
|
81 | 155 | end
|
82 | 156 | end
|
83 | 157 |
|
84 |
| -# TODO: Can this be written efficiently without a generated function? |
85 |
| -@generated function setblock!{T, N, R}(block_arr::PseudoBlockArray{T, N, R}, v, block::Vararg{Int, N}) |
86 |
| - return quote |
87 |
| - @boundscheck begin # TODO: Check if this eliminates the boundscheck with @inbounds |
88 |
| - for i in 1:N |
89 |
| - if size(v, i) != block_arr.block_sizes[i, block[i]] |
90 |
| - throw(ArgumentError(string("attempt to assign a $(size(v)) array to a ", ntuple(i -> block_arr.block_sizes[i][block[i]], Val{N}), " block"))) |
91 |
| - end |
92 |
| - end |
| 158 | +function _check_setblock!{T, N}(blockrange, x, block_arr::PseudoBlockArray{T,N}, block::NTuple{N, Int}) |
| 159 | + for i in 1:N |
| 160 | + if size(x, i) != block_arr.block_sizes[i, block[i]] |
| 161 | + throw(ArgumentError(string("attempt to assign a $(size(x)) array to a ", ntuple(i -> block_arr.block_sizes[i][block[i]], Val{N}), " block"))) |
93 | 162 | end
|
| 163 | + end |
| 164 | +end |
| 165 | + |
| 166 | +# vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv # |
| 167 | +@propagate_inbounds function setblock!{T}(block_arr::PseudoBlockArray{T,1}, x, block_i::Int) |
| 168 | + blockrange = globalrange(block_arr.block_sizes, (block_i,)) |
| 169 | + @boundscheck _check_setblock!(blockrange, x, block_arr, (block_i,)) |
| 170 | + |
| 171 | + arr = block_arr.blocks |
| 172 | + k_1 = 1 |
| 173 | + @inbounds for i in blockrange[1] |
| 174 | + arr[i] = x[k_1] |
| 175 | + k_1 += 1 |
| 176 | + end |
| 177 | + return x |
| 178 | +end |
94 | 179 |
|
| 180 | +@propagate_inbounds function setblock!{T}(block_arr::PseudoBlockArray{T,2}, x, block_i::Int, block_j::Int) |
| 181 | + blockrange = globalrange(block_arr.block_sizes, (block_i,block_j)) |
| 182 | + @boundscheck _check_setblock!(blockrange, x, block_arr, (block_i, block_j)) |
| 183 | + |
| 184 | + arr = block_arr.blocks |
| 185 | + k_2 = 1 |
| 186 | + @inbounds for j in blockrange[2] |
| 187 | + k_1 = 1 |
| 188 | + for i in blockrange[1] |
| 189 | + arr[i, j] = x[k_1, k_2] |
| 190 | + k_1 += 1 |
| 191 | + end |
| 192 | + k_2 += 1 |
| 193 | + end |
| 194 | + return x |
| 195 | +end |
| 196 | +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ # |
| 197 | + |
| 198 | +@generated function setblock!{T, N}(block_arr::PseudoBlockArray{T, N}, x, block::Vararg{Int, N}) |
| 199 | + return quote |
95 | 200 | blockrange = globalrange(block_arr.block_sizes, block)
|
| 201 | + @boundscheck _check_setblock!(blockrange, x, block_arr, block) |
96 | 202 | arr = block_arr.blocks
|
97 | 203 | @nexprs $N d -> k_d = 1
|
98 | 204 | @inbounds begin
|
99 | 205 | @nloops $N i (d->(blockrange[d])) (d-> k_{d-1}=1) (d-> k_d+=1) begin
|
100 |
| - (@nref $N arr i) = (@nref $N v k) |
| 206 | + (@nref $N arr i) = (@nref $N x k) |
101 | 207 | end
|
102 | 208 | end
|
103 | 209 | end
|
|
0 commit comments