-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
/
abstractarray.jl
3710 lines (3060 loc) · 118 KB
/
abstractarray.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# This file is a part of Julia. License is MIT: https://julialang.org/license
## Basic functions ##
"""
AbstractArray{T,N}
Supertype for `N`-dimensional arrays (or array-like types) with elements of type `T`.
[`Array`](@ref) and other types are subtypes of this. See the manual section on the
[`AbstractArray` interface](@ref man-interface-array).
See also: [`AbstractVector`](@ref), [`AbstractMatrix`](@ref), [`eltype`](@ref), [`ndims`](@ref).
"""
AbstractArray
convert(::Type{T}, a::T) where {T<:AbstractArray} = a
convert(::Type{AbstractArray{T}}, a::AbstractArray) where {T} = AbstractArray{T}(a)::AbstractArray{T}
convert(::Type{AbstractArray{T,N}}, a::AbstractArray{<:Any,N}) where {T,N} = AbstractArray{T,N}(a)::AbstractArray{T,N}
"""
size(A::AbstractArray, [dim])
Return a tuple containing the dimensions of `A`. Optionally you can specify a
dimension to just get the length of that dimension.
Note that `size` may not be defined for arrays with non-standard indices, in which case [`axes`](@ref)
may be useful. See the manual chapter on [arrays with custom indices](@ref man-custom-indices).
See also: [`length`](@ref), [`ndims`](@ref), [`eachindex`](@ref), [`sizeof`](@ref).
# Examples
```jldoctest
julia> A = fill(1, (2,3,4));
julia> size(A)
(2, 3, 4)
julia> size(A, 2)
3
```
"""
size(t::AbstractArray{T,N}, d) where {T,N} = d::Integer <= N ? size(t)[d] : 1
"""
axes(A, d)
Return the valid range of indices for array `A` along dimension `d`.
See also [`size`](@ref), and the manual chapter on [arrays with custom indices](@ref man-custom-indices).
# Examples
```jldoctest
julia> A = fill(1, (5,6,7));
julia> axes(A, 2)
Base.OneTo(6)
julia> axes(A, 4) == 1:1 # all dimensions d > ndims(A) have size 1
true
```
# Usage note
Each of the indices has to be an `AbstractUnitRange{<:Integer}`, but at the same time can be
a type that uses custom indices. So, for example, if you need a subset, use generalized
indexing constructs like `begin`/`end` or [`firstindex`](@ref)/[`lastindex`](@ref):
```julia
ix = axes(v, 1)
ix[2:end] # will work for eg Vector, but may fail in general
ix[(begin+1):end] # works for generalized indexes
```
"""
function axes(A::AbstractArray{T,N}, d) where {T,N}
@inline
d::Integer <= N ? axes(A)[d] : OneTo(1)
end
"""
axes(A)
Return the tuple of valid indices for array `A`.
See also: [`size`](@ref), [`keys`](@ref), [`eachindex`](@ref).
# Examples
```jldoctest
julia> A = fill(1, (5,6,7));
julia> axes(A)
(Base.OneTo(5), Base.OneTo(6), Base.OneTo(7))
```
"""
function axes(A)
@inline
map(unchecked_oneto, size(A))
end
"""
has_offset_axes(A)
has_offset_axes(A, B, ...)
Return `true` if the indices of `A` start with something other than 1 along any axis.
If multiple arguments are passed, equivalent to `has_offset_axes(A) || has_offset_axes(B) || ...`.
See also [`require_one_based_indexing`](@ref).
"""
has_offset_axes() = false
has_offset_axes(A) = _any_tuple(x->Int(first(x))::Int != 1, false, axes(A)...)
has_offset_axes(A::AbstractVector) = Int(firstindex(A))::Int != 1 # improve performance of a common case (ranges)
has_offset_axes(::Colon) = false
has_offset_axes(::Array) = false
# note: this could call `any` directly if the compiler can infer it. We don't use _any_tuple
# here because it stops full elision in some cases (#49332) and we don't need handling of
# `missing` (has_offset_axes(A) always returns a Bool)
has_offset_axes(A, As...) = has_offset_axes(A) || has_offset_axes(As...)
"""
require_one_based_indexing(A::AbstractArray)
require_one_based_indexing(A,B...)
Throw an `ArgumentError` if the indices of any argument start with something other than `1` along any axis.
See also [`has_offset_axes`](@ref).
!!! compat "Julia 1.2"
This function requires at least Julia 1.2.
"""
require_one_based_indexing(A...) = !has_offset_axes(A...) || throw(ArgumentError("offset arrays are not supported but got an array with index other than 1"))
# Performance optimization: get rid of a branch on `d` in `axes(A, d)`
# for d=1. 1d arrays are heavily used, and the first dimension comes up
# in other applications.
axes1(A::AbstractArray{<:Any,0}) = OneTo(1)
axes1(A::AbstractArray) = (@inline; axes(A)[1])
axes1(iter) = oneto(length(iter))
"""
keys(a::AbstractArray)
Return an efficient array describing all valid indices for `a` arranged in the shape of `a` itself.
The keys of 1-dimensional arrays (vectors) are integers, whereas all other N-dimensional
arrays use [`CartesianIndex`](@ref) to describe their locations. Often the special array
types [`LinearIndices`](@ref) and [`CartesianIndices`](@ref) are used to efficiently
represent these arrays of integers and `CartesianIndex`es, respectively.
Note that the `keys` of an array might not be the most efficient index type; for maximum
performance use [`eachindex`](@ref) instead.
# Examples
```jldoctest
julia> keys([4, 5, 6])
3-element LinearIndices{1, Tuple{Base.OneTo{Int64}}}:
1
2
3
julia> keys([4 5; 6 7])
CartesianIndices((2, 2))
```
"""
keys(a::AbstractArray) = CartesianIndices(axes(a))
keys(a::AbstractVector) = LinearIndices(a)
"""
keytype(T::Type{<:AbstractArray})
keytype(A::AbstractArray)
Return the key type of an array. This is equal to the
[`eltype`](@ref) of the result of `keys(...)`, and is provided
mainly for compatibility with the dictionary interface.
# Examples
```jldoctest
julia> keytype([1, 2, 3]) == Int
true
julia> keytype([1 2; 3 4])
CartesianIndex{2}
```
!!! compat "Julia 1.2"
For arrays, this function requires at least Julia 1.2.
"""
keytype(a::AbstractArray) = keytype(typeof(a))
keytype(::Type{Union{}}, slurp...) = eltype(Union{})
keytype(A::Type{<:AbstractArray}) = CartesianIndex{ndims(A)}
keytype(A::Type{<:AbstractVector}) = Int
valtype(a::AbstractArray) = valtype(typeof(a))
valtype(::Type{Union{}}, slurp...) = eltype(Union{})
"""
valtype(T::Type{<:AbstractArray})
valtype(A::AbstractArray)
Return the value type of an array. This is identical to [`eltype`](@ref) and is
provided mainly for compatibility with the dictionary interface.
# Examples
```jldoctest
julia> valtype(["one", "two", "three"])
String
```
!!! compat "Julia 1.2"
For arrays, this function requires at least Julia 1.2.
"""
valtype(A::Type{<:AbstractArray}) = eltype(A)
prevind(::AbstractArray, i::Integer) = Int(i)-1
nextind(::AbstractArray, i::Integer) = Int(i)+1
"""
eltype(type)
Determine the type of the elements generated by iterating a collection of the given `type`.
For dictionary types, this will be a `Pair{KeyType,ValType}`. The definition
`eltype(x) = eltype(typeof(x))` is provided for convenience so that instances can be passed
instead of types. However the form that accepts a type argument should be defined for new
types.
See also: [`keytype`](@ref), [`typeof`](@ref).
# Examples
```jldoctest
julia> eltype(fill(1f0, (2,2)))
Float32
julia> eltype(fill(0x1, (2,2)))
UInt8
```
"""
eltype(::Type) = Any
eltype(::Type{Bottom}, slurp...) = throw(ArgumentError("Union{} does not have elements"))
eltype(x) = eltype(typeof(x))
eltype(::Type{<:AbstractArray{E}}) where {E} = @isdefined(E) ? E : Any
"""
elsize(type)
Compute the memory stride in bytes between consecutive elements of [`eltype`](@ref)
stored inside the given `type`, if the array elements are stored densely with a
uniform linear stride.
# Examples
```jldoctest
julia> Base.elsize(rand(Float32, 10))
4
```
"""
elsize(A::AbstractArray) = elsize(typeof(A))
"""
ndims(A::AbstractArray) -> Integer
Return the number of dimensions of `A`.
See also: [`size`](@ref), [`axes`](@ref).
# Examples
```jldoctest
julia> A = fill(1, (3,4,5));
julia> ndims(A)
3
```
"""
ndims(::AbstractArray{T,N}) where {T,N} = N::Int
ndims(::Type{<:AbstractArray{<:Any,N}}) where {N} = N::Int
ndims(::Type{Union{}}, slurp...) = throw(ArgumentError("Union{} does not have elements"))
"""
length(collection) -> Integer
Return the number of elements in the collection.
Use [`lastindex`](@ref) to get the last valid index of an indexable collection.
See also: [`size`](@ref), [`ndims`](@ref), [`eachindex`](@ref).
# Examples
```jldoctest
julia> length(1:5)
5
julia> length([1, 2, 3, 4])
4
julia> length([1 2; 3 4])
4
```
"""
length
"""
length(A::AbstractArray)
Return the number of elements in the array, defaults to `prod(size(A))`.
# Examples
```jldoctest
julia> length([1, 2, 3, 4])
4
julia> length([1 2; 3 4])
4
```
"""
length(t::AbstractArray) = (@inline; prod(size(t)))
# `eachindex` is mostly an optimization of `keys`
eachindex(itrs...) = keys(itrs...)
# eachindex iterates over all indices. IndexCartesian definitions are later.
eachindex(A::AbstractVector) = (@inline(); axes1(A))
@noinline function throw_eachindex_mismatch_indices(::IndexLinear, inds...)
throw(DimensionMismatch("all inputs to eachindex must have the same indices, got $(join(inds, ", ", " and "))"))
end
@noinline function throw_eachindex_mismatch_indices(::IndexCartesian, inds...)
throw(DimensionMismatch("all inputs to eachindex must have the same axes, got $(join(inds, ", ", " and "))"))
end
"""
eachindex(A...)
eachindex(::IndexStyle, A::AbstractArray...)
Create an iterable object for visiting each index of an `AbstractArray` `A` in an efficient
manner. For array types that have opted into fast linear indexing (like `Array`), this is
simply the range `1:length(A)` if they use 1-based indexing.
For array types that have not opted into fast linear indexing, a specialized Cartesian
range is typically returned to efficiently index into the array with indices specified
for every dimension.
In general `eachindex` accepts arbitrary iterables, including strings and dictionaries, and returns
an iterator object supporting arbitrary index types (e.g. unevenly spaced or non-integer indices).
If `A` is `AbstractArray` it is possible to explicitly specify the style of the indices that
should be returned by `eachindex` by passing a value having `IndexStyle` type as its first argument
(typically `IndexLinear()` if linear indices are required or `IndexCartesian()` if Cartesian
range is wanted).
If you supply more than one `AbstractArray` argument, `eachindex` will create an
iterable object that is fast for all arguments (typically a [`UnitRange`](@ref)
if all inputs have fast linear indexing, a [`CartesianIndices`](@ref) otherwise).
If the arrays have different sizes and/or dimensionalities, a `DimensionMismatch` exception
will be thrown.
See also [`pairs`](@ref)`(A)` to iterate over indices and values together,
and [`axes`](@ref)`(A, 2)` for valid indices along one dimension.
# Examples
```jldoctest
julia> A = [10 20; 30 40];
julia> for i in eachindex(A) # linear indexing
println("A[", i, "] == ", A[i])
end
A[1] == 10
A[2] == 30
A[3] == 20
A[4] == 40
julia> for i in eachindex(view(A, 1:2, 1:1)) # Cartesian indexing
println(i)
end
CartesianIndex(1, 1)
CartesianIndex(2, 1)
```
"""
eachindex(A::AbstractArray) = (@inline(); eachindex(IndexStyle(A), A))
function eachindex(A::AbstractArray, B::AbstractArray)
@inline
eachindex(IndexStyle(A,B), A, B)
end
function eachindex(A::AbstractArray, B::AbstractArray...)
@inline
eachindex(IndexStyle(A,B...), A, B...)
end
eachindex(::IndexLinear, A::AbstractArray) = (@inline; oneto(length(A)))
eachindex(::IndexLinear, A::AbstractVector) = (@inline; axes1(A))
function eachindex(::IndexLinear, A::AbstractArray, B::AbstractArray...)
@inline
indsA = eachindex(IndexLinear(), A)
_all_match_first(X->eachindex(IndexLinear(), X), indsA, B...) ||
throw_eachindex_mismatch_indices(IndexLinear(), eachindex(A), eachindex.(B)...)
indsA
end
function _all_match_first(f::F, inds, A, B...) where F<:Function
@inline
(inds == f(A)) & _all_match_first(f, inds, B...)
end
_all_match_first(f::F, inds) where F<:Function = true
# keys with an IndexStyle
keys(s::IndexStyle, A::AbstractArray, B::AbstractArray...) = eachindex(s, A, B...)
"""
lastindex(collection) -> Integer
lastindex(collection, d) -> Integer
Return the last index of `collection`. If `d` is given, return the last index of `collection` along dimension `d`.
The syntaxes `A[end]` and `A[end, end]` lower to `A[lastindex(A)]` and
`A[lastindex(A, 1), lastindex(A, 2)]`, respectively.
See also: [`axes`](@ref), [`firstindex`](@ref), [`eachindex`](@ref), [`prevind`](@ref).
# Examples
```jldoctest
julia> lastindex([1,2,4])
3
julia> lastindex(rand(3,4,5), 2)
4
```
"""
lastindex(a::AbstractArray) = (@inline; last(eachindex(IndexLinear(), a)))
lastindex(a, d) = (@inline; last(axes(a, d)))
"""
firstindex(collection) -> Integer
firstindex(collection, d) -> Integer
Return the first index of `collection`. If `d` is given, return the first index of `collection` along dimension `d`.
The syntaxes `A[begin]` and `A[1, begin]` lower to `A[firstindex(A)]` and
`A[1, firstindex(A, 2)]`, respectively.
See also: [`first`](@ref), [`axes`](@ref), [`lastindex`](@ref), [`nextind`](@ref).
# Examples
```jldoctest
julia> firstindex([1,2,4])
1
julia> firstindex(rand(3,4,5), 2)
1
```
"""
firstindex(a::AbstractArray) = (@inline; first(eachindex(IndexLinear(), a)))
firstindex(a, d) = (@inline; first(axes(a, d)))
@propagate_inbounds first(a::AbstractArray) = a[first(eachindex(a))]
"""
first(coll)
Get the first element of an iterable collection. Return the start point of an
[`AbstractRange`](@ref) even if it is empty.
See also: [`only`](@ref), [`firstindex`](@ref), [`last`](@ref).
# Examples
```jldoctest
julia> first(2:2:10)
2
julia> first([1; 2; 3; 4])
1
```
"""
function first(itr)
x = iterate(itr)
x === nothing && throw(ArgumentError("collection must be non-empty"))
x[1]
end
"""
first(itr, n::Integer)
Get the first `n` elements of the iterable collection `itr`, or fewer elements if `itr` is not
long enough.
See also: [`startswith`](@ref), [`Iterators.take`](@ref).
!!! compat "Julia 1.6"
This method requires at least Julia 1.6.
# Examples
```jldoctest
julia> first(["foo", "bar", "qux"], 2)
2-element Vector{String}:
"foo"
"bar"
julia> first(1:6, 10)
1:6
julia> first(Bool[], 1)
Bool[]
```
"""
first(itr, n::Integer) = collect(Iterators.take(itr, n))
# Faster method for vectors
function first(v::AbstractVector, n::Integer)
n < 0 && throw(ArgumentError("Number of elements must be non-negative"))
v[range(begin, length=min(n, checked_length(v)))]
end
"""
last(coll)
Get the last element of an ordered collection, if it can be computed in O(1) time. This is
accomplished by calling [`lastindex`](@ref) to get the last index. Return the end
point of an [`AbstractRange`](@ref) even if it is empty.
See also [`first`](@ref), [`endswith`](@ref).
# Examples
```jldoctest
julia> last(1:2:10)
9
julia> last([1; 2; 3; 4])
4
```
"""
last(a) = a[end]
"""
last(itr, n::Integer)
Get the last `n` elements of the iterable collection `itr`, or fewer elements if `itr` is not
long enough.
!!! compat "Julia 1.6"
This method requires at least Julia 1.6.
# Examples
```jldoctest
julia> last(["foo", "bar", "qux"], 2)
2-element Vector{String}:
"bar"
"qux"
julia> last(1:6, 10)
1:6
julia> last(Float64[], 1)
Float64[]
```
"""
last(itr, n::Integer) = reverse!(collect(Iterators.take(Iterators.reverse(itr), n)))
# Faster method for arrays
function last(v::AbstractVector, n::Integer)
n < 0 && throw(ArgumentError("Number of elements must be non-negative"))
v[range(stop=lastindex(v), length=min(n, checked_length(v)))]
end
"""
strides(A)
Return a tuple of the memory strides in each dimension.
See also: [`stride`](@ref).
# Examples
```jldoctest
julia> A = fill(1, (3,4,5));
julia> strides(A)
(1, 3, 12)
```
"""
function strides end
"""
stride(A, k::Integer)
Return the distance in memory (in number of elements) between adjacent elements in dimension `k`.
See also: [`strides`](@ref).
# Examples
```jldoctest
julia> A = fill(1, (3,4,5));
julia> stride(A,2)
3
julia> stride(A,3)
12
```
"""
function stride(A::AbstractArray, k::Integer)
st = strides(A)
k ≤ ndims(A) && return st[k]
ndims(A) == 0 && return 1
sz = size(A)
s = st[1] * sz[1]
for i in 2:ndims(A)
s += st[i] * sz[i]
end
return s
end
@inline size_to_strides(s, d, sz...) = (s, size_to_strides(s * d, sz...)...)
size_to_strides(s, d) = (s,)
size_to_strides(s) = ()
function isstored(A::AbstractArray{<:Any,N}, I::Vararg{Integer,N}) where {N}
@boundscheck checkbounds(A, I...)
return true
end
# used to compute "end" for last index
function trailingsize(A, n)
s = 1
for i=n:ndims(A)
s *= size(A,i)
end
return s
end
function trailingsize(inds::Indices, n)
s = 1
for i=n:length(inds)
s *= length(inds[i])
end
return s
end
# This version is type-stable even if inds is heterogeneous
function trailingsize(inds::Indices)
@inline
prod(map(length, inds))
end
## Bounds checking ##
# The overall hierarchy is
# `checkbounds(A, I...)` ->
# `checkbounds(Bool, A, I...)` ->
# `checkbounds_indices(Bool, IA, I)`, which recursively calls
# `checkindex` for each dimension
#
# See the "boundscheck" devdocs for more information.
#
# Note this hierarchy has been designed to reduce the likelihood of
# method ambiguities. We try to make `checkbounds` the place to
# specialize on array type, and try to avoid specializations on index
# types; conversely, `checkindex` is intended to be specialized only
# on index type (especially, its last argument).
"""
checkbounds(Bool, A, I...)
Return `true` if the specified indices `I` are in bounds for the given
array `A`. Subtypes of `AbstractArray` should specialize this method
if they need to provide custom bounds checking behaviors; however, in
many cases one can rely on `A`'s indices and [`checkindex`](@ref).
See also [`checkindex`](@ref).
# Examples
```jldoctest
julia> A = rand(3, 3);
julia> checkbounds(Bool, A, 2)
true
julia> checkbounds(Bool, A, 3, 4)
false
julia> checkbounds(Bool, A, 1:3)
true
julia> checkbounds(Bool, A, 1:3, 2:4)
false
```
"""
function checkbounds(::Type{Bool}, A::AbstractArray, I...)
@inline
checkbounds_indices(Bool, axes(A), I)
end
# Linear indexing is explicitly allowed when there is only one (non-cartesian) index;
# indices that do not allow linear indexing (e.g., logical arrays, cartesian indices, etc)
# must add specialized methods to implement their restrictions
function checkbounds(::Type{Bool}, A::AbstractArray, i)
@inline
return checkindex(Bool, eachindex(IndexLinear(), A), i)
end
"""
checkbounds(A, I...)
Throw an error if the specified indices `I` are not in bounds for the given array `A`.
"""
function checkbounds(A::AbstractArray, I...)
@inline
checkbounds(Bool, A, I...) || throw_boundserror(A, I)
nothing
end
"""
checkbounds_indices(Bool, IA, I)
Return `true` if the "requested" indices in the tuple `I` fall within
the bounds of the "permitted" indices specified by the tuple
`IA`. This function recursively consumes elements of these tuples,
usually in a 1-for-1 fashion,
checkbounds_indices(Bool, (IA1, IA...), (I1, I...)) = checkindex(Bool, IA1, I1) &
checkbounds_indices(Bool, IA, I)
Note that [`checkindex`](@ref) is being used to perform the actual
bounds-check for a single dimension of the array.
There are two important exceptions to the 1-1 rule: linear indexing and
CartesianIndex{N}, both of which may "consume" more than one element
of `IA`.
See also [`checkbounds`](@ref).
"""
function checkbounds_indices(::Type{Bool}, inds::Tuple, I::Tuple{Any, Vararg})
@inline
return checkindex(Bool, get(inds, 1, OneTo(1)), I[1])::Bool &
checkbounds_indices(Bool, safe_tail(inds), tail(I))
end
checkbounds_indices(::Type{Bool}, inds::Tuple, ::Tuple{}) = (@inline; all(x->length(x)==1, inds))
# check along a single dimension
"""
checkindex(Bool, inds::AbstractUnitRange, index)
Return `true` if the given `index` is within the bounds of
`inds`. Custom types that would like to behave as indices for all
arrays can extend this method in order to provide a specialized bounds
checking implementation.
See also [`checkbounds`](@ref).
# Examples
```jldoctest
julia> checkindex(Bool, 1:20, 8)
true
julia> checkindex(Bool, 1:20, 21)
false
```
"""
checkindex(::Type{Bool}, inds, i) = throw(ArgumentError(LazyString("unable to check bounds for indices of type ", typeof(i))))
checkindex(::Type{Bool}, inds::AbstractUnitRange, i::Real) = (first(inds) <= i) & (i <= last(inds))
checkindex(::Type{Bool}, inds::IdentityUnitRange, i::Real) = checkindex(Bool, inds.indices, i)
checkindex(::Type{Bool}, inds::OneTo{T}, i::T) where {T<:BitInteger} = unsigned(i - one(i)) < unsigned(last(inds))
checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Colon) = true
checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Slice) = true
checkindex(::Type{Bool}, inds::AbstractUnitRange, i::AbstractRange) =
isempty(i) | (checkindex(Bool, inds, first(i)) & checkindex(Bool, inds, last(i)))
# range like indices with cheap `extrema`
checkindex(::Type{Bool}, inds::AbstractUnitRange, i::LinearIndices) =
isempty(i) | (checkindex(Bool, inds, first(i)) & checkindex(Bool, inds, last(i)))
function checkindex(::Type{Bool}, inds, I::AbstractArray)
@inline
b = true
for i in I
b &= checkindex(Bool, inds, i)
end
b
end
# See also specializations in multidimensional
## Constructors ##
# default arguments to similar()
"""
similar(array, [element_type=eltype(array)], [dims=size(array)])
Create an uninitialized mutable array with the given element type and size, based upon the
given source array. The second and third arguments are both optional, defaulting to the
given array's `eltype` and `size`. The dimensions may be specified either as a single tuple
argument or as a series of integer arguments.
Custom AbstractArray subtypes may choose which specific array type is best-suited to return
for the given element type and dimensionality. If they do not specialize this method, the
default is an `Array{element_type}(undef, dims...)`.
For example, `similar(1:10, 1, 4)` returns an uninitialized `Array{Int,2}` since ranges are
neither mutable nor support 2 dimensions:
```julia-repl
julia> similar(1:10, 1, 4)
1×4 Matrix{Int64}:
4419743872 4374413872 4419743888 0
```
Conversely, `similar(trues(10,10), 2)` returns an uninitialized `BitVector` with two
elements since `BitArray`s are both mutable and can support 1-dimensional arrays:
```julia-repl
julia> similar(trues(10,10), 2)
2-element BitVector:
0
0
```
Since `BitArray`s can only store elements of type [`Bool`](@ref), however, if you request a
different element type it will create a regular `Array` instead:
```julia-repl
julia> similar(falses(10), Float64, 2, 4)
2×4 Matrix{Float64}:
2.18425e-314 2.18425e-314 2.18425e-314 2.18425e-314
2.18425e-314 2.18425e-314 2.18425e-314 2.18425e-314
```
See also: [`undef`](@ref), [`isassigned`](@ref).
"""
similar(a::AbstractArray{T}) where {T} = similar(a, T)
similar(a::AbstractArray, ::Type{T}) where {T} = similar(a, T, to_shape(axes(a)))
similar(a::AbstractArray{T}, dims::Tuple) where {T} = similar(a, T, to_shape(dims))
similar(a::AbstractArray{T}, dims::DimOrInd...) where {T} = similar(a, T, to_shape(dims))
similar(a::AbstractArray, ::Type{T}, dims::DimOrInd...) where {T} = similar(a, T, to_shape(dims))
# Similar supports specifying dims as either Integers or AbstractUnitRanges or any mixed combination
# thereof. Ideally, we'd just convert Integers to OneTos and then call a canonical method with the axes,
# but we don't want to require all AbstractArray subtypes to dispatch on Base.OneTo. So instead we
# define this method to convert supported axes to Ints, with the expectation that an offset array
# package will define a method with dims::Tuple{Union{Integer, UnitRange}, Vararg{Union{Integer, UnitRange}}}
similar(a::AbstractArray, ::Type{T}, dims::Tuple{Union{Integer, OneTo}, Vararg{Union{Integer, OneTo}}}) where {T} = similar(a, T, to_shape(dims))
similar(a::AbstractArray, ::Type{T}, dims::Tuple{Integer, Vararg{Integer}}) where {T} = similar(a, T, to_shape(dims))
# similar creates an Array by default
similar(a::AbstractArray, ::Type{T}, dims::Dims{N}) where {T,N} = Array{T,N}(undef, dims)
to_shape(::Tuple{}) = ()
to_shape(dims::Dims) = dims
to_shape(dims::DimsOrInds) = map(to_shape, dims)::DimsOrInds
# each dimension
to_shape(i::Int) = i
to_shape(i::Integer) = Int(i)
to_shape(r::OneTo) = Int(last(r))
to_shape(r::AbstractUnitRange) = r
"""
similar(storagetype, axes)
Create an uninitialized mutable array analogous to that specified by
`storagetype`, but with `axes` specified by the last
argument.
**Examples**:
similar(Array{Int}, axes(A))
creates an array that "acts like" an `Array{Int}` (and might indeed be
backed by one), but which is indexed identically to `A`. If `A` has
conventional indexing, this will be identical to
`Array{Int}(undef, size(A))`, but if `A` has unconventional indexing then the
indices of the result will match `A`.
similar(BitArray, (axes(A, 2),))
would create a 1-dimensional logical array whose indices match those
of the columns of `A`.
"""
similar(::Type{T}, dims::DimOrInd...) where {T<:AbstractArray} = similar(T, dims)
similar(::Type{T}, shape::Tuple{Union{Integer, OneTo}, Vararg{Union{Integer, OneTo}}}) where {T<:AbstractArray} = similar(T, to_shape(shape))
similar(::Type{T}, dims::Dims) where {T<:AbstractArray} = T(undef, dims)
"""
empty(v::AbstractVector, [eltype])
Create an empty vector similar to `v`, optionally changing the `eltype`.
See also: [`empty!`](@ref), [`isempty`](@ref), [`isassigned`](@ref).
# Examples
```jldoctest
julia> empty([1.0, 2.0, 3.0])
Float64[]
julia> empty([1.0, 2.0, 3.0], String)
String[]
```
"""
empty(a::AbstractVector{T}, ::Type{U}=T) where {T,U} = similar(a, U, 0)
# like empty, but should return a mutable collection, a Vector by default
emptymutable(a::AbstractVector{T}, ::Type{U}=T) where {T,U} = Vector{U}()
emptymutable(itr, ::Type{U}) where {U} = Vector{U}()
"""
copy!(dst, src) -> dst
In-place [`copy`](@ref) of `src` into `dst`, discarding any pre-existing
elements in `dst`.
If `dst` and `src` are of the same type, `dst == src` should hold after
the call. If `dst` and `src` are vector types, they must have equal
offset. If `dst` and `src` are multidimensional arrays, they must have
equal [`axes`](@ref).
$(_DOCS_ALIASING_WARNING)
See also [`copyto!`](@ref).
!!! note
When operating on vector types, if `dst` and `src` are not of the
same length, `dst` is resized to `length(src)` prior to the `copy`.
!!! compat "Julia 1.1"
This method requires at least Julia 1.1. In Julia 1.0 this method
is available from the `Future` standard library as `Future.copy!`.
"""
function copy!(dst::AbstractVector, src::AbstractVector)
firstindex(dst) == firstindex(src) || throw(ArgumentError(
"vectors must have the same offset for copy! (consider using `copyto!`)"))
if length(dst) != length(src)
resize!(dst, length(src))
end
copyto!(dst, src)
end
function copy!(dst::AbstractArray, src::AbstractArray)
axes(dst) == axes(src) || throw(ArgumentError(
"arrays must have the same axes for copy! (consider using `copyto!`)"))
copyto!(dst, src)
end
## from general iterable to any array
# This is `Experimental.@max_methods 1 function copyto! end`, which is not
# defined at this point in bootstrap.
typeof(function copyto! end).name.max_methods = UInt8(1)
function copyto!(dest::AbstractArray, src)
destiter = eachindex(dest)
y = iterate(destiter)
for x in src
y === nothing &&
throw(ArgumentError("destination has fewer elements than required"))
dest[y[1]] = x
y = iterate(destiter, y[2])
end
return dest
end
function copyto!(dest::AbstractArray, dstart::Integer, src)
i = Int(dstart)
if haslength(src) && length(dest) > 0
@boundscheck checkbounds(dest, i:(i + length(src) - 1))
for x in src
@inbounds dest[i] = x
i += 1
end
else
for x in src
dest[i] = x
i += 1
end
end
return dest
end
# copy from an some iterable object into an AbstractArray
function copyto!(dest::AbstractArray, dstart::Integer, src, sstart::Integer)
if (sstart < 1)
throw(ArgumentError(LazyString("source start offset (",sstart,") is < 1")))
end
y = iterate(src)
for j = 1:(sstart-1)
if y === nothing
throw(ArgumentError(LazyString(
"source has fewer elements than required, ",
"expected at least ", sstart,", got ", j-1)))
end
y = iterate(src, y[2])
end
if y === nothing
throw(ArgumentError(LazyString(
"source has fewer elements than required, ",
"expected at least ",sstart," got ", sstart-1)))
end
i = Int(dstart)
while y !== nothing
val, st = y
dest[i] = val
i += 1
y = iterate(src, st)
end
return dest
end
# this method must be separate from the above since src might not have a length
function copyto!(dest::AbstractArray, dstart::Integer, src, sstart::Integer, n::Integer)
n < 0 && throw(ArgumentError(LazyString("tried to copy n=",n,
", elements, but n should be non-negative")))
n == 0 && return dest
dmax = dstart + n - 1
inds = LinearIndices(dest)