Skip to content

Commit 505f2aa

Browse files
committed
bits: Add from_f32le, to_f32le, ...
TODO: - show somehow generalize to/from encodings? - move code to somwewhere else?
1 parent dea9303 commit 505f2aa

File tree

2 files changed

+88
-0
lines changed

2 files changed

+88
-0
lines changed

format/bits/bits.go

+76
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,21 @@ package bits
22

33
import (
44
"embed"
5+
"encoding/binary"
6+
"fmt"
7+
"math"
58

69
"github.com/wader/fq/format"
10+
"github.com/wader/fq/internal/gojqex"
11+
"github.com/wader/fq/internal/mathex"
12+
"github.com/wader/fq/pkg/bitio"
713
"github.com/wader/fq/pkg/decode"
814
"github.com/wader/fq/pkg/interp"
915
"github.com/wader/fq/pkg/scalar"
1016
)
1117

1218
//go:embed bits.md
19+
//go:embed bits.jq
1320
//go:embed bytes.md
1421
var bitsFS embed.FS
1522

@@ -39,5 +46,74 @@ func init() {
3946
DecodeFn: decodeBits(8),
4047
SkipDecodeFunction: true, // skip add bytes and frombytes function
4148
})
49+
interp.RegisterFunc2("_from_float", func(_ *interp.Interp, c any, nBits int, isLE bool) any {
50+
switch nBits {
51+
case 16, 32, 64:
52+
default:
53+
return fmt.Errorf("unsupported bit size %d, must be 16, 32 or 64", nBits)
54+
}
55+
56+
br, err := interp.ToBitReader(c)
57+
if err != nil {
58+
return err
59+
}
60+
var b [8]byte
61+
bs := b[:][0 : nBits/8]
62+
_, err = br.ReadBits(bs[:], int64(nBits))
63+
if err != nil {
64+
return err
65+
}
66+
if isLE {
67+
decode.ReverseBytes(bs[:])
68+
}
69+
70+
switch nBits {
71+
case 64:
72+
return math.Float64frombits(binary.BigEndian.Uint64(bs[:]))
73+
case 32:
74+
return float64(math.Float32frombits(binary.BigEndian.Uint32(bs[:])))
75+
case 16:
76+
return float64(mathex.Float16(binary.BigEndian.Uint16(bs[:])).Float32())
77+
default:
78+
panic("unreachable")
79+
}
80+
})
81+
interp.RegisterFunc2("_to_float", func(_ *interp.Interp, c any, nBits int, isLE bool) any {
82+
switch nBits {
83+
case 16, 32, 64:
84+
default:
85+
return fmt.Errorf("unsupported bit size %d, must be 16, 32 or 64", nBits)
86+
}
87+
88+
v, ok := gojqex.Cast[float64](c)
89+
if !ok {
90+
return gojqex.FuncTypeError{Name: "_to_float", V: v}
91+
}
92+
93+
var b [8]byte
94+
bs := b[:][0 : nBits/8]
95+
switch nBits {
96+
case 64:
97+
binary.BigEndian.PutUint64(bs, math.Float64bits(v))
98+
case 32:
99+
binary.BigEndian.PutUint32(bs, math.Float32bits(float32(v)))
100+
case 16:
101+
binary.BigEndian.PutUint16(bs, uint16(mathex.NewFloat16(float32(v))))
102+
default:
103+
panic("unreachable")
104+
}
105+
if isLE {
106+
decode.ReverseBytes(bs[:])
107+
}
108+
109+
br, err := interp.NewBinaryFromBitReader(bitio.NewBitReader(bs, -1), 8, 0)
110+
if err != nil {
111+
return err
112+
}
113+
114+
return br
115+
116+
})
117+
42118
interp.RegisterFS(bitsFS)
43119
}

format/bits/bits.jq

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
def from_f16be: _from_float(16; false);
2+
def from_f32be: _from_float(32; false);
3+
def from_f64be: _from_float(64; false);
4+
def from_f16le: _from_float(16; true);
5+
def from_f32le: _from_float(32; true);
6+
def from_f64le: _from_float(64; true);
7+
def to_f16le: _to_float(16; true);
8+
def to_f32le: _to_float(32; true);
9+
def to_f64le: _to_float(64; true);
10+
def to_f16be: _to_float(16; false);
11+
def to_f32be: _to_float(32; false);
12+
def to_f64be: _to_float(64; false);

0 commit comments

Comments
 (0)