-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdecoder.go
108 lines (89 loc) · 1.77 KB
/
decoder.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
//
// Copyright (C) 2024 Dmitry Kolesnikov
//
// This file may be modified and distributed under the terms
// of the MIT license. See the LICENSE file for details.
// https://github.com/kshard/fvecs
//
package fvecs
import (
"encoding/binary"
"io"
"math"
)
// Vector base types
type Base interface {
float32 | uint32 | byte
}
// Vector decoder
type Decoder[T Base] struct {
r io.Reader
n int
codec func(int, []byte) []T
d [4]byte
b []byte
}
// New instance of decoder
func NewDecoder[T Base](r io.Reader) *Decoder[T] {
d := &Decoder[T]{r: r}
switch any(*new(T)).(type) {
case float32:
d.n = 4
d.codec = toFVec
case uint32:
d.n = 4
d.codec = toIVec
case byte:
d.n = 1
d.codec = toBVec
}
return d
}
// Read vector from stream
func (d *Decoder[T]) Read() ([]T, error) {
s, err := d.readSize()
if err != nil {
return nil, err
}
l := s * d.n
if len(d.b) != int(l) {
d.b = make([]byte, l)
}
_, err = io.ReadFull(d.r, d.b)
if err != nil {
return nil, err
}
return d.codec(s, d.b), nil
}
// read vector size
func (d *Decoder[T]) readSize() (int, error) {
ps := d.d[:]
_, err := io.ReadFull(d.r, ps)
return int(d.d[0]) | int(d.d[1])<<8 | int(d.d[2])<<16 | int(d.d[3])<<24, err
}
// bytes to .fvecs
func toFVec[T Base](s int, b []byte) []T {
v := make([]float32, s)
p := 0
for i := 0; i < len(b); i += 4 {
v[p] = math.Float32frombits(binary.LittleEndian.Uint32(b[i : i+4]))
p++
}
return any(v).([]T)
}
// bytes to .ivecs
func toIVec[T Base](s int, b []byte) []T {
v := make([]uint32, s)
p := 0
for i := 0; i < len(b); i += 4 {
v[p] = binary.LittleEndian.Uint32(b[i : i+4])
p++
}
return any(v).([]T)
}
// bytes to .bvecs
func toBVec[T Base](s int, b []byte) []T {
v := make([]byte, s)
copy(v, b)
return any(v).([]T)
}