github.com/weaviate/weaviate@v1.24.6/usecases/byteops/byteops.go (about) 1 // _ _ 2 // __ _____ __ ___ ___ __ _| |_ ___ 3 // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \ 4 // \ V V / __/ (_| |\ V /| | (_| | || __/ 5 // \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___| 6 // 7 // Copyright © 2016 - 2024 Weaviate B.V. All rights reserved. 8 // 9 // CONTACT: hello@weaviate.io 10 // 11 12 // Package byteops provides helper functions to (un-) marshal objects from or into a buffer 13 package byteops 14 15 import ( 16 "encoding/binary" 17 "errors" 18 "math" 19 ) 20 21 const ( 22 uint64Len = 8 23 uint32Len = 4 24 uint16Len = 2 25 uint8Len = 1 26 ) 27 28 type ReadWriter struct { 29 Position uint64 30 Buffer []byte 31 } 32 33 func WithPosition(pos uint64) func(*ReadWriter) { 34 return func(rw *ReadWriter) { 35 rw.Position = pos 36 } 37 } 38 39 func NewReadWriter(buf []byte, opts ...func(writer *ReadWriter)) ReadWriter { 40 rw := ReadWriter{Buffer: buf} 41 for _, opt := range opts { 42 opt(&rw) 43 } 44 return rw 45 } 46 47 func (bo *ReadWriter) ResetBuffer(buf []byte) { 48 bo.Buffer = buf 49 bo.Position = 0 50 } 51 52 func (bo *ReadWriter) ReadUint64() uint64 { 53 bo.Position += uint64Len 54 return binary.LittleEndian.Uint64(bo.Buffer[bo.Position-uint64Len : bo.Position]) 55 } 56 57 func (bo *ReadWriter) ReadUint16() uint16 { 58 bo.Position += uint16Len 59 return binary.LittleEndian.Uint16(bo.Buffer[bo.Position-uint16Len : bo.Position]) 60 } 61 62 func (bo *ReadWriter) ReadUint32() uint32 { 63 bo.Position += uint32Len 64 return binary.LittleEndian.Uint32(bo.Buffer[bo.Position-uint32Len : bo.Position]) 65 } 66 67 func (bo *ReadWriter) ReadUint8() uint8 { 68 bo.Position += uint8Len 69 return bo.Buffer[bo.Position-uint8Len] 70 } 71 72 func (bo *ReadWriter) CopyBytesFromBuffer(length uint64, out []byte) ([]byte, error) { 73 if out == nil { 74 out = make([]byte, length) 75 } 76 bo.Position += length 77 numCopiedBytes := copy(out, bo.Buffer[bo.Position-length:bo.Position]) 78 if numCopiedBytes != int(length) { 79 return nil, errors.New("could not copy data from buffer") 80 } 81 return out, nil 82 } 83 84 func (bo *ReadWriter) ReadBytesFromBuffer(length uint64) []byte { 85 subslice := bo.Buffer[bo.Position : bo.Position+length] 86 bo.Position += length 87 return subslice 88 } 89 90 func (bo *ReadWriter) ReadBytesFromBufferWithUint64LengthIndicator() []byte { 91 bo.Position += uint64Len 92 bufLen := binary.LittleEndian.Uint64(bo.Buffer[bo.Position-uint64Len : bo.Position]) 93 94 bo.Position += bufLen 95 subslice := bo.Buffer[bo.Position-bufLen : bo.Position] 96 return subslice 97 } 98 99 func (bo *ReadWriter) DiscardBytesFromBufferWithUint64LengthIndicator() uint64 { 100 bo.Position += uint64Len 101 bufLen := binary.LittleEndian.Uint64(bo.Buffer[bo.Position-uint64Len : bo.Position]) 102 103 bo.Position += bufLen 104 return bufLen 105 } 106 107 func (bo *ReadWriter) ReadBytesFromBufferWithUint32LengthIndicator() []byte { 108 bo.Position += uint32Len 109 bufLen := uint64(binary.LittleEndian.Uint32(bo.Buffer[bo.Position-uint32Len : bo.Position])) 110 111 if bufLen == 0 { 112 return nil 113 } 114 115 bo.Position += bufLen 116 subslice := bo.Buffer[bo.Position-bufLen : bo.Position] 117 return subslice 118 } 119 120 func (bo *ReadWriter) DiscardBytesFromBufferWithUint32LengthIndicator() uint32 { 121 bo.Position += uint32Len 122 bufLen := binary.LittleEndian.Uint32(bo.Buffer[bo.Position-uint32Len : bo.Position]) 123 124 bo.Position += uint64(bufLen) 125 return bufLen 126 } 127 128 func (bo *ReadWriter) WriteUint64(value uint64) { 129 bo.Position += uint64Len 130 binary.LittleEndian.PutUint64(bo.Buffer[bo.Position-uint64Len:bo.Position], value) 131 } 132 133 func (bo *ReadWriter) WriteUint32(value uint32) { 134 bo.Position += uint32Len 135 binary.LittleEndian.PutUint32(bo.Buffer[bo.Position-uint32Len:bo.Position], value) 136 } 137 138 func (bo *ReadWriter) WriteUint16(value uint16) { 139 bo.Position += uint16Len 140 binary.LittleEndian.PutUint16(bo.Buffer[bo.Position-uint16Len:bo.Position], value) 141 } 142 143 func (bo *ReadWriter) CopyBytesToBuffer(copyBytes []byte) error { 144 lenCopyBytes := uint64(len(copyBytes)) 145 bo.Position += lenCopyBytes 146 numCopiedBytes := copy(bo.Buffer[bo.Position-lenCopyBytes:bo.Position], copyBytes) 147 if numCopiedBytes != int(lenCopyBytes) { 148 return errors.New("could not copy data into buffer") 149 } 150 return nil 151 } 152 153 // Writes a uint64 length indicator about the buffer that's about to follow, 154 // then writes the buffer itself 155 func (bo *ReadWriter) CopyBytesToBufferWithUint64LengthIndicator(copyBytes []byte) error { 156 lenCopyBytes := uint64(len(copyBytes)) 157 bo.Position += uint64Len 158 binary.LittleEndian.PutUint64(bo.Buffer[bo.Position-uint64Len:bo.Position], lenCopyBytes) 159 bo.Position += lenCopyBytes 160 numCopiedBytes := copy(bo.Buffer[bo.Position-lenCopyBytes:bo.Position], copyBytes) 161 if numCopiedBytes != int(lenCopyBytes) { 162 return errors.New("could not copy data into buffer") 163 } 164 return nil 165 } 166 167 // Writes a uint32 length indicator about the buffer that's about to follow, 168 // then writes the buffer itself 169 func (bo *ReadWriter) CopyBytesToBufferWithUint32LengthIndicator(copyBytes []byte) error { 170 lenCopyBytes := uint32(len(copyBytes)) 171 bo.Position += uint32Len 172 binary.LittleEndian.PutUint32(bo.Buffer[bo.Position-uint32Len:bo.Position], lenCopyBytes) 173 bo.Position += uint64(lenCopyBytes) 174 numCopiedBytes := copy(bo.Buffer[bo.Position-uint64(lenCopyBytes):bo.Position], copyBytes) 175 if numCopiedBytes != int(lenCopyBytes) { 176 return errors.New("could not copy data into buffer") 177 } 178 return nil 179 } 180 181 func (bo *ReadWriter) MoveBufferPositionForward(length uint64) { 182 bo.Position += length 183 } 184 185 func (bo *ReadWriter) MoveBufferToAbsolutePosition(pos uint64) { 186 bo.Position = pos 187 } 188 189 func (bo *ReadWriter) WriteByte(b byte) { 190 bo.Buffer[bo.Position] = b 191 bo.Position += 1 192 } 193 194 func Float32ToByteVector(vec []float32) []byte { 195 byteVec := make([]byte, len(vec)*uint32Len) 196 for i := 0; i < len(vec); i++ { 197 binary.LittleEndian.PutUint32(byteVec[i*uint32Len:i*uint32Len+uint32Len], math.Float32bits(vec[i])) 198 } 199 return byteVec 200 } 201 202 func Float64ToByteVector(vec []float64) []byte { 203 byteVec := make([]byte, len(vec)*uint64Len) 204 for i := 0; i < len(vec); i++ { 205 binary.LittleEndian.PutUint64(byteVec[i*uint64Len:i*uint64Len+uint64Len], math.Float64bits(vec[i])) 206 } 207 return byteVec 208 } 209 210 func Float32FromByteVector(vecByte []byte) []float32 { 211 vector := make([]float32, len(vecByte)/uint32Len) 212 213 for i := 0; i < len(vector); i++ { 214 asUint := binary.LittleEndian.Uint32(vecByte[i*uint32Len : i*uint32Len+uint32Len]) 215 vector[i] = math.Float32frombits(asUint) 216 } 217 return vector 218 } 219 220 func Float64FromByteVector(vecByte []byte) []float64 { 221 vector := make([]float64, len(vecByte)/uint64Len) 222 223 for i := 0; i < len(vector); i++ { 224 asUint := binary.LittleEndian.Uint64(vecByte[i*uint64Len : i*uint64Len+uint64Len]) 225 vector[i] = math.Float64frombits(asUint) 226 } 227 return vector 228 }