Files
lattigo/utils/structs/vector.go

165 lines
4.4 KiB
Go

package structs
import (
"bufio"
"fmt"
"io"
"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] {
var ct *T
if c, isCopiable := any(ct).(CopyNewer[T]); !isCopiable {
panic(fmt.Errorf("vector component of type %T does not comply to %T", new(T), c))
}
vcpy := Vector[T](make([]T, len(v)))
for i, c := range v {
/* #nosec G601 -- Implicit memory aliasing in for loop acknowledged */
vcpy[i] = *any(&c).(CopyNewer[T]).CopyNew()
}
return &vcpy
}
// BinarySize returns the serialized size of the object in bytes.
func (v Vector[T]) BinarySize() (size int) {
var st *T
if s, isSizable := any(st).(BinarySizer); !isSizable {
panic(fmt.Errorf("vector component of type %T does not comply to %T", st, s))
}
size += 8
for _, c := range v {
/* #nosec G601 -- Implicit memory aliasing in for loop acknowledged */
size += any(&c).(BinarySizer).BinarySize()
}
return
}
// WriteTo writes the object on an io.Writer. It implements the io.WriterTo
// interface, and will write exactly object.BinarySize() bytes on w.
//
// Unless w implements the buffer.Writer interface (see lattigo/utils/buffer/writer.go),
// it will be wrapped into a bufio.Writer. Since this requires allocations, it
// is preferable to pass a buffer.Writer directly:
//
// - When writing multiple times to a io.Writer, it is preferable to first wrap the
// io.Writer in a pre-allocated bufio.Writer.
// - When writing to a pre-allocated var b []byte, it is preferable to pass
// buffer.NewBuffer(b) as w (see lattigo/utils/buffer/buffer.go).
func (v Vector[T]) WriteTo(w io.Writer) (n int64, err error) {
var o *T
if wt, isWritable := any(o).(io.WriterTo); !isWritable {
return 0, fmt.Errorf("vector component of type %T does not comply to %T", o, wt)
}
switch w := w.(type) {
case buffer.Writer:
var inc int64
if inc, err = buffer.WriteInt(w, len(v)); err != nil {
return inc, err
}
n += inc
for i := range v {
if inc, err = any(&v[i]).(io.WriterTo).WriteTo(w); 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. It implements the
// io.ReaderFrom interface.
//
// Unless r implements the buffer.Reader interface (see see lattigo/utils/buffer/reader.go),
// it will be wrapped into a bufio.Reader. Since this requires allocation, it
// is preferable to pass a buffer.Reader directly:
//
// - When reading multiple values from a io.Reader, it is preferable to first
// first wrap io.Reader in a pre-allocated bufio.Reader.
// - When reading from a var b []byte, it is preferable to pass a buffer.NewBuffer(b)
// as w (see lattigo/utils/buffer/buffer.go).
func (v *Vector[T]) ReadFrom(r io.Reader) (n int64, err error) {
var rt *T
if r, isReadable := any(rt).(io.ReaderFrom); !isReadable {
return 0, fmt.Errorf("vector component of type %T does not comply to %T", rt, r)
}
switch r := r.(type) {
case buffer.Reader:
var size int
var inc int64
if inc, err = buffer.ReadInt(r, &size); err != nil {
return inc, fmt.Errorf("cannot read vector size: %w", err)
}
n += inc
if cap(*v) < size {
*v = make([]T, size)
}
*v = (*v)[:size]
for i := range *v {
if inc, err = any(&(*v)[i]).(io.ReaderFrom).ReadFrom(r); err != nil {
return n + inc, err
}
n += inc
}
return n, nil
default:
return v.ReadFrom(bufio.NewReader(r))
}
}
// 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 := buffer.NewBufferSize(v.BinarySize())
_, 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(buffer.NewBuffer(p))
return
}
type Equatable[T any] interface {
Equal(*T) bool
}
func (v Vector[T]) Equal(other Vector[T]) bool {
if d, isEquatable := any(new(T)).(Equatable[T]); !isEquatable {
panic(fmt.Errorf("vector component of type %T does not comply to %T", new(T), d))
}
isEqual := true
for i, v := range v {
/* #nosec G601 -- Implicit memory aliasing in for loop acknowledged */
isEqual = isEqual && any(&v).(Equatable[T]).Equal(&other[i])
}
return isEqual
}