Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: proposed new array assignment shape matching rule #5226

Closed
wants to merge 8 commits into from
43 changes: 9 additions & 34 deletions base/array.jl
Original file line number Diff line number Diff line change
Expand Up @@ -433,15 +433,15 @@ end

function setindex!{T}(A::Array{T}, X::Array{T}, I::Range1{Int})
if length(X) != length(I)
error("tried to assign $(length(X)) elements to $(length(I)) destinations");
throw_setindex_mismatch(X, (I,))
end
copy!(A, first(I), X, 1, length(I))
return A
end

function setindex!{T<:Real}(A::Array, X::AbstractArray, I::AbstractVector{T})
if length(X) != length(I)
error("tried to assign $(length(X)) elements to $(length(I)) destinations");
throw_setindex_mismatch(X, (I,))
end
count = 1
if is(X,A)
Expand All @@ -465,7 +465,7 @@ function setindex!{T<:Real}(A::Array, x, i::Real, J::AbstractVector{T})
else
X = x
if length(X) != length(J)
error("tried to assign $(length(X)) elements to $(length(J)) destinations");
throw_setindex_mismatch(X, (i,J))
end
count = 1
for j in J
Expand All @@ -489,7 +489,7 @@ function setindex!{T<:Real}(A::Array, x, I::AbstractVector{T}, j::Real)
else
X = x
if length(X) != length(I)
error("tried to assign $(length(X)) elements to $(length(I)) destinations");
throw_setindex_mismatch(X, (I,j))
end
count = 1
for i in I
Expand All @@ -504,19 +504,15 @@ function setindex!{T}(A::Array{T}, X::Array{T}, I::Range1{Int}, j::Real)
j = to_index(j)
checkbounds(A, I, j)
if length(X) != length(I)
error("tried to assign $(length(X)) elements to $(length(I)) destinations");
throw_setindex_mismatch(X, (I,j))
end
unsafe_copy!(A, first(I) + (j-1)*size(A,1), X, 1, length(I))
return A
end

function setindex!{T}(A::Array{T}, X::Array{T}, I::Range1{Int}, J::Range1{Int})
checkbounds(A, I, J)
nel = length(I)*length(J)
if length(X) != nel ||
(ndims(X) > 1 && (size(X,1)!=length(I) || size(X,2)!=length(J)))
error("tried to assign $(size(X,1)) x $(size(X,2)) Array to $(length(I)) x $(length(J)) destination");
end
setindex_shape_check(X, I, J)
if length(I) == size(A,1)
unsafe_copy!(A, first(I) + (first(J)-1)*size(A,1), X, 1, size(A,1)*length(J))
else
Expand All @@ -531,11 +527,7 @@ end

