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

Prefixed array #11

Merged
merged 4 commits into from
Nov 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/src/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ Sequence
## Repeaters

```@docs
Repeater
SizedArray
PrefixedArray
GreedyVector
```

Expand Down
53 changes: 42 additions & 11 deletions src/Array.jl
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
"""
Repeater{T, TA<:AbstractArray{T}} <: Wrapper{T, TA}

Abstract base type for Array wrapper.
"""
abstract type Repeater{T, TA<:AbstractArray{T}} <: Wrapper{T, TA} end

deduceArrayType(::Type{TA}, ::Type{T}, N::Integer) where {T, TA<:AbstractArray} = deducetype(Base.similar, TA, Type{T}, Dims{N})

struct SizedArray{T, N, TA<:AbstractArray{T,N}, TSubCon<:Construct{T}} <: Repeater{T, TA}
struct SizedArray{T, N, TA<:AbstractArray{T,N}, TSubCon<:Construct{T}} <: Wrapper{T, TA}
subcon::TSubCon
size::NTuple{N, UInt}

Expand Down Expand Up @@ -35,13 +29,15 @@ Defines an array with specific size and element.
- `element::Construct{T}`: the construct of elements.
- `size`: the size of the array.
"""
function SizedArray(::Type{TA}, subcon::TSubCon, size::Vararg{Integer, N}) where {T, N, TA<:AbstractArray, TSubCon<:Construct{T}}
function SizedArray(::Type{TA}, subcon::TSubCon, size::NTuple{N, Integer}) where {T, N, TA<:AbstractArray, TSubCon<:Construct{T}}
SizedArray{T, N, TA, TSubCon}(subcon, convert(NTuple{N, UInt}, size))
end
SizedArray(::Type{TA}, subcon::TSubCon, size::Vararg{Integer, N}) where {T, N, TA<:AbstractArray, TSubCon<:Construct{T}} = SizedArray(TA, subcon, tuple(size...))
SizedArray(::Type{TA}, ::Type{T}, size::Vararg{Integer, N}) where {T, N, TA<:AbstractArray} = SizedArray(TA, Construct(T), size...)
SizedArray(::Type{TA}, ::Type{T}, size::NTuple{N, Integer}) where {T, N, TA<:AbstractArray} = SizedArray(TA, Construct(T), size)

SizedArray(subcon::Construct{T}, size::Vararg{Integer, N}) where {T, N} = SizedArray(Array{T, N}, subcon, size...)
SizedArray(::Type{T}, size::Vararg{Integer, N}) where {T, N} = SizedArray(Array{T, N}, Construct(T), size...)
SizedArray(subcon::Union{Construct{T}, Type{T}}, size::Vararg{Integer, N}) where {T, N} = SizedArray(Array{T, N}, Construct(subcon), size...)
SizedArray(subcon::Union{Construct{T}, Type{T}}, size::NTuple{N, Integer}) where {T, N} = SizedArray(Array{T, N}, Construct(subcon), size)

function deserialize(array::SizedArray{T, N, TA, TSubCon}, s::IO; contextkw...) where {T, N, TA, TSubCon}
result = similar(TA, array.size)
Expand All @@ -63,7 +59,42 @@ function serialize(array::SizedArray{T, N, TA, TSubCon}, s::IO, obj::TA; context
end
estimatesize(array::SizedArray; contextkw...) = prod(array.size) * estimatesize(array.subcon; contextkw...)

struct GreedyVector{T, TSubCon<:Construct{T}} <: Repeater{T, Vector{T}}
"""
PrefixedArray([TA], S|size, T|element) -> Construct{TA}

Defines an array with its size in the header.

# Arguments

