Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
go123
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
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
go123
Commits
66a27966
Commit
66a27966
authored
Dec 13, 2016
by
Kirill Smelkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
~gofmt
parent
ad78da1b
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
325 additions
and
326 deletions
+325
-326
exc/error.go
exc/error.go
+89
-89
exc/error_test.go
exc/error_test.go
+76
-77
mem/mem.go
mem/mem.go
+13
-13
mem/mem_test.go
mem/mem_test.go
+12
-12
myname/myname.go
myname/myname.go
+27
-27
myname/myname_test.go
myname/myname_test.go
+9
-9
xerr/xerr.go
xerr/xerr.go
+9
-9
xruntime/xruntime.go
xruntime/xruntime.go
+26
-26
xstrings/xstrings.go
xstrings/xstrings.go
+18
-18
xstrings/xstrings_test.go
xstrings/xstrings_test.go
+46
-46
No files found.
exc/error.go
View file @
66a27966
...
...
@@ -14,56 +14,56 @@
package
exc
import
(
"fmt"
"strings"
"fmt"
"strings"
"lab.nexedi.com/kirr/go123/myname"
"lab.nexedi.com/kirr/go123/xruntime"
"lab.nexedi.com/kirr/go123/myname"
"lab.nexedi.com/kirr/go123/xruntime"
)
// error type which is raised by Raise(arg)
type
Error
struct
{
arg
interface
{}
link
*
Error
// chain of linked Error(s) - see e.g. Context()
arg
interface
{}
link
*
Error
// chain of linked Error(s) - see e.g. Context()
}
func
(
e
*
Error
)
Error
()
string
{
msgv
:=
[]
string
{}
msg
:=
""
for
e
!=
nil
{
// TODO(go1.7) -> runtime.Frame (see xruntime.Traceback())
if
f
,
ok
:=
e
.
arg
.
(
xruntime
.
Frame
);
ok
{
//msg = f.Function
//msg = fmt.Sprintf("%s (%s:%d)", f.Function, f.File, f.Line)
msg
=
strings
.
TrimPrefix
(
f
.
Name
(),
_errorpkgdot
)
// XXX -> better prettyfunc
}
else
{
msg
=
fmt
.
Sprint
(
e
.
arg
)
}
msgv
=
append
(
msgv
,
msg
)
e
=
e
.
link
}
return
strings
.
Join
(
msgv
,
": "
)
msgv
:=
[]
string
{}
msg
:=
""
for
e
!=
nil
{
// TODO(go1.7) -> runtime.Frame (see xruntime.Traceback())
if
f
,
ok
:=
e
.
arg
.
(
xruntime
.
Frame
);
ok
{
//msg = f.Function
//msg = fmt.Sprintf("%s (%s:%d)", f.Function, f.File, f.Line)
msg
=
strings
.
TrimPrefix
(
f
.
Name
(),
_errorpkgdot
)
// XXX -> better prettyfunc
}
else
{
msg
=
fmt
.
Sprint
(
e
.
arg
)
}
msgv
=
append
(
msgv
,
msg
)
e
=
e
.
link
}
return
strings
.
Join
(
msgv
,
": "
)
}
// turn any value into Error
// if v is already Error - it stays the same
// otherwise new Error is created
func
Aserror
(
v
interface
{})
*
Error
{
if
e
,
ok
:=
v
.
(
*
Error
);
ok
{
return
e
}
return
&
Error
{
v
,
nil
}
if
e
,
ok
:=
v
.
(
*
Error
);
ok
{
return
e
}
return
&
Error
{
v
,
nil
}
}
// raise error to upper level
func
Raise
(
arg
interface
{})
{
panic
(
Aserror
(
arg
))
panic
(
Aserror
(
arg
))
}
// raise formatted string
func
Raisef
(
format
string
,
a
...
interface
{})
{
panic
(
Aserror
(
fmt
.
Sprintf
(
format
,
a
...
)))
panic
(
Aserror
(
fmt
.
Sprintf
(
format
,
a
...
)))
}
// raise if err != nil
...
...
@@ -72,32 +72,32 @@ func Raisef(format string, a ...interface{}) {
// err = obj
// err != nil is true
func
Raiseif
(
err
error
)
{
//if err != nil && !reflect.ValueOf(err).IsNil() {
if
err
!=
nil
{
panic
(
Aserror
(
err
))
}
//if err != nil && !reflect.ValueOf(err).IsNil() {
if
err
!=
nil
{
panic
(
Aserror
(
err
))
}
}
// checks recovered value to be of *Error
// if there is non-Error error - repanic it
// otherwise return Error either nil (no panic), or actual value
func
_errcatch
(
r
interface
{})
*
Error
{
e
,
_
:=
r
.
(
*
Error
)
if
e
==
nil
&&
r
!=
nil
{
panic
(
r
)
}
return
e
e
,
_
:=
r
.
(
*
Error
)
if
e
==
nil
&&
r
!=
nil
{
panic
(
r
)
}
return
e
}
// catch error and call f(e) if it was caught.
// must be called under defer
func
Catch
(
f
func
(
e
*
Error
))
{
e
:=
_errcatch
(
recover
())
if
e
==
nil
{
return
}
e
:=
_errcatch
(
recover
())
if
e
==
nil
{
return
}
f
(
e
)
f
(
e
)
}
// be notified when error unwinding is being happening.
...
...
@@ -105,15 +105,15 @@ func Catch(f func(e *Error)) {
// see also: Context()
// must be called under defer
func
Onunwind
(
f
func
(
e
*
Error
)
*
Error
)
{
// cannot do Catch(...)
// as recover() works only in first-level called functions
e
:=
_errcatch
(
recover
())
if
e
==
nil
{
return
}
e
=
f
(
e
)
panic
(
e
)
// cannot do Catch(...)
// as recover() works only in first-level called functions
e
:=
_errcatch
(
recover
())
if
e
==
nil
{
return
}
e
=
f
(
e
)
panic
(
e
)
}
// provide error context to automatically add on unwinding.
...
...
@@ -121,59 +121,59 @@ func Onunwind(f func(e *Error) *Error) {
// call result is added to raised error as "prefix" context
// must be called under defer
func
Context
(
f
func
()
interface
{})
{
e
:=
_errcatch
(
recover
())
if
e
==
nil
{
return
}
e
:=
_errcatch
(
recover
())
if
e
==
nil
{
return
}
arg
:=
f
()
panic
(
Addcontext
(
e
,
arg
))
arg
:=
f
()
panic
(
Addcontext
(
e
,
arg
))
}
// add "prefix" context to error
func
Addcontext
(
e
*
Error
,
arg
interface
{})
*
Error
{
return
&
Error
{
arg
,
e
}
return
&
Error
{
arg
,
e
}
}
var
(
_errorpkgname
string
// package name under which error.go lives
_errorpkgdot
string
// errorpkg.
_errorraise
string
// errorpkg.Raise
_errorpkgname
string
// package name under which error.go lives
_errorpkgdot
string
// errorpkg.
_errorraise
string
// errorpkg.Raise
)
func
init
()
{
_errorpkgname
=
myname
.
Pkg
()
_errorpkgdot
=
_errorpkgname
+
"."
_errorraise
=
_errorpkgname
+
".Raise"
_errorpkgname
=
myname
.
Pkg
()
_errorpkgdot
=
_errorpkgname
+
"."
_errorraise
=
_errorpkgname
+
".Raise"
}
// add calling context to error.
// Add calling function names as error context up-to topfunc not including.
// see also: Addcontext()
func
Addcallingcontext
(
topfunc
string
,
e
*
Error
)
*
Error
{
seenraise
:=
false
for
_
,
f
:=
range
xruntime
.
Traceback
(
2
)
{
// do not show anything after raise*()
if
!
seenraise
&&
strings
.
HasPrefix
(
f
.
Name
(),
_errorraise
)
{
seenraise
=
true
continue
}
if
!
seenraise
{
continue
}
// do not go beyond topfunc
if
topfunc
!=
""
&&
f
.
Name
()
==
topfunc
{
break
}
// skip intermediates
if
strings
.
HasSuffix
(
f
.
Name
(),
"_"
)
{
// XXX -> better skipfunc
continue
}
e
=
&
Error
{
f
,
e
}
}
return
e
seenraise
:=
false
for
_
,
f
:=
range
xruntime
.
Traceback
(
2
)
{
// do not show anything after raise*()
if
!
seenraise
&&
strings
.
HasPrefix
(
f
.
Name
(),
_errorraise
)
{
seenraise
=
true
continue
}
if
!
seenraise
{
continue
}
// do not go beyond topfunc
if
topfunc
!=
""
&&
f
.
Name
()
==
topfunc
{
break
}
// skip intermediates
if
strings
.
HasSuffix
(
f
.
Name
(),
"_"
)
{
// XXX -> better skipfunc
continue
}
e
=
&
Error
{
f
,
e
}
}
return
e
}
exc/error_test.go
View file @
66a27966
...
...
@@ -13,129 +13,128 @@
package
exc
import
(
"errors"
"testing"
"errors"
"testing"
"lab.nexedi.com/kirr/go123/myname"
"lab.nexedi.com/kirr/go123/myname"
)
func
do_raise1
()
{
Raise
(
1
)
Raise
(
1
)
}
func
TestErrRaiseCatch
(
t
*
testing
.
T
)
{
defer
Catch
(
func
(
e
*
Error
)
{
if
!
(
e
.
arg
==
1
&&
e
.
link
==
nil
)
{
t
.
Fatalf
(
"error caught but unexpected: %#v ; want {1, nil}"
,
e
)
}
})
do_raise1
()
t
.
Fatal
(
"error not caught"
)
defer
Catch
(
func
(
e
*
Error
)
{
if
!
(
e
.
arg
==
1
&&
e
.
link
==
nil
)
{
t
.
Fatalf
(
"error caught but unexpected: %#v ; want {1, nil}"
,
e
)
}
})
do_raise1
()
t
.
Fatal
(
"error not caught"
)
}
// verify err chain has .arg(s) as expected
func
verifyErrChain
(
t
*
testing
.
T
,
e
*
Error
,
argv
...
interface
{})
{
i
:=
0
for
;
e
!=
nil
;
i
,
e
=
i
+
1
,
e
.
link
{
if
i
>=
len
(
argv
)
{
t
.
Fatal
(
"too long error chain"
)
}
if
e
.
arg
!=
argv
[
i
]
{
t
.
Fatalf
(
"error caught but unexpected %vth arg: %v ; want %v"
,
i
,
e
.
arg
,
argv
[
i
])
}
}
if
i
<
len
(
argv
)
{
t
.
Fatal
(
"too small error chain"
)
}
i
:=
0
for
;
e
!=
nil
;
i
,
e
=
i
+
1
,
e
.
link
{
if
i
>=
len
(
argv
)
{
t
.
Fatal
(
"too long error chain"
)
}
if
e
.
arg
!=
argv
[
i
]
{
t
.
Fatalf
(
"error caught but unexpected %vth arg: %v ; want %v"
,
i
,
e
.
arg
,
argv
[
i
])
}
}
if
i
<
len
(
argv
)
{
t
.
Fatal
(
"too small error chain"
)
}
}
func
do_onunwind1
(
t
*
testing
.
T
)
{
defer
Onunwind
(
func
(
e
*
Error
)
*
Error
{
t
.
Fatal
(
"on unwind called without raise"
)
return
nil
})
defer
Onunwind
(
func
(
e
*
Error
)
*
Error
{
t
.
Fatal
(
"on unwind called without raise"
)
return
nil
})
}
func
do_onunwind2
()
{
defer
Onunwind
(
func
(
e
*
Error
)
*
Error
{
return
&
Error
{
2
,
e
}
})
do_raise1
()
defer
Onunwind
(
func
(
e
*
Error
)
*
Error
{
return
&
Error
{
2
,
e
}
})
do_raise1
()
}
func
TestErrOnUnwind
(
t
*
testing
.
T
)
{
defer
Catch
(
func
(
e
*
Error
)
{
verifyErrChain
(
t
,
e
,
2
,
1
)
})
do_onunwind1
(
t
)
do_onunwind2
()
t
.
Fatal
(
"error not caught"
)
defer
Catch
(
func
(
e
*
Error
)
{
verifyErrChain
(
t
,
e
,
2
,
1
)
})
do_onunwind1
(
t
)
do_onunwind2
()
t
.
Fatal
(
"error not caught"
)
}
func
do_context1
(
t
*
testing
.
T
)
{
defer
Context
(
func
()
interface
{}
{
t
.
Fatal
(
"on context called without raise"
)
return
nil
})
defer
Context
(
func
()
interface
{}
{
t
.
Fatal
(
"on context called without raise"
)
return
nil
})
}
func
do_context2
()
{
defer
Context
(
func
()
interface
{}
{
return
3
})
do_raise1
()
defer
Context
(
func
()
interface
{}
{
return
3
})
do_raise1
()
}
func
TestErrContext
(
t
*
testing
.
T
)
{
defer
Catch
(
func
(
e
*
Error
)
{
verifyErrChain
(
t
,
e
,
3
,
1
)
})
do_context1
(
t
)
do_context2
()
t
.
Fatal
(
"error not caught"
)
defer
Catch
(
func
(
e
*
Error
)
{
verifyErrChain
(
t
,
e
,
3
,
1
)
})
do_context1
(
t
)
do_context2
()
t
.
Fatal
(
"error not caught"
)
}
func
do_raise11
()
{
do_raise1
()
do_raise1
()
}
func
do_raise3if
()
{
Raiseif
(
errors
.
New
(
"3"
))
Raiseif
(
errors
.
New
(
"3"
))
}
func
do_raise3if1
()
{
do_raise3if
()
do_raise3if
()
}
func
do_raise4f
()
{
Raisef
(
"%d"
,
4
)
Raisef
(
"%d"
,
4
)
}
func
do_raise4f1
()
{
do_raise4f
()
do_raise4f
()
}
func
TestErrAddCallingContext
(
t
*
testing
.
T
)
{
var
tests
=
[]
struct
{
f
func
();
wanterrcontext
string
}
{
{
do_raise11
,
"do_raise11: do_raise1: 1"
},
{
do_raise3if1
,
"do_raise3if1: do_raise3if: 3"
},
{
do_raise4f1
,
"do_raise4f1: do_raise4f: 4"
},
}
for
_
,
tt
:=
range
tests
{
func
()
{
myfunc
:=
myname
.
Func
()
defer
Catch
(
func
(
e
*
Error
)
{
e
=
Addcallingcontext
(
myfunc
,
e
)
msg
:=
e
.
Error
()
if
msg
!=
tt
.
wanterrcontext
{
t
.
Fatalf
(
"err + calling context: %q ; want %q"
,
msg
,
tt
.
wanterrcontext
)
}
})
tt
.
f
()
t
.
Fatal
(
"error not caught"
)
}()
}
var
tests
=
[]
struct
{
f
func
();
wanterrcontext
string
}
{
{
do_raise11
,
"do_raise11: do_raise1: 1"
},
{
do_raise3if1
,
"do_raise3if1: do_raise3if: 3"
},
{
do_raise4f1
,
"do_raise4f1: do_raise4f: 4"
},
}
for
_
,
tt
:=
range
tests
{
func
()
{
myfunc
:=
myname
.
Func
()
defer
Catch
(
func
(
e
*
Error
)
{
e
=
Addcallingcontext
(
myfunc
,
e
)
msg
:=
e
.
Error
()
if
msg
!=
tt
.
wanterrcontext
{
t
.
Fatalf
(
"err + calling context: %q ; want %q"
,
msg
,
tt
.
wanterrcontext
)
}
})
tt
.
f
()
t
.
Fatal
(
"error not caught"
)
}()
}
}
mem/mem.go
View file @
66a27966
...
...
@@ -14,25 +14,25 @@
package
mem
import
(
"reflect"
"unsafe"
"reflect"
"unsafe"
)
// string -> []byte without copying
func
Bytes
(
s
string
)
[]
byte
{
var
b
[]
byte
bp
:=
(
*
reflect
.
SliceHeader
)(
unsafe
.
Pointer
(
&
b
))
bp
.
Data
=
(
*
reflect
.
StringHeader
)(
unsafe
.
Pointer
(
&
s
))
.
Data
bp
.
Cap
=
len
(
s
)
bp
.
Len
=
len
(
s
)
return
b
var
b
[]
byte
bp
:=
(
*
reflect
.
SliceHeader
)(
unsafe
.
Pointer
(
&
b
))
bp
.
Data
=
(
*
reflect
.
StringHeader
)(
unsafe
.
Pointer
(
&
s
))
.
Data
bp
.
Cap
=
len
(
s
)
bp
.
Len
=
len
(
s
)
return
b
}
// []byte -> string without copying
func
String
(
b
[]
byte
)
string
{
var
s
string
sp
:=
(
*
reflect
.
StringHeader
)(
unsafe
.
Pointer
(
&
s
))
sp
.
Data
=
(
*
reflect
.
SliceHeader
)(
unsafe
.
Pointer
(
&
b
))
.
Data
sp
.
Len
=
len
(
b
)
return
s
var
s
string
sp
:=
(
*
reflect
.
StringHeader
)(
unsafe
.
Pointer
(
&
s
))
sp
.
Data
=
(
*
reflect
.
SliceHeader
)(
unsafe
.
Pointer
(
&
b
))
.
Data
sp
.
Len
=
len
(
b
)
return
s
}
mem/mem_test.go
View file @
66a27966
...
...
@@ -13,21 +13,21 @@
package
mem
import
(
"reflect"
"testing"
"reflect"
"testing"
)
// check that String() and Bytes() create correct objects which alias original object memory
func
TestStringBytes
(
t
*
testing
.
T
)
{
s
:=
"Hello"
b
:=
[]
byte
(
s
)
s
:=
"Hello"
b
:=
[]
byte
(
s
)
s1
:=
String
(
b
)
b1
:=
Bytes
(
s1
)
if
s1
!=
s
{
t
.
Error
(
"string -> []byte -> String != Identity"
)
}
if
!
reflect
.
DeepEqual
(
b1
,
b
)
{
t
.
Error
(
"[]byte -> String -> Bytes != Identity"
)
}
b
[
0
]
=
'I'
if
s
!=
"Hello"
{
t
.
Error
(
"string -> []byte not copied"
)
}
if
s1
!=
"Iello"
{
t
.
Error
(
"[]byte -> String not aliased"
)
}
if
!
reflect
.
DeepEqual
(
b1
,
b
)
{
t
.
Error
(
"string -> Bytes not aliased"
)
}
s1
:=
String
(
b
)
b1
:=
Bytes
(
s1
)
if
s1
!=
s
{
t
.
Error
(
"string -> []byte -> String != Identity"
)
}
if
!
reflect
.
DeepEqual
(
b1
,
b
)
{
t
.
Error
(
"[]byte -> String -> Bytes != Identity"
)
}
b
[
0
]
=
'I'
if
s
!=
"Hello"
{
t
.
Error
(
"string -> []byte not copied"
)
}
if
s1
!=
"Iello"
{
t
.
Error
(
"[]byte -> String not aliased"
)
}
if
!
reflect
.
DeepEqual
(
b1
,
b
)
{
t
.
Error
(
"string -> Bytes not aliased"
)
}
}
myname/myname.go
View file @
66a27966
...
...
@@ -14,44 +14,44 @@
package
myname
import
(
"fmt"
"runtime"
"strings"
"fmt"
"runtime"
"strings"
)
func
_myfuncname
(
nskip
int
)
string
{
pcv
:=
[
1
]
uintptr
{}
runtime
.
Callers
(
nskip
,
pcv
[
:
])
f
:=
runtime
.
FuncForPC
(
pcv
[
0
])
if
f
==
nil
{
return
""
}
return
f
.
Name
()
pcv
:=
[
1
]
uintptr
{}
runtime
.
Callers
(
nskip
,
pcv
[
:
])
f
:=
runtime
.
FuncForPC
(
pcv
[
0
])
if
f
==
nil
{
return
""
}
return
f
.
Name
()
}
// get name of currently running function (caller of Func())
// name is fully qualified package/name.function(.x)
func
Func
()
string
{
return
_myfuncname
(
3
)
return
_myfuncname
(
3
)
}
// get name of currently running function's package
// package is fully qualified package/name
func
Pkg
()
string
{
myfunc
:=
_myfuncname
(
3
)
if
myfunc
==
""
{
return
""
}
// NOTE dots in package name are after last slash are escaped by go as %2e
// this way the first '.' after last '/' is delimiter between package and function
//
// lab.nexedi.com/kirr/git-backup/package%2ename.Function
// lab.nexedi.com/kirr/git-backup/pkg2.qqq/name%2ezzz.Function
islash
:=
strings
.
LastIndexByte
(
myfunc
,
'/'
)
iafterslash
:=
islash
+
1
// NOTE if '/' not found iafterslash = 0
idot
:=
strings
.
IndexByte
(
myfunc
[
iafterslash
:
],
'.'
)
if
idot
==
-
1
{
panic
(
fmt
.
Errorf
(
"funcname %q is not fully qualified"
,
myfunc
))
}
return
myfunc
[
:
iafterslash
+
idot
]
myfunc
:=
_myfuncname
(
3
)
if
myfunc
==
""
{
return
""
}
// NOTE dots in package name are after last slash are escaped by go as %2e
// this way the first '.' after last '/' is delimiter between package and function
//
// lab.nexedi.com/kirr/git-backup/package%2ename.Function
// lab.nexedi.com/kirr/git-backup/pkg2.qqq/name%2ezzz.Function
islash
:=
strings
.
LastIndexByte
(
myfunc
,
'/'
)
iafterslash
:=
islash
+
1
// NOTE if '/' not found iafterslash = 0
idot
:=
strings
.
IndexByte
(
myfunc
[
iafterslash
:
],
'.'
)
if
idot
==
-
1
{
panic
(
fmt
.
Errorf
(
"funcname %q is not fully qualified"
,
myfunc
))
}
return
myfunc
[
:
iafterslash
+
idot
]
}
myname/myname_test.go
View file @
66a27966
...
...
@@ -13,16 +13,16 @@
package
myname
import
(
"strings"
"testing"
"strings"
"testing"
)
func
TestMyFuncName
(
t
*
testing
.
T
)
{
myfunc
:=
Func
()
// go test changes full package name (putting filesystem of the tree into ti)
// thus we check only for suffix
wantsuffix
:=
".TestMyFuncName"
if
!
strings
.
HasSuffix
(
myfunc
,
wantsuffix
)
{
t
.
Errorf
(
"myname.Func() -> %v ; want *%v"
,
myfunc
,
wantsuffix
)
}
myfunc
:=
Func
()
// go test changes full package name (putting filesystem of the tree into ti)
// thus we check only for suffix
wantsuffix
:=
".TestMyFuncName"
if
!
strings
.
HasSuffix
(
myfunc
,
wantsuffix
)
{
t
.
Errorf
(
"myname.Func() -> %v ; want *%v"
,
myfunc
,
wantsuffix
)
}
}
xerr/xerr.go
View file @
66a27966
...
...
@@ -14,20 +14,20 @@
package
xerr
import
(
"fmt"
"fmt"
)
// error merging multiple errors (e.g. after collecting them from several parallel workers)
type
Errorv
[]
error
func
(
ev
Errorv
)
Error
()
string
{
if
len
(
ev
)
==
1
{
return
ev
[
0
]
.
Error
()
}
if
len
(
ev
)
==
1
{
return
ev
[
0
]
.
Error
()
}
msg
:=
fmt
.
Sprintf
(
"%d errors:
\n
"
,
len
(
ev
))
for
_
,
e
:=
range
ev
{
msg
+=
fmt
.
Sprintf
(
"
\t
- %s
\n
"
,
e
)
}
return
msg
msg
:=
fmt
.
Sprintf
(
"%d errors:
\n
"
,
len
(
ev
))
for
_
,
e
:=
range
ev
{
msg
+=
fmt
.
Sprintf
(
"
\t
- %s
\n
"
,
e
)
}
return
msg
}
xruntime/xruntime.go
View file @
66a27966
...
...
@@ -14,44 +14,44 @@
package
xruntime
import
(
"runtime"
"runtime"
)
// TODO(go1.7) goes away in favour of runtime.Frame
type
Frame
struct
{
*
runtime
.
Func
Pc
uintptr
*
runtime
.
Func
Pc
uintptr
}
// get current calling traceback as []Frame
// nskip meaning: the same as in runtime.Callers()
// TODO(go1.7) []Frame -> []runtime.Frame
func
Traceback
(
nskip
int
)
[]
Frame
{
// all callers
var
pcv
=
[]
uintptr
{
0
}
for
{
pcv
=
make
([]
uintptr
,
2
*
len
(
pcv
))
n
:=
runtime
.
Callers
(
nskip
+
1
,
pcv
)
if
n
<
len
(
pcv
)
{
pcv
=
pcv
[
:
n
]
break
}
}
// all callers
var
pcv
=
[]
uintptr
{
0
}
for
{
pcv
=
make
([]
uintptr
,
2
*
len
(
pcv
))
n
:=
runtime
.
Callers
(
nskip
+
1
,
pcv
)
if
n
<
len
(
pcv
)
{
pcv
=
pcv
[
:
n
]
break
}
}
// pcv -> frames
// pcv -> frames
/*
framev := make([]runtime.Frame, 0, len(pcv))
frames := runtime.CallersFrames(pcv)
for more := true; more; {
var frame runtime.Frame
frame, more = frames.Next()
framev = append(framev, frame)
}
framev := make([]runtime.Frame, 0, len(pcv))
frames := runtime.CallersFrames(pcv)
for more := true; more; {
var frame runtime.Frame
frame, more = frames.Next()
framev = append(framev, frame)
}
*/
framev
:=
make
([]
Frame
,
0
,
len
(
pcv
))
for
_
,
pc
:=
range
pcv
{
framev
=
append
(
framev
,
Frame
{
runtime
.
FuncForPC
(
pc
),
pc
})
}
framev
:=
make
([]
Frame
,
0
,
len
(
pcv
))
for
_
,
pc
:=
range
pcv
{
framev
=
append
(
framev
,
Frame
{
runtime
.
FuncForPC
(
pc
),
pc
})
}
return
framev
return
framev
}
xstrings/xstrings.go
View file @
66a27966
...
...
@@ -14,35 +14,35 @@
package
xstrings
import
(
"fmt"
"strings"
"fmt"
"strings"
)
// split string into lines. The last line, if it is empty, is omitted from the result
// (rationale is: string.Split("hello\nworld\n", "\n") -> ["hello", "world", ""])
func
SplitLines
(
s
,
sep
string
)
[]
string
{
sv
:=
strings
.
Split
(
s
,
sep
)
l
:=
len
(
sv
)
if
l
>
0
&&
sv
[
l
-
1
]
==
""
{
sv
=
sv
[
:
l
-
1
]
}
return
sv
sv
:=
strings
.
Split
(
s
,
sep
)
l
:=
len
(
sv
)
if
l
>
0
&&
sv
[
l
-
1
]
==
""
{
sv
=
sv
[
:
l
-
1
]
}
return
sv
}
// split string by sep and expect exactly 2 parts
func
Split2
(
s
,
sep
string
)
(
s1
,
s2
string
,
err
error
)
{
parts
:=
strings
.
Split
(
s
,
sep
)
if
len
(
parts
)
!=
2
{
return
""
,
""
,
fmt
.
Errorf
(
"split2: %q has %v parts (expected 2, sep: %q)"
,
s
,
len
(
parts
),
sep
)
}
return
parts
[
0
],
parts
[
1
],
nil
parts
:=
strings
.
Split
(
s
,
sep
)
if
len
(
parts
)
!=
2
{
return
""
,
""
,
fmt
.
Errorf
(
"split2: %q has %v parts (expected 2, sep: %q)"
,
s
,
len
(
parts
),
sep
)
}
return
parts
[
0
],
parts
[
1
],
nil
}
// (head+sep+tail) -> head, tail
func
HeadTail
(
s
,
sep
string
)
(
head
,
tail
string
,
err
error
)
{
parts
:=
strings
.
SplitN
(
s
,
sep
,
2
)
if
len
(
parts
)
!=
2
{
return
""
,
""
,
fmt
.
Errorf
(
"headtail: %q has no %q"
,
s
,
sep
)
}
return
parts
[
0
],
parts
[
1
],
nil
parts
:=
strings
.
SplitN
(
s
,
sep
,
2
)
if
len
(
parts
)
!=
2
{
return
""
,
""
,
fmt
.
Errorf
(
"headtail: %q has no %q"
,
s
,
sep
)
}
return
parts
[
0
],
parts
[
1
],
nil
}
xstrings/xstrings_test.go
View file @
66a27966
...
...
@@ -13,62 +13,62 @@
package
xstrings
import
(
"reflect"
"testing"
"reflect"
"testing"
)
func
TestSplitLines
(
t
*
testing
.
T
)
{
var
tests
=
[]
struct
{
input
,
sep
string
;
output
[]
string
}
{
{
""
,
"
\n
"
,
[]
string
{}},
{
"hello"
,
"
\n
"
,
[]
string
{
"hello"
}},
{
"hello
\n
"
,
"
\n
"
,
[]
string
{
"hello"
}},
{
"hello
\n
world"
,
"
\n
"
,
[]
string
{
"hello"
,
"world"
}},
{
"hello
\n
world
\n
"
,
"
\n
"
,
[]
string
{
"hello"
,
"world"
}},
{
"hello
\x00
world
\x00
"
,
"
\n
"
,
[]
string
{
"hello
\x00
world
\x00
"
}},
{
"hello
\x00
world
\x00
"
,
"
\x00
"
,
[]
string
{
"hello"
,
"world"
}},
}
var
tests
=
[]
struct
{
input
,
sep
string
;
output
[]
string
}
{
{
""
,
"
\n
"
,
[]
string
{}},
{
"hello"
,
"
\n
"
,
[]
string
{
"hello"
}},
{
"hello
\n
"
,
"
\n
"
,
[]
string
{
"hello"
}},
{
"hello
\n
world"
,
"
\n
"
,
[]
string
{
"hello"
,
"world"
}},
{
"hello
\n
world
\n
"
,
"
\n
"
,
[]
string
{
"hello"
,
"world"
}},
{
"hello
\x00
world
\x00
"
,
"
\n
"
,
[]
string
{
"hello
\x00
world
\x00
"
}},
{
"hello
\x00
world
\x00
"
,
"
\x00
"
,
[]
string
{
"hello"
,
"world"
}},
}
for
_
,
tt
:=
range
tests
{
sv
:=
SplitLines
(
tt
.
input
,
tt
.
sep
)
if
!
reflect
.
DeepEqual
(
sv
,
tt
.
output
)
{
t
.
Errorf
(
"splitlines(%q, %q) -> %q ; want %q"
,
tt
.
input
,
tt
.
sep
,
sv
,
tt
.
output
)
}
}
for
_
,
tt
:=
range
tests
{
sv
:=
SplitLines
(
tt
.
input
,
tt
.
sep
)
if
!
reflect
.
DeepEqual
(
sv
,
tt
.
output
)
{
t
.
Errorf
(
"splitlines(%q, %q) -> %q ; want %q"
,
tt
.
input
,
tt
.
sep
,
sv
,
tt
.
output
)
}
}
}
func
TestSplit2
(
t
*
testing
.
T
)
{
var
tests
=
[]
struct
{
input
,
s1
,
s2
string
;
ok
bool
}
{
{
""
,
""
,
""
,
false
},
{
" "
,
""
,
""
,
true
},
{
"hello"
,
""
,
""
,
false
},
{
"hello world"
,
"hello"
,
"world"
,
true
},
{
"hello world 1"
,
""
,
""
,
false
},
}
var
tests
=
[]
struct
{
input
,
s1
,
s2
string
;
ok
bool
}
{
{
""
,
""
,
""
,
false
},
{
" "
,
""
,
""
,
true
},
{
"hello"
,
""
,
""
,
false
},
{
"hello world"
,
"hello"
,
"world"
,
true
},
{
"hello world 1"
,
""
,
""
,
false
},
}
for
_
,
tt
:=
range
tests
{
s1
,
s2
,
err
:=
Split2
(
tt
.
input
,
" "
)
ok
:=
err
==
nil
if
s1
!=
tt
.
s1
||
s2
!=
tt
.
s2
||
ok
!=
tt
.
ok
{
t
.
Errorf
(
"split2(%q) -> %q %q %v ; want %q %q %v"
,
tt
.
input
,
s1
,
s2
,
ok
,
tt
.
s1
,
tt
.
s2
,
tt
.
ok
)
}
}
for
_
,
tt
:=
range
tests
{
s1
,
s2
,
err
:=
Split2
(
tt
.
input
,
" "
)
ok
:=
err
==
nil
if
s1
!=
tt
.
s1
||
s2
!=
tt
.
s2
||
ok
!=
tt
.
ok
{
t
.
Errorf
(
"split2(%q) -> %q %q %v ; want %q %q %v"
,
tt
.
input
,
s1
,
s2
,
ok
,
tt
.
s1
,
tt
.
s2
,
tt
.
ok
)
}
}
}
func
TestHeadtail
(
t
*
testing
.
T
)
{
var
tests
=
[]
struct
{
input
,
head
,
tail
string
;
ok
bool
}
{
{
""
,
""
,
""
,
false
},
{
" "
,
""
,
""
,
true
},
{
" "
,
""
,
" "
,
true
},
{
"hello world"
,
"hello"
,
"world"
,
true
},
{
"hello world 1"
,
"hello"
,
"world 1"
,
true
},
{
"hello world 2"
,
"hello"
,
" world 2"
,
true
},
}
var
tests
=
[]
struct
{
input
,
head
,
tail
string
;
ok
bool
}
{
{
""
,
""
,
""
,
false
},
{
" "
,
""
,
""
,
true
},
{
" "
,
""
,
" "
,
true
},
{
"hello world"
,
"hello"
,
"world"
,
true
},
{
"hello world 1"
,
"hello"
,
"world 1"
,
true
},
{
"hello world 2"
,
"hello"
,
" world 2"
,
true
},
}
for
_
,
tt
:=
range
tests
{
head
,
tail
,
err
:=
HeadTail
(
tt
.
input
,
" "
)
ok
:=
err
==
nil
if
head
!=
tt
.
head
||
tail
!=
tt
.
tail
||
ok
!=
tt
.
ok
{
t
.
Errorf
(
"headtail(%q) -> %q %q %v ; want %q %q %v"
,
tt
.
input
,
head
,
tail
,
ok
,
tt
.
head
,
tt
.
tail
,
tt
.
ok
)
}
}
for
_
,
tt
:=
range
tests
{
head
,
tail
,
err
:=
HeadTail
(
tt
.
input
,
" "
)
ok
:=
err
==
nil
if
head
!=
tt
.
head
||
tail
!=
tt
.
tail
||
ok
!=
tt
.
ok
{
t
.
Errorf
(
"headtail(%q) -> %q %q %v ; want %q %q %v"
,
tt
.
input
,
head
,
tail
,
ok
,
tt
.
head
,
tt
.
tail
,
tt
.
ok
)
}
}
}
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