From 4744e949d4218fc5a85a27f457a90d8d801476c8 Mon Sep 17 00:00:00 2001 From: Erik Schnetter Date: Wed, 21 Aug 2024 11:16:30 -0400 Subject: [PATCH] Use tuples instead of vectors for array dimensions --- src/mdarray/attribute.jl | 22 +++++------ src/mdarray/group.jl | 13 +++--- src/mdarray/mdarray.jl | 85 ++++++++++++++++++++++------------------ src/mdarray/types.jl | 23 +++++++++-- test/test_mdarray.jl | 53 ++++++++++++++++++++----- 5 files changed, 127 insertions(+), 69 deletions(-) diff --git a/src/mdarray/attribute.jl b/src/mdarray/attribute.jl index fc6c6d84..25daac76 100644 --- a/src/mdarray/attribute.jl +++ b/src/mdarray/attribute.jl @@ -24,9 +24,9 @@ function getdimensionssize(attribute::AbstractAttribute)::NTuple{<:Any,Int} @assert !isnull(attribute) count = Ref{Csize_t}() sizeptr = GDAL.gdalattributegetdimensionssize(attribute, count) - size = ntuple(n -> unsafe_load(sizeptr, n), count[]) + size = reverse(ntuple(d -> Int(unsafe_load(sizeptr, d), count[]))) GDAL.vsifree(sizeptr) - return Int.(size) + return size end function readasraw(attribute::AbstractAttribute)::AbstractVector{UInt8} @@ -158,7 +158,7 @@ function gettotalelementscount(attribute::AbstractAttribute)::Int64 return Int64(GDAL.gdalattributegettotalelementscount(attribute)) end -function Base.length(attribute::AbstractAttribute) +function Base.length(attribute::AbstractAttribute)::Int @assert !isnull(attribute) return Int(gettotalelementscount(attribute)) end @@ -178,8 +178,8 @@ function getdimensions( dimensionshptr = GDAL.gdalattributegetdimensions(attribute, dimensionscountref) dimensions = AbstractDimension[ - IDimension(unsafe_load(dimensionshptr, n), attribute.dataset) for - n in 1:dimensionscountref[] + IDimension(unsafe_load(dimensionshptr, d), attribute.dataset) for + d in dimensionscountref[]:-1:1 ] GDAL.vsifree(dimensionshptr) return dimensions @@ -193,8 +193,8 @@ function unsafe_getdimensions( dimensionshptr = GDAL.gdalattributegetdimensions(attribute, dimensionscountref) dimensions = AbstractDimension[ - Dimension(unsafe_load(dimensionshptr, n), attribute.dataset) for - n in 1:dimensionscountref[] + Dimension(unsafe_load(dimensionshptr, d), attribute.dataset) for + d in dimensionscountref[]:-1:1 ] GDAL.vsifree(dimensionshptr) return dimensions @@ -215,7 +215,7 @@ end function getblocksize( attribute::AbstractAttribute, options::OptionList = nothing, -)::AbstractVector{Int64} +)::NTuple{<:Any,Int} @assert !isnull(attribute) count = Ref{Csize_t}() blocksizeptr = GDAL.gdalattributegetblocksize( @@ -223,7 +223,7 @@ function getblocksize( count, CSLConstListWrapper(options), ) - blocksize = Int64[unsafe_load(blocksizeptr, n) for n in 1:count[]] + blocksize = reverse(ntuple(d -> Int(unsafe_load(blocksizeptr, d)), count[])) GDAL.vsifree(blocksizeptr) return blocksize end @@ -231,7 +231,7 @@ end function getprocessingchunksize( attribute::AbstractAttribute, maxchunkmemory::Integer, -)::AbstractVector{Int64} +)::NTuple{<:AnyInt} @assert !isnull(attribute) count = Ref{Csize_t}() chunksizeptr = GDAL.gdalattributegetprocessingchunksize( @@ -239,7 +239,7 @@ function getprocessingchunksize( count, maxchunkmemory, ) - chunksize = Int64[unsafe_load(chunksizeptr, n) for n in 1:count[]] + chunksize = reverse(ntuple(d -> Int(unsafe_load(chunksizeptr, d)), count[])) GDAL.vsifree(chunksizeptr) return chunksize end diff --git a/src/mdarray/group.jl b/src/mdarray/group.jl index 6d56e64e..3db9ebd0 100644 --- a/src/mdarray/group.jl +++ b/src/mdarray/group.jl @@ -175,7 +175,6 @@ function deletegroup( options::OptionList = nothing, )::Bool @assert !isnull(group) - # TODO: Do we need to set group.ptr = C_NULL? return GDAL.gdalgroupdeletegroup(group, name, CSLConstListWrapper(options)) end @@ -224,7 +223,7 @@ end function unsafe_createmdarray( group::AbstractGroup, name::AbstractString, - dimensions::AbstractVector{<:AbstractDimension}, + dimensions::VectorLike{<:AbstractDimension}, datatype::AbstractExtendedDataType, options::OptionList = nothing, )::AbstractMDArray @@ -246,7 +245,7 @@ end function createmdarray( group::AbstractGroup, name::AbstractString, - dimensions::AbstractVector{<:AbstractDimension}, + dimensions::VectorLike{<:AbstractDimension}, datatype::AbstractExtendedDataType, options::OptionList = nothing, )::AbstractMDArray @@ -498,7 +497,7 @@ end function unsafe_createattribute( group::AbstractGroup, name::AbstractString, - dimensions::AbstractVector{<:Integer}, + dimensions::VectorLike{<:Integer}, datatype::AbstractExtendedDataType, options::OptionList = nothing, )::AbstractAttribute @@ -508,7 +507,7 @@ function unsafe_createattribute( group, name, length(dimensions), - dimensions, + reverse(dimensions), datatype, CSLConstListWrapper(options), ) @@ -519,7 +518,7 @@ end function createattribute( group::AbstractGroup, name::AbstractString, - dimensions::AbstractVector{<:Integer}, + dimensions::VectorLike{<:Integer}, datatype::AbstractExtendedDataType, options::OptionList = nothing, )::AbstractAttribute @@ -529,7 +528,7 @@ function createattribute( group, name, length(dimensions), - dimensions, + reverse(dimensions), datatype, CSLConstListWrapper(options), ) diff --git a/src/mdarray/mdarray.jl b/src/mdarray/mdarray.jl index a5ccb9d1..1231607d 100644 --- a/src/mdarray/mdarray.jl +++ b/src/mdarray/mdarray.jl @@ -134,7 +134,7 @@ end function resize!( mdarray::AbstractMDArray, - newdimsizes::AbstractVector{<:Integer}, + newdimsizes::VectorLike{<:Integer}, options::OptionList = nothing, )::Bool @assert !isnull(mdarray) @@ -339,7 +339,7 @@ end # TODO: Wrap GDAL.GDALRIOResampleAlg function unsafe_getresampled( mdarray::AbstractMDArray, - newdims::Union{Nothing,AbstractVector{<:AbstractDimension}}, + newdims::Union{Nothing,VectorLike{<:AbstractDimension}}, resamplealg::GDAL.GDALRIOResampleAlg, targetsrs::Union{Nothing,AbstractSpatialRef}, options::OptionList = nothing, @@ -359,7 +359,7 @@ end function getresampled( mdarray::AbstractMDArray, - newdims::Union{Nothing,AbstractVector{<:AbstractDimension}}, + newdims::Union{Nothing,VectorLike{<:AbstractDimension}}, resamplealg::GDAL.GDALRIOResampleAlg, targetsrs::Union{Nothing,AbstractSpatialRef}, options::OptionList = nothing, @@ -540,27 +540,34 @@ function clearstatistics(mdarray::AbstractMDArray)::Nothing end function getcoordinatevariables( - mdarray::AbstractMDArray, -)::AbstractVector{<:AbstractMDArray} + mdarray::AbstractMDArray{<:Any,D}, +)::NTuple{D,T where T<:AbstractMDArray} where {D} @assert !isnull(mdarray) count = Ref{Csize_t}() coordinatevariablesptr = GDAL.gdalmdarraygetcoordinatevariables(mdarray, count) - coordinatevariables = AbstractMDArray[ - IMDArray(unsafe_load(coordinatevariablesptr, n), mdarray.dataset) - for n in 1:count[] - ] + coordinatevariables = reverse( + ntuple( + d -> IMDArray( + unsafe_load(coordinatevariablesptr, d), + mdarray.dataset, + ), + count[], + ), + ) GDAL.vsifree(coordinatevariablesptr) return coordinatevariables end function adviseread( - mdarray::AbstractMDArray, - arraystartidx::Union{Nothing,AbstractVector{<:Integer}}, - count::Union{Nothing,AbstractVector{<:Integer}}, + mdarray::AbstractMDArray{<:Any,D}, + arraystartidx::Union{Nothing,IndexLike{D}}, + count::Union{Nothing,IndexLike{D}}, options::OptionList = nothing, -)::Bool +)::Bool where {D} @assert !isnull(mdarray) + @assert isnothing(arraystartix) ? true : length(arraystartidx) == D + @assert isnothing(count) ? true : length(count == D) return GDAL.gdalmdarrayadviseread( mdarray, isnothing(arraystartidx) ? C_NULL : reverse(arraystartidx), @@ -640,36 +647,40 @@ getdimensioncount(mdarray::AbstractMDArray{<:Any,D}) where {D} = D Base.ndims(mdarray::AbstractMDArray)::Int = getdimensioncount(mdarray) function getdimensions( - mdarray::AbstractMDArray, -)::AbstractVector{<:AbstractDimension} + mdarray::AbstractMDArray{<:Any,D}, +)::NTuple{D,T where T<:AbstractDimension} where {D} @assert !isnull(mdarray) dimensionscountref = Ref{Csize_t}() dimensionshptr = GDAL.gdalmdarraygetdimensions(mdarray, dimensionscountref) - dimensions = AbstractDimension[ - IDimension(unsafe_load(dimensionshptr, n), mdarray.dataset) for - n in dimensionscountref[]:-1:1 - ] + dimensions = reverse( + ntuple( + d -> + IDimension(unsafe_load(dimensionshptr, d), mdarray.dataset), + dimensionscountref[], + ), + ) GDAL.vsifree(dimensionshptr) return dimensions end function unsafe_getdimensions( - mdarray::AbstractMDArray, -)::AbstractVector{<:AbstractDimension} + mdarray::AbstractMDArray{<:Any,D}, +)::NTuple{D,T where T<:AbstractDimension} where {D} @assert !isnull(mdarray) dimensionscountref = Ref{Csize_t}() dimensionshptr = GDAL.gdalmdarraygetdimensions(mdarray, dimensionscountref) - dimensions = AbstractDimension[ - Dimension(unsafe_load(dimensionshptr, n), mdarray.dataset) for - n in dimensionscountref[]:-1:1 - ] + dimensions = reverse( + ntuple( + d -> Dimension(unsafe_load(dimensionshptr, d), mdarray.dataset), + dimensionscountref[], + ), + ) GDAL.vsifree(dimensionshptr) return dimensions end -function Base.size(mdarray::AbstractMDArray) +function Base.size(mdarray::AbstractMDArray{<:Any,D})::NTuple{D,Int} where {D} getdimensions(mdarray) do dimensions - D = length(dimensions) return ntuple(d -> getsize(dimensions[d]), D) end end @@ -686,45 +697,41 @@ end Base.eltype(mdarray::AbstractMDArray{T}) where {T} = T -function getblocksize(mdarray::AbstractMDArray)::AbstractVector{Int64} +function getblocksize( + mdarray::AbstractMDArray{<:Any,D}, +)::NTuple{D,Int} where {D} @assert !isnull(mdarray) count = Ref{Csize_t}() blocksizeptr = GDAL.gdalmdarraygetblocksize(mdarray, count) - blocksize = Int64[unsafe_load(blocksizeptr, n) for n in count[]:-1:1] + blocksize = reverse(ntuple(d -> Int(unsafe_load(blocksizeptr, d)), count[])) GDAL.vsifree(blocksizeptr) return blocksize end DiskArrays.haschunks(::AbstractMDArray) = DiskArrays.Chunked() + function DiskArrays.eachchunk( mdarray::AbstractMDArray{<:Any,D}, )::NTuple{D,Int} where {D} blocksize = getblocksize(mdarray) - return DiskArrays.GridChunks(mdarray, Int.(blocksize)) + return DiskArrays.GridChunks(mdarray, blocksize) end function getprocessingchunksize( mdarray::AbstractMDArray, maxchunkmemory::Integer, -)::AbstractVector{Int64} +)::AbstractVector{Int} @assert !isnull(mdarray) count = Ref{Csize_t}() chunksizeptr = GDAL.gdalmdarraygetprocessingchunksize(mdarray, count, maxchunkmemory) - chunksize = Int64[unsafe_load(chunksizeptr, n) for n in count[]:-1:1] + chunksize = Int[unsafe_load(chunksizeptr, n) for n in count[]:-1:1] GDAL.vsifree(chunksizeptr) return chunksize end # processperchunk -const IndexLike{D} = - Union{AbstractVector{<:Integer},CartesianIndex{D},NTuple{D,<:Integer}} -const RangeLike{D} = Union{ - AbstractVector{<:AbstractRange{<:Integer}}, - NTuple{D,<:AbstractRange{<:Integer}}, -} - function read!( mdarray::AbstractMDArray, arraystartidx::IndexLike{D}, diff --git a/src/mdarray/types.jl b/src/mdarray/types.jl index 9b4a8276..ce26c6a9 100644 --- a/src/mdarray/types.jl +++ b/src/mdarray/types.jl @@ -176,6 +176,20 @@ isnull(x::StyleTool) = x.ptr == C_NULL ################################################################################ +const VectorLike{T} = Union{AbstractVector{<:T},NTuple{<:Any,X where X<:T}} + +const IndexLike{D} = Union{ + AbstractVector{<:Integer}, + CartesianIndex{D}, + NTuple{D,I where I<:Integer}, +} +const RangeLike{D} = Union{ + AbstractVector{<:AbstractRange{<:Integer}}, + NTuple{D,R where R<:AbstractRange{<:Integer}}, +} + +################################################################################ + Base.unsafe_convert(::Type{Ptr{Cvoid}}, x::AbstractExtendedDataType) = x.ptr Base.unsafe_convert(::Type{Ptr{Cvoid}}, x::AbstractEDTComponent) = x.ptr Base.unsafe_convert(::Type{Ptr{Cvoid}}, x::AbstractGroup) = x.ptr @@ -227,11 +241,11 @@ function destroy(dimension::AbstractDimension)::Nothing return nothing end -function destroy(edtcomponents::AbstractVector{<:AbstractEDTComponent}) +function destroy(edtcomponents::VectorLike{<:AbstractEDTComponent}) return destroy.(edtcomponents) end -destroy(attributes::AbstractVector{<:AbstractAttribute}) = destroy.(attributes) -destroy(dimensions::AbstractVector{<:AbstractDimension}) = destroy.(dimensions) +destroy(attributes::VectorLike{<:AbstractAttribute}) = destroy.(attributes) +destroy(dimensions::VectorLike{<:AbstractDimension}) = destroy.(dimensions) ################################################################################ @@ -280,6 +294,9 @@ struct DimensionHList return new(dimensionhs, dimensions) end end +function DimensionHList(dimensions::NTuple{<:Any,T where T<:AbstractDimension}) + return DimensionHList([dimensions...]) +end function Base.cconvert( ::Type{Ptr{GDAL.GDALDimensionH}}, diff --git a/test/test_mdarray.jl b/test/test_mdarray.jl index 102240d5..3f7a895b 100644 --- a/test/test_mdarray.jl +++ b/test/test_mdarray.jl @@ -153,7 +153,7 @@ end drivercreateoptions, ) @test !AG.isnull(dataset) - @test match(r"GDAL Dataset", string(dataset)) !== nothing + @test match(r"^GDAL Dataset", string(dataset)) !== nothing files = AG.filelist(dataset) if drivername in ["MEM"] @@ -166,7 +166,7 @@ end root = AG.getrootgroup(dataset) @test !AG.isnull(root) - @test match(r"ArchGDAL.Group", string(root)) !== nothing + @test match(r"^ArchGDAL.Group", string(root)) !== nothing rootname = AG.getname(root) @test rootname == "/" rootfullname = AG.getfullname(root) @@ -174,7 +174,7 @@ end group = AG.creategroup(root, "group") @test !AG.isnull(group) - @test match(r"ArchGDAL.IGroup", string(group)) !== nothing + @test match(r"^ArchGDAL.IGroup", string(group)) !== nothing @test AG.getname(group) == "group" @test AG.getfullname(group) == "/group" @@ -186,24 +186,41 @@ end nx, ny = 3, 4 dimx = AG.createdimension(group, "x", "", "", nx) @test !AG.isnull(dimx) - @test match(r"ArchGDAL.IDimension", string(dimx)) !== nothing + @test match(r"^ArchGDAL.IDimension", string(dimx)) !== nothing dimy = AG.createdimension(group, "y", "", "", ny) @test !AG.isnull(dimy) datatype = AG.extendeddatatypecreate(Float32) @test !AG.isnull(datatype) - @test match(r"ArchGDAL.IExtendedDataType", string(datatype)) !== - nothing + @test match( + r"^ArchGDAL.IExtendedDataType", + string(datatype), + ) !== nothing + + if drivername != "netCDF" + # netCDF does not support deleting MDArrays + mdarray0 = AG.createmdarray( + group, + "mdarray0", + [dimx, dimy], + datatype, + mdarraycreateoptions, + ) + @test !AG.isnull(mdarray0) + success = AG.deletemdarray(group, "mdarray0") + @test success + end mdarray = AG.createmdarray( group, "mdarray", - [dimx, dimy], + (dimx, dimy), datatype, mdarraycreateoptions, ) @test !AG.isnull(mdarray) - @test match(r"ArchGDAL.IMDArray", string(mdarray)) !== nothing + @test match(r"^3×4 ArchGDAL.IMDArray", string(mdarray)) !== + nothing @test AG.getmdarraynames(root) == [] @test AG.getmdarraynames(group) == ["mdarray"] @@ -385,10 +402,28 @@ end ) do datatype @test !AG.isnull(datatype) + if drivername != "netCDF" + # netCDF does not support deleting MDArrays + AG.createmdarray( + group, + "mdarray0", + [dimx, dimy], + datatype, + mdarraycreateoptions, + ) do mdarray0 + @test !AG.isnull(mdarray0) + end + success = AG.deletemdarray( + group, + "mdarray0", + ) + @test success + end + AG.createmdarray( group, "mdarray", - [dimx, dimy], + (dimx, dimy), datatype, mdarraycreateoptions, ) do mdarray