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  }