@@ -122,8 +122,50 @@ const DenseVecOrMat{T} = Union{DenseVector{T}, DenseMatrix{T}}
122
122
123
123
using Core: arraysize, arrayset, const_arrayref
124
124
125
+ """
126
+ @_safeindex
127
+
128
+ This internal macro converts:
129
+ - `getindex(xs::Tuple, )` -> `__inbounds_getindex(args...)`
130
+ - `setindex!(xs::Vector, args...)` -> `__inbounds_setindex!(xs, args...)`
131
+ to tell the compiler that indexing operations within the applied expression are always
132
+ inbounds and do not need to taint `:consistent` and `:nothrow`.
133
+ """
134
+ macro _safeindex (ex)
135
+ return esc (_safeindex (__module__, ex))
136
+ end
137
+ function _safeindex (__module__, ex)
138
+ isa (ex, Expr) || return ex
139
+ if ex. head === :(= )
140
+ lhs = arrayref (true , ex. args, 1 )
141
+ if isa (lhs, Expr) && lhs. head === :ref # xs[i] = x
142
+ rhs = arrayref (true , ex. args, 2 )
143
+ xs = arrayref (true , lhs. args, 1 )
144
+ args = Vector {Any} (undef, length (lhs. args)- 1 )
145
+ for i = 2 : length (lhs. args)
146
+ arrayset (true , args, _safeindex (__module__, arrayref (true , lhs. args, i)), i- 1 )
147
+ end
148
+ return Expr (:call , GlobalRef (__module__, :__inbounds_setindex! ), xs, _safeindex (__module__, rhs), args... )
149
+ end
150
+ elseif ex. head === :ref # xs[i]
151
+ return Expr (:call , GlobalRef (__module__, :__inbounds_getindex ), ex. args... )
152
+ end
153
+ args = Vector {Any} (undef, length (ex. args))
154
+ for i = 1 : length (ex. args)
155
+ arrayset (true , args, _safeindex (__module__, arrayref (true , ex. args, i)), i)
156
+ end
157
+ return Expr (ex. head, args... )
158
+ end
159
+
125
160
vect () = Vector {Any} ()
126
- vect (X:: T... ) where {T} = T[ X[i] for i = 1 : length (X) ]
161
+ function vect (X:: T... ) where T
162
+ @_terminates_locally_meta
163
+ vec = Vector {T} (undef, length (X))
164
+ @_safeindex for i = 1 : length (X)
165
+ vec[i] = X[i]
166
+ end
167
+ return vec
168
+ end
127
169
128
170
"""
129
171
vect(X...)
321
363
322
364
function _copyto_impl! (dest:: Array , doffs:: Integer , src:: Array , soffs:: Integer , n:: Integer )
323
365
n == 0 && return dest
324
- n > 0 || _throw_argerror ()
366
+ n > 0 || _throw_argerror (" Number of elements to copy must be nonnegative. " )
325
367
@boundscheck checkbounds (dest, doffs: doffs+ n- 1 )
326
368
@boundscheck checkbounds (src, soffs: soffs+ n- 1 )
327
369
unsafe_copyto! (dest, doffs, src, soffs, n)
331
373
# Outlining this because otherwise a catastrophic inference slowdown
332
374
# occurs, see discussion in #27874.
333
375
# It is also mitigated by using a constant string.
334
- function _throw_argerror ()
335
- @noinline
336
- throw (ArgumentError (" Number of elements to copy must be nonnegative." ))
337
- end
376
+ _throw_argerror (s) = (@noinline ; throw (ArgumentError (s)))
338
377
339
378
copyto! (dest:: Array , src:: Array ) = copyto! (dest, 1 , src, 1 , length (src))
340
379
@@ -397,9 +436,11 @@ julia> getindex(Int8, 1, 2, 3)
397
436
```
398
437
"""
399
438
function getindex (:: Type{T} , vals... ) where T
439
+ @inline
440
+ @_effect_free_terminates_locally_meta
400
441
a = Vector {T} (undef, length (vals))
401
442
if vals isa NTuple
402
- @inbounds for i in 1 : length (vals)
443
+ @_safeindex for i in 1 : length (vals)
403
444
a[i] = vals[i]
404
445
end
405
446
else
@@ -412,9 +453,21 @@ function getindex(::Type{T}, vals...) where T
412
453
return a
413
454
end
414
455
456
+ # safe version
457
+ function getindex (:: Type{T} , vals:: T... ) where T
458
+ @inline
459
+ @_effect_free_terminates_locally_meta
460
+ a = Vector {T} (undef, length (vals))
461
+ @_safeindex for i in 1 : length (vals)
462
+ a[i] = vals[i]
463
+ end
464
+ return a
465
+ end
466
+
415
467
function getindex (:: Type{Any} , @nospecialize vals... )
468
+ @_effect_free_terminates_locally_meta
416
469
a = Vector {Any} (undef, length (vals))
417
- @inbounds for i = 1 : length (vals)
470
+ @_safeindex for i = 1 : length (vals)
418
471
a[i] = vals[i]
419
472
end
420
473
return a
@@ -966,10 +1019,16 @@ Dict{String, Int64} with 2 entries:
966
1019
"""
967
1020
function setindex! end
968
1021
969
- @eval setindex! (A:: Array{T} , x, i1:: Int ) where {T} = arrayset ($ (Expr (:boundscheck )), A, convert (T,x):: T , i1)
1022
+ @eval setindex! (A:: Array{T} , x, i1:: Int ) where {T} =
1023
+ arrayset ($ (Expr (:boundscheck )), A, convert (T,x):: T , i1)
970
1024
@eval setindex! (A:: Array{T} , x, i1:: Int , i2:: Int , I:: Int... ) where {T} =
971
1025
(@inline ; arrayset ($ (Expr (:boundscheck )), A, convert (T,x):: T , i1, i2, I... ))
972
1026
1027
+ __inbounds_setindex! (A:: Array{T} , x, i1:: Int ) where {T} =
1028
+ arrayset (false , A, convert (T,x):: T , i1)
1029
+ __inbounds_setindex! (A:: Array{T} , x, i1:: Int , i2:: Int , I:: Int... ) where {T} =
1030
+ (@inline ; arrayset (false , A, convert (T,x):: T , i1, i2, I... ))
1031
+
973
1032
# This is redundant with the abstract fallbacks but needed and helpful for bootstrap
974
1033
function setindex! (A:: Array , X:: AbstractArray , I:: AbstractVector{Int} )
975
1034
@_propagate_inbounds_meta
@@ -1055,26 +1114,27 @@ See also [`pushfirst!`](@ref).
1055
1114
"""
1056
1115
function push! end
1057
1116
1058
- function push! (a:: Array{T,1 } , item) where T
1117
+ function push! (a:: Vector{T } , item) where T
1059
1118
# convert first so we don't grow the array if the assignment won't work
1060
1119
itemT = convert (T, item)
1061
1120
_growend! (a, 1 )
1062
- @inbounds a[end ] = itemT
1121
+ @_safeindex a[length (a) ] = itemT
1063
1122
return a
1064
1123
end
1065
1124
1066
1125
# specialize and optimize the single argument case
1067
1126
function push! (a:: Vector{Any} , @nospecialize x)
1068
1127
_growend! (a, 1 )
1069
- arrayset ( true , a, x, length (a))
1128
+ @_safeindex a[ length (a)] = x
1070
1129
return a
1071
1130
end
1072
1131
function push! (a:: Vector{Any} , @nospecialize x... )
1132
+ @_terminates_locally_meta
1073
1133
na = length (a)
1074
1134
nx = length (x)
1075
1135
_growend! (a, nx)
1076
- for i = 1 : nx
1077
- arrayset ( true , a, x[i], na + i)
1136
+ @_safeindex for i = 1 : nx
1137
+ a[na + i] = x[i]
1078
1138
end
1079
1139
return a
1080
1140
end
@@ -1129,10 +1189,11 @@ push!(a::AbstractVector, iter...) = append!(a, iter)
1129
1189
append! (a:: AbstractVector , iter... ) = foldl (append!, iter, init= a)
1130
1190
1131
1191
function _append! (a, :: Union{HasLength,HasShape} , iter)
1192
+ @_terminates_locally_meta
1132
1193
n = length (a)
1133
1194
i = lastindex (a)
1134
1195
resize! (a, n+ Int (length (iter)):: Int )
1135
- @inbounds for (i, item) in zip (i+ 1 : lastindex (a), iter)
1196
+ @_safeindex for (i, item) in zip (i+ 1 : lastindex (a), iter)
1136
1197
a[i] = item
1137
1198
end
1138
1199
a
@@ -1194,12 +1255,13 @@ pushfirst!(a::Vector, iter...) = prepend!(a, iter)
1194
1255
prepend! (a:: AbstractVector , iter... ) = foldr ((v, a) -> prepend! (a, v), iter, init= a)
1195
1256
1196
1257
function _prepend! (a, :: Union{HasLength,HasShape} , iter)
1258
+ @_terminates_locally_meta
1197
1259
require_one_based_indexing (a)
1198
1260
n = length (iter)
1199
1261
_growbeg! (a, n)
1200
1262
i = 0
1201
1263
for item in iter
1202
- @inbounds a[i += 1 ] = item
1264
+ @_safeindex a[i += 1 ] = item
1203
1265
end
1204
1266
a
1205
1267
end
@@ -1249,7 +1311,7 @@ function resize!(a::Vector, nl::Integer)
1249
1311
_growend! (a, nl- l)
1250
1312
elseif nl != l
1251
1313
if nl < 0
1252
- throw ( ArgumentError ( " new length must be ≥ 0" ) )
1314
+ _throw_argerror ( " new length must be ≥ 0" )
1253
1315
end
1254
1316
_deleteend! (a, l- nl)
1255
1317
end
@@ -1329,7 +1391,7 @@ julia> pop!(Dict(1=>2))
1329
1391
"""
1330
1392
function pop! (a:: Vector )
1331
1393
if isempty (a)
1332
- throw ( ArgumentError ( " array must be non-empty" ) )
1394
+ _throw_argerror ( " array must be non-empty" )
1333
1395
end
1334
1396
item = a[end ]
1335
1397
_deleteend! (a, 1 )
@@ -1403,24 +1465,25 @@ julia> pushfirst!([1, 2, 3, 4], 5, 6)
1403
1465
4
1404
1466
```
1405
1467
"""
1406
- function pushfirst! (a:: Array{T,1 } , item) where T
1468
+ function pushfirst! (a:: Vector{T } , item) where T
1407
1469
item = convert (T, item)
1408
1470
_growbeg! (a, 1 )
1409
- a[1 ] = item
1471
+ @_safeindex a[1 ] = item
1410
1472
return a
1411
1473
end
1412
1474
1413
1475
# specialize and optimize the single argument case
1414
1476
function pushfirst! (a:: Vector{Any} , @nospecialize x)
1415
1477
_growbeg! (a, 1 )
1416
- a[1 ] = x
1478
+ @_safeindex a[1 ] = x
1417
1479
return a
1418
1480
end
1419
1481
function pushfirst! (a:: Vector{Any} , @nospecialize x... )
1482
+ @_terminates_locally_meta
1420
1483
na = length (a)
1421
1484
nx = length (x)
1422
1485
_growbeg! (a, nx)
1423
- for i = 1 : nx
1486
+ @_safeindex for i = 1 : nx
1424
1487
a[i] = x[i]
1425
1488
end
1426
1489
return a
@@ -1460,7 +1523,7 @@ julia> A
1460
1523
"""
1461
1524
function popfirst! (a:: Vector )
1462
1525
if isempty (a)
1463
- throw ( ArgumentError ( " array must be non-empty" ) )
1526
+ _throw_argerror ( " array must be non-empty" )
1464
1527
end
1465
1528
item = a[1 ]
1466
1529
_deletebeg! (a, 1 )
@@ -1600,7 +1663,7 @@ function _deleteat!(a::Vector, inds, dltd=Nowhere())
1600
1663
(i,s) = y
1601
1664
if ! (q <= i <= n)
1602
1665
if i < q
1603
- throw ( ArgumentError ( " indices must be unique and sorted" ) )
1666
+ _throw_argerror ( " indices must be unique and sorted" )
1604
1667
else
1605
1668
throw (BoundsError ())
1606
1669
end
@@ -1856,7 +1919,7 @@ for (f,_f) in ((:reverse,:_reverse), (:reverse!,:_reverse!))
1856
1919
$ _f (A:: AbstractVector , :: Colon ) = $ f (A, firstindex (A), lastindex (A))
1857
1920
$ _f (A:: AbstractVector , dim:: Tuple{Integer} ) = $ _f (A, first (dim))
1858
1921
function $_f (A:: AbstractVector , dim:: Integer )
1859
- dim == 1 || throw ( ArgumentError (" invalid dimension $ dim ≠ 1" ))
1922
+ dim == 1 || _throw_argerror ( LazyString (" invalid dimension " , dim, " ≠ 1" ))
1860
1923
return $ _f (A, :)
1861
1924
end
1862
1925
end
0 commit comments