mirror of
https://github.com/tuneinsight/lattigo.git
synced 2025-09-13 03:27:14 +00:00
391 lines
9.0 KiB
Go
391 lines
9.0 KiB
Go
package buffer
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
"unsafe"
|
|
)
|
|
|
|
// WriteAsUint64 casts &T to an *uint64 and writes it to w.
|
|
// User must ensure that T can be stored in an uint64.
|
|
func WriteAsUint64[T any](w Writer, c T) (n int64, err error) {
|
|
/* #nosec G103 -- behavior and consequences well understood, pointer type cast */
|
|
return WriteUint64(w, *(*uint64)(unsafe.Pointer(&c)))
|
|
}
|
|
|
|
// WriteAsUint32 casts &T to an *uint32 and writes it to w.
|
|
// User must ensure that T can be stored in an uint32.
|
|
func WriteAsUint32[T any](w Writer, c T) (n int64, err error) {
|
|
/* #nosec G103 -- behavior and consequences well understood, pointer type cast */
|
|
return WriteUint32(w, *(*uint32)(unsafe.Pointer(&c)))
|
|
}
|
|
|
|
// WriteAsUint16 casts &T to an *uint16 and writes it to w.
|
|
// User must ensure that T can be stored in an uint16.
|
|
func WriteAsUint16[T any](w Writer, c T) (n int64, err error) {
|
|
/* #nosec G103 -- behavior and consequences well understood, pointer type cast */
|
|
return WriteUint16(w, *(*uint16)(unsafe.Pointer(&c)))
|
|
}
|
|
|
|
// WriteAsUint8 casts &T to an *uint8 and writes it to w.
|
|
// User must ensure that T can be stored in an uint8.
|
|
func WriteAsUint8[T any](w Writer, c T) (n int64, err error) {
|
|
/* #nosec G103 -- behavior and consequences well understood, pointer type cast */
|
|
return WriteUint8(w, *(*uint8)(unsafe.Pointer(&c)))
|
|
}
|
|
|
|
// WriteAsUint64Slice casts &[]T into *[]uint64 and writes it to w.
|
|
// User must ensure that T can be stored in an uint64.
|
|
func WriteAsUint64Slice[T any](w Writer, c []T) (n int64, err error) {
|
|
/* #nosec G103 -- behavior and consequences well understood, pointer type cast */
|
|
return WriteUint64Slice(w, *(*[]uint64)(unsafe.Pointer(&c)))
|
|
}
|
|
|
|
// WriteAsUint32Slice casts &[]T into *[]uint32 and writes it to w.
|
|
// User must ensure that T can be stored in an uint32.
|
|
func WriteAsUint32Slice[T any](w Writer, c []T) (n int64, err error) {
|
|
/* #nosec G103 -- behavior and consequences well understood, pointer type cast */
|
|
return WriteUint32Slice(w, *(*[]uint32)(unsafe.Pointer(&c)))
|
|
}
|
|
|
|
// WriteAsUint16Slice casts &[]T into *[]uint16 and writes it to w.
|
|
// User must ensure that T can be stored in an uint16.
|
|
func WriteAsUint16Slice[T any](w Writer, c []T) (n int64, err error) {
|
|
/* #nosec G103 -- behavior and consequences well understood, pointer type cast */
|
|
return WriteUint16Slice(w, *(*[]uint16)(unsafe.Pointer(&c)))
|
|
}
|
|
|
|
// WriteAsUint8Slice casts &[]T into *[]uint8 and writes it to w.
|
|
// User must ensure that T can be stored in an uint8.
|
|
func WriteAsUint8Slice[T any](w Writer, c []T) (n int64, err error) {
|
|
/* #nosec G103 -- behavior and consequences well understood, pointer type cast */
|
|
return WriteUint8Slice(w, *(*[]uint8)(unsafe.Pointer(&c)))
|
|
}
|
|
|
|
// Write writes a slice of bytes to w.
|
|
func Write(w Writer, c []byte) (n int64, err error) {
|
|
nint, err := w.Write(c)
|
|
return int64(nint), err
|
|
}
|
|
|
|
// WriteUint8 writes a byte c to w.
|
|
func WriteUint8(w Writer, c uint8) (n int64, err error) {
|
|
|
|
if w.Available() == 0 {
|
|
if err = w.Flush(); err != nil {
|
|
return
|
|
}
|
|
|
|
if w.Available() == 0 {
|
|
return 0, fmt.Errorf("cannot WriteUint8: available buffer is zero even after flush")
|
|
}
|
|
}
|
|
|
|
nint, err := w.Write([]byte{c})
|
|
|
|
return int64(nint), err
|
|
}
|
|
|
|
// WriteUint8Slice writes a slice of bytes c to w.
|
|
func WriteUint8Slice(w Writer, c []uint8) (n int64, err error) {
|
|
|
|
if len(c) == 0 {
|
|
return
|
|
}
|
|
|
|
// Remaining available space in the internal buffer
|
|
available := w.Available()
|
|
|
|
if available == 0 {
|
|
|
|
if err = w.Flush(); err != nil {
|
|
return
|
|
}
|
|
|
|
available = w.Available()
|
|
|
|
if available == 0 {
|
|
return 0, fmt.Errorf("cannot WriteUint8Slice: available buffer/2 is zero even after flush")
|
|
}
|
|
}
|
|
|
|
buf := w.AvailableBuffer()
|
|
|
|
if N := len(c); N <= available { // If there is enough space in the available buffer
|
|
buf = buf[:N]
|
|
|
|
copy(buf, c)
|
|
|
|
nint, err := w.Write(buf)
|
|
|
|
return int64(nint), err
|
|
}
|
|
|
|
// First fills the space
|
|
buf = buf[:available]
|
|
|
|
copy(buf, c)
|
|
|
|
var inc int
|
|
if inc, err = w.Write(buf); err != nil {
|
|
return n + int64(inc), err
|
|
}
|
|
|
|
n += int64(inc)
|
|
|
|
// Flushes
|
|
if err = w.Flush(); err != nil {
|
|
return n, err
|
|
}
|
|
|
|
// Then recurses on itself with the remaining slice
|
|
var inc64 int64
|
|
inc64, err = WriteUint8Slice(w, c[available:])
|
|
|
|
return n + inc64, err
|
|
}
|
|
|
|
// WriteUint16 writes a uint16 c to w.
|
|
func WriteUint16(w Writer, c uint16) (n int64, err error) {
|
|
|
|
if w.Available()>>1 == 0 {
|
|
if err = w.Flush(); err != nil {
|
|
return
|
|
}
|
|
|
|
if w.Available()>>1 == 0 {
|
|
return 0, fmt.Errorf("cannot WriteUint16: available buffer/2 is zero even after flush")
|
|
}
|
|
}
|
|
|
|
buf := w.AvailableBuffer()[:2]
|
|
|
|
binary.LittleEndian.PutUint16(buf, c)
|
|
|
|
nint, err := w.Write(buf)
|
|
|
|
return int64(nint), err
|
|
}
|
|
|
|
// WriteUint16Slice writes a slice of uint16 c to w.
|
|
func WriteUint16Slice(w Writer, c []uint16) (n int64, err error) {
|
|
|
|
if len(c) == 0 {
|
|
return
|
|
}
|
|
|
|
// Remaining available space in the internal buffer
|
|
available := w.Available() >> 1
|
|
|
|
if available == 0 {
|
|
if err = w.Flush(); err != nil {
|
|
return
|
|
}
|
|
|
|
available = w.Available() >> 1
|
|
|
|
if available == 0 {
|
|
return 0, fmt.Errorf("cannot WriteUint16Slice: available buffer/2 is zero even after flush")
|
|
}
|
|
}
|
|
|
|
buf := w.AvailableBuffer()
|
|
|
|
if N := len(c); N <= available { // If there is enough space in the available buffer
|
|
buf = buf[:N<<1]
|
|
for i := 0; i < N; i++ {
|
|
binary.LittleEndian.PutUint16(buf[i<<1:], c[i])
|
|
}
|
|
|
|
nint, err := w.Write(buf)
|
|
|
|
return int64(nint), err
|
|
}
|
|
|
|
buf = buf[:available<<1]
|
|
|
|
// First fills the space
|
|
for i := 0; i < available; i++ {
|
|
binary.LittleEndian.PutUint16(buf[i<<1:], c[i])
|
|
}
|
|
|
|
var inc int
|
|
if inc, err = w.Write(buf); err != nil {
|
|
return n + int64(inc), err
|
|
}
|
|
|
|
n += int64(inc)
|
|
|
|
// Flushes
|
|
if err = w.Flush(); err != nil {
|
|
return n, err
|
|
}
|
|
|
|
// Then recurses on itself with the remaining slice
|
|
var inc64 int64
|
|
inc64, err = WriteUint16Slice(w, c[available:])
|
|
|
|
return n + inc64, err
|
|
}
|
|
|
|
// WriteUint32 writes a uint32 c into w.
|
|
func WriteUint32(w Writer, c uint32) (n int64, err error) {
|
|
|
|
if w.Available()>>2 == 0 {
|
|
if err = w.Flush(); err != nil {
|
|
return
|
|
}
|
|
|
|
if w.Available()>>2 == 0 {
|
|
return 0, fmt.Errorf("cannot WriteUint32: available buffer/4 is zero even after flush")
|
|
}
|
|
}
|
|
|
|
buf := w.AvailableBuffer()[:4]
|
|
binary.LittleEndian.PutUint32(buf, c)
|
|
nint, err := w.Write(buf)
|
|
return int64(nint), err
|
|
}
|
|
|
|
// WriteUint32Slice writes a slice of uint32 c into w.
|
|
func WriteUint32Slice(w Writer, c []uint32) (n int64, err error) {
|
|
|
|
if len(c) == 0 {
|
|
return
|
|
}
|
|
|
|
// Remaining available space in the internal buffer
|
|
available := w.Available() >> 2
|
|
|
|
if available == 0 {
|
|
if err = w.Flush(); err != nil {
|
|
return
|
|
}
|
|
|
|
available = w.Available() >> 2
|
|
|
|
if available == 0 {
|
|
return 0, fmt.Errorf("cannot WriteUint32Slice: available buffer/4 is zero even after flush")
|
|
}
|
|
}
|
|
|
|
buf := w.AvailableBuffer()
|
|
|
|
if N := len(c); N <= available { // If there is enough space in the available buffer
|
|
buf = buf[:N<<2]
|
|
for i := 0; i < N; i++ {
|
|
binary.LittleEndian.PutUint32(buf[i<<2:], c[i])
|
|
}
|
|
|
|
nint, err := w.Write(buf)
|
|
|
|
return int64(nint), err
|
|
}
|
|
|
|
// First fills the space
|
|
buf = buf[:available<<2]
|
|
for i := 0; i < available; i++ {
|
|
binary.LittleEndian.PutUint32(buf[i<<2:], c[i])
|
|
}
|
|
|
|
var inc int
|
|
if inc, err = w.Write(buf); err != nil {
|
|
return n + int64(inc), err
|
|
}
|
|
|
|
n += int64(inc)
|
|
|
|
// Flushes
|
|
if err = w.Flush(); err != nil {
|
|
return n, err
|
|
}
|
|
|
|
// Then recurses on itself with the remaining slice
|
|
var inc64 int64
|
|
inc64, err = WriteUint32Slice(w, c[available:])
|
|
|
|
return n + inc64, err
|
|
}
|
|
|
|
// WriteUint64 writes a uint64 c into w.
|
|
func WriteUint64(w Writer, c uint64) (n int64, err error) {
|
|
|
|
if w.Available()>>3 == 0 {
|
|
if err = w.Flush(); err != nil {
|
|
return
|
|
}
|
|
|
|
if w.Available()>>3 == 0 {
|
|
return 0, fmt.Errorf("cannot WriteUint64: available buffer/8 is zero even after flush")
|
|
}
|
|
}
|
|
|
|
buf := w.AvailableBuffer()[:8]
|
|
|
|
binary.LittleEndian.PutUint64(buf, c)
|
|
|
|
nint, err := w.Write(buf)
|
|
|
|
return int64(nint), err
|
|
}
|
|
|
|
// WriteUint64Slice writes a slice of uint64 into w.
|
|
func WriteUint64Slice(w Writer, c []uint64) (n int64, err error) {
|
|
|
|
if len(c) == 0 {
|
|
return
|
|
}
|
|
|
|
// Remaining available space in the internal buffer
|
|
available := w.Available() >> 3
|
|
|
|
if available == 0 {
|
|
if err = w.Flush(); err != nil {
|
|
return
|
|
}
|
|
|
|
available = w.Available() >> 3
|
|
|
|
if available == 0 {
|
|
return 0, fmt.Errorf("cannot WriteUint64Slice: available buffer/8 is zero even after flush")
|
|
}
|
|
}
|
|
|
|
buf := w.AvailableBuffer()
|
|
|
|
if N := len(c); N <= available { // If there is enough space in the available buffer
|
|
buf = buf[:N<<3]
|
|
for i := 0; i < N; i++ {
|
|
binary.LittleEndian.PutUint64(buf[i<<3:], c[i])
|
|
}
|
|
|
|
nint, err := w.Write(buf)
|
|
|
|
return int64(nint), err
|
|
}
|
|
|
|
// First fills the space
|
|
buf = buf[:available<<3]
|
|
for i := 0; i < available; i++ {
|
|
binary.LittleEndian.PutUint64(buf[i<<3:], c[i])
|
|
}
|
|
|
|
var inc int
|
|
if inc, err = w.Write(buf); err != nil {
|
|
return n + int64(inc), err
|
|
}
|
|
|
|
n += int64(inc)
|
|
|
|
// Flushes
|
|
if err = w.Flush(); err != nil {
|
|
return n, err
|
|
}
|
|
|
|
// Then recurses on itself with the remaining slice
|
|
var inc64 int64
|
|
inc64, err = WriteUint64Slice(w, c[available:])
|
|
|
|
return n + inc64, err
|
|
}
|