Optimize network types IO (#286)
This commit is contained in:
@ -1,6 +1,7 @@
|
|||||||
package packet
|
package packet
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
@ -175,8 +176,9 @@ func (u *UnsignedByte) ReadFrom(r io.Reader) (n int64, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s Short) WriteTo(w io.Writer) (int64, error) {
|
func (s Short) WriteTo(w io.Writer) (int64, error) {
|
||||||
n := uint16(s)
|
var buf [2]byte
|
||||||
nn, err := w.Write([]byte{byte(n >> 8), byte(n)})
|
binary.BigEndian.PutUint16(buf[:], uint16(s))
|
||||||
|
nn, err := w.Write(buf[:])
|
||||||
return int64(nn), err
|
return int64(nn), err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -188,13 +190,14 @@ func (s *Short) ReadFrom(r io.Reader) (n int64, err error) {
|
|||||||
n += int64(nn)
|
n += int64(nn)
|
||||||
}
|
}
|
||||||
|
|
||||||
*s = Short(int16(bs[0])<<8 | int16(bs[1]))
|
*s = Short(binary.BigEndian.Uint16(bs[:]))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (us UnsignedShort) WriteTo(w io.Writer) (int64, error) {
|
func (us UnsignedShort) WriteTo(w io.Writer) (int64, error) {
|
||||||
n := uint16(us)
|
var buf [2]byte
|
||||||
nn, err := w.Write([]byte{byte(n >> 8), byte(n)})
|
binary.BigEndian.PutUint16(buf[:], uint16(us))
|
||||||
|
nn, err := w.Write(buf[:])
|
||||||
return int64(nn), err
|
return int64(nn), err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,13 +209,14 @@ func (us *UnsignedShort) ReadFrom(r io.Reader) (n int64, err error) {
|
|||||||
n += int64(nn)
|
n += int64(nn)
|
||||||
}
|
}
|
||||||
|
|
||||||
*us = UnsignedShort(int16(bs[0])<<8 | int16(bs[1]))
|
*us = UnsignedShort(binary.BigEndian.Uint16(bs[:]))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i Int) WriteTo(w io.Writer) (int64, error) {
|
func (i Int) WriteTo(w io.Writer) (int64, error) {
|
||||||
n := uint32(i)
|
var buf [4]byte
|
||||||
nn, err := w.Write([]byte{byte(n >> 24), byte(n >> 16), byte(n >> 8), byte(n)})
|
binary.BigEndian.PutUint32(buf[:], uint32(i))
|
||||||
|
nn, err := w.Write(buf[:])
|
||||||
return int64(nn), err
|
return int64(nn), err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,16 +228,14 @@ func (i *Int) ReadFrom(r io.Reader) (n int64, err error) {
|
|||||||
n += int64(nn)
|
n += int64(nn)
|
||||||
}
|
}
|
||||||
|
|
||||||
*i = Int(int32(bs[0])<<24 | int32(bs[1])<<16 | int32(bs[2])<<8 | int32(bs[3]))
|
*i = Int(binary.BigEndian.Uint32(bs[:]))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l Long) WriteTo(w io.Writer) (int64, error) {
|
func (l Long) WriteTo(w io.Writer) (int64, error) {
|
||||||
n := uint64(l)
|
var buf [8]byte
|
||||||
nn, err := w.Write([]byte{
|
binary.BigEndian.PutUint64(buf[:], uint64(l))
|
||||||
byte(n >> 56), byte(n >> 48), byte(n >> 40), byte(n >> 32),
|
nn, err := w.Write(buf[:])
|
||||||
byte(n >> 24), byte(n >> 16), byte(n >> 8), byte(n),
|
|
||||||
})
|
|
||||||
return int64(nn), err
|
return int64(nn), err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,8 +247,7 @@ func (l *Long) ReadFrom(r io.Reader) (n int64, err error) {
|
|||||||
n += int64(nn)
|
n += int64(nn)
|
||||||
}
|
}
|
||||||
|
|
||||||
*l = Long(int64(bs[0])<<56 | int64(bs[1])<<48 | int64(bs[2])<<40 | int64(bs[3])<<32 |
|
*l = Long(binary.BigEndian.Uint64(bs[:]))
|
||||||
int64(bs[4])<<24 | int64(bs[5])<<16 | int64(bs[6])<<8 | int64(bs[7]))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,36 +261,48 @@ func (v VarInt) WriteTo(w io.Writer) (n int64, err error) {
|
|||||||
// WriteToBytes encodes the VarInt into buf and returns the number of bytes written.
|
// WriteToBytes encodes the VarInt into buf and returns the number of bytes written.
|
||||||
// If the buffer is too small, WriteToBytes will panic.
|
// If the buffer is too small, WriteToBytes will panic.
|
||||||
func (v VarInt) WriteToBytes(buf []byte) int {
|
func (v VarInt) WriteToBytes(buf []byte) int {
|
||||||
|
// https://steinborn.me/posts/performance/how-fast-can-you-write-a-varint/
|
||||||
num := uint32(v)
|
num := uint32(v)
|
||||||
i := 0
|
if num&0xFFFFFF80 == 0 {
|
||||||
for {
|
buf[0] = byte(num)
|
||||||
b := num & 0x7F
|
return 1
|
||||||
num >>= 7
|
} else if num&0xFFFFC000 == 0 {
|
||||||
if num != 0 {
|
result := uint16((num&0x7F|0x80)<<8 | (num >> 7))
|
||||||
b |= 0x80
|
binary.BigEndian.PutUint16(buf, result)
|
||||||
|
return 2
|
||||||
|
} else if num&0xFFE00000 == 0 {
|
||||||
|
buf[2] = byte(num >> 14)
|
||||||
|
startingBytes := uint16((num&0x7F|0x80)<<8 | ((num>>7)&0x7F | 0x80))
|
||||||
|
binary.BigEndian.PutUint16(buf, startingBytes)
|
||||||
|
return 3
|
||||||
|
} else if num&0xF0000000 == 0 {
|
||||||
|
result := (num&0x7F|0x80)<<24 | (((num>>7)&0x7F | 0x80) << 16) |
|
||||||
|
((num>>14)&0x7F|0x80)<<8 | (num >> 21)
|
||||||
|
binary.BigEndian.PutUint32(buf, result)
|
||||||
|
return 4
|
||||||
|
} else {
|
||||||
|
buf[4] = byte(num >> 28)
|
||||||
|
startingBytes := (num&0x7F|0x80)<<24 | ((num>>7)&0x7F|0x80)<<16 |
|
||||||
|
((num>>14)&0x7F|0x80)<<8 | ((num>>21)&0x7F | 0x80)
|
||||||
|
binary.BigEndian.PutUint32(buf, startingBytes)
|
||||||
|
return 5
|
||||||
}
|
}
|
||||||
buf[i] = byte(b)
|
|
||||||
i++
|
|
||||||
if num == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return i
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *VarInt) ReadFrom(r io.Reader) (n int64, err error) {
|
func (v *VarInt) ReadFrom(r io.Reader) (n int64, err error) {
|
||||||
var V uint32
|
var V uint32
|
||||||
var num, n2 int64
|
var num int64
|
||||||
|
byteReader := CreateByteReader(r)
|
||||||
for sec := byte(0x80); sec&0x80 != 0; num++ {
|
for sec := byte(0x80); sec&0x80 != 0; num++ {
|
||||||
if num > MaxVarIntLen {
|
if num > MaxVarIntLen {
|
||||||
return n, errors.New("VarInt is too big")
|
return n, errors.New("VarInt is too big")
|
||||||
}
|
}
|
||||||
|
|
||||||
n2, sec, err = readByte(r)
|
sec, err = byteReader.ReadByte()
|
||||||
n += n2
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
n += 1
|
||||||
|
|
||||||
V |= uint32(sec&0x7F) << uint32(7*num)
|
V |= uint32(sec&0x7F) << uint32(7*num)
|
||||||
}
|
}
|
||||||
@ -326,35 +339,32 @@ func (v VarLong) WriteTo(w io.Writer) (n int64, err error) {
|
|||||||
// WriteToBytes encodes the VarLong into buf and returns the number of bytes written.
|
// WriteToBytes encodes the VarLong into buf and returns the number of bytes written.
|
||||||
// If the buffer is too small, WriteToBytes will panic.
|
// If the buffer is too small, WriteToBytes will panic.
|
||||||
func (v VarLong) WriteToBytes(buf []byte) int {
|
func (v VarLong) WriteToBytes(buf []byte) int {
|
||||||
|
// Like VarInt, but we don't unroll the loop because it might be too long.
|
||||||
num := uint64(v)
|
num := uint64(v)
|
||||||
i := 0
|
n := v.Len()
|
||||||
for {
|
continuationBytes := n - 1
|
||||||
b := num & 0x7F
|
_ = buf[continuationBytes] // bounds check hint to compiler; see golang.org/issue/14808
|
||||||
|
for i := 0; i < continuationBytes; i++ {
|
||||||
|
buf[i] = byte(num&0x7F | 0x80)
|
||||||
num >>= 7
|
num >>= 7
|
||||||
if num != 0 {
|
|
||||||
b |= 0x80
|
|
||||||
}
|
}
|
||||||
buf[i] = byte(b)
|
buf[continuationBytes] = byte(num)
|
||||||
i++
|
return n
|
||||||
if num == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return i
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *VarLong) ReadFrom(r io.Reader) (n int64, err error) {
|
func (v *VarLong) ReadFrom(r io.Reader) (n int64, err error) {
|
||||||
var V uint64
|
var V uint64
|
||||||
var num, n2 int64
|
var num int64
|
||||||
|
byteReader := CreateByteReader(r)
|
||||||
for sec := byte(0x80); sec&0x80 != 0; num++ {
|
for sec := byte(0x80); sec&0x80 != 0; num++ {
|
||||||
if num >= MaxVarLongLen {
|
if num >= MaxVarLongLen {
|
||||||
return n, errors.New("VarLong is too big")
|
return n, errors.New("VarLong is too big")
|
||||||
}
|
}
|
||||||
n2, sec, err = readByte(r)
|
sec, err = byteReader.ReadByte()
|
||||||
n += n2
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
n += 1
|
||||||
|
|
||||||
V |= uint64(sec&0x7F) << uint64(7*num)
|
V |= uint64(sec&0x7F) << uint64(7*num)
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ import (
|
|||||||
pk "github.com/Tnze/go-mc/net/packet"
|
pk "github.com/Tnze/go-mc/net/packet"
|
||||||
)
|
)
|
||||||
|
|
||||||
var VarInts = []pk.VarInt{0, 1, 2, 127, 128, 255, 2147483647, -1, -2147483648}
|
var VarInts = []pk.VarInt{0, 1, 2, 127, 128, 255, 25565, 2097151, 2147483647, -1, -2147483648}
|
||||||
|
|
||||||
var PackedVarInts = [][]byte{
|
var PackedVarInts = [][]byte{
|
||||||
{0x00},
|
{0x00},
|
||||||
@ -19,6 +19,8 @@ var PackedVarInts = [][]byte{
|
|||||||
{0x7f},
|
{0x7f},
|
||||||
{0x80, 0x01},
|
{0x80, 0x01},
|
||||||
{0xff, 0x01},
|
{0xff, 0x01},
|
||||||
|
{0xdd, 0xc7, 0x01},
|
||||||
|
{0xff, 0xff, 0x7f},
|
||||||
{0xff, 0xff, 0xff, 0xff, 0x07},
|
{0xff, 0xff, 0xff, 0xff, 0x07},
|
||||||
{0xff, 0xff, 0xff, 0xff, 0x0f},
|
{0xff, 0xff, 0xff, 0xff, 0x0f},
|
||||||
{0x80, 0x80, 0x80, 0x80, 0x08},
|
{0x80, 0x80, 0x80, 0x80, 0x08},
|
||||||
|
@ -273,3 +273,22 @@ func (t Tuple) ReadFrom(r io.Reader) (n int64, err error) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CreateByteReader(reader io.Reader) io.ByteReader {
|
||||||
|
if byteReader, isByteReader := reader.(io.ByteReader); isByteReader {
|
||||||
|
return byteReader
|
||||||
|
}
|
||||||
|
return byteReaderWrapper{reader}
|
||||||
|
}
|
||||||
|
|
||||||
|
type byteReaderWrapper struct {
|
||||||
|
io.Reader
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ io.ByteReader = byteReaderWrapper{}
|
||||||
|
|
||||||
|
func (r byteReaderWrapper) ReadByte() (byte, error) {
|
||||||
|
var buf [1]byte
|
||||||
|
_, err := io.ReadFull(r.Reader, buf[:])
|
||||||
|
return buf[0], err
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user