Commit 48ada1da authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent bbf27ce0
out.mem
out.cpu
mem.out
cpu.out
# files after go test -c
*.test
// TODO copyright/license // TODO copyright/license
// Package xfmt provide addons to std fmt and strconv package with focus on // Package xfmt provide addons to std fmt and strconv packages with focus on
// formatting text without allocations. // formatting text without allocations.
package xfmt package xfmt
...@@ -8,6 +8,8 @@ import ( ...@@ -8,6 +8,8 @@ import (
"encoding/hex" "encoding/hex"
"../xslice" "../xslice"
"lab.nexedi.com/kirr/go123/mem"
) )
const ( const (
...@@ -21,6 +23,15 @@ type Stringer interface { ...@@ -21,6 +23,15 @@ type Stringer interface {
XFmtString(b []byte) []byte XFmtString(b []byte) []byte
} }
// Buffer provides syntactic sugar for formatting mimicking fmt.Printf style
// XXX combine with bytes.Buffer ?
type Buffer []byte
// Reset empties the buffer keeping underlying storage for future formattings
func (b *Buffer) Reset() {
*b = (*b)[:0]
}
// Append appends to b formatted x // Append appends to b formatted x
// //
// NOTE sadly since x is interface it makes real value substituted to it // NOTE sadly since x is interface it makes real value substituted to it
...@@ -32,6 +43,13 @@ func Append(b []byte, x Stringer) []byte { ...@@ -32,6 +43,13 @@ func Append(b []byte, x Stringer) []byte {
return x.XFmtString(b) return x.XFmtString(b)
} }
// V, similarly to %v, adds x formatted by default rules
// XXX -> v(interface {}) ?
func (b *Buffer) V(x Stringer) *Buffer {
*b = Append(*b, x)
return b
}
// AppendHex appends to b hex representation of x // AppendHex appends to b hex representation of x
func AppendHex(b []byte, x []byte) []byte { func AppendHex(b []byte, x []byte) []byte {
lx := hex.EncodedLen(len(x)) lx := hex.EncodedLen(len(x))
...@@ -41,8 +59,21 @@ func AppendHex(b []byte, x []byte) []byte { ...@@ -41,8 +59,21 @@ func AppendHex(b []byte, x []byte) []byte {
return b return b
} }
// AppendHex64 appends to b x formateed 16-character hex string // X, similarly to %x, adds hex representation of x
func AppendHex64(b []byte, x uint64) []byte { func (b *Buffer) X(x []byte) *Buffer {
*b = AppendHex(*b, x)
return b
}
// XXX do we need it here ?
func (b *Buffer) Xs(x string) *Buffer {
return b.X(mem.Bytes(x))
}
// TODO XX = %X
// AppendHex016 appends to b x formatted 16-character hex string
func AppendHex016(b []byte, x uint64) []byte {
// like sprintf("%016x") but faster and less allocations // like sprintf("%016x") but faster and less allocations
l := len(b) l := len(b)
b = xslice.Grow(b, 16) b = xslice.Grow(b, 16)
...@@ -53,3 +84,9 @@ func AppendHex64(b []byte, x uint64) []byte { ...@@ -53,3 +84,9 @@ func AppendHex64(b []byte, x uint64) []byte {
} }
return b return b
} }
// X016, similarly to %016x, adds hex representation of uint64 x
func (b *Buffer) X016(x uint64) *Buffer {
*b = AppendHex016(*b, x)
return b
}
// TODO copyright/license
package xfmt
import (
"fmt"
"reflect"
"testing"
)
// verify formatting result is the same in between std fmt and xfmt
func TestXFmt(t *testing.T) {
testv := []struct {format, xformatMeth string; value interface{}} {
{"%x", "X", []byte("hello")},
{"%x", "Xs", "world"},
{"%016x", "X016", uint64(124)},
}
buf := &Buffer{}
xbuf := reflect.ValueOf(buf)
for _, tt := range testv {
// result via fmt
resFmt := fmt.Sprintf(tt.format, tt.value)
// result via xfmt (via reflect.Call)
buf.Reset()
xmeth := xbuf.MethodByName(tt.xformatMeth)
if !xmeth.IsValid() {
t.Errorf(".%v: no such method", tt.xformatMeth)
continue
}
xargv := []reflect.Value{reflect.ValueOf(tt.value)}
xretv := []reflect.Value{}
callOk := false
func () {
defer func() {
if r := recover(); r != nil {
t.Errorf("%v: panic: %v", tt, r)
}
}()
xretv = xmeth.Call(xargv)
callOk = true
}()
if !callOk {
continue
}
// check all formatters return pointer to the same buf
// (this way it is handy to do .S("hello ") .X016(123) .V(zzz) ...
if !(len(xretv) == 1 && xretv[0].Interface() == buf) {
t.Errorf(".%v: returned %#v ; want %#v", tt.xformatMeth, xretv[0].Interface(), buf)
continue
}
resXFmt := string(*buf)
// results must be the same
if resFmt != resXFmt {
t.Errorf(".%v(%v) -> %q != printf(%q) -> %q",
tt.xformatMeth, tt.value, resXFmt, tt.format, resFmt)
}
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment