@@ -16,7 +16,7 @@ function findblockindex(b::AbstractVector, k::Integer)
16
16
bl = blocklasts (b)
17
17
blockidx = _searchsortedfirst (bl, k)
18
18
@assert blockindex != lastindex (bl) + 1 # guaranteed by the @boundscheck above
19
- prevblocklast = blockidx == firstindex (bl) ? first (b)- 1 : bl[blockidx- 1 ]
19
+ prevblocklast = blockidx == firstindex (bl) ? first (b)- oneunit ( eltype (b)) : bl[blockidx- 1 ]
20
20
local_index = k - prevblocklast
21
21
return BlockIndex (blockidx, local_index)
22
22
end
@@ -36,7 +36,7 @@ a vector of block lengths to a `BlockedUnitRange`.
36
36
# Examples
37
37
```jldoctest
38
38
julia> blockedrange(2, [2,2,3]) # first value and block lengths
39
- 3-blocked 7-element BlockedUnitRange{Vector{Int64}}:
39
+ 3-blocked 7-element BlockedUnitRange{Int64, Vector{Int64}}:
40
40
2
41
41
3
42
42
─
@@ -50,31 +50,59 @@ julia> blockedrange(2, [2,2,3]) # first value and block lengths
50
50
51
51
See also [`BlockedOneTo`](@ref).
52
52
"""
53
- struct BlockedUnitRange{CS} <: AbstractBlockedUnitRange{Int ,CS}
54
- first:: Int
53
+ struct BlockedUnitRange{T <: Integer , CS} <: AbstractBlockedUnitRange{T ,CS}
54
+ first:: T
55
55
lasts:: CS
56
56
# assume that lasts is sorted, no checks carried out here
57
- global function _BlockedUnitRange (f, cs:: CS ) where CS
57
+ global function _BlockedUnitRange (f:: T , cs:: CS ) where {T,CS <: AbstractVector{T} }
58
58
Base. require_one_based_indexing (cs)
59
- new {CS} (f, cs)
59
+ return new {T,CS} (f, cs)
60
+ end
61
+ global function _BlockedUnitRange (f:: T , cs:: CS ) where {T,CS<: Tuple{T,Vararg{T}} }
62
+ return new {T,CS} (f, cs)
63
+ end
64
+ global function _BlockedUnitRange (f:: T , cs:: Tuple{} ) where {T}
65
+ return new {T,Tuple{}} (f, cs)
60
66
end
61
67
end
62
68
63
- @inline _BlockedUnitRange (cs) = _BlockedUnitRange (1 ,cs)
69
+ @inline function _BlockedUnitRange (f:: T , cs:: AbstractVector{S} ) where {T,S}
70
+ U = promote_type (T, S)
71
+ return _BlockedUnitRange (convert (U, f), convert .(U, cs))
72
+ end
73
+ @inline function _BlockedUnitRange (f:: T , cs:: Tuple{S,Vararg{S}} ) where {T,S}
74
+ U = promote_type (T, S)
75
+ return _BlockedUnitRange (convert (U, f), convert .(U, cs))
76
+ end
77
+ @inline function _BlockedUnitRange (f, cs:: Tuple )
78
+ return _BlockedUnitRange (f, promote (cs... ))
79
+ end
80
+ @inline _BlockedUnitRange (cs:: AbstractVector ) = _BlockedUnitRange (oneunit (eltype (cs)), cs)
81
+ @inline _BlockedUnitRange (cs:: NTuple ) = _BlockedUnitRange (oneunit (eltype (cs)), cs)
82
+ _BlockedUnitRange (cs:: Tuple ) = _BlockedUnitRange (promote (cs... ))
64
83
65
84
first (b:: BlockedUnitRange ) = b. first
66
85
@inline blocklasts (a:: BlockedUnitRange ) = a. lasts
67
86
68
87
BlockedUnitRange (:: BlockedUnitRange ) = throw (ArgumentError (" Forbidden due to ambiguity" ))
88
+ # Use `accumulate` instead of `cumsum` because it preserves the element type of the block lengths
89
+ _blocklengths2blocklasts (blocks) = accumulate (+ , blocks) # extra level to allow changing default accumulate behaviour
90
+ # Use `cumsum` for fill arrays to output lazy `StepRangeLen` representation
91
+ _blocklengths2blocklasts (blocks:: Fill ) = cumsum (blocks)
92
+ _blocklengths2blocklasts (blocks:: Ones ) = cumsum (blocks)
93
+
94
+ @inline blockfirsts (a:: AbstractBlockedUnitRange ) = [first (a); @views (blocklasts (a)[1 : end - 1 ]) .+ oneunit (eltype (a))]
69
95
70
- @inline blockfirsts (a:: AbstractBlockedUnitRange ) = [first (a); @views (blocklasts (a)[1 : end - 1 ]) .+ 1 ]
71
96
# optimize common cases
72
97
@inline function blockfirsts (a:: AbstractBlockedUnitRange{<:Any,<:Union{Vector, RangeCumsum{<:Any, <:UnitRange}}} )
73
98
v = Vector {eltype(a)} (undef, length (blocklasts (a)))
74
99
v[1 ] = first (a)
75
- v[2 : end ] .= @views (blocklasts (a)[oneto (end - 1 )]) .+ 1
100
+ v[2 : end ] .= @views (blocklasts (a)[oneto (end - 1 )]) .+ oneunit ( eltype (a))
76
101
return v
77
102
end
103
+ @inline function blockfirsts (a:: AbstractBlockedUnitRange{<:Any,<:Tuple} )
104
+ return (first (a), (blocklasts (a)[oneto (end - 1 )] .+ oneunit (eltype (a))). .. )
105
+ end
78
106
79
107
"""
80
108
BlockedOneTo
@@ -124,8 +152,6 @@ BlockedOneTo(::BlockedOneTo) = throw(ArgumentError("Forbidden due to ambiguity")
124
152
125
153
axes (b:: BlockedOneTo ) = (b,)
126
154
127
- _blocklengths2blocklasts (blocks) = cumsum (blocks) # extra level to allow changing default cumsum behaviour
128
-
129
155
"""
130
156
blockedrange(blocklengths::Union{Tuple, AbstractVector})
131
157
blockedrange(first::Int, blocklengths::Union{Tuple, AbstractVector})
@@ -144,27 +170,27 @@ julia> blockedrange([1,2])
144
170
3
145
171
146
172
julia> blockedrange(2, (1,2))
147
- 2-blocked 3-element BlockedUnitRange{Tuple{Int64, Int64}}:
173
+ 2-blocked 3-element BlockedUnitRange{Int64, Tuple{Int64, Int64}}:
148
174
2
149
175
─
150
176
3
151
177
4
152
178
```
153
179
"""
154
180
@inline blockedrange (blocks:: Union{Tuple,AbstractVector} ) = BlockedOneTo (_blocklengths2blocklasts (blocks))
155
- @inline blockedrange (f:: Int , blocks:: Union{Tuple,AbstractVector} ) = _BlockedUnitRange (f, f- 1 .+ _blocklengths2blocklasts (blocks))
181
+ @inline blockedrange (f:: Integer , blocks:: Union{Tuple,AbstractVector} ) = _BlockedUnitRange (f, f- oneunit (f) .+ _blocklengths2blocklasts (blocks))
156
182
157
183
_diff (a:: AbstractVector ) = diff (a)
158
184
_diff (a:: Tuple ) = diff (collect (a))
159
- @inline _blocklengths (a, bl, dbl) = isempty (bl) ? [dbl;] : [first (bl)- first (a)+ 1 ; dbl]
185
+ @inline _blocklengths (a, bl, dbl) = isempty (bl) ? [dbl;] : [first (bl)- first (a)+ oneunit ( eltype (a)) ; dbl]
160
186
@inline function _blocklengths (a:: BlockedOneTo , bl:: RangeCumsum , :: OrdinalRange )
161
187
# the 1:0 is hardcoded here to enable conversions to a Base.OneTo
162
188
isempty (bl) ? oftype (bl. range, 1 : 0 ) : bl. range
163
189
end
164
190
@inline _blocklengths (a, bl) = _blocklengths (a, bl, _diff (bl))
165
191
@inline blocklengths (a:: AbstractBlockedUnitRange ) = _blocklengths (a, blocklasts (a))
166
192
167
- length (a:: AbstractBlockedUnitRange ) = isempty (blocklasts (a)) ? 0 : Integer (last (blocklasts (a))- first (a)+ 1 )
193
+ length (a:: AbstractBlockedUnitRange ) = isempty (blocklasts (a)) ? zero ( eltype (a)) : Integer (last (blocklasts (a))- first (a)+ oneunit ( eltype (a)) )
168
194
169
195
"""
170
196
blockisequal(a::AbstractUnitRange{Int}, b::AbstractUnitRange{Int})
@@ -217,15 +243,15 @@ function Base.convert(::Type{BlockedUnitRange}, axis::AbstractUnitRange{Int})
217
243
f = first (axis)
218
244
_BlockedUnitRange (f, _shift_blocklengths (axis, bl, f))
219
245
end
220
- function Base. convert (:: Type{BlockedUnitRange{CS}} , axis:: AbstractUnitRange{Int} ) where CS
246
+ function Base. convert (:: Type{BlockedUnitRange{T, CS}} , axis:: AbstractUnitRange{Int} ) where {T,CS}
221
247
bl = blocklasts (axis)
222
248
f = first (axis)
223
- _BlockedUnitRange (f , convert (CS, _shift_blocklengths (axis, bl, f)))
249
+ _BlockedUnitRange (convert (T, f) , convert (CS, _shift_blocklengths (axis, bl, f)))
224
250
end
225
251
226
252
Base. unitrange (b:: AbstractBlockedUnitRange ) = first (b): last (b)
227
253
228
- Base. promote_rule (:: Type{<:AbstractBlockedUnitRange} , :: Type{Base.OneTo{Int}} ) = UnitRange{Int}
254
+ Base. promote_rule (:: Type{<:AbstractBlockedUnitRange{T}} , :: Type{Base.OneTo{Int}} ) where {T} = UnitRange{promote_type (T, Int) }
229
255
230
256
function Base. convert (:: Type{BlockedOneTo} , axis:: AbstractUnitRange{Int} )
231
257
first (axis) == 1 || throw (ArgumentError (" first element of range is not 1" ))
@@ -352,10 +378,10 @@ julia> blocksizes(A,2)
352
378
blocksizes (A) = map (blocklengths, axes (A))
353
379
blocksizes (A,i) = blocklengths (axes (A,i))
354
380
355
- axes (b:: AbstractBlockedUnitRange ) = (BlockedOneTo (blocklasts (b) .- (first (b)- 1 )),)
381
+ axes (b:: AbstractBlockedUnitRange ) = (BlockedOneTo (blocklasts (b) .- (first (b)- oneunit ( eltype (b)) )),)
356
382
unsafe_indices (b:: AbstractBlockedUnitRange ) = axes (b)
357
383
# ::Integer works around case where blocklasts might return different type
358
- last (b:: AbstractBlockedUnitRange ):: Integer = isempty (blocklasts (b)) ? first (b)- 1 : last (blocklasts (b))
384
+ last (b:: AbstractBlockedUnitRange ):: Integer = isempty (blocklasts (b)) ? first (b)- oneunit ( eltype (b)) : last (blocklasts (b))
359
385
360
386
# view and indexing are identical for a unitrange
361
387
view (b:: AbstractBlockedUnitRange , K:: Block{1} ) = b[K]
@@ -367,19 +393,19 @@ view(b::AbstractBlockedUnitRange, K::Block{1}) = b[K]
367
393
@boundscheck K in bax || throw (BlockBoundsError (b, k))
368
394
S = first (bax)
369
395
K == S && return first (b): first (cs)
370
- return cs[k- 1 ]+ 1 : cs[k]
396
+ return cs[k- 1 ]+ oneunit ( eltype (b)) : cs[k]
371
397
end
372
398
373
399
@propagate_inbounds function getindex (b:: AbstractBlockedUnitRange , KR:: BlockRange{1} )
374
400
cs = blocklasts (b)
375
- isempty (KR) && return _BlockedUnitRange (1 ,cs[1 : 0 ])
401
+ isempty (KR) && return _BlockedUnitRange (oneunit ( eltype (b)) ,cs[1 : 0 ])
376
402
K,J = first (KR),last (KR)
377
403
k,j = Integer (K),Integer (J)
378
404
bax = blockaxes (b,1 )
379
405
@boundscheck K in bax || throw (BlockBoundsError (b,K))
380
406
@boundscheck J in bax || throw (BlockBoundsError (b,J))
381
407
K == first (bax) && return _BlockedUnitRange (first (b),cs[k: j])
382
- _BlockedUnitRange (cs[k- 1 ]+ 1 ,cs[k: j])
408
+ _BlockedUnitRange (cs[k- 1 ]+ oneunit ( eltype (b)) ,cs[k: j])
383
409
end
384
410
385
411
@propagate_inbounds function getindex (b:: AbstractBlockedUnitRange , KR:: BlockRange{1,Tuple{Base.OneTo{Int}}} )
@@ -442,7 +468,7 @@ function findblock(b::AbstractUnitRange{Int}, k::Integer)
442
468
end
443
469
444
470
"""
445
- blockfirsts(a::AbstractUnitRange{Int })
471
+ blockfirsts(a::AbstractUnitRange{<:Integer })
446
472
447
473
Return the first index of each block of `a`.
448
474
@@ -466,9 +492,9 @@ julia> blockfirsts(b)
466
492
4
467
493
```
468
494
"""
469
- blockfirsts (a:: AbstractUnitRange{Int } ) = Ones {Int } (1 )
495
+ blockfirsts (a:: AbstractUnitRange{<:Integer } ) = Ones {eltype(a) } (1 )
470
496
"""
471
- blocklasts(a::AbstractUnitRange{Int })
497
+ blocklasts(a::AbstractUnitRange{<:Integer })
472
498
473
499
Return the last index of each block of `a`.
474
500
@@ -492,9 +518,9 @@ julia> blocklasts(b)
492
518
6
493
519
```
494
520
"""
495
- blocklasts (a:: AbstractUnitRange{Int } ) = Fill (length (a),1 )
521
+ blocklasts (a:: AbstractUnitRange{<:Integer } ) = Fill (eltype (a)( length (a) ),1 )
496
522
"""
497
- blocklengths(a::AbstractUnitRange{Int })
523
+ blocklengths(a::AbstractUnitRange{<:Integer })
498
524
499
525
Return the length of each block of `a`.
500
526
@@ -518,7 +544,7 @@ julia> blocklengths(b)
518
544
3
519
545
```
520
546
"""
521
- blocklengths (a:: AbstractUnitRange ) = blocklasts (a) .- blockfirsts (a) .+ 1
547
+ blocklengths (a:: AbstractUnitRange{<:Integer} ) = blocklasts (a) .- blockfirsts (a) .+ oneunit ( eltype (a))
522
548
523
549
Base. summary (io:: IO , a:: AbstractBlockedUnitRange ) = _block_summary (io, a)
524
550
@@ -538,7 +564,6 @@ blockaxes(S::Base.Slice) = blockaxes(S.indices)
538
564
_broadcaststyle (_) = Broadcast. DefaultArrayStyle {1} ()
539
565
Base. BroadcastStyle (:: Type{<:AbstractBlockedUnitRange{<:Any,R}} ) where R = _broadcaststyle (Base. BroadcastStyle (R))
540
566
541
-
542
567
# ##
543
568
# Special Fill/Range cases
544
569
#
@@ -548,22 +573,22 @@ Base.BroadcastStyle(::Type{<:AbstractBlockedUnitRange{<:Any,R}}) where R = _broa
548
573
_blocklengths2blocklasts (blocks:: AbstractRange ) = RangeCumsum (blocks)
549
574
function blockfirsts (a:: AbstractBlockedUnitRange{<:Any,Base.OneTo{Int}} )
550
575
first (a) == 1 || error (" Offset axes not supported" )
551
- Base. OneTo {Int } (length (blocklasts (a)))
576
+ Base. OneTo {eltype(a) } (length (blocklasts (a)))
552
577
end
553
578
function blocklengths (a:: AbstractBlockedUnitRange{<:Any,Base.OneTo{Int}} )
554
579
first (a) == 1 || error (" Offset axes not supported" )
555
- Ones {Int } (length (blocklasts (a)))
580
+ Ones {eltype(a) } (length (blocklasts (a)))
556
581
end
557
582
function blockfirsts (a:: AbstractBlockedUnitRange{<:Any,<:AbstractRange} )
558
583
st = step (blocklasts (a))
559
584
first (a) == 1 || error (" Offset axes not supported" )
560
- @assert first (blocklasts (a))- first (a)+ 1 == st
561
- range (1 ; step= st, length= length (blocklasts (a)))
585
+ @assert first (blocklasts (a))- first (a)+ oneunit ( eltype (a)) == st
586
+ range (oneunit ( eltype (a)) ; step= st, length= eltype (a)( length (blocklasts (a) )))
562
587
end
563
588
function blocklengths (a:: AbstractBlockedUnitRange{<:Any,<:AbstractRange} )
564
589
st = step (blocklasts (a))
565
590
first (a) == 1 || error (" Offset axes not supported" )
566
- @assert first (blocklasts (a))- first (a)+ 1 == st
591
+ @assert first (blocklasts (a))- first (a)+ oneunit ( eltype (a)) == st
567
592
Fill (st,length (blocklasts (a)))
568
593
end
569
594
0 commit comments