Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
N
neoppod
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Levin Zimmermann
neoppod
Commits
b1f25716
Commit
b1f25716
authored
Mar 27, 2017
by
Kirill Smelkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
.
parent
1380e37e
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
120 additions
and
53 deletions
+120
-53
t/neo/xcommon/xfmt/fmt.go
t/neo/xcommon/xfmt/fmt.go
+27
-3
t/neo/xcommon/xfmt/fmt_test.go
t/neo/xcommon/xfmt/fmt_test.go
+63
-26
t/neo/xcommon/xfmt/python.go
t/neo/xcommon/xfmt/python.go
+25
-20
t/neo/xcommon/xfmt/python_test.go
t/neo/xcommon/xfmt/python_test.go
+5
-4
No files found.
t/neo/xcommon/xfmt/fmt.go
View file @
b1f25716
// TODO copyright/license
// Copyright (C) 2017 Nexedi SA and Contributors.
// Kirill Smelkov <kirr@nexedi.com>
//
// This program is free software: you can Use, Study, Modify and Redistribute
// it under the terms of the GNU General Public License version 2, or (at your
// option) any later version, as published by the Free Software Foundation.
//
// This program is distributed WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// See COPYING file for full licensing terms.
// Package xfmt provide addons to std fmt and strconv packages with focus on
// Package xfmt provide
s
addons to std fmt and strconv packages with focus on
// formatting text without allocations.
// formatting text without allocations.
//
// For example if in fmt speak you have
//
// s := fmt.Sprintf("hello %q %d %x", "world", 1, []byte("data"))
//
// xfmt analog would be
//
// xbuf := xfmt.Buffer{}
// xbuf .S("hello ") .Qs("world") .C(' ') .D(1) .C(' ') .Xb([]byte("data"))
// s := xbuf.Bytes()
//
// xfmt.Buffer can be reused several times via Buffer.Reset() .
package
xfmt
package
xfmt
import
(
import
(
...
@@ -76,7 +98,7 @@ func (b *Buffer) Cb(c byte) *Buffer {
...
@@ -76,7 +98,7 @@ func (b *Buffer) Cb(c byte) *Buffer {
}
}
// AppendRune appends to b
e
UTF-8 encoding of r
// AppendRune appends to b UTF-8 encoding of r
func
AppendRune
(
b
[]
byte
,
r
rune
)
[]
byte
{
func
AppendRune
(
b
[]
byte
,
r
rune
)
[]
byte
{
l
:=
len
(
b
)
l
:=
len
(
b
)
b
=
xslice
.
Grow
(
b
,
utf8
.
UTFMax
)
b
=
xslice
.
Grow
(
b
,
utf8
.
UTFMax
)
...
@@ -142,3 +164,5 @@ func (b *Buffer) X016(x uint64) *Buffer {
...
@@ -142,3 +164,5 @@ func (b *Buffer) X016(x uint64) *Buffer {
*
b
=
AppendHex016
(
*
b
,
x
)
*
b
=
AppendHex016
(
*
b
,
x
)
return
b
return
b
}
}
// TODO Qs Qb ?
t/neo/xcommon/xfmt/fmt_test.go
View file @
b1f25716
...
@@ -8,29 +8,30 @@ import (
...
@@ -8,29 +8,30 @@ import (
"testing"
"testing"
)
)
var
testv
=
[]
struct
{
format
,
xformatMeth
string
;
value
interface
{}}
{
{
"%c"
,
"Cb"
,
byte
(
'A'
)},
{
"%c"
,
"C"
,
rune
(
-
1
)},
{
"%c"
,
"C"
,
'B'
},
// 1-byte encoded
{
"%c"
,
"C"
,
'и'
},
// 2-bytes encoded
{
"%c"
,
"C"
,
'\u20ac'
},
// 3-bytes encoded
{
"%c"
,
"C"
,
'\U00010001'
},
// 4-bytes encoded
// TODO %q qb qr qs qcb qc
{
"%s"
,
"S"
,
"hello"
},
{
"%s"
,
"Sb"
,
[]
byte
(
"world"
)},
{
"%x"
,
"Xb"
,
[]
byte
(
"hexstring"
)},
{
"%x"
,
"Xs"
,
"stringhex"
},
{
"%d"
,
"D"
,
12765
},
{
"%x"
,
"X"
,
12789
},
{
"%016x"
,
"X016"
,
uint64
(
124
)},
// TODO .V
}
// verify formatting result is the same in between std fmt and xfmt
// verify formatting result is the same in between std fmt and xfmt
func
TestXFmt
(
t
*
testing
.
T
)
{
func
TestXFmt
(
t
*
testing
.
T
)
{
testv
:=
[]
struct
{
format
,
xformatMeth
string
;
value
interface
{}}
{
{
"%c"
,
"Cb"
,
byte
(
'A'
)},
{
"%c"
,
"C"
,
rune
(
-
1
)},
{
"%c"
,
"C"
,
'B'
},
// 1-byte encoded
{
"%c"
,
"C"
,
'и'
},
// 2-bytes encoded
{
"%c"
,
"C"
,
'\u20ac'
},
// 3-bytes encoded
{
"%c"
,
"C"
,
'\U00010001'
},
// 4-bytes encoded
// TODO %q qb qr qs qcb qc
{
"%s"
,
"S"
,
"hello"
},
{
"%s"
,
"Sb"
,
[]
byte
(
"world"
)},
{
"%x"
,
"Xb"
,
[]
byte
(
"hexstring"
)},
{
"%x"
,
"Xs"
,
"stringhex"
},
{
"%d"
,
"D"
,
12765
},
{
"%x"
,
"X"
,
12789
},
{
"%016x"
,
"X016"
,
uint64
(
124
)},
// TODO .V
}
buf
:=
&
Buffer
{}
buf
:=
&
Buffer
{}
xbuf
:=
reflect
.
ValueOf
(
buf
)
xbuf
:=
reflect
.
ValueOf
(
buf
)
...
@@ -81,10 +82,46 @@ func TestXFmt(t *testing.T) {
...
@@ -81,10 +82,46 @@ func TestXFmt(t *testing.T) {
}
}
}
}
func
BenchmarkFmt
(
t
*
testing
.
T
)
{
func
BenchmarkXFmt
(
b
*
testing
.
B
)
{
// TODO
buf
:=
&
Buffer
{}
}
func
BenchmarkXFmt
(
t
*
testing
.
T
)
{
for
_
,
tt
:=
range
testv
{
// TODO
b
.
Run
(
fmt
.
Sprintf
(
"%s(%#v)"
,
tt
.
format
,
tt
.
value
),
func
(
b
*
testing
.
B
)
{
for
i
:=
0
;
i
<
b
.
N
;
i
++
{
fmt
.
Sprintf
(
tt
.
format
,
tt
.
value
)
}
})
// construct methProxy for natively calling (not via reflect) method associated with tt.xformatMeth
// (calling via reflect allocates a lot and is slow)
// NOTE because of proxies the call is a bit slower than e.g. directly calling buf.S("...")
var
methProxy
func
(
buf
*
Buffer
,
v
interface
{})
xmeth
,
ok
:=
reflect
.
TypeOf
(
buf
)
.
MethodByName
(
tt
.
xformatMeth
)
if
!
ok
{
b
.
Errorf
(
".%v: no such method"
,
tt
.
xformatMeth
)
continue
}
// XXX a bit ugly -> use code generation instead?
meth
:=
xmeth
.
Func
.
Interface
()
switch
tt
.
value
.
(
type
)
{
case
byte
:
methProxy
=
func
(
buf
*
Buffer
,
v
interface
{})
{
meth
.
(
func
(
*
Buffer
,
byte
)
*
Buffer
)(
buf
,
v
.
(
byte
))
}
case
rune
:
methProxy
=
func
(
buf
*
Buffer
,
v
interface
{})
{
meth
.
(
func
(
*
Buffer
,
rune
)
*
Buffer
)(
buf
,
v
.
(
rune
))
}
case
string
:
methProxy
=
func
(
buf
*
Buffer
,
v
interface
{})
{
meth
.
(
func
(
*
Buffer
,
string
)
*
Buffer
)(
buf
,
v
.
(
string
))
}
case
[]
byte
:
methProxy
=
func
(
buf
*
Buffer
,
v
interface
{})
{
meth
.
(
func
(
*
Buffer
,
[]
byte
)
*
Buffer
)(
buf
,
v
.
([]
byte
))
}
case
int
:
methProxy
=
func
(
buf
*
Buffer
,
v
interface
{})
{
meth
.
(
func
(
*
Buffer
,
int
)
*
Buffer
)(
buf
,
v
.
(
int
))
}
case
uint64
:
methProxy
=
func
(
buf
*
Buffer
,
v
interface
{})
{
meth
.
(
func
(
*
Buffer
,
uint64
)
*
Buffer
)(
buf
,
v
.
(
uint64
))
}
default
:
b
.
Fatalf
(
"TODO add support for %T"
,
tt
.
value
)
}
b
.
Run
(
fmt
.
Sprintf
(
".%s(%#v)"
,
tt
.
xformatMeth
,
tt
.
value
),
func
(
b
*
testing
.
B
)
{
for
i
:=
0
;
i
<
b
.
N
;
i
++
{
buf
.
Reset
()
methProxy
(
buf
,
tt
.
value
)
}
})
}
}
}
t/neo/xcommon/xfmt/python.go
View file @
b1f25716
package
x
mf
t
package
x
fm
t
import
(
import
(
"bytes"
"bytes"
...
@@ -9,20 +9,25 @@ import (
...
@@ -9,20 +9,25 @@ import (
)
)
const
hex
=
"0123456789abcdef"
// TODO remove - not needed ?
// // pyQuote quotes string the way python repr(str) would do
// pyQuote quotes string the way python repr(str) would do
// func pyQuote(s string) string {
func
pyQuote
(
s
string
)
string
{
// out := pyQuoteBytes(mem.Bytes(s))
out
:=
pyQuoteBytes
(
mem
.
Bytes
(
s
))
// return mem.String(out)
return
mem
.
String
(
out
)
// }
}
//
// func pyQuoteBytes(b []byte) []byte {
func
pyQuoteBytes
(
b
[]
byte
)
[]
byte
{
// buf := make([]byte, 0, (len(b) + 2) /* to reduce allocations when quoting */ * 2)
buf
:=
make
([]
byte
,
0
,
(
len
(
b
)
+
2
)
/* to reduce allocations when quoting */
*
2
)
// return pyAppendQuoteBytes(buf, b)
return
pyAppendQuoteBytes
(
buf
,
b
)
// }
// AppendQuotePy appends to buf Python quoting of s
func
AppendQuotePy
(
buf
[]
byte
,
s
string
)
[]
byte
{
return
AppendQuotePyBytes
(
buf
,
mem
.
Bytes
(
s
))
}
}
func
pyAppendQuoteBytes
(
buf
,
b
[]
byte
)
[]
byte
{
// AppendQuotePyBytes appends to buf Python quoting of b
func
AppendQuotePyBytes
(
buf
,
b
[]
byte
)
[]
byte
{
// smartquotes: choose ' or " as quoting character
// smartquotes: choose ' or " as quoting character
// https://github.com/python/cpython/blob/v2.7.13-116-g1aa1803b3d/Objects/stringobject.c#L947
// https://github.com/python/cpython/blob/v2.7.13-116-g1aa1803b3d/Objects/stringobject.c#L947
quote
:=
byte
(
'\'
'
)
quote
:=
byte
(
'\'
'
)
...
@@ -38,7 +43,7 @@ func pyAppendQuoteBytes(buf, b []byte) []byte {
...
@@ -38,7 +43,7 @@ func pyAppendQuoteBytes(buf, b []byte) []byte {
switch
r
{
switch
r
{
case
utf8
.
RuneError
:
case
utf8
.
RuneError
:
buf
=
append
(
buf
,
'\\'
,
'x'
,
hex
[
b
[
0
]
>>
4
],
hex
[
b
[
0
]
&
0xf
])
buf
=
append
(
buf
,
'\\'
,
'x'
,
hex
digits
[
b
[
0
]
>>
4
],
hexdigits
[
b
[
0
]
&
0xf
])
case
'\\'
,
rune
(
quote
)
:
case
'\\'
,
rune
(
quote
)
:
buf
=
append
(
buf
,
'\\'
,
byte
(
r
))
buf
=
append
(
buf
,
'\\'
,
byte
(
r
))
case
rune
(
noquote
)
:
case
rune
(
noquote
)
:
...
@@ -57,7 +62,7 @@ func pyAppendQuoteBytes(buf, b []byte) []byte {
...
@@ -57,7 +62,7 @@ func pyAppendQuoteBytes(buf, b []byte) []byte {
switch
{
switch
{
case
r
<
' '
:
case
r
<
' '
:
// we already converted to \<letter> what python represents as such above
// we already converted to \<letter> what python represents as such above
buf
=
append
(
buf
,
'\\'
,
'x'
,
hex
[
b
[
0
]
>>
4
],
hex
[
b
[
0
]
&
0xf
])
buf
=
append
(
buf
,
'\\'
,
'x'
,
hex
digits
[
b
[
0
]
>>
4
],
hexdigits
[
b
[
0
]
&
0xf
])
case
r
<
utf8
.
RuneSelf
/* RuneSelf itself is not printable */
-
1
:
case
r
<
utf8
.
RuneSelf
/* RuneSelf itself is not printable */
-
1
:
// we already escaped all < RuneSelf runes
// we already escaped all < RuneSelf runes
...
@@ -70,7 +75,7 @@ func pyAppendQuoteBytes(buf, b []byte) []byte {
...
@@ -70,7 +75,7 @@ func pyAppendQuoteBytes(buf, b []byte) []byte {
default
:
default
:
// everything else goes in numeric byte escapes
// everything else goes in numeric byte escapes
for
i
:=
0
;
i
<
size
;
i
++
{
for
i
:=
0
;
i
<
size
;
i
++
{
buf
=
append
(
buf
,
'\\'
,
'x'
,
hex
[
b
[
i
]
>>
4
],
hex
[
b
[
i
]
&
0xf
])
buf
=
append
(
buf
,
'\\'
,
'x'
,
hex
digits
[
b
[
i
]
>>
4
],
hexdigits
[
b
[
i
]
&
0xf
])
}
}
}
}
}
}
...
@@ -85,12 +90,12 @@ func pyAppendQuoteBytes(buf, b []byte) []byte {
...
@@ -85,12 +90,12 @@ func pyAppendQuoteBytes(buf, b []byte) []byte {
// Qpy appends string quoted as Python would do
// Qpy appends string quoted as Python would do
func
(
b
*
Buffer
)
Qpy
(
s
string
)
*
Buffer
{
func
(
b
*
Buffer
)
Qpy
(
s
string
)
*
Buffer
{
*
b
=
...
// TODO
*
b
=
AppendQuotePy
(
*
b
,
s
)
return
b
return
b
}
}
// Q
pyb
appends []byte quoted as Python would do
// Q
bpy
appends []byte quoted as Python would do
func
(
b
*
Buffer
)
Q
pyb
(
x
[]
byte
)
*
Buffer
{
func
(
b
*
Buffer
)
Q
bpy
(
x
[]
byte
)
*
Buffer
{
*
b
=
...
// TODO
*
b
=
AppendQuotePyBytes
(
*
b
,
x
)
return
b
return
b
}
}
t/neo/xcommon/xfmt/python_test.go
View file @
b1f25716
...
@@ -2,8 +2,6 @@ package xfmt
...
@@ -2,8 +2,6 @@ package xfmt
import
(
import
(
"testing"
"testing"
"lab.nexedi.com/kirr/go123/mem"
)
)
// byterange returns []byte with element [start,stop)
// byterange returns []byte with element [start,stop)
...
@@ -45,8 +43,11 @@ var pyQuoteTestv = []struct {in, quoted string} {
...
@@ -45,8 +43,11 @@ var pyQuoteTestv = []struct {in, quoted string} {
}
}
func
TestPyQuote
(
t
*
testing
.
T
)
{
func
TestPyQuote
(
t
*
testing
.
T
)
{
buf
:=
[]
byte
{}
for
_
,
tt
:=
range
pyQuoteTestv
{
for
_
,
tt
:=
range
pyQuoteTestv
{
quoted
:=
pyQuote
(
tt
.
in
)
buf
=
buf
[
:
0
]
buf
=
AppendQuotePy
(
buf
,
tt
.
in
)
quoted
:=
string
(
buf
)
if
quoted
!=
tt
.
quoted
{
if
quoted
!=
tt
.
quoted
{
t
.
Errorf
(
"pyQuote(%q) ->
\n
have: %s
\n
want: %s"
,
tt
.
in
,
quoted
,
tt
.
quoted
)
t
.
Errorf
(
"pyQuote(%q) ->
\n
have: %s
\n
want: %s"
,
tt
.
in
,
quoted
,
tt
.
quoted
)
}
}
...
@@ -59,7 +60,7 @@ func BenchmarkPyQuote(b *testing.B) {
...
@@ -59,7 +60,7 @@ func BenchmarkPyQuote(b *testing.B) {
for
i
:=
0
;
i
<
b
.
N
;
i
++
{
for
i
:=
0
;
i
<
b
.
N
;
i
++
{
for
_
,
tt
:=
range
pyQuoteTestv
{
for
_
,
tt
:=
range
pyQuoteTestv
{
buf
=
buf
[
:
0
]
buf
=
buf
[
:
0
]
buf
=
pyAppendQuoteBytes
(
buf
,
mem
.
Bytes
(
tt
.
in
)
)
buf
=
AppendQuotePy
(
buf
,
tt
.
in
)
}
}
}
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment