Files
lattigo/utils/buffer/reader.go
2023-04-01 14:28:13 +02:00

266 lines
4.8 KiB
Go

package buffer
import (
"encoding/binary"
"fmt"
"io"
"github.com/tuneinsight/lattigo/v4/utils"
)
// Reader defines a interface comprising of the minimum subset
// of methods defined by the type bufio.Reader necessary to run
// the functions defined in this file.
// See the documentation of bufio.Reader: https://pkg.go.dev/bufio.
type Reader interface {
io.Reader
Size() int
Peek(n int) ([]byte, error)
Discard(n int) (discarded int, err error)
}
func ReadInt(r Reader, c *int) (n int, err error) {
if c == nil {
return 0, fmt.Errorf("cannot ReadInt: c is nil")
}
return ReadUint64(r, utils.PointyIntToPointUint64(c))
}
func ReadUint8(r Reader, c *uint8) (n int, err error) {
if c == nil {
return 0, fmt.Errorf("cannot ReadUint8: c is nil")
}
var bb = [1]byte{}
if n, err = r.Read(bb[:]); err != nil {
return
}
// Reads one byte
*c = uint8(bb[0])
return n, nil
}
func ReadUint8Slice(r Reader, c []uint8) (n int, err error) {
return r.Read(c)
}
func ReadUint16(r Reader, c *uint16) (n int, err error) {
if c == nil {
return 0, fmt.Errorf("cannot ReadUint16: c is nil")
}
var bb = [2]byte{}
if n, err = r.Read(bb[:]); err != nil {
return
}
// Reads one byte
*c = binary.LittleEndian.Uint16(bb[:])
return n, nil
}
func ReadUint16Slice(r Reader, c []uint16) (n int, err error) {
// c is empty, return
if len(c) == 0 {
return
}
var slice []byte
size := r.Size()
if len(c)<<1 < size {
size = len(c) << 1
}
// Then returns the writen bytes
if slice, err = r.Peek(size); err != nil {
fmt.Println(err)
return
}
buffered := len(slice) >> 1
// If the slice to write on is equal or smaller than the amount peaked
if N := len(c); N <= buffered {
for i, j := 0, 0; i < N; i, j = i+1, j+2 {
c[i] = binary.LittleEndian.Uint16(slice[j:])
}
return r.Discard(N << 1) // Discards what was read
}
// Decodes the maximum
for i, j := 0, 0; i < buffered; i, j = i+1, j+2 {
c[i] = binary.LittleEndian.Uint16(slice[j:])
}
// Discard what was peeked
var inc int
if inc, err = r.Discard(len(slice)); err != nil {
return n + inc, err
}
n += inc
// Recurses on the remaining slice to fill
if inc, err = ReadUint16Slice(r, c[buffered:]); err != nil {
return n + inc, err
}
return n + inc, nil
}
func ReadUint32(r Reader, c *uint32) (n int, err error) {
if c == nil {
return 0, fmt.Errorf("cannot ReadUint32: c is nil")
}
var bb = [4]byte{}
if n, err = r.Read(bb[:]); err != nil {
return
}
// Reads one byte
*c = binary.LittleEndian.Uint32(bb[:])
return n, nil
}
func ReadUint32Slice(r Reader, c []uint32) (n int, err error) {
// c is empty, return
if len(c) == 0 {
return
}
var slice []byte
// Avoid EOF
size := r.Size()
if len(c)<<2 < size {
size = len(c) << 2
}
// Then returns the writen bytes
if slice, err = r.Peek(size); err != nil {
fmt.Println(err)
return
}
buffered := len(slice) >> 2
// If the slice to write on is equal or smaller than the amount peaked
if N := len(c); N <= buffered {
for i, j := 0, 0; i < N; i, j = i+1, j+4 {
c[i] = binary.LittleEndian.Uint32(slice[j:])
}
return r.Discard(N << 2) // Discards what was read
}
// Decodes the maximum
for i, j := 0, 0; i < buffered; i, j = i+1, j+4 {
c[i] = binary.LittleEndian.Uint32(slice[j:])
}
// Discard what was peeked
var inc int
if inc, err = r.Discard(len(slice)); err != nil {
return n + inc, err
}
n += inc
// Recurses on the remaining slice to fill
if inc, err = ReadUint32Slice(r, c[buffered:]); err != nil {
return n + inc, err
}
return n + inc, nil
}
func ReadUint64(r Reader, c *uint64) (n int, err error) {
if c == nil {
return 0, fmt.Errorf("cannot ReadUint64: c is nil")
}
var bb = [8]byte{}
if n, err = r.Read(bb[:]); err != nil {
return
}
// Reads one byte
*c = binary.LittleEndian.Uint64(bb[:])
return n, nil
}
func ReadUint64Slice(r Reader, c []uint64) (n int, err error) {
// c is empty, return
if len(c) == 0 {
return
}
var slice []byte
// Avoid EOF
size := r.Size()
if len(c)<<3 < size {
size = len(c) << 3
}
// Then returns the writen bytes
if slice, err = r.Peek(size); err != nil {
return
}
buffered := len(slice) >> 3
// If the slice to write on is equal or smaller than the amount peaked
if N := len(c); N <= buffered {
for i, j := 0, 0; i < N; i, j = i+1, j+8 {
c[i] = binary.LittleEndian.Uint64(slice[j:])
}
return r.Discard(N << 3) // Discards what was read
}
// Decodes the maximum
for i, j := 0, 0; i < buffered; i, j = i+1, j+8 {
c[i] = binary.LittleEndian.Uint64(slice[j:])
}
// Discard what was peeked
var inc int
if inc, err = r.Discard(len(slice)); err != nil {
return n + inc, err
}
n += inc
// Recurses on the remaining slice to fill
if inc, err = ReadUint64Slice(r, c[buffered:]); err != nil {
return n + inc, err
}
return n + inc, nil
}