Skip to content

Commit

Permalink
Merge pull request #232 from timholy/tuplefix
Browse files Browse the repository at this point in the history
Fix tuple types for 0.4
  • Loading branch information
simonster committed Apr 25, 2015
2 parents b170017 + 12479c5 commit 74d7f05
Show file tree
Hide file tree
Showing 8 changed files with 211 additions and 118 deletions.
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

0 comments on commit 74d7f05

Please sign in to comment.