- `TA<:AbstractArray{T, N}`: the target array type, the default is `Array{T, N}`.
- `S<:Union{Integer, NTuple{N, Integer}}`: the type of the size in the header.
- `T`: the type of elements.
- `size::Construct{S}`: the construct of size.
- `element::Construct{T}`: the construct of elements.
"""
PrefixedArray(size::Union{Type, Construct}, el::Union{Type, Construct}) = PrefixedArray(Construct(size), Construct(el))
PrefixedArray(::Type{TA}, size::Union{Type, Construct}, el::Union{Type, Construct}) where {TA} = PrefixedArray(TA, Construct(size), Construct(el))

PrefixedArray(sizecon::Construct{S}, subcon::Construct{T}) where {S<:Integer, T} = PrefixedArray(Vector{T}, sizecon, subcon)
PrefixedArray(sizecon::Construct{S}, subcon::Construct{T}) where {N, S<:NTuple{N, Integer}, T} = PrefixedArray(Array{T, N}, sizecon, subcon)

function PrefixedArray(::Type{TA}, sizecon::Construct{S}, subcon::Construct{T}) where {S<:Integer, T, TA<:AbstractVector{T}}
Prefixed{S, TA, typeof(sizecon), SizedArray{T, 1, TA, typeof(subcon)}}(
sizecon,
length,
(n::S) -> SizedArray(TA, subcon, n)
)
end

function PrefixedArray(::Type{TA}, sizecon::Construct{S}, subcon::Construct{T}) where {N, S<:NTuple{N, Integer}, T, TA<:AbstractArray{T, N}}
Prefixed{S, TA, typeof(sizecon), SizedArray{T, N, TA, typeof(subcon)}}(
sizecon,
size,
(n::S) -> SizedArray(TA, subcon, n)
)
end

struct GreedyVector{T, TSubCon<:Construct{T}} <: Wrapper{T, Vector{T}}
subcon::TSubCon
end

Expand Down
2 changes: 1 addition & 1 deletion src/Constructs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ export
Overwrite,
Try,
Sequence,
Repeater,
SizedArray,
PrefixedArray,
GreedyVector

include("context.jl")
Expand Down
21 changes: 21 additions & 0 deletions src/functional.jl
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,24 @@ Adapter(subcon::Union{Type, Construct}, encode::Function) = FunctionSymmetricAda
function encode(cons::FunctionSymmetricAdapter{T, TSubCon}, obj::T; contextkw...) where {T, TSubCon}
convert(T, apply_optional_contextkw(cons.encode, obj, contextkw))
end

# internal template
struct Prefixed{S, T, TSizeCon<:Construct{S}, TSubCon<:Construct{T}} <: Construct{T}
sizecon::TSizeCon
sizegetter::Function # obj::T -> S
fsubcon::Function # size::S -> TSubCon
end

function deserialize(cons::Prefixed{S, T, TSizeCon, TSubCon}, s::IO; contextkw...) where {S, T, TSizeCon<:Construct{S}, TSubCon<:Construct{T}}
size::S = deserialize(cons.sizecon, s; contextkw...)
subcon::TSubCon = cons.fsubcon(size)
deserialize(subcon, s; contextkw...)
end

function serialize(cons::Prefixed{S, T, TSizeCon, TSubCon}, s::IO, obj::T; contextkw...) where {S, T, TSizeCon<:Construct{S}, TSubCon<:Construct{T}}
size::S = cons.sizegetter(obj)
subcon::TSubCon = cons.fsubcon(size)
serialize(cons.sizecon, s, size; contextkw...) + serialize(subcon, s, obj; contextkw...)
end

estimatesize(cons::Prefixed; contextkw...) = estimatesize(cons.sizecon; contextkw...) + UnboundedSize(0) # assume the size of subcon is unbounded.
38 changes: 29 additions & 9 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -343,26 +343,46 @@ end
end
@testset "SizedArray" begin
@testset "deduce type" begin
@test Constructs.deducetype(() -> SizedArray(Int, 1, 2)) <: Repeater{Int, Array{Int, 2}}
@test Constructs.deducetype(() -> SizedArray(BitArray{2}, Bool, 1, 2)) <: Repeater{Bool, BitArray{2}}
@test Constructs.deducetype((x, y) -> SizedArray(Int, x, y), Int, Int) <: Repeater{Int, Array{Int, 2}}
@test Constructs.deducetype((x, y) -> SizedArray(BitArray{2}, Bool, x, y), Int, Int) <: Repeater{Bool, BitArray{2}}
@test Constructs.deducetype(() -> SizedArray(Int, 1, 2)) <: Construct{Array{Int, 2}}
@test Constructs.deducetype(() -> SizedArray(BitArray{2}, Bool, 1, 2)) <: Construct{BitArray{2}}
@test Constructs.deducetype((x, y) -> SizedArray(Int, x, y), Int, Int) <: Construct{Array{Int, 2}}
@test Constructs.deducetype((x, y) -> SizedArray(BitArray{2}, Bool, x, y), Int, Int) <: Construct{BitArray{2}}
@test Constructs.deducetype((size) -> SizedArray(Int, size), NTuple{3, Int}) <: Construct{Array{Int, 3}}
@test Constructs.deducetype((size) -> SizedArray(BitArray{5}, Bool, size), NTuple{5, Int}) <: Construct{BitArray{5}}
end
@test_throws TypeError SizedArray(BitArray{3}, Int, 2, 3, 5) # element type mismatch
@test_throws TypeError SizedArray(BitArray{3}, Int, (2, 3, 5)) # element type mismatch
@test_throws TypeError SizedArray(UnitRange{Int}, Int, 3) # immutable array cannot be deserialized
@test_throws TypeError SizedArray(typeof(view([1],1)), Int, 1) # indirect array cannot be deserialized
@test estimatesize(SizedArray(Int64)) == sizeof(Int64)
@test estimatesize(SizedArray(Int64, ())) == sizeof(Int64)
@test estimatesize(SizedArray(Int64, 10)) == 10*sizeof(Int64)
@test estimatesize(SizedArray(Int64, 2, 3, 5)) == 2*3*5*sizeof(Int64)
@test estimatesize(SizedArray(BitArray{2}, Bool, (2, 3))) == 2*3*sizeof(Bool)
@test estimatesize(SizedArray(BitArray{3}, Bool, 2, 3, 5)) == 2*3*5*sizeof(Bool)
@test deserialize(SizedArray(Int8), b"\x02")[] == 2
@test serialize(SizedArray(Int8), ones(Int8)) == b"\x01"
@test deserialize(SizedArray(Int8, ()), b"\x02")[] == 2
@test serialize(SizedArray(Int8, ()), ones(Int8, ())) == b"\x01"
@test deserialize(SizedArray(Int8, 3), b"\x01\xff\x00") == Int8[1, -1, 0]
@test serialize(SizedArray(Int8, 3), Int8[1, -1, 0]) == b"\x01\xff\x00"
@test_throws DimensionMismatch serialize(SizedArray(Int8, 3), Int8[1, -1])
@test deserialize(SizedArray(Int8, 2, 3), Vector{UInt8}(1:6)) == Int8[1 3 5; 2 4 6]
@test serialize(SizedArray(Int8, 2, 3), Int8[1 2 3; 4 5 6]) == b"\x01\x04\x02\x05\x03\x06"
end
@testset "PrefixedArray" begin
@testset "deduce type" begin
@test Constructs.deducetype(() -> PrefixedArray(UInt32, UInt8)) <: Construct{Vector{UInt8}}
@test Constructs.deducetype(() -> PrefixedArray(Sequence(UInt16, UInt16), UInt8)) <: Construct{Matrix{UInt8}}
@test Constructs.deducetype(() -> PrefixedArray(BitVector, UInt32, Bool)) <: Construct{BitVector}
@test Constructs.deducetype(() -> PrefixedArray(BitArray{2}, Sequence(UInt16, UInt16), Bool)) <: Construct{BitArray{2}}
end
@test estimatesize(PrefixedArray(UInt32, UInt8)) == UnboundedSize(sizeof(UInt32))
@test estimatesize(PrefixedArray(Sequence(UInt32, UInt16), UInt8)) == UnboundedSize(sizeof(UInt32) + sizeof(UInt16))
@test estimatesize(PrefixedArray(BitVector, UInt32, Bool)) == UnboundedSize(sizeof(UInt32))
@test estimatesize(PrefixedArray(BitArray{2}, Sequence(UInt16, UInt16), Bool)) == UnboundedSize(2 * sizeof(UInt16))
@test deserialize(PrefixedArray(UInt16le, Int8), b"\x02\x00\x12\xfe") == Int8[18, -2]
@test serialize(PrefixedArray(UInt16le, Int8), Int8[-3, 1, 7]) == b"\x03\x00\xfd\x01\x07"
@test deserialize(PrefixedArray(Sequence(UInt8, UInt16le), Int8), b"\x03\x02\x00\xff\xfe\xfd\x01\x02\x03") == Int8[-1 1; -2 2; -3 3]
@test serialize(PrefixedArray(Sequence(UInt16le, UInt8), Int8), Int8[-3 -2 -1; 1 2 3]) == b"\x02\x00\x03\xfd\x01\xfe\x02\xff\x03"
@test_throws InexactError serialize(PrefixedArray(Int8, UInt8), collect(0x01:0xff))
end
@testset "GreedyVector" begin
@test estimatesize(GreedyVector(Int8)) == UnboundedSize(0)
@test deserialize(GreedyVector(Int8), b"\x01\xff\x00") == Int8[1, -1, 0]
Expand Down Expand Up @@ -485,7 +505,7 @@ end
width::UInt32
height::UInt32
::Padded(8)
pixel::SizedArray(UInt8, (this.height, this.width))
pixel::SizedArray(UInt8, this.signature, this.width)
end
end
)
Expand Down