Files
lattigo/utils/structs/map.go
Jean-Philippe Bossuat 5951af1c23 staticcheck
2023-04-24 21:36:51 +02:00

233 lines
4.7 KiB
Go

package structs
import (
"bufio"
"bytes"
"encoding/binary"
"fmt"
"io"
"github.com/tuneinsight/lattigo/v4/utils"
"github.com/tuneinsight/lattigo/v4/utils/buffer"
"golang.org/x/exp/constraints"
)
// Map is a struct storing a map of any element indexed by an Integer.
type Map[V constraints.Integer, T any] map[V]*T
// CopyNew creates a copy of the oject.
func (m Map[V, T]) CopyNew() *Map[V, T] {
var mcpy = make(Map[V, T])
codec := Codec[T]{}
var err error
for key, object := range m {
if mcpy[key], err = codec.CopynewWrapper(object); err != nil {
panic(err)
}
}
return &mcpy
}
// MarshalBinary encodes the object into a binary form on a newly allocated slice of bytes.
func (m *Map[V, T]) MarshalBinary() (p []byte, err error) {
buf := bytes.NewBuffer([]byte{})
_, err = m.WriteTo(buf)
return buf.Bytes(), err
}
// UnmarshalBinary decodes a slice of bytes generated by
// MarshalBinary or WriteTo on the object.
func (m *Map[V, T]) UnmarshalBinary(p []byte) (err error) {
_, err = m.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 (m *Map[V, T]) WriteTo(w io.Writer) (n int64, err error) {
switch w := w.(type) {
case buffer.Writer:
mi := *m
var inc1 int
if inc1, err = buffer.WriteUint32(w, uint32(len(mi))); err != nil {
return n + int64(inc1), err
}
n += int64(inc1)
codec := Codec[T]{}
for _, key := range utils.GetSortedKeys(mi) {
if inc1, err = buffer.WriteUint64(w, uint64(key)); err != nil {
return n + int64(inc1), err
}
n += int64(inc1)
var inc2 int64
if inc2, err = codec.WriteToWrapper(w, mi[key]); err != nil {
return n + inc2, err
}
n += inc2
}
return
default:
return m.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 (m *Map[V, T]) ReadFrom(r io.Reader) (n int64, err error) {
switch r := r.(type) {
case buffer.Reader:
mi := *m
var inc1 int
var size uint32
if inc1, err = buffer.ReadUint32(r, &size); err != nil {
return n + int64(inc1), err
}
n += int64(inc1)
codec := Codec[T]{}
for i := 0; i < int(size); i++ {
var key uint64
if inc1, err = buffer.ReadUint64(r, &key); err != nil {
return n + int64(inc1), err
}
n += int64(inc1)
if mi[V(key)] == nil {
mi[V(key)] = new(T)
}
var inc2 int64
if inc2, err = codec.ReadFromWrapper(r, mi[V(key)]); err != nil {
return n + inc2, err
}
n += inc2
}
return
default:
return m.ReadFrom(bufio.NewReader(r))
}
}
// BinarySize returns the size in bytes of the object
// when encoded using Encode.
func (m Map[V, T]) BinarySize() (size int) {
size = 4 // #Ct
codec := Codec[T]{}
var inc int
var err error
for _, v := range m {
size += 8
if inc, err = codec.BinarySizeWrapper(v); 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 (m *Map[V, T]) Encode(p []byte) (n int, err error) {
if len(p) < m.BinarySize() {
return n, fmt.Errorf("cannot Encode: len(p)=%d < %d", len(p), m.BinarySize())
}
codec := Codec[T]{}
mi := *m
binary.LittleEndian.PutUint32(p[n:], uint32(len(mi)))
n += 4
for _, key := range utils.GetSortedKeys(mi) {
binary.LittleEndian.PutUint64(p[n:], uint64(key))
n += 8
var inc int
if inc, err = codec.EncodeWrapper(p[n:], mi[key]); 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 (m *Map[V, T]) Decode(p []byte) (n int, err error) {
mi := *m
size := int(binary.LittleEndian.Uint32(p[n:]))
n += 4
codec := Codec[T]{}
for i := 0; i < size; i++ {
idx := V(binary.LittleEndian.Uint64(p[n:]))
n += 8
if mi[idx] == nil {
mi[idx] = new(T)
}
var inc int
if inc, err = codec.DecodeWrapper(p[n:], mi[idx]); err != nil {
return n + inc, err
}
n += inc
}
return
}