binary

package module
v0.0.0-...-3607cc3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 24, 2020 License: MIT Imports: 3 Imported by: 0

README

GoDoc Build Status

binary

A faster binary encoder.

go get howl.moe/binary

Migrating to version 2

All slice-related methods have been removed - this is because they allocated their own slices (for reads). The way slices are implemented in binary protocols is often arbitrary, some specify the length, some only in certain cases, some use varints, others use different widths for the length. For this reason, we removed the methods.

ByteSlice and String have been kept, since those are even used internally.

There is no way to read a string directly like there was in the previous version - this is because of the aforementioned variability in implementation about encoding the length. You can still use the newly-added Read method (implements io.Reader) passing a byte slice with the length desired.

Why you should

The biggest, yet simplest, change was by removing all slice allocations. This is a common trick used often, in places such as fasthttp and nanojson (yes, that's what we call shameless advertising.)

Previously, every single tiny read and write allocated a byte slice. This is actually quite expensive - it is a heap allocation, which needs to be tracked by the garbage collector, and so on. Writes are now buffered in an internal 512-byte array, and by being able to encode binary data straight in that array we reach big performance boosts.

$ git checkout v1
$ go test -bench=.
go test -bench=. -benchmem
goos: linux
goarch: amd64
pkg: github.com/thehowl/binary
BenchmarkWriteSmall-4    	37062871	        27.2 ns/op	       1 B/op	       1 allocs/op
BenchmarkWriteMedium-4   	 5283705	       210 ns/op	      40 B/op	       5 allocs/op
BenchmarkWriteLong-4     	  849973	      1417 ns/op	     240 B/op	      12 allocs/op
PASS
ok  	github.com/thehowl/binary	4.592s

$ git checkout master
$ go test -bench=. -benchmem
goos: linux
goarch: amd64
pkg: howl.moe/binary
BenchmarkWriteSmall-4                 	60495008	        17.9 ns/op	       0 B/op	       0 allocs/op
BenchmarkWriteSmallEncodingBinary-4   	40247256	        29.3 ns/op	       1 B/op	       1 allocs/op
BenchmarkWriteMedium-4                	19292994	        52.6 ns/op	       0 B/op	       0 allocs/op
BenchmarkWriteLong-4                  	11028130	       104 ns/op	       0 B/op	       0 allocs/op
BenchmarkWriteLongEncodingBinary-4    	 5126353	       256 ns/op	      96 B/op	       3 allocs/op
PASS
ok  	howl.moe/binary	7.164s

As you can see, for writes of large chunks of data, this can be up to a 14x improvement from the previous version. As it turns out, the allocations were so expensive that the package was actually slower than encoding/binary. Not anymore: you can now see that this package is 2x faster on long writes than encoding/binary.

Documentation

Overview

Package binary approaches binary encoding with a different approach from encoding/binary. The main aim of this package is to be *fast*, and thus not to use reflection, and with more type-safety.

By its nature, this package is statically typed, and as such will not support arrays, structs and slices of compound/non-builtin types (or slices of slices). Apart from that, behaviour is pretty much like that of encoding/binary.

Index

Examples

Constants

This section is empty.

Variables

View Source
var BigEndian bigEndian

BigEndian is the big-endian implementation of ByteOrder.

View Source
var LittleEndian littleEndian

LittleEndian is the little-endian implementation of ByteOrder.

Functions

This section is empty.

Types

type ByteOrder

type ByteOrder interface {
	Uint16([]byte) uint16
	Uint32([]byte) uint32
	Uint64([]byte) uint64
	PutUint16([]byte, uint16)
	PutUint32([]byte, uint32)
	PutUint64([]byte, uint64)
	String() string
}

A ByteOrder specifies how to convert byte sequences into 16-, 32-, or 64-bit unsigned integers.

type Reader

type Reader struct {
	Reader    io.Reader
	ByteOrder ByteOrder
	// contains filtered or unexported fields
}

Reader is the simplified version of ReadChain. Instead of having to pass pointers to decode bytes, using Reader you can read data directly and do, for instance, simple assignments.

Example
package main

import (
	"bytes"
	"fmt"

	"howl.moe/binary"
)

func main() {
	buf := bytes.NewBuffer([]byte("\x05\xff\x02\x00"))
	r := &binary.Reader{
		Reader:    buf,
		ByteOrder: binary.LittleEndian,
	}
	var (
		b1 = r.Byte()
		b2 = r.Int8()
		i  = r.Int16()
	)
	_, err := r.End()
	if err != nil {
		panic(err)
	}
	fmt.Printf("%d - %d - %d\n", b1, b2, i)
}
Output:

5 - -1 - 2

func (*Reader) Bool

func (r *Reader) Bool() bool

Bool decodes a bool from the Reader.

func (*Reader) Byte

func (r *Reader) Byte() byte

Byte decodes an uint64 from the Reader.

func (*Reader) Complex128

func (r *Reader) Complex128() complex128

Complex128 decodes a Complex128 from the Reader.

func (*Reader) Complex64

func (r *Reader) Complex64() complex64

Complex64 decodes a Complex64 from the Reader.

func (*Reader) End

func (r *Reader) End() (int, error)

End returns the amount of read bytes and any eventual error, and sets the internal amount of written bytes to 0, and the error to nil.

func (*Reader) Float32

func (r *Reader) Float32() float32

Float32 decodes a float32 from the Reader.

func (*Reader) Float64

func (r *Reader) Float64() float64

Float64 decodes a float64 from the Reader.

func (*Reader) Int16

func (r *Reader) Int16() int16

Int16 decodes an int16 from the Reader.

func (*Reader) Int32

func (r *Reader) Int32() int32

Int32 decodes an int32 from the Reader.

func (*Reader) Int64

func (r *Reader) Int64() int64

Int64 decodes an int64 from the Reader.

func (*Reader) Int8

func (r *Reader) Int8() int8

Int8 decodes an int8 from the Reader.

func (*Reader) Read

func (r *Reader) Read(p []byte) (int, error)

Read is a simple wrapper around r.Reader.Read. The Reader's internal read counter will be incremented and the error will be set if any, so that r.End returns the correct result.

func (*Reader) Rune

func (r *Reader) Rune() rune

Rune decodes an rune from the Reader.

func (*Reader) Uint16

func (r *Reader) Uint16() uint16

Uint16 decodes an uint16 from the Reader.

func (*Reader) Uint32

func (r *Reader) Uint32() uint32

Uint32 decodes an uint32 from the Reader.

func (*Reader) Uint64

func (r *Reader) Uint64() uint64

Uint64 decodes an uint64 from the Reader.

func (*Reader) Uint8

func (r *Reader) Uint8() uint8

Uint8 decodes an uint8 from the Reader.

type WriteChain

type WriteChain struct {
	Writer    io.Writer
	ByteOrder ByteOrder
	// contains filtered or unexported fields
}

WriteChain wraps around an io.Writer and a encoding.ByteOrder, and writes data into the Writer using the given ByteOrder. WriteChain is not thread-safe.

Example
package main

import (
	"bytes"
	"fmt"

	"howl.moe/binary"
)

func main() {
	buf := &bytes.Buffer{}
	writer := &binary.WriteChain{
		Writer:    buf,
		ByteOrder: binary.LittleEndian,
	}
	_, err := writer.
		Uint16(266).
		Byte(1).
		Uint32(2).
		End()
	if err != nil {
		panic(err)
	}
	fmt.Printf("% x\n", buf.Bytes())
}
Output:

0a 01 01 02 00 00 00

func (*WriteChain) Bool

func (c *WriteChain) Bool(b bool) *WriteChain

Bool encodes a boolean into the write, transforming true into uint8(1) and false into uint8(0).

func (*WriteChain) Byte

func (c *WriteChain) Byte(b byte) *WriteChain

Byte encodes a byte into the writer.

func (*WriteChain) ByteSlice

func (c *WriteChain) ByteSlice(b []byte) *WriteChain

ByteSlice writes a raw byte slice into the WriteChain

func (*WriteChain) Complex128

func (c *WriteChain) Complex128(com complex128) *WriteChain

Complex128 encodes a complex128 into the writer.

func (*WriteChain) Complex64

func (c *WriteChain) Complex64(com complex64) *WriteChain

Complex64 encodes a complex64 into the writer.

func (*WriteChain) End

func (c *WriteChain) End() (int, error)

End finishes writing to the Writer, and returns the amount of written bytes and any eventual error occured during the WriteChain lifetime. It also clears out the written bytes and the error, making WriteChain usable as defined by the user initially again.

func (*WriteChain) Float32

func (c *WriteChain) Float32(f float32) *WriteChain

Float32 encodes a float32 into the writer.

func (*WriteChain) Float64

func (c *WriteChain) Float64(f float64) *WriteChain

Float64 encodes a float64 into the writer.

func (*WriteChain) Int16

func (c *WriteChain) Int16(i int16) *WriteChain

Int16 encodes an int16 into the writer.

func (*WriteChain) Int32

func (c *WriteChain) Int32(i int32) *WriteChain

Int32 encodes an int32 into the writer.

func (*WriteChain) Int64

func (c *WriteChain) Int64(i int64) *WriteChain

Int64 encodes an int64 into the writer.

func (*WriteChain) Int8

func (c *WriteChain) Int8(i int8) *WriteChain

Int8 encodes an int8 into the writer.

func (*WriteChain) Rune

func (c *WriteChain) Rune(r rune) *WriteChain

Rune encodes a rune into the writer.

func (*WriteChain) String

func (c *WriteChain) String(s string) *WriteChain

String writes a string to the write chain.

func (*WriteChain) Uint16

func (c *WriteChain) Uint16(u uint16) *WriteChain

Uint16 encodes an uint16 into the writer.

func (*WriteChain) Uint32

func (c *WriteChain) Uint32(u uint32) *WriteChain

Uint32 encodes an uint32 into the writer.

func (*WriteChain) Uint64

func (c *WriteChain) Uint64(u uint64) *WriteChain

Uint64 encodes an uint64 into the writer.

func (*WriteChain) Uint8

func (c *WriteChain) Uint8(u uint8) *WriteChain

Uint8 encodes an uint8 into the writer.

func (*WriteChain) Write

func (c *WriteChain) Write(p []byte) (int, error)

Write is a simple wrapper around c.Writer.Write. The WriteChain's internal written counter will be incremented and the error will be set if any, so that c.End returns the correct result.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL