Skip to content

Fix tuple types for 0.4 #232

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

Merged
merged 12 commits into from
Apr 25, 2015
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ notifications:
email: false
script:
- if [[ -a .git/shallow ]]; then git fetch --unshallow; fi
- julia -e 'Pkg.clone(pwd()); Pkg.build("HDF5"); Pkg.add("JLDArchives")'
- if [ $TRAVIS_JULIA_VERSION = "nightly" ]; then julia --check-bounds=yes --inline=no --code-coverage=user -e 'include(Pkg.dir("HDF5", "test", "runtests.jl")); include(Pkg.dir("JLDArchives", "test", "runtests.jl"))'; fi
- julia -e 'Pkg.clone(pwd()); Pkg.build("HDF5"); Pkg.add("JLDArchives"); Pkg.checkout("JLDArchives")'
- if [ $TRAVIS_JULIA_VERSION = "nightly" ]; then julia --check-bounds=yes --inline=no --code-coverage=user -e 'reload("HDF5/test/runtests.jl"); workspace(); import LastMain.Compat, LastMain.HDF5; reload("HDF5/src/JLD.jl"); reload("JLDArchives/test/runtests.jl")'; fi
- if [ $TRAVIS_JULIA_VERSION = "release" ]; then julia --check-bounds=yes -e 'Pkg.test("HDF5"); Pkg.test("JLDArchives")'; fi
after_success:
- if [ $TRAVIS_JULIA_VERSION = "nightly" ]; then julia -e 'cd(Pkg.dir("HDF5")); Pkg.add("Coverage"); using Coverage; Coveralls.submit(Coveralls.process_folder())'; fi
127 changes: 95 additions & 32 deletions src/JLD.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,6 @@ import HDF5: close, dump, exists, file, getindex, setindex!, g_create, g_open, o
HDF5ReferenceObj, HDF5BitsKind, ismmappable, readmmap
import Base: length, endof, show, done, next, ndims, start, delete!, size, sizeof

# .jld files written before v"0.4.0-dev+1419" might have UInt32 instead of UInt32 as the typename string.
# See julia issue #8907
if VERSION >= v"0.4.0-dev+1419"
julia_type(s::AbstractString) = _julia_type(replace(s, r"UInt(?=\d{1,3})", "UInt"))
else
julia_type(s::AbstractString) = _julia_type(s)
end


const magic_base = "Julia data file (HDF5), version "
const version_current = v"0.1"
const pathrefs = "/_refs"
Expand Down Expand Up @@ -111,6 +102,11 @@ immutable AssociativeWrapper{K,V,T<:Associative}
values::Vector{V}
end

# Wrapper for SimpleVector
immutable SimpleVectorWrapper
elements::Vector
end

include("jld_types.jl")

file(x::JldFile) = x
Expand Down Expand Up @@ -294,7 +290,7 @@ function delete!(parent::Union(JldFile, JldGroup), path::ByteString)
exists(parent, path) || error("$path does not exist in $parent")
delete!(parent[path])
end
delete!(parent::Union(JldFile, JldGroup), args::(ByteString...)) = for a in args delete!(parent,a) end
delete!(parent::Union(JldFile, JldGroup), args::@compat Tuple{Vararg{ByteString}}) = for a in args delete!(parent,a) end
ismmappable(obj::JldDataset) = ismmappable(obj.plain)
readmmap(obj::JldDataset, args...) = readmmap(obj.plain, args...)
setindex!(parent::Union(JldFile, JldGroup), val, path::ASCIIString) = write(parent, path, val)
Expand Down Expand Up @@ -376,11 +372,16 @@ function after_read{K,V,T}(x::AssociativeWrapper{K,V,T})
ret
end

# Special case for SimpleVector
if VERSION >= v"0.4.0-dev+4319"
after_read(x::SimpleVectorWrapper) = Base.svec(x.elements...)
end

## Arrays

# Read an array
function read_array(obj::JldDataset, dtype::HDF5Datatype, dspace_id::HDF5.Hid, dsel_id::HDF5.Hid,
dims::(Int...)=convert((Int...), HDF5.h5s_get_simple_extent_dims(dspace_id)[1]))
dims::(@compat Tuple{Vararg{Int}})=convert((@compat Tuple{Vararg{Int}}), HDF5.h5s_get_simple_extent_dims(dspace_id)[1]))
if HDF5.h5t_get_class(dtype) == HDF5.H5T_REFERENCE
return read_refs(obj, refarray_eltype(obj), dspace_id, dsel_id, dims)
else
Expand All @@ -390,7 +391,7 @@ end

# Arrays of basic HDF5 kinds
function read_vals{S<:HDF5BitsKind}(obj::JldDataset, dtype::HDF5Datatype, T::Union(Type{S}, Type{Complex{S}}),
dspace_id::HDF5.Hid, dsel_id::HDF5.Hid, dims::(Int...))
dspace_id::HDF5.Hid, dsel_id::HDF5.Hid, dims::@compat Tuple{Vararg{Int}})
if obj.file.mmaparrays && HDF5.iscontiguous(obj.plain) && dsel_id == HDF5.H5S_ALL
readmmap(obj.plain, Array{T})
else
Expand All @@ -402,7 +403,7 @@ end

# Arrays of immutables/bitstypes
function read_vals(obj::JldDataset, dtype::HDF5Datatype, T::Type, dspace_id::HDF5.Hid,
dsel_id::HDF5.Hid, dims::(Int...))
dsel_id::HDF5.Hid, dims::@compat Tuple{Vararg{Int}})
out = Array(T, dims)
# Empty objects don't need to be read at all
T.size == 0 && !T.mutable && return out
Expand Down Expand Up @@ -437,7 +438,7 @@ end

# Arrays of references
function read_refs{T}(obj::JldDataset, ::Type{T}, dspace_id::HDF5.Hid, dsel_id::HDF5.Hid,
dims::(Int...))
dims::@compat Tuple{Vararg{Int}})
refs = Array(HDF5ReferenceObj, dims)
HDF5.h5d_read(obj.plain.id, HDF5.H5T_STD_REF_OBJ, dspace_id, dsel_id, HDF5.H5P_DEFAULT, refs)

Expand Down Expand Up @@ -488,7 +489,7 @@ write(parent::Union(JldFile, JldGroup), name::ByteString,
close(_write(parent, name, data, wsession; kargs...))

# Pick whether to use compact or default storage based on data size
function dset_create_properties(parent, sz::Int, obj, chunk=Int[]; mmap = false)
function dset_create_properties(parent, sz::Int, obj, chunk=Int[]; mmap::Bool=false)
if sz <= 8192 && !ismmapped(parent) && !mmap
return compact_properties(), false
end
Expand Down Expand Up @@ -634,18 +635,24 @@ write_ref(parent::JldGroup, data, wsession::JldWriteSession) =
write_ref(file(parent), data, wsession)

# Special case for associative, to rehash keys
function _write(parent::Union(JldFile, JldGroup), name::ByteString,
d::Associative, wsession::JldWriteSession; kargs...)
function _write{K,V}(parent::Union(JldFile, JldGroup), name::ByteString,
d::Associative{K,V}, wsession::JldWriteSession; kargs...)
n = length(d)
K, V = eltype(d)
ks = Array(K, n)
vs = Array(V, n)
i = 0
for (k,v) in d
ks[i+=1] = k
vs[i] = v
end
write_compound(parent, name, AssociativeWrapper{K,V,typeof(d)}(ks, vs), wsession)
write_compound(parent, name, AssociativeWrapper{K,V,typeof(d)}(ks, vs), wsession; kargs...)
end

# Special case for SimpleVector
if VERSION >= v"0.4.0-dev+4319"
_write(parent::Union(JldFile, JldGroup), name::ByteString,
d::SimpleVector, wsession::JldWriteSession; kargs...) =
write_compound(parent, name, SimpleVectorWrapper([d...]), wsession; kargs...)
end

# Expressions, drop line numbers
Expand Down Expand Up @@ -757,14 +764,66 @@ is_valid_type_ex{T}(::T) = isbits(T)
is_valid_type_ex(e::Expr) = ((e.head == :curly || e.head == :tuple || e.head == :.) && all(map(is_valid_type_ex, e.args))) ||
(e.head == :call && (e.args[1] == :Union || e.args[1] == :TypeVar))

# Work around https://github.com/JuliaLang/julia/issues/8226
if VERSION >= v"0.4.0-dev+1419"
const typemap_Core = @compat Dict(
:Uint8 => :UInt8,
:Uint16 => :Uint16,
:Uint32 => :UInt32,
:Uint64 => :UInt64,
:Nothing => :Void
)
else
const typemap_Core = @compat Dict(
:UInt8 => :Uint8,
:UInt16 => :Uint16,
:UInt32 => :Uint32,
:UInt64 => :Uint64,
:Void => :Nothing
)
end

const _typedict = Dict{UTF8String,Type}()
_typedict["Core.Type{TypeVar(:T,Union(Core.Any,Core.Undef))}"] = Type

function _julia_type(s::AbstractString)
fixtypes(typ) = typ
@eval begin
function fixtypes(typ::Expr)
if typ.head == :.
if length(typ.args) == 2 && typ.args[1] == :Core
arg = typ.args[2].value
return Expr(:., :Core, QuoteNode(get(typemap_Core, arg, arg)))
else
return typ
end
elseif typ == :(Core.Type{TypeVar(:T,Union(Core.Any,Core.Undef))}) || typ == :(Core.Type{TypeVar(:T)})
# Work around https://github.com/JuliaLang/julia/issues/8226 and the removal of Top
return :(Core.Type)
end

for i = 1:length(typ.args)
typ.args[i] = fixtypes(typ.args[i])
end

$(if VERSION >= v"0.4.0-dev+4319"
quote
if typ.head == :tuple
return Expr(:curly, :Tuple, typ.args...)
end
end
else
quote
if typ.head == :curly && !isempty(typ.args) && typ.args[1] == :(Core.Tuple)
return Expr(:tuple, typ.args[2:end]...)
end
end
end)
typ
end
end

function julia_type(s::AbstractString)
typ = get(_typedict, s, UnconvertedType)
if typ == UnconvertedType
typ = julia_type(parse(s))
typ = julia_type(fixtypes(parse(s)))
if typ != UnsupportedType
_typedict[s] = typ
end
Expand Down Expand Up @@ -811,13 +870,15 @@ function full_typename(io::IO, file::JldFile, tv::TypeVar)
print(io, ')')
end
end
function full_typename(io::IO, file::JldFile, jltype::(Type...))
print(io, '(')
for t in jltype
full_typename(io, file, t)
print(io, ',')
if VERSION < v"0.4.0-dev+4319"
function full_typename(io::IO, file::JldFile, jltype::@compat Tuple{Vararg{Type}})
print(io, '(')
for t in jltype
full_typename(io, file, t)
print(io, ',')
end
print(io, ')')
end
print(io, ')')
end
function full_typename(io::IO, ::JldFile, x)
# Only allow bitstypes that show as AST literals and make sure that they
Expand All @@ -826,7 +887,7 @@ function full_typename(io::IO, ::JldFile, x)
# A different implementation will be required to support custom immutables
# or things as simple as Int16(1).
s = sprint(show, x)
if isbits(x) && parse(s) === x
if isbits(x) && parse(s) === x && !isa(x, Tuple)
print(io, s)
else
error("type parameters with objects of type ", typeof(x), " are currently unsupported")
Expand Down Expand Up @@ -859,6 +920,8 @@ function full_typename(io::IO, file::JldFile, jltype::DataType)
full_typename(io, file, jltype.parameters[i])
end
print(io, '}')
elseif jltype <: Tuple
print(io, "{}")
end
end
function full_typename(file::JldFile, x)
Expand Down Expand Up @@ -976,7 +1039,7 @@ function save(filename::AbstractString, dict::Associative; compress::Bool=false)
end
# Or the names and values may be specified as alternating pairs
function save(filename::AbstractString, name::AbstractString, value, pairs...; compress::Bool=false)
if isodd(length(pairs)) || !isa(pairs[1:2:end], (AbstractString...))
if isodd(length(pairs)) || !isa(pairs[1:2:end], @compat Tuple{Vararg{AbstractString}})
throw(ArgumentError("arguments must be in name-value pairs"))
end
jldopen(filename, "w"; compress=compress) do file
Expand All @@ -1001,7 +1064,7 @@ function load(filename::AbstractString, varname::AbstractString)
end
end
load(filename::AbstractString, varnames::AbstractString...) = load(filename, varnames)
function load(filename::AbstractString, varnames::(AbstractString...))
function load(filename::AbstractString, varnames::@compat Tuple{Vararg{AbstractString}})
jldopen(filename, "r") do file
map((var)->read(file, var), varnames)
end
Expand Down
31 changes: 17 additions & 14 deletions src/JLD00.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ using HDF5, Compat
import HDF5: close, dump, exists, file, getindex, setindex!, g_create, g_open, o_delete, name, names, read, size, write,
HDF5ReferenceObj, HDF5BitsKind, ismmappable, readmmap
import Base: length, endof, show, done, next, start, delete!
import JLD

if !isdefined(:setfield!)
const setfield! = setfield
Expand Down Expand Up @@ -226,7 +227,7 @@ function delete!(parent::Union(JldFile, JldGroup), path::ByteString)
exists(parent, path) || error("$path does not exist in $parent")
delete!(parent[path])
end
delete!(parent::Union(JldFile, JldGroup), args::(ByteString...)) = for a in args delete!(parent,a) end
delete!(parent::Union(JldFile, JldGroup), args::@compat Tuple{Vararg{ByteString}}) = for a in args delete!(parent,a) end
ismmappable(obj::JldDataset) = ismmappable(obj.plain)
readmmap(obj::JldDataset, args...) = readmmap(obj.plain, args...)
setindex!(parent::Union(JldFile, JldGroup), val, path::ASCIIString) = write(parent, path, val)
Expand Down Expand Up @@ -367,7 +368,7 @@ end

# Nothing
read(obj::JldDataset, ::Type{Nothing}) = nothing
read(obj::JldDataset, ::Type{Bool}) = bool(read(obj, UInt8))
read(obj::JldDataset, ::Type{Bool}) = read(obj, UInt8) != 0

# Types
read{T}(obj::JldDataset, ::Type{Type{T}}) = T
Expand Down Expand Up @@ -397,7 +398,7 @@ read(obj::JldDataset, ::Type{Symbol}) = symbol(read(obj.plain, ByteString))
read{N}(obj::JldDataset, ::Type{Array{Symbol,N}}) = map(symbol, read(obj.plain, Array{ByteString}))

# Char
read(obj::JldDataset, ::Type{Char}) = char(read(obj.plain, UInt32))
read(obj::JldDataset, ::Type{Char}) = @compat Char(read(obj.plain, UInt32))

# UTF16String (not defined in julia 0.2)
if VERSION >= v"0.3-"
Expand Down Expand Up @@ -436,7 +437,7 @@ end

# CompositeKind
function read(obj::JldDataset, T::DataType)
if isempty(T.names) && T.size > 0
if isempty(fieldnames(T)) && T.size > 0
return read_bitstype(obj, T)
end
local x
Expand All @@ -453,12 +454,12 @@ function read(obj::JldDataset, T::DataType)
if length(v) == 0
x = ccall(:jl_new_struct, Any, (Any,Any...), T)
else
n = T.names
n = fieldnames(T)
if length(v) != length(n)
error("Wrong number of fields")
end
if !T.mutable
x = ccall(:jl_new_structv, Any, (Any,Ptr{Void},UInt32), T, v, length(T.names))
x = ccall(:jl_new_structv, Any, (Any,Ptr{Void},UInt32), T, v, length(fieldnames(T)))
else
x = ccall(:jl_new_struct_uninit, Any, (Any,), T)
for i = 1:length(v)
Expand Down Expand Up @@ -583,9 +584,9 @@ write(parent::Union(JldFile, JldGroup), name::ByteString, n::Nothing) = write(pa
# Types
# the first is needed to avoid an ambiguity warning
if isdefined(Core, :Top)
write{T<:Top}(parent::Union(JldFile, JldGroup), name::ByteString, t::(Type{T}...)) = write(parent, name, Any[t...], "Tuple")
write{T<:Top}(parent::Union(JldFile, JldGroup), name::ByteString, t::@compat Tuple{Vararg{Type{T}}}) = write(parent, name, Any[t...], "Tuple")
else
write{T}(parent::Union(JldFile, JldGroup), name::ByteString, t::(Type{T}...)) = write(parent, name, Any[t...], "Tuple")
write{T}(parent::Union(JldFile, JldGroup), name::ByteString, t::@compat Tuple{Vararg{Type{T}}}) = write(parent, name, Any[t...], "Tuple")
end
write{T}(parent::Union(JldFile, JldGroup), name::ByteString, t::Type{T}) = write(parent, name, nothing, string("Type{", full_typename(t), "}"))

Expand Down Expand Up @@ -720,7 +721,7 @@ write(parent::Union(JldFile, JldGroup), name::ByteString, s; rootmodule="") = wr

function write_composite(parent::Union(JldFile, JldGroup), name::ByteString, s; rootmodule="")
T = typeof(s)
if isempty(T.names)
if isempty(fieldnames(T))
if T.size > 0
return write_bitstype(parent, name, s)
end
Expand All @@ -730,7 +731,7 @@ function write_composite(parent::Union(JldFile, JldGroup), name::ByteString, s;
return
end
Tname = string(T.name.name)
n = T.names
n = fieldnames(T)
local gtypes
if !exists(file(parent), pathtypes)
gtypes = g_create(file(parent), pathtypes)
Expand Down Expand Up @@ -803,7 +804,7 @@ function has_pointer_field(obj::Tuple, name)
end

function has_pointer_field(obj, name)
names = typeof(obj).names
names = fieldnames(typeof(obj))
for fieldname in names
if isdefined(obj, fieldname)
x = getfield(obj, fieldname)
Expand Down Expand Up @@ -937,6 +938,7 @@ function _julia_type(s::AbstractString)
typ = get(_typedict, s, UnconvertedType)
if typ == UnconvertedType
e = parse(s)
e = JLD.fixtypes(e)
typ = UnsupportedType
if is_valid_type_ex(e)
try # try needed to catch undefined symbols
Expand Down Expand Up @@ -975,8 +977,9 @@ function full_typename(tv::TypeVar)
"TypeVar(:$(tv.name),$(full_typename(tv.lb)),$(full_typename(tv.ub)))"
end
end
full_typename(jltype::(Type...)) = length(jltype) == 1 ? @sprintf("(%s,)", full_typename(jltype[1])) :
@sprintf("(%s)", join(map(full_typename, jltype), ","))
full_typename(jltype::@compat Tuple{Vararg{Type}}) =
length(jltype) == 1 ? @sprintf("(%s,)", full_typename(jltype[1])) :
@sprintf("(%s)", join(map(full_typename, jltype), ","))
full_typename(x) = string(x)
function full_typename(jltype::DataType)
#tname = "$(jltype.name.module).$(jltype.name)"
Expand Down Expand Up @@ -1117,7 +1120,7 @@ function load(filename::AbstractString, varname::AbstractString)
end
end
load(filename::AbstractString, varnames::AbstractString...) = load(filename, varnames)
function load(filename::AbstractString, varnames::(AbstractString...))
function load(filename::AbstractString, varnames::@compat Tuple{Vararg{AbstractString}})
jldopen(filename, "r") do file
map((var)->read(file, var), varnames)
end
Expand Down
Loading