function setindex!{T}(A::Array{T}, X::Array{T}, I::Range1{Int}, J::AbstractVector{Int})
checkbounds(A, I, J)
nel = length(I)*length(J)
if length(X) != nel ||
(ndims(X) > 1 && (size(X,1)!=length(I) || size(X,2)!=length(J)))
error("tried to assign $(size(X)) Array to ($(length(I)),$(length(J))) destination");
end
setindex_shape_check(X, I, J)
refoffset = 1
for j = J
unsafe_copy!(A, first(I) + (j-1)*size(A,1), X, refoffset, length(I))
Expand All @@ -556,11 +548,7 @@ function setindex!{T<:Real}(A::Array, x, I::AbstractVector{T}, J::AbstractVector
end
else
X = x
nel = length(I)*length(J)
if length(X) != nel ||
(ndims(X) > 1 && (size(X,1)!=length(I) || size(X,2)!=length(J)))
error("tried to assign $(size(X,1)) x $(size(X,2)) Array to $(length(I)) x $(length(J)) destination");
end
setindex_shape_check(X, I, J)
count = 1
for j in J
offset = (j-1)*m
Expand Down Expand Up @@ -593,20 +581,7 @@ function setindex!(A::Array, x, I::Union(Real,AbstractArray)...)
assign_cache = Dict()
end
X = x
nel = 1
for idx in I
nel *= length(idx)
end
if length(X) != nel
throw(DimensionMismatch(""))
end
if ndims(X) > 1
for i = 1:length(I)
if size(X,i) != length(I[i])
throw(DimensionMismatch(""))
end
end
end
setindex_shape_check(X, I...)
gen_array_index_map(assign_cache, storeind -> quote
A[$storeind] = X[refind]
refind += 1
Expand Down
5 changes: 4 additions & 1 deletion base/client.jl
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ function repl_callback(ast::ANY, show_value)
put(repl_channel, (ast, show_value))
end

_eval_done = Condition()

function run_repl()
global const repl_channel = RemoteRef()

Expand All @@ -155,7 +157,7 @@ function run_repl()
read(STDIN, buf)
ccall(:jl_read_buffer,Void,(Ptr{Void},Cssize_t),buf,1)
if _repl_enough_stdin
yield()
wait(_eval_done)
end
end
put(repl_channel,(nothing,-1))
Expand All @@ -175,6 +177,7 @@ function run_repl()
break
end
eval_user_input(ast, show_value!=0)
notify(_eval_done)
end

if have_color
Expand Down
75 changes: 64 additions & 11 deletions base/operators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -205,24 +205,77 @@ end
index_shape(I::Real...) = ()
index_shape(i, I...) = tuple(length(i), index_shape(I...)...)

function throw_setindex_mismatch(X, I)
if length(I) == 1
e = DimensionMismatch("tried to assign $(length(X)) elements to $(length(I[1])) destinations")
else
e = DimensionMismatch("tried to assign $(dims2string(size(X))) array to $(dims2string(map(length,I))) destination")
end
throw(e)
end

# check for valid sizes in A[I...] = X where X <: AbstractArray
# we want to allow dimensions that are equal up to permutation, but only
# for permutations that leave array elements in the same linear order.
# those are the permutations that preserve the order of the non-singleton
# dimensions.
function setindex_shape_check(X::AbstractArray, I...)
nel = 1
for idx in I
nel *= length(idx)
end
if length(X) != nel
error("dimensions must match")
end
if ndims(X) > 1
for i = 1:length(I)
if size(X,i) != length(I[i])
error("dimensions must match")
li = ndims(X)
lj = length(I)
i = j = 1
while true
ii = size(X,i)
jj = length(I[j])::Int
if i == li || j == lj
while i < li
i += 1
ii *= size(X,i)
end
while j < lj
j += 1
jj *= length(I[j])::Int
end
if ii != jj
throw_setindex_mismatch(X, I)
end
return
end
if ii == jj
i += 1
j += 1
elseif ii == 1
i += 1
elseif jj == 1
j += 1
else
throw_setindex_mismatch(X, I)
end
end
end

setindex_shape_check(X::AbstractArray) =
(length(X)==1 || throw_setindex_mismatch(X,()))

setindex_shape_check(X::AbstractArray, i) =
(length(X)==length(i) || throw_setindex_mismatch(X, (i,)))

setindex_shape_check{T}(X::AbstractArray{T,1}, i) =
(length(X)==length(i) || throw_setindex_mismatch(X, (i,)))

setindex_shape_check{T}(X::AbstractArray{T,1}, i, j) =
(length(X)==length(i)*length(j) || throw_setindex_mismatch(X, (i,j)))

function setindex_shape_check{T}(X::AbstractArray{T,2}, i, j)
li, lj = length(i), length(j)
if length(X) != li*lj
throw_setindex_mismatch(X, (i,j))
end
sx1 = size(X,1)
if !(li == 1 || li == sx1 || sx1 == 1)
throw_setindex_mismatch(X, (i,j))
end
end

# convert to integer index
to_index(i) = i
to_index(i::Real) = convert(Int, i)
Expand Down
2 changes: 1 addition & 1 deletion src/ccall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@ static native_sym_arg_t interpret_symbol_arg(jl_value_t *arg, jl_codectx_t *ctx,
"cglobal: first argument not a pointer or valid constant expression",
ctx);
}
jl_ptr = emit_unbox(T_size, arg1, ptr_ty);
jl_ptr = emit_unbox(T_size, arg1, (jl_value_t*)jl_voidpointer_type);
}

void *fptr=NULL;
Expand Down
3 changes: 1 addition & 2 deletions src/cgutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1229,8 +1229,7 @@ static Value *boxed(Value *v, jl_codectx_t *ctx, jl_value_t *jt)
Value *tpl = builder.CreateCall(jl_alloc_tuple_func,ConstantInt::get(T_size,n));
int last_depth = ctx->argDepth;
make_gcroot(tpl,ctx);
for (size_t i = 0; i < n; ++i)
{
for (size_t i = 0; i < n; ++i) {
jl_value_t *jti = jl_tupleref(jt,i);
Value *vi = emit_tupleref(v,ConstantInt::get(T_size,i+1),jt,ctx);
emit_tupleset(tpl,ConstantInt::get(T_size,i+1),boxed(vi,ctx,jti),jt,ctx);
Expand Down