Files
lattigo/utils/structs/vector.go
2023-05-01 21:10:26 +02:00

210 lines
4.1 KiB
Go

package structs
import (
"bufio"
"bytes"
"fmt"
"io"
"encoding/binary"
"github.com/tuneinsight/lattigo/v4/utils/buffer"
)
type Vector[T any] []*T
// CopyNew creates a copy of the oject.
func (v Vector[T]) CopyNew() *Vector[T] {
vcpy := Vector[T](make([]*T, len(v)))
var err error
codec := Codec[T]{}
for i := range v {
if vcpy[i], err = codec.CopynewWrapper(v[i]); err != nil {
panic(err)
}
}
return &vcpy
}
// MarshalBinary encodes the object into a binary form on a newly allocated slice of bytes.
func (v *Vector[T]) MarshalBinary() (p []byte, err error) {
buf := bytes.NewBuffer([]byte{})
_, err = v.WriteTo(buf)
return buf.Bytes(), err
}
// UnmarshalBinary decodes a slice of bytes generated by
// MarshalBinary or WriteTo on the object.
func (v *Vector[T]) UnmarshalBinary(p []byte) (err error) {
_, err = v.ReadFrom(bytes.NewBuffer(p))
return
}
// WriteTo writes the object on an io.Writer.
// To ensure optimal efficiency and minimal allocations, the user is encouraged
// to provide a struct implementing the interface buffer.Writer, which defines
// a subset of the method of the bufio.Writer.
// If w is not compliant to the buffer.Writer interface, it will be wrapped in
// a new bufio.Writer.
// For additional information, see lattigo/utils/buffer/writer.go.
func (v *Vector[T]) WriteTo(w io.Writer) (int64, error) {
switch w := w.(type) {
case buffer.Writer:
var err error
var n int64
vi := *v
var inc int
if inc, err = buffer.WriteInt(w, len(vi)); err != nil {
return int64(inc), err
}
n += int64(inc)
codec := Codec[T]{}
for i := range vi {
var inc int64
if inc, err = codec.WriteToWrapper(w, vi[i]); err != nil {
return n + inc, err
}
n += inc
}
return n, w.Flush()
default:
return v.WriteTo(bufio.NewWriter(w))
}
}
// ReadFrom reads on the object from an io.Writer.
// To ensure optimal efficiency and minimal allocations, the user is encouraged
// to provide a struct implementing the interface buffer.Reader, which defines
// a subset of the method of the bufio.Reader.
// If r is not compliant to the buffer.Reader interface, it will be wrapped in
// a new bufio.Reader.
// For additional information, see lattigo/utils/buffer/reader.go.
func (v *Vector[T]) ReadFrom(r io.Reader) (int64, error) {
switch r := r.(type) {
case buffer.Reader:
var err error
var size, n int
if n, err = buffer.ReadInt(r, &size); err != nil {
return int64(n), fmt.Errorf("cannot ReadFrom: size: %w", err)
}
if len(*v) != size {
*v = make([]*T, size)
}
vi := *v
codec := Codec[T]{}
for i := range vi {
if vi[i] == nil {
vi[i] = new(T)
}
var inc int64
if inc, err = codec.ReadFromWrapper(r, vi[i]); err != nil {
return int64(n) + inc, err
}
n += int(inc)
}
return int64(n), nil
default:
return v.ReadFrom(bufio.NewReader(r))
}
}
// BinarySize returns the size in bytes of the object
// when encoded using Encode.
func (v Vector[T]) BinarySize() (size int) {
var err error
var inc int
codec := Codec[T]{}
size += 8
for _, vi := range v {
if inc, err = codec.BinarySizeWrapper(vi); err != nil {
panic(err)
}
size += inc
}
return
}
// Encode encodes the object into a binary form on a preallocated slice of bytes
// and returns the number of bytes written.
func (v *Vector[T]) Encode(b []byte) (n int, err error) {
vi := *v
binary.LittleEndian.PutUint64(b[n:], uint64(len(vi)))
n += 8
codec := Codec[T]{}
var inc int
for i := range vi {
if inc, err = codec.EncodeWrapper(b[n:], vi[i]); err != nil {
return n + inc, err
}
n += inc
}
return
}
// Decode decodes a slice of bytes generated by Encode
// on the object and returns the number of bytes read.
func (v *Vector[T]) Decode(p []byte) (n int, err error) {
size := int(binary.LittleEndian.Uint64(p[n:]))
n += 8
if len(*v) != size {
*v = make([]*T, size)
}
vi := *v
codec := Codec[T]{}
var inc int
for i := range vi {
if vi[i] == nil {
vi[i] = new(T)
}
if inc, err = codec.DecodeWrapper(p[n:], vi[i]); err != nil {
return n + inc, err
}
n += inc
}
return
}