diff --git a/base/abstractarray.jl b/base/abstractarray.jl index d11d543daade9..e08d1901e0d81 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -1087,34 +1087,6 @@ foreach(f) = (f(); nothing) foreach(f, itr) = (for x in itr; f(x); end; nothing) foreach(f, itrs...) = (for z in zip(itrs...); f(z...); end; nothing) -# generic map on any iterator -function map(f, iters...) - result = [] - len = length(iters) - states = [start(iters[idx]) for idx in 1:len] - nxtvals = cell(len) - cont = true - for idx in 1:len - if done(iters[idx], states[idx]) - cont = false - break - end - end - while cont - for idx in 1:len - nxtvals[idx],states[idx] = next(iters[idx], states[idx]) - end - push!(result, f(nxtvals...)) - for idx in 1:len - if done(iters[idx], states[idx]) - cont = false - break - end - end - end - result -end - ## map over arrays ## ## transform any set of dimensions @@ -1175,39 +1147,6 @@ function mapslices(f, A::AbstractArray, dims::AbstractVector) return R end - -# using promote_type -function promote_to!{T,F}(f::F, offs, dest::AbstractArray{T}, A::AbstractArray) - # map to dest array, checking the type of each result. if a result does not - # match, do a type promotion and re-dispatch. - for i = offs:length(A) - @inbounds Ai = A[i] - el = f(Ai) - S = typeof(el) - if S === T || S <: T - @inbounds dest[i] = el::T - else - R = promote_type(T, S) - if R !== T - new = similar(dest, R) - copy!(new,1, dest,1, i-1) - new[i] = el - return promote_to!(f, i+1, new, A) - end - @inbounds dest[i] = el - end - end - return dest -end - -function map_promote(f, A::AbstractArray) - if isempty(A); return similar(A, Bottom); end - first = f(A[1]) - dest = similar(A, typeof(first)) - dest[1] = first - return promote_to!(f, 2, dest, A) -end - # These are needed because map(eltype, As) is not inferrable promote_eltype_op(::Any) = (@_pure_meta; Bottom) promote_eltype_op{T}(op, ::AbstractArray{T}) = (@_pure_meta; promote_op(op, T)) @@ -1226,39 +1165,7 @@ function map!{F}(f::F, dest::AbstractArray, A::AbstractArray) return dest end -function map_to!{T,F}(f::F, offs, st, dest::AbstractArray{T}, A) - # map to dest array, checking the type of each result. if a result does not - # match, widen the result type and re-dispatch. - i = offs - while !done(A, st) - @inbounds Ai, st = next(A, st) - el = f(Ai) - S = typeof(el) - if S === T || S <: T - @inbounds dest[i] = el::T - i += 1 - else - R = typejoin(T, S) - new = similar(dest, R) - copy!(new,1, dest,1, i-1) - @inbounds new[i] = el - return map_to!(f, i+1, st, new, A) - end - end - return dest -end - -function map(f, A::AbstractArray) - if isempty(A) - return isa(f,Type) ? similar(A,f) : similar(A) - end - st = start(A) - A1, st = next(A, st) - first = f(A1) - dest = similar(A, typeof(first)) - dest[1] = first - return map_to!(f, 2, st, dest, A) -end +map{F}(f::F, A::AbstractArray) = collect(Generator(f,A)) ## 2 argument function map!{F}(f::F, dest::AbstractArray, A::AbstractArray, B::AbstractArray) @@ -1268,34 +1175,6 @@ function map!{F}(f::F, dest::AbstractArray, A::AbstractArray, B::AbstractArray) return dest end -function map_to!{T,F}(f::F, offs, dest::AbstractArray{T}, A::AbstractArray, B::AbstractArray) - for i = offs:length(A) - @inbounds Ai, Bi = A[i], B[i] - el = f(Ai, Bi) - S = typeof(el) - if (S !== T) && !(S <: T) - R = typejoin(T, S) - new = similar(dest, R) - copy!(new,1, dest,1, i-1) - @inbounds new[i] = el - return map_to!(f, i+1, new, A, B) - end - @inbounds dest[i] = el::T - end - return dest -end - -function map(f, A::AbstractArray, B::AbstractArray) - shp = promote_shape(size(A),size(B)) - if prod(shp) == 0 - return similar(A, promote_type(eltype(A),eltype(B)), shp) - end - first = f(A[1], B[1]) - dest = similar(A, typeof(first), shp) - dest[1] = first - return map_to!(f, 2, dest, A, B) -end - ## N argument ith_all(i, ::Tuple{}) = () @@ -1311,32 +1190,9 @@ end map!{F}(f::F, dest::AbstractArray, As::AbstractArray...) = map_n!(f, dest, As) -function map_to_n!{T,F}(f::F, offs, dest::AbstractArray{T}, As) - for i = offs:length(As[1]) - el = f(ith_all(i, As)...) - S = typeof(el) - if (S !== T) && !(S <: T) - R = typejoin(T, S) - new = similar(dest, R) - copy!(new,1, dest,1, i-1) - @inbounds new[i] = el - return map_to_n!(f, i+1, new, As) - end - @inbounds dest[i] = el::T - end - return dest -end +spread(f) = (args)->f(args...) -function map(f, As::AbstractArray...) - shape = mapreduce(size, promote_shape, As) - if prod(shape) == 0 - return similar(As[1], promote_eltype(As...), shape) - end - first = f(map(a->a[1], As)...) - dest = similar(As[1], typeof(first), shape) - dest[1] = first - return map_to_n!(f, 2, dest, As) -end +map(f, iters...) = collect(Generator(spread(f),zip(iters...))) # multi-item push!, unshift! (built on top of type-specific 1-item version) # (note: must not cause a dispatch loop when 1-item case is not defined) diff --git a/base/array.jl b/base/array.jl index 89596506a1206..ad20b5a96cd5a 100644 --- a/base/array.jl +++ b/base/array.jl @@ -204,30 +204,93 @@ promote_rule{T,n,S}(::Type{Array{T,n}}, ::Type{Array{S,n}}) = Array{promote_type Return an array of type `Array{element_type,1}` of all items in a collection. """ -function collect{T}(::Type{T}, itr) - if applicable(length, itr) - # when length() isn't defined this branch might pollute the - # type of the other. - a = Array(T,length(itr)::Integer) - i = 0 - for x in itr - a[i+=1] = x - end - else - a = Array(T,0) - for x in itr - push!(a,x) - end - end - return a -end +collect{T}(::Type{T}, itr) = _collect_t(T, itr, iteratorsize(itr)) """ collect(collection) Return an array of all items in a collection. For associative collections, returns Pair{KeyType, ValType}. """ -collect(itr) = collect(eltype(itr), itr) +collect(itr) = _collect(itr, iteratoreltype(itr), iteratorsize(itr)) + +_collect(itr, ::HasEltype, isz) = _collect_t(eltype(itr), itr, isz) + +_collect_t(T::Type, itr, ::HasLength) = copy!(Array(T,Int(length(itr)::Integer)), itr) +_collect_t(T::Type, itr, ::HasShape) = copy!(Array(T,convert(Dims,size(itr))), itr) +function _collect_t(T::Type, itr, ::SizeUnknown) + a = Array(T,0) + for x in itr + push!(a,x) + end + return a +end + +_collect(itr, ::EltypeUnknown, ::HasLength) = _collect_shaped(itr, (Int(length(itr)),)) +_collect(itr, ::EltypeUnknown, ::HasShape) = _collect_shaped(itr, convert(Dims,size(itr))) + +_default_container(itr, elty, sz) = Array(elty, sz) +_default_container(itr::AbstractArray, elty, sz) = similar(itr, elty, sz) + +function collect_to!{T}(itr, offs, st, dest::AbstractArray{T}) + # collect to dest array, checking the type of each result. if a result does not + # match, widen the result type and re-dispatch. + i = offs + while !done(itr, st) + el, st = next(itr, st) + S = typeof(el) + if S === T || S <: T + @inbounds dest[i] = el::T + i += 1 + else + R = typejoin(T, S) + new = similar(dest, R) + copy!(new,1, dest,1, i-1) + @inbounds new[i] = el + return collect_to!(itr, i+1, st, new) + end + end + return dest +end + +function _collect_shaped(itr, sz) + if prod(sz) == 0 + return _default_container(itr, Union{}, sz) + end + st = start(itr) + v1, st = next(itr, st) + dest = _default_container(itr, typeof(v1), sz) + dest[1] = v1 + return collect_to!(itr, 2, st, dest) +end + +function grow_to!{T}(itr, st, dest::AbstractArray{T}) + while !done(itr, st) + el, st = next(itr, st) + S = typeof(el) + if S === T || S <: T + push!(dest, el::T) + else + R = typejoin(T, S) + n = length(dest) + new = similar(dest, R, n+1) + copy!(new,1, dest,1, n) + @inbounds new[n+1] = el + return grow_to!(itr, st, new) + end + end + return dest +end + +function _collect(itr, ::EltypeUnknown, ::SizeUnknown) + st = start(itr) + if done(itr,st) + return _default_container(itr, Union{}, 0) + end + v1, st = next(itr, st) + dest = _default_container(itr, typeof(v1), 1) + dest[1] = v1 + return grow_to!(itr, st, dest) +end ## Iteration ## start(A::Array) = 1 diff --git a/base/dict.jl b/base/dict.jl index c6f52be16e69d..67a61c3c47f58 100644 --- a/base/dict.jl +++ b/base/dict.jl @@ -4,6 +4,9 @@ abstract Associative{K,V} +iteratorsize{T<:Associative}(::Type{T}) = HasLength() +iteratoreltype{T<:Associative}(::Type{T}) = HasEltype() + const secret_table_token = :__c782dbf1cf4d6a2e5e3865d7e95634f2e09b5902__ haskey(d::Associative, k) = in(k,keys(d)) diff --git a/base/docs/helpdb/Base.jl b/base/docs/helpdb/Base.jl index 725144d806079..c2ba3e043fe3a 100644 --- a/base/docs/helpdb/Base.jl +++ b/base/docs/helpdb/Base.jl @@ -2095,8 +2095,7 @@ isdigit """ @windows -Given `@windows? a : b`, do `a` on Windows and `b` elsewhere. See documentation for Handling -Platform Variations in the Calling C and Fortran Code section of the manual. +Given `@windows? a : b`, do `a` on Windows and `b` elsewhere. See documentation in [Handling Operating System Variation](:ref:`Handling Operating System Variation `). """ :@windows @@ -2104,11 +2103,25 @@ Platform Variations in the Calling C and Fortran Code section of the manual. @unix Given `@unix? a : b`, do `a` on Unix systems (including Linux and OS X) and `b` elsewhere. -See documentation for Handling Platform Variations in the Calling C and Fortran Code section -of the manual. +See documentation in [Handling Operating System Variation](:ref:`Handling Operating System Variation `). """ :@unix +""" + @windows_only + +A macro that evaluates the given expression only on Windows systems. See documentation in [Handling Operating System Variation](:ref:`Handling Operating System Variation `). +""" +:@windows_only + +""" + @unix_only + +A macro that evaluates the given expression only on Unix systems (including Linux and OS X). See +documentation in [Handling Operating System Variation](:ref:`Handling Operating System Variation `). +""" +:@unix_only + """ num2hex(f) @@ -6538,11 +6551,17 @@ ndims """ @osx -Given `@osx? a : b`, do `a` on OS X and `b` elsewhere. See documentation for Handling -Platform Variations in the Calling C and Fortran Code section of the manual. +Given `@osx? a : b`, do `a` on OS X and `b` elsewhere. See documentation in [Handling Operating System Variation](:ref:`Handling Operating System Variation `). """ :@osx +""" + @osx_only + +A macro that evaluates the given expression only on OS X systems. See documentation in [Handling Operating System Variation](:ref:`Handling Operating System Variation `). +""" +:@osx_only + """ ishermitian(A) -> Bool @@ -8194,11 +8213,17 @@ cumprod! """ @linux -Given `@linux? a : b`, do `a` on Linux and `b` elsewhere. See documentation for Handling -Platform Variations in the Calling C and Fortran Code section of the manual. +Given `@linux? a : b`, do `a` on Linux and `b` elsewhere. See documentation [Handling Operating System Variation](:ref:`Handling Operating System Variation `). """ :@linux +""" + @linux_only + +A macro that evaluates the given expression only on Linux systems. See documentation in [Handling Operating System Variation](:ref:`Handling Operating System Variation `). +""" +:@linux_only + """ complement(s) diff --git a/base/env.jl b/base/env.jl index 0cf7922660eaf..0f47a04202e78 100644 --- a/base/env.jl +++ b/base/env.jl @@ -1,74 +1,63 @@ # This file is a part of Julia. License is MIT: http://julialang.org/license @unix_only begin - _getenv(var::AbstractString) = ccall(:getenv, Cstring, (Cstring,), var) - _hasenv(s::AbstractString) = _getenv(s) != C_NULL + +_getenv(var::AbstractString) = ccall(:getenv, Cstring, (Cstring,), var) +_hasenv(s::AbstractString) = _getenv(s) != C_NULL + +function access_env(onError::Function, var::AbstractString) + val = _getenv(var) + val == C_NULL ? onError(var) : bytestring(val) +end + +function _setenv(var::AbstractString, val::AbstractString, overwrite::Bool=true) + ret = ccall(:setenv, Int32, (Cstring,Cstring,Int32), var, val, overwrite) + systemerror(:setenv, ret != 0) +end + +function _unsetenv(var::AbstractString) + ret = ccall(:unsetenv, Int32, (Cstring,), var) + systemerror(:unsetenv, ret != 0) end +end # @unix_only + @windows_only begin + const ERROR_ENVVAR_NOT_FOUND = UInt32(203) + _getenvlen(var::AbstractString) = ccall(:GetEnvironmentVariableW,stdcall,UInt32,(Cwstring,Ptr{UInt8},UInt32),var,C_NULL,0) _hasenv(s::AbstractString) = _getenvlen(s)!=0 || Libc.GetLastError()!=ERROR_ENVVAR_NOT_FOUND -function _jl_win_getenv(s::UTF16String,len::UInt32) - val=zeros(UInt16,len) - ret=ccall(:GetEnvironmentVariableW,stdcall,UInt32,(Cwstring,Ptr{UInt16},UInt32),s,val,len) - if (ret == 0 && len != 1) || ret != len-1 || val[end] != 0 - error(string("getenv: ", s, ' ', len, "-1 != ", ret, ": ", Libc.FormatMessage())) - end - val -end -end -macro accessEnv(var,errorcase) - @unix_only return quote - val=_getenv($(esc(var))) - if val == C_NULL - $(esc(errorcase)) - end - bytestring(val) +function access_env(onError::Function, str::AbstractString) + var = utf16(str) + len = _getenvlen(var) + if len == 0 + return Libc.GetLastError() != ERROR_ENVVAR_NOT_FOUND ? utf8("") : onError(str) end - @windows_only return quote - let var = utf16($(esc(var))) - len=_getenvlen(var) - if len == 0 - if Libc.GetLastError() != ERROR_ENVVAR_NOT_FOUND - return utf8("") - else - $(esc(errorcase)) - end - end - utf8(UTF16String(_jl_win_getenv(var,len))) - end + val = zeros(UInt16,len) + ret = ccall(:GetEnvironmentVariableW,stdcall,UInt32,(Cwstring,Ptr{UInt16},UInt32),var,val,len) + if (ret == 0 && len != 1) || ret != len-1 || val[end] != 0 + error(string("getenv: ", str, ' ', len, "-1 != ", ret, ": ", Libc.FormatMessage())) end + return utf8(UTF16String(val)) end -function _setenv(var::AbstractString, val::AbstractString, overwrite::Bool) - @unix_only begin - ret = ccall(:setenv, Int32, (Cstring,Cstring,Int32), var, val, overwrite) - systemerror(:setenv, ret != 0) - end - @windows_only begin - var = utf16(var) - if overwrite || !_hasenv(var) - ret = ccall(:SetEnvironmentVariableW,stdcall,Int32,(Cwstring,Cwstring),var,val) - systemerror(:setenv, ret == 0) - end +function _setenv(var::AbstractString, val::AbstractString, overwrite::Bool=true) + var = utf16(var) + if overwrite || !_hasenv(var) + ret = ccall(:SetEnvironmentVariableW,stdcall,Int32,(Cwstring,Cwstring),var,val) + systemerror(:setenv, ret == 0) end end -_setenv(var::AbstractString, val::AbstractString) = _setenv(var, val, true) - function _unsetenv(var::AbstractString) - @unix_only begin - ret = ccall(:unsetenv, Int32, (Cstring,), var) - systemerror(:unsetenv, ret != 0) - end - @windows_only begin - ret = ccall(:SetEnvironmentVariableW,stdcall,Int32,(Cwstring,Ptr{UInt16}),var,C_NULL) - systemerror(:setenv, ret == 0) - end + ret = ccall(:SetEnvironmentVariableW,stdcall,Int32,(Cwstring,Ptr{UInt16}),var,C_NULL) + systemerror(:setenv, ret == 0) end +end # @windows_only + ## ENV: hash interface ## type EnvHash <: Associative{ByteString,ByteString}; end @@ -76,19 +65,12 @@ const ENV = EnvHash() similar(::EnvHash) = Dict{ByteString,ByteString}() -getindex(::EnvHash, k::AbstractString) = @accessEnv k throw(KeyError(k)) -get(::EnvHash, k::AbstractString, def) = @accessEnv k (return def) +getindex(::EnvHash, k::AbstractString) = access_env(k->throw(KeyError(k)), k) +get(::EnvHash, k::AbstractString, def) = access_env(k->def, k) in(k::AbstractString, ::KeyIterator{EnvHash}) = _hasenv(k) pop!(::EnvHash, k::AbstractString) = (v = ENV[k]; _unsetenv(k); v) pop!(::EnvHash, k::AbstractString, def) = haskey(ENV,k) ? pop!(ENV,k) : def -function delete!(::EnvHash, k::AbstractString) - warn_once(""" - delete!(ENV,key) now returns the modified environment. - Use pop!(ENV,key) to retrieve the value instead. - """) - _unsetenv(k) - ENV -end +delete!(::EnvHash, k::AbstractString) = (_unsetenv(k); ENV) delete!(::EnvHash, k::AbstractString, def) = haskey(ENV,k) ? delete!(ENV,k) : def setindex!(::EnvHash, v, k::AbstractString) = _setenv(k,string(v)) push!(::EnvHash, k::AbstractString, v) = setindex!(ENV, v, k) @@ -114,7 +96,7 @@ end @windows_only begin start(hash::EnvHash) = (pos = ccall(:GetEnvironmentStringsW,stdcall,Ptr{UInt16},()); (pos,pos)) function done(hash::EnvHash, block::Tuple{Ptr{UInt16},Ptr{UInt16}}) - if unsafe_load(block[1])==0 + if unsafe_load(block[1]) == 0 ccall(:FreeEnvironmentStringsW,stdcall,Int32,(Ptr{UInt16},),block[2]) return true end @@ -155,12 +137,12 @@ function withenv{T<:AbstractString}(f::Function, keyvals::Pair{T}...) old = Dict{T,Any}() for (key,val) in keyvals old[key] = get(ENV,key,nothing) - val !== nothing ? (ENV[key]=val) : _unsetenv(key) + val !== nothing ? (ENV[key]=val) : delete!(ENV, key) end try f() finally for (key,val) in old - val !== nothing ? (ENV[key]=val) : _unsetenv(key) + val !== nothing ? (ENV[key]=val) : delete!(ENV, key) end end end diff --git a/base/generator.jl b/base/generator.jl index 34da38023886b..cce7238c83601 100644 --- a/base/generator.jl +++ b/base/generator.jl @@ -11,6 +11,8 @@ immutable Generator{I,F} iter::I end +Generator{T,I}(::Type{T}, iter::I) = Generator{I,Type{T}}(T, iter) + start(g::Generator) = start(g.iter) done(g::Generator, s) = done(g.iter, s) function next(g::Generator, s) @@ -18,4 +20,39 @@ function next(g::Generator, s) g.f(v), s2 end -collect(g::Generator) = map(g.f, g.iter) +## iterator traits + +abstract IteratorSize +immutable SizeUnknown <: IteratorSize end +immutable HasLength <: IteratorSize end +immutable HasShape <: IteratorSize end + +iteratorsize(x) = iteratorsize(typeof(x)) +iteratorsize(::Type) = SizeUnknown() + +and_iteratorsize{T}(isz::T, ::T) = isz +and_iteratorsize(::HasLength, ::HasShape) = HasLength() +and_iteratorsize(::HasShape, ::HasLength) = HasLength() +and_iteratorsize(a, b) = SizeUnknown() + +abstract IteratorEltype +immutable EltypeUnknown <: IteratorEltype end +immutable HasEltype <: IteratorEltype end + +iteratoreltype(x) = iteratoreltype(typeof(x)) +iteratoreltype(::Type) = EltypeUnknown() + +and_iteratoreltype{T}(iel::T, ::T) = iel +and_iteratoreltype(a, b) = EltypeUnknown() + +iteratorsize{T<:AbstractArray}(::Type{T}) = HasShape() +iteratorsize{T<:AbstractString}(::Type{T}) = HasLength() +iteratorsize{T<:Tuple}(::Type{T}) = HasLength() +iteratorsize{I,F}(::Type{Generator{I,F}}) = iteratorsize(I) +length(g::Generator) = length(g.iter) +size(g::Generator) = size(g.iter) + +iteratoreltype{T<:AbstractArray}(::Type{T}) = HasEltype() +iteratoreltype{T<:AbstractString}(::Type{T}) = HasEltype() +iteratoreltype{I,T}(::Type{Generator{I,Type{T}}}) = HasEltype() +eltype{I,T}(::Type{Generator{I,Type{T}}}) = T diff --git a/base/iterator.jl b/base/iterator.jl index 0b526aae32cbf..de4bfa34085e3 100644 --- a/base/iterator.jl +++ b/base/iterator.jl @@ -10,6 +10,7 @@ end enumerate(itr) = Enumerate(itr) length(e::Enumerate) = length(e.itr) +size(e::Enumerate) = size(e.itr) start(e::Enumerate) = (1, start(e.itr)) function next(e::Enumerate, state) n = next(e.itr,state[2]) @@ -19,6 +20,9 @@ done(e::Enumerate, state) = done(e.itr, state[2]) eltype{I}(::Type{Enumerate{I}}) = Tuple{Int, eltype(I)} +iteratorsize{I}(::Type{Enumerate{I}}) = iteratorsize(I) +iteratoreltype{I}(::Type{Enumerate{I}}) = iteratoreltype(I) + # zip abstract AbstractZipIterator @@ -28,6 +32,7 @@ immutable Zip1{I} <: AbstractZipIterator end zip(a) = Zip1(a) length(z::Zip1) = length(z.a) +size(z::Zip1) = size(z.a) eltype{I}(::Type{Zip1{I}}) = Tuple{eltype(I)} start(z::Zip1) = (start(z.a),) function next(z::Zip1, st) @@ -36,12 +41,16 @@ function next(z::Zip1, st) end done(z::Zip1, st) = done(z.a,st[1]) +iteratorsize{I}(::Type{Zip1{I}}) = iteratorsize(I) +iteratoreltype{I}(::Type{Zip1{I}}) = iteratoreltype(I) + immutable Zip2{I1, I2} <: AbstractZipIterator a::I1 b::I2 end zip(a, b) = Zip2(a, b) length(z::Zip2) = min(length(z.a), length(z.b)) +size(z::Zip2) = promote_shape(size(z.a), size(z.b)) eltype{I1,I2}(::Type{Zip2{I1,I2}}) = Tuple{eltype(I1), eltype(I2)} start(z::Zip2) = (start(z.a), start(z.b)) function next(z::Zip2, st) @@ -51,12 +60,16 @@ function next(z::Zip2, st) end done(z::Zip2, st) = done(z.a,st[1]) | done(z.b,st[2]) +iteratorsize{I1,I2}(::Type{Zip2{I1,I2}}) = and_iteratorsize(iteratorsize(I1),iteratorsize(I2)) +iteratoreltype{I1,I2}(::Type{Zip2{I1,I2}}) = and_iteratoreltype(iteratoreltype(I1),iteratoreltype(I2)) + immutable Zip{I, Z<:AbstractZipIterator} <: AbstractZipIterator a::I z::Z end zip(a, b, c...) = Zip(a, zip(b, c...)) length(z::Zip) = min(length(z.a), length(z.z)) +size(z::Zip) = promote_shape(size(z.a), size(z.z)) tuple_type_cons{S}(::Type{S}, ::Type{Union{}}) = Union{} function tuple_type_cons{S,T<:Tuple}(::Type{S}, ::Type{T}) @_pure_meta @@ -71,6 +84,9 @@ function next(z::Zip, st) end done(z::Zip, st) = done(z.a,st[1]) | done(z.z,st[2]) +iteratorsize{I1,I2}(::Type{Zip{I1,I2}}) = and_iteratorsize(iteratorsize(I1),iteratorsize(I2)) +iteratoreltype{I1,I2}(::Type{Zip{I1,I2}}) = and_iteratoreltype(iteratoreltype(I1),iteratoreltype(I2)) + # filter immutable Filter{F,I} @@ -108,6 +124,7 @@ end done(f::Filter, s) = s[1] eltype{I}(::Type{Filter{I}}) = eltype(I) +iteratoreltype{F,I}(::Type{Filter{F,I}}) = iteratoreltype(I) # Rest -- iterate starting at the given state @@ -122,6 +139,7 @@ next(i::Rest, st) = next(i.itr, st) done(i::Rest, st) = done(i.itr, st) eltype{I}(::Type{Rest{I}}) = eltype(I) +iteratoreltype{I,S}(::Type{Rest{I,S}}) = iteratoreltype(I) # Count -- infinite counting @@ -134,6 +152,7 @@ countfrom(start::Number) = Count(start, one(start)) countfrom() = Count(1, 1) eltype{S}(::Type{Count{S}}) = S +iteratoreltype{I<:Count}(::Type{I}) = HasEltype() start(it::Count) = it.start next(it::Count, state) = (state, state + it.step) @@ -148,6 +167,7 @@ end take(xs, n::Int) = Take(xs, n) eltype{I}(::Type{Take{I}}) = eltype(I) +iteratoreltype{I}(::Type{Take{I}}) = iteratoreltype(I) start(it::Take) = (it.n, start(it.xs)) @@ -171,6 +191,7 @@ end drop(xs, n::Int) = Drop(xs, n) eltype{I}(::Type{Drop{I}}) = eltype(I) +iteratoreltype{I}(::Type{Drop{I}}) = iteratoreltype(I) function start(it::Drop) xs_state = start(it.xs) @@ -195,6 +216,7 @@ end cycle(xs) = Cycle(xs) eltype{I}(::Type{Cycle{I}}) = eltype(I) +iteratoreltype{I}(::Type{Cycle{I}}) = iteratoreltype(I) function start(it::Cycle) s = start(it.xs) @@ -219,6 +241,7 @@ immutable Repeated{O} end repeated(x) = Repeated(x) eltype{O}(::Type{Repeated{O}}) = O +iteratoreltype{O}(::Type{Repeated{O}}) = HasEltype() start(it::Repeated) = nothing next(it::Repeated, state) = (it.x, nothing) done(it::Repeated, state) = false @@ -253,7 +276,9 @@ changes the fastest. Example: product(a) = Zip1(a) product(a, b) = Prod2(a, b) eltype{I1,I2}(::Type{Prod2{I1,I2}}) = Tuple{eltype(I1), eltype(I2)} +iteratoreltype{I1,I2}(::Type{Prod2{I1,I2}}) = and_iteratoreltype(iteratoreltype(I1),iteratoreltype(I2)) length(p::AbstractProdIterator) = length(p.a)*length(p.b) +iteratorsize{I1,I2}(::Type{Prod2{I1,I2}}) = prod_iteratorsize(iteratorsize(I1),iteratorsize(I2)) function start(p::AbstractProdIterator) s1, s2 = start(p.a), start(p.b) @@ -287,12 +312,17 @@ end product(a, b, c...) = Prod(a, product(b, c...)) eltype{I1,I2}(::Type{Prod{I1,I2}}) = tuple_type_cons(eltype(I1), eltype(I2)) +iteratoreltype{I1,I2}(::Type{Prod{I1,I2}}) = and_iteratoreltype(iteratoreltype(I1),iteratoreltype(I2)) +iteratorsize{I1,I2}(::Type{Prod{I1,I2}}) = prod_iteratorsize(iteratorsize(I1),iteratorsize(I2)) @inline function next{I1,I2}(p::Prod{I1,I2}, st) x = prod_next(p, st) ((x[1][1],x[1][2]...), x[2]) end +prod_iteratorsize(::Union{HasLength,HasShape}, ::Union{HasLength,HasShape}) = HasLength() +prod_iteratorsize(a, b) = SizeUnknown() + _size(p::Prod2) = (length(p.a), length(p.b)) _size(p::Prod) = (length(p.a), _size(p.b)...) @@ -325,19 +355,7 @@ next(i::IteratorND, s) = next(i.iter, s) size(i::IteratorND) = i.dims length(i::IteratorND) = prod(size(i)) ndims{I,N}(::IteratorND{I,N}) = N +iteratorsize{T<:IteratorND}(::Type{T}) = HasShape() eltype{I}(::IteratorND{I}) = eltype(I) - -collect(i::IteratorND) = copy!(Array(eltype(i),size(i)), i) - -function collect{I<:IteratorND}(g::Generator{I}) - sz = size(g.iter) - if length(g.iter) == 0 - return Array(Union{}, sz) - end - st = start(g) - first, st = next(g, st) - dest = Array(typeof(first), sz) - dest[1] = first - return map_to!(g.f, 2, st, dest, g.iter) -end +iteratoreltype{I}(::Type{IteratorND{I}}) = iteratoreltype(I) diff --git a/base/mmap.jl b/base/mmap.jl index 5f9cda44f0fe2..832fbcbff1648 100644 --- a/base/mmap.jl +++ b/base/mmap.jl @@ -87,7 +87,7 @@ function gethandle(io::IO) return Int(handle) end -settings(sh::Anonymous) = utf16(sh.name), sh.readonly, sh.create +settings(sh::Anonymous) = sh.name, sh.readonly, sh.create settings(io::IO) = Ptr{Cwchar_t}(0), isreadonly(io), true end # @windows_only @@ -124,7 +124,7 @@ function mmap{T,N}(io::IO, @windows_only begin name, readonly, create = settings(io) - szfile = convert(DWORD, len + offset) + szfile = convert(Csize_t, len + offset) readonly && szfile > filesize(io) && throw(ArgumentError("unable to increase file size to $szfile due to read-only permissions")) handle = create ? ccall(:CreateFileMappingW, stdcall, Ptr{Void}, (Cptrdiff_t, Ptr{Void}, DWORD, DWORD, DWORD, Cwstring), file_desc, C_NULL, readonly ? PAGE_READONLY : PAGE_READWRITE, szfile >> 32, szfile & typemax(UInt32), name) : diff --git a/base/sparse.jl b/base/sparse.jl index e8ae4bf35b61b..d45eb0004a3e7 100644 --- a/base/sparse.jl +++ b/base/sparse.jl @@ -17,7 +17,7 @@ import Base: @get!, acos, acosd, acot, acotd, acsch, asech, asin, asind, asinh, log2, lu, maxabs, minabs, next, sec, secd, sech, show, showarray, sin, sinc, sind, sinh, sinpi, squeeze, start, sum, sumabs, sumabs2, summary, tan, tand, tanh, trace, transpose!, tril!, triu!, trunc, vecnorm, writemime, abs, abs2, - broadcast, ceil, complex, cond, conj, convert, copy, ctranspose, diagm, + broadcast, ceil, complex, cond, conj, convert, copy, copy!, ctranspose, diagm, exp, expm1, factorize, find, findmax, findmin, findnz, float, full, getindex, hcat, hvcat, imag, indmax, ishermitian, kron, length, log, log1p, max, min, maximum, minimum, norm, one, promote_eltype, real, reinterpret, reshape, rot180, diff --git a/base/sparse/sparsematrix.jl b/base/sparse/sparsematrix.jl index 05b51f78babf3..21fab807e582d 100644 --- a/base/sparse/sparsematrix.jl +++ b/base/sparse/sparsematrix.jl @@ -193,6 +193,23 @@ end copy(S::SparseMatrixCSC) = SparseMatrixCSC(S.m, S.n, copy(S.colptr), copy(S.rowval), copy(S.nzval)) +function copy!{TvA, TiA, TvB, TiB}(A::SparseMatrixCSC{TvA,TiA}, + B::SparseMatrixCSC{TvB,TiB}) + # If the two matrices have the same size then all the + # elements in A will be overwritten and we can simply copy the + # internal fields of B to A. + if size(A) == size(B) + copy!(A.colptr, B.colptr) + resize!(A.nzval, length(B.nzval)) + resize!(A.rowval, length(B.rowval)) + copy!(A.rowval, B.rowval) + copy!(A.nzval, B.nzval) + else + invoke(Base.copy!, Tuple{AbstractMatrix{TvA}, AbstractMatrix{TvB}}, A, B) + end + return A +end + similar(S::SparseMatrixCSC, Tv::Type=eltype(S)) = SparseMatrixCSC(S.m, S.n, copy(S.colptr), copy(S.rowval), Array(Tv, length(S.nzval))) similar{Tv,Ti,TvNew,TiNew}(S::SparseMatrixCSC{Tv,Ti}, ::Type{TvNew}, ::Type{TiNew}) = SparseMatrixCSC(S.m, S.n, convert(Array{TiNew},S.colptr), convert(Array{TiNew}, S.rowval), Array(TvNew, length(S.nzval))) similar{Tv, N}(S::SparseMatrixCSC, ::Type{Tv}, d::NTuple{N, Integer}) = spzeros(Tv, d...) diff --git a/contrib/julia-mode.el b/contrib/julia-mode.el index bd5e792ac85c4..0907483dcf08c 100644 --- a/contrib/julia-mode.el +++ b/contrib/julia-mode.el @@ -3202,7 +3202,7 @@ y2 = g(x)")) :type 'string :group 'julia) -(defvar julia-prompt-regexp "julia>" +(defvar julia-prompt-regexp "^\\w*> " "Regexp for matching `inferior-julia' prompt.") (defvar inferior-julia-mode-map diff --git a/doc/index.rst b/doc/index.rst index b1ef5c7781112..1cffce078fc20 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -41,6 +41,7 @@ manual/dates manual/running-external-programs manual/calling-c-and-fortran-code + manual/handling-operating-system-variation manual/interacting-with-julia manual/embedding manual/packages diff --git a/doc/manual/calling-c-and-fortran-code.rst b/doc/manual/calling-c-and-fortran-code.rst index 231a79c1725ec..90d965dc75186 100644 --- a/doc/manual/calling-c-and-fortran-code.rst +++ b/doc/manual/calling-c-and-fortran-code.rst @@ -1049,33 +1049,3 @@ C++ Limited support for C++ is provided by the `Cpp `_, `Clang `_, and `Cxx `_ packages. - -Handling Operating System Variation ------------------------------------ - -When dealing with platform libraries, it is often necessary to provide special cases -for various platforms. The variable ``OS_NAME`` can be used to write these special -cases. Additionally, there are several macros intended to make this easier: -``@windows``, ``@unix``, ``@linux``, and ``@osx``. Note that ``@linux`` and ``@osx`` are mutually -exclusive subsets of ``@unix``. Their usage takes the form of a ternary conditional -operator, as demonstrated in the following examples. - -Simple blocks:: - - ccall( (@windows? :_fopen : :fopen), ...) - -Complex blocks:: - - @linux? ( - begin - some_complicated_thing(a) - end - : begin - some_different_thing(a) - end - ) - -Chaining (parentheses optional, but recommended for readability):: - - @windows? :a : (@osx? :b : :c) - diff --git a/doc/manual/constructors.rst b/doc/manual/constructors.rst index 1e88fb5898eb1..73f4398f3b70b 100644 --- a/doc/manual/constructors.rst +++ b/doc/manual/constructors.rst @@ -570,11 +570,10 @@ constructors for abstract types, by explicitly defining methods for the appropriate types. However, in some cases you could consider adding methods to -``Base.convert`` *instead* of defining a constructor, because defining -a :func:`convert` method *automatically* defines a corresponding -constructor, while the reverse is not true. That is, defining -``Base.convert(::Type{T}, args...) = ...`` automatically defines a -constructor ``T(args...) = ...``. +``Base.convert`` *instead* of defining a constructor, because Julia +falls back to calling :func:`convert` if no matching constructor +is found. For example, if no constructor ``T(args...) = ...`` exists +``Base.convert(::Type{T}, args...) = ...`` is called. ``convert`` is used extensively throughout Julia whenever one type needs to be converted to another (e.g. in assignment, ``ccall``, diff --git a/doc/manual/handling-operating-system-variation.rst b/doc/manual/handling-operating-system-variation.rst new file mode 100644 index 0000000000000..aa81937a64dc6 --- /dev/null +++ b/doc/manual/handling-operating-system-variation.rst @@ -0,0 +1,38 @@ +.. _man-handling-operating-system-variation: + +************************************* + Handling Operating System Variation +************************************* + +When dealing with platform libraries, it is often necessary to provide special cases +for various platforms. The variable ``OS_NAME`` can be used to write these special +cases. There are several macros intended to make this easier: ``@windows_only``, +``@unix_only``, ``@linux_only``, and ``@osx_only``. These may be used as follows:: + + @windows_only begin + some_complicated_thing(a) + end + +Note that ``@linux_only`` and ``@osx_only`` are mutually exclusive subsets of ``@unix_only``\ . (This +similarly applies to ``@unix``\ .) +Additionally, there are:``@windows``, ``@unix``, ``@linux``, and ``@osx``. Their usage takes +the form of a ternary conditional operator, as demonstrated in the following examples. + +Simple blocks:: + + ccall( (@windows? :_fopen : :fopen), ...) + +Complex blocks:: + + @linux? ( + begin + some_complicated_thing(a) + end + : begin + some_different_thing(a) + end + ) + +Chaining (parentheses optional, but recommended for readability):: + + @windows? :a : (@osx? :b : :c) diff --git a/doc/manual/index.rst b/doc/manual/index.rst index d601ce5606550..415b9e30bd0ae 100644 --- a/doc/manual/index.rst +++ b/doc/manual/index.rst @@ -32,6 +32,7 @@ interacting-with-julia running-external-programs calling-c-and-fortran-code + handling-operating-system-variation embedding packages profile diff --git a/doc/stdlib/base.rst b/doc/stdlib/base.rst index 9e7121e8ce180..ecbb001bae889 100644 --- a/doc/stdlib/base.rst +++ b/doc/stdlib/base.rst @@ -977,25 +977,49 @@ System .. Docstring generated from Julia source - Given ``@unix? a : b``\ , do ``a`` on Unix systems (including Linux and OS X) and ``b`` elsewhere. See documentation for Handling Platform Variations in the Calling C and Fortran Code section of the manual. + Given ``@unix? a : b``\ , do ``a`` on Unix systems (including Linux and OS X) and ``b`` elsewhere. See documentation in :ref:`Handling Operating System Variation `\ . + +.. function:: @unix_only + + .. Docstring generated from Julia source + + A macro that evaluates the given expression only on Unix systems (including Linux and OS X). See documentation in :ref:`Handling Operating System Variation `\ . .. function:: @osx .. Docstring generated from Julia source - Given ``@osx? a : b``\ , do ``a`` on OS X and ``b`` elsewhere. See documentation for Handling Platform Variations in the Calling C and Fortran Code section of the manual. + Given ``@osx? a : b``\ , do ``a`` on OS X and ``b`` elsewhere. See documentation in :ref:`Handling Operating System Variation `\ . + +.. function:: @osx_only + + .. Docstring generated from Julia source + + A macro that evaluates the given expression only on OS X systems. See documentation in :ref:`Handling Operating System Variation `\ . .. function:: @linux .. Docstring generated from Julia source - Given ``@linux? a : b``\ , do ``a`` on Linux and ``b`` elsewhere. See documentation for Handling Platform Variations in the Calling C and Fortran Code section of the manual. + Given ``@linux? a : b``\ , do ``a`` on Linux and ``b`` elsewhere. See documentation :ref:`Handling Operating System Variation `\ . + +.. function:: @linux_only + + .. Docstring generated from Julia source + + A macro that evaluates the given expression only on Linux systems. See documentation in :ref:`Handling Operating System Variation `\ . .. function:: @windows .. Docstring generated from Julia source - Given ``@windows? a : b``\ , do ``a`` on Windows and ``b`` elsewhere. See documentation for Handling Platform Variations in the Calling C and Fortran Code section of the manual. + Given ``@windows? a : b``\ , do ``a`` on Windows and ``b`` elsewhere. See documentation in :ref:`Handling Operating System Variation `\ . + +.. function:: @windows_only + + .. Docstring generated from Julia source + + A macro that evaluates the given expression only on Windows systems. See documentation in :ref:`Handling Operating System Variation `\ . Errors ------ diff --git a/src/flisp/julia_extensions.c b/src/flisp/julia_extensions.c index ad1482cefeb5a..61746cc39c0ba 100644 --- a/src/flisp/julia_extensions.c +++ b/src/flisp/julia_extensions.c @@ -187,8 +187,10 @@ value_t fl_accum_julia_symbol(fl_context_t *fl_ctx, value_t *args, uint32_t narg type_error(fl_ctx, "accum-julia-symbol", "wchar", args[0]); uint32_t wc = *(uint32_t*)cp_data((cprim_t*)ptr(args[0])); ios_t str; + int allascii=1; ios_mem(&str, 0); - while (jl_id_char(wc)) { + do { + allascii &= (wc <= 0x7f); ios_getutf8(s, &wc); if (wc == '!') { uint32_t nwc; @@ -202,9 +204,9 @@ value_t fl_accum_julia_symbol(fl_context_t *fl_ctx, value_t *args, uint32_t narg ios_pututf8(&str, wc); if (ios_peekutf8(s, &wc) == IOS_EOF) break; - } + } while (jl_id_char(wc)); ios_pututf8(&str, 0); - return symbol(fl_ctx, normalize(fl_ctx, str.buf)); + return symbol(fl_ctx, allascii ? str.buf : normalize(fl_ctx, str.buf)); } static const builtinspec_t julia_flisp_func_info[] = { diff --git a/src/julia-parser.scm b/src/julia-parser.scm index 510d75cea99fe..070ad44d2e202 100644 --- a/src/julia-parser.scm +++ b/src/julia-parser.scm @@ -158,9 +158,6 @@ ;; --- lexer --- -(define special-char? - (let ((chrs (string->list "()[]{},;\"`@"))) - (lambda (c) (memv c chrs)))) (define (newline? c) (eqv? c #\newline)) (define (skip-to-eol port) @@ -438,15 +435,15 @@ (define (next-token port s) (aset! s 2 (eq? (skip-ws port whitespace-newline) #t)) (let ((c (peek-char port))) - (cond ((or (eof-object? c) (newline? c)) (read-char port)) + (cond ((or (eof-object? c) (eqv? c #\newline)) (read-char port)) - ((identifier-start-char? c) (accum-julia-symbol c port)) + ((identifier-start-char? c) (accum-julia-symbol c port)) - ((special-char? c) (read-char port)) + ((string.find "()[]{},;\"`@" c) (read-char port)) - ((char-numeric? c) (read-number port #f #f)) + ((string.find "0123456789" c) (read-number port #f #f)) - ((eqv? c #\#) (skip-comment port) (next-token port s)) + ((eqv? c #\#) (skip-comment port) (next-token port s)) ;; . is difficult to handle; it could start a number or operator ((and (eqv? c #\.) diff --git a/test/abstractarray.jl b/test/abstractarray.jl index 363ad822840d1..28d22b31554a4 100644 --- a/test/abstractarray.jl +++ b/test/abstractarray.jl @@ -411,23 +411,16 @@ function test_map(::Type{TestAbstractArray}) A = Array(Int, 10) B = Float64[1:10...] C = Float64[1:10...] - @test Base.map_to!(f, 1, A, B, C) == Real[ 2 * i for i in 1:10 ] - @test map(f, Int[], Float64[]) == Float64[] + @test map(f, convert(Vector{Int},B), C) == Float64[ 2 * i for i in 1:10 ] + @test map(f, Int[], Float64[]) == Union{}[] # AbstractArray map for N-arg case f(x, y, z) = x + y + z D = Float64[1:10...] @test map!(f, A, B, C, D) == Int[ 3 * i for i in 1:10 ] - @test Base.map_to_n!(f, 1, A, (B, C, D)) == Real[ 3 * i for i in 1:10 ] @test map(f, B, C, D) == Float64[ 3 * i for i in 1:10 ] - @test map(f, Int[], Int[], Complex{Int}[]) == Number[] -end - -function test_map_promote(::Type{TestAbstractArray}) - A = [1:10...] - f(x) = iseven(x) ? 1.0 : 1 - @test Base.map_promote(f, A) == fill(1.0, 10) + @test map(f, Int[], Int[], Complex{Int}[]) == Union{}[] end function test_UInt_indexing(::Type{TestAbstractArray}) @@ -492,7 +485,6 @@ test_get(TestAbstractArray) test_cat(TestAbstractArray) test_ind2sub(TestAbstractArray) test_map(TestAbstractArray) -test_map_promote(TestAbstractArray) test_UInt_indexing(TestAbstractArray) test_vcat_depwarn(TestAbstractArray) test_13315(TestAbstractArray) diff --git a/test/arrayops.jl b/test/arrayops.jl index 47593953bf694..e0cf3e4a8826f 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -1459,7 +1459,7 @@ let A = zeros(Int, 2, 2), B = zeros(Float64, 2, 2) end # issue #14482 -@inferred Base.map_to!(Int8, 1, 1, Int8[0], Int[0]) +@inferred map(Int8, Int[0]) # make sure @inbounds isn't used too much type OOB_Functor{T}; a::T; end diff --git a/test/datafmt.jl b/test/datafmt.jl index 8e7cba730e8ce..fe32b81f6408e 100644 --- a/test/datafmt.jl +++ b/test/datafmt.jl @@ -259,7 +259,7 @@ for writefunc in ((io,x) -> writemime(io, "text/csv", x), let x = ["foo", "bar"], io = IOBuffer() writefunc(io, x) seek(io, 0) - @test collect(readcsv(io)) == x + @test vec(readcsv(io)) == x end end diff --git a/test/numbers.jl b/test/numbers.jl index 85914957ed3af..71003e482ee1e 100644 --- a/test/numbers.jl +++ b/test/numbers.jl @@ -2710,3 +2710,51 @@ end # issue #12536 @test Rational{Int16}(1,2) === Rational(Int16(1),Int16(2)) @test Rational{Int16}(500000,1000000) === Rational(Int16(1),Int16(2)) + + +rand_int = rand(Int8) + +for T in [Int8, Int16, Int32, Int128, BigInt] + @test num(convert(T, rand_int)) == rand_int + @test den(convert(T, rand_int)) == 1 + + @test typemin(Rational{T}) == -one(T)//zero(T) + @test typemax(Rational{T}) == one(T)//zero(T) + @test widen(Rational{T}) == Rational{widen(T)} +end + +@test Rational(Float32(rand_int)) == Rational(rand_int) + +@test Rational(Rational(rand_int)) == Rational(rand_int) + +@test begin + var = -Rational(UInt32(0)) + var == UInt32(0) +end + +@test Rational(rand_int, 3)/Complex(3, 2) == Complex(Rational(rand_int, 13), -Rational(rand_int*2, 39)) + +@test Complex(rand_int, 0) == Rational(rand_int) +@test Rational(rand_int) == Complex(rand_int, 0) + +@test (Complex(rand_int, 4) == Rational(rand_int)) == false +@test (Rational(rand_int) == Complex(rand_int, 4)) == false + +@test trunc(Rational(BigInt(rand_int), BigInt(3))) == Rational(trunc(BigInt, Rational(BigInt(rand_int),BigInt(3)))) +@test ceil(Rational(BigInt(rand_int), BigInt(3))) == Rational( ceil(BigInt, Rational(BigInt(rand_int),BigInt(3)))) +@test round(Rational(BigInt(rand_int), BigInt(3))) == Rational(round(BigInt, Rational(BigInt(rand_int),BigInt(3)))) + + +for a = -3:3 + @test Rational(Float32(a)) == Rational(a) + @test Rational(a)//2 == a//2 + @test a//Rational(2) == Rational(a/2) + @test a.//[-2, -1, 1, 2] == [-a//2, -a//1, a//1, a//2] + for b=-3:3, c=1:3 + @test b//(a+c*im) == b*a//(a^2+c^2)-(b*c//(a^2+c^2))*im + for d=-3:3 + @test (a+b*im)//(c+d*im) == (a*c+b*d+(b*c-a*d)*im)//(c^2+d^2) + @test Complex(Rational(a)+b*im)//Complex(Rational(c)+d*im) == Complex(a+b*im)//Complex(c+d*im) + end + end +end \ No newline at end of file diff --git a/test/sparsedir/sparse.jl b/test/sparsedir/sparse.jl index 8175d4de0922c..acf1df68adbfb 100644 --- a/test/sparsedir/sparse.jl +++ b/test/sparsedir/sparse.jl @@ -225,8 +225,31 @@ b = randn(3) @test scale(0.5, dA) == scale!(0.5, copy(sA)) @test scale!(sC, 0.5, sA) == scale!(sC, sA, 0.5) -# conj +# copy! +let + A = sprand(5, 5, 0.2) + B = sprand(5, 5, 0.2) + copy!(A, B) + @test A == B + @test pointer(A.nzval) != pointer(B.nzval) + @test pointer(A.rowval) != pointer(B.rowval) + @test pointer(A.colptr) != pointer(B.colptr) + # Test size(A) != size(B) + B = sprand(3, 3, 0.2) + copy!(A, B) + @test A[1:9] == B[:] + # Test eltype(A) != eltype(B), size(A) != size(B) + B = sparse(rand(Float32, 3, 3)) + copy!(A, B) + @test A[1:9] == B[:] + # Test eltype(A) != eltype(B), size(A) == size(B) + A = sparse(rand(Float64, 3, 3)) + B = sparse(rand(Float32, 3, 3)) + copy!(A, B) + @test A == B +end +# conj cA = sprandn(5,5,0.2) + im*sprandn(5,5,0.2) @test full(conj(cA)) == conj(full(cA)) @@ -1098,11 +1121,11 @@ A = sparse(reshape([1.0],1,1)) Ac = sprandn(20,20,.5) + im* sprandn(20,20,.5) Ar = sprandn(20,20,.5) @test cond(A,1) == 1.0 -@test_approx_eq_eps cond(Ar,1) cond(full(Ar),1) 1e-4 -# this test fails sometimes, cf. issue #14778 -# @test_approx_eq_eps cond(Ac,1) cond(full(Ac),1) 1e-4 -@test_approx_eq_eps cond(Ar,Inf) cond(full(Ar),Inf) 1e-4 -@test_approx_eq_eps cond(Ac,Inf) cond(full(Ac),Inf) 1e-4 +# For a discussion of the tolerance, see #14778 +@test 0.99 <= cond(Ar, 1) \ norm(Ar, 1) * norm(inv(full(Ar)), 1) < 3 +@test 0.99 <= cond(Ac, 1) \ norm(Ac, 1) * norm(inv(full(Ac)), 1) < 3 +@test 0.99 <= cond(Ar, Inf) \ norm(Ar, Inf) * norm(inv(full(Ar)), Inf) < 3 +@test 0.99 <= cond(Ac, Inf) \ norm(Ac, Inf) * norm(inv(full(Ac)), Inf) < 3 @test_throws ArgumentError cond(A,2) @test_throws ArgumentError cond(A,3) let Arect = spzeros(10, 6) diff --git a/test/sysinfo.jl b/test/sysinfo.jl index 3136227606b93..c6d687fa2c556 100644 --- a/test/sysinfo.jl +++ b/test/sysinfo.jl @@ -12,6 +12,10 @@ Base.Sys.loadavg() @test_throws ArgumentError ENV["okname"] = "bad\0val" @test_throws ArgumentError Sys.set_process_title("bad\0title") +withenv("bad"=>"dog") do + @test_throws ArgumentError ENV["bad\0cat"] +end + # issue #11170 withenv("TEST"=>"nonempty") do @test ENV["TEST"] == "nonempty" @@ -25,3 +29,9 @@ let c = collect(ENV) @test length(ENV) == length(c) @test isempty(ENV) || first(ENV) in c end + +# test for non-existent keys +key = randstring(25) +@test !haskey(ENV,key) +@test_throws KeyError ENV[key] +@test get(ENV,key,"default") == "default" diff --git a/test/unicode/utf8proc.jl b/test/unicode/utf8proc.jl index 4f979c347b721..5cca4da65c1b6 100644 --- a/test/unicode/utf8proc.jl +++ b/test/unicode/utf8proc.jl @@ -244,7 +244,7 @@ let grphtest = (("b\u0300lahβlahb\u0302láh", ["b\u0300","l","a","h", @test typeof(first(graphemes(s_))) == SubString{typeof(s_)} end grph = collect(graphemes(s_)) - @test eltype(grph) == SubString{typeof(s_)} + @test isempty(grph) || eltype(grph) == SubString{typeof(s_)} @test grph == g_ @test length(graphemes(s_)) == length(grph) end