From 4270d3b44e53e9fa68dcdbb6cb416d232615db4c Mon Sep 17 00:00:00 2001 From: Steffen Zahn Date: Fri, 2 Jul 2021 08:17:57 +0200 Subject: [PATCH 01/16] Fix spelling error, a missing r (#41443) --- doc/src/manual/mathematical-operations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/manual/mathematical-operations.md b/doc/src/manual/mathematical-operations.md index 4d1ebc726fa6d..c285ed9abbabd 100644 --- a/doc/src/manual/mathematical-operations.md +++ b/doc/src/manual/mathematical-operations.md @@ -69,7 +69,7 @@ The following [Boolean operators](https://en.wikipedia.org/wiki/Boolean_algebra# | `x && y` | [short-circuiting and](@ref man-conditional-evaluation) | | `x \|\| y` | [short-circuiting or](@ref man-conditional-evaluation) | -Negation changes `true` to `false` and vice versa. The short-circuiting opeations are explained on the linked page. +Negation changes `true` to `false` and vice versa. The short-circuiting operations are explained on the linked page. Note that `Bool` is an integer type and all the usual promotion rules and numeric operators are also defined on it. From 3eefaf0a52d1f537c512282a3027ead8e5e4f44e Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Fri, 2 Jul 2021 10:28:41 -0400 Subject: [PATCH 02/16] deprecate unsafe_length for simply length (#40382) This seems to be a fairly arbitrary case for throwing exceptions, when the user might often use this value in arithmetic afterwards, which is not checked. It leads to awkward complexity in the API however, where it may be unclear which function to reach for, with no particular justification for why a particular usage is "safe". And it inhibits optimization and performance due to the additional checks and error cases (and is not even entirely type-stable). --- NEWS.md | 5 + base/abstractarray.jl | 15 +- base/broadcast.jl | 2 +- base/checked.jl | 12 +- base/deprecated.jl | 3 + base/indices.jl | 8 +- base/multidimensional.jl | 2 +- base/range.jl | 147 +++++++++++++------ base/subarray.jl | 10 +- doc/src/base/collections.md | 1 + stdlib/Dates/test/ranges.jl | 2 +- test/ranges.jl | 217 +++++++++++++++++++++-------- test/testhelpers/Furlongs.jl | 15 +- test/testhelpers/InfiniteArrays.jl | 8 +- test/testhelpers/OffsetArrays.jl | 1 - 15 files changed, 308 insertions(+), 140 deletions(-) diff --git a/NEWS.md b/NEWS.md index e4885c4c34d51..445f3b84ad178 100644 --- a/NEWS.md +++ b/NEWS.md @@ -39,6 +39,11 @@ New library features Standard library changes ------------------------ +* The `length` function on certain ranges of certain specific element types no longer checks for integer + overflow in most cases. The new function `checked_length` is now available, which will try to use checked + arithmetic to error if the result may be wrapping. Or use a package such as SaferIntegers.jl when + constructing the range. ([#40382]) + #### Package Manager #### LinearAlgebra diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 78757c1a056f0..96b1b834e7d43 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -116,9 +116,6 @@ axes1(A::AbstractArray{<:Any,0}) = OneTo(1) axes1(A::AbstractArray) = (@_inline_meta; axes(A)[1]) axes1(iter) = oneto(length(iter)) -unsafe_indices(A) = axes(A) -unsafe_indices(r::AbstractRange) = (oneto(unsafe_length(r)),) # Ranges use checked_sub for size - """ keys(a::AbstractArray) @@ -580,14 +577,14 @@ end function trailingsize(inds::Indices, n) s = 1 for i=n:length(inds) - s *= unsafe_length(inds[i]) + s *= length(inds[i]) end return s end # This version is type-stable even if inds is heterogeneous function trailingsize(inds::Indices) @_inline_meta - prod(map(unsafe_length, inds)) + prod(map(length, inds)) end ## Bounds checking ## @@ -688,7 +685,7 @@ function checkbounds_indices(::Type{Bool}, ::Tuple{}, I::Tuple) @_inline_meta checkindex(Bool, OneTo(1), I[1])::Bool & checkbounds_indices(Bool, (), tail(I)) end -checkbounds_indices(::Type{Bool}, IA::Tuple, ::Tuple{}) = (@_inline_meta; all(x->unsafe_length(x)==1, IA)) +checkbounds_indices(::Type{Bool}, IA::Tuple, ::Tuple{}) = (@_inline_meta; all(x->length(x)==1, IA)) checkbounds_indices(::Type{Bool}, ::Tuple{}, ::Tuple{}) = true throw_boundserror(A, I) = (@_noinline_meta; throw(BoundsError(A, I))) @@ -2499,8 +2496,8 @@ function _sub2ind_recurse(inds, L, ind, i::Integer, I::Integer...) end nextL(L, l::Integer) = L*l -nextL(L, r::AbstractUnitRange) = L*unsafe_length(r) -nextL(L, r::Slice) = L*unsafe_length(r.indices) +nextL(L, r::AbstractUnitRange) = L*length(r) +nextL(L, r::Slice) = L*length(r.indices) offsetin(i, l::Integer) = i-1 offsetin(i, r::AbstractUnitRange) = i-first(r) @@ -2526,7 +2523,7 @@ end _lookup(ind, d::Integer) = ind+1 _lookup(ind, r::AbstractUnitRange) = ind+first(r) _div(ind, d::Integer) = div(ind, d), 1, d -_div(ind, r::AbstractUnitRange) = (d = unsafe_length(r); (div(ind, d), first(r), d)) +_div(ind, r::AbstractUnitRange) = (d = length(r); (div(ind, d), first(r), d)) # Vectorized forms function _sub2ind(inds::Indices{1}, I1::AbstractVector{T}, I::AbstractVector{T}...) where T<:Integer diff --git a/base/broadcast.jl b/base/broadcast.jl index 7c87fef3f19e6..c6651e28489a3 100644 --- a/base/broadcast.jl +++ b/base/broadcast.jl @@ -566,7 +566,7 @@ an `Int`. """ Base.@propagate_inbounds newindex(arg, I::CartesianIndex) = CartesianIndex(_newindex(axes(arg), I.I)) Base.@propagate_inbounds newindex(arg, I::Integer) = CartesianIndex(_newindex(axes(arg), (I,))) -Base.@propagate_inbounds _newindex(ax::Tuple, I::Tuple) = (ifelse(Base.unsafe_length(ax[1])==1, ax[1][1], I[1]), _newindex(tail(ax), tail(I))...) +Base.@propagate_inbounds _newindex(ax::Tuple, I::Tuple) = (ifelse(length(ax[1]) == 1, ax[1][1], I[1]), _newindex(tail(ax), tail(I))...) Base.@propagate_inbounds _newindex(ax::Tuple{}, I::Tuple) = () Base.@propagate_inbounds _newindex(ax::Tuple, I::Tuple{}) = (ax[1][1], _newindex(tail(ax), ())...) Base.@propagate_inbounds _newindex(ax::Tuple{}, I::Tuple{}) = () diff --git a/base/checked.jl b/base/checked.jl index 840015861923f..ba23d4c5acd2b 100644 --- a/base/checked.jl +++ b/base/checked.jl @@ -6,14 +6,14 @@ module Checked export checked_neg, checked_abs, checked_add, checked_sub, checked_mul, checked_div, checked_rem, checked_fld, checked_mod, checked_cld, - add_with_overflow, sub_with_overflow, mul_with_overflow + checked_length, add_with_overflow, sub_with_overflow, mul_with_overflow import Core.Intrinsics: checked_sadd_int, checked_ssub_int, checked_smul_int, checked_sdiv_int, checked_srem_int, checked_uadd_int, checked_usub_int, checked_umul_int, checked_udiv_int, checked_urem_int -import ..no_op_err, ..@_inline_meta, ..@_noinline_meta +import ..no_op_err, ..@_inline_meta, ..@_noinline_meta, ..checked_length # define promotion behavior for checked operations checked_add(x::Integer, y::Integer) = checked_add(promote(x,y)...) @@ -349,4 +349,12 @@ The overflow protection may impose a perceptible performance penalty. """ checked_cld(x::T, y::T) where {T<:Integer} = cld(x, y) # Base.cld already checks +""" + Base.checked_length(r) + +Calculates `length(r)`, but may check for overflow errors where applicable when +the result doesn't fit into `Union{Integer(eltype(r)),Int}`. +""" +checked_length(r) = length(r) # for most things, length doesn't error + end diff --git a/base/deprecated.jl b/base/deprecated.jl index d60cc3393662c..3ed9ffa9c34e8 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -240,6 +240,9 @@ end @deprecate cat_shape(dims, shape::Tuple{}, shapes::Tuple...) cat_shape(dims, shapes) false cat_shape(dims, shape::Tuple{}) = () # make sure `cat_shape(dims, ())` do not recursively calls itself +@deprecate unsafe_indices(A) axes(A) false +@deprecate unsafe_length(r) length(r) false + # END 1.6 deprecations # BEGIN 1.7 deprecations diff --git a/base/indices.jl b/base/indices.jl index ef9e2c52ca6a3..817d9d435522b 100644 --- a/base/indices.jl +++ b/base/indices.jl @@ -352,17 +352,14 @@ struct Slice{T<:AbstractUnitRange} <: AbstractUnitRange{Int} end Slice(S::Slice) = S axes(S::Slice) = (IdentityUnitRange(S.indices),) -unsafe_indices(S::Slice) = (IdentityUnitRange(S.indices),) axes1(S::Slice) = IdentityUnitRange(S.indices) axes(S::Slice{<:OneTo}) = (S.indices,) -unsafe_indices(S::Slice{<:OneTo}) = (S.indices,) axes1(S::Slice{<:OneTo}) = S.indices first(S::Slice) = first(S.indices) last(S::Slice) = last(S.indices) size(S::Slice) = (length(S.indices),) length(S::Slice) = length(S.indices) -unsafe_length(S::Slice) = unsafe_length(S.indices) getindex(S::Slice, i::Int) = (@_inline_meta; @boundscheck checkbounds(S, i); i) getindex(S::Slice, i::AbstractUnitRange{<:Integer}) = (@_inline_meta; @boundscheck checkbounds(S, i); i) getindex(S::Slice, i::StepRange{<:Integer}) = (@_inline_meta; @boundscheck checkbounds(S, i); i) @@ -383,17 +380,14 @@ end IdentityUnitRange(S::IdentityUnitRange) = S # IdentityUnitRanges are offset and thus have offset axes, so they are their own axes axes(S::IdentityUnitRange) = (S,) -unsafe_indices(S::IdentityUnitRange) = (S,) axes1(S::IdentityUnitRange) = S axes(S::IdentityUnitRange{<:OneTo}) = (S.indices,) -unsafe_indices(S::IdentityUnitRange{<:OneTo}) = (S.indices,) axes1(S::IdentityUnitRange{<:OneTo}) = S.indices first(S::IdentityUnitRange) = first(S.indices) last(S::IdentityUnitRange) = last(S.indices) size(S::IdentityUnitRange) = (length(S.indices),) length(S::IdentityUnitRange) = length(S.indices) -unsafe_length(S::IdentityUnitRange) = unsafe_length(S.indices) getindex(S::IdentityUnitRange, i::Int) = (@_inline_meta; @boundscheck checkbounds(S, i); i) getindex(S::IdentityUnitRange, i::AbstractUnitRange{<:Integer}) = (@_inline_meta; @boundscheck checkbounds(S, i); i) getindex(S::IdentityUnitRange, i::StepRange{<:Integer}) = (@_inline_meta; @boundscheck checkbounds(S, i); i) @@ -479,7 +473,7 @@ convert(::Type{LinearIndices{N,R}}, inds::LinearIndices{N}) where {N,R} = # AbstractArray implementation IndexStyle(::Type{<:LinearIndices}) = IndexLinear() axes(iter::LinearIndices) = map(axes1, iter.indices) -size(iter::LinearIndices) = map(unsafe_length, iter.indices) +size(iter::LinearIndices) = map(length, iter.indices) function getindex(iter::LinearIndices, i::Int) @_inline_meta @boundscheck checkbounds(iter, i) diff --git a/base/multidimensional.jl b/base/multidimensional.jl index 2f277af36cdc1..8104cddb34387 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -849,7 +849,7 @@ function _unsafe_getindex(::IndexStyle, A::AbstractArray, I::Vararg{Union{Real, # This is specifically not inlined to prevent excessive allocations in type unstable code shape = index_shape(I...) dest = similar(A, shape) - map(unsafe_length, axes(dest)) == map(unsafe_length, shape) || throw_checksize_error(dest, shape) + map(length, axes(dest)) == map(length, shape) || throw_checksize_error(dest, shape) _unsafe_getindex!(dest, A, I...) # usually a generated function, don't allow it to impact inference result return dest end diff --git a/base/range.jl b/base/range.jl index 37b2da7a3bb4c..9207949090d1d 100644 --- a/base/range.jl +++ b/base/range.jl @@ -585,9 +585,11 @@ end ## interface implementations +length(r::AbstractRange) = error("length implementation missing") # catch mistakes size(r::AbstractRange) = (length(r),) isempty(r::StepRange) = + # steprange_last_empty(r.start, r.step, r.stop) == r.stop (r.start != r.stop) & ((r.step > zero(r.step)) != (r.stop > r.start)) isempty(r::AbstractUnitRange) = first(r) > last(r) isempty(r::StepRangeLen) = length(r) == 0 @@ -614,7 +616,7 @@ julia> step(range(2.5, stop=10.9, length=85)) ``` """ step(r::StepRange) = r.step -step(r::AbstractUnitRange{T}) where{T} = oneunit(T) - zero(T) +step(r::AbstractUnitRange{T}) where {T} = oneunit(T) - zero(T) step(r::StepRangeLen) = r.step step(r::StepRangeLen{T}) where {T<:AbstractFloat} = T(r.step) step(r::LinRange) = (last(r)-first(r))/r.lendiv @@ -622,60 +624,127 @@ step(r::LinRange) = (last(r)-first(r))/r.lendiv step_hp(r::StepRangeLen) = r.step step_hp(r::AbstractRange) = step(r) -unsafe_length(r::AbstractRange) = length(r) # generic fallback - -function unsafe_length(r::StepRange) - n = Integer(div((r.stop - r.start) + r.step, r.step)) - isempty(r) ? zero(n) : n -end -length(r::StepRange) = unsafe_length(r) -unsafe_length(r::AbstractUnitRange) = Integer(last(r) - first(r) + step(r)) -unsafe_length(r::OneTo) = Integer(r.stop - zero(r.stop)) -length(r::AbstractUnitRange) = unsafe_length(r) -length(r::OneTo) = unsafe_length(r) -length(r::StepRangeLen) = r.len -length(r::LinRange) = r.len +axes(r::AbstractRange) = (oneto(length(r)),) # Needed to fold the `firstindex` call in SimdLoop.simd_index firstindex(::UnitRange) = 1 firstindex(::StepRange) = 1 firstindex(::LinRange) = 1 -function length(r::StepRange{T}) where T<:Union{Int,UInt,Int64,UInt64,Int128,UInt128} - isempty(r) && return zero(T) - if r.step > 1 - return checked_add(convert(T, div(unsigned(r.stop - r.start), r.step)), one(T)) - elseif r.step < -1 - return checked_add(convert(T, div(unsigned(r.start - r.stop), -r.step)), one(T)) - elseif r.step > 0 - return checked_add(div(checked_sub(r.stop, r.start), r.step), one(T)) +# n.b. checked_length for these is defined iff checked_add and checked_sub are +# defined between the relevant types +function checked_length(r::OrdinalRange{T}) where T + s = step(r) + # s != 0, by construction, but avoids the division error later + start = first(r) + if s == zero(s) || isempty(r) + return Integer(start - start + zero(s)) + end + stop = last(r) + if isless(s, zero(s)) + diff = checked_sub(start, stop) + s = -s else - return checked_add(div(checked_sub(r.start, r.stop), -r.step), one(T)) + diff = checked_sub(stop, start) end + a = Integer(div(diff, s)) + return checked_add(a, one(a)) end -function length(r::AbstractUnitRange{T}) where T<:Union{Int,Int64,Int128} +function checked_length(r::AbstractUnitRange{T}) where T + # compiler optimization: remove dead cases from above + if isempty(r) + return Integer(first(r) - first(r)) + end + a = Integer(checked_add(checked_sub(last(r), first(r)))) + return checked_add(a, one(a)) +end + +function length(r::OrdinalRange{T}) where T + s = step(r) + # s != 0, by construction, but avoids the division error later + start = first(r) + if s == zero(s) || isempty(r) + return Integer(start - start + zero(s)) + end + stop = last(r) + if isless(s, zero(s)) + diff = start - stop + s = -s + else + diff = stop - start + end + a = Integer(div(diff, s)) + return a + one(a) +end + + +function length(r::AbstractUnitRange{T}) where T @_inline_meta - checked_add(checked_sub(last(r), first(r)), one(T)) + a = Integer(last(r) - first(r)) # even when isempty, by construction (with overflow) + return a + one(a) end -length(r::OneTo{T}) where {T<:Union{Int,Int64}} = T(r.stop) -length(r::AbstractUnitRange{T}) where {T<:Union{UInt,UInt64,UInt128}} = - r.stop < r.start ? zero(T) : checked_add(last(r) - first(r), one(T)) +length(r::OneTo) = Integer(r.stop - zero(r.stop)) +length(r::StepRangeLen) = r.len +length(r::LinRange) = r.len -# some special cases to favor default Int type -let smallint = (Int === Int64 ? - Union{Int8,UInt8,Int16,UInt16,Int32,UInt32} : - Union{Int8,UInt8,Int16,UInt16}) - global length - - function length(r::StepRange{<:smallint}) - isempty(r) && return Int(0) - div(Int(r.stop)+Int(r.step) - Int(r.start), Int(r.step)) +let bigints = Union{Int, UInt, Int64, UInt64, Int128, UInt128} + global length, checked_length + # compile optimization for which promote_type(T, Int) == T + length(r::OneTo{T}) where {T<:bigints} = r.stop + # slightly more accurate length and checked_length in extreme cases + # (near typemax) for types with known `unsigned` functions + function length(r::OrdinalRange{T}) where T<:bigints + s = step(r) + s == zero(s) && return zero(T) # unreachable, by construction, but avoids the error case here later + isempty(r) && return zero(T) + diff = last(r) - first(r) + # if |s| > 1, diff might have overflowed, but unsigned(diff)÷s should + # therefore still be valid (if the result is representable at all) + # n.b. !(s isa T) + if s isa Unsigned || -1 <= s <= 1 || s == -s + a = div(diff, s) + elseif s < 0 + a = div(unsigned(-diff), -s) % typeof(diff) + else + a = div(unsigned(diff), s) % typeof(diff) + end + return Integer(a) + one(a) + end + function checked_length(r::OrdinalRange{T}) where T<:bigints + s = step(r) + s == zero(s) && return zero(T) # unreachable, by construction, but avoids the error case here later + isempty(r) && return zero(T) + stop, start = last(r), first(r) + # n.b. !(s isa T) + if s > 1 + diff = stop - start + a = convert(T, div(unsigned(diff), s)) + elseif s < -1 + diff = start - stop + a = convert(T, div(unsigned(diff), -s)) + elseif s > 0 + a = div(checked_sub(stop, start), s) + else + a = div(checked_sub(start, stop), -s) + end + return checked_add(a, one(a)) end +end - length(r::AbstractUnitRange{<:smallint}) = Int(last(r)) - Int(first(r)) + 1 - length(r::OneTo{<:smallint}) = Int(r.stop) +# some special cases to favor default Int type +let smallints = (Int === Int64 ? + Union{Int8, UInt8, Int16, UInt16, Int32, UInt32} : + Union{Int8, UInt8, Int16, UInt16}) + global length, checked_length + # n.b. !(step isa T) + length(r::OrdinalRange{<:smallints}) = div(Int(last(r)) - Int(first(r)), step(r)) + 1 + length(r::AbstractUnitRange{<:smallints}) = Int(last(r)) - Int(first(r)) + 1 + length(r::OneTo{<:smallints}) = Int(r.stop) + checked_length(r::OrdinalRange{<:smallints}) = length(r) + checked_length(r::AbstractUnitRange{<:smallints}) = length(r) + checked_length(r::OneTo{<:smallints}) = length(r) end first(r::OrdinalRange{T}) where {T} = convert(T, r.start) diff --git a/base/subarray.jl b/base/subarray.jl index 32262058cb55b..89a4db4d65790 100644 --- a/base/subarray.jl +++ b/base/subarray.jl @@ -60,7 +60,7 @@ viewindexing(I::Tuple{Vararg{Any}}) = IndexCartesian() viewindexing(I::Tuple{AbstractArray, Vararg{Any}}) = IndexCartesian() # Simple utilities -size(V::SubArray) = (@_inline_meta; map(unsafe_length, axes(V))) +size(V::SubArray) = (@_inline_meta; map(length, axes(V))) similar(V::SubArray, T::Type, dims::Dims) = similar(V.parent, T, dims) @@ -362,7 +362,7 @@ compute_stride1(parent::AbstractArray, I::NTuple{N,Any}) where {N} = compute_stride1(s, inds, I::Tuple{}) = s compute_stride1(s, inds, I::Tuple{Vararg{ScalarIndex}}) = s compute_stride1(s, inds, I::Tuple{ScalarIndex, Vararg{Any}}) = - (@_inline_meta; compute_stride1(s*unsafe_length(inds[1]), tail(inds), tail(I))) + (@_inline_meta; compute_stride1(s*length(inds[1]), tail(inds), tail(I))) compute_stride1(s, inds, I::Tuple{AbstractRange, Vararg{Any}}) = s*step(I[1]) compute_stride1(s, inds, I::Tuple{Slice, Vararg{Any}}) = s compute_stride1(s, inds, I::Tuple{Any, Vararg{Any}}) = throw(ArgumentError("invalid strided index type $(typeof(I[1]))")) @@ -407,12 +407,12 @@ end function compute_linindex(f, s, IP::Tuple, I::Tuple{ScalarIndex, Vararg{Any}}) @_inline_meta Δi = I[1]-first(IP[1]) - compute_linindex(f + Δi*s, s*unsafe_length(IP[1]), tail(IP), tail(I)) + compute_linindex(f + Δi*s, s*length(IP[1]), tail(IP), tail(I)) end function compute_linindex(f, s, IP::Tuple, I::Tuple{Any, Vararg{Any}}) @_inline_meta Δi = first(I[1])-first(IP[1]) - compute_linindex(f + Δi*s, s*unsafe_length(IP[1]), tail(IP), tail(I)) + compute_linindex(f + Δi*s, s*length(IP[1]), tail(IP), tail(I)) end compute_linindex(f, s, IP::Tuple, I::Tuple{}) = f @@ -447,5 +447,5 @@ _indices_sub(::Real, I...) = (@_inline_meta; _indices_sub(I...)) _indices_sub() = () function _indices_sub(i1::AbstractArray, I...) @_inline_meta - (unsafe_indices(i1)..., _indices_sub(I...)...) + (axes(i1)..., _indices_sub(I...)...) end diff --git a/doc/src/base/collections.md b/doc/src/base/collections.md index f8ef12071171a..84e5702e0e396 100644 --- a/doc/src/base/collections.md +++ b/doc/src/base/collections.md @@ -66,6 +66,7 @@ Base.LinRange Base.isempty Base.empty! Base.length +Base.checked_length ``` Fully implemented by: diff --git a/stdlib/Dates/test/ranges.jl b/stdlib/Dates/test/ranges.jl index 6eb6371376867..52416fc95ec0c 100644 --- a/stdlib/Dates/test/ranges.jl +++ b/stdlib/Dates/test/ranges.jl @@ -515,7 +515,7 @@ end @test length(Dates.Year(1):Dates.Year(1):Dates.Year(10)) == 10 @test length(Dates.Year(10):Dates.Year(-1):Dates.Year(1)) == 10 @test length(Dates.Year(10):Dates.Year(-2):Dates.Year(1)) == 5 -@test_throws OverflowError length(typemin(Dates.Year):Dates.Year(1):typemax(Dates.Year)) +@test length(typemin(Dates.Year):Dates.Year(1):typemax(Dates.Year)) == 0 # overflow @test_throws MethodError Dates.Date(0):Dates.DateTime(2000) @test_throws MethodError Dates.Date(0):Dates.Year(10) @test length(range(Dates.Date(2000), step=Dates.Day(1), length=366)) == 366 diff --git a/test/ranges.jl b/test/ranges.jl index 783120c361bcd..b622fc05b3ca6 100644 --- a/test/ranges.jl +++ b/test/ranges.jl @@ -1,5 +1,7 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license +using Base.Checked: checked_length + @testset "range construction" begin @test_throws ArgumentError range(start=1, step=1, stop=2, length=10) @test_throws ArgumentError range(start=1, step=1, stop=10, length=11) @@ -267,22 +269,28 @@ end end end @testset "length" begin - @test length(.1:.1:.3) == 3 - @test length(1.1:1.1:3.3) == 3 - @test length(1.1:1.3:3) == 2 - @test length(1:1:1.8) == 1 - @test length(1:.2:2) == 6 - @test length(1.:.2:2.) == 6 - @test length(2:-.2:1) == 6 - @test length(2.:-.2:1.) == 6 - @test length(2:.2:1) == 0 + @test length(.1:.1:.3) == checked_length(.1:.1:.3) == 3 + @test length(1.1:1.1:3.3) == checked_length(1.1:1.1:3.3) == 3 + @test length(1.1:1.3:3) == checked_length(1.1:1.3:3) == 2 + @test length(1:1:1.8) == checked_length(1:1:1.8) == 1 + @test length(1:.2:2) == checked_length(1:.2:2) == 6 + @test length(1.:.2:2.) == checked_length(1.:.2:2.) == 6 + @test length(2:-.2:1) == checked_length(2:-.2:1) == 6 + @test length(2.:-.2:1.) == checked_length(2.:-.2:1.) == 6 + @test length(2:.2:1) == checked_length(2:.2:1) == 0 @test length(2.:.2:1.) == 0 - @test length(1:0) == 0 - @test length(0.0:-0.5) == 0 - @test length(1:2:0) == 0 - @test length(Char(0):Char(0x001fffff)) == 2097152 - @test length(typemax(UInt64)//one(UInt64):1:typemax(UInt64)//one(UInt64)) == 1 + @test length(1:0) == checked_length(1:0) == 0 + @test length(0.0:-0.5) == checked_length(0.0:-0.5) == 0 + @test length(1:2:0) == checked_length(1:2:0) == 0 + let r = Char(0):Char(0x001fffff) + @test length(r) == 2097152 + @test_throws MethodError checked_length(r) == 2097152 # this would work if checked_sub is defined on Char + end + let r = typemax(UInt64)//one(UInt64):1:typemax(UInt64)//one(UInt64) + @test length(r) == 1 + @test_throws MethodError checked_length(r) == 1 # this would work if checked_sub is defined on Rational + end end @testset "keys/values" begin keytype_is_correct(r) = keytype(r) == eltype(keys(r)) @@ -501,22 +509,41 @@ for a=AbstractRange[3:6, 0:2:10], b=AbstractRange[0:1, 2:-1:0] end # avoiding intermediate overflow (#5065) -@test length(1:4:typemax(Int)) == div(typemax(Int),4) + 1 +@test length(1:4:typemax(Int)) == div(typemax(Int), 4) + 1 +@test checked_length(1:4:typemax(Int)) == div(typemax(Int), 4) + 1 # computed exactly in modulo arithmetic @testset "overflow in length" begin - Tset = Int === Int64 ? (Int,UInt,Int128,UInt128) : - (Int,UInt,Int64,UInt64,Int128, UInt128) + Tset = Int === Int64 ? (Int, UInt, Int128, UInt128) : + (Int, UInt, Int64, UInt64, Int128, UInt128) for T in Tset - @test_throws OverflowError length(zero(T):typemax(T)) - @test_throws OverflowError length(typemin(T):typemax(T)) - @test_throws OverflowError length(zero(T):one(T):typemax(T)) - @test_throws OverflowError length(typemin(T):one(T):typemax(T)) + @test length(zero(T):typemax(T)) == typemin(T) + @test length(typemin(T):typemax(T)) == T(0) + @test length(zero(T):one(T):typemax(T)) == typemin(T) + @test length(typemin(T):one(T):typemax(T)) == T(0) + @test_throws OverflowError checked_length(zero(T):typemax(T)) + @test_throws OverflowError checked_length(typemin(T):typemax(T)) + @test_throws OverflowError checked_length(zero(T):one(T):typemax(T)) + @test_throws OverflowError checked_length(typemin(T):one(T):typemax(T)) + @test length(one(T):typemax(T)) == checked_length(one(T):typemax(T)) == typemax(T) if T <: Signed - @test_throws OverflowError length(-one(T):typemax(T)-one(T)) - @test_throws OverflowError length(-one(T):one(T):typemax(T)-one(T)) + @test length(-one(T):typemax(T)-one(T)) == typemin(T) + @test length(-one(T):one(T):typemax(T)-one(T)) == typemin(T) + @test length(-one(T):typemax(T)) == typemin(T) + T(1) + @test length(zero(T):typemin(T):typemin(T)) == 2 + @test length(one(T):typemin(T):typemin(T)) == 2 + @test length(typemax(T):typemin(T):typemin(T)) == 2 + @test length(-one(T):typemin(T):typemin(T)) == 1 + @test length(zero(T):typemin(T):zero(T)) == 1 + @test length(zero(T):typemin(T):one(T)) == 0 + @test_throws OverflowError checked_length(-one(T):typemax(T)-one(T)) + @test_throws OverflowError checked_length(-one(T):one(T):typemax(T)-one(T)) + @test_throws InexactError checked_length(zero(T):typemin(T):typemin(T)) == 2 # this can be improved + @test_throws InexactError checked_length(one(T):typemin(T):typemin(T)) == 2 # this can be improved + @test_throws InexactError checked_length(typemax(T):typemin(T):typemin(T)) == 2 # this can be improved end end end + @testset "loops involving typemin/typemax" begin n = 0 s = 0 @@ -871,32 +898,45 @@ end end # issue #2959 @test 1.0:1.5 == 1.0:1.0:1.5 == 1.0:1.0 -#@test 1.0:(.3-.1)/.1 == 1.0:2.0 +@test_broken 1.0:(.3-.1)/.1 == 1.0:2.0 # (this is just shy of 2.0) @testset "length with typemin/typemax" begin - let r = typemin(Int64):2:typemax(Int64), s = typemax(Int64):-2:typemin(Int64) + let r = typemin(Int64):2:typemax(Int64) @test first(r) == typemin(Int64) - @test last(r) == (typemax(Int64)-1) - @test_throws OverflowError length(r) - - @test first(s) == typemax(Int64) - @test last(s) == (typemin(Int64)+1) - @test_throws OverflowError length(s) + @test last(r) == typemax(Int64) - 1 + @test length(r) == typemin(Int64) + @test_throws OverflowError checked_length(r) + end + let r = typemax(Int64):-2:typemin(Int64) + @test first(r) == typemax(Int64) + @test last(r) == typemin(Int64) + 1 + @test length(r) == typemin(Int64) + @test_throws OverflowError checked_length(r) end - @test length(typemin(Int64):3:typemax(Int64)) == 6148914691236517206 - @test length(typemax(Int64):-3:typemin(Int64)) == 6148914691236517206 + let r = typemin(Int64):3:typemax(Int64) + @test length(r) == checked_length(r) == 6148914691236517206 + end + let r = typemax(Int64):-3:typemin(Int64) + @test length(r) == checked_length(r) == 6148914691236517206 + end for s in 3:100 - @test length(typemin(Int):s:typemax(Int)) == length(big(typemin(Int)):big(s):big(typemax(Int))) - @test length(typemax(Int):-s:typemin(Int)) == length(big(typemax(Int)):big(-s):big(typemin(Int))) + r = typemin(Int):s:typemax(Int) + br = big(typemin(Int)):big(s):big(typemax(Int)) + @test length(r) == checked_length(r) == length(br) + + r = typemax(Int):-s:typemin(Int) + br = big(typemax(Int)):big(-s):big(typemin(Int)) + @test length(r) == checked_length(r) == length(br) end - @test length(UInt(1):UInt(1):UInt(0)) == 0 - @test length(typemax(UInt):UInt(1):(typemax(UInt)-1)) == 0 - @test length(typemax(UInt):UInt(2):(typemax(UInt)-1)) == 0 - @test length((typemin(Int)+3):5:(typemin(Int)+1)) == 0 + @test length(UInt(1):UInt(1):UInt(0)) == checked_length(UInt(1):UInt(1):UInt(0)) == 0 + @test length(typemax(UInt):UInt(1):(typemax(UInt)-1)) == checked_length(typemax(UInt):UInt(1):(typemax(UInt)-1)) == 0 + @test length(typemax(UInt):UInt(2):(typemax(UInt)-1)) == checked_length(typemax(UInt):UInt(2):(typemax(UInt)-1)) == 0 + @test length((typemin(Int)+3):5:(typemin(Int)+1)) == checked_length((typemin(Int)+3):5:(typemin(Int)+1)) == 0 end + # issue #6364 @test length((1:64)*(pi/5)) == 64 @@ -966,7 +1006,8 @@ end (Int8,UInt8,Int16,UInt16,Int32,UInt32) : (Int8,UInt8,Int16,UInt16)) for T in smallint - @test length(typemin(T):typemax(T)) == 2^(8*sizeof(T)) + s = typemin(T):typemax(T) + @test length(s) == checked_length(s) == 2^(8*sizeof(T)) end end @@ -974,7 +1015,7 @@ end @test (0:1//2:2)[1:2:3] == 0:1//1:1 # issue #12278 -@test length(1:UInt(0)) == 0 +@test length(1:UInt(0)) == checked_length(1:UInt(0)) == 0 @testset "zip" begin i = 0 @@ -1047,17 +1088,14 @@ end @test reverse(LinRange{Int}(0,3,4)) === LinRange{Int}(3,0,4) @test reverse(LinRange{Float64}(0.,3.,4)) === LinRange{Float64}(3.,0.,4) end -@testset "Issue #11245" begin - io = IOBuffer() - show(io, range(1, stop=2, length=3)) - str = String(take!(io)) -# @test str == "range(1.0, stop=2.0, length=3)" - @test str == "1.0:0.5:2.0" -end + +# issue #11245 +@test repr(range(1, stop=2, length=3)) == "1.0:0.5:2.0" @testset "issue 10950" begin r = 1//2:3 @test length(r) == 3 + @test_throws MethodError checked_length(r) == 3 # this would work if checked_sub is defined on Rational i = 1 for x in r @test x == i//2 @@ -1268,19 +1306,22 @@ end end r = 1f8-10:1f8 - @test_broken argmin(f) == argmin(collect(r)) - @test_broken argmax(f) == argmax(collect(r)) + rv = collect(r) + @test argmin(r) == argmin(rv) == 1 + @test r[argmax(r)] == r[argmax(rv)] == 1f8 + @test argmax(r) == lastindex(r) + @test argmax(rv) != lastindex(r) end @testset "OneTo" begin let r = Base.OneTo(-5) @test isempty(r) - @test length(r) == 0 + @test length(r) == checked_length(r) == 0 @test size(r) == (0,) end let r = Base.OneTo(3) @test !isempty(r) - @test length(r) == 3 + @test length(r) == checked_length(r) == 3 @test size(r) == (3,) @test step(r) == 1 @test first(r) == 1 @@ -1377,7 +1418,7 @@ end @testset "issue #20520" begin r = range(1.3173739f0, stop=1.3173739f0, length=3) - @test length(r) == 3 + @test length(r) == checked_length(r) == 3 @test first(r) === 1.3173739f0 @test last(r) === 1.3173739f0 @test r[2] === 1.3173739f0 @@ -1401,7 +1442,7 @@ using .Main.Furlongs @testset "dimensional correctness" begin @test length(Vector(Furlong(2):Furlong(10))) == 9 - @test length(range(Furlong(2), length=9)) == 9 + @test length(range(Furlong(2), length=9)) == checked_length(range(Furlong(2), length=9)) == 9 @test Vector(Furlong(2):Furlong(1):Furlong(10)) == Vector(range(Furlong(2), step=Furlong(1), length=9)) == Furlong.(2:10) @test Vector(Furlong(1.0):Furlong(0.5):Furlong(10.0)) == Vector(Furlong(1):Furlong(0.5):Furlong(10)) == Furlong.(1:0.5:10) @@ -1496,15 +1537,18 @@ module NonStandardIntegerRangeTest using Test +using Base.Checked: checked_length +import Base.Checked: checked_add, checked_sub + struct Position <: Integer val::Int end -Position(x::Position) = x # to resolve ambiguity with boot.jl:728 +Position(x::Position) = x # to resolve ambiguity with boot.jl:770 struct Displacement <: Integer val::Int end -Displacement(x::Displacement) = x # to resolve ambiguity with boot.jl:728 +Displacement(x::Displacement) = x # to resolve ambiguity with boot.jl:770 Base.:-(x::Displacement) = Displacement(-x.val) Base.:-(x::Position, y::Position) = Displacement(x.val - y.val) @@ -1521,14 +1565,67 @@ Base.Unsigned(x::Displacement) = Unsigned(x.val) Base.rem(x::Displacement, y::Displacement) = Displacement(rem(x.val, y.val)) Base.div(x::Displacement, y::Displacement) = Displacement(div(x.val, y.val)) -# required for collect (summing lengths); alternatively, should unsafe_length return Int by default? +# required for collect (summing lengths); alternatively, should length return Int by default? Base.promote_rule(::Type{Displacement}, ::Type{Int}) = Int Base.convert(::Type{Int}, x::Displacement) = x.val +# Unsigned complement, for testing checked_length +struct UPosition <: Unsigned + val::UInt +end +UPosition(x::UPosition) = x # to resolve ambiguity with boot.jl:770 + +struct UDisplacement <: Unsigned + val::UInt +end +UDisplacement(x::UDisplacement) = x # to resolve ambiguity with boot.jl:770 + +Base.show(io::IO, x::Union{Position, UPosition, Displacement, UDisplacement}) = + # should use show if we were to do this properly (instead of just a test-helper) + print(io, typeof(x).name.name, "(", x.val, ")") + +Base.:-(x::UPosition, y::UPosition) = UDisplacement(x.val - y.val) +Base.:-(x::UPosition, y::UDisplacement) = UPosition(x.val - y.val) +Base.:+(x::UPosition, y::UDisplacement) = UPosition(x.val + y.val) +Base.:+(x::UDisplacement, y::Displacement) = UDisplacement(x.val + y.val) +Base.:+(x::UDisplacement, y::UDisplacement) = UDisplacement(x.val + y.val) +checked_sub(x::UPosition, y::UPosition) = UDisplacement(checked_sub(x.val, y.val)) +checked_sub(x::UPosition, y::UDisplacement) = UPosition(checked_sub(x.val, y.val)) +checked_sub(x::UDisplacement, y::UDisplacement) = UDisplacement(checked_sub(x.val, y.val)) +checked_add(x::UPosition, y::UDisplacement) = UPosition(checked_add(x.val, y.val)) +checked_add(x::UDisplacement, y::UDisplacement) = UDisplacement(checked_add(x.val, y.val)) +Base.:+(x::UPosition, y::Displacement) = UPosition(x.val + y.val) +Base.:(<=)(x::UPosition, y::UPosition) = x.val <= y.val +Base.:(<)(x::UPosition, y::UPosition) = x.val < y.val +Base.:(<)(x::UDisplacement, y::UDisplacement) = x.val < y.val + +# for StepRange computation: +Base.rem(x::UDisplacement, y::Displacement) = UDisplacement(rem(x.val, y.val)) +Base.div(x::UDisplacement, y::Displacement) = UDisplacement(div(x.val, y.val)) +Base.rem(x::UDisplacement, y::UDisplacement) = UDisplacement(rem(x.val, y.val)) +Base.div(x::UDisplacement, y::UDisplacement) = UDisplacement(div(x.val, y.val)) + +#Base.promote_rule(::Type{UDisplacement}, ::Type{Int}) = Int +#Base.convert(::Type{Int}, x::UDisplacement) = Int(x.val) + @testset "Ranges with nonstandard Integers" begin for (start, stop) in [(2, 4), (3, 3), (3, -2)] - @test collect(Position(start) : Position(stop)) == Position.(start : stop) - end + r = Position(start) : Position(stop) + @test length(r) === Displacement(stop >= start ? stop - start + 1 : 0) + start >= 0 && stop >= 0 && @test UDisplacement(length(r).val) === + checked_length(UPosition(start) : UPosition(stop)) === + checked_length(UPosition(start) : Displacement(1) : UPosition(stop)) === + checked_length(UPosition(start) : UDisplacement(1) : UPosition(stop)) + @test collect(r) == Position.(start : stop) + end + + @test length(UPosition(3):Displacement(7):UPosition(100)) === checked_length(UPosition(3):Displacement(7):UPosition(100)) === UDisplacement(14) + @test length(UPosition(100):Displacement(7):UPosition(3)) === checked_length(UPosition(100):Displacement(7):UPosition(3)) === UDisplacement(0) + @test length(UPosition(100):Displacement(-7):UPosition(3)) === checked_length(UPosition(100):Displacement(-7):UPosition(3)) === UDisplacement(14) + @test length(UPosition(3):Displacement(-7):UPosition(100)) === checked_length(UPosition(3):Displacement(-7):UPosition(100)) === UDisplacement(0) + @test_throws OverflowError checked_length(zero(UPosition):UPosition(typemax(UInt))) + @test_throws OverflowError checked_length(zero(UPosition):Displacement(1):UPosition(typemax(UInt))) + @test_throws OverflowError checked_length(UPosition(typemax(UInt)):Displacement(-1):zero(UPosition)) for start in [3, 0, -2] @test collect(Base.OneTo(Position(start))) == Position.(Base.OneTo(start)) @@ -1550,7 +1647,7 @@ end end # module NonStandardIntegerRangeTest @testset "Issue #26619" begin - @test length(UInt(100) : -1 : 1) === UInt(100) + @test length(UInt(100) : -1 : 1) == checked_length(UInt(100) : -1 : 1) === UInt(100) @test collect(UInt(5) : -1 : 3) == [UInt(5), UInt(4), UInt(3)] let r = UInt(5) : -2 : 2 diff --git a/test/testhelpers/Furlongs.jl b/test/testhelpers/Furlongs.jl index 73d23a39d2d7b..f3583a532215a 100644 --- a/test/testhelpers/Furlongs.jl +++ b/test/testhelpers/Furlongs.jl @@ -20,7 +20,7 @@ Furlong{p}(x::Furlong{q}) where {p,q} = (@assert(p==q); Furlong{p,typeof(x.val)} Furlong{p,T}(x::Furlong{q}) where {T,p,q} = (@assert(p==q); Furlong{p,T}(T(x.val))) Base.promote_type(::Type{Furlong{p,T}}, ::Type{Furlong{p,S}}) where {p,T,S} = - (Base.@_pure_meta; Furlong{p,promote_type(T,S)}) + Furlong{p,promote_type(T,S)} Base.one(x::Furlong{p,T}) where {p,T} = one(T) Base.one(::Type{Furlong{p,T}}) where {p,T} = one(T) @@ -38,14 +38,12 @@ Base.floatmax(::Type{Furlong{p,T}}) where {p,T<:AbstractFloat} = Furlong{p}(floa Base.floatmax(::Furlong{p,T}) where {p,T<:AbstractFloat} = floatmax(Furlong{p,T}) Base.conj(x::Furlong{p,T}) where {p,T} = Furlong{p,T}(conj(x.val)) -# convert Furlong exponent p to a canonical form. This -# is not type stable, but it doesn't matter since it is used -# at compile time (in generated functions), not runtime +# convert Furlong exponent p to a canonical form canonical_p(p) = isinteger(p) ? Int(p) : Rational{Int}(p) Base.abs(x::Furlong{p}) where {p} = Furlong{p}(abs(x.val)) -@generated Base.abs2(x::Furlong{p}) where {p} = :(Furlong{$(canonical_p(2p))}(abs2(x.val))) -@generated Base.inv(x::Furlong{p}) where {p} = :(Furlong{$(canonical_p(-p))}(inv(x.val))) +Base.abs2(x::Furlong{p}) where {p} = Furlong{canonical_p(2p)}(abs2(x.val)) +Base.inv(x::Furlong{p}) where {p} = Furlong{canonical_p(-p)}(inv(x.val)) for f in (:isfinite, :isnan, :isreal, :isinf) @eval Base.$f(x::Furlong) = $f(x.val) @@ -64,11 +62,10 @@ end for op in (:(==), :(!=), :<, :<=, :isless, :isequal) @eval $op(x::Furlong{p}, y::Furlong{p}) where {p} = $op(x.val, y.val) end -# generated functions to allow type inference of the value of the exponent: for (f,op) in ((:_plus,:+),(:_minus,:-),(:_times,:*),(:_div,://)) - @eval @generated function $f(v::T, ::Furlong{p}, ::Union{Furlong{q},Val{q}}) where {T,p,q} + @eval function $f(v::T, ::Furlong{p}, ::Union{Furlong{q},Val{q}}) where {T,p,q} s = $op(p, q) - :(Furlong{$(canonical_p(s)),$T}(v)) + Furlong{canonical_p(s),T}(v) end end for (op,eop) in ((:*, :_plus), (:/, :_minus), (://, :_minus), (:div, :_minus)) diff --git a/test/testhelpers/InfiniteArrays.jl b/test/testhelpers/InfiniteArrays.jl index bc6de1afc5503..d69130f4d726a 100644 --- a/test/testhelpers/InfiniteArrays.jl +++ b/test/testhelpers/InfiniteArrays.jl @@ -39,13 +39,11 @@ struct OneToInf{T<:Integer} <: AbstractUnitRange{T} end OneToInf() = OneToInf{Int}() Base.axes(r::OneToInf) = (r,) -Base.unsafe_indices(r::OneToInf) = (r,) -Base.unsafe_length(r::OneToInf) = Infinity() Base.size(r::OneToInf) = (Infinity(),) Base.first(r::OneToInf{T}) where {T} = oneunit(T) -Base.length(r::OneToInf{T}) where {T} = Infinity() -Base.last(r::OneToInf{T}) where {T} = Infinity() +Base.length(r::OneToInf) = Infinity() +Base.last(r::OneToInf) = Infinity() Base.unitrange(r::OneToInf) = r Base.oneto(::Infinity) = OneToInf() -end \ No newline at end of file +end diff --git a/test/testhelpers/OffsetArrays.jl b/test/testhelpers/OffsetArrays.jl index 67de3ef476652..2f650808a12f2 100644 --- a/test/testhelpers/OffsetArrays.jl +++ b/test/testhelpers/OffsetArrays.jl @@ -68,7 +68,6 @@ offset_coerce(::Type{I}, r::AbstractUnitRange) where I<:AbstractUnitRange{T} whe @inline Base.parent(r::IdOffsetRange) = r.parent @inline Base.axes(r::IdOffsetRange) = (Base.axes1(r),) @inline Base.axes1(r::IdOffsetRange) = IdOffsetRange(Base.axes1(r.parent), r.offset) -@inline Base.unsafe_indices(r::IdOffsetRange) = (r,) @inline Base.length(r::IdOffsetRange) = length(r.parent) Base.reduced_index(i::IdOffsetRange) = typeof(i)(first(i):first(i)) # Workaround for #92 on Julia < 1.4 From 74e79e35746ee1d8b0d8808175a50c23e897391b Mon Sep 17 00:00:00 2001 From: DilumAluthgeBot <43731525+DilumAluthgeBot@users.noreply.github.com> Date: Fri, 2 Jul 2021 14:29:35 +0000 Subject: [PATCH 03/16] =?UTF-8?q?=F0=9F=A4=96=20Bump=20the=20Pkg=20stdlib?= =?UTF-8?q?=20from=209914dabf=20to=20e476cd0c=20(#41436)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Dilum Aluthge --- .../Pkg-9914dabfd66813197e0c67e28b78cfe0b393fe88.tar.gz/md5 | 1 - .../Pkg-9914dabfd66813197e0c67e28b78cfe0b393fe88.tar.gz/sha512 | 1 - .../Pkg-e476cd0c61e19b645cc0e32bb30f8e44f60001f7.tar.gz/md5 | 1 + .../Pkg-e476cd0c61e19b645cc0e32bb30f8e44f60001f7.tar.gz/sha512 | 1 + stdlib/Pkg.version | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 deps/checksums/Pkg-9914dabfd66813197e0c67e28b78cfe0b393fe88.tar.gz/md5 delete mode 100644 deps/checksums/Pkg-9914dabfd66813197e0c67e28b78cfe0b393fe88.tar.gz/sha512 create mode 100644 deps/checksums/Pkg-e476cd0c61e19b645cc0e32bb30f8e44f60001f7.tar.gz/md5 create mode 100644 deps/checksums/Pkg-e476cd0c61e19b645cc0e32bb30f8e44f60001f7.tar.gz/sha512 diff --git a/deps/checksums/Pkg-9914dabfd66813197e0c67e28b78cfe0b393fe88.tar.gz/md5 b/deps/checksums/Pkg-9914dabfd66813197e0c67e28b78cfe0b393fe88.tar.gz/md5 deleted file mode 100644 index 7e270d33db3d1..0000000000000 --- a/deps/checksums/Pkg-9914dabfd66813197e0c67e28b78cfe0b393fe88.tar.gz/md5 +++ /dev/null @@ -1 +0,0 @@ -91de1078abb41513423dfab4e0e7d406 diff --git a/deps/checksums/Pkg-9914dabfd66813197e0c67e28b78cfe0b393fe88.tar.gz/sha512 b/deps/checksums/Pkg-9914dabfd66813197e0c67e28b78cfe0b393fe88.tar.gz/sha512 deleted file mode 100644 index 3f6952477519a..0000000000000 --- a/deps/checksums/Pkg-9914dabfd66813197e0c67e28b78cfe0b393fe88.tar.gz/sha512 +++ /dev/null @@ -1 +0,0 @@ -1a6a87e27839910829a322326c7aa52a66a3467850de9a4a17c19003c3b4a4de8507bbe19fddc5cc3bc40be8e3a8902af1c0458107b7f5d55213cf2c9cafad21 diff --git a/deps/checksums/Pkg-e476cd0c61e19b645cc0e32bb30f8e44f60001f7.tar.gz/md5 b/deps/checksums/Pkg-e476cd0c61e19b645cc0e32bb30f8e44f60001f7.tar.gz/md5 new file mode 100644 index 0000000000000..de586e869f6db --- /dev/null +++ b/deps/checksums/Pkg-e476cd0c61e19b645cc0e32bb30f8e44f60001f7.tar.gz/md5 @@ -0,0 +1 @@ +af31db7882d62388fcc3fccf81fe699c diff --git a/deps/checksums/Pkg-e476cd0c61e19b645cc0e32bb30f8e44f60001f7.tar.gz/sha512 b/deps/checksums/Pkg-e476cd0c61e19b645cc0e32bb30f8e44f60001f7.tar.gz/sha512 new file mode 100644 index 0000000000000..e6703d6365171 --- /dev/null +++ b/deps/checksums/Pkg-e476cd0c61e19b645cc0e32bb30f8e44f60001f7.tar.gz/sha512 @@ -0,0 +1 @@ +6982d5a2eebf2cd2a69b43a9ee8c54c3833f494f89aef9fab852d3b9b48a0724fa58b4f59fbc8dfd27406ae9c8e8c4beedba7f7a8dc8d128d435f6d9a8a03147 diff --git a/stdlib/Pkg.version b/stdlib/Pkg.version index ed4959ee4756e..296410c62e300 100644 --- a/stdlib/Pkg.version +++ b/stdlib/Pkg.version @@ -1,2 +1,2 @@ PKG_BRANCH = master -PKG_SHA1 = 9914dabfd66813197e0c67e28b78cfe0b393fe88 +PKG_SHA1 = e476cd0c61e19b645cc0e32bb30f8e44f60001f7 From 46cd67f6c41b7cd598ff96124de269fa14bf8392 Mon Sep 17 00:00:00 2001 From: Jishnu Bhattacharya Date: Fri, 2 Jul 2021 19:11:38 +0400 Subject: [PATCH 04/16] Distributed: add type assertion in take!(::RemoteChannel) (#41403) --- stdlib/Distributed/src/remotecall.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stdlib/Distributed/src/remotecall.jl b/stdlib/Distributed/src/remotecall.jl index 91e5de36736bd..6be7be2c8a91b 100644 --- a/stdlib/Distributed/src/remotecall.jl +++ b/stdlib/Distributed/src/remotecall.jl @@ -544,7 +544,7 @@ fetch_ref(rid, args...) = fetch(lookup_ref(rid).c, args...) Wait for and get a value from a [`RemoteChannel`](@ref). Exceptions raised are the same as for a [`Future`](@ref). Does not remove the item fetched. """ -fetch(r::RemoteChannel, args...) = call_on_owner(fetch_ref, r, args...) +fetch(r::RemoteChannel, args...) = call_on_owner(fetch_ref, r, args...)::eltype(r) isready(rv::RemoteValue, args...) = isready(rv.c, args...) @@ -623,7 +623,7 @@ end Fetch value(s) from a [`RemoteChannel`](@ref) `rr`, removing the value(s) in the process. """ -take!(rr::RemoteChannel, args...) = call_on_owner(take_ref, rr, myid(), args...) +take!(rr::RemoteChannel, args...) = call_on_owner(take_ref, rr, myid(), args...)::eltype(rr) # close and isopen are not supported on Future From 5584620db87603fb8be313092712a9f052b8876f Mon Sep 17 00:00:00 2001 From: Dilum Aluthge Date: Fri, 2 Jul 2021 14:38:56 -0400 Subject: [PATCH 05/16] README: only have a single Buildkite badge (#41377) --- README.md | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 3f5990cf4c76c..1021f58331087 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,16 @@ Documentation: [![version 1][docs-img]](https://docs.julialang.org) +Code coverage: +[![coveralls][coveralls-img]](https://coveralls.io/r/JuliaLang/julia?branch=master) +[![codecov][codecov-img]](https://codecov.io/github/JuliaLang/julia?branch=master) + +Continuous integration: [![Build status](https://badge.buildkite.com/f28e0d28b345f9fad5856ce6a8d64fffc7c70df8f4f2685cd8.svg?branch=master)](https://buildkite.com/julialang/julia) + [docs-img]: https://img.shields.io/badge/docs-v1-blue.svg +[coveralls-img]: https://img.shields.io/coveralls/github/JuliaLang/julia/master.svg?label=coveralls +[codecov-img]: https://img.shields.io/codecov/c/github/JuliaLang/julia/master.svg?label=codecov + ## The Julia Language @@ -141,19 +150,3 @@ Supported IDEs include: [julia-vscode](https://github.com/JuliaEditorSupport/jul Code plugin), [Juno](http://junolab.org/) (Atom plugin). [Jupyter](https://jupyter.org/) notebooks are available through the [IJulia](https://github.com/JuliaLang/IJulia.jl) package, and [Pluto](https://github.com/fonsp/Pluto.jl) notebooks through the Pluto.jl package. - -## Continuous Integration (CI) Builders - -Code coverage: -[![coveralls][coveralls-img]](https://coveralls.io/r/JuliaLang/julia?branch=master) -[![codecov][codecov-img]](https://codecov.io/github/JuliaLang/julia?branch=master) - -| Builder | Status | -| ---------- | ------ | -| Overall | [![Build status](https://badge.buildkite.com/f28e0d28b345f9fad5856ce6a8d64fffc7c70df8f4f2685cd8.svg?branch=master)](https://buildkite.com/julialang/julia) | -| analyzegc | [![Build status](https://badge.buildkite.com/f28e0d28b345f9fad5856ce6a8d64fffc7c70df8f4f2685cd8.svg?branch=master&step=analyzegc)](https://buildkite.com/julialang/julia) | -| llvmpasses | [![Build status](https://badge.buildkite.com/f28e0d28b345f9fad5856ce6a8d64fffc7c70df8f4f2685cd8.svg?branch=master&step=llvmpasses)](https://buildkite.com/julialang/julia) | -| coverage | [![Build status](https://badge.buildkite.com/d5ae34dbbf6fefe615300c4f3118bf63cb4a5ae7fd962263c1.svg?branch=master)](https://buildkite.com/julialang/julia-coverage-linux64) | - -[coveralls-img]: https://img.shields.io/coveralls/github/JuliaLang/julia/master.svg?label=coveralls -[codecov-img]: https://img.shields.io/codecov/c/github/JuliaLang/julia/master.svg?label=codecov From 4b1e6f37ab52976d3bd8a5d32c022d9945a4b240 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Migniot?= Date: Sun, 4 Jul 2021 10:55:06 +0200 Subject: [PATCH 06/16] [doc] fix typo in functions.md, close #41456(#41459) --- doc/src/manual/functions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/manual/functions.md b/doc/src/manual/functions.md index d8e68d535088f..5fbca52bbfaad 100644 --- a/doc/src/manual/functions.md +++ b/doc/src/manual/functions.md @@ -180,7 +180,7 @@ end ``` This is a *convention* in the sense that `nothing` is not a Julia keyword -but a only singleton object of type `Nothing`. +but only a singleton object of type `Nothing`. Also, you may notice that the `printx` function example above is contrived, because `println` already returns `nothing`, so that the `return` line is redundant. From 18f2f9fabf638b108a3f522bdb9162f7929bd869 Mon Sep 17 00:00:00 2001 From: Daniel Karrasch Date: Sun, 4 Jul 2021 11:36:06 +0200 Subject: [PATCH 07/16] Concatenation with UniformScaling and numbers (#41394) Co-authored-by: Jameson Nash --- stdlib/LinearAlgebra/src/LinearAlgebra.jl | 4 ++-- stdlib/LinearAlgebra/src/uniformscaling.jl | 26 +++++++++++++++------ stdlib/LinearAlgebra/test/uniformscaling.jl | 12 ++++++++++ stdlib/SparseArrays/src/sparsevector.jl | 17 ++++++++------ 4 files changed, 43 insertions(+), 16 deletions(-) diff --git a/stdlib/LinearAlgebra/src/LinearAlgebra.jl b/stdlib/LinearAlgebra/src/LinearAlgebra.jl index 55caad1f82bee..f0f13776146d1 100644 --- a/stdlib/LinearAlgebra/src/LinearAlgebra.jl +++ b/stdlib/LinearAlgebra/src/LinearAlgebra.jl @@ -15,8 +15,8 @@ import Base: USE_BLAS64, abs, acos, acosh, acot, acoth, acsc, acsch, adjoint, as oneunit, parent, power_by_squaring, print_matrix, promote_rule, real, round, sec, sech, setindex!, show, similar, sin, sincos, sinh, size, sqrt, strides, stride, tan, tanh, transpose, trunc, typed_hcat, vec -using Base: IndexLinear, promote_op, promote_typeof, - @propagate_inbounds, @pure, reduce, typed_vcat, require_one_based_indexing, +using Base: IndexLinear, promote_eltype, promote_op, promote_typeof, + @propagate_inbounds, @pure, reduce, typed_hvcat, typed_vcat, require_one_based_indexing, splat using Base.Broadcast: Broadcasted, broadcasted import Libdl diff --git a/stdlib/LinearAlgebra/src/uniformscaling.jl b/stdlib/LinearAlgebra/src/uniformscaling.jl index 44ad5d98e99a4..bbcade43c5569 100644 --- a/stdlib/LinearAlgebra/src/uniformscaling.jl +++ b/stdlib/LinearAlgebra/src/uniformscaling.jl @@ -391,6 +391,7 @@ end # in A to matrices of type T and sizes given by n[k:end]. n is an array # so that the same promotion code can be used for hvcat. We pass the type T # so that we can re-use this code for sparse-matrix hcat etcetera. +promote_to_arrays_(n::Int, ::Type, a::Number) = a promote_to_arrays_(n::Int, ::Type{Matrix}, J::UniformScaling{T}) where {T} = copyto!(Matrix{T}(undef, n,n), J) promote_to_arrays_(n::Int, ::Type, A::AbstractVecOrMat) = A promote_to_arrays(n,k, ::Type) = () @@ -401,11 +402,11 @@ promote_to_arrays(n,k, ::Type{T}, A, B, C) where {T} = (promote_to_arrays_(n[k], T, A), promote_to_arrays_(n[k+1], T, B), promote_to_arrays_(n[k+2], T, C)) promote_to_arrays(n,k, ::Type{T}, A, B, Cs...) where {T} = (promote_to_arrays_(n[k], T, A), promote_to_arrays_(n[k+1], T, B), promote_to_arrays(n,k+2, T, Cs...)...) -promote_to_array_type(A::Tuple{Vararg{Union{AbstractVecOrMat,UniformScaling}}}) = Matrix +promote_to_array_type(A::Tuple{Vararg{Union{AbstractVecOrMat,UniformScaling,Number}}}) = Matrix for (f,dim,name) in ((:hcat,1,"rows"), (:vcat,2,"cols")) @eval begin - function $f(A::Union{AbstractVecOrMat,UniformScaling}...) + function $f(A::Union{AbstractVecOrMat,UniformScaling,Number}...) n = -1 for a in A if !isa(a, UniformScaling) @@ -418,13 +419,13 @@ for (f,dim,name) in ((:hcat,1,"rows"), (:vcat,2,"cols")) end end n == -1 && throw(ArgumentError($("$f of only UniformScaling objects cannot determine the matrix size"))) - return $f(promote_to_arrays(fill(n,length(A)),1, promote_to_array_type(A), A...)...) + return cat(promote_to_arrays(fill(n, length(A)), 1, promote_to_array_type(A), A...)..., dims=Val(3-$dim)) end end end -function hvcat(rows::Tuple{Vararg{Int}}, A::Union{AbstractVecOrMat,UniformScaling}...) +function hvcat(rows::Tuple{Vararg{Int}}, A::Union{AbstractVecOrMat,UniformScaling,Number}...) require_one_based_indexing(A...) nr = length(rows) sum(rows) == length(A) || throw(ArgumentError("mismatch between row sizes and number of arguments")) @@ -467,8 +468,8 @@ function hvcat(rows::Tuple{Vararg{Int}}, A::Union{AbstractVecOrMat,UniformScalin j = 0 for i = 1:nr if rows[i] > 0 && n[j+1] == -1 # this row consists entirely of UniformScalings - nci = nc ÷ rows[i] - nci * rows[i] != nc && throw(DimensionMismatch("indivisible UniformScaling sizes")) + nci, r = divrem(nc, rows[i]) + r != 0 && throw(DimensionMismatch("indivisible UniformScaling sizes")) for k = 1:rows[i] n[j+k] = nci end @@ -476,7 +477,18 @@ function hvcat(rows::Tuple{Vararg{Int}}, A::Union{AbstractVecOrMat,UniformScalin j += rows[i] end end - return hvcat(rows, promote_to_arrays(n,1, promote_to_array_type(A), A...)...) + Atyp = promote_to_array_type(A) + Amat = promote_to_arrays(n, 1, Atyp, A...) + # We have two methods for promote_to_array_type, one returning Matrix and + # another one returning SparseMatrixCSC (in SparseArrays.jl). In the dense + # case, we cannot call hvcat for the promoted UniformScalings because this + # causes a stack overflow. In the sparse case, however, we cannot call + # typed_hvcat because we need a sparse output. + if Atyp == Matrix + return typed_hvcat(promote_eltype(Amat...), rows, Amat...) + else + return hvcat(rows, Amat...) + end end ## Matrix construction from UniformScaling diff --git a/stdlib/LinearAlgebra/test/uniformscaling.jl b/stdlib/LinearAlgebra/test/uniformscaling.jl index 04d4d7d7e0c9e..edbb1789a366b 100644 --- a/stdlib/LinearAlgebra/test/uniformscaling.jl +++ b/stdlib/LinearAlgebra/test/uniformscaling.jl @@ -335,10 +335,19 @@ end B = T(rand(3,3)) C = T(rand(0,3)) D = T(rand(2,0)) + E = T(rand(1,3)) + F = T(rand(3,1)) + α = rand() @test (hcat(A, 2I))::T == hcat(A, Matrix(2I, 3, 3)) + @test (hcat(E, α))::T == hcat(E, [α]) + @test (hcat(E, α, 2I))::T == hcat(E, [α], fill(2, 1, 1)) @test (vcat(A, 2I))::T == vcat(A, Matrix(2I, 4, 4)) + @test (vcat(F, α))::T == vcat(F, [α]) + @test (vcat(F, α, 2I))::T == vcat(F, [α], fill(2, 1, 1)) @test (hcat(C, 2I))::T == C + @test_throws DimensionMismatch hcat(C, α) @test (vcat(D, 2I))::T == D + @test_throws DimensionMismatch vcat(D, α) @test (hcat(I, 3I, A, 2I))::T == hcat(Matrix(I, 3, 3), Matrix(3I, 3, 3), A, Matrix(2I, 3, 3)) @test (vcat(I, 3I, A, 2I))::T == vcat(Matrix(I, 4, 4), Matrix(3I, 4, 4), A, Matrix(2I, 4, 4)) @test (hvcat((2,1,2), B, 2I, I, 3I, 4I))::T == @@ -353,6 +362,9 @@ end hvcat((2,2,2), B, Matrix(2I, 3, 3), C, C, Matrix(3I, 3, 3), Matrix(4I, 3, 3)) @test hvcat((3,2,1), C, C, I, B ,3I, 2I)::T == hvcat((2,2,1), C, C, B, Matrix(3I,3,3), Matrix(2I,6,6)) + @test (hvcat((1,2), A, E, α))::T == hvcat((1,2), A, E, [α]) == hvcat((1,2), A, E, α*I) + @test (hvcat((2,2), α, E, F, 3I))::T == hvcat((2,2), [α], E, F, Matrix(3I, 3, 3)) + @test (hvcat((2,2), 3I, F, E, α))::T == hvcat((2,2), Matrix(3I, 3, 3), F, E, [α]) end end diff --git a/stdlib/SparseArrays/src/sparsevector.jl b/stdlib/SparseArrays/src/sparsevector.jl index dae26a77626b4..55ad738a7eb77 100644 --- a/stdlib/SparseArrays/src/sparsevector.jl +++ b/stdlib/SparseArrays/src/sparsevector.jl @@ -1083,23 +1083,26 @@ const _Triangular_DenseArrays{T,A<:Matrix} = LinearAlgebra.AbstractTriangular{T, const _Annotated_DenseArrays = Union{_Triangular_DenseArrays, _Symmetric_DenseArrays, _Hermitian_DenseArrays} const _Annotated_Typed_DenseArrays{T} = Union{_Triangular_DenseArrays{T}, _Symmetric_DenseArrays{T}, _Hermitian_DenseArrays{T}} -const _SparseConcatGroup = Union{Vector, Adjoint{<:Any,<:Vector}, Transpose{<:Any,<:Vector}, Matrix, _SparseConcatArrays, _Annotated_SparseConcatArrays, _Annotated_DenseArrays} -const _DenseConcatGroup = Union{Vector, Adjoint{<:Any,<:Vector}, Transpose{<:Any,<:Vector}, Matrix, _Annotated_DenseArrays} +const _SparseConcatGroup = Union{Number, Vector, Adjoint{<:Any,<:Vector}, Transpose{<:Any,<:Vector}, Matrix, _SparseConcatArrays, _Annotated_SparseConcatArrays, _Annotated_DenseArrays} +const _DenseConcatGroup = Union{Number, Vector, Adjoint{<:Any,<:Vector}, Transpose{<:Any,<:Vector}, Matrix, _Annotated_DenseArrays} const _TypedDenseConcatGroup{T} = Union{Vector{T}, Adjoint{T,Vector{T}}, Transpose{T,Vector{T}}, Matrix{T}, _Annotated_Typed_DenseArrays{T}} # Concatenations involving un/annotated sparse/special matrices/vectors should yield sparse arrays +_makesparse(x::Number) = x +_makesparse(x::AbstractArray) = SparseMatrixCSC(issparse(x) ? x : sparse(x)) + function Base._cat(dims, Xin::_SparseConcatGroup...) - X = map(x -> SparseMatrixCSC(issparse(x) ? x : sparse(x)), Xin) + X = map(_makesparse, Xin) T = promote_eltype(Xin...) Base.cat_t(T, X...; dims=dims) end function hcat(Xin::_SparseConcatGroup...) - X = map(x -> SparseMatrixCSC(issparse(x) ? x : sparse(x)), Xin) - hcat(X...) + X = map(_makesparse, Xin) + return cat(X..., dims=Val(2)) end function vcat(Xin::_SparseConcatGroup...) - X = map(x -> SparseMatrixCSC(issparse(x) ? x : sparse(x)), Xin) - vcat(X...) + X = map(_makesparse, Xin) + return cat(X..., dims=Val(1)) end hvcat(rows::Tuple{Vararg{Int}}, X::_SparseConcatGroup...) = vcat(_hvcat_rows(rows, X...)...) From 7ffc10bf4ee13d0d0669a6a2315907a2361c38df Mon Sep 17 00:00:00 2001 From: Jameson Nash Date: Sun, 4 Jul 2021 08:45:34 -0400 Subject: [PATCH 08/16] codegen: complete handling for partial-layout objects (#41438) Fixes #41425 --- src/ccall.cpp | 2 +- src/cgutils.cpp | 20 +++++++------------- src/codegen.cpp | 22 ++++++++++----------- src/datatype.c | 41 +++++++++++++++++++++++++--------------- src/jltypes.c | 28 +++++++++++++-------------- src/julia_internal.h | 3 ++- test/compiler/codegen.jl | 13 +++++++++++++ 7 files changed, 74 insertions(+), 55 deletions(-) diff --git a/src/ccall.cpp b/src/ccall.cpp index 15f51cf9d6897..c7853ccc2a8d8 100644 --- a/src/ccall.cpp +++ b/src/ccall.cpp @@ -493,7 +493,7 @@ static Value *julia_to_native( assert(!byRef); // don't expect any ABI to pass pointers by pointer return boxed(ctx, jvinfo); } - assert(jl_is_datatype(jlto) && julia_struct_has_layout((jl_datatype_t*)jlto)); + assert(jl_is_datatype(jlto) && jl_struct_try_layout((jl_datatype_t*)jlto)); typeassert_input(ctx, jvinfo, jlto, jlto_env, argn); if (!byRef) diff --git a/src/cgutils.cpp b/src/cgutils.cpp index 2303ddb286971..f715abb3b490b 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -321,7 +321,7 @@ static size_t dereferenceable_size(jl_value_t *jt) // Array has at least this much data return sizeof(jl_array_t); } - else if (jl_is_datatype(jt) && ((jl_datatype_t*)jt)->layout) { + else if (jl_is_datatype(jt) && jl_struct_try_layout((jl_datatype_t*)jt)) { return jl_datatype_size(jt); } return 0; @@ -339,7 +339,7 @@ static unsigned julia_alignment(jl_value_t *jt) // and this is the guarantee we have for the GC bits return 16; } - assert(jl_is_datatype(jt) && ((jl_datatype_t*)jt)->layout); + assert(jl_is_datatype(jt) && jl_struct_try_layout((jl_datatype_t*)jt)); unsigned alignment = jl_datatype_align(jt); if (alignment > JL_HEAP_ALIGNMENT) return JL_HEAP_ALIGNMENT; @@ -555,16 +555,10 @@ static Type *bitstype_to_llvm(jl_value_t *bt, bool llvmcall = false) } static bool jl_type_hasptr(jl_value_t* typ) -{ // assumes that jl_stored_inline(typ) is true +{ // assumes that jl_stored_inline(typ) is true (and therefore that layout is defined) return jl_is_datatype(typ) && ((jl_datatype_t*)typ)->layout->npointers > 0; } -// return whether all concrete subtypes of this type have the same layout -static bool julia_struct_has_layout(jl_datatype_t *dt) -{ - return dt->layout || jl_has_fixed_layout(dt); -} - static unsigned jl_field_align(jl_datatype_t *dt, size_t i) { unsigned al = jl_field_offset(dt, i); @@ -588,11 +582,8 @@ static Type *_julia_struct_to_llvm(jl_codegen_params_t *ctx, jl_value_t *jt, boo bool isTuple = jl_is_tuple_type(jt); jl_svec_t *ftypes = jl_get_fieldtypes(jst); size_t i, ntypes = jl_svec_len(ftypes); - if (!julia_struct_has_layout(jst)) + if (!jl_struct_try_layout(jst)) return NULL; // caller should have checked jl_type_mappable_to_c already, but we'll be nice - if (jst->layout == NULL) - jl_compute_field_offsets(jst); - assert(jst->layout); if (ntypes == 0 || jl_datatype_nbits(jst) == 0) return T_void; Type *_struct_decl = NULL; @@ -1904,6 +1895,9 @@ static bool emit_getfield_unknownidx(jl_codectx_t &ctx, return true; } if (nfields == 1) { + if (jl_has_free_typevars(jl_field_type(stt, 0))) { + return false; + } (void)idx0(); *ret = emit_getfield_knownidx(ctx, strct, 0, stt, order); return true; diff --git a/src/codegen.cpp b/src/codegen.cpp index dc03d453d4578..3d8ad33516080 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -933,12 +933,12 @@ static MDNode *best_tbaa(jl_value_t *jt) { // note that this includes jl_isbits, although codegen should work regardless static bool jl_is_concrete_immutable(jl_value_t* t) { - return jl_is_immutable_datatype(t) && ((jl_datatype_t*)t)->layout; + return jl_is_immutable_datatype(t) && ((jl_datatype_t*)t)->isconcretetype; } static bool jl_is_pointerfree(jl_value_t* t) { - if (!jl_is_immutable_datatype(t)) + if (!jl_is_concrete_immutable(t)) return 0; const jl_datatype_layout_t *layout = ((jl_datatype_t*)t)->layout; return layout && layout->npointers == 0; @@ -3033,9 +3033,9 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, return true; } - if (jl_is_datatype(utt) && utt->layout) { + if (jl_is_datatype(utt) && jl_struct_try_layout(utt)) { ssize_t idx = jl_field_index(utt, name, 0); - if (idx != -1) { + if (idx != -1 && !jl_has_free_typevars(jl_field_type(utt, idx))) { *ret = emit_getfield_knownidx(ctx, obj, idx, utt, order); return true; } @@ -3063,14 +3063,16 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, } if (jl_is_datatype(utt)) { - if (jl_is_structtype(utt) && utt->layout) { + if (jl_struct_try_layout(utt)) { size_t nfields = jl_datatype_nfields(utt); // integer index size_t idx; if (fld.constant && (idx = jl_unbox_long(fld.constant) - 1) < nfields) { - // known index - *ret = emit_getfield_knownidx(ctx, obj, idx, utt, order); - return true; + if (!jl_has_free_typevars(jl_field_type(utt, idx))) { + // known index + *ret = emit_getfield_knownidx(ctx, obj, idx, utt, order); + return true; + } } else { // unknown index @@ -3115,8 +3117,6 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, } } } - // TODO: attempt better codegen for approximate types, if the types - // and offsets of some fields are independent of parameters. // TODO: generic getfield func with more efficient calling convention return false; } @@ -3155,7 +3155,7 @@ static bool emit_builtin_call(jl_codectx_t &ctx, jl_cgval_t *ret, jl_value_t *f, } jl_datatype_t *uty = (jl_datatype_t*)jl_unwrap_unionall(obj.typ); - if (jl_is_structtype(uty) && uty->layout) { + if (jl_is_datatype(uty) && jl_struct_try_layout(uty)) { ssize_t idx = -1; if (fld.constant && fld.typ == (jl_value_t*)jl_symbol_type) { idx = jl_field_index(uty, (jl_sym_t*)fld.constant, 0); diff --git a/src/datatype.c b/src/datatype.c index 9bad2bc3d3bd8..a321b417d91c0 100644 --- a/src/datatype.c +++ b/src/datatype.c @@ -220,27 +220,36 @@ unsigned jl_special_vector_alignment(size_t nfields, jl_value_t *t) return next_power_of_two(size); } -STATIC_INLINE int jl_is_datatype_make_singleton(jl_datatype_t *d) +STATIC_INLINE int jl_is_datatype_make_singleton(jl_datatype_t *d) JL_NOTSAFEPOINT { return (!d->name->abstract && jl_datatype_size(d) == 0 && d != jl_symbol_type && d->name != jl_array_typename && d->isconcretetype && !d->name->mutabl); } -STATIC_INLINE void jl_maybe_allocate_singleton_instance(jl_datatype_t *st) +STATIC_INLINE void jl_maybe_allocate_singleton_instance(jl_datatype_t *st) JL_NOTSAFEPOINT { if (jl_is_datatype_make_singleton(st)) { // It's possible for st to already have an ->instance if it was redefined - if (!st->instance) { - jl_task_t *ct = jl_current_task; - st->instance = jl_gc_alloc(ct->ptls, 0, st); - jl_gc_wb(st, st->instance); - } + if (!st->instance) + st->instance = jl_gc_permobj(0, st); } } +// return whether all concrete subtypes of this type have the same layout +int jl_struct_try_layout(jl_datatype_t *dt) +{ + if (dt->layout) + return 1; + else if (!jl_has_fixed_layout(dt)) + return 0; + jl_compute_field_offsets(dt); + assert(dt->layout); + return 1; +} + int jl_datatype_isinlinealloc(jl_datatype_t *ty, int pointerfree) JL_NOTSAFEPOINT { - if (ty->name->mayinlinealloc && ty->layout) { + if (ty->name->mayinlinealloc && (ty->isconcretetype || ((jl_datatype_t*)jl_unwrap_unionall(ty->name->wrapper))->layout)) { // TODO: use jl_struct_try_layout(dt) (but it is a safepoint) if (ty->layout->npointers > 0) { if (pointerfree) return 0; @@ -348,9 +357,6 @@ void jl_compute_field_offsets(jl_datatype_t *st) if (st->name->wrapper == NULL) return; // we got called too early--we'll be back jl_datatype_t *w = (jl_datatype_t*)jl_unwrap_unionall(st->name->wrapper); - assert(st->types && w->types); - size_t i, nfields = jl_svec_len(st->types); - assert(st->name->n_uninitialized <= nfields); if (st == w && st->layout) { // this check allows us to force re-computation of the layout for some types during init st->layout = NULL; @@ -358,6 +364,7 @@ void jl_compute_field_offsets(jl_datatype_t *st) st->zeroinit = 0; st->has_concrete_subtype = 1; } + int isbitstype = st->isconcretetype && st->name->mayinlinealloc; // If layout doesn't depend on type parameters, it's stored in st->name->wrapper // and reused by all subtypes. if (w->layout) { @@ -365,11 +372,16 @@ void jl_compute_field_offsets(jl_datatype_t *st) st->size = w->size; st->zeroinit = w->zeroinit; st->has_concrete_subtype = w->has_concrete_subtype; - if (jl_is_layout_opaque(st->layout)) { // e.g. jl_array_typename - return; + if (!jl_is_layout_opaque(st->layout)) { // e.g. jl_array_typename + st->isbitstype = isbitstype && st->layout->npointers == 0; + jl_maybe_allocate_singleton_instance(st); } + return; } - else if (nfields == 0) { + assert(st->types && w->types); + size_t i, nfields = jl_svec_len(st->types); + assert(st->name->n_uninitialized <= nfields); + if (nfields == 0) { // if we have no fields, we can trivially skip the rest if (st == jl_symbol_type || st == jl_string_type) { // opaque layout - heap-allocated blob @@ -404,7 +416,6 @@ void jl_compute_field_offsets(jl_datatype_t *st) } } - int isbitstype = st->isconcretetype && st->name->mayinlinealloc; for (i = 0; isbitstype && i < nfields; i++) { jl_value_t *fld = jl_field_type(st, i); isbitstype = jl_isbits(fld); diff --git a/src/jltypes.c b/src/jltypes.c index f9f60f1227b9a..886abadb046e0 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -223,7 +223,9 @@ int jl_has_fixed_layout(jl_datatype_t *dt) { if (dt->layout || dt->isconcretetype) return 1; - if (jl_is_tuple_type(dt)) + if (dt->name->abstract) + return 0; + if (jl_is_tuple_type(dt) || jl_is_namedtuple_type(dt)) return 0; // TODO: relax more? jl_svec_t *types = jl_get_fieldtypes(dt); size_t i, l = jl_svec_len(types); @@ -242,9 +244,10 @@ int jl_type_mappable_to_c(jl_value_t *ty) assert(!jl_is_typevar(ty) && jl_is_type(ty)); if (jl_is_structtype(ty)) { jl_datatype_t *jst = (jl_datatype_t*)ty; - return jst->layout || jl_has_fixed_layout(jst); + return jl_has_fixed_layout(jst); } - if (jl_is_tuple_type(jl_unwrap_unionall(ty))) + ty = jl_unwrap_unionall(ty); + if (jl_is_tuple_type(ty) || jl_is_namedtuple_type(ty)) return 0; // TODO: relax some? return 1; // as boxed or primitive } @@ -1437,7 +1440,7 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value jl_gc_wb(ndt, ndt->parameters); ndt->types = NULL; // to be filled in below if (istuple) { - ndt->types = p; + ndt->types = p; // TODO: this may need to filter out certain types } else if (isnamedtuple) { jl_value_t *names_tup = jl_svecref(p, 0); @@ -1463,19 +1466,16 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value jl_gc_wb(ndt, ndt->types); } else { - ndt->types = jl_emptysvec; + ndt->types = jl_emptysvec; // XXX: this is essentially always false } } - ndt->size = 0; - jl_precompute_memoized_dt(ndt, cacheable); - - if (jl_is_primitivetype(dt)) { - ndt->size = dt->size; - ndt->layout = dt->layout; - ndt->isbitstype = ndt->isconcretetype; - } jl_datatype_t *primarydt = ((jl_datatype_t*)jl_unwrap_unionall(tn->wrapper)); + jl_precompute_memoized_dt(ndt, cacheable); + ndt->size = 0; + if (primarydt->layout) + jl_compute_field_offsets(ndt); + if (istuple || isnamedtuple) { ndt->super = jl_any_type; } @@ -1516,7 +1516,7 @@ static jl_value_t *inst_datatype_inner(jl_datatype_t *dt, jl_svec_t *p, jl_value // leading to incorrect layouts and data races (#40050: the A{T} should be // an isbitstype singleton of size 0) if (cacheable) { - if (!jl_is_primitivetype(dt) && ndt->types != NULL && ndt->isconcretetype) { + if (dt->layout == NULL && !jl_is_primitivetype(dt) && ndt->types != NULL && ndt->isconcretetype) { jl_compute_field_offsets(ndt); } jl_cache_type_(ndt); diff --git a/src/julia_internal.h b/src/julia_internal.h index c22f8846de52a..e044ecc1bce61 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -388,7 +388,7 @@ STATIC_INLINE jl_gc_tracked_buffer_t *jl_gc_alloc_buf(jl_ptls_t ptls, size_t sz) return jl_gc_alloc(ptls, sz, (void*)jl_buff_tag); } -STATIC_INLINE jl_value_t *jl_gc_permobj(size_t sz, void *ty) +STATIC_INLINE jl_value_t *jl_gc_permobj(size_t sz, void *ty) JL_NOTSAFEPOINT { const size_t allocsz = sz + sizeof(jl_taggedvalue_t); unsigned align = (sz == 0 ? sizeof(void*) : (allocsz <= sizeof(void*) * 2 ? @@ -539,6 +539,7 @@ jl_datatype_t *jl_mk_builtin_func(jl_datatype_t *dt, const char *name, jl_fptr_a int jl_obviously_unequal(jl_value_t *a, jl_value_t *b); JL_DLLEXPORT jl_array_t *jl_find_free_typevars(jl_value_t *v); int jl_has_fixed_layout(jl_datatype_t *t); +int jl_struct_try_layout(jl_datatype_t *dt); int jl_type_mappable_to_c(jl_value_t *ty); jl_svec_t *jl_outer_unionall_vars(jl_value_t *u); jl_value_t *jl_type_intersection_env_s(jl_value_t *a, jl_value_t *b, jl_svec_t **penv, int *issubty); diff --git a/test/compiler/codegen.jl b/test/compiler/codegen.jl index b8fa5536865bb..df29a339d5a85 100644 --- a/test/compiler/codegen.jl +++ b/test/compiler/codegen.jl @@ -580,3 +580,16 @@ g40612(a, b) = a[]|a[] === b[]|b[] @test g40612(Union{Bool,Missing}[missing], Union{Bool,Missing}[missing]) @test g40612(Union{Bool,Missing}[true], Union{Bool,Missing}[true]) @test g40612(Union{Bool,Missing}[false], Union{Bool,Missing}[false]) + +# issue #41438 +struct A41438{T} + x::Ptr{T} +end +struct B41438{T} + x::T +end +f41438(y) = y[].x +@test A41438.body.layout != C_NULL +@test B41438.body.layout === C_NULL +@test f41438(Ref{A41438}(A41438(C_NULL))) === C_NULL +@test f41438(Ref{B41438}(B41438(C_NULL))) === C_NULL From 69c8e0bb4255779dda61a0613b231c00e84748cf Mon Sep 17 00:00:00 2001 From: Michael Abbott <32575566+mcabbott@users.noreply.github.com> Date: Sun, 4 Jul 2021 08:46:22 -0400 Subject: [PATCH 09/16] Mention integers in `mod1` docstring (#41448) Co-authored-by: Jameson Nash --- base/operators.jl | 15 ++++++++++++--- base/range.jl | 4 ++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/base/operators.jl b/base/operators.jl index 3292ab8f7abe6..00211ea56e76b 100644 --- a/base/operators.jl +++ b/base/operators.jl @@ -875,15 +875,24 @@ const ÷ = div Modulus after flooring division, returning a value `r` such that `mod(r, y) == mod(x, y)` in the range ``(0, y]`` for positive `y` and in the range ``[y,0)`` for negative `y`. -See also [`fld1`](@ref), [`fldmod1`](@ref). +With integer arguments and positive `y`, this is equal to `mod(x, 1:y)`, and hence natural +for 1-based indexing. By comparison, `mod(x, y) == mod(x, 0:y-1)` is natural for computations with +offsets or strides. + +See also [`mod`](@ref), [`fld1`](@ref), [`fldmod1`](@ref). # Examples ```jldoctest julia> mod1(4, 2) 2 -julia> mod1(4, 3) -1 +julia> mod1.(-5:5, 3)' +1×11 adjoint(::Vector{Int64}) with eltype Int64: + 1 2 3 1 2 3 1 2 3 1 2 + +julia> mod1.([-0.1, 0, 0.1, 1, 2, 2.9, 3, 3.1]', 3) +1×8 Matrix{Float64}: + 2.9 3.0 0.1 1.0 2.0 2.9 3.0 0.1 ``` """ mod1(x::T, y::T) where {T<:Real} = (m = mod(x, y); ifelse(m == 0, y, m)) diff --git a/base/range.jl b/base/range.jl index 9207949090d1d..8845f363cd38c 100644 --- a/base/range.jl +++ b/base/range.jl @@ -1357,10 +1357,10 @@ See also [`mod1`](@ref). # Examples ```jldoctest -julia> mod(0, Base.OneTo(3)) +julia> mod(0, Base.OneTo(3)) # mod1(0, 3) 3 -julia> mod(3, 0:2) +julia> mod(3, 0:2) # mod(3, 3) 0 ``` From 5faad5fee902b8654880d97ed0d9e533083bded2 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Sun, 4 Jul 2021 23:16:47 +0200 Subject: [PATCH 10/16] remove dependency of Pkg from libblastrampoline_jll (#41460) --- stdlib/libblastrampoline_jll/Project.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/stdlib/libblastrampoline_jll/Project.toml b/stdlib/libblastrampoline_jll/Project.toml index 64f88602b862f..644107b9dac00 100644 --- a/stdlib/libblastrampoline_jll/Project.toml +++ b/stdlib/libblastrampoline_jll/Project.toml @@ -3,7 +3,6 @@ uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" version = "3.0.4+0" [deps] -Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" Artifacts = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" OpenBLAS_jll = "4536629a-c528-5b80-bd46-f80d51c5b363" From e52eb1e6bba9334f80a0cc69a0cfbb3b780e625a Mon Sep 17 00:00:00 2001 From: N5N3 <2642243996@qq.com> Date: Mon, 5 Jul 2021 09:40:57 +0800 Subject: [PATCH 11/16] Update compiler.jl --- base/compiler/compiler.jl | 5 ----- 1 file changed, 5 deletions(-) diff --git a/base/compiler/compiler.jl b/base/compiler/compiler.jl index a3e05b3040f9e..6a0362b78f759 100644 --- a/base/compiler/compiler.jl +++ b/base/compiler/compiler.jl @@ -70,11 +70,6 @@ add_with_overflow(x::T, y::T) where {T<:SignedInt} = checked_sadd_int(x, y) add_with_overflow(x::T, y::T) where {T<:UnsignedInt} = checked_uadd_int(x, y) add_with_overflow(x::Bool, y::Bool) = (x+y, false) -# SIMD loops (The new copyto_unalias! use @simd) -@pure sizeof(s::String) = Core.sizeof(s) # needed by gensym as called from simdloop -include("simdloop.jl") -using .SimdLoop - # core array operations include("indices.jl") include("array.jl") From 06d5fb00478588095f576cdf2b760a201f36648f Mon Sep 17 00:00:00 2001 From: N5N3 <2642243996@qq.com> Date: Mon, 5 Jul 2021 09:43:03 +0800 Subject: [PATCH 12/16] Update Base.jl --- base/Base.jl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/base/Base.jl b/base/Base.jl index 9a4091447395b..42a506479326b 100644 --- a/base/Base.jl +++ b/base/Base.jl @@ -124,11 +124,6 @@ include("refpointer.jl") include("checked.jl") using .Checked -# SIMD loops -@pure sizeof(s::String) = Core.sizeof(s) # needed by gensym as called from simdloop -include("simdloop.jl") -using .SimdLoop - # array structures include("indices.jl") include("array.jl") @@ -177,6 +172,11 @@ using .MultiplicativeInverses include("abstractarraymath.jl") include("arraymath.jl") +# SIMD loops +@pure sizeof(s::String) = Core.sizeof(s) # needed by gensym as called from simdloop +include("simdloop.jl") +using .SimdLoop + # map-reduce operators include("reduce.jl") From 13434770983e70760c731529929c2524219d38cf Mon Sep 17 00:00:00 2001 From: N5N3 <2642243996@qq.com> Date: Mon, 5 Jul 2021 10:06:57 +0800 Subject: [PATCH 13/16] Update abstractarray.jl Move some copyto! definitions to other place. --- base/abstractarray.jl | 109 +++++++++++------------------------------- 1 file changed, 28 insertions(+), 81 deletions(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index eeda52ea22e4c..1ed5a2ef568be 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -886,7 +886,35 @@ function copy!(dst::AbstractArray, src::AbstractArray) end ## from general iterable to any array + +""" + copyto!(dest::AbstractArray, src) -> dest + +Copy all elements from collection `src` to array `dest`, whose length must be greater than +or equal to the length `n` of `src`. The first `n` elements of `dest` are overwritten, +the other elements are left untouched. + +See also [`copy!`](@ref Base.copy!), [`copy`](@ref). +# Examples +```jldoctest +julia> x = [1., 0., 3., 0., 5.]; + +julia> y = zeros(7); + +julia> copyto!(y, x); + +julia> y +7-element Vector{Float64}: + 1.0 + 0.0 + 3.0 + 0.0 + 5.0 + 0.0 + 0.0 +``` +""" function copyto!(dest::AbstractArray, src) destiter = eachindex(dest) y = iterate(destiter) @@ -964,87 +992,6 @@ function copyto!(dest::AbstractArray, dstart::Integer, src, sstart::Integer, n:: return dest end -## copy between abstract arrays - generally more efficient -## since a single index variable can be used. - -""" - copyto!(dest::AbstractArray, src) -> dest - -Copy all elements from collection `src` to array `dest`, whose length must be greater than -or equal to the length `n` of `src`. The first `n` elements of `dest` are overwritten, -the other elements are left untouched. - -See also [`copy!`](@ref Base.copy!), [`copy`](@ref). - -# Examples -```jldoctest -julia> x = [1., 0., 3., 0., 5.]; - -julia> y = zeros(7); - -julia> copyto!(y, x); - -julia> y -7-element Vector{Float64}: - 1.0 - 0.0 - 3.0 - 0.0 - 5.0 - 0.0 - 0.0 -``` -""" -function copyto!(dest::AbstractArray, src::AbstractArray) - isempty(src) && return dest - src′ = unalias(dest, src) - copyto_unaliased!(IndexStyle(dest), dest, IndexStyle(src′), src′) -end - -function copyto!(deststyle::IndexStyle, dest::AbstractArray, srcstyle::IndexStyle, src::AbstractArray) - isempty(src) && return dest - src′ = unalias(dest, src) - copyto_unaliased!(deststyle, dest, srcstyle, src′) -end - -function copyto_unaliased!(deststyle::IndexStyle, dest::AbstractArray, srcstyle::IndexStyle, src::AbstractArray) - isempty(src) && return dest - length(dest) >= length(src) || throw(BoundsError(dest, LinearIndices(src))) - if deststyle isa IndexLinear - if srcstyle isa IndexLinear - Δi = firstindex(dest) - firstindex(src) - for i in eachindex(src) - @inbounds dest[i + Δi] = src[i] - end - else - j = firstindex(dest) - 1 - @inbounds @simd for I in eachindex(src) - dest[j+=1] = src[I] - end - end - else - if srcstyle isa IndexLinear - i = firstindex(src) - 1 - @inbounds @simd for J in eachindex(dest) - dest[J] = src[i+=1] - end - else - iterdest, itersrc = eachindex(dest), eachindex(src) - if iterdest == itersrc - # Shared-iterator implementation - @inbounds @simd for I in itersrc - dest[I] = src[I] - end - else - for (I,J) in zip(itersrc, iterdest) - @inbounds dest[J] = src[I] - end - end - end - end - return dest -end - function copyto!(dest::AbstractArray, dstart::Integer, src::AbstractArray) copyto!(dest, dstart, src, first(LinearIndices(src)), length(src)) end From bbc4a2f17b7d183a4b7dca37b0b8c3190bda41b0 Mon Sep 17 00:00:00 2001 From: N5N3 <2642243996@qq.com> Date: Mon, 5 Jul 2021 10:14:06 +0800 Subject: [PATCH 14/16] Create abstractarraypatch.jl These definitions need @simd. --- base/abstractarraypatch.jl | 53 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 base/abstractarraypatch.jl diff --git a/base/abstractarraypatch.jl b/base/abstractarraypatch.jl new file mode 100644 index 0000000000000..33b4eabf94eee --- /dev/null +++ b/base/abstractarraypatch.jl @@ -0,0 +1,53 @@ +## copy between abstract arrays - generally more efficient +## since a single index variable can be used. +## copyto_unaliased! use @simd to speed up, so these definition is seperated from abstractarray.jl + +function copyto!(dest::AbstractArray, src::AbstractArray) + isempty(src) && return dest + src′ = unalias(dest, src) + copyto_unaliased!(IndexStyle(dest), dest, IndexStyle(src′), src′) +end + +function copyto!(deststyle::IndexStyle, dest::AbstractArray, srcstyle::IndexStyle, src::AbstractArray) + isempty(src) && return dest + src′ = unalias(dest, src) + copyto_unaliased!(deststyle, dest, srcstyle, src′) +end + +function copyto_unaliased!(deststyle::IndexStyle, dest::AbstractArray, srcstyle::IndexStyle, src::AbstractArray) + isempty(src) && return dest + length(dest) >= length(src) || throw(BoundsError(dest, LinearIndices(src))) + if deststyle isa IndexLinear + if srcstyle isa IndexLinear + Δi = firstindex(dest) - firstindex(src) + for i in eachindex(src) + @inbounds dest[i + Δi] = src[i] + end + else + j = firstindex(dest) - 1 + @inbounds @simd for I in eachindex(src) + dest[j+=1] = src[I] + end + end + else + if srcstyle isa IndexLinear + i = firstindex(src) - 1 + @inbounds @simd for J in eachindex(dest) + dest[J] = src[i+=1] + end + else + iterdest, itersrc = eachindex(dest), eachindex(src) + if iterdest == itersrc + # Shared-iterator implementation + @inbounds @simd for I in itersrc + dest[I] = src[I] + end + else + for (I,J) in zip(itersrc, iterdest) + @inbounds dest[J] = src[I] + end + end + end + end + return dest +end From 1838f88b6f5fb541f70f8e0b0f18aaf8e96b718b Mon Sep 17 00:00:00 2001 From: N5N3 <2642243996@qq.com> Date: Mon, 5 Jul 2021 10:17:16 +0800 Subject: [PATCH 15/16] Update Base.jl --- base/Base.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/base/Base.jl b/base/Base.jl index 42a506479326b..0bfd3b6e7d7b7 100644 --- a/base/Base.jl +++ b/base/Base.jl @@ -177,6 +177,9 @@ include("arraymath.jl") include("simdloop.jl") using .SimdLoop +# functions for AbstractArray with @simd +include("abstractarraypatch.jl") + # map-reduce operators include("reduce.jl") From 996e27216a588a3719975b72167f1df7fef72da9 Mon Sep 17 00:00:00 2001 From: N5N3 <2642243996@qq.com> Date: Mon, 5 Jul 2021 10:19:50 +0800 Subject: [PATCH 16/16] Update abstractarraypatch.jl add license info --- base/abstractarraypatch.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/base/abstractarraypatch.jl b/base/abstractarraypatch.jl index 33b4eabf94eee..eee678fccecaf 100644 --- a/base/abstractarraypatch.jl +++ b/base/abstractarraypatch.jl @@ -1,3 +1,5 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + ## copy between abstract arrays - generally more efficient ## since a single index variable can be used. ## copyto_unaliased! use @simd to speed up, so these definition is seperated from abstractarray.jl