Skip to content

Commit

Permalink
add zero copy reader (#44)
Browse files Browse the repository at this point in the history
  • Loading branch information
laizy authored Jun 3, 2022
1 parent f3cc0fc commit 2589aec
Show file tree
Hide file tree
Showing 2 changed files with 215 additions and 1 deletion.
160 changes: 160 additions & 0 deletions utils/codec/zero_copy_reader.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
package codec

import (
"io"

"github.com/laizy/web3"
)

type ZeroCopyReader struct {
Source *ZeroCopySource
err error
}

func (self *ZeroCopyReader) Error() error {
return self.err
}

// Len returns the number of bytes of the unread portion of the
// slice.
func (self *ZeroCopyReader) Len() uint64 {
return self.Source.Len()
}

func (self *ZeroCopyReader) Pos() uint64 {
return self.Source.Pos()
}

// Size returns the original length of the underlying byte slice.
// Size is the number of bytes available for reading via ReadAt.
// The returned value is always the same and is not affected by calls
// to any other method.
func (self *ZeroCopyReader) Size() uint64 { return self.Source.Size() }

// Read implements the io.ZeroCopyReader interface.
func (self *ZeroCopyReader) ReadBytes(n uint64) (data []byte) {
if self.err != nil {
return
}
data, self.err = self.Source.ReadBytes(n)
return
}

func (self *ZeroCopyReader) Skip(n uint64) {
if self.err != nil {
return
}
eof := self.Source.Skip(n)
if eof {
self.err = io.ErrUnexpectedEOF
}
return
}

func (self *ZeroCopyReader) ReadUint8() (data uint8) {
if self.err != nil {
return
}
data, self.err = self.Source.ReadByte()
return
}

func (self *ZeroCopyReader) ReadBool() (data bool) {
if self.err != nil {
return
}
data, self.err = self.Source.ReadBool()
return
}

// Backs up a number of bytes, so that the next call to NextXXX() returns data again
// that was already returned by the last call to NextXXX().
func (self *ZeroCopyReader) BackUp(n uint64) {
self.Source.BackUp(n)
}

func (self *ZeroCopyReader) ReadUint32() (data uint32) {
if self.err != nil {
return
}
data, self.err = self.Source.ReadUint32BE()
return
}

func (self *ZeroCopyReader) ReadUint32BE() (data uint32) {
if self.err != nil {
return
}
data, self.err = self.Source.ReadUint32BE()
return
}

func (self *ZeroCopyReader) ReadUint64() (data uint64) {
if self.err != nil {
return
}
data, self.err = self.Source.ReadUint64()
return
}

func (self *ZeroCopyReader) ReadUint64BE() (data uint64) {
if self.err != nil {
return
}
data, self.err = self.Source.ReadUint64BE()
return
}

func (self *ZeroCopyReader) ReadInt32() (data int32) {
return int32(self.ReadUint32())
}

func (self *ZeroCopyReader) ReadInt64() (data int64) {
return int64(self.ReadUint64())
}

func (self *ZeroCopyReader) ReadString() (data string) {
if self.err != nil {
return
}
data, self.err = self.Source.ReadString()
return
}

func (self *ZeroCopyReader) ReadVarBytes() (data []byte) {
if self.err != nil {
return nil
}
data, self.err = self.Source.ReadVarBytes()
return data
}

func (self *ZeroCopyReader) ReadAddress() (addr web3.Address) {
if self.err != nil {
return
}
addr, self.err = self.Source.ReadAddress()
return
}

func (self *ZeroCopyReader) ReadHash() (hash web3.Hash) {
if self.err != nil {
return
}
hash, self.err = self.Source.ReadHash()
return
}

func (self *ZeroCopyReader) ReadVarUint() (data uint64) {
if self.err != nil {
return
}
data, self.err = self.Source.ReadVarUint()
return
}

func NewZeroCopyReader(b []byte) *ZeroCopyReader {
return &ZeroCopyReader{
Source: NewZeroCopySource(b),
}
}
56 changes: 55 additions & 1 deletion utils/codec/zero_copy_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,23 @@ func (self *ZeroCopySource) NextByte() (data byte, eof bool) {
return b, false
}

func (self *ZeroCopySource) ReadByte() (data byte, err error) {
d, eof := self.NextByte()
if eof {
err = io.ErrUnexpectedEOF
return
}
return d, nil
}

func (self *ZeroCopySource) ReadUint8() (data uint8, err error) {
return self.ReadByte()
}

func (self *ZeroCopySource) NextUint8() (data uint8, eof bool) {
var val byte
val, eof = self.NextByte()
return uint8(val), eof
return val, eof
}

func (self *ZeroCopySource) NextBool() (data bool, irregular bool, eof bool) {
Expand All @@ -116,9 +129,24 @@ func (self *ZeroCopySource) NextBool() (data bool, irregular bool, eof bool) {
return
}

func (self *ZeroCopySource) ReadBool() (data bool, err error) {
d, irr, eof := self.NextBool()
if eof {
err = io.ErrUnexpectedEOF
return
} else if irr {
err = ErrIrregularData
return
}
return d, nil
}

// Backs up a number of bytes, so that the next call to NextXXX() returns data again
// that was already returned by the last call to NextXXX().
func (self *ZeroCopySource) BackUp(n uint64) {
if n > self.off {
panic("backup too large")
}
self.off -= n
}

Expand Down Expand Up @@ -224,6 +252,16 @@ func (self *ZeroCopySource) ReadString() (string, error) {
return string(d), err
}

func (self *ZeroCopySource) ReadBytes(n uint64) (data []byte, err error) {
d, eof := self.NextBytes(n)
if eof {
err = io.ErrUnexpectedEOF
return
}

return d, nil
}

func (self *ZeroCopySource) ReadVarBytes() (data []byte, err error) {
data, _, irr, eof := self.NextVarBytes()
if irr {
Expand Down Expand Up @@ -283,6 +321,18 @@ func (self *ZeroCopySource) NextString() (data string, size uint64, irregular bo
return
}

func (self *ZeroCopySource) ReadVarUint() (data uint64, err error) {
d, _, irr, eof := self.NextVarUint()
if eof {
err = io.ErrUnexpectedEOF
return
} else if irr {
err = ErrIrregularData
return
}
return d, nil
}

func (self *ZeroCopySource) NextVarUint() (data uint64, size uint64, irregular bool, eof bool) {
var fb byte
fb, eof = self.NextByte()
Expand Down Expand Up @@ -345,3 +395,7 @@ func NewZeroCopySource(b []byte) *ZeroCopySource {
byteOrder: binary.LittleEndian,
}
}

func (self *ZeroCopySource) Reader() *ZeroCopyReader {
return &ZeroCopyReader{Source: self}
}

0 comments on commit 2589aec

Please sign in to comment.