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] { if c, isCopiable := any(new(T)).(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 := range v { vcpy[i] = *any(&v[i]).(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 i := range v { size += any(&v[i]).(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 }