Skip to content

Commit 8a42545

Browse files
committed
NarrowTuple fixes
1 parent e975580 commit 8a42545

3 files changed

Lines changed: 44 additions & 50 deletions

File tree

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "BitPacking"
22
uuid = "b58c8408-13c4-4787-8733-7038ae624acf"
3-
version = "0.2.0"
3+
version = "0.2.1"
44
authors = ["Anton Oresten <antonoresten@proton.me> and contributors"]
55

66
[deps]

src/NarrowTuple.jl

Lines changed: 41 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,12 @@ Use [`ZeroPad`](@ref) or [`OnePad`](@ref) in layouts.
1111
"""
1212
abstract type Pad{N} end
1313

14+
function check_pad_bitwidth(N)
15+
N isa Integer || throw(ArgumentError("padding bitwidth must be an integer, got $N"))
16+
N >= 1 || throw(ArgumentError("padding bitwidth must be positive, got $N"))
17+
return Int(N)
18+
end
19+
1420
"""
1521
ZeroPad{N} <: Pad{N}
1622
ZeroPad(N)
@@ -32,7 +38,12 @@ Tuple(nt) # (0x00, true, BitPacking.ZeroPad(7))
3238
Raw-storage constructors validate that the corresponding padding bits are
3339
zero.
3440
"""
35-
abstract type ZeroPad{N} <: Pad{N} end
41+
struct ZeroPad{N} <: Pad{N}
42+
function ZeroPad{N}() where N
43+
check_pad_bitwidth(N)
44+
new{N}()
45+
end
46+
end
3647

3748
"""
3849
OnePad{N} <: Pad{N}
@@ -54,28 +65,18 @@ Tuple(nt) # (0x00, true, BitPacking.OnePad(7))
5465
Raw-storage constructors validate that the corresponding padding bits are
5566
one.
5667
"""
57-
abstract type OnePad{N} <: Pad{N} end
58-
59-
struct ZeroPadValue{N} <: ZeroPad{N} end
60-
struct OnePadValue{N} <: OnePad{N} end
61-
62-
function check_pad_bitwidth(N)
63-
N isa Integer || throw(ArgumentError("padding bitwidth must be an integer, got $N"))
64-
N >= 1 || throw(ArgumentError("padding bitwidth must be positive, got $N"))
65-
return Int(N)
68+
struct OnePad{N} <: Pad{N}
69+
function OnePad{N}() where N
70+
check_pad_bitwidth(N)
71+
new{N}()
72+
end
6673
end
6774

68-
ZeroPad(N) = ZeroPadValue{check_pad_bitwidth(N)}()
69-
OnePad(N) = OnePadValue{check_pad_bitwidth(N)}()
70-
(::Type{ZeroPad{N}})() where N = ZeroPadValue{check_pad_bitwidth(N)}()
71-
(::Type{OnePad{N}})() where N = OnePadValue{check_pad_bitwidth(N)}()
75+
ZeroPad(N) = ZeroPad{N}()
76+
OnePad(N) = OnePad{N}()
7277

7378
bitwidth(::Type{<:Pad{N}}) where N = check_pad_bitwidth(N)
7479

75-
is_pad_type(::Type{T}) where T = T <: Pad
76-
is_zero_pad_type(::Type{T}) where T = T <: ZeroPad
77-
is_one_pad_type(::Type{T}) where T = T <: OnePad
78-
7980
layout_fieldtype(::Type{T}) where {N,T<:ZeroPad{N}} = ZeroPad{N}
8081
layout_fieldtype(::Type{T}) where {N,T<:OnePad{N}} = OnePad{N}
8182
layout_fieldtype(::Type{T}) where T = T
@@ -84,8 +85,6 @@ function layout_tuple_type(::Type{Ts}) where Ts<:Tuple
8485
return Tuple{map(layout_fieldtype, fieldtypes(Ts))...}
8586
end
8687

87-
materialized_fieldtype(::Type{T}) where {N,T<:ZeroPad{N}} = ZeroPadValue{N}
88-
materialized_fieldtype(::Type{T}) where {N,T<:OnePad{N}} = OnePadValue{N}
8988
materialized_fieldtype(::Type{T}) where T = T
9089

9190
function materialized_fieldtypes(::Type{Ts}) where Ts<:Tuple
@@ -97,15 +96,15 @@ function materialized_tuple_type(::Type{Ts}) where Ts<:Tuple
9796
end
9897

9998
function unpadded_fieldtypes(::Type{Ts}) where Ts<:Tuple
100-
return Tuple(T for T in fieldtypes(Ts) if !is_pad_type(T))
99+
return Tuple(T for T in fieldtypes(Ts) if !(T <: Pad))
101100
end
102101

103102
function unpadded_tuple_type(::Type{Ts}) where Ts<:Tuple
104103
return Tuple{unpadded_fieldtypes(Ts)...}
105104
end
106105

107-
pad_value(::Type{T}) where {N,T<:ZeroPad{N}} = ZeroPadValue{N}()
108-
pad_value(::Type{T}) where {N,T<:OnePad{N}} = OnePadValue{N}()
106+
pad_value(::Type{T}) where {N,T<:ZeroPad{N}} = ZeroPad(N)
107+
pad_value(::Type{T}) where {N,T<:OnePad{N}} = OnePad(N)
109108

110109
function check_narrow_tuple_type(::Type{Ts}) where Ts<:Tuple
111110
for T in fieldtypes(Ts)
@@ -115,9 +114,7 @@ function check_narrow_tuple_type(::Type{Ts}) where Ts<:Tuple
115114
W isa Integer ||
116115
throw(ArgumentError("bitwidth($T) must be an integer, got $W"))
117116

118-
if is_pad_type(T)
119-
(is_zero_pad_type(T) || is_one_pad_type(T)) ||
120-
throw(ArgumentError("NarrowTuple padding field type must be ZeroPad or OnePad, got $T"))
117+
if T <: Pad
121118
W >= 1 || throw(ArgumentError("padding bitwidth must be positive, got $W"))
122119
else
123120
isbitstype(T) ||
@@ -231,7 +228,7 @@ struct NarrowTuple{Ts<:Tuple,D<:Storage}
231228
end
232229
end
233230

234-
bitwidth(::Type{<:NarrowTuple{Ts}}) where Ts = bitwidth(Ts)
231+
bitwidth(::Type{<:NarrowTuple{Ts}}) where Ts = sum(bitwidth, Ts.parameters; init=0)
235232

236233
@generated function narrow_tuple_pack(::Val{Ws}, ::Type{Layout}, ::Type{D}, xs::Values) where {Ws,Layout<:Tuple,D<:Storage,Values<:Tuple}
237234
types = fieldtypes(Layout)
@@ -243,7 +240,7 @@ bitwidth(::Type{<:NarrowTuple{Ts}}) where Ts = bitwidth(Ts)
243240
length(widths) == length(types) ||
244241
throw(ArgumentError("expected $(length(types)) field bitwidths for $Layout, got $(length(widths))"))
245242
for (T, W) in zip(types, widths)
246-
is_pad_type(T) && continue
243+
T <: Pad && continue
247244
1 <= W <= 8 * sizeof(T) ||
248245
throw(ArgumentError("bitwidth($T) must be in 1:$(8 * sizeof(T)), got $W"))
249246
end
@@ -257,8 +254,8 @@ bitwidth(::Type{<:NarrowTuple{Ts}}) where Ts = bitwidth(Ts)
257254
if D <: Unsigned
258255
terms = Any[]
259256
for (index, (T, W, start)) in enumerate(zip(types, widths, starts))
260-
if is_pad_type(T)
261-
is_one_pad_type(T) || continue
257+
if T <: Pad
258+
T <: OnePad || continue
262259
expr = :($D($(narrow_mask(D, W))))
263260
else
264261
U = unsigned_type(sizeof(T))
@@ -289,8 +286,8 @@ bitwidth(::Type{<:NarrowTuple{Ts}}) where Ts = bitwidth(Ts)
289286
dest_shift = first_bit - byte_first_bit
290287
width = last_bit - first_bit + 1
291288

292-
if is_pad_type(T)
293-
is_one_pad_type(T) || continue
289+
if T <: Pad
290+
T <: OnePad || continue
294291
expr = :(UInt8($(_low_mask(width))))
295292
else
296293
expr = field_raw_expr(:xs, field_index, T)
@@ -318,7 +315,7 @@ function materialize_narrow_tuple_values(::Type{Ts}, xs::Tuple) where Ts<:Tuple
318315
value_index = 1
319316

320317
for T in fieldtypes(Ts)
321-
if is_pad_type(T)
318+
if T <: Pad
322319
push!(result, pad_value(T))
323320
else
324321
push!(result, values[value_index])
@@ -346,7 +343,7 @@ NarrowTuple(xs::Ts) where Ts<:Tuple = NarrowTuple{layout_tuple_type(Ts)}(xs)
346343
length(widths) == length(types) ||
347344
throw(ArgumentError("expected $(length(types)) field bitwidths for $Ts, got $(length(widths))"))
348345
for (T, W) in zip(types, widths)
349-
is_pad_type(T) && continue
346+
T <: Pad && continue
350347
1 <= W <= 8 * sizeof(T) ||
351348
throw(ArgumentError("bitwidth($T) must be in 1:$(8 * sizeof(T)), got $W"))
352349
end
@@ -360,7 +357,7 @@ NarrowTuple(xs::Ts) where Ts<:Tuple = NarrowTuple{layout_tuple_type(Ts)}(xs)
360357

361358
if D <: Unsigned
362359
for (index, (T, W, start)) in enumerate(zip(types, widths, starts))
363-
if is_pad_type(T)
360+
if T <: Pad
364361
push!(values, pad_value(T))
365362
continue
366363
end
@@ -375,7 +372,7 @@ NarrowTuple(xs::Ts) where Ts<:Tuple = NarrowTuple{layout_tuple_type(Ts)}(xs)
375372
end
376373

377374
for (field_index, (T, W, field_first_bit)) in enumerate(zip(types, widths, starts))
378-
if is_pad_type(T)
375+
if T <: Pad
379376
push!(values, pad_value(T))
380377
continue
381378
end
@@ -419,18 +416,18 @@ end
419416

420417
if D <: Unsigned
421418
for (T, W, start) in zip(types, widths, starts)
422-
is_pad_type(T) || continue
419+
T <: Pad || continue
423420

424421
actual = :data
425422
start > 0 && (actual = :($actual >>> $start))
426423
actual = :($actual & $(narrow_mask(D, W)))
427-
expected = is_one_pad_type(T) ? narrow_mask(D, W) : zero(D)
424+
expected = T <: OnePad ? narrow_mask(D, W) : zero(D)
428425
message = "packed data does not match padding bits for $T"
429426
push!(checks, :($actual == $expected || throw(ArgumentError($message))))
430427
end
431428
else
432429
for (T, W, field_first_bit) in zip(types, widths, starts)
433-
is_pad_type(T) || continue
430+
T <: Pad || continue
434431

435432
field_last_bit = field_first_bit + W - 1
436433
first_byte = field_first_bit ÷ 8
@@ -449,7 +446,7 @@ end
449446
actual = :(Core.getfield(data, $(byte_index + 1)))
450447
source_shift > 0 && (actual = :($actual >>> $source_shift))
451448
width < 8 && (actual = :($actual & $(_low_mask(width))))
452-
expected = is_one_pad_type(T) ? _low_mask(width) : 0x00
449+
expected = T <: OnePad ? _low_mask(width) : 0x00
453450
message = "packed data does not match padding bits for $T"
454451
push!(checks, :($actual == $expected || throw(ArgumentError($message))))
455452
end
@@ -471,11 +468,11 @@ Base.iterate(nt::NarrowTuple, state...) = iterate(Tuple(nt), state...)
471468
Base.convert(::Type{Values}, nt::NarrowTuple) where Values<:Tuple = convert(Values, Tuple(nt))
472469
Base.reinterpret(::Type{T}, nt::NarrowTuple) where T = reinterpret(T, nt.data)
473470

474-
Base.show(io::IO, ::ZeroPadValue{N}) where N = print(io, "BitPacking.ZeroPad(", N, ")")
475-
Base.show(io::IO, ::OnePadValue{N}) where N = print(io, "BitPacking.OnePad(", N, ")")
471+
Base.show(io::IO, ::ZeroPad{N}) where N = print(io, ZeroPad, "(", N, ")")
472+
Base.show(io::IO, ::OnePad{N}) where N = print(io, OnePad, "(", N, ")")
476473

477474
function Base.show(io::IO, nt::NarrowTuple)
478-
print(io, "@NarrowTuple(")
475+
print(io, var"@NarrowTuple", "(")
479476
for (i, x) in enumerate(Tuple(nt))
480477
i > 1 && print(io, ", ")
481478
show(io, x)
@@ -502,7 +499,7 @@ function Base.show(io::IO, ::Type{T}) where {T<:NarrowTuple}
502499
return invoke(show, Tuple{IO,Type}, io, T)
503500
end
504501

505-
print(io, "@NarrowTuple{")
502+
print(io, var"@NarrowTuple", "{")
506503
show_narrow_tuple_fields(io, Ts)
507504
print(io, "}")
508505
end

test/runtests.jl

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,8 @@ bits(x) = x
129129
@testset "NarrowTuple" begin
130130
T3 = @NarrowTuple{Float4_E2M1FN,UInt8,Float4_E2M1FN}
131131
@test T3 === NarrowTuple{Tuple{Float4_E2M1FN,UInt8,Float4_E2M1FN},UInt16}
132-
@test BitPacking.bitwidth(Tuple{Float4_E2M1FN,UInt8,Float4_E2M1FN}) == 16
132+
@test BitPacking.bitwidth(T3) == 16
133+
@test BitPacking.bitwidth(Tuple{Float4_E2M1FN,UInt8,Float4_E2M1FN}) == 24
133134

134135
x3 = (float4(0x0a), 0xbc, float4(0x03))
135136
nt3 = T3(x3)
@@ -178,14 +179,10 @@ bits(x) = x
178179
@test Tuple(nt_nested) == (true, nt_bool)
179180
@test sprint(show, typeof(nt_nested)) == "@NarrowTuple{Bool, @NarrowTuple{UInt8, Bool}}"
180181

181-
@test isabstracttype(BitPacking.ZeroPad{7})
182-
@test isabstracttype(BitPacking.OnePad{7})
183182
@test BitPacking.bitwidth(BitPacking.ZeroPad{7}) == 7
184183
@test BitPacking.bitwidth(BitPacking.OnePad{7}) == 7
185184
@test BitPacking.bitwidth(BitPacking.ZeroPad(7)) == 7
186185
@test BitPacking.bitwidth(BitPacking.OnePad(7)) == 7
187-
@test BitPacking.ZeroPad{7}() == BitPacking.ZeroPad(7)
188-
@test BitPacking.OnePad{7}() == BitPacking.OnePad(7)
189186
@test sprint(show, BitPacking.ZeroPad(7)) == "BitPacking.ZeroPad(7)"
190187
@test sprint(show, BitPacking.OnePad(7)) == "BitPacking.OnePad(7)"
191188

0 commit comments

Comments
 (0)