diff --git a/docs/reference/go-gno-compatibility.md b/docs/reference/go-gno-compatibility.md index bad19860655..f73ff33cce7 100644 --- a/docs/reference/go-gno-compatibility.md +++ b/docs/reference/go-gno-compatibility.md @@ -248,7 +248,7 @@ Legend: | runtime/trace | `gospec` | | slices | `gnics` | | sort | `part`[^6] | -| strconv | `part` | +| strconv | `full`[^10] | | strings | `full` | | sync | `tbd` | | sync/atomic | `tbd` | @@ -292,6 +292,8 @@ Legend: [^8]: `crypto/ed25519` is currently only implemented for `Verify`, which should still cover a majority of use cases. A full implementation is welcome. [^9]: `math/rand` in Gno ports over Go's `math/rand/v2`. +[^10]: `strconv` does not have the methods relating to types `complex64` and + `complex128`. ## Tooling (`gno` binary) diff --git a/gno.land/cmd/gnoland/testdata/append.txtar b/gno.land/cmd/gnoland/testdata/append.txtar index 46b66f9524b..3450b3e9b32 100644 --- a/gno.land/cmd/gnoland/testdata/append.txtar +++ b/gno.land/cmd/gnoland/testdata/append.txtar @@ -3,69 +3,69 @@ loadpkg gno.land/p/demo/ufmt # start a new node gnoland start -gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/append -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/append -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 stdout OK! # Call Append 1 -gnokey maketx call -pkgpath gno.land/r/append -func Append -gas-fee 1000000ugnot -gas-wanted 2000000 -args '1' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append -func Append -gas-fee 1000000ugnot -gas-wanted 4000000 -args '1' -broadcast -chainid=tendermint_test test1 stdout OK! -gnokey maketx call -pkgpath gno.land/r/append -func AppendNil -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append -func AppendNil -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 stdout OK! # Call Append 2 -gnokey maketx call -pkgpath gno.land/r/append -func Append -gas-fee 1000000ugnot -gas-wanted 2000000 -args '2' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append -func Append -gas-fee 1000000ugnot -gas-wanted 4000000 -args '2' -broadcast -chainid=tendermint_test test1 stdout OK! # Call Append 3 -gnokey maketx call -pkgpath gno.land/r/append -func Append -gas-fee 1000000ugnot -gas-wanted 2000000 -args '3' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append -func Append -gas-fee 1000000ugnot -gas-wanted 4000000 -args '3' -broadcast -chainid=tendermint_test test1 stdout OK! # Call render -gnokey maketx call -pkgpath gno.land/r/append -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append -func Render -gas-fee 1000000ugnot -gas-wanted 4000000 -args '' -broadcast -chainid=tendermint_test test1 stdout '("1-2-3-" string)' stdout OK! # Call Pop -gnokey maketx call -pkgpath gno.land/r/append -func Pop -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append -func Pop -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 stdout OK! # Call render -gnokey maketx call -pkgpath gno.land/r/append -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append -func Render -gas-fee 1000000ugnot -gas-wanted 4000000 -args '' -broadcast -chainid=tendermint_test test1 stdout '("2-3-" string)' stdout OK! # Call Append 42 -gnokey maketx call -pkgpath gno.land/r/append -func Append -gas-fee 1000000ugnot -gas-wanted 2000000 -args '42' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append -func Append -gas-fee 1000000ugnot -gas-wanted 4000000 -args '42' -broadcast -chainid=tendermint_test test1 stdout OK! # Call render -gnokey maketx call -pkgpath gno.land/r/append -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append -func Render -gas-fee 1000000ugnot -gas-wanted 4000000 -args '' -broadcast -chainid=tendermint_test test1 stdout '("2-3-42-" string)' stdout OK! -gnokey maketx call -pkgpath gno.land/r/append -func CopyAppend -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append -func CopyAppend -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 stdout OK! -gnokey maketx call -pkgpath gno.land/r/append -func PopB -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append -func PopB -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 stdout OK! # Call render -gnokey maketx call -pkgpath gno.land/r/append -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append -func Render -gas-fee 1000000ugnot -gas-wanted 4000000 -args '' -broadcast -chainid=tendermint_test test1 stdout '("2-3-42-" string)' stdout OK! -gnokey maketx call -pkgpath gno.land/r/append -func AppendMoreAndC -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append -func AppendMoreAndC -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 stdout OK! -gnokey maketx call -pkgpath gno.land/r/append -func ReassignC -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append -func ReassignC -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 stdout OK! -gnokey maketx call -pkgpath gno.land/r/append -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append -func Render -gas-fee 1000000ugnot -gas-wanted 4000000 -args '' -broadcast -chainid=tendermint_test test1 stdout '("2-3-42-70-100-" string)' stdout OK! -gnokey maketx call -pkgpath gno.land/r/append -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args 'd' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/append -func Render -gas-fee 1000000ugnot -gas-wanted 4000000 -args 'd' -broadcast -chainid=tendermint_test test1 stdout '("1-" string)' stdout OK! diff --git a/gno.land/cmd/gnoland/testdata/assertorigincall.txtar b/gno.land/cmd/gnoland/testdata/assertorigincall.txtar index e3cd1be744a..1315f23cc95 100644 --- a/gno.land/cmd/gnoland/testdata/assertorigincall.txtar +++ b/gno.land/cmd/gnoland/testdata/assertorigincall.txtar @@ -33,85 +33,85 @@ gnoland start # Test cases ## 1. MsgCall -> myrlm.A: PANIC -! gnokey maketx call -pkgpath gno.land/r/myrlm -func A -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +! gnokey maketx call -pkgpath gno.land/r/myrlm -func A -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 stderr 'invalid non-origin call' ## 2. MsgCall -> myrlm.B: PASS -gnokey maketx call -pkgpath gno.land/r/myrlm -func B -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/myrlm -func B -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 stdout 'OK!' ## 3. MsgCall -> myrlm.C: PASS -gnokey maketx call -pkgpath gno.land/r/myrlm -func C -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/myrlm -func C -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 stdout 'OK!' ## 4. MsgCall -> r/foo.A -> myrlm.A: PANIC -! gnokey maketx call -pkgpath gno.land/r/foo -func A -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +! gnokey maketx call -pkgpath gno.land/r/foo -func A -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 stderr 'invalid non-origin call' ## 5. MsgCall -> r/foo.B -> myrlm.B: PASS -gnokey maketx call -pkgpath gno.land/r/foo -func B -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/foo -func B -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 stdout 'OK!' ## 6. MsgCall -> r/foo.C -> myrlm.C: PANIC -! gnokey maketx call -pkgpath gno.land/r/foo -func C -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +! gnokey maketx call -pkgpath gno.land/r/foo -func C -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 stderr 'invalid non-origin call' ## remove due to update to maketx call can only call realm (case 7,8,9) ## 7. MsgCall -> p/demo/bar.A -> myrlm.A: PANIC -## ! gnokey maketx call -pkgpath gno.land/p/demo/bar -func A -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +## ! gnokey maketx call -pkgpath gno.land/p/demo/bar -func A -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 ## stderr 'invalid non-origin call' ## 8. MsgCall -> p/demo/bar.B -> myrlm.B: PASS -## gnokey maketx call -pkgpath gno.land/p/demo/bar -func B -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +## gnokey maketx call -pkgpath gno.land/p/demo/bar -func B -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 ## stdout 'OK!' ## 9. MsgCall -> p/demo/bar.C -> myrlm.C: PANIC -## ! gnokey maketx call -pkgpath gno.land/p/demo/bar -func C -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +## ! gnokey maketx call -pkgpath gno.land/p/demo/bar -func C -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 ## stderr 'invalid non-origin call' ## 10. MsgRun -> run.main -> myrlm.A: PANIC -! gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/myrlmA.gno +! gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 $WORK/run/myrlmA.gno stderr 'invalid non-origin call' ## 11. MsgRun -> run.main -> myrlm.B: PASS -gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/myrlmB.gno +gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 $WORK/run/myrlmB.gno stdout 'OK!' ## 12. MsgRun -> run.main -> myrlm.C: PANIC -! gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/myrlmC.gno +! gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 $WORK/run/myrlmC.gno stderr 'invalid non-origin call' ## 13. MsgRun -> run.main -> foo.A: PANIC -! gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/fooA.gno +! gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 $WORK/run/fooA.gno stderr 'invalid non-origin call' ## 14. MsgRun -> run.main -> foo.B: PASS -gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/fooB.gno +gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 $WORK/run/fooB.gno stdout 'OK!' ## 15. MsgRun -> run.main -> foo.C: PANIC -! gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/fooC.gno +! gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 $WORK/run/fooC.gno stderr 'invalid non-origin call' ## 16. MsgRun -> run.main -> bar.A: PANIC -! gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/barA.gno +! gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 $WORK/run/barA.gno stderr 'invalid non-origin call' ## 17. MsgRun -> run.main -> bar.B: PASS -gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/barB.gno +gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 $WORK/run/barB.gno stdout 'OK!' ## 18. MsgRun -> run.main -> bar.C: PANIC -! gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/barC.gno +! gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 $WORK/run/barC.gno stderr 'invalid non-origin call' ## remove testcase 19 due to maketx call forced to call a realm ## 19. MsgCall -> std.AssertOriginCall: pass -## gnokey maketx call -pkgpath std -func AssertOriginCall -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +## gnokey maketx call -pkgpath std -func AssertOriginCall -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 ## stdout 'OK!' ## 20. MsgRun -> std.AssertOriginCall: PANIC -! gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/baz.gno +! gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 $WORK/run/baz.gno stderr 'invalid non-origin call' diff --git a/gno.land/cmd/gnoland/testdata/grc20_registry.txtar b/gno.land/cmd/gnoland/testdata/grc20_registry.txtar index 20e78f7ba6e..a5f7ad5eee3 100644 --- a/gno.land/cmd/gnoland/testdata/grc20_registry.txtar +++ b/gno.land/cmd/gnoland/testdata/grc20_registry.txtar @@ -6,15 +6,15 @@ loadpkg gno.land/r/registry $WORK/registry gnoland start # we call Transfer with foo20, before it's registered -gnokey maketx call -pkgpath gno.land/r/registry -func TransferByName -args 'foo20' -args 'g123456789' -args '42' -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/registry -func TransferByName -args 'foo20' -args 'g123456789' -args '42' -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 stdout 'not found' # add foo20, and foo20wrapper -gnokey maketx addpkg -pkgdir $WORK/foo20 -pkgpath gno.land/r/foo20 -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 -gnokey maketx addpkg -pkgdir $WORK/foo20wrapper -pkgpath gno.land/r/foo20wrapper -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx addpkg -pkgdir $WORK/foo20 -pkgpath gno.land/r/foo20 -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx addpkg -pkgdir $WORK/foo20wrapper -pkgpath gno.land/r/foo20wrapper -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 # we call Transfer with foo20, after it's registered -gnokey maketx call -pkgpath gno.land/r/registry -func TransferByName -args 'foo20' -args 'g123456789' -args '42' -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/registry -func TransferByName -args 'foo20' -args 'g123456789' -args '42' -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 stdout 'same address, success!' -- registry/registry.gno -- @@ -49,7 +49,7 @@ import "gno.land/r/registry" import "gno.land/r/foo20" func init() { - registry.Register("foo20", foo20.Transfer) + registry.Register("foo20", foo20.Transfer) } -- foo20/foo20.gno -- diff --git a/gno.land/cmd/gnoland/testdata/issue_1167.txtar b/gno.land/cmd/gnoland/testdata/issue_1167.txtar index c43f7a45bd5..73febb0235a 100644 --- a/gno.land/cmd/gnoland/testdata/issue_1167.txtar +++ b/gno.land/cmd/gnoland/testdata/issue_1167.txtar @@ -4,30 +4,30 @@ loadpkg gno.land/p/demo/avl gnoland start # add contract -gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/demo/xx -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/demo/xx -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 stdout OK! # execute New -gnokey maketx call -pkgpath gno.land/r/demo/xx -func New -args X -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/xx -func New -args X -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 stdout OK! # execute Delta for the first time -gnokey maketx call -pkgpath gno.land/r/demo/xx -func Delta -args X -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/xx -func Delta -args X -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 stdout OK! stdout '"1,1,1;" string' # execute Delta for the second time -gnokey maketx call -pkgpath gno.land/r/demo/xx -func Delta -args X -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/xx -func Delta -args X -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 stdout OK! stdout '1,1,1;2,2,2;" string' # execute Delta for the third time -gnokey maketx call -pkgpath gno.land/r/demo/xx -func Delta -args X -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/xx -func Delta -args X -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 stdout OK! stdout '1,1,1;2,2,2;3,3,3;" string' # execute Render -gnokey maketx call -pkgpath gno.land/r/demo/xx -func Render -args X -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/demo/xx -func Render -args X -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 stdout OK! stdout '1,1,1;2,2,2;3,3,3;" string' diff --git a/gno.land/cmd/gnoland/testdata/prevrealm.txtar b/gno.land/cmd/gnoland/testdata/prevrealm.txtar index 72a207fae22..7a0d994a686 100644 --- a/gno.land/cmd/gnoland/testdata/prevrealm.txtar +++ b/gno.land/cmd/gnoland/testdata/prevrealm.txtar @@ -34,60 +34,60 @@ env RFOO_ADDR=g1evezrh92xaucffmtgsaa3rvmz5s8kedffsg469 # Test cases ## 1. MsgCall -> myrlm.A: user address -gnokey maketx call -pkgpath gno.land/r/myrlm -func A -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/myrlm -func A -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 stdout ${USER_ADDR_test1} ## 2. MsgCall -> myrealm.B -> myrlm.A: user address -gnokey maketx call -pkgpath gno.land/r/myrlm -func B -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/myrlm -func B -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 stdout ${USER_ADDR_test1} ## 3. MsgCall -> r/foo.A -> myrlm.A: r/foo -gnokey maketx call -pkgpath gno.land/r/foo -func A -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/foo -func A -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 stdout ${RFOO_ADDR} ## 4. MsgCall -> r/foo.B -> myrlm.B -> r/foo.A: r/foo -gnokey maketx call -pkgpath gno.land/r/foo -func B -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/foo -func B -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 stdout ${RFOO_ADDR} ## remove due to update to maketx call can only call realm (case 5, 6, 13) ## 5. MsgCall -> p/demo/bar.A -> myrlm.A: user address -## gnokey maketx call -pkgpath gno.land/p/demo/bar -func A -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +## gnokey maketx call -pkgpath gno.land/p/demo/bar -func A -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 ## stdout ${USER_ADDR_test1} ## 6. MsgCall -> p/demo/bar.B -> myrlm.B -> r/foo.A: user address -## gnokey maketx call -pkgpath gno.land/p/demo/bar -func B -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +## gnokey maketx call -pkgpath gno.land/p/demo/bar -func B -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 ## stdout ${USER_ADDR_test1} ## 7. MsgRun -> myrlm.A: user address -gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/myrlmA.gno +gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 $WORK/run/myrlmA.gno stdout ${USER_ADDR_test1} ## 8. MsgRun -> myrealm.B -> myrlm.A: user address -gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/myrlmB.gno +gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 $WORK/run/myrlmB.gno stdout ${USER_ADDR_test1} ## 9. MsgRun -> r/foo.A -> myrlm.A: r/foo -gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/fooA.gno +gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 $WORK/run/fooA.gno stdout ${RFOO_ADDR} ## 10. MsgRun -> r/foo.B -> myrlm.B -> r/foo.A: r/foo -gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/fooB.gno +gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 $WORK/run/fooB.gno stdout ${RFOO_ADDR} ## 11. MsgRun -> p/demo/bar.A -> myrlm.A: user address -gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/barA.gno +gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 $WORK/run/barA.gno stdout ${USER_ADDR_test1} ## 12. MsgRun -> p/demo/bar.B -> myrlm.B -> r/foo.A: user address -gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/barB.gno +gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 $WORK/run/barB.gno stdout ${USER_ADDR_test1} ## 13. MsgCall -> std.PrevRealm(): user address -## gnokey maketx call -pkgpath std -func PrevRealm -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 +## gnokey maketx call -pkgpath std -func PrevRealm -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 ## stdout ${USER_ADDR_test1} ## 14. MsgRun -> std.PrevRealm(): user address -gnokey maketx run -gas-fee 100000ugnot -gas-wanted 2000000 -broadcast -chainid tendermint_test test1 $WORK/run/baz.gno +gnokey maketx run -gas-fee 100000ugnot -gas-wanted 4000000 -broadcast -chainid tendermint_test test1 $WORK/run/baz.gno stdout ${USER_ADDR_test1} -- r/myrlm/myrlm.gno -- diff --git a/gno.land/cmd/gnoland/testdata/restart_missing_type.txtar b/gno.land/cmd/gnoland/testdata/restart_missing_type.txtar index 7eb91096437..c492f1c6646 100644 --- a/gno.land/cmd/gnoland/testdata/restart_missing_type.txtar +++ b/gno.land/cmd/gnoland/testdata/restart_missing_type.txtar @@ -162,7 +162,7 @@ gnoland restart } ], "fee": { - "gas_wanted": "16000000", + "gas_wanted": "20000000", "gas_fee": "1000000ugnot" }, "signatures": [], @@ -193,10 +193,9 @@ gnoland restart } ], "fee": { - "gas_wanted": "15000000", + "gas_wanted": "16000000", "gas_fee": "1000000ugnot" }, "signatures": [], "memo": "" } - diff --git a/gno.land/pkg/gnoclient/integration_test.go b/gno.land/pkg/gnoclient/integration_test.go index ea068e0680b..846962766f8 100644 --- a/gno.land/pkg/gnoclient/integration_test.go +++ b/gno.land/pkg/gnoclient/integration_test.go @@ -359,7 +359,7 @@ func TestRunMultiple_Integration(t *testing.T) { // Make Tx config baseCfg := BaseTxCfg{ GasFee: ugnot.ValueString(10000), - GasWanted: 8000000, + GasWanted: 13000000, AccountNumber: 0, SequenceNumber: 0, Memo: "", @@ -556,7 +556,7 @@ func Echo(str string) string { body2 := `package hello func Hello(str string) string { - return "Hello " + str + "!" + return "Hello " + str + "!" }` caller, err := client.Signer.Info() diff --git a/gno.land/pkg/integration/testdata/loadpkg_example.txtar b/gno.land/pkg/integration/testdata/loadpkg_example.txtar index d0c95331ff5..9dccd72c8a6 100644 --- a/gno.land/pkg/integration/testdata/loadpkg_example.txtar +++ b/gno.land/pkg/integration/testdata/loadpkg_example.txtar @@ -4,11 +4,11 @@ loadpkg gno.land/p/demo/ufmt ## start a new node gnoland start -gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/importtest -gas-fee 1000000ugnot -gas-wanted 2000000 -broadcast -chainid=tendermint_test test1 +gnokey maketx addpkg -pkgdir $WORK -pkgpath gno.land/r/importtest -gas-fee 1000000ugnot -gas-wanted 4000000 -broadcast -chainid=tendermint_test test1 stdout OK! ## execute Render -gnokey maketx call -pkgpath gno.land/r/importtest -func Render -gas-fee 1000000ugnot -gas-wanted 2000000 -args '' -broadcast -chainid=tendermint_test test1 +gnokey maketx call -pkgpath gno.land/r/importtest -func Render -gas-fee 1000000ugnot -gas-wanted 4000000 -args '' -broadcast -chainid=tendermint_test test1 stdout '("92054" string)' stdout OK! @@ -25,4 +25,3 @@ import ( func Render(_ string) string { return ufmt.Sprintf("%d", 92054) } - diff --git a/gnovm/pkg/gnolang/gonative.go b/gnovm/pkg/gnolang/gonative.go index 6127fa42b07..0676854aa39 100644 --- a/gnovm/pkg/gnolang/gonative.go +++ b/gnovm/pkg/gnolang/gonative.go @@ -866,7 +866,7 @@ func gno2GoType(t Type) reflect.Type { return rt } else { // NOTE: can this be implemented in go1.15? i think not. - panic("not yet supported") + panic("gno2go conversion of type not yet supported: " + ct.String()) } case *TypeType: panic("should not happen") diff --git a/gnovm/pkg/gnolang/machine.go b/gnovm/pkg/gnolang/machine.go index a0542bf9713..ad94f1a2b3a 100644 --- a/gnovm/pkg/gnolang/machine.go +++ b/gnovm/pkg/gnolang/machine.go @@ -8,6 +8,8 @@ import ( "io" "os" "reflect" + "slices" + "strconv" "strings" "sync" "testing" @@ -278,8 +280,10 @@ func (m *Machine) RunMemPackageWithOverrides(memPkg *std.MemPackage, save bool) func (m *Machine) runMemPackage(memPkg *std.MemPackage, save, overrides bool) (*PackageNode, *PackageValue) { // parse files. files := ParseMemPackage(memPkg) - if !overrides && checkDuplicates(files) { - panic(fmt.Errorf("running package %q: duplicate declarations not allowed", memPkg.Path)) + if !overrides { + if err := checkDuplicates(files); err != nil { + panic(fmt.Errorf("running package %q: %w", memPkg.Path, err)) + } } // make and set package if doesn't exist. pn := (*PackageNode)(nil) @@ -322,9 +326,31 @@ func (m *Machine) runMemPackage(memPkg *std.MemPackage, save, overrides bool) (* return pn, pv } -// checkDuplicates returns true if there duplicate declarations in the fset. -func checkDuplicates(fset *FileSet) bool { +type redeclarationErrors []Name + +func (r redeclarationErrors) Error() string { + var b strings.Builder + b.WriteString("redeclarations for identifiers: ") + for idx, s := range r { + b.WriteString(strconv.Quote(string(s))) + if idx != len(r)-1 { + b.WriteString(", ") + } + } + return b.String() +} + +func (r redeclarationErrors) add(newI Name) redeclarationErrors { + if slices.Contains(r, newI) { + return r + } + return append(r, newI) +} + +// checkDuplicates returns an error if there are duplicate declarations in the fset. +func checkDuplicates(fset *FileSet) error { defined := make(map[Name]struct{}, 128) + var duplicated redeclarationErrors for _, f := range fset.Files { for _, d := range f.Decls { var name Name @@ -345,7 +371,7 @@ func checkDuplicates(fset *FileSet) bool { continue } if _, ok := defined[nx.Name]; ok { - return true + duplicated = duplicated.add(nx.Name) } defined[nx.Name] = struct{}{} } @@ -357,12 +383,15 @@ func checkDuplicates(fset *FileSet) bool { continue } if _, ok := defined[name]; ok { - return true + duplicated = duplicated.add(name) } defined[name] = struct{}{} } } - return false + if len(duplicated) > 0 { + return duplicated + } + return nil } func destar(x Expr) Expr { diff --git a/gnovm/pkg/gnolang/nodes.go b/gnovm/pkg/gnolang/nodes.go index 8927eafcfb2..5f5e8bd30b9 100644 --- a/gnovm/pkg/gnolang/nodes.go +++ b/gnovm/pkg/gnolang/nodes.go @@ -2118,7 +2118,6 @@ const ( ATTR_TYPEOF_VALUE GnoAttribute = "ATTR_TYPEOF_VALUE" ATTR_IOTA GnoAttribute = "ATTR_IOTA" ATTR_LOCATIONED GnoAttribute = "ATTR_LOCATIONED" - ATTR_INJECTED GnoAttribute = "ATTR_INJECTED" ATTR_SHIFT_RHS GnoAttribute = "ATTR_SHIFT_RHS" ) diff --git a/gnovm/pkg/gnolang/preprocess.go b/gnovm/pkg/gnolang/preprocess.go index df1f7bab498..61096626f28 100644 --- a/gnovm/pkg/gnolang/preprocess.go +++ b/gnovm/pkg/gnolang/preprocess.go @@ -2104,14 +2104,28 @@ func Preprocess(store Store, ctx BlockNode, n Node) Node { case *BranchStmt: switch n.Op { case BREAK: - if !isSwitchLabel(ns, n.Label) { - findBranchLabel(last, n.Label) + if n.Label == "" { + if !findBreakableNode(ns) { + panic("cannot break with no parent loop or switch") + } + } else { + // Make sure that the label exists, either for a switch or a + // BranchStmt. + if !isSwitchLabel(ns, n.Label) { + findBranchLabel(last, n.Label) + } } case CONTINUE: - if isSwitchLabel(ns, n.Label) { - panic(fmt.Sprintf("invalid continue label %q\n", n.Label)) + if n.Label == "" { + if !findContinuableNode(ns) { + panic("cannot continue with no parent loop") + } + } else { + if isSwitchLabel(ns, n.Label) { + panic(fmt.Sprintf("invalid continue label %q\n", n.Label)) + } + findBranchLabel(last, n.Label) } - findBranchLabel(last, n.Label) case GOTO: _, depth, index := findGotoLabel(last, n.Label) n.Depth = depth @@ -2775,6 +2789,26 @@ func funcOf(last BlockNode) (BlockNode, *FuncTypeExpr) { } } +func findBreakableNode(ns []Node) bool { + for _, n := range ns { + switch n.(type) { + case *ForStmt, *RangeStmt, *SwitchClauseStmt: + return true + } + } + return false +} + +func findContinuableNode(ns []Node) bool { + for _, n := range ns { + switch n.(type) { + case *ForStmt, *RangeStmt: + return true + } + } + return false +} + func findBranchLabel(last BlockNode, label Name) ( bn BlockNode, depth uint8, bodyIdx int, ) { diff --git a/gnovm/pkg/gnolang/store.go b/gnovm/pkg/gnolang/store.go index 8a1743ddf53..0e6d89a7bf3 100644 --- a/gnovm/pkg/gnolang/store.go +++ b/gnovm/pkg/gnolang/store.go @@ -25,9 +25,6 @@ import ( // cause writes to happen to the store, such as MemPackages to iavlstore. type PackageGetter func(pkgPath string, store Store) (*PackageNode, *PackageValue) -// inject natives into a new or loaded package (value and node) -type PackageInjector func(store Store, pn *PackageNode) - // NativeStore is a function which can retrieve native bodies of native functions. type NativeStore func(pkgName string, name Name) func(m *Machine) @@ -66,7 +63,6 @@ type Store interface { GetMemFile(path string, name string) *std.MemFile IterMemPackage() <-chan *std.MemPackage ClearObjectCache() // run before processing a message - SetPackageInjector(PackageInjector) // for natives SetNativeStore(NativeStore) // for "new" natives XXX GetNative(pkgPath string, name Name) func(m *Machine) // for "new" natives XXX SetLogStoreOps(enabled bool) @@ -101,7 +97,6 @@ type defaultStore struct { // store configuration; cannot be modified in a transaction pkgGetter PackageGetter // non-realm packages cacheNativeTypes map[reflect.Type]Type // reflect doc: reflect.Type are comparable - pkgInjector PackageInjector // for injecting natives nativeStore NativeStore // for injecting natives go2gnoStrict bool // if true, native->gno type conversion must be registered. @@ -124,7 +119,6 @@ func NewStore(alloc *Allocator, baseStore, iavlStore store.Store) *defaultStore // store configuration pkgGetter: nil, cacheNativeTypes: make(map[reflect.Type]Type), - pkgInjector: nil, nativeStore: nil, go2gnoStrict: true, } @@ -154,7 +148,6 @@ func (ds *defaultStore) BeginTransaction(baseStore, iavlStore store.Store) Trans // store configuration pkgGetter: ds.pkgGetter, cacheNativeTypes: ds.cacheNativeTypes, - pkgInjector: ds.pkgInjector, nativeStore: ds.nativeStore, go2gnoStrict: ds.go2gnoStrict, @@ -190,10 +183,6 @@ func (transactionStore) ClearCache() { // panic("Go2GnoType may not be called in a transaction store") // } -func (transactionStore) SetPackageInjector(inj PackageInjector) { - panic("SetPackageInjector may not be called in a transaction store") -} - func (transactionStore) SetNativeStore(ns NativeStore) { panic("SetNativeStore may not be called in a transaction store") } @@ -263,26 +252,6 @@ func (ds *defaultStore) GetPackage(pkgPath string, isImport bool) *PackageValue rlm := ds.GetPackageRealm(pkgPath) pv.Realm = rlm } - // get package node. - pl := PackageNodeLocation(pkgPath) - pn, ok := ds.GetBlockNodeSafe(pl).(*PackageNode) - if !ok { - // Do not inject packages from packageGetter - // that don't have corresponding *PackageNodes. - } else { - // Inject natives after load. - if ds.pkgInjector != nil { - if pn.HasAttribute(ATTR_INJECTED) { - // e.g. in checktx or simulate or query. - pn.PrepareNewValues(pv) - } else { - // pv.GetBlock(ds) // preload pv.Block - ds.pkgInjector(ds, pn) - pn.SetAttribute(ATTR_INJECTED, true) - pn.PrepareNewValues(pv) - } - } - } // Rederive pv.fBlocksMap. pv.deriveFBlocksMap(ds) return pv @@ -303,18 +272,6 @@ func (ds *defaultStore) GetPackage(pkgPath string, isImport bool) *PackageValue // will get written elsewhere // later. ds.cacheObjects[oid] = pv - // inject natives after init. - if ds.pkgInjector != nil { - if pn.HasAttribute(ATTR_INJECTED) { - // not sure why this would happen. - panic("should not happen") - // pn.PrepareNewValues(pv) - } else { - ds.pkgInjector(ds, pn) - pn.SetAttribute(ATTR_INJECTED, true) - pn.PrepareNewValues(pv) - } - } // cache all types. usually preprocess() sets types, // but packages gotten from the pkgGetter may skip this step, // so fill in store.CacheTypes here. @@ -742,10 +699,6 @@ func (ds *defaultStore) ClearObjectCache() { ds.SetCachePackage(Uverse()) } -func (ds *defaultStore) SetPackageInjector(inj PackageInjector) { - ds.pkgInjector = inj -} - func (ds *defaultStore) SetNativeStore(ns NativeStore) { ds.nativeStore = ns } diff --git a/gnovm/pkg/gnolang/store_test.go b/gnovm/pkg/gnolang/store_test.go index 8114291d1b6..17f55993705 100644 --- a/gnovm/pkg/gnolang/store_test.go +++ b/gnovm/pkg/gnolang/store_test.go @@ -59,7 +59,6 @@ func TestTransactionStore_blockedMethods(t *testing.T) { // only be changed in the root store. assert.Panics(t, func() { transactionStore{}.SetPackageGetter(nil) }) assert.Panics(t, func() { transactionStore{}.ClearCache() }) - assert.Panics(t, func() { transactionStore{}.SetPackageInjector(nil) }) assert.Panics(t, func() { transactionStore{}.SetNativeStore(nil) }) assert.Panics(t, func() { transactionStore{}.SetStrictGo2GnoMapping(false) }) } diff --git a/gnovm/stdlibs/generated.go b/gnovm/stdlibs/generated.go index 4c460e220b7..7693e9d6e70 100644 --- a/gnovm/stdlibs/generated.go +++ b/gnovm/stdlibs/generated.go @@ -11,7 +11,6 @@ import ( libs_crypto_sha256 "github.com/gnolang/gno/gnovm/stdlibs/crypto/sha256" libs_math "github.com/gnolang/gno/gnovm/stdlibs/math" libs_std "github.com/gnolang/gno/gnovm/stdlibs/std" - libs_strconv "github.com/gnolang/gno/gnovm/stdlibs/strconv" libs_testing "github.com/gnolang/gno/gnovm/stdlibs/testing" libs_time "github.com/gnolang/gno/gnovm/stdlibs/time" ) @@ -721,252 +720,6 @@ var nativeFuncs = [...]NativeFunc{ )) }, }, - { - "strconv", - "Itoa", - []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("int")}, - }, - []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("string")}, - }, - false, - func(m *gno.Machine) { - b := m.LastBlock() - var ( - p0 int - rp0 = reflect.ValueOf(&p0).Elem() - ) - - gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 0, "")).TV, rp0) - - r0 := libs_strconv.Itoa(p0) - - m.PushValue(gno.Go2GnoValue( - m.Alloc, - m.Store, - reflect.ValueOf(&r0).Elem(), - )) - }, - }, - { - "strconv", - "AppendUint", - []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("[]byte")}, - {Name: gno.N("p1"), Type: gno.X("uint64")}, - {Name: gno.N("p2"), Type: gno.X("int")}, - }, - []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("[]byte")}, - }, - false, - func(m *gno.Machine) { - b := m.LastBlock() - var ( - p0 []byte - rp0 = reflect.ValueOf(&p0).Elem() - p1 uint64 - rp1 = reflect.ValueOf(&p1).Elem() - p2 int - rp2 = reflect.ValueOf(&p2).Elem() - ) - - gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 0, "")).TV, rp0) - gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 1, "")).TV, rp1) - gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 2, "")).TV, rp2) - - r0 := libs_strconv.AppendUint(p0, p1, p2) - - m.PushValue(gno.Go2GnoValue( - m.Alloc, - m.Store, - reflect.ValueOf(&r0).Elem(), - )) - }, - }, - { - "strconv", - "Atoi", - []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("string")}, - }, - []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("int")}, - {Name: gno.N("r1"), Type: gno.X("error")}, - }, - false, - func(m *gno.Machine) { - b := m.LastBlock() - var ( - p0 string - rp0 = reflect.ValueOf(&p0).Elem() - ) - - gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 0, "")).TV, rp0) - - r0, r1 := libs_strconv.Atoi(p0) - - m.PushValue(gno.Go2GnoValue( - m.Alloc, - m.Store, - reflect.ValueOf(&r0).Elem(), - )) - m.PushValue(gno.Go2GnoValue( - m.Alloc, - m.Store, - reflect.ValueOf(&r1).Elem(), - )) - }, - }, - { - "strconv", - "CanBackquote", - []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("string")}, - }, - []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("bool")}, - }, - false, - func(m *gno.Machine) { - b := m.LastBlock() - var ( - p0 string - rp0 = reflect.ValueOf(&p0).Elem() - ) - - gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 0, "")).TV, rp0) - - r0 := libs_strconv.CanBackquote(p0) - - m.PushValue(gno.Go2GnoValue( - m.Alloc, - m.Store, - reflect.ValueOf(&r0).Elem(), - )) - }, - }, - { - "strconv", - "FormatInt", - []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("int64")}, - {Name: gno.N("p1"), Type: gno.X("int")}, - }, - []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("string")}, - }, - false, - func(m *gno.Machine) { - b := m.LastBlock() - var ( - p0 int64 - rp0 = reflect.ValueOf(&p0).Elem() - p1 int - rp1 = reflect.ValueOf(&p1).Elem() - ) - - gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 0, "")).TV, rp0) - gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 1, "")).TV, rp1) - - r0 := libs_strconv.FormatInt(p0, p1) - - m.PushValue(gno.Go2GnoValue( - m.Alloc, - m.Store, - reflect.ValueOf(&r0).Elem(), - )) - }, - }, - { - "strconv", - "FormatUint", - []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("uint64")}, - {Name: gno.N("p1"), Type: gno.X("int")}, - }, - []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("string")}, - }, - false, - func(m *gno.Machine) { - b := m.LastBlock() - var ( - p0 uint64 - rp0 = reflect.ValueOf(&p0).Elem() - p1 int - rp1 = reflect.ValueOf(&p1).Elem() - ) - - gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 0, "")).TV, rp0) - gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 1, "")).TV, rp1) - - r0 := libs_strconv.FormatUint(p0, p1) - - m.PushValue(gno.Go2GnoValue( - m.Alloc, - m.Store, - reflect.ValueOf(&r0).Elem(), - )) - }, - }, - { - "strconv", - "Quote", - []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("string")}, - }, - []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("string")}, - }, - false, - func(m *gno.Machine) { - b := m.LastBlock() - var ( - p0 string - rp0 = reflect.ValueOf(&p0).Elem() - ) - - gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 0, "")).TV, rp0) - - r0 := libs_strconv.Quote(p0) - - m.PushValue(gno.Go2GnoValue( - m.Alloc, - m.Store, - reflect.ValueOf(&r0).Elem(), - )) - }, - }, - { - "strconv", - "QuoteToASCII", - []gno.FieldTypeExpr{ - {Name: gno.N("p0"), Type: gno.X("string")}, - }, - []gno.FieldTypeExpr{ - {Name: gno.N("r0"), Type: gno.X("string")}, - }, - false, - func(m *gno.Machine) { - b := m.LastBlock() - var ( - p0 string - rp0 = reflect.ValueOf(&p0).Elem() - ) - - gno.Gno2GoValue(b.GetPointerTo(nil, gno.NewValuePathBlock(1, 0, "")).TV, rp0) - - r0 := libs_strconv.QuoteToASCII(p0) - - m.PushValue(gno.Go2GnoValue( - m.Alloc, - m.Store, - reflect.ValueOf(&r0).Elem(), - )) - }, - }, { "testing", "unixNano", diff --git a/gnovm/stdlibs/strconv/atob.gno b/gnovm/stdlibs/strconv/atob.gno new file mode 100644 index 00000000000..0a495008d77 --- /dev/null +++ b/gnovm/stdlibs/strconv/atob.gno @@ -0,0 +1,35 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strconv + +// ParseBool returns the boolean value represented by the string. +// It accepts 1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False. +// Any other value returns an error. +func ParseBool(str string) (bool, error) { + switch str { + case "1", "t", "T", "true", "TRUE", "True": + return true, nil + case "0", "f", "F", "false", "FALSE", "False": + return false, nil + } + return false, syntaxError("ParseBool", str) +} + +// FormatBool returns "true" or "false" according to the value of b. +func FormatBool(b bool) string { + if b { + return "true" + } + return "false" +} + +// AppendBool appends "true" or "false", according to the value of b, +// to dst and returns the extended buffer. +func AppendBool(dst []byte, b bool) []byte { + if b { + return append(dst, "true"...) + } + return append(dst, "false"...) +} diff --git a/gnovm/stdlibs/strconv/atob_test.gno b/gnovm/stdlibs/strconv/atob_test.gno new file mode 100644 index 00000000000..39746f8953d --- /dev/null +++ b/gnovm/stdlibs/strconv/atob_test.gno @@ -0,0 +1,90 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strconv + +import ( + "bytes" + "testing" +) + +type atobTest struct { + in string + out bool + err error +} + +var atobtests = []atobTest{ + {"", false, ErrSyntax}, + {"asdf", false, ErrSyntax}, + {"0", false, nil}, + {"f", false, nil}, + {"F", false, nil}, + {"FALSE", false, nil}, + {"false", false, nil}, + {"False", false, nil}, + {"1", true, nil}, + {"t", true, nil}, + {"T", true, nil}, + {"TRUE", true, nil}, + {"true", true, nil}, + {"True", true, nil}, +} + +func TestParseBool(t *testing.T) { + for _, test := range atobtests { + b, e := ParseBool(test.in) + if test.err != nil { + // expect an error + if e == nil { + t.Errorf("ParseBool(%s) = nil; want %s", test.in, test.err) + } else { + // NumError assertion must succeed; it's the only thing we return. + if e.(*NumError).Err != test.err { + t.Errorf("ParseBool(%s) = %s; want %s", test.in, e, test.err) + } + } + } else { + if e != nil { + t.Errorf("ParseBool(%s) = %s; want nil", test.in, e) + } + if b != test.out { + t.Errorf("ParseBool(%s) = %t; want %t", test.in, b, test.out) + } + } + } +} + +var boolString = map[bool]string{ + true: "true", + false: "false", +} + +func TestFormatBool(t *testing.T) { + for b, s := range boolString { + if f := FormatBool(b); f != s { + t.Errorf("FormatBool(%v) = %q; want %q", b, f, s) + } + } +} + +type appendBoolTest struct { + b bool + in []byte + out []byte +} + +var appendBoolTests = []appendBoolTest{ + {true, []byte("foo "), []byte("foo true")}, + {false, []byte("foo "), []byte("foo false")}, +} + +func TestAppendBool(t *testing.T) { + for _, test := range appendBoolTests { + b := AppendBool(test.in, test.b) + if !bytes.Equal(b, test.out) { + t.Errorf("AppendBool(%q, %v) = %q; want %q", test.in, test.b, b, test.out) + } + } +} diff --git a/gnovm/stdlibs/strconv/atof.gno b/gnovm/stdlibs/strconv/atof.gno new file mode 100644 index 00000000000..8fc90425f69 --- /dev/null +++ b/gnovm/stdlibs/strconv/atof.gno @@ -0,0 +1,709 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strconv + +// decimal to binary floating point conversion. +// Algorithm: +// 1) Store input in multiprecision decimal. +// 2) Multiply/divide decimal by powers of two until in range [0.5, 1) +// 3) Multiply by 2^precision and round to get mantissa. + +import "math" + +var optimize = true // set to false to force slow-path conversions for testing + +// commonPrefixLenIgnoreCase returns the length of the common +// prefix of s and prefix, with the character case of s ignored. +// The prefix argument must be all lower-case. +func commonPrefixLenIgnoreCase(s, prefix string) int { + n := len(prefix) + if n > len(s) { + n = len(s) + } + for i := 0; i < n; i++ { + c := s[i] + if 'A' <= c && c <= 'Z' { + c += 'a' - 'A' + } + if c != prefix[i] { + return i + } + } + return n +} + +// special returns the floating-point value for the special, +// possibly signed floating-point representations inf, infinity, +// and NaN. The result is ok if a prefix of s contains one +// of these representations and n is the length of that prefix. +// The character case is ignored. +func special(s string) (f float64, n int, ok bool) { + if len(s) == 0 { + return 0, 0, false + } + sign := 1 + nsign := 0 + switch s[0] { + case '+', '-': + if s[0] == '-' { + sign = -1 + } + nsign = 1 + s = s[1:] + fallthrough + case 'i', 'I': + n := commonPrefixLenIgnoreCase(s, "infinity") + // Anything longer than "inf" is ok, but if we + // don't have "infinity", only consume "inf". + if 3 < n && n < 8 { + n = 3 + } + if n == 3 || n == 8 { + return math.Inf(sign), nsign + n, true + } + case 'n', 'N': + if commonPrefixLenIgnoreCase(s, "nan") == 3 { + return math.NaN(), 3, true + } + } + return 0, 0, false +} + +func (b *decimal) set(s string) (ok bool) { + i := 0 + b.neg = false + b.trunc = false + + // optional sign + if i >= len(s) { + return + } + switch { + case s[i] == '+': + i++ + case s[i] == '-': + b.neg = true + i++ + } + + // digits + sawdot := false + sawdigits := false + for ; i < len(s); i++ { + switch { + case s[i] == '_': + // readFloat already checked underscores + continue + case s[i] == '.': + if sawdot { + return + } + sawdot = true + b.dp = b.nd + continue + + case '0' <= s[i] && s[i] <= '9': + sawdigits = true + if s[i] == '0' && b.nd == 0 { // ignore leading zeros + b.dp-- + continue + } + if b.nd < len(b.d) { + b.d[b.nd] = s[i] + b.nd++ + } else if s[i] != '0' { + b.trunc = true + } + continue + } + break + } + if !sawdigits { + return + } + if !sawdot { + b.dp = b.nd + } + + // optional exponent moves decimal point. + // if we read a very large, very long number, + // just be sure to move the decimal point by + // a lot (say, 100000). it doesn't matter if it's + // not the exact number. + if i < len(s) && lower(s[i]) == 'e' { + i++ + if i >= len(s) { + return + } + esign := 1 + if s[i] == '+' { + i++ + } else if s[i] == '-' { + i++ + esign = -1 + } + if i >= len(s) || s[i] < '0' || s[i] > '9' { + return + } + e := 0 + for ; i < len(s) && ('0' <= s[i] && s[i] <= '9' || s[i] == '_'); i++ { + if s[i] == '_' { + // readFloat already checked underscores + continue + } + if e < 10000 { + e = e*10 + int(s[i]) - '0' + } + } + b.dp += e * esign + } + + if i != len(s) { + return + } + + ok = true + return +} + +// readFloat reads a decimal or hexadecimal mantissa and exponent from a float +// string representation in s; the number may be followed by other characters. +// readFloat reports the number of bytes consumed (i), and whether the number +// is valid (ok). +func readFloat(s string) (mantissa uint64, exp int, neg, trunc, hex bool, i int, ok bool) { + underscores := false + + // optional sign + if i >= len(s) { + return + } + switch { + case s[i] == '+': + i++ + case s[i] == '-': + neg = true + i++ + } + + // digits + base := uint64(10) + maxMantDigits := 19 // 10^19 fits in uint64 + expChar := byte('e') + if i+2 < len(s) && s[i] == '0' && lower(s[i+1]) == 'x' { + base = 16 + maxMantDigits = 16 // 16^16 fits in uint64 + i += 2 + expChar = 'p' + hex = true + } + sawdot := false + sawdigits := false + nd := 0 + ndMant := 0 + dp := 0 +loop: + for ; i < len(s); i++ { + switch c := s[i]; true { + case c == '_': + underscores = true + continue + + case c == '.': + if sawdot { + break loop + } + sawdot = true + dp = nd + continue + + case '0' <= c && c <= '9': + sawdigits = true + if c == '0' && nd == 0 { // ignore leading zeros + dp-- + continue + } + nd++ + if ndMant < maxMantDigits { + mantissa *= base + mantissa += uint64(c - '0') + ndMant++ + } else if c != '0' { + trunc = true + } + continue + + case base == 16 && 'a' <= lower(c) && lower(c) <= 'f': + sawdigits = true + nd++ + if ndMant < maxMantDigits { + mantissa *= 16 + mantissa += uint64(lower(c) - 'a' + 10) + ndMant++ + } else { + trunc = true + } + continue + } + break + } + if !sawdigits { + return + } + if !sawdot { + dp = nd + } + + if base == 16 { + dp *= 4 + ndMant *= 4 + } + + // optional exponent moves decimal point. + // if we read a very large, very long number, + // just be sure to move the decimal point by + // a lot (say, 100000). it doesn't matter if it's + // not the exact number. + if i < len(s) && lower(s[i]) == expChar { + i++ + if i >= len(s) { + return + } + esign := 1 + if s[i] == '+' { + i++ + } else if s[i] == '-' { + i++ + esign = -1 + } + if i >= len(s) || s[i] < '0' || s[i] > '9' { + return + } + e := 0 + for ; i < len(s) && ('0' <= s[i] && s[i] <= '9' || s[i] == '_'); i++ { + if s[i] == '_' { + underscores = true + continue + } + if e < 10000 { + e = e*10 + int(s[i]) - '0' + } + } + dp += e * esign + } else if base == 16 { + // Must have exponent. + return + } + + if mantissa != 0 { + exp = dp - ndMant + } + + if underscores && !underscoreOK(s[:i]) { + return + } + + ok = true + return +} + +// decimal power of ten to binary power of two. +var powtab = []int{1, 3, 6, 9, 13, 16, 19, 23, 26} + +func (d *decimal) floatBits(flt *floatInfo) (b uint64, overflow bool) { + var exp int + var mant uint64 + + // Zero is always a special case. + if d.nd == 0 { + mant = 0 + exp = flt.bias + goto out + } + + // Obvious overflow/underflow. + // These bounds are for 64-bit floats. + // Will have to change if we want to support 80-bit floats in the future. + if d.dp > 310 { + goto overflow + } + if d.dp < -330 { + // zero + mant = 0 + exp = flt.bias + goto out + } + + // Scale by powers of two until in range [0.5, 1.0) + exp = 0 + for d.dp > 0 { + var n int + if d.dp >= len(powtab) { + n = 27 + } else { + n = powtab[d.dp] + } + d.Shift(-n) + exp += n + } + for d.dp < 0 || d.dp == 0 && d.d[0] < '5' { + var n int + if -d.dp >= len(powtab) { + n = 27 + } else { + n = powtab[-d.dp] + } + d.Shift(n) + exp -= n + } + + // Our range is [0.5,1) but floating point range is [1,2). + exp-- + + // Minimum representable exponent is flt.bias+1. + // If the exponent is smaller, move it up and + // adjust d accordingly. + if exp < flt.bias+1 { + n := flt.bias + 1 - exp + d.Shift(-n) + exp += n + } + + if exp-flt.bias >= 1<>= 1 + exp++ + if exp-flt.bias >= 1<>float64info.mantbits != 0 { + return + } + f = float64(mantissa) + if neg { + f = -f + } + switch { + case exp == 0: + // an integer. + return f, true + // Exact integers are <= 10^15. + // Exact powers of ten are <= 10^22. + case exp > 0 && exp <= 15+22: // int * 10^k + // If exponent is big but number of digits is not, + // can move a few zeros into the integer part. + if exp > 22 { + f *= float64pow10[exp-22] + exp = 22 + } + if f > 1e15 || f < -1e15 { + // the exponent was really too large. + return + } + return f * float64pow10[exp], true + case exp < 0 && exp >= -22: // int / 10^k + return f / float64pow10[-exp], true + } + return +} + +// If possible to compute mantissa*10^exp to 32-bit float f exactly, +// entirely in floating-point math, do so, avoiding the machinery above. +func atof32exact(mantissa uint64, exp int, neg bool) (f float32, ok bool) { + if mantissa>>float32info.mantbits != 0 { + return + } + f = float32(mantissa) + if neg { + f = -f + } + switch { + case exp == 0: + return f, true + // Exact integers are <= 10^7. + // Exact powers of ten are <= 10^10. + case exp > 0 && exp <= 7+10: // int * 10^k + // If exponent is big but number of digits is not, + // can move a few zeros into the integer part. + if exp > 10 { + f *= float32pow10[exp-10] + exp = 10 + } + if f > 1e7 || f < -1e7 { + // the exponent was really too large. + return + } + return f * float32pow10[exp], true + case exp < 0 && exp >= -10: // int / 10^k + return f / float32pow10[-exp], true + } + return +} + +// atofHex converts the hex floating-point string s +// to a rounded float32 or float64 value (depending on flt==&float32info or flt==&float64info) +// and returns it as a float64. +// The string s has already been parsed into a mantissa, exponent, and sign (neg==true for negative). +// If trunc is true, trailing non-zero bits have been omitted from the mantissa. +func atofHex(s string, flt *floatInfo, mantissa uint64, exp int, neg, trunc bool) (float64, error) { + maxExp := 1<>(flt.mantbits+2) == 0 { + mantissa <<= 1 + exp-- + } + if trunc { + mantissa |= 1 + } + for mantissa>>(1+flt.mantbits+2) != 0 { + mantissa = mantissa>>1 | mantissa&1 + exp++ + } + + // If exponent is too negative, + // denormalize in hopes of making it representable. + // (The -2 is for the rounding bits.) + for mantissa > 1 && exp < minExp-2 { + mantissa = mantissa>>1 | mantissa&1 + exp++ + } + + // Round using two bottom bits. + round := mantissa & 3 + mantissa >>= 2 + round |= mantissa & 1 // round to even (round up if mantissa is odd) + exp += 2 + if round == 3 { + mantissa++ + if mantissa == 1<<(1+flt.mantbits) { + mantissa >>= 1 + exp++ + } + } + + if mantissa>>flt.mantbits == 0 { // Denormal or zero. + exp = flt.bias + } + var err error + if exp > maxExp { // infinity and range error + mantissa = 1 << flt.mantbits + exp = maxExp + 1 + err = rangeError(fnParseFloat, s) + } + + bits := mantissa & (1<", "(", ")", "i", "init"} { + in := test.in + suffix + _, n, err := ParseFloatPrefix(in, 64) + if err != nil { + t.Errorf("ParseFloatPrefix(%q, 64): err = %v; want no error", in, err) + } + if n != len(test.in) { + t.Errorf("ParseFloatPrefix(%q, 64): n = %d; want %d", in, n, len(test.in)) + } + } + } +} + +func errEqual(e1, e2 error) bool { + // XXX: used in place of reflect.DeepEqual + if e1 == nil || e2 == nil { + return e1 == e2 + } + return e1.Error() == e2.Error() +} + +func printError(err error) string { + // XXX: gonative fns (like fmt.Printf, t.Errorf...) do not support printing errors + // and it would be very complicated to add. hence we're simplifying them to strings here. + if err == nil { + return "" + } + return err.Error() +} + +func testAtof(t *testing.T, opt bool) { + initAtof() + oldopt := SetOptimize(opt) + for i := 0; i < len(atoftests); i++ { + test := &atoftests[i] + out, err := ParseFloat(test.in, 64) + outs := FormatFloat(out, 'g', -1, 64) + if outs != test.out || !errEqual(err, test.err) { + t.Errorf("ParseFloat(%v, 64) = %v, %v want %v, %v", + test.in, out, printError(err), test.out, printError(test.err)) + } + + if float64(float32(out)) == out { + out, err := ParseFloat(test.in, 32) + out32 := float32(out) + if float64(out32) != out { + t.Errorf("ParseFloat(%v, 32) = %v, not a float32 (closest is %v)", test.in, out, float64(out32)) + continue + } + outs := FormatFloat(float64(out32), 'g', -1, 32) + if outs != test.out || !errEqual(err, test.err) { + t.Errorf("ParseFloat(%v, 32) = %v, %v want %v, %v # %v", + test.in, out32, printError(err), test.out, printError(test.err), out) + } + } + } + for _, test := range atof32tests { + out, err := ParseFloat(test.in, 32) + out32 := float32(out) + if float64(out32) != out { + t.Errorf("ParseFloat(%v, 32) = %v, not a float32 (closest is %v)", test.in, out, float64(out32)) + continue + } + outs := FormatFloat(float64(out32), 'g', -1, 32) + if outs != test.out || !errEqual(err, test.err) { + t.Errorf("ParseFloat(%v, 32) = %v, %v want %v, %v # %v", + test.in, out32, printError(err), test.out, printError(test.err), out) + } + } + SetOptimize(oldopt) +} + +func TestAtof(t *testing.T) { testAtof(t, true) } + +func TestAtofSlow(t *testing.T) { testAtof(t, false) } + +func TestAtofRandom(t *testing.T) { + initAtof() + for _, test := range atofRandomTests { + x, _ := ParseFloat(test.s, 64) + switch { + default: + t.Errorf("number %s badly parsed as %b (expected %b)", test.s, x, test.x) + case x == test.x: + case math.IsNaN(test.x) && math.IsNaN(x): + } + } + t.Logf("tested %d random numbers", len(atofRandomTests)) +} + +var roundTripCases = []struct { + f float64 + s string +}{ + // Issue 2917. + // This test will break the optimized conversion if the + // FPU is using 80-bit registers instead of 64-bit registers, + // usually because the operating system initialized the + // thread with 80-bit precision and the Go runtime didn't + // fix the FP control word. + {8865794286000691 << 39, "4.87402195346389e+27"}, + {8865794286000692 << 39, "4.8740219534638903e+27"}, +} + +func TestRoundTrip(t *testing.T) { + for _, tt := range roundTripCases { + old := SetOptimize(false) + s := FormatFloat(tt.f, 'g', -1, 64) + if s != tt.s { + t.Errorf("no-opt FormatFloat(%b) = %s, want %s", tt.f, s, tt.s) + } + f, err := ParseFloat(tt.s, 64) + if f != tt.f || err != nil { + t.Errorf("no-opt ParseFloat(%s) = %b, %v want %b, nil", tt.s, f, err, tt.f) + } + SetOptimize(true) + s = FormatFloat(tt.f, 'g', -1, 64) + if s != tt.s { + t.Errorf("opt FormatFloat(%b) = %s, want %s", tt.f, s, tt.s) + } + f, err = ParseFloat(tt.s, 64) + if f != tt.f || err != nil { + t.Errorf("opt ParseFloat(%s) = %b, %v want %b, nil", tt.s, f, err, tt.f) + } + SetOptimize(old) + } +} + +// TestRoundTrip32 tries a fraction of all finite positive float32 values. +func TestRoundTrip32(t *testing.T) { + step := uint32(997) + if testing.Short() { + step = 99991 + } + count := 0 + for i := uint32(0); i < 0xff<<23; i += step { + f := math.Float32frombits(i) + if i&1 == 1 { + f = -f // negative + } + s := FormatFloat(float64(f), 'g', -1, 32) + + parsed, err := ParseFloat(s, 32) + parsed32 := float32(parsed) + switch { + case err != nil: + t.Errorf("ParseFloat(%q, 32) gave error %s", s, err) + case float64(parsed32) != parsed: + t.Errorf("ParseFloat(%q, 32) = %v, not a float32 (nearest is %v)", s, parsed, parsed32) + case parsed32 != f: + t.Errorf("ParseFloat(%q, 32) = %b (expected %b)", s, parsed32, f) + } + count++ + } + t.Logf("tested %d float32's", count) +} + +// Issue 42297: a lot of code in the wild accidentally calls ParseFloat(s, 10) +// or ParseFloat(s, 0), so allow bitSize values other than 32 and 64. +func TestParseFloatIncorrectBitSize(t *testing.T) { + const s = "1.5e308" + const want = 1.5e308 + + for _, bitSize := range []int{0, 10, 100, 128} { + f, err := ParseFloat(s, bitSize) + if err != nil { + t.Fatalf("ParseFloat(%q, %d) gave error %s", s, bitSize, err) + } + if f != want { + t.Fatalf("ParseFloat(%q, %d) = %g (expected %g)", s, bitSize, f, want) + } + } +} + +func BenchmarkAtof64Decimal(b *testing.B) { + for i := 0; i < b.N; i++ { + ParseFloat("33909", 64) + } +} + +func BenchmarkAtof64Float(b *testing.B) { + for i := 0; i < b.N; i++ { + ParseFloat("339.7784", 64) + } +} + +func BenchmarkAtof64FloatExp(b *testing.B) { + for i := 0; i < b.N; i++ { + ParseFloat("-5.09e75", 64) + } +} + +func BenchmarkAtof64Big(b *testing.B) { + for i := 0; i < b.N; i++ { + ParseFloat("123456789123456789123456789", 64) + } +} + +func BenchmarkAtof64RandomBits(b *testing.B) { + initAtof() + b.ResetTimer() + for i := 0; i < b.N; i++ { + ParseFloat(benchmarksRandomBits[i%1024], 64) + } +} + +func BenchmarkAtof64RandomFloats(b *testing.B) { + initAtof() + b.ResetTimer() + for i := 0; i < b.N; i++ { + ParseFloat(benchmarksRandomNormal[i%1024], 64) + } +} + +func BenchmarkAtof64RandomLongFloats(b *testing.B) { + initAtof() + samples := make([]string, len(atofRandomTests)) + for i, t := range atofRandomTests { + samples[i] = FormatFloat(t.x, 'g', 20, 64) + } + b.ResetTimer() + idx := 0 + for i := 0; i < b.N; i++ { + ParseFloat(samples[idx], 64) + idx++ + if idx == len(samples) { + idx = 0 + } + } +} + +func BenchmarkAtof32Decimal(b *testing.B) { + for i := 0; i < b.N; i++ { + ParseFloat("33909", 32) + } +} + +func BenchmarkAtof32Float(b *testing.B) { + for i := 0; i < b.N; i++ { + ParseFloat("339.778", 32) + } +} + +func BenchmarkAtof32FloatExp(b *testing.B) { + for i := 0; i < b.N; i++ { + ParseFloat("12.3456e32", 32) + } +} + +func BenchmarkAtof32Random(b *testing.B) { + n := uint32(997) + var float32strings [4096]string + for i := range float32strings { + n = (99991*n + 42) % (0xff << 23) + float32strings[i] = FormatFloat(float64(math.Float32frombits(n)), 'g', -1, 32) + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + ParseFloat(float32strings[i%4096], 32) + } +} + +func BenchmarkAtof32RandomLong(b *testing.B) { + n := uint32(997) + var float32strings [4096]string + for i := range float32strings { + n = (99991*n + 42) % (0xff << 23) + float32strings[i] = FormatFloat(float64(math.Float32frombits(n)), 'g', 20, 32) + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + ParseFloat(float32strings[i%4096], 32) + } +} diff --git a/gnovm/stdlibs/strconv/atoi.gno b/gnovm/stdlibs/strconv/atoi.gno new file mode 100644 index 00000000000..28b8e7f0b14 --- /dev/null +++ b/gnovm/stdlibs/strconv/atoi.gno @@ -0,0 +1,332 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strconv + +import "errors" + +// lower(c) is a lower-case letter if and only if +// c is either that lower-case letter or the equivalent upper-case letter. +// Instead of writing c == 'x' || c == 'X' one can write lower(c) == 'x'. +// Note that lower of non-letters can produce other non-letters. +func lower(c byte) byte { + return c | ('x' - 'X') +} + +// ErrRange indicates that a value is out of range for the target type. +var ErrRange = errors.New("value out of range") + +// ErrSyntax indicates that a value does not have the right syntax for the target type. +var ErrSyntax = errors.New("invalid syntax") + +// A NumError records a failed conversion. +type NumError struct { + Func string // the failing function (ParseBool, ParseInt, ParseUint, ParseFloat) + Num string // the input + Err error // the reason the conversion failed (e.g. ErrRange, ErrSyntax, etc.) +} + +func (e *NumError) Error() string { + return "strconv." + e.Func + ": " + "parsing " + Quote(e.Num) + ": " + e.Err.Error() +} + +func (e *NumError) Unwrap() error { return e.Err } + +// cloneString returns a string copy of x. +// +// All ParseXXX functions allow the input string to escape to the error value. +// This hurts strconv.ParseXXX(string(b)) calls where b is []byte since +// the conversion from []byte must allocate a string on the heap. +// If we assume errors are infrequent, then we can avoid escaping the input +// back to the output by copying it first. This allows the compiler to call +// strconv.ParseXXX without a heap allocation for most []byte to string +// conversions, since it can now prove that the string cannot escape Parse. +// +// TODO: Use strings.Clone instead? However, we cannot depend on "strings" +// since it incurs a transitive dependency on "unicode". +// Either move strings.Clone to an internal/bytealg or make the +// "strings" to "unicode" dependency lighter (see https://go.dev/issue/54098). +func cloneString(x string) string { return string([]byte(x)) } + +func syntaxError(fn, str string) *NumError { + return &NumError{fn, cloneString(str), ErrSyntax} +} + +func rangeError(fn, str string) *NumError { + return &NumError{fn, cloneString(str), ErrRange} +} + +func baseError(fn, str string, base int) *NumError { + return &NumError{fn, cloneString(str), errors.New("invalid base " + Itoa(base))} +} + +func bitSizeError(fn, str string, bitSize int) *NumError { + return &NumError{fn, cloneString(str), errors.New("invalid bit size " + Itoa(bitSize))} +} + +const intSize = 32 << (^uint(0) >> 63) + +// IntSize is the size in bits of an int or uint value. +const IntSize = intSize + +const maxUint64 = 1<<64 - 1 + +// ParseUint is like ParseInt but for unsigned numbers. +// +// A sign prefix is not permitted. +func ParseUint(s string, base int, bitSize int) (uint64, error) { + const fnParseUint = "ParseUint" + + if s == "" { + return 0, syntaxError(fnParseUint, s) + } + + base0 := base == 0 + + s0 := s + switch { + case 2 <= base && base <= 36: + // valid base; nothing to do + + case base == 0: + // Look for octal, hex prefix. + base = 10 + if s[0] == '0' { + switch { + case len(s) >= 3 && lower(s[1]) == 'b': + base = 2 + s = s[2:] + case len(s) >= 3 && lower(s[1]) == 'o': + base = 8 + s = s[2:] + case len(s) >= 3 && lower(s[1]) == 'x': + base = 16 + s = s[2:] + default: + base = 8 + s = s[1:] + } + } + + default: + return 0, baseError(fnParseUint, s0, base) + } + + if bitSize == 0 { + bitSize = IntSize + } else if bitSize < 0 || bitSize > 64 { + return 0, bitSizeError(fnParseUint, s0, bitSize) + } + + // Cutoff is the smallest number such that cutoff*base > maxUint64. + // Use compile-time constants for common cases. + var cutoff uint64 + switch base { + case 10: + cutoff = maxUint64/10 + 1 + case 16: + cutoff = maxUint64/16 + 1 + default: + cutoff = maxUint64/uint64(base) + 1 + } + + maxVal := uint64(1)<= byte(base) { + return 0, syntaxError(fnParseUint, s0) + } + + if n >= cutoff { + // n*base overflows + return maxVal, rangeError(fnParseUint, s0) + } + n *= uint64(base) + + n1 := n + uint64(d) + if n1 < n || n1 > maxVal { + // n+d overflows + return maxVal, rangeError(fnParseUint, s0) + } + n = n1 + } + + if underscores && !underscoreOK(s0) { + return 0, syntaxError(fnParseUint, s0) + } + + return n, nil +} + +// ParseInt interprets a string s in the given base (0, 2 to 36) and +// bit size (0 to 64) and returns the corresponding value i. +// +// The string may begin with a leading sign: "+" or "-". +// +// If the base argument is 0, the true base is implied by the string's +// prefix following the sign (if present): 2 for "0b", 8 for "0" or "0o", +// 16 for "0x", and 10 otherwise. Also, for argument base 0 only, +// underscore characters are permitted as defined by the Go syntax for +// [integer literals]. +// +// The bitSize argument specifies the integer type +// that the result must fit into. Bit sizes 0, 8, 16, 32, and 64 +// correspond to int, int8, int16, int32, and int64. +// If bitSize is below 0 or above 64, an error is returned. +// +// The errors that ParseInt returns have concrete type *NumError +// and include err.Num = s. If s is empty or contains invalid +// digits, err.Err = ErrSyntax and the returned value is 0; +// if the value corresponding to s cannot be represented by a +// signed integer of the given size, err.Err = ErrRange and the +// returned value is the maximum magnitude integer of the +// appropriate bitSize and sign. +// +// [integer literals]: https://go.dev/ref/spec#Integer_literals +func ParseInt(s string, base int, bitSize int) (i int64, err error) { + const fnParseInt = "ParseInt" + + if s == "" { + return 0, syntaxError(fnParseInt, s) + } + + // Pick off leading sign. + s0 := s + neg := false + if s[0] == '+' { + s = s[1:] + } else if s[0] == '-' { + neg = true + s = s[1:] + } + + // Convert unsigned and check range. + var un uint64 + un, err = ParseUint(s, base, bitSize) + if err != nil && err.(*NumError).Err != ErrRange { + err.(*NumError).Func = fnParseInt + err.(*NumError).Num = cloneString(s0) + return 0, err + } + + if bitSize == 0 { + bitSize = IntSize + } + + cutoff := uint64(1 << uint(bitSize-1)) + if !neg && un >= cutoff { + return int64(cutoff - 1), rangeError(fnParseInt, s0) + } + if neg && un > cutoff { + return -int64(cutoff), rangeError(fnParseInt, s0) + } + n := int64(un) + if neg { + n = -n + } + return n, nil +} + +// Atoi is equivalent to ParseInt(s, 10, 0), converted to type int. +func Atoi(s string) (int, error) { + const fnAtoi = "Atoi" + + sLen := len(s) + if intSize == 32 && (0 < sLen && sLen < 10) || + intSize == 64 && (0 < sLen && sLen < 19) { + // Fast path for small integers that fit int type. + s0 := s + if s[0] == '-' || s[0] == '+' { + s = s[1:] + if len(s) < 1 { + return 0, syntaxError(fnAtoi, s0) + } + } + + n := 0 + for _, ch := range []byte(s) { + ch -= '0' + if ch > 9 { + return 0, syntaxError(fnAtoi, s0) + } + n = n*10 + int(ch) + } + if s0[0] == '-' { + n = -n + } + return n, nil + } + + // Slow path for invalid, big, or underscored integers. + i64, err := ParseInt(s, 10, 0) + if nerr, ok := err.(*NumError); ok { + nerr.Func = fnAtoi + } + return int(i64), err +} + +// underscoreOK reports whether the underscores in s are allowed. +// Checking them in this one function lets all the parsers skip over them simply. +// Underscore must appear only between digits or between a base prefix and a digit. +func underscoreOK(s string) bool { + // saw tracks the last character (class) we saw: + // ^ for beginning of number, + // 0 for a digit or base prefix, + // _ for an underscore, + // ! for none of the above. + saw := '^' + i := 0 + + // Optional sign. + if len(s) >= 1 && (s[0] == '-' || s[0] == '+') { + s = s[1:] + } + + // Optional base prefix. + hex := false + if len(s) >= 2 && s[0] == '0' && (lower(s[1]) == 'b' || lower(s[1]) == 'o' || lower(s[1]) == 'x') { + i = 2 + saw = '0' // base prefix counts as a digit for "underscore as digit separator" + hex = lower(s[1]) == 'x' + } + + // Number proper. + for ; i < len(s); i++ { + // Digits are always okay. + if '0' <= s[i] && s[i] <= '9' || hex && 'a' <= lower(s[i]) && lower(s[i]) <= 'f' { + saw = '0' + continue + } + // Underscore must follow digit. + if s[i] == '_' { + if saw != '0' { + return false + } + saw = '_' + continue + } + // Underscore must also be followed by digit. + if saw == '_' { + return false + } + // Saw non-digit, non-underscore. + saw = '!' + } + return saw != '_' +} diff --git a/gnovm/stdlibs/strconv/atoi_test.gno b/gnovm/stdlibs/strconv/atoi_test.gno new file mode 100644 index 00000000000..cb150628f5c --- /dev/null +++ b/gnovm/stdlibs/strconv/atoi_test.gno @@ -0,0 +1,677 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strconv + +import ( + "errors" + "fmt" + "testing" +) + +type parseUint64Test struct { + in string + out uint64 + err error +} + +var parseUint64Tests = []parseUint64Test{ + {"", 0, ErrSyntax}, + {"0", 0, nil}, + {"1", 1, nil}, + {"12345", 12345, nil}, + {"012345", 12345, nil}, + {"12345x", 0, ErrSyntax}, + {"98765432100", 98765432100, nil}, + {"18446744073709551615", 1<<64 - 1, nil}, + {"18446744073709551616", 1<<64 - 1, ErrRange}, + {"18446744073709551620", 1<<64 - 1, ErrRange}, + {"1_2_3_4_5", 0, ErrSyntax}, // base=10 so no underscores allowed + {"_12345", 0, ErrSyntax}, + {"1__2345", 0, ErrSyntax}, + {"12345_", 0, ErrSyntax}, + {"-0", 0, ErrSyntax}, + {"-1", 0, ErrSyntax}, + {"+1", 0, ErrSyntax}, +} + +type parseUint64BaseTest struct { + in string + base int + out uint64 + err error +} + +var parseUint64BaseTests = []parseUint64BaseTest{ + {"", 0, 0, ErrSyntax}, + {"0", 0, 0, nil}, + {"0x", 0, 0, ErrSyntax}, + {"0X", 0, 0, ErrSyntax}, + {"1", 0, 1, nil}, + {"12345", 0, 12345, nil}, + {"012345", 0, 012345, nil}, + {"0x12345", 0, 0x12345, nil}, + {"0X12345", 0, 0x12345, nil}, + {"12345x", 0, 0, ErrSyntax}, + {"0xabcdefg123", 0, 0, ErrSyntax}, + {"123456789abc", 0, 0, ErrSyntax}, + {"98765432100", 0, 98765432100, nil}, + {"18446744073709551615", 0, 1<<64 - 1, nil}, + {"18446744073709551616", 0, 1<<64 - 1, ErrRange}, + {"18446744073709551620", 0, 1<<64 - 1, ErrRange}, + {"0xFFFFFFFFFFFFFFFF", 0, 1<<64 - 1, nil}, + {"0x10000000000000000", 0, 1<<64 - 1, ErrRange}, + {"01777777777777777777777", 0, 1<<64 - 1, nil}, + {"01777777777777777777778", 0, 0, ErrSyntax}, + {"02000000000000000000000", 0, 1<<64 - 1, ErrRange}, + {"0200000000000000000000", 0, 1 << 61, nil}, + {"0b", 0, 0, ErrSyntax}, + {"0B", 0, 0, ErrSyntax}, + {"0b101", 0, 5, nil}, + {"0B101", 0, 5, nil}, + {"0o", 0, 0, ErrSyntax}, + {"0O", 0, 0, ErrSyntax}, + {"0o377", 0, 255, nil}, + {"0O377", 0, 255, nil}, + + // underscores allowed with base == 0 only + {"1_2_3_4_5", 0, 12345, nil}, // base 0 => 10 + {"_12345", 0, 0, ErrSyntax}, + {"1__2345", 0, 0, ErrSyntax}, + {"12345_", 0, 0, ErrSyntax}, + + {"1_2_3_4_5", 10, 0, ErrSyntax}, // base 10 + {"_12345", 10, 0, ErrSyntax}, + {"1__2345", 10, 0, ErrSyntax}, + {"12345_", 10, 0, ErrSyntax}, + + {"0x_1_2_3_4_5", 0, 0x12345, nil}, // base 0 => 16 + {"_0x12345", 0, 0, ErrSyntax}, + {"0x__12345", 0, 0, ErrSyntax}, + {"0x1__2345", 0, 0, ErrSyntax}, + {"0x1234__5", 0, 0, ErrSyntax}, + {"0x12345_", 0, 0, ErrSyntax}, + + {"1_2_3_4_5", 16, 0, ErrSyntax}, // base 16 + {"_12345", 16, 0, ErrSyntax}, + {"1__2345", 16, 0, ErrSyntax}, + {"1234__5", 16, 0, ErrSyntax}, + {"12345_", 16, 0, ErrSyntax}, + + {"0_1_2_3_4_5", 0, 012345, nil}, // base 0 => 8 (0377) + {"_012345", 0, 0, ErrSyntax}, + {"0__12345", 0, 0, ErrSyntax}, + {"01234__5", 0, 0, ErrSyntax}, + {"012345_", 0, 0, ErrSyntax}, + + {"0o_1_2_3_4_5", 0, 012345, nil}, // base 0 => 8 (0o377) + {"_0o12345", 0, 0, ErrSyntax}, + {"0o__12345", 0, 0, ErrSyntax}, + {"0o1234__5", 0, 0, ErrSyntax}, + {"0o12345_", 0, 0, ErrSyntax}, + + {"0_1_2_3_4_5", 8, 0, ErrSyntax}, // base 8 + {"_012345", 8, 0, ErrSyntax}, + {"0__12345", 8, 0, ErrSyntax}, + {"01234__5", 8, 0, ErrSyntax}, + {"012345_", 8, 0, ErrSyntax}, + + {"0b_1_0_1", 0, 5, nil}, // base 0 => 2 (0b101) + {"_0b101", 0, 0, ErrSyntax}, + {"0b__101", 0, 0, ErrSyntax}, + {"0b1__01", 0, 0, ErrSyntax}, + {"0b10__1", 0, 0, ErrSyntax}, + {"0b101_", 0, 0, ErrSyntax}, + + {"1_0_1", 2, 0, ErrSyntax}, // base 2 + {"_101", 2, 0, ErrSyntax}, + {"1_01", 2, 0, ErrSyntax}, + {"10_1", 2, 0, ErrSyntax}, + {"101_", 2, 0, ErrSyntax}, +} + +type parseInt64Test struct { + in string + out int64 + err error +} + +var parseInt64Tests = []parseInt64Test{ + {"", 0, ErrSyntax}, + {"0", 0, nil}, + {"-0", 0, nil}, + {"+0", 0, nil}, + {"1", 1, nil}, + {"-1", -1, nil}, + {"+1", 1, nil}, + {"12345", 12345, nil}, + {"-12345", -12345, nil}, + {"012345", 12345, nil}, + {"-012345", -12345, nil}, + {"98765432100", 98765432100, nil}, + {"-98765432100", -98765432100, nil}, + {"9223372036854775807", 1<<63 - 1, nil}, + {"-9223372036854775807", -(1<<63 - 1), nil}, + {"9223372036854775808", 1<<63 - 1, ErrRange}, + {"-9223372036854775808", -1 << 63, nil}, + {"9223372036854775809", 1<<63 - 1, ErrRange}, + {"-9223372036854775809", -1 << 63, ErrRange}, + {"-1_2_3_4_5", 0, ErrSyntax}, // base=10 so no underscores allowed + {"-_12345", 0, ErrSyntax}, + {"_12345", 0, ErrSyntax}, + {"1__2345", 0, ErrSyntax}, + {"12345_", 0, ErrSyntax}, + {"123%45", 0, ErrSyntax}, +} + +type parseInt64BaseTest struct { + in string + base int + out int64 + err error +} + +var parseInt64BaseTests = []parseInt64BaseTest{ + {"", 0, 0, ErrSyntax}, + {"0", 0, 0, nil}, + {"-0", 0, 0, nil}, + {"1", 0, 1, nil}, + {"-1", 0, -1, nil}, + {"12345", 0, 12345, nil}, + {"-12345", 0, -12345, nil}, + {"012345", 0, 012345, nil}, + {"-012345", 0, -012345, nil}, + {"0x12345", 0, 0x12345, nil}, + {"-0X12345", 0, -0x12345, nil}, + {"12345x", 0, 0, ErrSyntax}, + {"-12345x", 0, 0, ErrSyntax}, + {"98765432100", 0, 98765432100, nil}, + {"-98765432100", 0, -98765432100, nil}, + {"9223372036854775807", 0, 1<<63 - 1, nil}, + {"-9223372036854775807", 0, -(1<<63 - 1), nil}, + {"9223372036854775808", 0, 1<<63 - 1, ErrRange}, + {"-9223372036854775808", 0, -1 << 63, nil}, + {"9223372036854775809", 0, 1<<63 - 1, ErrRange}, + {"-9223372036854775809", 0, -1 << 63, ErrRange}, + + // other bases + {"g", 17, 16, nil}, + {"10", 25, 25, nil}, + {"holycow", 35, (((((17*35+24)*35+21)*35+34)*35+12)*35+24)*35 + 32, nil}, + {"holycow", 36, (((((17*36+24)*36+21)*36+34)*36+12)*36+24)*36 + 32, nil}, + + // base 2 + {"0", 2, 0, nil}, + {"-1", 2, -1, nil}, + {"1010", 2, 10, nil}, + {"1000000000000000", 2, 1 << 15, nil}, + {"111111111111111111111111111111111111111111111111111111111111111", 2, 1<<63 - 1, nil}, + {"1000000000000000000000000000000000000000000000000000000000000000", 2, 1<<63 - 1, ErrRange}, + {"-1000000000000000000000000000000000000000000000000000000000000000", 2, -1 << 63, nil}, + {"-1000000000000000000000000000000000000000000000000000000000000001", 2, -1 << 63, ErrRange}, + + // base 8 + {"-10", 8, -8, nil}, + {"57635436545", 8, 057635436545, nil}, + {"100000000", 8, 1 << 24, nil}, + + // base 16 + {"10", 16, 16, nil}, + {"-123456789abcdef", 16, -0x123456789abcdef, nil}, + {"7fffffffffffffff", 16, 1<<63 - 1, nil}, + + // underscores + {"-0x_1_2_3_4_5", 0, -0x12345, nil}, + {"0x_1_2_3_4_5", 0, 0x12345, nil}, + {"-_0x12345", 0, 0, ErrSyntax}, + {"_-0x12345", 0, 0, ErrSyntax}, + {"_0x12345", 0, 0, ErrSyntax}, + {"0x__12345", 0, 0, ErrSyntax}, + {"0x1__2345", 0, 0, ErrSyntax}, + {"0x1234__5", 0, 0, ErrSyntax}, + {"0x12345_", 0, 0, ErrSyntax}, + + {"-0_1_2_3_4_5", 0, -012345, nil}, // octal + {"0_1_2_3_4_5", 0, 012345, nil}, // octal + {"-_012345", 0, 0, ErrSyntax}, + {"_-012345", 0, 0, ErrSyntax}, + {"_012345", 0, 0, ErrSyntax}, + {"0__12345", 0, 0, ErrSyntax}, + {"01234__5", 0, 0, ErrSyntax}, + {"012345_", 0, 0, ErrSyntax}, + + {"+0xf", 0, 0xf, nil}, + {"-0xf", 0, -0xf, nil}, + {"0x+f", 0, 0, ErrSyntax}, + {"0x-f", 0, 0, ErrSyntax}, +} + +type parseUint32Test struct { + in string + out uint32 + err error +} + +var parseUint32Tests = []parseUint32Test{ + {"", 0, ErrSyntax}, + {"0", 0, nil}, + {"1", 1, nil}, + {"12345", 12345, nil}, + {"012345", 12345, nil}, + {"12345x", 0, ErrSyntax}, + {"987654321", 987654321, nil}, + {"4294967295", 1<<32 - 1, nil}, + {"4294967296", 1<<32 - 1, ErrRange}, + {"1_2_3_4_5", 0, ErrSyntax}, // base=10 so no underscores allowed + {"_12345", 0, ErrSyntax}, + {"_12345", 0, ErrSyntax}, + {"1__2345", 0, ErrSyntax}, + {"12345_", 0, ErrSyntax}, +} + +type parseInt32Test struct { + in string + out int32 + err error +} + +var parseInt32Tests = []parseInt32Test{ + {"", 0, ErrSyntax}, + {"0", 0, nil}, + {"-0", 0, nil}, + {"1", 1, nil}, + {"-1", -1, nil}, + {"12345", 12345, nil}, + {"-12345", -12345, nil}, + {"012345", 12345, nil}, + {"-012345", -12345, nil}, + {"12345x", 0, ErrSyntax}, + {"-12345x", 0, ErrSyntax}, + {"987654321", 987654321, nil}, + {"-987654321", -987654321, nil}, + {"2147483647", 1<<31 - 1, nil}, + {"-2147483647", -(1<<31 - 1), nil}, + {"2147483648", 1<<31 - 1, ErrRange}, + {"-2147483648", -1 << 31, nil}, + {"2147483649", 1<<31 - 1, ErrRange}, + {"-2147483649", -1 << 31, ErrRange}, + {"-1_2_3_4_5", 0, ErrSyntax}, // base=10 so no underscores allowed + {"-_12345", 0, ErrSyntax}, + {"_12345", 0, ErrSyntax}, + {"1__2345", 0, ErrSyntax}, + {"12345_", 0, ErrSyntax}, + {"123%45", 0, ErrSyntax}, +} + +type numErrorTest struct { + num, want string +} + +var numErrorTests = []numErrorTest{ + {"0", `strconv.ParseFloat: parsing "0": failed`}, + {"`", "strconv.ParseFloat: parsing \"`\": failed"}, + {"1\x00.2", `strconv.ParseFloat: parsing "1\x00.2": failed`}, +} + +func init() { + // The parse routines return NumErrors wrapping + // the error and the string. Convert the tables above. + for i := range parseUint64Tests { + test := &parseUint64Tests[i] + if test.err != nil { + test.err = &NumError{"ParseUint", test.in, test.err} + } + } + for i := range parseUint64BaseTests { + test := &parseUint64BaseTests[i] + if test.err != nil { + test.err = &NumError{"ParseUint", test.in, test.err} + } + } + for i := range parseInt64Tests { + test := &parseInt64Tests[i] + if test.err != nil { + test.err = &NumError{"ParseInt", test.in, test.err} + } + } + for i := range parseInt64BaseTests { + test := &parseInt64BaseTests[i] + if test.err != nil { + test.err = &NumError{"ParseInt", test.in, test.err} + } + } + for i := range parseUint32Tests { + test := &parseUint32Tests[i] + if test.err != nil { + test.err = &NumError{"ParseUint", test.in, test.err} + } + } + for i := range parseInt32Tests { + test := &parseInt32Tests[i] + if test.err != nil { + test.err = &NumError{"ParseInt", test.in, test.err} + } + } +} + +func TestParseUint32(t *testing.T) { + for i := range parseUint32Tests { + test := &parseUint32Tests[i] + out, err := ParseUint(test.in, 10, 32) + if uint64(test.out) != out || !errEqual(test.err, err) { + t.Errorf("ParseUint(%q, 10, 32) = %v, %v want %v, %v", + test.in, out, err, test.out, test.err) + } + } +} + +func TestParseUint64(t *testing.T) { + for i := range parseUint64Tests { + test := &parseUint64Tests[i] + out, err := ParseUint(test.in, 10, 64) + if test.out != out || !errEqual(test.err, err) { + t.Errorf("ParseUint(%q, 10, 64) = %v, %v want %v, %v", + test.in, out, err, test.out, test.err) + } + } +} + +func TestParseUint64Base(t *testing.T) { + for i := range parseUint64BaseTests { + test := &parseUint64BaseTests[i] + out, err := ParseUint(test.in, test.base, 64) + if test.out != out || !errEqual(test.err, err) { + t.Errorf("ParseUint(%q, %v, 64) = %v, %v want %v, %v", + test.in, test.base, out, err, test.out, test.err) + } + } +} + +func TestParseInt32(t *testing.T) { + for i := range parseInt32Tests { + test := &parseInt32Tests[i] + out, err := ParseInt(test.in, 10, 32) + if int64(test.out) != out || !errEqual(test.err, err) { + t.Errorf("ParseInt(%q, 10 ,32) = %v, %v want %v, %v", + test.in, out, err, test.out, test.err) + } + } +} + +func TestParseInt64(t *testing.T) { + for i := range parseInt64Tests { + test := &parseInt64Tests[i] + out, err := ParseInt(test.in, 10, 64) + if test.out != out || !errEqual(test.err, err) { + t.Errorf("ParseInt(%q, 10, 64) = %v, %v want %v, %v", + test.in, out, err, test.out, test.err) + } + } +} + +func TestParseInt64Base(t *testing.T) { + for i := range parseInt64BaseTests { + test := &parseInt64BaseTests[i] + out, err := ParseInt(test.in, test.base, 64) + if test.out != out || !errEqual(test.err, err) { + t.Errorf("ParseInt(%q, %v, 64) = %v, %v want %v, %v", + test.in, test.base, out, err, test.out, test.err) + } + } +} + +func TestParseUint(t *testing.T) { + switch IntSize { + case 32: + for i := range parseUint32Tests { + test := &parseUint32Tests[i] + out, err := ParseUint(test.in, 10, 0) + if uint64(test.out) != out || !errEqual(test.err, err) { + t.Errorf("ParseUint(%q, 10, 0) = %v, %v want %v, %v", + test.in, out, err, test.out, test.err) + } + } + case 64: + for i := range parseUint64Tests { + test := &parseUint64Tests[i] + out, err := ParseUint(test.in, 10, 0) + if test.out != out || !errEqual(test.err, err) { + t.Errorf("ParseUint(%q, 10, 0) = %v, %v want %v, %v", + test.in, out, err, test.out, test.err) + } + } + } +} + +func TestParseInt(t *testing.T) { + switch IntSize { + case 32: + for i := range parseInt32Tests { + test := &parseInt32Tests[i] + out, err := ParseInt(test.in, 10, 0) + if int64(test.out) != out || !errEqual(test.err, err) { + t.Errorf("ParseInt(%q, 10, 0) = %v, %v want %v, %v", + test.in, out, err, test.out, test.err) + } + } + case 64: + for i := range parseInt64Tests { + test := &parseInt64Tests[i] + out, err := ParseInt(test.in, 10, 0) + if test.out != out || !errEqual(test.err, err) { + t.Errorf("ParseInt(%q, 10, 0) = %v, %v want %v, %v", + test.in, out, err, test.out, test.err) + } + } + } +} + +func TestAtoi(t *testing.T) { + switch IntSize { + case 32: + for i := range parseInt32Tests { + test := &parseInt32Tests[i] + out, err := Atoi(test.in) + var testErr error + if test.err != nil { + testErr = &NumError{"Atoi", test.in, test.err.(*NumError).Err} + } + if int(test.out) != out || !errEqual(testErr, err) { + t.Errorf("Atoi(%q) = %v, %v want %v, %v", + test.in, out, err, test.out, testErr) + } + } + case 64: + for i := range parseInt64Tests { + test := &parseInt64Tests[i] + out, err := Atoi(test.in) + var testErr error + if test.err != nil { + testErr = &NumError{"Atoi", test.in, test.err.(*NumError).Err} + } + if test.out != int64(out) || !errEqual(testErr, err) { + t.Errorf("Atoi(%q) = %v, %v want %v, %v", + test.in, out, err, test.out, testErr) + } + } + } +} + +func bitSizeErrStub(name string, bitSize int) error { + return BitSizeError(name, "0", bitSize) +} + +func baseErrStub(name string, base int) error { + return BaseError(name, "0", base) +} + +func noErrStub(name string, arg int) error { + return nil +} + +type parseErrorTest struct { + arg int + errStub func(name string, arg int) error +} + +var parseBitSizeTests = []parseErrorTest{ + {-1, bitSizeErrStub}, + {0, noErrStub}, + {64, noErrStub}, + {65, bitSizeErrStub}, +} + +var parseBaseTests = []parseErrorTest{ + {-1, baseErrStub}, + {0, noErrStub}, + {1, baseErrStub}, + {2, noErrStub}, + {36, noErrStub}, + {37, baseErrStub}, +} + +func equalError(a, b error) bool { + if a == nil { + return b == nil + } + if b == nil { + return a == nil + } + return a.Error() == b.Error() +} + +func TestParseIntBitSize(t *testing.T) { + for i := range parseBitSizeTests { + test := &parseBitSizeTests[i] + testErr := test.errStub("ParseInt", test.arg) + _, err := ParseInt("0", 0, test.arg) + if !equalError(testErr, err) { + t.Errorf("ParseInt(\"0\", 0, %v) = 0, %v want 0, %v", + test.arg, err, testErr) + } + } +} + +func TestParseUintBitSize(t *testing.T) { + for i := range parseBitSizeTests { + test := &parseBitSizeTests[i] + testErr := test.errStub("ParseUint", test.arg) + _, err := ParseUint("0", 0, test.arg) + if !equalError(testErr, err) { + t.Errorf("ParseUint(\"0\", 0, %v) = 0, %v want 0, %v", + test.arg, err, testErr) + } + } +} + +func TestParseIntBase(t *testing.T) { + for i := range parseBaseTests { + test := &parseBaseTests[i] + testErr := test.errStub("ParseInt", test.arg) + _, err := ParseInt("0", test.arg, 0) + if !equalError(testErr, err) { + t.Errorf("ParseInt(\"0\", %v, 0) = 0, %v want 0, %v", + test.arg, err, testErr) + } + } +} + +func TestParseUintBase(t *testing.T) { + for i := range parseBaseTests { + test := &parseBaseTests[i] + testErr := test.errStub("ParseUint", test.arg) + _, err := ParseUint("0", test.arg, 0) + if !equalError(testErr, err) { + t.Errorf("ParseUint(\"0\", %v, 0) = 0, %v want 0, %v", + test.arg, err, testErr) + } + } +} + +func TestNumError(t *testing.T) { + for _, test := range numErrorTests { + err := &NumError{ + Func: "ParseFloat", + Num: test.num, + Err: errors.New("failed"), + } + if got := err.Error(); got != test.want { + t.Errorf(`(&NumError{"ParseFloat", %q, "failed"}).Error() = %v, want %v`, test.num, got, test.want) + } + } +} + +/* XXX: add when we support reflection / error un/wrapping. +func TestNumErrorUnwrap(t *testing.T) { + err := &NumError{Err: ErrSyntax} + if !errEqual(err, ErrSyntax) { + t.Error("errors.Is failed, wanted success") + } +} +*/ + +func BenchmarkParseInt(b *testing.B) { + b.Run("Pos", func(b *testing.B) { + benchmarkParseInt(b, 1) + }) + b.Run("Neg", func(b *testing.B) { + benchmarkParseInt(b, -1) + }) +} + +type benchCase struct { + name string + num int64 +} + +func benchmarkParseInt(b *testing.B, neg int) { + cases := []benchCase{ + {"7bit", 1<<7 - 1}, + {"26bit", 1<<26 - 1}, + {"31bit", 1<<31 - 1}, + {"56bit", 1<<56 - 1}, + {"63bit", 1<<63 - 1}, + } + for _, cs := range cases { + b.Run(cs.name, func(b *testing.B) { + s := fmt.Sprintf("%d", cs.num*int64(neg)) + for i := 0; i < b.N; i++ { + out, _ := ParseInt(s, 10, 64) + BenchSink += int(out) + } + }) + } +} + +func BenchmarkAtoi(b *testing.B) { + b.Run("Pos", func(b *testing.B) { + benchmarkAtoi(b, 1) + }) + b.Run("Neg", func(b *testing.B) { + benchmarkAtoi(b, -1) + }) +} + +func benchmarkAtoi(b *testing.B, neg int) { + cases := []benchCase{ + {"7bit", 1<<7 - 1}, + {"26bit", 1<<26 - 1}, + {"31bit", 1<<31 - 1}, + } + if IntSize == 64 { + cases = append(cases, []benchCase{ + {"56bit", 1<<56 - 1}, + {"63bit", 1<<63 - 1}, + }...) + } + for _, cs := range cases { + b.Run(cs.name, func(b *testing.B) { + s := fmt.Sprintf("%d", cs.num*int64(neg)) + for i := 0; i < b.N; i++ { + out, _ := Atoi(s) + BenchSink += out + } + }) + } +} diff --git a/gnovm/stdlibs/strconv/bytealg.gno b/gnovm/stdlibs/strconv/bytealg.gno new file mode 100644 index 00000000000..2c813885f53 --- /dev/null +++ b/gnovm/stdlibs/strconv/bytealg.gno @@ -0,0 +1,12 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strconv + +import "internal/bytealg" + +// index returns the index of the first instance of c in s, or -1 if missing. +func index(s string, c byte) int { + return bytealg.IndexByteString(s, c) +} diff --git a/gnovm/stdlibs/strconv/decimal.gno b/gnovm/stdlibs/strconv/decimal.gno new file mode 100644 index 00000000000..b58001888e8 --- /dev/null +++ b/gnovm/stdlibs/strconv/decimal.gno @@ -0,0 +1,415 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Multiprecision decimal numbers. +// For floating-point formatting only; not general purpose. +// Only operations are assign and (binary) left/right shift. +// Can do binary floating point in multiprecision decimal precisely +// because 2 divides 10; cannot do decimal floating point +// in multiprecision binary precisely. + +package strconv + +type decimal struct { + d [800]byte // digits, big-endian representation + nd int // number of digits used + dp int // decimal point + neg bool // negative flag + trunc bool // discarded nonzero digits beyond d[:nd] +} + +func (a *decimal) String() string { + n := 10 + a.nd + if a.dp > 0 { + n += a.dp + } + if a.dp < 0 { + n += -a.dp + } + + buf := make([]byte, n) + w := 0 + switch { + case a.nd == 0: + return "0" + + case a.dp <= 0: + // zeros fill space between decimal point and digits + buf[w] = '0' + w++ + buf[w] = '.' + w++ + w += digitZero(buf[w : w+-a.dp]) + w += copy(buf[w:], a.d[0:a.nd]) + + case a.dp < a.nd: + // decimal point in middle of digits + w += copy(buf[w:], a.d[0:a.dp]) + buf[w] = '.' + w++ + w += copy(buf[w:], a.d[a.dp:a.nd]) + + default: + // zeros fill space between digits and decimal point + w += copy(buf[w:], a.d[0:a.nd]) + w += digitZero(buf[w : w+a.dp-a.nd]) + } + return string(buf[0:w]) +} + +func digitZero(dst []byte) int { + for i := range dst { + dst[i] = '0' + } + return len(dst) +} + +// trim trailing zeros from number. +// (They are meaningless; the decimal point is tracked +// independent of the number of digits.) +func trim(a *decimal) { + for a.nd > 0 && a.d[a.nd-1] == '0' { + a.nd-- + } + if a.nd == 0 { + a.dp = 0 + } +} + +// Assign v to a. +func (a *decimal) Assign(v uint64) { + var buf [24]byte + + // Write reversed decimal in buf. + n := 0 + for v > 0 { + v1 := v / 10 + v -= 10 * v1 + buf[n] = byte(v + '0') + n++ + v = v1 + } + + // Reverse again to produce forward decimal in a.d. + a.nd = 0 + for n--; n >= 0; n-- { + a.d[a.nd] = buf[n] + a.nd++ + } + a.dp = a.nd + trim(a) +} + +// Maximum shift that we can do in one pass without overflow. +// A uint has 32 or 64 bits, and we have to be able to accommodate 9<> 63) +const maxShift = uintSize - 4 + +// Binary shift right (/ 2) by k bits. k <= maxShift to avoid overflow. +func rightShift(a *decimal, k uint) { + r := 0 // read pointer + w := 0 // write pointer + + // Pick up enough leading digits to cover first shift. + var n uint + for ; n>>k == 0; r++ { + if r >= a.nd { + if n == 0 { + // a == 0; shouldn't get here, but handle anyway. + a.nd = 0 + return + } + for n>>k == 0 { + n = n * 10 + r++ + } + break + } + c := uint(a.d[r]) + n = n*10 + c - '0' + } + a.dp -= r - 1 + + var mask uint = (1 << k) - 1 + + // Pick up a digit, put down a digit. + for ; r < a.nd; r++ { + c := uint(a.d[r]) + dig := n >> k + n &= mask + a.d[w] = byte(dig + '0') + w++ + n = n*10 + c - '0' + } + + // Put down extra digits. + for n > 0 { + dig := n >> k + n &= mask + if w < len(a.d) { + a.d[w] = byte(dig + '0') + w++ + } else if dig > 0 { + a.trunc = true + } + n = n * 10 + } + + a.nd = w + trim(a) +} + +// Cheat sheet for left shift: table indexed by shift count giving +// number of new digits that will be introduced by that shift. +// +// For example, leftcheats[4] = {2, "625"}. That means that +// if we are shifting by 4 (multiplying by 16), it will add 2 digits +// when the string prefix is "625" through "999", and one fewer digit +// if the string prefix is "000" through "624". +// +// Credit for this trick goes to Ken. + +type leftCheat struct { + delta int // number of new digits + cutoff string // minus one digit if original < a. +} + +var leftcheats = []leftCheat{ + // Leading digits of 1/2^i = 5^i. + // 5^23 is not an exact 64-bit floating point number, + // so have to use bc for the math. + // Go up to 60 to be large enough for 32bit and 64bit platforms. + /* + seq 60 | sed 's/^/5^/' | bc | + awk 'BEGIN{ print "\t{ 0, \"\" }," } + { + log2 = log(2)/log(10) + printf("\t{ %d, \"%s\" },\t// * %d\n", + int(log2*NR+1), $0, 2**NR) + }' + */ + {0, ""}, + {1, "5"}, // * 2 + {1, "25"}, // * 4 + {1, "125"}, // * 8 + {2, "625"}, // * 16 + {2, "3125"}, // * 32 + {2, "15625"}, // * 64 + {3, "78125"}, // * 128 + {3, "390625"}, // * 256 + {3, "1953125"}, // * 512 + {4, "9765625"}, // * 1024 + {4, "48828125"}, // * 2048 + {4, "244140625"}, // * 4096 + {4, "1220703125"}, // * 8192 + {5, "6103515625"}, // * 16384 + {5, "30517578125"}, // * 32768 + {5, "152587890625"}, // * 65536 + {6, "762939453125"}, // * 131072 + {6, "3814697265625"}, // * 262144 + {6, "19073486328125"}, // * 524288 + {7, "95367431640625"}, // * 1048576 + {7, "476837158203125"}, // * 2097152 + {7, "2384185791015625"}, // * 4194304 + {7, "11920928955078125"}, // * 8388608 + {8, "59604644775390625"}, // * 16777216 + {8, "298023223876953125"}, // * 33554432 + {8, "1490116119384765625"}, // * 67108864 + {9, "7450580596923828125"}, // * 134217728 + {9, "37252902984619140625"}, // * 268435456 + {9, "186264514923095703125"}, // * 536870912 + {10, "931322574615478515625"}, // * 1073741824 + {10, "4656612873077392578125"}, // * 2147483648 + {10, "23283064365386962890625"}, // * 4294967296 + {10, "116415321826934814453125"}, // * 8589934592 + {11, "582076609134674072265625"}, // * 17179869184 + {11, "2910383045673370361328125"}, // * 34359738368 + {11, "14551915228366851806640625"}, // * 68719476736 + {12, "72759576141834259033203125"}, // * 137438953472 + {12, "363797880709171295166015625"}, // * 274877906944 + {12, "1818989403545856475830078125"}, // * 549755813888 + {13, "9094947017729282379150390625"}, // * 1099511627776 + {13, "45474735088646411895751953125"}, // * 2199023255552 + {13, "227373675443232059478759765625"}, // * 4398046511104 + {13, "1136868377216160297393798828125"}, // * 8796093022208 + {14, "5684341886080801486968994140625"}, // * 17592186044416 + {14, "28421709430404007434844970703125"}, // * 35184372088832 + {14, "142108547152020037174224853515625"}, // * 70368744177664 + {15, "710542735760100185871124267578125"}, // * 140737488355328 + {15, "3552713678800500929355621337890625"}, // * 281474976710656 + {15, "17763568394002504646778106689453125"}, // * 562949953421312 + {16, "88817841970012523233890533447265625"}, // * 1125899906842624 + {16, "444089209850062616169452667236328125"}, // * 2251799813685248 + {16, "2220446049250313080847263336181640625"}, // * 4503599627370496 + {16, "11102230246251565404236316680908203125"}, // * 9007199254740992 + {17, "55511151231257827021181583404541015625"}, // * 18014398509481984 + {17, "277555756156289135105907917022705078125"}, // * 36028797018963968 + {17, "1387778780781445675529539585113525390625"}, // * 72057594037927936 + {18, "6938893903907228377647697925567626953125"}, // * 144115188075855872 + {18, "34694469519536141888238489627838134765625"}, // * 288230376151711744 + {18, "173472347597680709441192448139190673828125"}, // * 576460752303423488 + {19, "867361737988403547205962240695953369140625"}, // * 1152921504606846976 +} + +// Is the leading prefix of b lexicographically less than s? +func prefixIsLessThan(b []byte, s string) bool { + for i := 0; i < len(s); i++ { + if i >= len(b) { + return true + } + if b[i] != s[i] { + return b[i] < s[i] + } + } + return false +} + +// Binary shift left (* 2) by k bits. k <= maxShift to avoid overflow. +func leftShift(a *decimal, k uint) { + delta := leftcheats[k].delta + if prefixIsLessThan(a.d[0:a.nd], leftcheats[k].cutoff) { + delta-- + } + + r := a.nd // read index + w := a.nd + delta // write index + + // Pick up a digit, put down a digit. + var n uint + for r--; r >= 0; r-- { + n += (uint(a.d[r]) - '0') << k + quo := n / 10 + rem := n - 10*quo + w-- + if w < len(a.d) { + a.d[w] = byte(rem + '0') + } else if rem != 0 { + a.trunc = true + } + n = quo + } + + // Put down extra digits. + for n > 0 { + quo := n / 10 + rem := n - 10*quo + w-- + if w < len(a.d) { + a.d[w] = byte(rem + '0') + } else if rem != 0 { + a.trunc = true + } + n = quo + } + + a.nd += delta + if a.nd >= len(a.d) { + a.nd = len(a.d) + } + a.dp += delta + trim(a) +} + +// Binary shift left (k > 0) or right (k < 0). +func (a *decimal) Shift(k int) { + switch { + case a.nd == 0: + // nothing to do: a == 0 + case k > 0: + for k > maxShift { + leftShift(a, maxShift) + k -= maxShift + } + leftShift(a, uint(k)) + case k < 0: + for k < -maxShift { + rightShift(a, maxShift) + k += maxShift + } + rightShift(a, uint(-k)) + } +} + +// If we chop a at nd digits, should we round up? +func shouldRoundUp(a *decimal, nd int) bool { + if nd < 0 || nd >= a.nd { + return false + } + if a.d[nd] == '5' && nd+1 == a.nd { // exactly halfway - round to even + // if we truncated, a little higher than what's recorded - always round up + if a.trunc { + return true + } + return nd > 0 && (a.d[nd-1]-'0')%2 != 0 + } + // not halfway - digit tells all + return a.d[nd] >= '5' +} + +// Round a to nd digits (or fewer). +// If nd is zero, it means we're rounding +// just to the left of the digits, as in +// 0.09 -> 0.1. +func (a *decimal) Round(nd int) { + if nd < 0 || nd >= a.nd { + return + } + if shouldRoundUp(a, nd) { + a.RoundUp(nd) + } else { + a.RoundDown(nd) + } +} + +// Round a down to nd digits (or fewer). +func (a *decimal) RoundDown(nd int) { + if nd < 0 || nd >= a.nd { + return + } + a.nd = nd + trim(a) +} + +// Round a up to nd digits (or fewer). +func (a *decimal) RoundUp(nd int) { + if nd < 0 || nd >= a.nd { + return + } + + // round up + for i := nd - 1; i >= 0; i-- { + c := a.d[i] + if c < '9' { // can stop after this digit + a.d[i]++ + a.nd = i + 1 + return + } + } + + // Number is all 9s. + // Change to single 1 with adjusted decimal point. + a.d[0] = '1' + a.nd = 1 + a.dp++ +} + +// Extract integer part, rounded appropriately. +// No guarantees about overflow. +func (a *decimal) RoundedInteger() uint64 { + if a.dp > 20 { + return 0xFFFFFFFFFFFFFFFF + } + var i int + n := uint64(0) + for i = 0; i < a.dp && i < a.nd; i++ { + n = n*10 + uint64(a.d[i]-'0') + } + for ; i < a.dp; i++ { + n *= 10 + } + if shouldRoundUp(a, a.dp) { + n++ + } + return n +} diff --git a/gnovm/stdlibs/strconv/decimal_test.gno b/gnovm/stdlibs/strconv/decimal_test.gno new file mode 100644 index 00000000000..9dc8c997b9c --- /dev/null +++ b/gnovm/stdlibs/strconv/decimal_test.gno @@ -0,0 +1,126 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strconv + +import ( + "testing" +) + +type shiftTest struct { + i uint64 + shift int + out string +} + +var shifttests = []shiftTest{ + {0, -100, "0"}, + {0, 100, "0"}, + {1, 100, "1267650600228229401496703205376"}, + {1, -100, + "0.00000000000000000000000000000078886090522101180541" + + "17285652827862296732064351090230047702789306640625", + }, + {12345678, 8, "3160493568"}, + {12345678, -8, "48225.3046875"}, + {195312, 9, "99999744"}, + {1953125, 9, "1000000000"}, +} + +func TestDecimalShift(t *testing.T) { + for i := 0; i < len(shifttests); i++ { + test := &shifttests[i] + d := NewDecimal(test.i) + d.Shift(test.shift) + s := d.String() + if s != test.out { + t.Errorf("Decimal %v << %v = %v, want %v", + test.i, test.shift, s, test.out) + } + } +} + +type roundTest struct { + i uint64 + nd int + down, round, up string + int uint64 +} + +var roundtests = []roundTest{ + {0, 4, "0", "0", "0", 0}, + {12344999, 4, "12340000", "12340000", "12350000", 12340000}, + {12345000, 4, "12340000", "12340000", "12350000", 12340000}, + {12345001, 4, "12340000", "12350000", "12350000", 12350000}, + {23454999, 4, "23450000", "23450000", "23460000", 23450000}, + {23455000, 4, "23450000", "23460000", "23460000", 23460000}, + {23455001, 4, "23450000", "23460000", "23460000", 23460000}, + + {99994999, 4, "99990000", "99990000", "100000000", 99990000}, + {99995000, 4, "99990000", "100000000", "100000000", 100000000}, + {99999999, 4, "99990000", "100000000", "100000000", 100000000}, + + {12994999, 4, "12990000", "12990000", "13000000", 12990000}, + {12995000, 4, "12990000", "13000000", "13000000", 13000000}, + {12999999, 4, "12990000", "13000000", "13000000", 13000000}, +} + +func TestDecimalRound(t *testing.T) { + for i := 0; i < len(roundtests); i++ { + test := &roundtests[i] + d := NewDecimal(test.i) + d.RoundDown(test.nd) + s := d.String() + if s != test.down { + t.Errorf("Decimal %v RoundDown %d = %v, want %v", + test.i, test.nd, s, test.down) + } + d = NewDecimal(test.i) + d.Round(test.nd) + s = d.String() + if s != test.round { + t.Errorf("Decimal %v Round %d = %v, want %v", + test.i, test.nd, s, test.down) + } + d = NewDecimal(test.i) + d.RoundUp(test.nd) + s = d.String() + if s != test.up { + t.Errorf("Decimal %v RoundUp %d = %v, want %v", + test.i, test.nd, s, test.up) + } + } +} + +type roundIntTest struct { + i uint64 + shift int + int uint64 +} + +var roundinttests = []roundIntTest{ + {0, 100, 0}, + {512, -8, 2}, + {513, -8, 2}, + {640, -8, 2}, + {641, -8, 3}, + {384, -8, 2}, + {385, -8, 2}, + {383, -8, 1}, + {1, 100, 1<<64 - 1}, + {1000, 0, 1000}, +} + +func TestDecimalRoundedInteger(t *testing.T) { + for i := 0; i < len(roundinttests); i++ { + test := roundinttests[i] + d := NewDecimal(test.i) + d.Shift(test.shift) + num := d.RoundedInteger() + if num != test.int { + t.Errorf("Decimal %v >> %v RoundedInteger = %v, want %v", + test.i, test.shift, num, test.int) + } + } +} diff --git a/gnovm/stdlibs/strconv/doc.gno b/gnovm/stdlibs/strconv/doc.gno new file mode 100644 index 00000000000..9a22d77a0cd --- /dev/null +++ b/gnovm/stdlibs/strconv/doc.gno @@ -0,0 +1,59 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package strconv implements conversions to and from string representations +// of basic data types. +// +// # Numeric Conversions +// +// The most common numeric conversions are Atoi (string to int) and Itoa (int to string). +// +// i, err := strconv.Atoi("-42") +// s := strconv.Itoa(-42) +// +// These assume decimal and the Go int type. +// +// [ParseBool], [ParseFloat], [ParseInt], and [ParseUint] convert strings to values: +// +// b, err := strconv.ParseBool("true") +// f, err := strconv.ParseFloat("3.1415", 64) +// i, err := strconv.ParseInt("-42", 10, 64) +// u, err := strconv.ParseUint("42", 10, 64) +// +// The parse functions return the widest type (float64, int64, and uint64), +// but if the size argument specifies a narrower width the result can be +// converted to that narrower type without data loss: +// +// s := "2147483647" // biggest int32 +// i64, err := strconv.ParseInt(s, 10, 32) +// ... +// i := int32(i64) +// +// [FormatBool], [FormatFloat], [FormatInt], and [FormatUint] convert values to strings: +// +// s := strconv.FormatBool(true) +// s := strconv.FormatFloat(3.1415, 'E', -1, 64) +// s := strconv.FormatInt(-42, 16) +// s := strconv.FormatUint(42, 16) +// +// [AppendBool], [AppendFloat], [AppendInt], and [AppendUint] are similar but +// append the formatted value to a destination slice. +// +// # String Conversions +// +// [Quote] and [QuoteToASCII] convert strings to quoted Go string literals. +// The latter guarantees that the result is an ASCII string, by escaping +// any non-ASCII Unicode with \u: +// +// q := strconv.Quote("Hello, 世界") +// q := strconv.QuoteToASCII("Hello, 世界") +// +// [QuoteRune] and [QuoteRuneToASCII] are similar but accept runes and +// return quoted Go rune literals. +// +// [Unquote] and [UnquoteChar] unquote Go string and rune literals. +// +// XXX: Gno does not implement any of the functions from Go's strconv which +// pertain to complex numbers, such as FormatComplex and ParseComplex. +package strconv diff --git a/gnovm/stdlibs/strconv/eisel_lemire.gno b/gnovm/stdlibs/strconv/eisel_lemire.gno new file mode 100644 index 00000000000..03842e50797 --- /dev/null +++ b/gnovm/stdlibs/strconv/eisel_lemire.gno @@ -0,0 +1,884 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strconv + +// This file implements the Eisel-Lemire ParseFloat algorithm, published in +// 2020 and discussed extensively at +// https://nigeltao.github.io/blog/2020/eisel-lemire.html +// +// The original C++ implementation is at +// https://github.com/lemire/fast_double_parser/blob/644bef4306059d3be01a04e77d3cc84b379c596f/include/fast_double_parser.h#L840 +// +// This Go re-implementation closely follows the C re-implementation at +// https://github.com/google/wuffs/blob/ba3818cb6b473a2ed0b38ecfc07dbbd3a97e8ae7/internal/cgen/base/floatconv-submodule-code.c#L990 +// +// Additional testing (on over several million test strings) is done by +// https://github.com/nigeltao/parse-number-fxx-test-data/blob/5280dcfccf6d0b02a65ae282dad0b6d9de50e039/script/test-go-strconv.go + +import ( + "math" + "math/bits" +) + +func eiselLemire64(man uint64, exp10 int, neg bool) (f float64, ok bool) { + // The terse comments in this function body refer to sections of the + // https://nigeltao.github.io/blog/2020/eisel-lemire.html blog post. + + // Exp10 Range. + if man == 0 { + if neg { + f = math.Float64frombits(0x8000000000000000) // Negative zero. + } + return f, true + } + if exp10 < detailedPowersOfTenMinExp10 || detailedPowersOfTenMaxExp10 < exp10 { + return 0, false + } + + // Normalization. + clz := bits.LeadingZeros64(man) + man <<= uint(clz) + const float64ExponentBias = 1023 + retExp2 := uint64(217706*exp10>>16+64+float64ExponentBias) - uint64(clz) + + // Multiplication. + xHi, xLo := bits.Mul64(man, detailedPowersOfTen[exp10-detailedPowersOfTenMinExp10][1]) + + // Wider Approximation. + if xHi&0x1FF == 0x1FF && xLo+man < man { + yHi, yLo := bits.Mul64(man, detailedPowersOfTen[exp10-detailedPowersOfTenMinExp10][0]) + mergedHi, mergedLo := xHi, xLo+yHi + if mergedLo < xLo { + mergedHi++ + } + if mergedHi&0x1FF == 0x1FF && mergedLo+1 == 0 && yLo+man < man { + return 0, false + } + xHi, xLo = mergedHi, mergedLo + } + + // Shifting to 54 Bits. + msb := xHi >> 63 + retMantissa := xHi >> (msb + 9) + retExp2 -= 1 ^ msb + + // Half-way Ambiguity. + if xLo == 0 && xHi&0x1FF == 0 && retMantissa&3 == 1 { + return 0, false + } + + // From 54 to 53 Bits. + retMantissa += retMantissa & 1 + retMantissa >>= 1 + if retMantissa>>53 > 0 { + retMantissa >>= 1 + retExp2 += 1 + } + // retExp2 is a uint64. Zero or underflow means that we're in subnormal + // float64 space. 0x7FF or above means that we're in Inf/NaN float64 space. + // + // The if block is equivalent to (but has fewer branches than): + // if retExp2 <= 0 || retExp2 >= 0x7FF { etc } + if retExp2-1 >= 0x7FF-1 { + return 0, false + } + retBits := retExp2<<52 | retMantissa&0x000FFFFFFFFFFFFF + if neg { + retBits |= 0x8000000000000000 + } + return math.Float64frombits(retBits), true +} + +func eiselLemire32(man uint64, exp10 int, neg bool) (f float32, ok bool) { + // The terse comments in this function body refer to sections of the + // https://nigeltao.github.io/blog/2020/eisel-lemire.html blog post. + // + // That blog post discusses the float64 flavor (11 exponent bits with a + // -1023 bias, 52 mantissa bits) of the algorithm, but the same approach + // applies to the float32 flavor (8 exponent bits with a -127 bias, 23 + // mantissa bits). The computation here happens with 64-bit values (e.g. + // man, xHi, retMantissa) before finally converting to a 32-bit float. + + // Exp10 Range. + if man == 0 { + if neg { + f = math.Float32frombits(0x80000000) // Negative zero. + } + return f, true + } + if exp10 < detailedPowersOfTenMinExp10 || detailedPowersOfTenMaxExp10 < exp10 { + return 0, false + } + + // Normalization. + clz := bits.LeadingZeros64(man) + man <<= uint(clz) + const float32ExponentBias = 127 + retExp2 := uint64(217706*exp10>>16+64+float32ExponentBias) - uint64(clz) + + // Multiplication. + xHi, xLo := bits.Mul64(man, detailedPowersOfTen[exp10-detailedPowersOfTenMinExp10][1]) + + // Wider Approximation. + if xHi&0x3FFFFFFFFF == 0x3FFFFFFFFF && xLo+man < man { + yHi, yLo := bits.Mul64(man, detailedPowersOfTen[exp10-detailedPowersOfTenMinExp10][0]) + mergedHi, mergedLo := xHi, xLo+yHi + if mergedLo < xLo { + mergedHi++ + } + if mergedHi&0x3FFFFFFFFF == 0x3FFFFFFFFF && mergedLo+1 == 0 && yLo+man < man { + return 0, false + } + xHi, xLo = mergedHi, mergedLo + } + + // Shifting to 54 Bits (and for float32, it's shifting to 25 bits). + msb := xHi >> 63 + retMantissa := xHi >> (msb + 38) + retExp2 -= 1 ^ msb + + // Half-way Ambiguity. + if xLo == 0 && xHi&0x3FFFFFFFFF == 0 && retMantissa&3 == 1 { + return 0, false + } + + // From 54 to 53 Bits (and for float32, it's from 25 to 24 bits). + retMantissa += retMantissa & 1 + retMantissa >>= 1 + if retMantissa>>24 > 0 { + retMantissa >>= 1 + retExp2 += 1 + } + // retExp2 is a uint64. Zero or underflow means that we're in subnormal + // float32 space. 0xFF or above means that we're in Inf/NaN float32 space. + // + // The if block is equivalent to (but has fewer branches than): + // if retExp2 <= 0 || retExp2 >= 0xFF { etc } + if retExp2-1 >= 0xFF-1 { + return 0, false + } + retBits := retExp2<<23 | retMantissa&0x007FFFFF + if neg { + retBits |= 0x80000000 + } + return math.Float32frombits(uint32(retBits)), true +} + +// detailedPowersOfTen{Min,Max}Exp10 is the power of 10 represented by the +// first and last rows of detailedPowersOfTen. Both bounds are inclusive. +const ( + detailedPowersOfTenMinExp10 = -348 + detailedPowersOfTenMaxExp10 = +347 +) + +// detailedPowersOfTen contains 128-bit mantissa approximations (rounded down) +// to the powers of 10. For example: +// +// - 1e43 ≈ (0xE596B7B0_C643C719 * (2 ** 79)) +// - 1e43 = (0xE596B7B0_C643C719_6D9CCD05_D0000000 * (2 ** 15)) +// +// The mantissas are explicitly listed. The exponents are implied by a linear +// expression with slope 217706.0/65536.0 ≈ log(10)/log(2). +// +// The table was generated by +// https://github.com/google/wuffs/blob/ba3818cb6b473a2ed0b38ecfc07dbbd3a97e8ae7/script/print-mpb-powers-of-10.go +var detailedPowersOfTen = [...][2]uint64{ + {0x1732C869CD60E453, 0xFA8FD5A0081C0288}, // 1e-348 + {0x0E7FBD42205C8EB4, 0x9C99E58405118195}, // 1e-347 + {0x521FAC92A873B261, 0xC3C05EE50655E1FA}, // 1e-346 + {0xE6A797B752909EF9, 0xF4B0769E47EB5A78}, // 1e-345 + {0x9028BED2939A635C, 0x98EE4A22ECF3188B}, // 1e-344 + {0x7432EE873880FC33, 0xBF29DCABA82FDEAE}, // 1e-343 + {0x113FAA2906A13B3F, 0xEEF453D6923BD65A}, // 1e-342 + {0x4AC7CA59A424C507, 0x9558B4661B6565F8}, // 1e-341 + {0x5D79BCF00D2DF649, 0xBAAEE17FA23EBF76}, // 1e-340 + {0xF4D82C2C107973DC, 0xE95A99DF8ACE6F53}, // 1e-339 + {0x79071B9B8A4BE869, 0x91D8A02BB6C10594}, // 1e-338 + {0x9748E2826CDEE284, 0xB64EC836A47146F9}, // 1e-337 + {0xFD1B1B2308169B25, 0xE3E27A444D8D98B7}, // 1e-336 + {0xFE30F0F5E50E20F7, 0x8E6D8C6AB0787F72}, // 1e-335 + {0xBDBD2D335E51A935, 0xB208EF855C969F4F}, // 1e-334 + {0xAD2C788035E61382, 0xDE8B2B66B3BC4723}, // 1e-333 + {0x4C3BCB5021AFCC31, 0x8B16FB203055AC76}, // 1e-332 + {0xDF4ABE242A1BBF3D, 0xADDCB9E83C6B1793}, // 1e-331 + {0xD71D6DAD34A2AF0D, 0xD953E8624B85DD78}, // 1e-330 + {0x8672648C40E5AD68, 0x87D4713D6F33AA6B}, // 1e-329 + {0x680EFDAF511F18C2, 0xA9C98D8CCB009506}, // 1e-328 + {0x0212BD1B2566DEF2, 0xD43BF0EFFDC0BA48}, // 1e-327 + {0x014BB630F7604B57, 0x84A57695FE98746D}, // 1e-326 + {0x419EA3BD35385E2D, 0xA5CED43B7E3E9188}, // 1e-325 + {0x52064CAC828675B9, 0xCF42894A5DCE35EA}, // 1e-324 + {0x7343EFEBD1940993, 0x818995CE7AA0E1B2}, // 1e-323 + {0x1014EBE6C5F90BF8, 0xA1EBFB4219491A1F}, // 1e-322 + {0xD41A26E077774EF6, 0xCA66FA129F9B60A6}, // 1e-321 + {0x8920B098955522B4, 0xFD00B897478238D0}, // 1e-320 + {0x55B46E5F5D5535B0, 0x9E20735E8CB16382}, // 1e-319 + {0xEB2189F734AA831D, 0xC5A890362FDDBC62}, // 1e-318 + {0xA5E9EC7501D523E4, 0xF712B443BBD52B7B}, // 1e-317 + {0x47B233C92125366E, 0x9A6BB0AA55653B2D}, // 1e-316 + {0x999EC0BB696E840A, 0xC1069CD4EABE89F8}, // 1e-315 + {0xC00670EA43CA250D, 0xF148440A256E2C76}, // 1e-314 + {0x380406926A5E5728, 0x96CD2A865764DBCA}, // 1e-313 + {0xC605083704F5ECF2, 0xBC807527ED3E12BC}, // 1e-312 + {0xF7864A44C633682E, 0xEBA09271E88D976B}, // 1e-311 + {0x7AB3EE6AFBE0211D, 0x93445B8731587EA3}, // 1e-310 + {0x5960EA05BAD82964, 0xB8157268FDAE9E4C}, // 1e-309 + {0x6FB92487298E33BD, 0xE61ACF033D1A45DF}, // 1e-308 + {0xA5D3B6D479F8E056, 0x8FD0C16206306BAB}, // 1e-307 + {0x8F48A4899877186C, 0xB3C4F1BA87BC8696}, // 1e-306 + {0x331ACDABFE94DE87, 0xE0B62E2929ABA83C}, // 1e-305 + {0x9FF0C08B7F1D0B14, 0x8C71DCD9BA0B4925}, // 1e-304 + {0x07ECF0AE5EE44DD9, 0xAF8E5410288E1B6F}, // 1e-303 + {0xC9E82CD9F69D6150, 0xDB71E91432B1A24A}, // 1e-302 + {0xBE311C083A225CD2, 0x892731AC9FAF056E}, // 1e-301 + {0x6DBD630A48AAF406, 0xAB70FE17C79AC6CA}, // 1e-300 + {0x092CBBCCDAD5B108, 0xD64D3D9DB981787D}, // 1e-299 + {0x25BBF56008C58EA5, 0x85F0468293F0EB4E}, // 1e-298 + {0xAF2AF2B80AF6F24E, 0xA76C582338ED2621}, // 1e-297 + {0x1AF5AF660DB4AEE1, 0xD1476E2C07286FAA}, // 1e-296 + {0x50D98D9FC890ED4D, 0x82CCA4DB847945CA}, // 1e-295 + {0xE50FF107BAB528A0, 0xA37FCE126597973C}, // 1e-294 + {0x1E53ED49A96272C8, 0xCC5FC196FEFD7D0C}, // 1e-293 + {0x25E8E89C13BB0F7A, 0xFF77B1FCBEBCDC4F}, // 1e-292 + {0x77B191618C54E9AC, 0x9FAACF3DF73609B1}, // 1e-291 + {0xD59DF5B9EF6A2417, 0xC795830D75038C1D}, // 1e-290 + {0x4B0573286B44AD1D, 0xF97AE3D0D2446F25}, // 1e-289 + {0x4EE367F9430AEC32, 0x9BECCE62836AC577}, // 1e-288 + {0x229C41F793CDA73F, 0xC2E801FB244576D5}, // 1e-287 + {0x6B43527578C1110F, 0xF3A20279ED56D48A}, // 1e-286 + {0x830A13896B78AAA9, 0x9845418C345644D6}, // 1e-285 + {0x23CC986BC656D553, 0xBE5691EF416BD60C}, // 1e-284 + {0x2CBFBE86B7EC8AA8, 0xEDEC366B11C6CB8F}, // 1e-283 + {0x7BF7D71432F3D6A9, 0x94B3A202EB1C3F39}, // 1e-282 + {0xDAF5CCD93FB0CC53, 0xB9E08A83A5E34F07}, // 1e-281 + {0xD1B3400F8F9CFF68, 0xE858AD248F5C22C9}, // 1e-280 + {0x23100809B9C21FA1, 0x91376C36D99995BE}, // 1e-279 + {0xABD40A0C2832A78A, 0xB58547448FFFFB2D}, // 1e-278 + {0x16C90C8F323F516C, 0xE2E69915B3FFF9F9}, // 1e-277 + {0xAE3DA7D97F6792E3, 0x8DD01FAD907FFC3B}, // 1e-276 + {0x99CD11CFDF41779C, 0xB1442798F49FFB4A}, // 1e-275 + {0x40405643D711D583, 0xDD95317F31C7FA1D}, // 1e-274 + {0x482835EA666B2572, 0x8A7D3EEF7F1CFC52}, // 1e-273 + {0xDA3243650005EECF, 0xAD1C8EAB5EE43B66}, // 1e-272 + {0x90BED43E40076A82, 0xD863B256369D4A40}, // 1e-271 + {0x5A7744A6E804A291, 0x873E4F75E2224E68}, // 1e-270 + {0x711515D0A205CB36, 0xA90DE3535AAAE202}, // 1e-269 + {0x0D5A5B44CA873E03, 0xD3515C2831559A83}, // 1e-268 + {0xE858790AFE9486C2, 0x8412D9991ED58091}, // 1e-267 + {0x626E974DBE39A872, 0xA5178FFF668AE0B6}, // 1e-266 + {0xFB0A3D212DC8128F, 0xCE5D73FF402D98E3}, // 1e-265 + {0x7CE66634BC9D0B99, 0x80FA687F881C7F8E}, // 1e-264 + {0x1C1FFFC1EBC44E80, 0xA139029F6A239F72}, // 1e-263 + {0xA327FFB266B56220, 0xC987434744AC874E}, // 1e-262 + {0x4BF1FF9F0062BAA8, 0xFBE9141915D7A922}, // 1e-261 + {0x6F773FC3603DB4A9, 0x9D71AC8FADA6C9B5}, // 1e-260 + {0xCB550FB4384D21D3, 0xC4CE17B399107C22}, // 1e-259 + {0x7E2A53A146606A48, 0xF6019DA07F549B2B}, // 1e-258 + {0x2EDA7444CBFC426D, 0x99C102844F94E0FB}, // 1e-257 + {0xFA911155FEFB5308, 0xC0314325637A1939}, // 1e-256 + {0x793555AB7EBA27CA, 0xF03D93EEBC589F88}, // 1e-255 + {0x4BC1558B2F3458DE, 0x96267C7535B763B5}, // 1e-254 + {0x9EB1AAEDFB016F16, 0xBBB01B9283253CA2}, // 1e-253 + {0x465E15A979C1CADC, 0xEA9C227723EE8BCB}, // 1e-252 + {0x0BFACD89EC191EC9, 0x92A1958A7675175F}, // 1e-251 + {0xCEF980EC671F667B, 0xB749FAED14125D36}, // 1e-250 + {0x82B7E12780E7401A, 0xE51C79A85916F484}, // 1e-249 + {0xD1B2ECB8B0908810, 0x8F31CC0937AE58D2}, // 1e-248 + {0x861FA7E6DCB4AA15, 0xB2FE3F0B8599EF07}, // 1e-247 + {0x67A791E093E1D49A, 0xDFBDCECE67006AC9}, // 1e-246 + {0xE0C8BB2C5C6D24E0, 0x8BD6A141006042BD}, // 1e-245 + {0x58FAE9F773886E18, 0xAECC49914078536D}, // 1e-244 + {0xAF39A475506A899E, 0xDA7F5BF590966848}, // 1e-243 + {0x6D8406C952429603, 0x888F99797A5E012D}, // 1e-242 + {0xC8E5087BA6D33B83, 0xAAB37FD7D8F58178}, // 1e-241 + {0xFB1E4A9A90880A64, 0xD5605FCDCF32E1D6}, // 1e-240 + {0x5CF2EEA09A55067F, 0x855C3BE0A17FCD26}, // 1e-239 + {0xF42FAA48C0EA481E, 0xA6B34AD8C9DFC06F}, // 1e-238 + {0xF13B94DAF124DA26, 0xD0601D8EFC57B08B}, // 1e-237 + {0x76C53D08D6B70858, 0x823C12795DB6CE57}, // 1e-236 + {0x54768C4B0C64CA6E, 0xA2CB1717B52481ED}, // 1e-235 + {0xA9942F5DCF7DFD09, 0xCB7DDCDDA26DA268}, // 1e-234 + {0xD3F93B35435D7C4C, 0xFE5D54150B090B02}, // 1e-233 + {0xC47BC5014A1A6DAF, 0x9EFA548D26E5A6E1}, // 1e-232 + {0x359AB6419CA1091B, 0xC6B8E9B0709F109A}, // 1e-231 + {0xC30163D203C94B62, 0xF867241C8CC6D4C0}, // 1e-230 + {0x79E0DE63425DCF1D, 0x9B407691D7FC44F8}, // 1e-229 + {0x985915FC12F542E4, 0xC21094364DFB5636}, // 1e-228 + {0x3E6F5B7B17B2939D, 0xF294B943E17A2BC4}, // 1e-227 + {0xA705992CEECF9C42, 0x979CF3CA6CEC5B5A}, // 1e-226 + {0x50C6FF782A838353, 0xBD8430BD08277231}, // 1e-225 + {0xA4F8BF5635246428, 0xECE53CEC4A314EBD}, // 1e-224 + {0x871B7795E136BE99, 0x940F4613AE5ED136}, // 1e-223 + {0x28E2557B59846E3F, 0xB913179899F68584}, // 1e-222 + {0x331AEADA2FE589CF, 0xE757DD7EC07426E5}, // 1e-221 + {0x3FF0D2C85DEF7621, 0x9096EA6F3848984F}, // 1e-220 + {0x0FED077A756B53A9, 0xB4BCA50B065ABE63}, // 1e-219 + {0xD3E8495912C62894, 0xE1EBCE4DC7F16DFB}, // 1e-218 + {0x64712DD7ABBBD95C, 0x8D3360F09CF6E4BD}, // 1e-217 + {0xBD8D794D96AACFB3, 0xB080392CC4349DEC}, // 1e-216 + {0xECF0D7A0FC5583A0, 0xDCA04777F541C567}, // 1e-215 + {0xF41686C49DB57244, 0x89E42CAAF9491B60}, // 1e-214 + {0x311C2875C522CED5, 0xAC5D37D5B79B6239}, // 1e-213 + {0x7D633293366B828B, 0xD77485CB25823AC7}, // 1e-212 + {0xAE5DFF9C02033197, 0x86A8D39EF77164BC}, // 1e-211 + {0xD9F57F830283FDFC, 0xA8530886B54DBDEB}, // 1e-210 + {0xD072DF63C324FD7B, 0xD267CAA862A12D66}, // 1e-209 + {0x4247CB9E59F71E6D, 0x8380DEA93DA4BC60}, // 1e-208 + {0x52D9BE85F074E608, 0xA46116538D0DEB78}, // 1e-207 + {0x67902E276C921F8B, 0xCD795BE870516656}, // 1e-206 + {0x00BA1CD8A3DB53B6, 0x806BD9714632DFF6}, // 1e-205 + {0x80E8A40ECCD228A4, 0xA086CFCD97BF97F3}, // 1e-204 + {0x6122CD128006B2CD, 0xC8A883C0FDAF7DF0}, // 1e-203 + {0x796B805720085F81, 0xFAD2A4B13D1B5D6C}, // 1e-202 + {0xCBE3303674053BB0, 0x9CC3A6EEC6311A63}, // 1e-201 + {0xBEDBFC4411068A9C, 0xC3F490AA77BD60FC}, // 1e-200 + {0xEE92FB5515482D44, 0xF4F1B4D515ACB93B}, // 1e-199 + {0x751BDD152D4D1C4A, 0x991711052D8BF3C5}, // 1e-198 + {0xD262D45A78A0635D, 0xBF5CD54678EEF0B6}, // 1e-197 + {0x86FB897116C87C34, 0xEF340A98172AACE4}, // 1e-196 + {0xD45D35E6AE3D4DA0, 0x9580869F0E7AAC0E}, // 1e-195 + {0x8974836059CCA109, 0xBAE0A846D2195712}, // 1e-194 + {0x2BD1A438703FC94B, 0xE998D258869FACD7}, // 1e-193 + {0x7B6306A34627DDCF, 0x91FF83775423CC06}, // 1e-192 + {0x1A3BC84C17B1D542, 0xB67F6455292CBF08}, // 1e-191 + {0x20CABA5F1D9E4A93, 0xE41F3D6A7377EECA}, // 1e-190 + {0x547EB47B7282EE9C, 0x8E938662882AF53E}, // 1e-189 + {0xE99E619A4F23AA43, 0xB23867FB2A35B28D}, // 1e-188 + {0x6405FA00E2EC94D4, 0xDEC681F9F4C31F31}, // 1e-187 + {0xDE83BC408DD3DD04, 0x8B3C113C38F9F37E}, // 1e-186 + {0x9624AB50B148D445, 0xAE0B158B4738705E}, // 1e-185 + {0x3BADD624DD9B0957, 0xD98DDAEE19068C76}, // 1e-184 + {0xE54CA5D70A80E5D6, 0x87F8A8D4CFA417C9}, // 1e-183 + {0x5E9FCF4CCD211F4C, 0xA9F6D30A038D1DBC}, // 1e-182 + {0x7647C3200069671F, 0xD47487CC8470652B}, // 1e-181 + {0x29ECD9F40041E073, 0x84C8D4DFD2C63F3B}, // 1e-180 + {0xF468107100525890, 0xA5FB0A17C777CF09}, // 1e-179 + {0x7182148D4066EEB4, 0xCF79CC9DB955C2CC}, // 1e-178 + {0xC6F14CD848405530, 0x81AC1FE293D599BF}, // 1e-177 + {0xB8ADA00E5A506A7C, 0xA21727DB38CB002F}, // 1e-176 + {0xA6D90811F0E4851C, 0xCA9CF1D206FDC03B}, // 1e-175 + {0x908F4A166D1DA663, 0xFD442E4688BD304A}, // 1e-174 + {0x9A598E4E043287FE, 0x9E4A9CEC15763E2E}, // 1e-173 + {0x40EFF1E1853F29FD, 0xC5DD44271AD3CDBA}, // 1e-172 + {0xD12BEE59E68EF47C, 0xF7549530E188C128}, // 1e-171 + {0x82BB74F8301958CE, 0x9A94DD3E8CF578B9}, // 1e-170 + {0xE36A52363C1FAF01, 0xC13A148E3032D6E7}, // 1e-169 + {0xDC44E6C3CB279AC1, 0xF18899B1BC3F8CA1}, // 1e-168 + {0x29AB103A5EF8C0B9, 0x96F5600F15A7B7E5}, // 1e-167 + {0x7415D448F6B6F0E7, 0xBCB2B812DB11A5DE}, // 1e-166 + {0x111B495B3464AD21, 0xEBDF661791D60F56}, // 1e-165 + {0xCAB10DD900BEEC34, 0x936B9FCEBB25C995}, // 1e-164 + {0x3D5D514F40EEA742, 0xB84687C269EF3BFB}, // 1e-163 + {0x0CB4A5A3112A5112, 0xE65829B3046B0AFA}, // 1e-162 + {0x47F0E785EABA72AB, 0x8FF71A0FE2C2E6DC}, // 1e-161 + {0x59ED216765690F56, 0xB3F4E093DB73A093}, // 1e-160 + {0x306869C13EC3532C, 0xE0F218B8D25088B8}, // 1e-159 + {0x1E414218C73A13FB, 0x8C974F7383725573}, // 1e-158 + {0xE5D1929EF90898FA, 0xAFBD2350644EEACF}, // 1e-157 + {0xDF45F746B74ABF39, 0xDBAC6C247D62A583}, // 1e-156 + {0x6B8BBA8C328EB783, 0x894BC396CE5DA772}, // 1e-155 + {0x066EA92F3F326564, 0xAB9EB47C81F5114F}, // 1e-154 + {0xC80A537B0EFEFEBD, 0xD686619BA27255A2}, // 1e-153 + {0xBD06742CE95F5F36, 0x8613FD0145877585}, // 1e-152 + {0x2C48113823B73704, 0xA798FC4196E952E7}, // 1e-151 + {0xF75A15862CA504C5, 0xD17F3B51FCA3A7A0}, // 1e-150 + {0x9A984D73DBE722FB, 0x82EF85133DE648C4}, // 1e-149 + {0xC13E60D0D2E0EBBA, 0xA3AB66580D5FDAF5}, // 1e-148 + {0x318DF905079926A8, 0xCC963FEE10B7D1B3}, // 1e-147 + {0xFDF17746497F7052, 0xFFBBCFE994E5C61F}, // 1e-146 + {0xFEB6EA8BEDEFA633, 0x9FD561F1FD0F9BD3}, // 1e-145 + {0xFE64A52EE96B8FC0, 0xC7CABA6E7C5382C8}, // 1e-144 + {0x3DFDCE7AA3C673B0, 0xF9BD690A1B68637B}, // 1e-143 + {0x06BEA10CA65C084E, 0x9C1661A651213E2D}, // 1e-142 + {0x486E494FCFF30A62, 0xC31BFA0FE5698DB8}, // 1e-141 + {0x5A89DBA3C3EFCCFA, 0xF3E2F893DEC3F126}, // 1e-140 + {0xF89629465A75E01C, 0x986DDB5C6B3A76B7}, // 1e-139 + {0xF6BBB397F1135823, 0xBE89523386091465}, // 1e-138 + {0x746AA07DED582E2C, 0xEE2BA6C0678B597F}, // 1e-137 + {0xA8C2A44EB4571CDC, 0x94DB483840B717EF}, // 1e-136 + {0x92F34D62616CE413, 0xBA121A4650E4DDEB}, // 1e-135 + {0x77B020BAF9C81D17, 0xE896A0D7E51E1566}, // 1e-134 + {0x0ACE1474DC1D122E, 0x915E2486EF32CD60}, // 1e-133 + {0x0D819992132456BA, 0xB5B5ADA8AAFF80B8}, // 1e-132 + {0x10E1FFF697ED6C69, 0xE3231912D5BF60E6}, // 1e-131 + {0xCA8D3FFA1EF463C1, 0x8DF5EFABC5979C8F}, // 1e-130 + {0xBD308FF8A6B17CB2, 0xB1736B96B6FD83B3}, // 1e-129 + {0xAC7CB3F6D05DDBDE, 0xDDD0467C64BCE4A0}, // 1e-128 + {0x6BCDF07A423AA96B, 0x8AA22C0DBEF60EE4}, // 1e-127 + {0x86C16C98D2C953C6, 0xAD4AB7112EB3929D}, // 1e-126 + {0xE871C7BF077BA8B7, 0xD89D64D57A607744}, // 1e-125 + {0x11471CD764AD4972, 0x87625F056C7C4A8B}, // 1e-124 + {0xD598E40D3DD89BCF, 0xA93AF6C6C79B5D2D}, // 1e-123 + {0x4AFF1D108D4EC2C3, 0xD389B47879823479}, // 1e-122 + {0xCEDF722A585139BA, 0x843610CB4BF160CB}, // 1e-121 + {0xC2974EB4EE658828, 0xA54394FE1EEDB8FE}, // 1e-120 + {0x733D226229FEEA32, 0xCE947A3DA6A9273E}, // 1e-119 + {0x0806357D5A3F525F, 0x811CCC668829B887}, // 1e-118 + {0xCA07C2DCB0CF26F7, 0xA163FF802A3426A8}, // 1e-117 + {0xFC89B393DD02F0B5, 0xC9BCFF6034C13052}, // 1e-116 + {0xBBAC2078D443ACE2, 0xFC2C3F3841F17C67}, // 1e-115 + {0xD54B944B84AA4C0D, 0x9D9BA7832936EDC0}, // 1e-114 + {0x0A9E795E65D4DF11, 0xC5029163F384A931}, // 1e-113 + {0x4D4617B5FF4A16D5, 0xF64335BCF065D37D}, // 1e-112 + {0x504BCED1BF8E4E45, 0x99EA0196163FA42E}, // 1e-111 + {0xE45EC2862F71E1D6, 0xC06481FB9BCF8D39}, // 1e-110 + {0x5D767327BB4E5A4C, 0xF07DA27A82C37088}, // 1e-109 + {0x3A6A07F8D510F86F, 0x964E858C91BA2655}, // 1e-108 + {0x890489F70A55368B, 0xBBE226EFB628AFEA}, // 1e-107 + {0x2B45AC74CCEA842E, 0xEADAB0ABA3B2DBE5}, // 1e-106 + {0x3B0B8BC90012929D, 0x92C8AE6B464FC96F}, // 1e-105 + {0x09CE6EBB40173744, 0xB77ADA0617E3BBCB}, // 1e-104 + {0xCC420A6A101D0515, 0xE55990879DDCAABD}, // 1e-103 + {0x9FA946824A12232D, 0x8F57FA54C2A9EAB6}, // 1e-102 + {0x47939822DC96ABF9, 0xB32DF8E9F3546564}, // 1e-101 + {0x59787E2B93BC56F7, 0xDFF9772470297EBD}, // 1e-100 + {0x57EB4EDB3C55B65A, 0x8BFBEA76C619EF36}, // 1e-99 + {0xEDE622920B6B23F1, 0xAEFAE51477A06B03}, // 1e-98 + {0xE95FAB368E45ECED, 0xDAB99E59958885C4}, // 1e-97 + {0x11DBCB0218EBB414, 0x88B402F7FD75539B}, // 1e-96 + {0xD652BDC29F26A119, 0xAAE103B5FCD2A881}, // 1e-95 + {0x4BE76D3346F0495F, 0xD59944A37C0752A2}, // 1e-94 + {0x6F70A4400C562DDB, 0x857FCAE62D8493A5}, // 1e-93 + {0xCB4CCD500F6BB952, 0xA6DFBD9FB8E5B88E}, // 1e-92 + {0x7E2000A41346A7A7, 0xD097AD07A71F26B2}, // 1e-91 + {0x8ED400668C0C28C8, 0x825ECC24C873782F}, // 1e-90 + {0x728900802F0F32FA, 0xA2F67F2DFA90563B}, // 1e-89 + {0x4F2B40A03AD2FFB9, 0xCBB41EF979346BCA}, // 1e-88 + {0xE2F610C84987BFA8, 0xFEA126B7D78186BC}, // 1e-87 + {0x0DD9CA7D2DF4D7C9, 0x9F24B832E6B0F436}, // 1e-86 + {0x91503D1C79720DBB, 0xC6EDE63FA05D3143}, // 1e-85 + {0x75A44C6397CE912A, 0xF8A95FCF88747D94}, // 1e-84 + {0xC986AFBE3EE11ABA, 0x9B69DBE1B548CE7C}, // 1e-83 + {0xFBE85BADCE996168, 0xC24452DA229B021B}, // 1e-82 + {0xFAE27299423FB9C3, 0xF2D56790AB41C2A2}, // 1e-81 + {0xDCCD879FC967D41A, 0x97C560BA6B0919A5}, // 1e-80 + {0x5400E987BBC1C920, 0xBDB6B8E905CB600F}, // 1e-79 + {0x290123E9AAB23B68, 0xED246723473E3813}, // 1e-78 + {0xF9A0B6720AAF6521, 0x9436C0760C86E30B}, // 1e-77 + {0xF808E40E8D5B3E69, 0xB94470938FA89BCE}, // 1e-76 + {0xB60B1D1230B20E04, 0xE7958CB87392C2C2}, // 1e-75 + {0xB1C6F22B5E6F48C2, 0x90BD77F3483BB9B9}, // 1e-74 + {0x1E38AEB6360B1AF3, 0xB4ECD5F01A4AA828}, // 1e-73 + {0x25C6DA63C38DE1B0, 0xE2280B6C20DD5232}, // 1e-72 + {0x579C487E5A38AD0E, 0x8D590723948A535F}, // 1e-71 + {0x2D835A9DF0C6D851, 0xB0AF48EC79ACE837}, // 1e-70 + {0xF8E431456CF88E65, 0xDCDB1B2798182244}, // 1e-69 + {0x1B8E9ECB641B58FF, 0x8A08F0F8BF0F156B}, // 1e-68 + {0xE272467E3D222F3F, 0xAC8B2D36EED2DAC5}, // 1e-67 + {0x5B0ED81DCC6ABB0F, 0xD7ADF884AA879177}, // 1e-66 + {0x98E947129FC2B4E9, 0x86CCBB52EA94BAEA}, // 1e-65 + {0x3F2398D747B36224, 0xA87FEA27A539E9A5}, // 1e-64 + {0x8EEC7F0D19A03AAD, 0xD29FE4B18E88640E}, // 1e-63 + {0x1953CF68300424AC, 0x83A3EEEEF9153E89}, // 1e-62 + {0x5FA8C3423C052DD7, 0xA48CEAAAB75A8E2B}, // 1e-61 + {0x3792F412CB06794D, 0xCDB02555653131B6}, // 1e-60 + {0xE2BBD88BBEE40BD0, 0x808E17555F3EBF11}, // 1e-59 + {0x5B6ACEAEAE9D0EC4, 0xA0B19D2AB70E6ED6}, // 1e-58 + {0xF245825A5A445275, 0xC8DE047564D20A8B}, // 1e-57 + {0xEED6E2F0F0D56712, 0xFB158592BE068D2E}, // 1e-56 + {0x55464DD69685606B, 0x9CED737BB6C4183D}, // 1e-55 + {0xAA97E14C3C26B886, 0xC428D05AA4751E4C}, // 1e-54 + {0xD53DD99F4B3066A8, 0xF53304714D9265DF}, // 1e-53 + {0xE546A8038EFE4029, 0x993FE2C6D07B7FAB}, // 1e-52 + {0xDE98520472BDD033, 0xBF8FDB78849A5F96}, // 1e-51 + {0x963E66858F6D4440, 0xEF73D256A5C0F77C}, // 1e-50 + {0xDDE7001379A44AA8, 0x95A8637627989AAD}, // 1e-49 + {0x5560C018580D5D52, 0xBB127C53B17EC159}, // 1e-48 + {0xAAB8F01E6E10B4A6, 0xE9D71B689DDE71AF}, // 1e-47 + {0xCAB3961304CA70E8, 0x9226712162AB070D}, // 1e-46 + {0x3D607B97C5FD0D22, 0xB6B00D69BB55C8D1}, // 1e-45 + {0x8CB89A7DB77C506A, 0xE45C10C42A2B3B05}, // 1e-44 + {0x77F3608E92ADB242, 0x8EB98A7A9A5B04E3}, // 1e-43 + {0x55F038B237591ED3, 0xB267ED1940F1C61C}, // 1e-42 + {0x6B6C46DEC52F6688, 0xDF01E85F912E37A3}, // 1e-41 + {0x2323AC4B3B3DA015, 0x8B61313BBABCE2C6}, // 1e-40 + {0xABEC975E0A0D081A, 0xAE397D8AA96C1B77}, // 1e-39 + {0x96E7BD358C904A21, 0xD9C7DCED53C72255}, // 1e-38 + {0x7E50D64177DA2E54, 0x881CEA14545C7575}, // 1e-37 + {0xDDE50BD1D5D0B9E9, 0xAA242499697392D2}, // 1e-36 + {0x955E4EC64B44E864, 0xD4AD2DBFC3D07787}, // 1e-35 + {0xBD5AF13BEF0B113E, 0x84EC3C97DA624AB4}, // 1e-34 + {0xECB1AD8AEACDD58E, 0xA6274BBDD0FADD61}, // 1e-33 + {0x67DE18EDA5814AF2, 0xCFB11EAD453994BA}, // 1e-32 + {0x80EACF948770CED7, 0x81CEB32C4B43FCF4}, // 1e-31 + {0xA1258379A94D028D, 0xA2425FF75E14FC31}, // 1e-30 + {0x096EE45813A04330, 0xCAD2F7F5359A3B3E}, // 1e-29 + {0x8BCA9D6E188853FC, 0xFD87B5F28300CA0D}, // 1e-28 + {0x775EA264CF55347D, 0x9E74D1B791E07E48}, // 1e-27 + {0x95364AFE032A819D, 0xC612062576589DDA}, // 1e-26 + {0x3A83DDBD83F52204, 0xF79687AED3EEC551}, // 1e-25 + {0xC4926A9672793542, 0x9ABE14CD44753B52}, // 1e-24 + {0x75B7053C0F178293, 0xC16D9A0095928A27}, // 1e-23 + {0x5324C68B12DD6338, 0xF1C90080BAF72CB1}, // 1e-22 + {0xD3F6FC16EBCA5E03, 0x971DA05074DA7BEE}, // 1e-21 + {0x88F4BB1CA6BCF584, 0xBCE5086492111AEA}, // 1e-20 + {0x2B31E9E3D06C32E5, 0xEC1E4A7DB69561A5}, // 1e-19 + {0x3AFF322E62439FCF, 0x9392EE8E921D5D07}, // 1e-18 + {0x09BEFEB9FAD487C2, 0xB877AA3236A4B449}, // 1e-17 + {0x4C2EBE687989A9B3, 0xE69594BEC44DE15B}, // 1e-16 + {0x0F9D37014BF60A10, 0x901D7CF73AB0ACD9}, // 1e-15 + {0x538484C19EF38C94, 0xB424DC35095CD80F}, // 1e-14 + {0x2865A5F206B06FB9, 0xE12E13424BB40E13}, // 1e-13 + {0xF93F87B7442E45D3, 0x8CBCCC096F5088CB}, // 1e-12 + {0xF78F69A51539D748, 0xAFEBFF0BCB24AAFE}, // 1e-11 + {0xB573440E5A884D1B, 0xDBE6FECEBDEDD5BE}, // 1e-10 + {0x31680A88F8953030, 0x89705F4136B4A597}, // 1e-9 + {0xFDC20D2B36BA7C3D, 0xABCC77118461CEFC}, // 1e-8 + {0x3D32907604691B4C, 0xD6BF94D5E57A42BC}, // 1e-7 + {0xA63F9A49C2C1B10F, 0x8637BD05AF6C69B5}, // 1e-6 + {0x0FCF80DC33721D53, 0xA7C5AC471B478423}, // 1e-5 + {0xD3C36113404EA4A8, 0xD1B71758E219652B}, // 1e-4 + {0x645A1CAC083126E9, 0x83126E978D4FDF3B}, // 1e-3 + {0x3D70A3D70A3D70A3, 0xA3D70A3D70A3D70A}, // 1e-2 + {0xCCCCCCCCCCCCCCCC, 0xCCCCCCCCCCCCCCCC}, // 1e-1 + {0x0000000000000000, 0x8000000000000000}, // 1e0 + {0x0000000000000000, 0xA000000000000000}, // 1e1 + {0x0000000000000000, 0xC800000000000000}, // 1e2 + {0x0000000000000000, 0xFA00000000000000}, // 1e3 + {0x0000000000000000, 0x9C40000000000000}, // 1e4 + {0x0000000000000000, 0xC350000000000000}, // 1e5 + {0x0000000000000000, 0xF424000000000000}, // 1e6 + {0x0000000000000000, 0x9896800000000000}, // 1e7 + {0x0000000000000000, 0xBEBC200000000000}, // 1e8 + {0x0000000000000000, 0xEE6B280000000000}, // 1e9 + {0x0000000000000000, 0x9502F90000000000}, // 1e10 + {0x0000000000000000, 0xBA43B74000000000}, // 1e11 + {0x0000000000000000, 0xE8D4A51000000000}, // 1e12 + {0x0000000000000000, 0x9184E72A00000000}, // 1e13 + {0x0000000000000000, 0xB5E620F480000000}, // 1e14 + {0x0000000000000000, 0xE35FA931A0000000}, // 1e15 + {0x0000000000000000, 0x8E1BC9BF04000000}, // 1e16 + {0x0000000000000000, 0xB1A2BC2EC5000000}, // 1e17 + {0x0000000000000000, 0xDE0B6B3A76400000}, // 1e18 + {0x0000000000000000, 0x8AC7230489E80000}, // 1e19 + {0x0000000000000000, 0xAD78EBC5AC620000}, // 1e20 + {0x0000000000000000, 0xD8D726B7177A8000}, // 1e21 + {0x0000000000000000, 0x878678326EAC9000}, // 1e22 + {0x0000000000000000, 0xA968163F0A57B400}, // 1e23 + {0x0000000000000000, 0xD3C21BCECCEDA100}, // 1e24 + {0x0000000000000000, 0x84595161401484A0}, // 1e25 + {0x0000000000000000, 0xA56FA5B99019A5C8}, // 1e26 + {0x0000000000000000, 0xCECB8F27F4200F3A}, // 1e27 + {0x4000000000000000, 0x813F3978F8940984}, // 1e28 + {0x5000000000000000, 0xA18F07D736B90BE5}, // 1e29 + {0xA400000000000000, 0xC9F2C9CD04674EDE}, // 1e30 + {0x4D00000000000000, 0xFC6F7C4045812296}, // 1e31 + {0xF020000000000000, 0x9DC5ADA82B70B59D}, // 1e32 + {0x6C28000000000000, 0xC5371912364CE305}, // 1e33 + {0xC732000000000000, 0xF684DF56C3E01BC6}, // 1e34 + {0x3C7F400000000000, 0x9A130B963A6C115C}, // 1e35 + {0x4B9F100000000000, 0xC097CE7BC90715B3}, // 1e36 + {0x1E86D40000000000, 0xF0BDC21ABB48DB20}, // 1e37 + {0x1314448000000000, 0x96769950B50D88F4}, // 1e38 + {0x17D955A000000000, 0xBC143FA4E250EB31}, // 1e39 + {0x5DCFAB0800000000, 0xEB194F8E1AE525FD}, // 1e40 + {0x5AA1CAE500000000, 0x92EFD1B8D0CF37BE}, // 1e41 + {0xF14A3D9E40000000, 0xB7ABC627050305AD}, // 1e42 + {0x6D9CCD05D0000000, 0xE596B7B0C643C719}, // 1e43 + {0xE4820023A2000000, 0x8F7E32CE7BEA5C6F}, // 1e44 + {0xDDA2802C8A800000, 0xB35DBF821AE4F38B}, // 1e45 + {0xD50B2037AD200000, 0xE0352F62A19E306E}, // 1e46 + {0x4526F422CC340000, 0x8C213D9DA502DE45}, // 1e47 + {0x9670B12B7F410000, 0xAF298D050E4395D6}, // 1e48 + {0x3C0CDD765F114000, 0xDAF3F04651D47B4C}, // 1e49 + {0xA5880A69FB6AC800, 0x88D8762BF324CD0F}, // 1e50 + {0x8EEA0D047A457A00, 0xAB0E93B6EFEE0053}, // 1e51 + {0x72A4904598D6D880, 0xD5D238A4ABE98068}, // 1e52 + {0x47A6DA2B7F864750, 0x85A36366EB71F041}, // 1e53 + {0x999090B65F67D924, 0xA70C3C40A64E6C51}, // 1e54 + {0xFFF4B4E3F741CF6D, 0xD0CF4B50CFE20765}, // 1e55 + {0xBFF8F10E7A8921A4, 0x82818F1281ED449F}, // 1e56 + {0xAFF72D52192B6A0D, 0xA321F2D7226895C7}, // 1e57 + {0x9BF4F8A69F764490, 0xCBEA6F8CEB02BB39}, // 1e58 + {0x02F236D04753D5B4, 0xFEE50B7025C36A08}, // 1e59 + {0x01D762422C946590, 0x9F4F2726179A2245}, // 1e60 + {0x424D3AD2B7B97EF5, 0xC722F0EF9D80AAD6}, // 1e61 + {0xD2E0898765A7DEB2, 0xF8EBAD2B84E0D58B}, // 1e62 + {0x63CC55F49F88EB2F, 0x9B934C3B330C8577}, // 1e63 + {0x3CBF6B71C76B25FB, 0xC2781F49FFCFA6D5}, // 1e64 + {0x8BEF464E3945EF7A, 0xF316271C7FC3908A}, // 1e65 + {0x97758BF0E3CBB5AC, 0x97EDD871CFDA3A56}, // 1e66 + {0x3D52EEED1CBEA317, 0xBDE94E8E43D0C8EC}, // 1e67 + {0x4CA7AAA863EE4BDD, 0xED63A231D4C4FB27}, // 1e68 + {0x8FE8CAA93E74EF6A, 0x945E455F24FB1CF8}, // 1e69 + {0xB3E2FD538E122B44, 0xB975D6B6EE39E436}, // 1e70 + {0x60DBBCA87196B616, 0xE7D34C64A9C85D44}, // 1e71 + {0xBC8955E946FE31CD, 0x90E40FBEEA1D3A4A}, // 1e72 + {0x6BABAB6398BDBE41, 0xB51D13AEA4A488DD}, // 1e73 + {0xC696963C7EED2DD1, 0xE264589A4DCDAB14}, // 1e74 + {0xFC1E1DE5CF543CA2, 0x8D7EB76070A08AEC}, // 1e75 + {0x3B25A55F43294BCB, 0xB0DE65388CC8ADA8}, // 1e76 + {0x49EF0EB713F39EBE, 0xDD15FE86AFFAD912}, // 1e77 + {0x6E3569326C784337, 0x8A2DBF142DFCC7AB}, // 1e78 + {0x49C2C37F07965404, 0xACB92ED9397BF996}, // 1e79 + {0xDC33745EC97BE906, 0xD7E77A8F87DAF7FB}, // 1e80 + {0x69A028BB3DED71A3, 0x86F0AC99B4E8DAFD}, // 1e81 + {0xC40832EA0D68CE0C, 0xA8ACD7C0222311BC}, // 1e82 + {0xF50A3FA490C30190, 0xD2D80DB02AABD62B}, // 1e83 + {0x792667C6DA79E0FA, 0x83C7088E1AAB65DB}, // 1e84 + {0x577001B891185938, 0xA4B8CAB1A1563F52}, // 1e85 + {0xED4C0226B55E6F86, 0xCDE6FD5E09ABCF26}, // 1e86 + {0x544F8158315B05B4, 0x80B05E5AC60B6178}, // 1e87 + {0x696361AE3DB1C721, 0xA0DC75F1778E39D6}, // 1e88 + {0x03BC3A19CD1E38E9, 0xC913936DD571C84C}, // 1e89 + {0x04AB48A04065C723, 0xFB5878494ACE3A5F}, // 1e90 + {0x62EB0D64283F9C76, 0x9D174B2DCEC0E47B}, // 1e91 + {0x3BA5D0BD324F8394, 0xC45D1DF942711D9A}, // 1e92 + {0xCA8F44EC7EE36479, 0xF5746577930D6500}, // 1e93 + {0x7E998B13CF4E1ECB, 0x9968BF6ABBE85F20}, // 1e94 + {0x9E3FEDD8C321A67E, 0xBFC2EF456AE276E8}, // 1e95 + {0xC5CFE94EF3EA101E, 0xEFB3AB16C59B14A2}, // 1e96 + {0xBBA1F1D158724A12, 0x95D04AEE3B80ECE5}, // 1e97 + {0x2A8A6E45AE8EDC97, 0xBB445DA9CA61281F}, // 1e98 + {0xF52D09D71A3293BD, 0xEA1575143CF97226}, // 1e99 + {0x593C2626705F9C56, 0x924D692CA61BE758}, // 1e100 + {0x6F8B2FB00C77836C, 0xB6E0C377CFA2E12E}, // 1e101 + {0x0B6DFB9C0F956447, 0xE498F455C38B997A}, // 1e102 + {0x4724BD4189BD5EAC, 0x8EDF98B59A373FEC}, // 1e103 + {0x58EDEC91EC2CB657, 0xB2977EE300C50FE7}, // 1e104 + {0x2F2967B66737E3ED, 0xDF3D5E9BC0F653E1}, // 1e105 + {0xBD79E0D20082EE74, 0x8B865B215899F46C}, // 1e106 + {0xECD8590680A3AA11, 0xAE67F1E9AEC07187}, // 1e107 + {0xE80E6F4820CC9495, 0xDA01EE641A708DE9}, // 1e108 + {0x3109058D147FDCDD, 0x884134FE908658B2}, // 1e109 + {0xBD4B46F0599FD415, 0xAA51823E34A7EEDE}, // 1e110 + {0x6C9E18AC7007C91A, 0xD4E5E2CDC1D1EA96}, // 1e111 + {0x03E2CF6BC604DDB0, 0x850FADC09923329E}, // 1e112 + {0x84DB8346B786151C, 0xA6539930BF6BFF45}, // 1e113 + {0xE612641865679A63, 0xCFE87F7CEF46FF16}, // 1e114 + {0x4FCB7E8F3F60C07E, 0x81F14FAE158C5F6E}, // 1e115 + {0xE3BE5E330F38F09D, 0xA26DA3999AEF7749}, // 1e116 + {0x5CADF5BFD3072CC5, 0xCB090C8001AB551C}, // 1e117 + {0x73D9732FC7C8F7F6, 0xFDCB4FA002162A63}, // 1e118 + {0x2867E7FDDCDD9AFA, 0x9E9F11C4014DDA7E}, // 1e119 + {0xB281E1FD541501B8, 0xC646D63501A1511D}, // 1e120 + {0x1F225A7CA91A4226, 0xF7D88BC24209A565}, // 1e121 + {0x3375788DE9B06958, 0x9AE757596946075F}, // 1e122 + {0x0052D6B1641C83AE, 0xC1A12D2FC3978937}, // 1e123 + {0xC0678C5DBD23A49A, 0xF209787BB47D6B84}, // 1e124 + {0xF840B7BA963646E0, 0x9745EB4D50CE6332}, // 1e125 + {0xB650E5A93BC3D898, 0xBD176620A501FBFF}, // 1e126 + {0xA3E51F138AB4CEBE, 0xEC5D3FA8CE427AFF}, // 1e127 + {0xC66F336C36B10137, 0x93BA47C980E98CDF}, // 1e128 + {0xB80B0047445D4184, 0xB8A8D9BBE123F017}, // 1e129 + {0xA60DC059157491E5, 0xE6D3102AD96CEC1D}, // 1e130 + {0x87C89837AD68DB2F, 0x9043EA1AC7E41392}, // 1e131 + {0x29BABE4598C311FB, 0xB454E4A179DD1877}, // 1e132 + {0xF4296DD6FEF3D67A, 0xE16A1DC9D8545E94}, // 1e133 + {0x1899E4A65F58660C, 0x8CE2529E2734BB1D}, // 1e134 + {0x5EC05DCFF72E7F8F, 0xB01AE745B101E9E4}, // 1e135 + {0x76707543F4FA1F73, 0xDC21A1171D42645D}, // 1e136 + {0x6A06494A791C53A8, 0x899504AE72497EBA}, // 1e137 + {0x0487DB9D17636892, 0xABFA45DA0EDBDE69}, // 1e138 + {0x45A9D2845D3C42B6, 0xD6F8D7509292D603}, // 1e139 + {0x0B8A2392BA45A9B2, 0x865B86925B9BC5C2}, // 1e140 + {0x8E6CAC7768D7141E, 0xA7F26836F282B732}, // 1e141 + {0x3207D795430CD926, 0xD1EF0244AF2364FF}, // 1e142 + {0x7F44E6BD49E807B8, 0x8335616AED761F1F}, // 1e143 + {0x5F16206C9C6209A6, 0xA402B9C5A8D3A6E7}, // 1e144 + {0x36DBA887C37A8C0F, 0xCD036837130890A1}, // 1e145 + {0xC2494954DA2C9789, 0x802221226BE55A64}, // 1e146 + {0xF2DB9BAA10B7BD6C, 0xA02AA96B06DEB0FD}, // 1e147 + {0x6F92829494E5ACC7, 0xC83553C5C8965D3D}, // 1e148 + {0xCB772339BA1F17F9, 0xFA42A8B73ABBF48C}, // 1e149 + {0xFF2A760414536EFB, 0x9C69A97284B578D7}, // 1e150 + {0xFEF5138519684ABA, 0xC38413CF25E2D70D}, // 1e151 + {0x7EB258665FC25D69, 0xF46518C2EF5B8CD1}, // 1e152 + {0xEF2F773FFBD97A61, 0x98BF2F79D5993802}, // 1e153 + {0xAAFB550FFACFD8FA, 0xBEEEFB584AFF8603}, // 1e154 + {0x95BA2A53F983CF38, 0xEEAABA2E5DBF6784}, // 1e155 + {0xDD945A747BF26183, 0x952AB45CFA97A0B2}, // 1e156 + {0x94F971119AEEF9E4, 0xBA756174393D88DF}, // 1e157 + {0x7A37CD5601AAB85D, 0xE912B9D1478CEB17}, // 1e158 + {0xAC62E055C10AB33A, 0x91ABB422CCB812EE}, // 1e159 + {0x577B986B314D6009, 0xB616A12B7FE617AA}, // 1e160 + {0xED5A7E85FDA0B80B, 0xE39C49765FDF9D94}, // 1e161 + {0x14588F13BE847307, 0x8E41ADE9FBEBC27D}, // 1e162 + {0x596EB2D8AE258FC8, 0xB1D219647AE6B31C}, // 1e163 + {0x6FCA5F8ED9AEF3BB, 0xDE469FBD99A05FE3}, // 1e164 + {0x25DE7BB9480D5854, 0x8AEC23D680043BEE}, // 1e165 + {0xAF561AA79A10AE6A, 0xADA72CCC20054AE9}, // 1e166 + {0x1B2BA1518094DA04, 0xD910F7FF28069DA4}, // 1e167 + {0x90FB44D2F05D0842, 0x87AA9AFF79042286}, // 1e168 + {0x353A1607AC744A53, 0xA99541BF57452B28}, // 1e169 + {0x42889B8997915CE8, 0xD3FA922F2D1675F2}, // 1e170 + {0x69956135FEBADA11, 0x847C9B5D7C2E09B7}, // 1e171 + {0x43FAB9837E699095, 0xA59BC234DB398C25}, // 1e172 + {0x94F967E45E03F4BB, 0xCF02B2C21207EF2E}, // 1e173 + {0x1D1BE0EEBAC278F5, 0x8161AFB94B44F57D}, // 1e174 + {0x6462D92A69731732, 0xA1BA1BA79E1632DC}, // 1e175 + {0x7D7B8F7503CFDCFE, 0xCA28A291859BBF93}, // 1e176 + {0x5CDA735244C3D43E, 0xFCB2CB35E702AF78}, // 1e177 + {0x3A0888136AFA64A7, 0x9DEFBF01B061ADAB}, // 1e178 + {0x088AAA1845B8FDD0, 0xC56BAEC21C7A1916}, // 1e179 + {0x8AAD549E57273D45, 0xF6C69A72A3989F5B}, // 1e180 + {0x36AC54E2F678864B, 0x9A3C2087A63F6399}, // 1e181 + {0x84576A1BB416A7DD, 0xC0CB28A98FCF3C7F}, // 1e182 + {0x656D44A2A11C51D5, 0xF0FDF2D3F3C30B9F}, // 1e183 + {0x9F644AE5A4B1B325, 0x969EB7C47859E743}, // 1e184 + {0x873D5D9F0DDE1FEE, 0xBC4665B596706114}, // 1e185 + {0xA90CB506D155A7EA, 0xEB57FF22FC0C7959}, // 1e186 + {0x09A7F12442D588F2, 0x9316FF75DD87CBD8}, // 1e187 + {0x0C11ED6D538AEB2F, 0xB7DCBF5354E9BECE}, // 1e188 + {0x8F1668C8A86DA5FA, 0xE5D3EF282A242E81}, // 1e189 + {0xF96E017D694487BC, 0x8FA475791A569D10}, // 1e190 + {0x37C981DCC395A9AC, 0xB38D92D760EC4455}, // 1e191 + {0x85BBE253F47B1417, 0xE070F78D3927556A}, // 1e192 + {0x93956D7478CCEC8E, 0x8C469AB843B89562}, // 1e193 + {0x387AC8D1970027B2, 0xAF58416654A6BABB}, // 1e194 + {0x06997B05FCC0319E, 0xDB2E51BFE9D0696A}, // 1e195 + {0x441FECE3BDF81F03, 0x88FCF317F22241E2}, // 1e196 + {0xD527E81CAD7626C3, 0xAB3C2FDDEEAAD25A}, // 1e197 + {0x8A71E223D8D3B074, 0xD60B3BD56A5586F1}, // 1e198 + {0xF6872D5667844E49, 0x85C7056562757456}, // 1e199 + {0xB428F8AC016561DB, 0xA738C6BEBB12D16C}, // 1e200 + {0xE13336D701BEBA52, 0xD106F86E69D785C7}, // 1e201 + {0xECC0024661173473, 0x82A45B450226B39C}, // 1e202 + {0x27F002D7F95D0190, 0xA34D721642B06084}, // 1e203 + {0x31EC038DF7B441F4, 0xCC20CE9BD35C78A5}, // 1e204 + {0x7E67047175A15271, 0xFF290242C83396CE}, // 1e205 + {0x0F0062C6E984D386, 0x9F79A169BD203E41}, // 1e206 + {0x52C07B78A3E60868, 0xC75809C42C684DD1}, // 1e207 + {0xA7709A56CCDF8A82, 0xF92E0C3537826145}, // 1e208 + {0x88A66076400BB691, 0x9BBCC7A142B17CCB}, // 1e209 + {0x6ACFF893D00EA435, 0xC2ABF989935DDBFE}, // 1e210 + {0x0583F6B8C4124D43, 0xF356F7EBF83552FE}, // 1e211 + {0xC3727A337A8B704A, 0x98165AF37B2153DE}, // 1e212 + {0x744F18C0592E4C5C, 0xBE1BF1B059E9A8D6}, // 1e213 + {0x1162DEF06F79DF73, 0xEDA2EE1C7064130C}, // 1e214 + {0x8ADDCB5645AC2BA8, 0x9485D4D1C63E8BE7}, // 1e215 + {0x6D953E2BD7173692, 0xB9A74A0637CE2EE1}, // 1e216 + {0xC8FA8DB6CCDD0437, 0xE8111C87C5C1BA99}, // 1e217 + {0x1D9C9892400A22A2, 0x910AB1D4DB9914A0}, // 1e218 + {0x2503BEB6D00CAB4B, 0xB54D5E4A127F59C8}, // 1e219 + {0x2E44AE64840FD61D, 0xE2A0B5DC971F303A}, // 1e220 + {0x5CEAECFED289E5D2, 0x8DA471A9DE737E24}, // 1e221 + {0x7425A83E872C5F47, 0xB10D8E1456105DAD}, // 1e222 + {0xD12F124E28F77719, 0xDD50F1996B947518}, // 1e223 + {0x82BD6B70D99AAA6F, 0x8A5296FFE33CC92F}, // 1e224 + {0x636CC64D1001550B, 0xACE73CBFDC0BFB7B}, // 1e225 + {0x3C47F7E05401AA4E, 0xD8210BEFD30EFA5A}, // 1e226 + {0x65ACFAEC34810A71, 0x8714A775E3E95C78}, // 1e227 + {0x7F1839A741A14D0D, 0xA8D9D1535CE3B396}, // 1e228 + {0x1EDE48111209A050, 0xD31045A8341CA07C}, // 1e229 + {0x934AED0AAB460432, 0x83EA2B892091E44D}, // 1e230 + {0xF81DA84D5617853F, 0xA4E4B66B68B65D60}, // 1e231 + {0x36251260AB9D668E, 0xCE1DE40642E3F4B9}, // 1e232 + {0xC1D72B7C6B426019, 0x80D2AE83E9CE78F3}, // 1e233 + {0xB24CF65B8612F81F, 0xA1075A24E4421730}, // 1e234 + {0xDEE033F26797B627, 0xC94930AE1D529CFC}, // 1e235 + {0x169840EF017DA3B1, 0xFB9B7CD9A4A7443C}, // 1e236 + {0x8E1F289560EE864E, 0x9D412E0806E88AA5}, // 1e237 + {0xF1A6F2BAB92A27E2, 0xC491798A08A2AD4E}, // 1e238 + {0xAE10AF696774B1DB, 0xF5B5D7EC8ACB58A2}, // 1e239 + {0xACCA6DA1E0A8EF29, 0x9991A6F3D6BF1765}, // 1e240 + {0x17FD090A58D32AF3, 0xBFF610B0CC6EDD3F}, // 1e241 + {0xDDFC4B4CEF07F5B0, 0xEFF394DCFF8A948E}, // 1e242 + {0x4ABDAF101564F98E, 0x95F83D0A1FB69CD9}, // 1e243 + {0x9D6D1AD41ABE37F1, 0xBB764C4CA7A4440F}, // 1e244 + {0x84C86189216DC5ED, 0xEA53DF5FD18D5513}, // 1e245 + {0x32FD3CF5B4E49BB4, 0x92746B9BE2F8552C}, // 1e246 + {0x3FBC8C33221DC2A1, 0xB7118682DBB66A77}, // 1e247 + {0x0FABAF3FEAA5334A, 0xE4D5E82392A40515}, // 1e248 + {0x29CB4D87F2A7400E, 0x8F05B1163BA6832D}, // 1e249 + {0x743E20E9EF511012, 0xB2C71D5BCA9023F8}, // 1e250 + {0x914DA9246B255416, 0xDF78E4B2BD342CF6}, // 1e251 + {0x1AD089B6C2F7548E, 0x8BAB8EEFB6409C1A}, // 1e252 + {0xA184AC2473B529B1, 0xAE9672ABA3D0C320}, // 1e253 + {0xC9E5D72D90A2741E, 0xDA3C0F568CC4F3E8}, // 1e254 + {0x7E2FA67C7A658892, 0x8865899617FB1871}, // 1e255 + {0xDDBB901B98FEEAB7, 0xAA7EEBFB9DF9DE8D}, // 1e256 + {0x552A74227F3EA565, 0xD51EA6FA85785631}, // 1e257 + {0xD53A88958F87275F, 0x8533285C936B35DE}, // 1e258 + {0x8A892ABAF368F137, 0xA67FF273B8460356}, // 1e259 + {0x2D2B7569B0432D85, 0xD01FEF10A657842C}, // 1e260 + {0x9C3B29620E29FC73, 0x8213F56A67F6B29B}, // 1e261 + {0x8349F3BA91B47B8F, 0xA298F2C501F45F42}, // 1e262 + {0x241C70A936219A73, 0xCB3F2F7642717713}, // 1e263 + {0xED238CD383AA0110, 0xFE0EFB53D30DD4D7}, // 1e264 + {0xF4363804324A40AA, 0x9EC95D1463E8A506}, // 1e265 + {0xB143C6053EDCD0D5, 0xC67BB4597CE2CE48}, // 1e266 + {0xDD94B7868E94050A, 0xF81AA16FDC1B81DA}, // 1e267 + {0xCA7CF2B4191C8326, 0x9B10A4E5E9913128}, // 1e268 + {0xFD1C2F611F63A3F0, 0xC1D4CE1F63F57D72}, // 1e269 + {0xBC633B39673C8CEC, 0xF24A01A73CF2DCCF}, // 1e270 + {0xD5BE0503E085D813, 0x976E41088617CA01}, // 1e271 + {0x4B2D8644D8A74E18, 0xBD49D14AA79DBC82}, // 1e272 + {0xDDF8E7D60ED1219E, 0xEC9C459D51852BA2}, // 1e273 + {0xCABB90E5C942B503, 0x93E1AB8252F33B45}, // 1e274 + {0x3D6A751F3B936243, 0xB8DA1662E7B00A17}, // 1e275 + {0x0CC512670A783AD4, 0xE7109BFBA19C0C9D}, // 1e276 + {0x27FB2B80668B24C5, 0x906A617D450187E2}, // 1e277 + {0xB1F9F660802DEDF6, 0xB484F9DC9641E9DA}, // 1e278 + {0x5E7873F8A0396973, 0xE1A63853BBD26451}, // 1e279 + {0xDB0B487B6423E1E8, 0x8D07E33455637EB2}, // 1e280 + {0x91CE1A9A3D2CDA62, 0xB049DC016ABC5E5F}, // 1e281 + {0x7641A140CC7810FB, 0xDC5C5301C56B75F7}, // 1e282 + {0xA9E904C87FCB0A9D, 0x89B9B3E11B6329BA}, // 1e283 + {0x546345FA9FBDCD44, 0xAC2820D9623BF429}, // 1e284 + {0xA97C177947AD4095, 0xD732290FBACAF133}, // 1e285 + {0x49ED8EABCCCC485D, 0x867F59A9D4BED6C0}, // 1e286 + {0x5C68F256BFFF5A74, 0xA81F301449EE8C70}, // 1e287 + {0x73832EEC6FFF3111, 0xD226FC195C6A2F8C}, // 1e288 + {0xC831FD53C5FF7EAB, 0x83585D8FD9C25DB7}, // 1e289 + {0xBA3E7CA8B77F5E55, 0xA42E74F3D032F525}, // 1e290 + {0x28CE1BD2E55F35EB, 0xCD3A1230C43FB26F}, // 1e291 + {0x7980D163CF5B81B3, 0x80444B5E7AA7CF85}, // 1e292 + {0xD7E105BCC332621F, 0xA0555E361951C366}, // 1e293 + {0x8DD9472BF3FEFAA7, 0xC86AB5C39FA63440}, // 1e294 + {0xB14F98F6F0FEB951, 0xFA856334878FC150}, // 1e295 + {0x6ED1BF9A569F33D3, 0x9C935E00D4B9D8D2}, // 1e296 + {0x0A862F80EC4700C8, 0xC3B8358109E84F07}, // 1e297 + {0xCD27BB612758C0FA, 0xF4A642E14C6262C8}, // 1e298 + {0x8038D51CB897789C, 0x98E7E9CCCFBD7DBD}, // 1e299 + {0xE0470A63E6BD56C3, 0xBF21E44003ACDD2C}, // 1e300 + {0x1858CCFCE06CAC74, 0xEEEA5D5004981478}, // 1e301 + {0x0F37801E0C43EBC8, 0x95527A5202DF0CCB}, // 1e302 + {0xD30560258F54E6BA, 0xBAA718E68396CFFD}, // 1e303 + {0x47C6B82EF32A2069, 0xE950DF20247C83FD}, // 1e304 + {0x4CDC331D57FA5441, 0x91D28B7416CDD27E}, // 1e305 + {0xE0133FE4ADF8E952, 0xB6472E511C81471D}, // 1e306 + {0x58180FDDD97723A6, 0xE3D8F9E563A198E5}, // 1e307 + {0x570F09EAA7EA7648, 0x8E679C2F5E44FF8F}, // 1e308 + {0x2CD2CC6551E513DA, 0xB201833B35D63F73}, // 1e309 + {0xF8077F7EA65E58D1, 0xDE81E40A034BCF4F}, // 1e310 + {0xFB04AFAF27FAF782, 0x8B112E86420F6191}, // 1e311 + {0x79C5DB9AF1F9B563, 0xADD57A27D29339F6}, // 1e312 + {0x18375281AE7822BC, 0xD94AD8B1C7380874}, // 1e313 + {0x8F2293910D0B15B5, 0x87CEC76F1C830548}, // 1e314 + {0xB2EB3875504DDB22, 0xA9C2794AE3A3C69A}, // 1e315 + {0x5FA60692A46151EB, 0xD433179D9C8CB841}, // 1e316 + {0xDBC7C41BA6BCD333, 0x849FEEC281D7F328}, // 1e317 + {0x12B9B522906C0800, 0xA5C7EA73224DEFF3}, // 1e318 + {0xD768226B34870A00, 0xCF39E50FEAE16BEF}, // 1e319 + {0xE6A1158300D46640, 0x81842F29F2CCE375}, // 1e320 + {0x60495AE3C1097FD0, 0xA1E53AF46F801C53}, // 1e321 + {0x385BB19CB14BDFC4, 0xCA5E89B18B602368}, // 1e322 + {0x46729E03DD9ED7B5, 0xFCF62C1DEE382C42}, // 1e323 + {0x6C07A2C26A8346D1, 0x9E19DB92B4E31BA9}, // 1e324 + {0xC7098B7305241885, 0xC5A05277621BE293}, // 1e325 + {0xB8CBEE4FC66D1EA7, 0xF70867153AA2DB38}, // 1e326 + {0x737F74F1DC043328, 0x9A65406D44A5C903}, // 1e327 + {0x505F522E53053FF2, 0xC0FE908895CF3B44}, // 1e328 + {0x647726B9E7C68FEF, 0xF13E34AABB430A15}, // 1e329 + {0x5ECA783430DC19F5, 0x96C6E0EAB509E64D}, // 1e330 + {0xB67D16413D132072, 0xBC789925624C5FE0}, // 1e331 + {0xE41C5BD18C57E88F, 0xEB96BF6EBADF77D8}, // 1e332 + {0x8E91B962F7B6F159, 0x933E37A534CBAAE7}, // 1e333 + {0x723627BBB5A4ADB0, 0xB80DC58E81FE95A1}, // 1e334 + {0xCEC3B1AAA30DD91C, 0xE61136F2227E3B09}, // 1e335 + {0x213A4F0AA5E8A7B1, 0x8FCAC257558EE4E6}, // 1e336 + {0xA988E2CD4F62D19D, 0xB3BD72ED2AF29E1F}, // 1e337 + {0x93EB1B80A33B8605, 0xE0ACCFA875AF45A7}, // 1e338 + {0xBC72F130660533C3, 0x8C6C01C9498D8B88}, // 1e339 + {0xEB8FAD7C7F8680B4, 0xAF87023B9BF0EE6A}, // 1e340 + {0xA67398DB9F6820E1, 0xDB68C2CA82ED2A05}, // 1e341 + {0x88083F8943A1148C, 0x892179BE91D43A43}, // 1e342 + {0x6A0A4F6B948959B0, 0xAB69D82E364948D4}, // 1e343 + {0x848CE34679ABB01C, 0xD6444E39C3DB9B09}, // 1e344 + {0xF2D80E0C0C0B4E11, 0x85EAB0E41A6940E5}, // 1e345 + {0x6F8E118F0F0E2195, 0xA7655D1D2103911F}, // 1e346 + {0x4B7195F2D2D1A9FB, 0xD13EB46469447567}, // 1e347 +} diff --git a/gnovm/stdlibs/strconv/example_test.gno b/gnovm/stdlibs/strconv/example_test.gno new file mode 100644 index 00000000000..428fde4e660 --- /dev/null +++ b/gnovm/stdlibs/strconv/example_test.gno @@ -0,0 +1,440 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strconv_test + +import ( + "fmt" + "log" + "strconv" +) + +func ExampleAppendBool() { + b := []byte("bool:") + b = strconv.AppendBool(b, true) + fmt.Println(string(b)) + + // Output: + // bool:true +} + +func ExampleAppendFloat() { + b32 := []byte("float32:") + b32 = strconv.AppendFloat(b32, 3.1415926535, 'E', -1, 32) + fmt.Println(string(b32)) + + b64 := []byte("float64:") + b64 = strconv.AppendFloat(b64, 3.1415926535, 'E', -1, 64) + fmt.Println(string(b64)) + + // Output: + // float32:3.1415927E+00 + // float64:3.1415926535E+00 +} + +func ExampleAppendInt() { + b10 := []byte("int (base 10):") + b10 = strconv.AppendInt(b10, -42, 10) + fmt.Println(string(b10)) + + b16 := []byte("int (base 16):") + b16 = strconv.AppendInt(b16, -42, 16) + fmt.Println(string(b16)) + + // Output: + // int (base 10):-42 + // int (base 16):-2a +} + +func ExampleAppendQuote() { + b := []byte("quote:") + b = strconv.AppendQuote(b, `"Fran & Freddie's Diner"`) + fmt.Println(string(b)) + + // Output: + // quote:"\"Fran & Freddie's Diner\"" +} + +func ExampleAppendQuoteRune() { + b := []byte("rune:") + b = strconv.AppendQuoteRune(b, '☺') + fmt.Println(string(b)) + + // Output: + // rune:'☺' +} + +func ExampleAppendQuoteRuneToASCII() { + b := []byte("rune (ascii):") + b = strconv.AppendQuoteRuneToASCII(b, '☺') + fmt.Println(string(b)) + + // Output: + // rune (ascii):'\u263a' +} + +func ExampleAppendQuoteToASCII() { + b := []byte("quote (ascii):") + b = strconv.AppendQuoteToASCII(b, `"Fran & Freddie's Diner"`) + fmt.Println(string(b)) + + // Output: + // quote (ascii):"\"Fran & Freddie's Diner\"" +} + +func ExampleAppendUint() { + b10 := []byte("uint (base 10):") + b10 = strconv.AppendUint(b10, 42, 10) + fmt.Println(string(b10)) + + b16 := []byte("uint (base 16):") + b16 = strconv.AppendUint(b16, 42, 16) + fmt.Println(string(b16)) + + // Output: + // uint (base 10):42 + // uint (base 16):2a +} + +func ExampleAtoi() { + v := "10" + if s, err := strconv.Atoi(v); err == nil { + fmt.Printf("%T, %v", s, s) + } + + // Output: + // int, 10 +} + +func ExampleCanBackquote() { + fmt.Println(strconv.CanBackquote("Fran & Freddie's Diner ☺")) + fmt.Println(strconv.CanBackquote("`can't backquote this`")) + + // Output: + // true + // false +} + +func ExampleFormatBool() { + v := true + s := strconv.FormatBool(v) + fmt.Printf("%T, %v\n", s, s) + + // Output: + // string, true +} + +func ExampleFormatFloat() { + v := 3.1415926535 + + s32 := strconv.FormatFloat(v, 'E', -1, 32) + fmt.Printf("%T, %v\n", s32, s32) + + s64 := strconv.FormatFloat(v, 'E', -1, 64) + fmt.Printf("%T, %v\n", s64, s64) + + // fmt.Println uses these arguments to print floats + fmt64 := strconv.FormatFloat(v, 'g', -1, 64) + fmt.Printf("%T, %v\n", fmt64, fmt64) + + // Output: + // string, 3.1415927E+00 + // string, 3.1415926535E+00 + // string, 3.1415926535 +} + +func ExampleFormatInt() { + v := int64(-42) + + s10 := strconv.FormatInt(v, 10) + fmt.Printf("%T, %v\n", s10, s10) + + s16 := strconv.FormatInt(v, 16) + fmt.Printf("%T, %v\n", s16, s16) + + // Output: + // string, -42 + // string, -2a +} + +func ExampleFormatUint() { + v := uint64(42) + + s10 := strconv.FormatUint(v, 10) + fmt.Printf("%T, %v\n", s10, s10) + + s16 := strconv.FormatUint(v, 16) + fmt.Printf("%T, %v\n", s16, s16) + + // Output: + // string, 42 + // string, 2a +} + +func ExampleIsGraphic() { + shamrock := strconv.IsGraphic('☘') + fmt.Println(shamrock) + + a := strconv.IsGraphic('a') + fmt.Println(a) + + bel := strconv.IsGraphic('\007') + fmt.Println(bel) + + // Output: + // true + // true + // false +} + +func ExampleIsPrint() { + c := strconv.IsPrint('\u263a') + fmt.Println(c) + + bel := strconv.IsPrint('\007') + fmt.Println(bel) + + // Output: + // true + // false +} + +func ExampleItoa() { + i := 10 + s := strconv.Itoa(i) + fmt.Printf("%T, %v\n", s, s) + + // Output: + // string, 10 +} + +func ExampleParseBool() { + v := "true" + if s, err := strconv.ParseBool(v); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + + // Output: + // bool, true +} + +func ExampleParseFloat() { + v := "3.1415926535" + if s, err := strconv.ParseFloat(v, 32); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + if s, err := strconv.ParseFloat(v, 64); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + if s, err := strconv.ParseFloat("NaN", 32); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + // ParseFloat is case insensitive + if s, err := strconv.ParseFloat("nan", 32); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + if s, err := strconv.ParseFloat("inf", 32); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + if s, err := strconv.ParseFloat("+Inf", 32); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + if s, err := strconv.ParseFloat("-Inf", 32); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + if s, err := strconv.ParseFloat("-0", 32); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + if s, err := strconv.ParseFloat("+0", 32); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + + // Output: + // float64, 3.1415927410125732 + // float64, 3.1415926535 + // float64, NaN + // float64, NaN + // float64, +Inf + // float64, +Inf + // float64, -Inf + // float64, -0 + // float64, 0 +} + +func ExampleParseInt() { + v32 := "-354634382" + if s, err := strconv.ParseInt(v32, 10, 32); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + if s, err := strconv.ParseInt(v32, 16, 32); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + + v64 := "-3546343826724305832" + if s, err := strconv.ParseInt(v64, 10, 64); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + if s, err := strconv.ParseInt(v64, 16, 64); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + + // Output: + // int64, -354634382 + // int64, -3546343826724305832 +} + +func ExampleParseUint() { + v := "42" + if s, err := strconv.ParseUint(v, 10, 32); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + if s, err := strconv.ParseUint(v, 10, 64); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + + // Output: + // uint64, 42 + // uint64, 42 +} + +func ExampleQuote() { + // This string literal contains a tab character. + s := strconv.Quote(`"Fran & Freddie's Diner ☺"`) + fmt.Println(s) + + // Output: + // "\"Fran & Freddie's Diner\t☺\"" +} + +func ExampleQuoteRune() { + s := strconv.QuoteRune('☺') + fmt.Println(s) + + // Output: + // '☺' +} + +func ExampleQuoteRuneToASCII() { + s := strconv.QuoteRuneToASCII('☺') + fmt.Println(s) + + // Output: + // '\u263a' +} + +func ExampleQuoteRuneToGraphic() { + s := strconv.QuoteRuneToGraphic('☺') + fmt.Println(s) + + s = strconv.QuoteRuneToGraphic('\u263a') + fmt.Println(s) + + s = strconv.QuoteRuneToGraphic('\u000a') + fmt.Println(s) + + s = strconv.QuoteRuneToGraphic(' ') // tab character + fmt.Println(s) + + // Output: + // '☺' + // '☺' + // '\n' + // '\t' +} + +func ExampleQuoteToASCII() { + // This string literal contains a tab character. + s := strconv.QuoteToASCII(`"Fran & Freddie's Diner ☺"`) + fmt.Println(s) + + // Output: + // "\"Fran & Freddie's Diner\t\u263a\"" +} + +func ExampleQuoteToGraphic() { + s := strconv.QuoteToGraphic("☺") + fmt.Println(s) + + // This string literal contains a tab character. + s = strconv.QuoteToGraphic("This is a \u263a \u000a") + fmt.Println(s) + + s = strconv.QuoteToGraphic(`" This is a ☺ \n "`) + fmt.Println(s) + + // Output: + // "☺" + // "This is a ☺\t\n" + // "\" This is a ☺ \\n \"" +} + +func ExampleQuotedPrefix() { + s, err := strconv.QuotedPrefix("not a quoted string") + fmt.Printf("%q, %v\n", s, err) + s, err = strconv.QuotedPrefix("\"double-quoted string\" with trailing text") + fmt.Printf("%q, %v\n", s, err) + s, err = strconv.QuotedPrefix("`or backquoted` with more trailing text") + fmt.Printf("%q, %v\n", s, err) + s, err = strconv.QuotedPrefix("'\u263a' is also okay") + fmt.Printf("%q, %v\n", s, err) + + // Output: + // "", invalid syntax + // "\"double-quoted string\"", + // "`or backquoted`", + // "'☺'", +} + +func ExampleUnquote() { + s, err := strconv.Unquote("You can't unquote a string without quotes") + fmt.Printf("%q, %v\n", s, err) + s, err = strconv.Unquote("\"The string must be either double-quoted\"") + fmt.Printf("%q, %v\n", s, err) + s, err = strconv.Unquote("`or backquoted.`") + fmt.Printf("%q, %v\n", s, err) + s, err = strconv.Unquote("'\u263a'") // single character only allowed in single quotes + fmt.Printf("%q, %v\n", s, err) + s, err = strconv.Unquote("'\u2639\u2639'") + fmt.Printf("%q, %v\n", s, err) + + // Output: + // "", invalid syntax + // "The string must be either double-quoted", + // "or backquoted.", + // "☺", + // "", invalid syntax +} + +func ExampleUnquoteChar() { + v, mb, t, err := strconv.UnquoteChar(`\"Fran & Freddie's Diner\"`, '"') + if err != nil { + log.Fatal(err) + } + + fmt.Println("value:", string(v)) + fmt.Println("multibyte:", mb) + fmt.Println("tail:", t) + + // Output: + // value: " + // multibyte: false + // tail: Fran & Freddie's Diner\" +} + +func ExampleNumError() { + str := "Not a number" + if _, err := strconv.ParseFloat(str, 64); err != nil { + e := err.(*strconv.NumError) + fmt.Println("Func:", e.Func) + fmt.Println("Num:", e.Num) + fmt.Println("Err:", e.Err) + fmt.Println(err) + } + + // Output: + // Func: ParseFloat + // Num: Not a number + // Err: invalid syntax + // strconv.ParseFloat: parsing "Not a number": invalid syntax +} diff --git a/gnovm/stdlibs/strconv/export_test.gno b/gnovm/stdlibs/strconv/export_test.gno new file mode 100644 index 00000000000..8c03a7ffb4f --- /dev/null +++ b/gnovm/stdlibs/strconv/export_test.gno @@ -0,0 +1,10 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strconv + +var ( + BitSizeError = bitSizeError + BaseError = baseError +) diff --git a/gnovm/stdlibs/strconv/fp_test.gno b/gnovm/stdlibs/strconv/fp_test.gno new file mode 100644 index 00000000000..76cc95663c4 --- /dev/null +++ b/gnovm/stdlibs/strconv/fp_test.gno @@ -0,0 +1,320 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strconv_test + +import ( + "bufio" + "fmt" + "strconv" + "strings" + "testing" +) + +func pow2(i int) float64 { + switch { + case i < 0: + return 1 / pow2(-i) + case i == 0: + return 1 + case i == 1: + return 2 + } + return pow2(i/2) * pow2(i-i/2) +} + +// Wrapper around strconv.ParseFloat(x, 64). Handles dddddp+ddd (binary exponent) +// itself, passes the rest on to strconv.ParseFloat. +func myatof64(s string) (f float64, ok bool) { + if mant, exp, ok := strings.Cut(s, "p"); ok { + n, err := strconv.ParseInt(mant, 10, 64) + if err != nil { + return 0, false + } + e, err1 := strconv.Atoi(exp) + if err1 != nil { + println("bad e", exp) + return 0, false + } + v := float64(n) + // We expect that v*pow2(e) fits in a float64, + // but pow2(e) by itself may not. Be careful. + if e <= -1000 { + v *= pow2(-1000) + e += 1000 + for e < 0 { + v /= 2 + e++ + } + return v, true + } + if e >= 1000 { + v *= pow2(1000) + e -= 1000 + for e > 0 { + v *= 2 + e-- + } + return v, true + } + return v * pow2(e), true + } + f1, err := strconv.ParseFloat(s, 64) + if err != nil { + return 0, false + } + return f1, true +} + +// Wrapper around strconv.ParseFloat(x, 32). Handles dddddp+ddd (binary exponent) +// itself, passes the rest on to strconv.ParseFloat. +func myatof32(s string) (f float32, ok bool) { + if mant, exp, ok := strings.Cut(s, "p"); ok { + n, err := strconv.Atoi(mant) + if err != nil { + println("bad n", mant) + return 0, false + } + e, err1 := strconv.Atoi(exp) + if err1 != nil { + println("bad p", exp) + return 0, false + } + return float32(float64(n) * pow2(e)), true + } + f64, err1 := strconv.ParseFloat(s, 32) + f1 := float32(f64) + if err1 != nil { + return 0, false + } + return f1, true +} + +// XXX: copied from go source src/strconv/testdata/testfp.txt +// to avoid using os.Open in our tests +const testfp = `# Floating-point conversion test cases. +# Empty lines and lines beginning with # are ignored. +# The rest have four fields per line: type, format, input, and output. +# The input is given either in decimal or binary scientific notation. +# The output is the string that should be produced by formatting the +# input with the given format. +# +# The formats are as in C's printf, except that %b means print +# binary scientific notation: NpE = N x 2^E. + +# TODO: +# Powers of 10. +# Powers of 2. +# %.20g versions. +# random sources +# random targets +# random targets ± half a ULP + +# Difficult boundary cases, derived from tables given in +# Vern Paxson, A Program for Testing IEEE Decimal-Binary Conversion +# ftp://ftp.ee.lbl.gov/testbase-report.ps.Z + +# Table 1: Stress Inputs for Conversion to 53-bit Binary, < 1/2 ULP +float64 %b 5e+125 6653062250012735p+365 +float64 %b 69e+267 4705683757438170p+841 +float64 %b 999e-026 6798841691080350p-129 +float64 %b 7861e-034 8975675289889240p-153 +float64 %b 75569e-254 6091718967192243p-880 +float64 %b 928609e-261 7849264900213743p-900 +float64 %b 9210917e+080 8341110837370930p+236 +float64 %b 84863171e+114 4625202867375927p+353 +float64 %b 653777767e+273 5068902999763073p+884 +float64 %b 5232604057e-298 5741343011915040p-1010 +float64 %b 27235667517e-109 6707124626673586p-380 +float64 %b 653532977297e-123 7078246407265384p-422 +float64 %b 3142213164987e-294 8219991337640559p-988 +float64 %b 46202199371337e-072 5224462102115359p-246 +float64 %b 231010996856685e-073 5224462102115359p-247 +float64 %b 9324754620109615e+212 5539753864394442p+705 +float64 %b 78459735791271921e+049 8388176519442766p+166 +float64 %b 272104041512242479e+200 5554409530847367p+670 +float64 %b 6802601037806061975e+198 5554409530847367p+668 +float64 %b 20505426358836677347e-221 4524032052079546p-722 +float64 %b 836168422905420598437e-234 5070963299887562p-760 +float64 %b 4891559871276714924261e+222 6452687840519111p+757 + +# Table 2: Stress Inputs for Conversion to 53-bit Binary, > 1/2 ULP +float64 %b 9e-265 8168427841980010p-930 +float64 %b 85e-037 6360455125664090p-169 +float64 %b 623e+100 6263531988747231p+289 +float64 %b 3571e+263 6234526311072170p+833 +float64 %b 81661e+153 6696636728760206p+472 +float64 %b 920657e-023 5975405561110124p-109 +float64 %b 4603285e-024 5975405561110124p-110 +float64 %b 87575437e-309 8452160731874668p-1053 +float64 %b 245540327e+122 4985336549131723p+381 +float64 %b 6138508175e+120 4985336549131723p+379 +float64 %b 83356057653e+193 5986732817132056p+625 +float64 %b 619534293513e+124 4798406992060657p+399 +float64 %b 2335141086879e+218 5419088166961646p+713 +float64 %b 36167929443327e-159 8135819834632444p-536 +float64 %b 609610927149051e-255 4576664294594737p-850 +float64 %b 3743626360493413e-165 6898586531774201p-549 +float64 %b 94080055902682397e-242 6273271706052298p-800 +float64 %b 899810892172646163e+283 7563892574477827p+947 +float64 %b 7120190517612959703e+120 5385467232557565p+409 +float64 %b 25188282901709339043e-252 5635662608542340p-825 +float64 %b 308984926168550152811e-052 5644774693823803p-157 +float64 %b 6372891218502368041059e+064 4616868614322430p+233 + +# Table 3: Stress Inputs for Converting 53-bit Binary to Decimal, < 1/2 ULP +float64 %.0e 8511030020275656p-342 9e-88 +float64 %.1e 5201988407066741p-824 4.6e-233 +float64 %.2e 6406892948269899p+237 1.41e+87 +float64 %.3e 8431154198732492p+72 3.981e+37 +float64 %.4e 6475049196144587p+99 4.1040e+45 +float64 %.5e 8274307542972842p+726 2.92084e+234 +float64 %.6e 5381065484265332p-456 2.891946e-122 +float64 %.7e 6761728585499734p-1057 4.3787718e-303 +float64 %.8e 7976538478610756p+376 1.22770163e+129 +float64 %.9e 5982403858958067p+377 1.841552452e+129 +float64 %.10e 5536995190630837p+93 5.4835744350e+43 +float64 %.11e 7225450889282194p+710 3.89190181146e+229 +float64 %.12e 7225450889282194p+709 1.945950905732e+229 +float64 %.13e 8703372741147379p+117 1.4460958381605e+51 +float64 %.14e 8944262675275217p-1001 4.17367747458531e-286 +float64 %.15e 7459803696087692p-707 1.107950772878888e-197 +float64 %.16e 6080469016670379p-381 1.2345501366327440e-99 +float64 %.17e 8385515147034757p+721 9.25031711960365024e+232 +float64 %.18e 7514216811389786p-828 4.198047150284889840e-234 +float64 %.19e 8397297803260511p-345 1.1716315319786511046e-88 +float64 %.20e 6733459239310543p+202 4.32810072844612493629e+76 +float64 %.21e 8091450587292794p-473 3.317710118160031081518e-127 + +# Table 4: Stress Inputs for Converting 53-bit Binary to Decimal, > 1/2 ULP +float64 %.0e 6567258882077402p+952 3e+302 +float64 %.1e 6712731423444934p+535 7.6e+176 +float64 %.2e 6712731423444934p+534 3.78e+176 +float64 %.3e 5298405411573037p-957 4.350e-273 +float64 %.4e 5137311167659507p-144 2.3037e-28 +float64 %.5e 6722280709661868p+363 1.26301e+125 +float64 %.6e 5344436398034927p-169 7.142211e-36 +float64 %.7e 8369123604277281p-853 1.3934574e-241 +float64 %.8e 8995822108487663p-780 1.41463449e-219 +float64 %.9e 8942832835564782p-383 4.539277920e-100 +float64 %.10e 8942832835564782p-384 2.2696389598e-100 +float64 %.11e 8942832835564782p-385 1.13481947988e-100 +float64 %.12e 6965949469487146p-249 7.700366561890e-60 +float64 %.13e 6965949469487146p-250 3.8501832809448e-60 +float64 %.14e 6965949469487146p-251 1.92509164047238e-60 +float64 %.15e 7487252720986826p+548 6.898586531774201e+180 +float64 %.16e 5592117679628511p+164 1.3076622631878654e+65 +float64 %.17e 8887055249355788p+665 1.36052020756121240e+216 +float64 %.18e 6994187472632449p+690 3.592810217475959676e+223 +float64 %.19e 8797576579012143p+588 8.9125197712484551899e+192 +float64 %.20e 7363326733505337p+272 5.58769757362301140950e+97 +float64 %.21e 8549497411294502p-448 1.176257830728540379990e-119 + +# Table 14: Stress Inputs for Conversion to 24-bit Binary, <1/2 ULP +# NOTE: The lines with exponent p-149 have been changed from the +# paper. Those entries originally read p-150 and had a mantissa +# twice as large (and even), but IEEE single-precision has no p-150: +# that's the start of the denormals. +float32 %b 5e-20 15474250p-88 +float32 %b 67e+14 12479722p+29 +float32 %b 985e+15 14333636p+36 +# float32 %b 7693e-42 10979816p-150 +float32 %b 7693e-42 5489908p-149 +float32 %b 55895e-16 12888509p-61 +# float32 %b 996622e-44 14224264p-150 +float32 %b 996622e-44 7112132p-149 +float32 %b 7038531e-32 11420669p-107 +# float32 %b 60419369e-46 8623340p-150 +float32 %b 60419369e-46 4311670p-149 +float32 %b 702990899e-20 16209866p-61 +# float32 %b 6930161142e-48 9891056p-150 +float32 %b 6930161142e-48 4945528p-149 +float32 %b 25933168707e+13 14395800p+54 +float32 %b 596428896559e+20 12333860p+82 + +# Table 15: Stress Inputs for Conversion to 24-bit Binary, >1/2 ULP +float32 %b 3e-23 9507380p-98 +float32 %b 57e+18 12960300p+42 +float32 %b 789e-35 10739312p-130 +float32 %b 2539e-18 11990089p-72 +float32 %b 76173e+28 9845130p+86 +float32 %b 887745e-11 9760860p-40 +float32 %b 5382571e-37 11447463p-124 +float32 %b 82381273e-35 8554961p-113 +float32 %b 750486563e-38 9975678p-120 +float32 %b 3752432815e-39 9975678p-121 +float32 %b 75224575729e-45 13105970p-137 +float32 %b 459926601011e+15 12466336p+65 + +# Table 16: Stress Inputs for Converting 24-bit Binary to Decimal, < 1/2 ULP +float32 %.0e 12676506p-102 2e-24 +float32 %.1e 12676506p-103 1.2e-24 +float32 %.2e 15445013p+86 1.19e+33 +float32 %.3e 13734123p-138 3.941e-35 +float32 %.4e 12428269p-130 9.1308e-33 +float32 %.5e 15334037p-146 1.71900e-37 +float32 %.6e 11518287p-41 5.237910e-06 +float32 %.7e 12584953p-145 2.8216440e-37 +float32 %.8e 15961084p-125 3.75243281e-31 +float32 %.9e 14915817p-146 1.672120916e-37 +float32 %.10e 10845484p-102 2.1388945814e-24 +float32 %.11e 16431059p-61 7.12583594561e-12 + +# Table 17: Stress Inputs for Converting 24-bit Binary to Decimal, > 1/2 ULP +float32 %.0e 16093626p+69 1e+28 +float32 %.1e 9983778p+25 3.4e+14 +float32 %.2e 12745034p+104 2.59e+38 +float32 %.3e 12706553p+72 6.001e+28 +float32 %.4e 11005028p+45 3.8721e+20 +float32 %.5e 15059547p+71 3.55584e+28 +float32 %.6e 16015691p-99 2.526831e-23 +float32 %.7e 8667859p+56 6.2458507e+23 +float32 %.8e 14855922p-82 3.07213267e-18 +float32 %.9e 14855922p-83 1.536066333e-18 +float32 %.10e 10144164p-110 7.8147796834e-27 +float32 %.11e 13248074p+95 5.24810279937e+35 +` + +func TestFp(t *testing.T) { + s := bufio.NewScanner(strings.NewReader(testfp)) + + for lineno := 1; s.Scan(); lineno++ { + line := s.Text() + if len(line) == 0 || line[0] == '#' { + continue + } + a := strings.Split(line, " ") + if len(a) != 4 { + t.Error("testdata/testfp.txt:", lineno, ": wrong field count") + continue + } + var s string + var v float64 + switch a[0] { + case "float64": + var ok bool + v, ok = myatof64(a[2]) + if !ok { + t.Error("testdata/testfp.txt:", lineno, ": cannot atof64 ", a[2]) + continue + } + s = fmt.Sprintf(a[1], v) + case "float32": + v1, ok := myatof32(a[2]) + if !ok { + t.Error("testdata/testfp.txt:", lineno, ": cannot atof32 ", a[2]) + continue + } + s = fmt.Sprintf(a[1], v1) + v = float64(v1) + } + if s != a[3] { + t.Error("testdata/testfp.txt:", lineno, ": ", a[0], " ", a[1], " ", a[2], " (", v, ") ", + "want ", a[3], " got ", s) + } + } + if s.Err() != nil { + t.Fatal("testfp: read testdata/testfp.txt: ", s.Err()) + } +} diff --git a/gnovm/stdlibs/strconv/ftoa.gno b/gnovm/stdlibs/strconv/ftoa.gno new file mode 100644 index 00000000000..fcbf4df13b6 --- /dev/null +++ b/gnovm/stdlibs/strconv/ftoa.gno @@ -0,0 +1,584 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Binary to decimal floating point conversion. +// Algorithm: +// 1) store mantissa in multiprecision decimal +// 2) shift decimal by exponent +// 3) read digits out & format + +package strconv + +import "math" + +// TODO: move elsewhere? +type floatInfo struct { + mantbits uint + expbits uint + bias int +} + +var float32info = floatInfo{23, 8, -127} +var float64info = floatInfo{52, 11, -1023} + +// FormatFloat converts the floating-point number f to a string, +// according to the format fmt and precision prec. It rounds the +// result assuming that the original was obtained from a floating-point +// value of bitSize bits (32 for float32, 64 for float64). +// +// The format fmt is one of +// 'b' (-ddddp±ddd, a binary exponent), +// 'e' (-d.dddde±dd, a decimal exponent), +// 'E' (-d.ddddE±dd, a decimal exponent), +// 'f' (-ddd.dddd, no exponent), +// 'g' ('e' for large exponents, 'f' otherwise), +// 'G' ('E' for large exponents, 'f' otherwise), +// 'x' (-0xd.ddddp±ddd, a hexadecimal fraction and binary exponent), or +// 'X' (-0Xd.ddddP±ddd, a hexadecimal fraction and binary exponent). +// +// The precision prec controls the number of digits (excluding the exponent) +// printed by the 'e', 'E', 'f', 'g', 'G', 'x', and 'X' formats. +// For 'e', 'E', 'f', 'x', and 'X', it is the number of digits after the decimal point. +// For 'g' and 'G' it is the maximum number of significant digits (trailing +// zeros are removed). +// The special precision -1 uses the smallest number of digits +// necessary such that ParseFloat will return f exactly. +func FormatFloat(f float64, fmt byte, prec, bitSize int) string { + return string(genericFtoa(make([]byte, 0, max(prec+4, 24)), f, fmt, prec, bitSize)) +} + +// AppendFloat appends the string form of the floating-point number f, +// as generated by FormatFloat, to dst and returns the extended buffer. +func AppendFloat(dst []byte, f float64, fmt byte, prec, bitSize int) []byte { + return genericFtoa(dst, f, fmt, prec, bitSize) +} + +func genericFtoa(dst []byte, val float64, fmt byte, prec, bitSize int) []byte { + var bits uint64 + var flt *floatInfo + switch bitSize { + case 32: + bits = uint64(math.Float32bits(float32(val))) + flt = &float32info + case 64: + bits = math.Float64bits(val) + flt = &float64info + default: + panic("strconv: illegal AppendFloat/FormatFloat bitSize") + } + + neg := bits>>(flt.expbits+flt.mantbits) != 0 + exp := int(bits>>flt.mantbits) & (1< digs.nd && digs.nd >= digs.dp { + eprec = digs.nd + } + // %e is used if the exponent from the conversion + // is less than -4 or greater than or equal to the precision. + // if precision was the shortest possible, use precision 6 for this decision. + if shortest { + eprec = 6 + } + exp := digs.dp - 1 + if exp < -4 || exp >= eprec { + if prec > digs.nd { + prec = digs.nd + } + return fmtE(dst, neg, digs, prec-1, fmt+'e'-'g') + } + if prec > digs.dp { + prec = digs.nd + } + return fmtF(dst, neg, digs, max(prec-digs.dp, 0)) + } + + // unknown format + return append(dst, '%', fmt) +} + +// roundShortest rounds d (= mant * 2^exp) to the shortest number of digits +// that will let the original floating point value be precisely reconstructed. +func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) { + // If mantissa is zero, the number is zero; stop now. + if mant == 0 { + d.nd = 0 + return + } + + // Compute upper and lower such that any decimal number + // between upper and lower (possibly inclusive) + // will round to the original floating point number. + + // We may see at once that the number is already shortest. + // + // Suppose d is not denormal, so that 2^exp <= d < 10^dp. + // The closest shorter number is at least 10^(dp-nd) away. + // The lower/upper bounds computed below are at distance + // at most 2^(exp-mantbits). + // + // So the number is already shortest if 10^(dp-nd) > 2^(exp-mantbits), + // or equivalently log2(10)*(dp-nd) > exp-mantbits. + // It is true if 332/100*(dp-nd) >= exp-mantbits (log2(10) > 3.32). + minexp := flt.bias + 1 // minimum possible exponent + if exp > minexp && 332*(d.dp-d.nd) >= 100*(exp-int(flt.mantbits)) { + // The number is already shortest. + return + } + + // d = mant << (exp - mantbits) + // Next highest floating point number is mant+1 << exp-mantbits. + // Our upper bound is halfway between, mant*2+1 << exp-mantbits-1. + upper := new(decimal) + upper.Assign(mant*2 + 1) + upper.Shift(exp - int(flt.mantbits) - 1) + + // d = mant << (exp - mantbits) + // Next lowest floating point number is mant-1 << exp-mantbits, + // unless mant-1 drops the significant bit and exp is not the minimum exp, + // in which case the next lowest is mant*2-1 << exp-mantbits-1. + // Either way, call it mantlo << explo-mantbits. + // Our lower bound is halfway between, mantlo*2+1 << explo-mantbits-1. + var mantlo uint64 + var explo int + if mant > 1<= d.nd { + break + } + li := ui - upper.dp + lower.dp + l := byte('0') // lower digit + if li >= 0 && li < lower.nd { + l = lower.d[li] + } + m := byte('0') // middle digit + if mi >= 0 { + m = d.d[mi] + } + u := byte('0') // upper digit + if ui < upper.nd { + u = upper.d[ui] + } + + // Okay to round down (truncate) if lower has a different digit + // or if lower is inclusive and is exactly the result of rounding + // down (i.e., and we have reached the final digit of lower). + okdown := l != m || inclusive && li+1 == lower.nd + + switch { + case upperdelta == 0 && m+1 < u: + // Example: + // m = 12345xxx + // u = 12347xxx + upperdelta = 2 + case upperdelta == 0 && m != u: + // Example: + // m = 12345xxx + // u = 12346xxx + upperdelta = 1 + case upperdelta == 1 && (m != '9' || u != '0'): + // Example: + // m = 1234598x + // u = 1234600x + upperdelta = 2 + } + // Okay to round up if upper has a different digit and either upper + // is inclusive or upper is bigger than the result of rounding up. + okup := upperdelta > 0 && (inclusive || upperdelta > 1 || ui+1 < upper.nd) + + // If it's okay to do either, then round to the nearest one. + // If it's okay to do only one, do it. + switch { + case okdown && okup: + d.Round(mi + 1) + return + case okdown: + d.RoundDown(mi + 1) + return + case okup: + d.RoundUp(mi + 1) + return + } + } +} + +type decimalSlice struct { + d []byte + nd, dp int +} + +// %e: -d.ddddde±dd +func fmtE(dst []byte, neg bool, d decimalSlice, prec int, fmt byte) []byte { + // sign + if neg { + dst = append(dst, '-') + } + + // first digit + ch := byte('0') + if d.nd != 0 { + ch = d.d[0] + } + dst = append(dst, ch) + + // .moredigits + if prec > 0 { + dst = append(dst, '.') + i := 1 + m := min(d.nd, prec+1) + if i < m { + dst = append(dst, d.d[i:m]...) + i = m + } + for ; i <= prec; i++ { + dst = append(dst, '0') + } + } + + // e± + dst = append(dst, fmt) + exp := d.dp - 1 + if d.nd == 0 { // special case: 0 has exponent 0 + exp = 0 + } + if exp < 0 { + ch = '-' + exp = -exp + } else { + ch = '+' + } + dst = append(dst, ch) + + // dd or ddd + switch { + case exp < 10: + dst = append(dst, '0', byte(exp)+'0') + case exp < 100: + dst = append(dst, byte(exp/10)+'0', byte(exp%10)+'0') + default: + dst = append(dst, byte(exp/100)+'0', byte(exp/10)%10+'0', byte(exp%10)+'0') + } + + return dst +} + +// %f: -ddddddd.ddddd +func fmtF(dst []byte, neg bool, d decimalSlice, prec int) []byte { + // sign + if neg { + dst = append(dst, '-') + } + + // integer, padded with zeros as needed. + if d.dp > 0 { + m := min(d.nd, d.dp) + dst = append(dst, d.d[:m]...) + for ; m < d.dp; m++ { + dst = append(dst, '0') + } + } else { + dst = append(dst, '0') + } + + // fraction + if prec > 0 { + dst = append(dst, '.') + for i := 0; i < prec; i++ { + ch := byte('0') + if j := d.dp + i; 0 <= j && j < d.nd { + ch = d.d[j] + } + dst = append(dst, ch) + } + } + + return dst +} + +// %b: -ddddddddp±ddd +func fmtB(dst []byte, neg bool, mant uint64, exp int, flt *floatInfo) []byte { + // sign + if neg { + dst = append(dst, '-') + } + + // mantissa + dst, _ = formatBits(dst, mant, 10, false, true) + + // p + dst = append(dst, 'p') + + // ±exponent + exp -= int(flt.mantbits) + if exp >= 0 { + dst = append(dst, '+') + } + dst, _ = formatBits(dst, uint64(exp), 10, exp < 0, true) + + return dst +} + +// %x: -0x1.yyyyyyyyp±ddd or -0x0p+0. (y is hex digit, d is decimal digit) +func fmtX(dst []byte, prec int, fmt byte, neg bool, mant uint64, exp int, flt *floatInfo) []byte { + if mant == 0 { + exp = 0 + } + + // Shift digits so leading 1 (if any) is at bit 1<<60. + mant <<= 60 - flt.mantbits + for mant != 0 && mant&(1<<60) == 0 { + mant <<= 1 + exp-- + } + + // Round if requested. + if prec >= 0 && prec < 15 { + shift := uint(prec * 4) + extra := (mant << shift) & (1<<60 - 1) + mant >>= 60 - shift + if extra|(mant&1) > 1<<59 { + mant++ + } + mant <<= 60 - shift + if mant&(1<<61) != 0 { + // Wrapped around. + mant >>= 1 + exp++ + } + } + + hex := lowerhex + if fmt == 'X' { + hex = upperhex + } + + // sign, 0x, leading digit + if neg { + dst = append(dst, '-') + } + dst = append(dst, '0', fmt, '0'+byte((mant>>60)&1)) + + // .fraction + mant <<= 4 // remove leading 0 or 1 + if prec < 0 && mant != 0 { + dst = append(dst, '.') + for mant != 0 { + dst = append(dst, hex[(mant>>60)&15]) + mant <<= 4 + } + } else if prec > 0 { + dst = append(dst, '.') + for i := 0; i < prec; i++ { + dst = append(dst, hex[(mant>>60)&15]) + mant <<= 4 + } + } + + // p± + ch := byte('P') + if fmt == lower(fmt) { + ch = 'p' + } + dst = append(dst, ch) + if exp < 0 { + ch = '-' + exp = -exp + } else { + ch = '+' + } + dst = append(dst, ch) + + // dd or ddd or dddd + switch { + case exp < 100: + dst = append(dst, byte(exp/10)+'0', byte(exp%10)+'0') + case exp < 1000: + dst = append(dst, byte(exp/100)+'0', byte((exp/10)%10)+'0', byte(exp%10)+'0') + default: + dst = append(dst, byte(exp/1000)+'0', byte(exp/100)%10+'0', byte((exp/10)%10)+'0', byte(exp%10)+'0') + } + + return dst +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} diff --git a/gnovm/stdlibs/strconv/ftoa_test.gno b/gnovm/stdlibs/strconv/ftoa_test.gno new file mode 100644 index 00000000000..df1cc733827 --- /dev/null +++ b/gnovm/stdlibs/strconv/ftoa_test.gno @@ -0,0 +1,323 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strconv + +import ( + "math" + "math/rand" + "testing" +) + +type ftoaTest struct { + f float64 + fmt byte + prec int + s string +} + +func fdiv(a, b float64) float64 { return a / b } + +const ( + below1e23 = 99999999999999974834176 + above1e23 = 100000000000000008388608 +) + +var ftoatests = []ftoaTest{ + {1, 'e', 5, "1.00000e+00"}, + {1, 'f', 5, "1.00000"}, + {1, 'g', 5, "1"}, + {1, 'g', -1, "1"}, + {1, 'x', -1, "0x1p+00"}, + {1, 'x', 5, "0x1.00000p+00"}, + {20, 'g', -1, "20"}, + {20, 'x', -1, "0x1.4p+04"}, + {1234567.8, 'g', -1, "1.2345678e+06"}, + {1234567.8, 'x', -1, "0x1.2d687cccccccdp+20"}, + {200000, 'g', -1, "200000"}, + {200000, 'x', -1, "0x1.86ap+17"}, + {200000, 'X', -1, "0X1.86AP+17"}, + {2000000, 'g', -1, "2e+06"}, + {1e10, 'g', -1, "1e+10"}, + + // g conversion and zero suppression + {400, 'g', 2, "4e+02"}, + {40, 'g', 2, "40"}, + {4, 'g', 2, "4"}, + {.4, 'g', 2, "0.4"}, + {.04, 'g', 2, "0.04"}, + {.004, 'g', 2, "0.004"}, + {.0004, 'g', 2, "0.0004"}, + {.00004, 'g', 2, "4e-05"}, + {.000004, 'g', 2, "4e-06"}, + + {0, 'e', 5, "0.00000e+00"}, + {0, 'f', 5, "0.00000"}, + {0, 'g', 5, "0"}, + {0, 'g', -1, "0"}, + {0, 'x', 5, "0x0.00000p+00"}, + + {-1, 'e', 5, "-1.00000e+00"}, + {-1, 'f', 5, "-1.00000"}, + {-1, 'g', 5, "-1"}, + {-1, 'g', -1, "-1"}, + + {12, 'e', 5, "1.20000e+01"}, + {12, 'f', 5, "12.00000"}, + {12, 'g', 5, "12"}, + {12, 'g', -1, "12"}, + + {123456700, 'e', 5, "1.23457e+08"}, + {123456700, 'f', 5, "123456700.00000"}, + {123456700, 'g', 5, "1.2346e+08"}, + {123456700, 'g', -1, "1.234567e+08"}, + + {1.2345e6, 'e', 5, "1.23450e+06"}, + {1.2345e6, 'f', 5, "1234500.00000"}, + {1.2345e6, 'g', 5, "1.2345e+06"}, + + // Round to even + {1.2345e6, 'e', 3, "1.234e+06"}, + {1.2355e6, 'e', 3, "1.236e+06"}, + {1.2345, 'f', 3, "1.234"}, + {1.2355, 'f', 3, "1.236"}, + {1234567890123456.5, 'e', 15, "1.234567890123456e+15"}, + {1234567890123457.5, 'e', 15, "1.234567890123458e+15"}, + {108678236358137.625, 'g', -1, "1.0867823635813762e+14"}, + + {1e23, 'e', 17, "9.99999999999999916e+22"}, + {1e23, 'f', 17, "99999999999999991611392.00000000000000000"}, + {1e23, 'g', 17, "9.9999999999999992e+22"}, + + {1e23, 'e', -1, "1e+23"}, + {1e23, 'f', -1, "100000000000000000000000"}, + {1e23, 'g', -1, "1e+23"}, + + {below1e23, 'e', 17, "9.99999999999999748e+22"}, + {below1e23, 'f', 17, "99999999999999974834176.00000000000000000"}, + {below1e23, 'g', 17, "9.9999999999999975e+22"}, + + {below1e23, 'e', -1, "9.999999999999997e+22"}, + {below1e23, 'f', -1, "99999999999999970000000"}, + {below1e23, 'g', -1, "9.999999999999997e+22"}, + + {above1e23, 'e', 17, "1.00000000000000008e+23"}, + {above1e23, 'f', 17, "100000000000000008388608.00000000000000000"}, + {above1e23, 'g', 17, "1.0000000000000001e+23"}, + + {above1e23, 'e', -1, "1.0000000000000001e+23"}, + {above1e23, 'f', -1, "100000000000000010000000"}, + {above1e23, 'g', -1, "1.0000000000000001e+23"}, + + {fdiv(5e-304, 1e20), 'g', -1, "5e-324"}, // avoid constant arithmetic + {fdiv(-5e-304, 1e20), 'g', -1, "-5e-324"}, // avoid constant arithmetic + + {32, 'g', -1, "32"}, + {32, 'g', 0, "3e+01"}, + + {100, 'x', -1, "0x1.9p+06"}, + {100, 'y', -1, "%y"}, + + {math.NaN(), 'g', -1, "NaN"}, + {-math.NaN(), 'g', -1, "NaN"}, + {math.Inf(0), 'g', -1, "+Inf"}, + {math.Inf(-1), 'g', -1, "-Inf"}, + {-math.Inf(0), 'g', -1, "-Inf"}, + + {-1, 'b', -1, "-4503599627370496p-52"}, + + // fixed bugs + {0.9, 'f', 1, "0.9"}, + {0.09, 'f', 1, "0.1"}, + {0.0999, 'f', 1, "0.1"}, + {0.05, 'f', 1, "0.1"}, + {0.05, 'f', 0, "0"}, + {0.5, 'f', 1, "0.5"}, + {0.5, 'f', 0, "0"}, + {1.5, 'f', 0, "2"}, + + // https://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/ + {2.2250738585072012e-308, 'g', -1, "2.2250738585072014e-308"}, + // https://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/ + {2.2250738585072011e-308, 'g', -1, "2.225073858507201e-308"}, + + // Issue 2625. + {383260575764816448, 'f', 0, "383260575764816448"}, + {383260575764816448, 'g', -1, "3.8326057576481645e+17"}, + + // Issue 29491. + {498484681984085570, 'f', -1, "498484681984085570"}, + {-5.8339553793802237e+23, 'g', -1, "-5.8339553793802237e+23"}, + + // Issue 52187 + {123.45, '?', 0, "%?"}, + {123.45, '?', 1, "%?"}, + {123.45, '?', -1, "%?"}, + + // rounding + {2.275555555555555, 'x', -1, "0x1.23456789abcdep+01"}, + {2.275555555555555, 'x', 0, "0x1p+01"}, + {2.275555555555555, 'x', 2, "0x1.23p+01"}, + {2.275555555555555, 'x', 16, "0x1.23456789abcde000p+01"}, + {2.275555555555555, 'x', 21, "0x1.23456789abcde00000000p+01"}, + {2.2755555510520935, 'x', -1, "0x1.2345678p+01"}, + {2.2755555510520935, 'x', 6, "0x1.234568p+01"}, + {2.275555431842804, 'x', -1, "0x1.2345668p+01"}, + {2.275555431842804, 'x', 6, "0x1.234566p+01"}, + {3.999969482421875, 'x', -1, "0x1.ffffp+01"}, + {3.999969482421875, 'x', 4, "0x1.ffffp+01"}, + {3.999969482421875, 'x', 3, "0x1.000p+02"}, + {3.999969482421875, 'x', 2, "0x1.00p+02"}, + {3.999969482421875, 'x', 1, "0x1.0p+02"}, + {3.999969482421875, 'x', 0, "0x1p+02"}, +} + +func TestFtoa(t *testing.T) { + for i := 0; i < len(ftoatests); i++ { + test := &ftoatests[i] + s := FormatFloat(test.f, test.fmt, test.prec, 64) + if s != test.s { + t.Error("testN=64", test.f, string(test.fmt), test.prec, "want", test.s, "got", s) + } + x := AppendFloat([]byte("abc"), test.f, test.fmt, test.prec, 64) + if string(x) != "abc"+test.s { + t.Error("AppendFloat testN=64", test.f, string(test.fmt), test.prec, "want", "abc"+test.s, "got", string(x)) + } + if float64(float32(test.f)) == test.f && test.fmt != 'b' { + s := FormatFloat(test.f, test.fmt, test.prec, 32) + if s != test.s { + t.Error("testN=32", test.f, string(test.fmt), test.prec, "want", test.s, "got", s) + } + x := AppendFloat([]byte("abc"), test.f, test.fmt, test.prec, 32) + if string(x) != "abc"+test.s { + t.Error("AppendFloat testN=32", test.f, string(test.fmt), test.prec, "want", "abc"+test.s, "got", string(x)) + } + } + } +} + +func TestFtoaPowersOfTwo(t *testing.T) { + for exp := -2048; exp <= 2048; exp++ { + f := math.Ldexp(1, exp) + if !math.IsInf(f, 0) { + s := FormatFloat(f, 'e', -1, 64) + if x, _ := ParseFloat(s, 64); x != f { + t.Errorf("failed roundtrip %v => %s => %v", f, s, x) + } + } + f32 := float32(f) + if !math.IsInf(float64(f32), 0) { + s := FormatFloat(float64(f32), 'e', -1, 32) + if x, _ := ParseFloat(s, 32); float32(x) != f32 { + t.Errorf("failed roundtrip %v => %s => %v", f32, s, float32(x)) + } + } + } +} + +func TestFtoaRandom(t *testing.T) { + N := int(1e4) + if testing.Short() { + N = 100 + } + t.Logf("testing %d random numbers with fast and slow FormatFloat", N) + for i := 0; i < N; i++ { + bits := uint64(rand.Uint32())<<32 | uint64(rand.Uint32()) + x := math.Float64frombits(bits) + + shortFast := FormatFloat(x, 'g', -1, 64) + SetOptimize(false) + shortSlow := FormatFloat(x, 'g', -1, 64) + SetOptimize(true) + if shortSlow != shortFast { + t.Errorf("%b printed as %s, want %s", x, shortFast, shortSlow) + } + + prec := rand.IntN(12) + 5 + shortFast = FormatFloat(x, 'e', prec, 64) + SetOptimize(false) + shortSlow = FormatFloat(x, 'e', prec, 64) + SetOptimize(true) + if shortSlow != shortFast { + t.Errorf("%b printed as %s, want %s", x, shortFast, shortSlow) + } + } +} + +func TestFormatFloatInvalidBitSize(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Fatalf("expected panic due to invalid bitSize") + } + }() + _ = FormatFloat(3.14, 'g', -1, 100) +} + +var ftoaBenches = []struct { + name string + float float64 + fmt byte + prec int + bitSize int +}{ + {"Decimal", 33909, 'g', -1, 64}, + {"Float", 339.7784, 'g', -1, 64}, + {"Exp", -5.09e75, 'g', -1, 64}, + {"NegExp", -5.11e-95, 'g', -1, 64}, + {"LongExp", 1.234567890123456e-78, 'g', -1, 64}, + + {"Big", 123456789123456789123456789, 'g', -1, 64}, + {"BinaryExp", -1, 'b', -1, 64}, + + {"32Integer", 33909, 'g', -1, 32}, + {"32ExactFraction", 3.375, 'g', -1, 32}, + {"32Point", 339.7784, 'g', -1, 32}, + {"32Exp", -5.09e25, 'g', -1, 32}, + {"32NegExp", -5.11e-25, 'g', -1, 32}, + {"32Shortest", 1.234567e-8, 'g', -1, 32}, + {"32Fixed8Hard", math.Ldexp(15961084, -125), 'e', 8, 32}, + {"32Fixed9Hard", math.Ldexp(14855922, -83), 'e', 9, 32}, + + {"64Fixed1", 123456, 'e', 3, 64}, + {"64Fixed2", 123.456, 'e', 3, 64}, + {"64Fixed3", 1.23456e+78, 'e', 3, 64}, + {"64Fixed4", 1.23456e-78, 'e', 3, 64}, + {"64Fixed12", 1.23456e-78, 'e', 12, 64}, + {"64Fixed16", 1.23456e-78, 'e', 16, 64}, + // From testdata/testfp.txt + {"64Fixed12Hard", math.Ldexp(6965949469487146, -249), 'e', 12, 64}, + {"64Fixed17Hard", math.Ldexp(8887055249355788, 665), 'e', 17, 64}, + {"64Fixed18Hard", math.Ldexp(6994187472632449, 690), 'e', 18, 64}, + + // Trigger slow path (see issue #15672). + // The shortest is: 8.034137530808823e+43 + {"Slowpath64", 8.03413753080882349e+43, 'e', -1, 64}, + // This denormal is pathological because the lower/upper + // halfways to neighboring floats are: + // 622666234635.321003e-320 ~= 622666234635.321e-320 + // 622666234635.321497e-320 ~= 622666234635.3215e-320 + // making it hard to find the 3rd digit + {"SlowpathDenormal64", 622666234635.3213e-320, 'e', -1, 64}, +} + +func BenchmarkFormatFloat(b *testing.B) { + for _, c := range ftoaBenches { + b.Run(c.name, func(b *testing.B) { + for i := 0; i < b.N; i++ { + FormatFloat(c.float, c.fmt, c.prec, c.bitSize) + } + }) + } +} + +func BenchmarkAppendFloat(b *testing.B) { + dst := make([]byte, 30) + for _, c := range ftoaBenches { + b.Run(c.name, func(b *testing.B) { + for i := 0; i < b.N; i++ { + AppendFloat(dst[:0], c.float, c.fmt, c.prec, c.bitSize) + } + }) + } +} diff --git a/gnovm/stdlibs/strconv/ftoaryu.gno b/gnovm/stdlibs/strconv/ftoaryu.gno new file mode 100644 index 00000000000..2e7bf71df0b --- /dev/null +++ b/gnovm/stdlibs/strconv/ftoaryu.gno @@ -0,0 +1,569 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strconv + +import ( + "math/bits" +) + +// binary to decimal conversion using the Ryū algorithm. +// +// See Ulf Adams, "Ryū: Fast Float-to-String Conversion" (doi:10.1145/3192366.3192369) +// +// Fixed precision formatting is a variant of the original paper's +// algorithm, where a single multiplication by 10^k is required, +// sharing the same rounding guarantees. + +// ryuFtoaFixed32 formats mant*(2^exp) with prec decimal digits. +func ryuFtoaFixed32(d *decimalSlice, mant uint32, exp int, prec int) { + if prec < 0 { + panic("ryuFtoaFixed32 called with negative prec") + } + if prec > 9 { + panic("ryuFtoaFixed32 called with prec > 9") + } + // Zero input. + if mant == 0 { + d.nd, d.dp = 0, 0 + return + } + // Renormalize to a 25-bit mantissa. + e2 := exp + if b := bits.Len32(mant); b < 25 { + mant <<= uint(25 - b) + e2 += b - 25 + } + // Choose an exponent such that rounded mant*(2^e2)*(10^q) has + // at least prec decimal digits, i.e + // mant*(2^e2)*(10^q) >= 10^(prec-1) + // Because mant >= 2^24, it is enough to choose: + // 2^(e2+24) >= 10^(-q+prec-1) + // or q = -mulByLog2Log10(e2+24) + prec - 1 + q := -mulByLog2Log10(e2+24) + prec - 1 + + // Now compute mant*(2^e2)*(10^q). + // Is it an exact computation? + // Only small positive powers of 10 are exact (5^28 has 66 bits). + exact := q <= 27 && q >= 0 + + di, dexp2, d0 := mult64bitPow10(mant, e2, q) + if dexp2 >= 0 { + panic("not enough significant bits after mult64bitPow10") + } + // As a special case, computation might still be exact, if exponent + // was negative and if it amounts to computing an exact division. + // In that case, we ignore all lower bits. + // Note that division by 10^11 cannot be exact as 5^11 has 26 bits. + if q < 0 && q >= -10 && divisibleByPower5(uint64(mant), -q) { + exact = true + d0 = true + } + // Remove extra lower bits and keep rounding info. + extra := uint(-dexp2) + extraMask := uint32(1<>extra, di&extraMask + roundUp := false + if exact { + // If we computed an exact product, d + 1/2 + // should round to d+1 if 'd' is odd. + roundUp = dfrac > 1<<(extra-1) || + (dfrac == 1<<(extra-1) && !d0) || + (dfrac == 1<<(extra-1) && d0 && di&1 == 1) + } else { + // otherwise, d+1/2 always rounds up because + // we truncated below. + roundUp = dfrac>>(extra-1) == 1 + } + if dfrac != 0 { + d0 = false + } + // Proceed to the requested number of digits + formatDecimal(d, uint64(di), !d0, roundUp, prec) + // Adjust exponent + d.dp -= q +} + +// ryuFtoaFixed64 formats mant*(2^exp) with prec decimal digits. +func ryuFtoaFixed64(d *decimalSlice, mant uint64, exp int, prec int) { + if prec > 18 { + panic("ryuFtoaFixed64 called with prec > 18") + } + // Zero input. + if mant == 0 { + d.nd, d.dp = 0, 0 + return + } + // Renormalize to a 55-bit mantissa. + e2 := exp + if b := bits.Len64(mant); b < 55 { + mant = mant << uint(55-b) + e2 += b - 55 + } + // Choose an exponent such that rounded mant*(2^e2)*(10^q) has + // at least prec decimal digits, i.e + // mant*(2^e2)*(10^q) >= 10^(prec-1) + // Because mant >= 2^54, it is enough to choose: + // 2^(e2+54) >= 10^(-q+prec-1) + // or q = -mulByLog2Log10(e2+54) + prec - 1 + // + // The minimal required exponent is -mulByLog2Log10(1025)+18 = -291 + // The maximal required exponent is mulByLog2Log10(1074)+18 = 342 + q := -mulByLog2Log10(e2+54) + prec - 1 + + // Now compute mant*(2^e2)*(10^q). + // Is it an exact computation? + // Only small positive powers of 10 are exact (5^55 has 128 bits). + exact := q <= 55 && q >= 0 + + di, dexp2, d0 := mult128bitPow10(mant, e2, q) + if dexp2 >= 0 { + panic("not enough significant bits after mult128bitPow10") + } + // As a special case, computation might still be exact, if exponent + // was negative and if it amounts to computing an exact division. + // In that case, we ignore all lower bits. + // Note that division by 10^23 cannot be exact as 5^23 has 54 bits. + if q < 0 && q >= -22 && divisibleByPower5(mant, -q) { + exact = true + d0 = true + } + // Remove extra lower bits and keep rounding info. + extra := uint(-dexp2) + extraMask := uint64(1<>extra, di&extraMask + roundUp := false + if exact { + // If we computed an exact product, d + 1/2 + // should round to d+1 if 'd' is odd. + roundUp = dfrac > 1<<(extra-1) || + (dfrac == 1<<(extra-1) && !d0) || + (dfrac == 1<<(extra-1) && d0 && di&1 == 1) + } else { + // otherwise, d+1/2 always rounds up because + // we truncated below. + roundUp = dfrac>>(extra-1) == 1 + } + if dfrac != 0 { + d0 = false + } + // Proceed to the requested number of digits + formatDecimal(d, di, !d0, roundUp, prec) + // Adjust exponent + d.dp -= q +} + +var uint64pow10 = [...]uint64{ + 1, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, +} + +// formatDecimal fills d with at most prec decimal digits +// of mantissa m. The boolean trunc indicates whether m +// is truncated compared to the original number being formatted. +func formatDecimal(d *decimalSlice, m uint64, trunc bool, roundUp bool, prec int) { + max := uint64pow10[prec] + trimmed := 0 + for m >= max { + a, b := m/10, m%10 + m = a + trimmed++ + if b > 5 { + roundUp = true + } else if b < 5 { + roundUp = false + } else { // b == 5 + // round up if there are trailing digits, + // or if the new value of m is odd (round-to-even convention) + roundUp = trunc || m&1 == 1 + } + if b != 0 { + trunc = true + } + } + if roundUp { + m++ + } + if m >= max { + // Happens if di was originally 99999....xx + m /= 10 + trimmed++ + } + // render digits (similar to formatBits) + n := uint(prec) + d.nd = prec + v := m + for v >= 100 { + var v1, v2 uint64 + if v>>32 == 0 { + v1, v2 = uint64(uint32(v)/100), uint64(uint32(v)%100) + } else { + v1, v2 = v/100, v%100 + } + n -= 2 + d.d[n+1] = smallsString[2*v2+1] + d.d[n+0] = smallsString[2*v2+0] + v = v1 + } + if v > 0 { + n-- + d.d[n] = smallsString[2*v+1] + } + if v >= 10 { + n-- + d.d[n] = smallsString[2*v] + } + for d.d[d.nd-1] == '0' { + d.nd-- + trimmed++ + } + d.dp = d.nd + trimmed +} + +// ryuFtoaShortest formats mant*2^exp with prec decimal digits. +func ryuFtoaShortest(d *decimalSlice, mant uint64, exp int, flt *floatInfo) { + if mant == 0 { + d.nd, d.dp = 0, 0 + return + } + // If input is an exact integer with fewer bits than the mantissa, + // the previous and next integer are not admissible representations. + if exp <= 0 && bits.TrailingZeros64(mant) >= -exp { + mant >>= uint(-exp) + ryuDigits(d, mant, mant, mant, true, false) + return + } + ml, mc, mu, e2 := computeBounds(mant, exp, flt) + if e2 == 0 { + ryuDigits(d, ml, mc, mu, true, false) + return + } + // Find 10^q *larger* than 2^-e2 + q := mulByLog2Log10(-e2) + 1 + + // We are going to multiply by 10^q using 128-bit arithmetic. + // The exponent is the same for all 3 numbers. + var dl, dc, du uint64 + var dl0, dc0, du0 bool + if flt == &float32info { + var dl32, dc32, du32 uint32 + dl32, _, dl0 = mult64bitPow10(uint32(ml), e2, q) + dc32, _, dc0 = mult64bitPow10(uint32(mc), e2, q) + du32, e2, du0 = mult64bitPow10(uint32(mu), e2, q) + dl, dc, du = uint64(dl32), uint64(dc32), uint64(du32) + } else { + dl, _, dl0 = mult128bitPow10(ml, e2, q) + dc, _, dc0 = mult128bitPow10(mc, e2, q) + du, e2, du0 = mult128bitPow10(mu, e2, q) + } + if e2 >= 0 { + panic("not enough significant bits after mult128bitPow10") + } + // Is it an exact computation? + if q > 55 { + // Large positive powers of ten are not exact + dl0, dc0, du0 = false, false, false + } + if q < 0 && q >= -24 { + // Division by a power of ten may be exact. + // (note that 5^25 is a 59-bit number so division by 5^25 is never exact). + if divisibleByPower5(ml, -q) { + dl0 = true + } + if divisibleByPower5(mc, -q) { + dc0 = true + } + if divisibleByPower5(mu, -q) { + du0 = true + } + } + // Express the results (dl, dc, du)*2^e2 as integers. + // Extra bits must be removed and rounding hints computed. + extra := uint(-e2) + extraMask := uint64(1<>extra, dl&extraMask + dc, fracc := dc>>extra, dc&extraMask + du, fracu := du>>extra, du&extraMask + // Is it allowed to use 'du' as a result? + // It is always allowed when it is truncated, but also + // if it is exact and the original binary mantissa is even + // When disallowed, we can subtract 1. + uok := !du0 || fracu > 0 + if du0 && fracu == 0 { + uok = mant&1 == 0 + } + if !uok { + du-- + } + // Is 'dc' the correctly rounded base 10 mantissa? + // The correct rounding might be dc+1 + cup := false // don't round up. + if dc0 { + // If we computed an exact product, the half integer + // should round to next (even) integer if 'dc' is odd. + cup = fracc > 1<<(extra-1) || + (fracc == 1<<(extra-1) && dc&1 == 1) + } else { + // otherwise, the result is a lower truncation of the ideal + // result. + cup = fracc>>(extra-1) == 1 + } + // Is 'dl' an allowed representation? + // Only if it is an exact value, and if the original binary mantissa + // was even. + lok := dl0 && fracl == 0 && (mant&1 == 0) + if !lok { + dl++ + } + // We need to remember whether the trimmed digits of 'dc' are zero. + c0 := dc0 && fracc == 0 + // render digits + ryuDigits(d, dl, dc, du, c0, cup) + d.dp -= q +} + +// mulByLog2Log10 returns math.Floor(x * log(2)/log(10)) for an integer x in +// the range -1600 <= x && x <= +1600. +// +// The range restriction lets us work in faster integer arithmetic instead of +// slower floating point arithmetic. Correctness is verified by unit tests. +func mulByLog2Log10(x int) int { + // log(2)/log(10) ≈ 0.30102999566 ≈ 78913 / 2^18 + return (x * 78913) >> 18 +} + +// mulByLog10Log2 returns math.Floor(x * log(10)/log(2)) for an integer x in +// the range -500 <= x && x <= +500. +// +// The range restriction lets us work in faster integer arithmetic instead of +// slower floating point arithmetic. Correctness is verified by unit tests. +func mulByLog10Log2(x int) int { + // log(10)/log(2) ≈ 3.32192809489 ≈ 108853 / 2^15 + return (x * 108853) >> 15 +} + +// computeBounds returns a floating-point vector (l, c, u)×2^e2 +// where the mantissas are 55-bit (or 26-bit) integers, describing the interval +// represented by the input float64 or float32. +func computeBounds(mant uint64, exp int, flt *floatInfo) (lower, central, upper uint64, e2 int) { + if mant != 1< 5e8) || (clo == 5e8 && cup) + ryuDigits32(d, lhi, chi, uhi, c0, cup, 8) + d.dp += 9 + } else { + d.nd = 0 + // emit high part + n := uint(9) + for v := chi; v > 0; { + v1, v2 := v/10, v%10 + v = v1 + n-- + d.d[n] = byte(v2 + '0') + } + d.d = d.d[n:] + d.nd = int(9 - n) + // emit low part + ryuDigits32(d, llo, clo, ulo, + c0, cup, d.nd+8) + } + // trim trailing zeros + for d.nd > 0 && d.d[d.nd-1] == '0' { + d.nd-- + } + // trim initial zeros + for d.nd > 0 && d.d[0] == '0' { + d.nd-- + d.dp-- + d.d = d.d[1:] + } +} + +// ryuDigits32 emits decimal digits for a number less than 1e9. +func ryuDigits32(d *decimalSlice, lower, central, upper uint32, + c0, cup bool, endindex int) { + if upper == 0 { + d.dp = endindex + 1 + return + } + trimmed := 0 + // Remember last trimmed digit to check for round-up. + // c0 will be used to remember zeroness of following digits. + cNextDigit := 0 + for upper > 0 { + // Repeatedly compute: + // l = Ceil(lower / 10^k) + // c = Round(central / 10^k) + // u = Floor(upper / 10^k) + // and stop when c goes out of the (l, u) interval. + l := (lower + 9) / 10 + c, cdigit := central/10, central%10 + u := upper / 10 + if l > u { + // don't trim the last digit as it is forbidden to go below l + // other, trim and exit now. + break + } + // Check that we didn't cross the lower boundary. + // The case where l < u but c == l-1 is essentially impossible, + // but may happen if: + // lower = ..11 + // central = ..19 + // upper = ..31 + // and means that 'central' is very close but less than + // an integer ending with many zeros, and usually + // the "round-up" logic hides the problem. + if l == c+1 && c < u { + c++ + cdigit = 0 + cup = false + } + trimmed++ + // Remember trimmed digits of c + c0 = c0 && cNextDigit == 0 + cNextDigit = int(cdigit) + lower, central, upper = l, c, u + } + // should we round up? + if trimmed > 0 { + cup = cNextDigit > 5 || + (cNextDigit == 5 && !c0) || + (cNextDigit == 5 && c0 && central&1 == 1) + } + if central < upper && cup { + central++ + } + // We know where the number ends, fill directly + endindex -= trimmed + v := central + n := endindex + for n > d.nd { + v1, v2 := v/100, v%100 + d.d[n] = smallsString[2*v2+1] + d.d[n-1] = smallsString[2*v2+0] + n -= 2 + v = v1 + } + if n == d.nd { + d.d[n] = byte(v + '0') + } + d.nd = endindex + 1 + d.dp = d.nd + trimmed +} + +// mult64bitPow10 takes a floating-point input with a 25-bit +// mantissa and multiplies it with 10^q. The resulting mantissa +// is m*P >> 57 where P is a 64-bit element of the detailedPowersOfTen tables. +// It is typically 31 or 32-bit wide. +// The returned boolean is true if all trimmed bits were zero. +// +// That is: +// +// m*2^e2 * round(10^q) = resM * 2^resE + ε +// exact = ε == 0 +func mult64bitPow10(m uint32, e2, q int) (resM uint32, resE int, exact bool) { + if q == 0 { + // P == 1<<63 + return m << 6, e2 - 6, true + } + if q < detailedPowersOfTenMinExp10 || detailedPowersOfTenMaxExp10 < q { + // This never happens due to the range of float32/float64 exponent + panic("mult64bitPow10: power of 10 is out of range") + } + pow := detailedPowersOfTen[q-detailedPowersOfTenMinExp10][1] + if q < 0 { + // Inverse powers of ten must be rounded up. + pow += 1 + } + hi, lo := bits.Mul64(uint64(m), pow) + e2 += mulByLog10Log2(q) - 63 + 57 + return uint32(hi<<7 | lo>>57), e2, lo<<7 == 0 +} + +// mult128bitPow10 takes a floating-point input with a 55-bit +// mantissa and multiplies it with 10^q. The resulting mantissa +// is m*P >> 119 where P is a 128-bit element of the detailedPowersOfTen tables. +// It is typically 63 or 64-bit wide. +// The returned boolean is true is all trimmed bits were zero. +// +// That is: +// +// m*2^e2 * round(10^q) = resM * 2^resE + ε +// exact = ε == 0 +func mult128bitPow10(m uint64, e2, q int) (resM uint64, resE int, exact bool) { + if q == 0 { + // P == 1<<127 + return m << 8, e2 - 8, true + } + if q < detailedPowersOfTenMinExp10 || detailedPowersOfTenMaxExp10 < q { + // This never happens due to the range of float32/float64 exponent + panic("mult128bitPow10: power of 10 is out of range") + } + pow := detailedPowersOfTen[q-detailedPowersOfTenMinExp10] + if q < 0 { + // Inverse powers of ten must be rounded up. + pow[0] += 1 + } + e2 += mulByLog10Log2(q) - 127 + 119 + + // long multiplication + l1, l0 := bits.Mul64(m, pow[0]) + h1, h0 := bits.Mul64(m, pow[1]) + mid, carry := bits.Add64(l1, h0, 0) + h1 += carry + return h1<<9 | mid>>55, e2, mid<<9 == 0 && l0 == 0 +} + +func divisibleByPower5(m uint64, k int) bool { + if m == 0 { + return true + } + for i := 0; i < k; i++ { + if m%5 != 0 { + return false + } + m /= 5 + } + return true +} + +// divmod1e9 computes quotient and remainder of division by 1e9, +// avoiding runtime uint64 division on 32-bit platforms. +func divmod1e9(x uint64) (uint32, uint32) { + if !host32bit { + return uint32(x / 1e9), uint32(x % 1e9) + } + // Use the same sequence of operations as the amd64 compiler. + hi, _ := bits.Mul64(x>>1, 0x89705f4136b4a598) // binary digits of 1e-9 + q := hi >> 28 + return uint32(q), uint32(x - q*1e9) +} diff --git a/gnovm/stdlibs/strconv/ftoaryu_test.gno b/gnovm/stdlibs/strconv/ftoaryu_test.gno new file mode 100644 index 00000000000..bd969e8e997 --- /dev/null +++ b/gnovm/stdlibs/strconv/ftoaryu_test.gno @@ -0,0 +1,30 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strconv + +import ( + "math" + "testing" +) + +func TestMulByLog2Log10(t *testing.T) { + for x := -1600; x <= +1600; x++ { + iMath := MulByLog2Log10(x) + fMath := int(math.Floor(float64(x) * math.Ln2 / math.Ln10)) + if iMath != fMath { + t.Errorf("mulByLog2Log10(%d) failed: %d vs %d\n", x, iMath, fMath) + } + } +} + +func TestMulByLog10Log2(t *testing.T) { + for x := -500; x <= +500; x++ { + iMath := MulByLog10Log2(x) + fMath := int(math.Floor(float64(x) * math.Ln10 / math.Ln2)) + if iMath != fMath { + t.Errorf("mulByLog10Log2(%d) failed: %d vs %d\n", x, iMath, fMath) + } + } +} diff --git a/gnovm/stdlibs/strconv/internal_test.gno b/gnovm/stdlibs/strconv/internal_test.gno new file mode 100644 index 00000000000..f2cceff20eb --- /dev/null +++ b/gnovm/stdlibs/strconv/internal_test.gno @@ -0,0 +1,31 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// export access to strconv internals for tests + +package strconv + +func NewDecimal(i uint64) *decimal { + d := new(decimal) + d.Assign(i) + return d +} + +func SetOptimize(b bool) bool { + old := optimize + optimize = b + return old +} + +func ParseFloatPrefix(s string, bitSize int) (float64, int, error) { + return parseFloatPrefix(s, bitSize) +} + +func MulByLog2Log10(x int) int { + return mulByLog2Log10(x) +} + +func MulByLog10Log2(x int) int { + return mulByLog10Log2(x) +} diff --git a/gnovm/stdlibs/strconv/isprint.gno b/gnovm/stdlibs/strconv/isprint.gno new file mode 100644 index 00000000000..baa14a65bd6 --- /dev/null +++ b/gnovm/stdlibs/strconv/isprint.gno @@ -0,0 +1,752 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Code generated by go run makeisprint.go -output isprint.go; DO NOT EDIT. + +package strconv + +// (424+133+112)*2 + (508)*4 = 3370 bytes + +var isPrint16 = []uint16{ + 0x0020, 0x007e, + 0x00a1, 0x0377, + 0x037a, 0x037f, + 0x0384, 0x0556, + 0x0559, 0x058a, + 0x058d, 0x05c7, + 0x05d0, 0x05ea, + 0x05ef, 0x05f4, + 0x0606, 0x070d, + 0x0710, 0x074a, + 0x074d, 0x07b1, + 0x07c0, 0x07fa, + 0x07fd, 0x082d, + 0x0830, 0x085b, + 0x085e, 0x086a, + 0x0870, 0x088e, + 0x0898, 0x098c, + 0x098f, 0x0990, + 0x0993, 0x09b2, + 0x09b6, 0x09b9, + 0x09bc, 0x09c4, + 0x09c7, 0x09c8, + 0x09cb, 0x09ce, + 0x09d7, 0x09d7, + 0x09dc, 0x09e3, + 0x09e6, 0x09fe, + 0x0a01, 0x0a0a, + 0x0a0f, 0x0a10, + 0x0a13, 0x0a39, + 0x0a3c, 0x0a42, + 0x0a47, 0x0a48, + 0x0a4b, 0x0a4d, + 0x0a51, 0x0a51, + 0x0a59, 0x0a5e, + 0x0a66, 0x0a76, + 0x0a81, 0x0ab9, + 0x0abc, 0x0acd, + 0x0ad0, 0x0ad0, + 0x0ae0, 0x0ae3, + 0x0ae6, 0x0af1, + 0x0af9, 0x0b0c, + 0x0b0f, 0x0b10, + 0x0b13, 0x0b39, + 0x0b3c, 0x0b44, + 0x0b47, 0x0b48, + 0x0b4b, 0x0b4d, + 0x0b55, 0x0b57, + 0x0b5c, 0x0b63, + 0x0b66, 0x0b77, + 0x0b82, 0x0b8a, + 0x0b8e, 0x0b95, + 0x0b99, 0x0b9f, + 0x0ba3, 0x0ba4, + 0x0ba8, 0x0baa, + 0x0bae, 0x0bb9, + 0x0bbe, 0x0bc2, + 0x0bc6, 0x0bcd, + 0x0bd0, 0x0bd0, + 0x0bd7, 0x0bd7, + 0x0be6, 0x0bfa, + 0x0c00, 0x0c39, + 0x0c3c, 0x0c4d, + 0x0c55, 0x0c5a, + 0x0c5d, 0x0c5d, + 0x0c60, 0x0c63, + 0x0c66, 0x0c6f, + 0x0c77, 0x0cb9, + 0x0cbc, 0x0ccd, + 0x0cd5, 0x0cd6, + 0x0cdd, 0x0ce3, + 0x0ce6, 0x0cf3, + 0x0d00, 0x0d4f, + 0x0d54, 0x0d63, + 0x0d66, 0x0d96, + 0x0d9a, 0x0dbd, + 0x0dc0, 0x0dc6, + 0x0dca, 0x0dca, + 0x0dcf, 0x0ddf, + 0x0de6, 0x0def, + 0x0df2, 0x0df4, + 0x0e01, 0x0e3a, + 0x0e3f, 0x0e5b, + 0x0e81, 0x0ebd, + 0x0ec0, 0x0ed9, + 0x0edc, 0x0edf, + 0x0f00, 0x0f6c, + 0x0f71, 0x0fda, + 0x1000, 0x10c7, + 0x10cd, 0x10cd, + 0x10d0, 0x124d, + 0x1250, 0x125d, + 0x1260, 0x128d, + 0x1290, 0x12b5, + 0x12b8, 0x12c5, + 0x12c8, 0x1315, + 0x1318, 0x135a, + 0x135d, 0x137c, + 0x1380, 0x1399, + 0x13a0, 0x13f5, + 0x13f8, 0x13fd, + 0x1400, 0x169c, + 0x16a0, 0x16f8, + 0x1700, 0x1715, + 0x171f, 0x1736, + 0x1740, 0x1753, + 0x1760, 0x1773, + 0x1780, 0x17dd, + 0x17e0, 0x17e9, + 0x17f0, 0x17f9, + 0x1800, 0x1819, + 0x1820, 0x1878, + 0x1880, 0x18aa, + 0x18b0, 0x18f5, + 0x1900, 0x192b, + 0x1930, 0x193b, + 0x1940, 0x1940, + 0x1944, 0x196d, + 0x1970, 0x1974, + 0x1980, 0x19ab, + 0x19b0, 0x19c9, + 0x19d0, 0x19da, + 0x19de, 0x1a1b, + 0x1a1e, 0x1a7c, + 0x1a7f, 0x1a89, + 0x1a90, 0x1a99, + 0x1aa0, 0x1aad, + 0x1ab0, 0x1ace, + 0x1b00, 0x1b4c, + 0x1b50, 0x1bf3, + 0x1bfc, 0x1c37, + 0x1c3b, 0x1c49, + 0x1c4d, 0x1c88, + 0x1c90, 0x1cba, + 0x1cbd, 0x1cc7, + 0x1cd0, 0x1cfa, + 0x1d00, 0x1f15, + 0x1f18, 0x1f1d, + 0x1f20, 0x1f45, + 0x1f48, 0x1f4d, + 0x1f50, 0x1f7d, + 0x1f80, 0x1fd3, + 0x1fd6, 0x1fef, + 0x1ff2, 0x1ffe, + 0x2010, 0x2027, + 0x2030, 0x205e, + 0x2070, 0x2071, + 0x2074, 0x209c, + 0x20a0, 0x20c0, + 0x20d0, 0x20f0, + 0x2100, 0x218b, + 0x2190, 0x2426, + 0x2440, 0x244a, + 0x2460, 0x2b73, + 0x2b76, 0x2cf3, + 0x2cf9, 0x2d27, + 0x2d2d, 0x2d2d, + 0x2d30, 0x2d67, + 0x2d6f, 0x2d70, + 0x2d7f, 0x2d96, + 0x2da0, 0x2e5d, + 0x2e80, 0x2ef3, + 0x2f00, 0x2fd5, + 0x2ff0, 0x2ffb, + 0x3001, 0x3096, + 0x3099, 0x30ff, + 0x3105, 0x31e3, + 0x31f0, 0xa48c, + 0xa490, 0xa4c6, + 0xa4d0, 0xa62b, + 0xa640, 0xa6f7, + 0xa700, 0xa7ca, + 0xa7d0, 0xa7d9, + 0xa7f2, 0xa82c, + 0xa830, 0xa839, + 0xa840, 0xa877, + 0xa880, 0xa8c5, + 0xa8ce, 0xa8d9, + 0xa8e0, 0xa953, + 0xa95f, 0xa97c, + 0xa980, 0xa9d9, + 0xa9de, 0xaa36, + 0xaa40, 0xaa4d, + 0xaa50, 0xaa59, + 0xaa5c, 0xaac2, + 0xaadb, 0xaaf6, + 0xab01, 0xab06, + 0xab09, 0xab0e, + 0xab11, 0xab16, + 0xab20, 0xab6b, + 0xab70, 0xabed, + 0xabf0, 0xabf9, + 0xac00, 0xd7a3, + 0xd7b0, 0xd7c6, + 0xd7cb, 0xd7fb, + 0xf900, 0xfa6d, + 0xfa70, 0xfad9, + 0xfb00, 0xfb06, + 0xfb13, 0xfb17, + 0xfb1d, 0xfbc2, + 0xfbd3, 0xfd8f, + 0xfd92, 0xfdc7, + 0xfdcf, 0xfdcf, + 0xfdf0, 0xfe19, + 0xfe20, 0xfe6b, + 0xfe70, 0xfefc, + 0xff01, 0xffbe, + 0xffc2, 0xffc7, + 0xffca, 0xffcf, + 0xffd2, 0xffd7, + 0xffda, 0xffdc, + 0xffe0, 0xffee, + 0xfffc, 0xfffd, +} + +var isNotPrint16 = []uint16{ + 0x00ad, + 0x038b, + 0x038d, + 0x03a2, + 0x0530, + 0x0590, + 0x061c, + 0x06dd, + 0x083f, + 0x085f, + 0x08e2, + 0x0984, + 0x09a9, + 0x09b1, + 0x09de, + 0x0a04, + 0x0a29, + 0x0a31, + 0x0a34, + 0x0a37, + 0x0a3d, + 0x0a5d, + 0x0a84, + 0x0a8e, + 0x0a92, + 0x0aa9, + 0x0ab1, + 0x0ab4, + 0x0ac6, + 0x0aca, + 0x0b00, + 0x0b04, + 0x0b29, + 0x0b31, + 0x0b34, + 0x0b5e, + 0x0b84, + 0x0b91, + 0x0b9b, + 0x0b9d, + 0x0bc9, + 0x0c0d, + 0x0c11, + 0x0c29, + 0x0c45, + 0x0c49, + 0x0c57, + 0x0c8d, + 0x0c91, + 0x0ca9, + 0x0cb4, + 0x0cc5, + 0x0cc9, + 0x0cdf, + 0x0cf0, + 0x0d0d, + 0x0d11, + 0x0d45, + 0x0d49, + 0x0d80, + 0x0d84, + 0x0db2, + 0x0dbc, + 0x0dd5, + 0x0dd7, + 0x0e83, + 0x0e85, + 0x0e8b, + 0x0ea4, + 0x0ea6, + 0x0ec5, + 0x0ec7, + 0x0ecf, + 0x0f48, + 0x0f98, + 0x0fbd, + 0x0fcd, + 0x10c6, + 0x1249, + 0x1257, + 0x1259, + 0x1289, + 0x12b1, + 0x12bf, + 0x12c1, + 0x12d7, + 0x1311, + 0x1680, + 0x176d, + 0x1771, + 0x180e, + 0x191f, + 0x1a5f, + 0x1b7f, + 0x1f58, + 0x1f5a, + 0x1f5c, + 0x1f5e, + 0x1fb5, + 0x1fc5, + 0x1fdc, + 0x1ff5, + 0x208f, + 0x2b96, + 0x2d26, + 0x2da7, + 0x2daf, + 0x2db7, + 0x2dbf, + 0x2dc7, + 0x2dcf, + 0x2dd7, + 0x2ddf, + 0x2e9a, + 0x3040, + 0x3130, + 0x318f, + 0x321f, + 0xa7d2, + 0xa7d4, + 0xa9ce, + 0xa9ff, + 0xab27, + 0xab2f, + 0xfb37, + 0xfb3d, + 0xfb3f, + 0xfb42, + 0xfb45, + 0xfe53, + 0xfe67, + 0xfe75, + 0xffe7, +} + +var isPrint32 = []uint32{ + 0x010000, 0x01004d, + 0x010050, 0x01005d, + 0x010080, 0x0100fa, + 0x010100, 0x010102, + 0x010107, 0x010133, + 0x010137, 0x01019c, + 0x0101a0, 0x0101a0, + 0x0101d0, 0x0101fd, + 0x010280, 0x01029c, + 0x0102a0, 0x0102d0, + 0x0102e0, 0x0102fb, + 0x010300, 0x010323, + 0x01032d, 0x01034a, + 0x010350, 0x01037a, + 0x010380, 0x0103c3, + 0x0103c8, 0x0103d5, + 0x010400, 0x01049d, + 0x0104a0, 0x0104a9, + 0x0104b0, 0x0104d3, + 0x0104d8, 0x0104fb, + 0x010500, 0x010527, + 0x010530, 0x010563, + 0x01056f, 0x0105bc, + 0x010600, 0x010736, + 0x010740, 0x010755, + 0x010760, 0x010767, + 0x010780, 0x0107ba, + 0x010800, 0x010805, + 0x010808, 0x010838, + 0x01083c, 0x01083c, + 0x01083f, 0x01089e, + 0x0108a7, 0x0108af, + 0x0108e0, 0x0108f5, + 0x0108fb, 0x01091b, + 0x01091f, 0x010939, + 0x01093f, 0x01093f, + 0x010980, 0x0109b7, + 0x0109bc, 0x0109cf, + 0x0109d2, 0x010a06, + 0x010a0c, 0x010a35, + 0x010a38, 0x010a3a, + 0x010a3f, 0x010a48, + 0x010a50, 0x010a58, + 0x010a60, 0x010a9f, + 0x010ac0, 0x010ae6, + 0x010aeb, 0x010af6, + 0x010b00, 0x010b35, + 0x010b39, 0x010b55, + 0x010b58, 0x010b72, + 0x010b78, 0x010b91, + 0x010b99, 0x010b9c, + 0x010ba9, 0x010baf, + 0x010c00, 0x010c48, + 0x010c80, 0x010cb2, + 0x010cc0, 0x010cf2, + 0x010cfa, 0x010d27, + 0x010d30, 0x010d39, + 0x010e60, 0x010ead, + 0x010eb0, 0x010eb1, + 0x010efd, 0x010f27, + 0x010f30, 0x010f59, + 0x010f70, 0x010f89, + 0x010fb0, 0x010fcb, + 0x010fe0, 0x010ff6, + 0x011000, 0x01104d, + 0x011052, 0x011075, + 0x01107f, 0x0110c2, + 0x0110d0, 0x0110e8, + 0x0110f0, 0x0110f9, + 0x011100, 0x011147, + 0x011150, 0x011176, + 0x011180, 0x0111f4, + 0x011200, 0x011241, + 0x011280, 0x0112a9, + 0x0112b0, 0x0112ea, + 0x0112f0, 0x0112f9, + 0x011300, 0x01130c, + 0x01130f, 0x011310, + 0x011313, 0x011344, + 0x011347, 0x011348, + 0x01134b, 0x01134d, + 0x011350, 0x011350, + 0x011357, 0x011357, + 0x01135d, 0x011363, + 0x011366, 0x01136c, + 0x011370, 0x011374, + 0x011400, 0x011461, + 0x011480, 0x0114c7, + 0x0114d0, 0x0114d9, + 0x011580, 0x0115b5, + 0x0115b8, 0x0115dd, + 0x011600, 0x011644, + 0x011650, 0x011659, + 0x011660, 0x01166c, + 0x011680, 0x0116b9, + 0x0116c0, 0x0116c9, + 0x011700, 0x01171a, + 0x01171d, 0x01172b, + 0x011730, 0x011746, + 0x011800, 0x01183b, + 0x0118a0, 0x0118f2, + 0x0118ff, 0x011906, + 0x011909, 0x011909, + 0x01190c, 0x011938, + 0x01193b, 0x011946, + 0x011950, 0x011959, + 0x0119a0, 0x0119a7, + 0x0119aa, 0x0119d7, + 0x0119da, 0x0119e4, + 0x011a00, 0x011a47, + 0x011a50, 0x011aa2, + 0x011ab0, 0x011af8, + 0x011b00, 0x011b09, + 0x011c00, 0x011c45, + 0x011c50, 0x011c6c, + 0x011c70, 0x011c8f, + 0x011c92, 0x011cb6, + 0x011d00, 0x011d36, + 0x011d3a, 0x011d47, + 0x011d50, 0x011d59, + 0x011d60, 0x011d98, + 0x011da0, 0x011da9, + 0x011ee0, 0x011ef8, + 0x011f00, 0x011f3a, + 0x011f3e, 0x011f59, + 0x011fb0, 0x011fb0, + 0x011fc0, 0x011ff1, + 0x011fff, 0x012399, + 0x012400, 0x012474, + 0x012480, 0x012543, + 0x012f90, 0x012ff2, + 0x013000, 0x01342f, + 0x013440, 0x013455, + 0x014400, 0x014646, + 0x016800, 0x016a38, + 0x016a40, 0x016a69, + 0x016a6e, 0x016ac9, + 0x016ad0, 0x016aed, + 0x016af0, 0x016af5, + 0x016b00, 0x016b45, + 0x016b50, 0x016b77, + 0x016b7d, 0x016b8f, + 0x016e40, 0x016e9a, + 0x016f00, 0x016f4a, + 0x016f4f, 0x016f87, + 0x016f8f, 0x016f9f, + 0x016fe0, 0x016fe4, + 0x016ff0, 0x016ff1, + 0x017000, 0x0187f7, + 0x018800, 0x018cd5, + 0x018d00, 0x018d08, + 0x01aff0, 0x01b122, + 0x01b132, 0x01b132, + 0x01b150, 0x01b152, + 0x01b155, 0x01b155, + 0x01b164, 0x01b167, + 0x01b170, 0x01b2fb, + 0x01bc00, 0x01bc6a, + 0x01bc70, 0x01bc7c, + 0x01bc80, 0x01bc88, + 0x01bc90, 0x01bc99, + 0x01bc9c, 0x01bc9f, + 0x01cf00, 0x01cf2d, + 0x01cf30, 0x01cf46, + 0x01cf50, 0x01cfc3, + 0x01d000, 0x01d0f5, + 0x01d100, 0x01d126, + 0x01d129, 0x01d172, + 0x01d17b, 0x01d1ea, + 0x01d200, 0x01d245, + 0x01d2c0, 0x01d2d3, + 0x01d2e0, 0x01d2f3, + 0x01d300, 0x01d356, + 0x01d360, 0x01d378, + 0x01d400, 0x01d49f, + 0x01d4a2, 0x01d4a2, + 0x01d4a5, 0x01d4a6, + 0x01d4a9, 0x01d50a, + 0x01d50d, 0x01d546, + 0x01d54a, 0x01d6a5, + 0x01d6a8, 0x01d7cb, + 0x01d7ce, 0x01da8b, + 0x01da9b, 0x01daaf, + 0x01df00, 0x01df1e, + 0x01df25, 0x01df2a, + 0x01e000, 0x01e018, + 0x01e01b, 0x01e02a, + 0x01e030, 0x01e06d, + 0x01e08f, 0x01e08f, + 0x01e100, 0x01e12c, + 0x01e130, 0x01e13d, + 0x01e140, 0x01e149, + 0x01e14e, 0x01e14f, + 0x01e290, 0x01e2ae, + 0x01e2c0, 0x01e2f9, + 0x01e2ff, 0x01e2ff, + 0x01e4d0, 0x01e4f9, + 0x01e7e0, 0x01e8c4, + 0x01e8c7, 0x01e8d6, + 0x01e900, 0x01e94b, + 0x01e950, 0x01e959, + 0x01e95e, 0x01e95f, + 0x01ec71, 0x01ecb4, + 0x01ed01, 0x01ed3d, + 0x01ee00, 0x01ee24, + 0x01ee27, 0x01ee3b, + 0x01ee42, 0x01ee42, + 0x01ee47, 0x01ee54, + 0x01ee57, 0x01ee64, + 0x01ee67, 0x01ee9b, + 0x01eea1, 0x01eebb, + 0x01eef0, 0x01eef1, + 0x01f000, 0x01f02b, + 0x01f030, 0x01f093, + 0x01f0a0, 0x01f0ae, + 0x01f0b1, 0x01f0f5, + 0x01f100, 0x01f1ad, + 0x01f1e6, 0x01f202, + 0x01f210, 0x01f23b, + 0x01f240, 0x01f248, + 0x01f250, 0x01f251, + 0x01f260, 0x01f265, + 0x01f300, 0x01f6d7, + 0x01f6dc, 0x01f6ec, + 0x01f6f0, 0x01f6fc, + 0x01f700, 0x01f776, + 0x01f77b, 0x01f7d9, + 0x01f7e0, 0x01f7eb, + 0x01f7f0, 0x01f7f0, + 0x01f800, 0x01f80b, + 0x01f810, 0x01f847, + 0x01f850, 0x01f859, + 0x01f860, 0x01f887, + 0x01f890, 0x01f8ad, + 0x01f8b0, 0x01f8b1, + 0x01f900, 0x01fa53, + 0x01fa60, 0x01fa6d, + 0x01fa70, 0x01fa7c, + 0x01fa80, 0x01fa88, + 0x01fa90, 0x01fac5, + 0x01face, 0x01fadb, + 0x01fae0, 0x01fae8, + 0x01faf0, 0x01faf8, + 0x01fb00, 0x01fbca, + 0x01fbf0, 0x01fbf9, + 0x020000, 0x02a6df, + 0x02a700, 0x02b739, + 0x02b740, 0x02b81d, + 0x02b820, 0x02cea1, + 0x02ceb0, 0x02ebe0, + 0x02f800, 0x02fa1d, + 0x030000, 0x03134a, + 0x031350, 0x0323af, + 0x0e0100, 0x0e01ef, +} + +var isNotPrint32 = []uint16{ // add 0x10000 to each entry + 0x000c, + 0x0027, + 0x003b, + 0x003e, + 0x018f, + 0x039e, + 0x057b, + 0x058b, + 0x0593, + 0x0596, + 0x05a2, + 0x05b2, + 0x05ba, + 0x0786, + 0x07b1, + 0x0809, + 0x0836, + 0x0856, + 0x08f3, + 0x0a04, + 0x0a14, + 0x0a18, + 0x0e7f, + 0x0eaa, + 0x10bd, + 0x1135, + 0x11e0, + 0x1212, + 0x1287, + 0x1289, + 0x128e, + 0x129e, + 0x1304, + 0x1329, + 0x1331, + 0x1334, + 0x133a, + 0x145c, + 0x1914, + 0x1917, + 0x1936, + 0x1c09, + 0x1c37, + 0x1ca8, + 0x1d07, + 0x1d0a, + 0x1d3b, + 0x1d3e, + 0x1d66, + 0x1d69, + 0x1d8f, + 0x1d92, + 0x1f11, + 0x246f, + 0x6a5f, + 0x6abf, + 0x6b5a, + 0x6b62, + 0xaff4, + 0xaffc, + 0xafff, + 0xd455, + 0xd49d, + 0xd4ad, + 0xd4ba, + 0xd4bc, + 0xd4c4, + 0xd506, + 0xd515, + 0xd51d, + 0xd53a, + 0xd53f, + 0xd545, + 0xd551, + 0xdaa0, + 0xe007, + 0xe022, + 0xe025, + 0xe7e7, + 0xe7ec, + 0xe7ef, + 0xe7ff, + 0xee04, + 0xee20, + 0xee23, + 0xee28, + 0xee33, + 0xee38, + 0xee3a, + 0xee48, + 0xee4a, + 0xee4c, + 0xee50, + 0xee53, + 0xee58, + 0xee5a, + 0xee5c, + 0xee5e, + 0xee60, + 0xee63, + 0xee6b, + 0xee73, + 0xee78, + 0xee7d, + 0xee7f, + 0xee8a, + 0xeea4, + 0xeeaa, + 0xf0c0, + 0xf0d0, + 0xfabe, + 0xfb93, +} + +// isGraphic lists the graphic runes not matched by IsPrint. +var isGraphic = []uint16{ + 0x00a0, + 0x1680, + 0x2000, + 0x2001, + 0x2002, + 0x2003, + 0x2004, + 0x2005, + 0x2006, + 0x2007, + 0x2008, + 0x2009, + 0x200a, + 0x202f, + 0x205f, + 0x3000, +} diff --git a/gnovm/stdlibs/strconv/itoa.gno b/gnovm/stdlibs/strconv/itoa.gno new file mode 100644 index 00000000000..b0c2666e7cb --- /dev/null +++ b/gnovm/stdlibs/strconv/itoa.gno @@ -0,0 +1,205 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strconv + +import "math/bits" + +const fastSmalls = true // enable fast path for small integers + +// FormatUint returns the string representation of i in the given base, +// for 2 <= base <= 36. The result uses the lower-case letters 'a' to 'z' +// for digit values >= 10. +func FormatUint(i uint64, base int) string { + if fastSmalls && i < nSmalls && base == 10 { + return small(int(i)) + } + _, s := formatBits(nil, i, base, false, false) + return s +} + +// FormatInt returns the string representation of i in the given base, +// for 2 <= base <= 36. The result uses the lower-case letters 'a' to 'z' +// for digit values >= 10. +func FormatInt(i int64, base int) string { + if fastSmalls && 0 <= i && i < nSmalls && base == 10 { + return small(int(i)) + } + _, s := formatBits(nil, uint64(i), base, i < 0, false) + return s +} + +// Itoa is equivalent to FormatInt(int64(i), 10). +func Itoa(i int) string { + return FormatInt(int64(i), 10) +} + +// AppendInt appends the string form of the integer i, +// as generated by FormatInt, to dst and returns the extended buffer. +func AppendInt(dst []byte, i int64, base int) []byte { + if fastSmalls && 0 <= i && i < nSmalls && base == 10 { + return append(dst, small(int(i))...) + } + dst, _ = formatBits(dst, uint64(i), base, i < 0, true) + return dst +} + +// AppendUint appends the string form of the unsigned integer i, +// as generated by FormatUint, to dst and returns the extended buffer. +func AppendUint(dst []byte, i uint64, base int) []byte { + if fastSmalls && i < nSmalls && base == 10 { + return append(dst, small(int(i))...) + } + dst, _ = formatBits(dst, i, base, false, true) + return dst +} + +// small returns the string for an i with 0 <= i < nSmalls. +func small(i int) string { + if i < 10 { + return digits[i : i+1] + } + return smallsString[i*2 : i*2+2] +} + +const nSmalls = 100 + +const smallsString = "00010203040506070809" + + "10111213141516171819" + + "20212223242526272829" + + "30313233343536373839" + + "40414243444546474849" + + "50515253545556575859" + + "60616263646566676869" + + "70717273747576777879" + + "80818283848586878889" + + "90919293949596979899" + +const host32bit = ^uint(0)>>32 == 0 + +const digits = "0123456789abcdefghijklmnopqrstuvwxyz" + +// formatBits computes the string representation of u in the given base. +// If neg is set, u is treated as negative int64 value. If append_ is +// set, the string is appended to dst and the resulting byte slice is +// returned as the first result value; otherwise the string is returned +// as the second result value. +func formatBits(dst []byte, u uint64, base int, neg, append_ bool) (d []byte, s string) { + if base < 2 || base > len(digits) { + panic("strconv: illegal AppendInt/FormatInt base") + } + // 2 <= base && base <= len(digits) + + var a [64 + 1]byte // +1 for sign of 64bit value in base 2 + i := len(a) + + if neg { + u = -u + } + + // convert bits + // We use uint values where we can because those will + // fit into a single register even on a 32bit machine. + if base == 10 { + // common case: use constants for / because + // the compiler can optimize it into a multiply+shift + + if host32bit { + // convert the lower digits using 32bit operations + for u >= 1e9 { + // Avoid using r = a%b in addition to q = a/b + // since 64bit division and modulo operations + // are calculated by runtime functions on 32bit machines. + q := u / 1e9 + us := uint(u - q*1e9) // u % 1e9 fits into a uint + for j := 4; j > 0; j-- { + is := us % 100 * 2 + us /= 100 + i -= 2 + a[i+1] = smallsString[is+1] + a[i+0] = smallsString[is+0] + } + + // us < 10, since it contains the last digit + // from the initial 9-digit us. + i-- + a[i] = smallsString[us*2+1] + + u = q + } + // u < 1e9 + } + + // u guaranteed to fit into a uint + us := uint(u) + for us >= 100 { + is := us % 100 * 2 + us /= 100 + i -= 2 + a[i+1] = smallsString[is+1] + a[i+0] = smallsString[is+0] + } + + // us < 100 + is := us * 2 + i-- + a[i] = smallsString[is+1] + if us >= 10 { + i-- + a[i] = smallsString[is] + } + + } else if isPowerOfTwo(base) { + // Use shifts and masks instead of / and %. + // Base is a power of 2 and 2 <= base <= len(digits) where len(digits) is 36. + // The largest power of 2 below or equal to 36 is 32, which is 1 << 5; + // i.e., the largest possible shift count is 5. By &-ind that value with + // the constant 7 we tell the compiler that the shift count is always + // less than 8 which is smaller than any register width. This allows + // the compiler to generate better code for the shift operation. + shift := uint(bits.TrailingZeros(uint(base))) & 7 + b := uint64(base) + m := uint(base) - 1 // == 1<= b { + i-- + a[i] = digits[uint(u)&m] + u >>= shift + } + // u < base + i-- + a[i] = digits[uint(u)] + } else { + // general case + b := uint64(base) + for u >= b { + i-- + // Avoid using r = a%b in addition to q = a/b + // since 64bit division and modulo operations + // are calculated by runtime functions on 32bit machines. + q := u / b + a[i] = digits[uint(u-q*b)] + u = q + } + // u < base + i-- + a[i] = digits[uint(u)] + } + + // add sign, if any + if neg { + i-- + a[i] = '-' + } + + if append_ { + d = append(dst, a[i:]...) + return + } + s = string(a[i:]) + return +} + +func isPowerOfTwo(x int) bool { + return x&(x-1) == 0 +} diff --git a/gnovm/stdlibs/strconv/itoa_test.gno b/gnovm/stdlibs/strconv/itoa_test.gno new file mode 100644 index 00000000000..b76acc78183 --- /dev/null +++ b/gnovm/stdlibs/strconv/itoa_test.gno @@ -0,0 +1,242 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strconv + +import ( + "testing" +) + +type itob64Test struct { + in int64 + base int + out string +} + +var itob64tests = []itob64Test{ + {0, 10, "0"}, + {1, 10, "1"}, + {-1, 10, "-1"}, + {12345678, 10, "12345678"}, + {-987654321, 10, "-987654321"}, + {1<<31 - 1, 10, "2147483647"}, + {-1<<31 + 1, 10, "-2147483647"}, + {1 << 31, 10, "2147483648"}, + {-1 << 31, 10, "-2147483648"}, + {1<<31 + 1, 10, "2147483649"}, + {-1<<31 - 1, 10, "-2147483649"}, + {1<<32 - 1, 10, "4294967295"}, + {-1<<32 + 1, 10, "-4294967295"}, + {1 << 32, 10, "4294967296"}, + {-1 << 32, 10, "-4294967296"}, + {1<<32 + 1, 10, "4294967297"}, + {-1<<32 - 1, 10, "-4294967297"}, + {1 << 50, 10, "1125899906842624"}, + {1<<63 - 1, 10, "9223372036854775807"}, + {-1<<63 + 1, 10, "-9223372036854775807"}, + {-1 << 63, 10, "-9223372036854775808"}, + + {0, 2, "0"}, + {10, 2, "1010"}, + {-1, 2, "-1"}, + {1 << 15, 2, "1000000000000000"}, + + {-8, 8, "-10"}, + {057635436545, 8, "57635436545"}, + {1 << 24, 8, "100000000"}, + + {16, 16, "10"}, + {-0x123456789abcdef, 16, "-123456789abcdef"}, + {1<<63 - 1, 16, "7fffffffffffffff"}, + {1<<63 - 1, 2, "111111111111111111111111111111111111111111111111111111111111111"}, + {-1 << 63, 2, "-1000000000000000000000000000000000000000000000000000000000000000"}, + + {16, 17, "g"}, + {25, 25, "10"}, + {(((((17*35+24)*35+21)*35+34)*35+12)*35+24)*35 + 32, 35, "holycow"}, + {(((((17*36+24)*36+21)*36+34)*36+12)*36+24)*36 + 32, 36, "holycow"}, +} + +func TestItoa(t *testing.T) { + for _, test := range itob64tests { + s := FormatInt(test.in, test.base) + if s != test.out { + t.Errorf("FormatInt(%v, %v) = %v want %v", + test.in, test.base, s, test.out) + } + x := AppendInt([]byte("abc"), test.in, test.base) + if string(x) != "abc"+test.out { + t.Errorf("AppendInt(%q, %v, %v) = %q want %v", + "abc", test.in, test.base, x, test.out) + } + + if test.in >= 0 { + s := FormatUint(uint64(test.in), test.base) + if s != test.out { + t.Errorf("FormatUint(%v, %v) = %v want %v", + test.in, test.base, s, test.out) + } + x := AppendUint(nil, uint64(test.in), test.base) + if string(x) != test.out { + t.Errorf("AppendUint(%q, %v, %v) = %q want %v", + "abc", uint64(test.in), test.base, x, test.out) + } + } + + if test.base == 10 && int64(int(test.in)) == test.in { + s := Itoa(int(test.in)) + if s != test.out { + t.Errorf("Itoa(%v) = %v want %v", + test.in, s, test.out) + } + } + } + + // Override when base is illegal + defer func() { + if r := recover(); r == nil { + t.Fatalf("expected panic due to illegal base") + } + }() + FormatUint(12345678, 1) +} + +type uitob64Test struct { + in uint64 + base int + out string +} + +var uitob64tests = []uitob64Test{ + {1<<63 - 1, 10, "9223372036854775807"}, + {1 << 63, 10, "9223372036854775808"}, + {1<<63 + 1, 10, "9223372036854775809"}, + {1<<64 - 2, 10, "18446744073709551614"}, + {1<<64 - 1, 10, "18446744073709551615"}, + {1<<64 - 1, 2, "1111111111111111111111111111111111111111111111111111111111111111"}, +} + +func TestUitoa(t *testing.T) { + for _, test := range uitob64tests { + s := FormatUint(test.in, test.base) + if s != test.out { + t.Errorf("FormatUint(%v, %v) = %v want %v", + test.in, test.base, s, test.out) + } + x := AppendUint([]byte("abc"), test.in, test.base) + if string(x) != "abc"+test.out { + t.Errorf("AppendUint(%q, %v, %v) = %q want %v", + "abc", test.in, test.base, x, test.out) + } + + } +} + +var varlenUints = []struct { + in uint64 + out string +}{ + {1, "1"}, + {12, "12"}, + {123, "123"}, + {1234, "1234"}, + {12345, "12345"}, + {123456, "123456"}, + {1234567, "1234567"}, + {12345678, "12345678"}, + {123456789, "123456789"}, + {1234567890, "1234567890"}, + {12345678901, "12345678901"}, + {123456789012, "123456789012"}, + {1234567890123, "1234567890123"}, + {12345678901234, "12345678901234"}, + {123456789012345, "123456789012345"}, + {1234567890123456, "1234567890123456"}, + {12345678901234567, "12345678901234567"}, + {123456789012345678, "123456789012345678"}, + {1234567890123456789, "1234567890123456789"}, + {12345678901234567890, "12345678901234567890"}, +} + +func TestFormatUintVarlen(t *testing.T) { + for _, test := range varlenUints { + s := FormatUint(test.in, 10) + if s != test.out { + t.Errorf("FormatUint(%v, 10) = %v want %v", test.in, s, test.out) + } + } +} + +func BenchmarkFormatInt(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, test := range itob64tests { + s := FormatInt(test.in, test.base) + BenchSink += len(s) + } + } +} + +func BenchmarkAppendInt(b *testing.B) { + dst := make([]byte, 0, 30) + for i := 0; i < b.N; i++ { + for _, test := range itob64tests { + dst = AppendInt(dst[:0], test.in, test.base) + BenchSink += len(dst) + } + } +} + +func BenchmarkFormatUint(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, test := range uitob64tests { + s := FormatUint(test.in, test.base) + BenchSink += len(s) + } + } +} + +func BenchmarkAppendUint(b *testing.B) { + dst := make([]byte, 0, 30) + for i := 0; i < b.N; i++ { + for _, test := range uitob64tests { + dst = AppendUint(dst[:0], test.in, test.base) + BenchSink += len(dst) + } + } +} + +func BenchmarkFormatIntSmall(b *testing.B) { + smallInts := []int64{7, 42} + for _, smallInt := range smallInts { + b.Run(Itoa(int(smallInt)), func(b *testing.B) { + for i := 0; i < b.N; i++ { + s := FormatInt(smallInt, 10) + BenchSink += len(s) + } + }) + } +} + +func BenchmarkAppendIntSmall(b *testing.B) { + dst := make([]byte, 0, 30) + const smallInt = 42 + for i := 0; i < b.N; i++ { + dst = AppendInt(dst[:0], smallInt, 10) + BenchSink += len(dst) + } +} + +func BenchmarkAppendUintVarlen(b *testing.B) { + for _, test := range varlenUints { + b.Run(test.out, func(b *testing.B) { + dst := make([]byte, 0, 30) + for j := 0; j < b.N; j++ { + dst = AppendUint(dst[:0], test.in, 10) + BenchSink += len(dst) + } + }) + } +} + +var BenchSink int // make sure compiler cannot optimize away benchmarks diff --git a/gnovm/stdlibs/strconv/quote.gno b/gnovm/stdlibs/strconv/quote.gno new file mode 100644 index 00000000000..7c384336795 --- /dev/null +++ b/gnovm/stdlibs/strconv/quote.gno @@ -0,0 +1,599 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:generate go run makeisprint.go -output isprint.go + +package strconv + +import ( + "unicode/utf8" +) + +const ( + lowerhex = "0123456789abcdef" + upperhex = "0123456789ABCDEF" +) + +// contains reports whether the string contains the byte c. +func contains(s string, c byte) bool { + return index(s, c) != -1 +} + +func quoteWith(s string, quote byte, ASCIIonly, graphicOnly bool) string { + return string(appendQuotedWith(make([]byte, 0, 3*len(s)/2), s, quote, ASCIIonly, graphicOnly)) +} + +func quoteRuneWith(r rune, quote byte, ASCIIonly, graphicOnly bool) string { + return string(appendQuotedRuneWith(nil, r, quote, ASCIIonly, graphicOnly)) +} + +func appendQuotedWith(buf []byte, s string, quote byte, ASCIIonly, graphicOnly bool) []byte { + // Often called with big strings, so preallocate. If there's quoting, + // this is conservative but still helps a lot. + if cap(buf)-len(buf) < len(s) { + nBuf := make([]byte, len(buf), len(buf)+1+len(s)+1) + copy(nBuf, buf) + buf = nBuf + } + buf = append(buf, quote) + for width := 0; len(s) > 0; s = s[width:] { + r := rune(s[0]) + width = 1 + if r >= utf8.RuneSelf { + r, width = utf8.DecodeRuneInString(s) + } + if width == 1 && r == utf8.RuneError { + buf = append(buf, `\x`...) + buf = append(buf, lowerhex[s[0]>>4]) + buf = append(buf, lowerhex[s[0]&0xF]) + continue + } + buf = appendEscapedRune(buf, r, quote, ASCIIonly, graphicOnly) + } + buf = append(buf, quote) + return buf +} + +func appendQuotedRuneWith(buf []byte, r rune, quote byte, ASCIIonly, graphicOnly bool) []byte { + buf = append(buf, quote) + if !utf8.ValidRune(r) { + r = utf8.RuneError + } + buf = appendEscapedRune(buf, r, quote, ASCIIonly, graphicOnly) + buf = append(buf, quote) + return buf +} + +func appendEscapedRune(buf []byte, r rune, quote byte, ASCIIonly, graphicOnly bool) []byte { + if r == rune(quote) || r == '\\' { // always backslashed + buf = append(buf, '\\') + buf = append(buf, byte(r)) + return buf + } + if ASCIIonly { + if r < utf8.RuneSelf && IsPrint(r) { + buf = append(buf, byte(r)) + return buf + } + } else if IsPrint(r) || graphicOnly && isInGraphicList(r) { + return utf8.AppendRune(buf, r) + } + switch r { + case '\a': + buf = append(buf, `\a`...) + case '\b': + buf = append(buf, `\b`...) + case '\f': + buf = append(buf, `\f`...) + case '\n': + buf = append(buf, `\n`...) + case '\r': + buf = append(buf, `\r`...) + case '\t': + buf = append(buf, `\t`...) + case '\v': + buf = append(buf, `\v`...) + default: + switch { + case r < ' ' || r == 0x7f: + buf = append(buf, `\x`...) + buf = append(buf, lowerhex[byte(r)>>4]) + buf = append(buf, lowerhex[byte(r)&0xF]) + case !utf8.ValidRune(r): + r = 0xFFFD + fallthrough + case r < 0x10000: + buf = append(buf, `\u`...) + for s := 12; s >= 0; s -= 4 { + buf = append(buf, lowerhex[r>>uint(s)&0xF]) + } + default: + buf = append(buf, `\U`...) + for s := 28; s >= 0; s -= 4 { + buf = append(buf, lowerhex[r>>uint(s)&0xF]) + } + } + } + return buf +} + +// Quote returns a double-quoted Go string literal representing s. The +// returned string uses Go escape sequences (\t, \n, \xFF, \u0100) for +// control characters and non-printable characters as defined by +// IsPrint. +func Quote(s string) string { + return quoteWith(s, '"', false, false) +} + +// AppendQuote appends a double-quoted Go string literal representing s, +// as generated by Quote, to dst and returns the extended buffer. +func AppendQuote(dst []byte, s string) []byte { + return appendQuotedWith(dst, s, '"', false, false) +} + +// QuoteToASCII returns a double-quoted Go string literal representing s. +// The returned string uses Go escape sequences (\t, \n, \xFF, \u0100) for +// non-ASCII characters and non-printable characters as defined by IsPrint. +func QuoteToASCII(s string) string { + return quoteWith(s, '"', true, false) +} + +// AppendQuoteToASCII appends a double-quoted Go string literal representing s, +// as generated by QuoteToASCII, to dst and returns the extended buffer. +func AppendQuoteToASCII(dst []byte, s string) []byte { + return appendQuotedWith(dst, s, '"', true, false) +} + +// QuoteToGraphic returns a double-quoted Go string literal representing s. +// The returned string leaves Unicode graphic characters, as defined by +// IsGraphic, unchanged and uses Go escape sequences (\t, \n, \xFF, \u0100) +// for non-graphic characters. +func QuoteToGraphic(s string) string { + return quoteWith(s, '"', false, true) +} + +// AppendQuoteToGraphic appends a double-quoted Go string literal representing s, +// as generated by QuoteToGraphic, to dst and returns the extended buffer. +func AppendQuoteToGraphic(dst []byte, s string) []byte { + return appendQuotedWith(dst, s, '"', false, true) +} + +// QuoteRune returns a single-quoted Go character literal representing the +// rune. The returned string uses Go escape sequences (\t, \n, \xFF, \u0100) +// for control characters and non-printable characters as defined by IsPrint. +// If r is not a valid Unicode code point, it is interpreted as the Unicode +// replacement character U+FFFD. +func QuoteRune(r rune) string { + return quoteRuneWith(r, '\'', false, false) +} + +// AppendQuoteRune appends a single-quoted Go character literal representing the rune, +// as generated by QuoteRune, to dst and returns the extended buffer. +func AppendQuoteRune(dst []byte, r rune) []byte { + return appendQuotedRuneWith(dst, r, '\'', false, false) +} + +// QuoteRuneToASCII returns a single-quoted Go character literal representing +// the rune. The returned string uses Go escape sequences (\t, \n, \xFF, +// \u0100) for non-ASCII characters and non-printable characters as defined +// by IsPrint. +// If r is not a valid Unicode code point, it is interpreted as the Unicode +// replacement character U+FFFD. +func QuoteRuneToASCII(r rune) string { + return quoteRuneWith(r, '\'', true, false) +} + +// AppendQuoteRuneToASCII appends a single-quoted Go character literal representing the rune, +// as generated by QuoteRuneToASCII, to dst and returns the extended buffer. +func AppendQuoteRuneToASCII(dst []byte, r rune) []byte { + return appendQuotedRuneWith(dst, r, '\'', true, false) +} + +// QuoteRuneToGraphic returns a single-quoted Go character literal representing +// the rune. If the rune is not a Unicode graphic character, +// as defined by IsGraphic, the returned string will use a Go escape sequence +// (\t, \n, \xFF, \u0100). +// If r is not a valid Unicode code point, it is interpreted as the Unicode +// replacement character U+FFFD. +func QuoteRuneToGraphic(r rune) string { + return quoteRuneWith(r, '\'', false, true) +} + +// AppendQuoteRuneToGraphic appends a single-quoted Go character literal representing the rune, +// as generated by QuoteRuneToGraphic, to dst and returns the extended buffer. +func AppendQuoteRuneToGraphic(dst []byte, r rune) []byte { + return appendQuotedRuneWith(dst, r, '\'', false, true) +} + +// CanBackquote reports whether the string s can be represented +// unchanged as a single-line backquoted string without control +// characters other than tab. +func CanBackquote(s string) bool { + for len(s) > 0 { + r, wid := utf8.DecodeRuneInString(s) + s = s[wid:] + if wid > 1 { + if r == '\ufeff' { + return false // BOMs are invisible and should not be quoted. + } + continue // All other multibyte runes are correctly encoded and assumed printable. + } + if r == utf8.RuneError { + return false + } + if (r < ' ' && r != '\t') || r == '`' || r == '\u007F' { + return false + } + } + return true +} + +func unhex(b byte) (v rune, ok bool) { + c := rune(b) + switch { + case '0' <= c && c <= '9': + return c - '0', true + case 'a' <= c && c <= 'f': + return c - 'a' + 10, true + case 'A' <= c && c <= 'F': + return c - 'A' + 10, true + } + return +} + +// UnquoteChar decodes the first character or byte in the escaped string +// or character literal represented by the string s. +// It returns four values: +// +// 1. value, the decoded Unicode code point or byte value; +// 2. multibyte, a boolean indicating whether the decoded character requires a multibyte UTF-8 representation; +// 3. tail, the remainder of the string after the character; and +// 4. an error that will be nil if the character is syntactically valid. +// +// The second argument, quote, specifies the type of literal being parsed +// and therefore which escaped quote character is permitted. +// If set to a single quote, it permits the sequence \' and disallows unescaped '. +// If set to a double quote, it permits \" and disallows unescaped ". +// If set to zero, it does not permit either escape and allows both quote characters to appear unescaped. +func UnquoteChar(s string, quote byte) (value rune, multibyte bool, tail string, err error) { + // easy cases + if len(s) == 0 { + err = ErrSyntax + return + } + switch c := s[0]; { + case c == quote && (quote == '\'' || quote == '"'): + err = ErrSyntax + return + case c >= utf8.RuneSelf: + r, size := utf8.DecodeRuneInString(s) + return r, true, s[size:], nil + case c != '\\': + return rune(s[0]), false, s[1:], nil + } + + // hard case: c is backslash + if len(s) <= 1 { + err = ErrSyntax + return + } + c := s[1] + s = s[2:] + + switch c { + case 'a': + value = '\a' + case 'b': + value = '\b' + case 'f': + value = '\f' + case 'n': + value = '\n' + case 'r': + value = '\r' + case 't': + value = '\t' + case 'v': + value = '\v' + case 'x', 'u', 'U': + n := 0 + switch c { + case 'x': + n = 2 + case 'u': + n = 4 + case 'U': + n = 8 + } + var v rune + if len(s) < n { + err = ErrSyntax + return + } + for j := 0; j < n; j++ { + x, ok := unhex(s[j]) + if !ok { + err = ErrSyntax + return + } + v = v<<4 | x + } + s = s[n:] + if c == 'x' { + // single-byte string, possibly not UTF-8 + value = v + break + } + if !utf8.ValidRune(v) { + err = ErrSyntax + return + } + value = v + multibyte = true + case '0', '1', '2', '3', '4', '5', '6', '7': + v := rune(c) - '0' + if len(s) < 2 { + err = ErrSyntax + return + } + for j := 0; j < 2; j++ { // one digit already; two more + x := rune(s[j]) - '0' + if x < 0 || x > 7 { + err = ErrSyntax + return + } + v = (v << 3) | x + } + s = s[2:] + if v > 255 { + err = ErrSyntax + return + } + value = v + case '\\': + value = '\\' + case '\'', '"': + if c != quote { + err = ErrSyntax + return + } + value = rune(c) + default: + err = ErrSyntax + return + } + tail = s + return +} + +// QuotedPrefix returns the quoted string (as understood by Unquote) at the prefix of s. +// If s does not start with a valid quoted string, QuotedPrefix returns an error. +func QuotedPrefix(s string) (string, error) { + out, _, err := unquote(s, false) + return out, err +} + +// Unquote interprets s as a single-quoted, double-quoted, +// or backquoted Go string literal, returning the string value +// that s quotes. (If s is single-quoted, it would be a Go +// character literal; Unquote returns the corresponding +// one-character string.) +func Unquote(s string) (string, error) { + out, rem, err := unquote(s, true) + if len(rem) > 0 { + return "", ErrSyntax + } + return out, err +} + +// unquote parses a quoted string at the start of the input, +// returning the parsed prefix, the remaining suffix, and any parse errors. +// If unescape is true, the parsed prefix is unescaped, +// otherwise the input prefix is provided verbatim. +func unquote(in string, unescape bool) (out, rem string, err error) { + // Determine the quote form and optimistically find the terminating quote. + if len(in) < 2 { + return "", in, ErrSyntax + } + quote := in[0] + end := index(in[1:], quote) + if end < 0 { + return "", in, ErrSyntax + } + end += 2 // position after terminating quote; may be wrong if escape sequences are present + + switch quote { + case '`': + switch { + case !unescape: + out = in[:end] // include quotes + case !contains(in[:end], '\r'): + out = in[len("`") : end-len("`")] // exclude quotes + default: + // Carriage return characters ('\r') inside raw string literals + // are discarded from the raw string value. + buf := make([]byte, 0, end-len("`")-len("\r")-len("`")) + for i := len("`"); i < end-len("`"); i++ { + if in[i] != '\r' { + buf = append(buf, in[i]) + } + } + out = string(buf) + } + // NOTE: Prior implementations did not verify that raw strings consist + // of valid UTF-8 characters and we continue to not verify it as such. + // The Go specification does not explicitly require valid UTF-8, + // but only mention that it is implicitly valid for Go source code + // (which must be valid UTF-8). + return out, in[end:], nil + case '"', '\'': + // Handle quoted strings without any escape sequences. + if !contains(in[:end], '\\') && !contains(in[:end], '\n') { + var valid bool + switch quote { + case '"': + valid = utf8.ValidString(in[len(`"`) : end-len(`"`)]) + case '\'': + r, n := utf8.DecodeRuneInString(in[len("'") : end-len("'")]) + valid = len("'")+n+len("'") == end && (r != utf8.RuneError || n != 1) + } + if valid { + out = in[:end] + if unescape { + out = out[1 : end-1] // exclude quotes + } + return out, in[end:], nil + } + } + + // Handle quoted strings with escape sequences. + var buf []byte + in0 := in + in = in[1:] // skip starting quote + if unescape { + buf = make([]byte, 0, 3*end/2) // try to avoid more allocations + } + for len(in) > 0 && in[0] != quote { + // Process the next character, + // rejecting any unescaped newline characters which are invalid. + r, multibyte, rem, err := UnquoteChar(in, quote) + if in[0] == '\n' || err != nil { + return "", in0, ErrSyntax + } + in = rem + + // Append the character if unescaping the input. + if unescape { + if r < utf8.RuneSelf || !multibyte { + buf = append(buf, byte(r)) + } else { + buf = utf8.AppendRune(buf, r) + } + } + + // Single quoted strings must be a single character. + if quote == '\'' { + break + } + } + + // Verify that the string ends with a terminating quote. + if !(len(in) > 0 && in[0] == quote) { + return "", in0, ErrSyntax + } + in = in[1:] // skip terminating quote + + if unescape { + return string(buf), in, nil + } + return in0[:len(in0)-len(in)], in, nil + default: + return "", in, ErrSyntax + } +} + +// bsearch16 returns the smallest i such that a[i] >= x. +// If there is no such i, bsearch16 returns len(a). +func bsearch16(a []uint16, x uint16) int { + i, j := 0, len(a) + for i < j { + h := i + (j-i)>>1 + if a[h] < x { + i = h + 1 + } else { + j = h + } + } + return i +} + +// bsearch32 returns the smallest i such that a[i] >= x. +// If there is no such i, bsearch32 returns len(a). +func bsearch32(a []uint32, x uint32) int { + i, j := 0, len(a) + for i < j { + h := i + (j-i)>>1 + if a[h] < x { + i = h + 1 + } else { + j = h + } + } + return i +} + +// TODO: IsPrint is a local implementation of unicode.IsPrint, verified by the tests +// to give the same answer. It allows this package not to depend on unicode, +// and therefore not pull in all the Unicode tables. If the linker were better +// at tossing unused tables, we could get rid of this implementation. +// That would be nice. + +// IsPrint reports whether the rune is defined as printable by Go, with +// the same definition as unicode.IsPrint: letters, numbers, punctuation, +// symbols and ASCII space. +func IsPrint(r rune) bool { + // Fast check for Latin-1 + if r <= 0xFF { + if 0x20 <= r && r <= 0x7E { + // All the ASCII is printable from space through DEL-1. + return true + } + if 0xA1 <= r && r <= 0xFF { + // Similarly for ¡ through ÿ... + return r != 0xAD // ...except for the bizarre soft hyphen. + } + return false + } + + // Same algorithm, either on uint16 or uint32 value. + // First, find first i such that isPrint[i] >= x. + // This is the index of either the start or end of a pair that might span x. + // The start is even (isPrint[i&^1]) and the end is odd (isPrint[i|1]). + // If we find x in a range, make sure x is not in isNotPrint list. + + if 0 <= r && r < 1<<16 { + rr, isPrint, isNotPrint := uint16(r), isPrint16, isNotPrint16 + i := bsearch16(isPrint, rr) + if i >= len(isPrint) || rr < isPrint[i&^1] || isPrint[i|1] < rr { + return false + } + j := bsearch16(isNotPrint, rr) + return j >= len(isNotPrint) || isNotPrint[j] != rr + } + + rr, isPrint, isNotPrint := uint32(r), isPrint32, isNotPrint32 + i := bsearch32(isPrint, rr) + if i >= len(isPrint) || rr < isPrint[i&^1] || isPrint[i|1] < rr { + return false + } + if r >= 0x20000 { + return true + } + r -= 0x10000 + j := bsearch16(isNotPrint, uint16(r)) + return j >= len(isNotPrint) || isNotPrint[j] != uint16(r) +} + +// IsGraphic reports whether the rune is defined as a Graphic by Unicode. Such +// characters include letters, marks, numbers, punctuation, symbols, and +// spaces, from categories L, M, N, P, S, and Zs. +func IsGraphic(r rune) bool { + if IsPrint(r) { + return true + } + return isInGraphicList(r) +} + +// isInGraphicList reports whether the rune is in the isGraphic list. This separation +// from IsGraphic allows quoteWith to avoid two calls to IsPrint. +// Should be called only if IsPrint fails. +func isInGraphicList(r rune) bool { + // We know r must fit in 16 bits - see makeisprint.go. + if r > 0xFFFF { + return false + } + rr := uint16(r) + i := bsearch16(isGraphic, rr) + return i < len(isGraphic) && rr == isGraphic[i] +} diff --git a/gnovm/stdlibs/strconv/quote_test.gno b/gnovm/stdlibs/strconv/quote_test.gno new file mode 100644 index 00000000000..b11e95461b0 --- /dev/null +++ b/gnovm/stdlibs/strconv/quote_test.gno @@ -0,0 +1,383 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strconv + +import ( + "strings" + "testing" + "unicode" +) + +// Verify that our IsPrint agrees with unicode.IsPrint. +func TestIsPrint(t *testing.T) { + n := 0 + for r := rune(0); r <= unicode.MaxRune; r++ { + if IsPrint(r) != unicode.IsPrint(r) { + t.Errorf("IsPrint(%U)=%t incorrect", r, IsPrint(r)) + n++ + if n > 10 { + return + } + } + } +} + +// Verify that our IsGraphic agrees with unicode.IsGraphic. +func TestIsGraphic(t *testing.T) { + n := 0 + for r := rune(0); r <= unicode.MaxRune; r++ { + if IsGraphic(r) != unicode.IsGraphic(r) { + t.Errorf("IsGraphic(%U)=%t incorrect", r, IsGraphic(r)) + n++ + if n > 10 { + return + } + } + } +} + +type quoteTest struct { + in string + out string + ascii string + graphic string +} + +var quotetests = []quoteTest{ + {"\a\b\f\r\n\t\v", `"\a\b\f\r\n\t\v"`, `"\a\b\f\r\n\t\v"`, `"\a\b\f\r\n\t\v"`}, + {"\\", `"\\"`, `"\\"`, `"\\"`}, + {"abc\xffdef", `"abc\xffdef"`, `"abc\xffdef"`, `"abc\xffdef"`}, + {"\u263a", `"☺"`, `"\u263a"`, `"☺"`}, + {"\U0010ffff", `"\U0010ffff"`, `"\U0010ffff"`, `"\U0010ffff"`}, + {"\x04", `"\x04"`, `"\x04"`, `"\x04"`}, + // Some non-printable but graphic runes. Final column is double-quoted. + {"!\u00a0!\u2000!\u3000!", `"!\u00a0!\u2000!\u3000!"`, `"!\u00a0!\u2000!\u3000!"`, "\"!\u00a0!\u2000!\u3000!\""}, + {"\x7f", `"\x7f"`, `"\x7f"`, `"\x7f"`}, +} + +func TestQuote(t *testing.T) { + for _, tt := range quotetests { + if out := Quote(tt.in); out != tt.out { + t.Errorf("Quote(%s) = %s, want %s", tt.in, out, tt.out) + } + if out := AppendQuote([]byte("abc"), tt.in); string(out) != "abc"+tt.out { + t.Errorf("AppendQuote(%q, %s) = %s, want %s", "abc", tt.in, out, "abc"+tt.out) + } + } +} + +func TestQuoteToASCII(t *testing.T) { + for _, tt := range quotetests { + if out := QuoteToASCII(tt.in); out != tt.ascii { + t.Errorf("QuoteToASCII(%s) = %s, want %s", tt.in, out, tt.ascii) + } + if out := AppendQuoteToASCII([]byte("abc"), tt.in); string(out) != "abc"+tt.ascii { + t.Errorf("AppendQuoteToASCII(%q, %s) = %s, want %s", "abc", tt.in, out, "abc"+tt.ascii) + } + } +} + +func TestQuoteToGraphic(t *testing.T) { + for _, tt := range quotetests { + if out := QuoteToGraphic(tt.in); out != tt.graphic { + t.Errorf("QuoteToGraphic(%s) = %s, want %s", tt.in, out, tt.graphic) + } + if out := AppendQuoteToGraphic([]byte("abc"), tt.in); string(out) != "abc"+tt.graphic { + t.Errorf("AppendQuoteToGraphic(%q, %s) = %s, want %s", "abc", tt.in, out, "abc"+tt.graphic) + } + } +} + +func BenchmarkQuote(b *testing.B) { + for i := 0; i < b.N; i++ { + Quote("\a\b\f\r\n\t\v\a\b\f\r\n\t\v\a\b\f\r\n\t\v") + } +} + +func BenchmarkQuoteRune(b *testing.B) { + for i := 0; i < b.N; i++ { + QuoteRune('\a') + } +} + +var benchQuoteBuf []byte + +func BenchmarkAppendQuote(b *testing.B) { + for i := 0; i < b.N; i++ { + benchQuoteBuf = AppendQuote(benchQuoteBuf[:0], "\a\b\f\r\n\t\v\a\b\f\r\n\t\v\a\b\f\r\n\t\v") + } +} + +var benchQuoteRuneBuf []byte + +func BenchmarkAppendQuoteRune(b *testing.B) { + for i := 0; i < b.N; i++ { + benchQuoteRuneBuf = AppendQuoteRune(benchQuoteRuneBuf[:0], '\a') + } +} + +type quoteRuneTest struct { + in rune + out string + ascii string + graphic string +} + +var quoterunetests = []quoteRuneTest{ + {'a', `'a'`, `'a'`, `'a'`}, + {'\a', `'\a'`, `'\a'`, `'\a'`}, + {'\\', `'\\'`, `'\\'`, `'\\'`}, + {0xFF, `'ÿ'`, `'\u00ff'`, `'ÿ'`}, + {0x263a, `'☺'`, `'\u263a'`, `'☺'`}, + {0xdead, `'�'`, `'\ufffd'`, `'�'`}, + {0xfffd, `'�'`, `'\ufffd'`, `'�'`}, + {0x0010ffff, `'\U0010ffff'`, `'\U0010ffff'`, `'\U0010ffff'`}, + {0x0010ffff + 1, `'�'`, `'\ufffd'`, `'�'`}, + {0x04, `'\x04'`, `'\x04'`, `'\x04'`}, + // Some differences between graphic and printable. Note the last column is double-quoted. + {'\u00a0', `'\u00a0'`, `'\u00a0'`, "'\u00a0'"}, + {'\u2000', `'\u2000'`, `'\u2000'`, "'\u2000'"}, + {'\u3000', `'\u3000'`, `'\u3000'`, "'\u3000'"}, +} + +func TestQuoteRune(t *testing.T) { + for _, tt := range quoterunetests { + if out := QuoteRune(tt.in); out != tt.out { + t.Errorf("QuoteRune(%U) = %s, want %s", tt.in, out, tt.out) + } + if out := AppendQuoteRune([]byte("abc"), tt.in); string(out) != "abc"+tt.out { + t.Errorf("AppendQuoteRune(%q, %U) = %s, want %s", "abc", tt.in, out, "abc"+tt.out) + } + } +} + +func TestQuoteRuneToASCII(t *testing.T) { + for _, tt := range quoterunetests { + if out := QuoteRuneToASCII(tt.in); out != tt.ascii { + t.Errorf("QuoteRuneToASCII(%U) = %s, want %s", tt.in, out, tt.ascii) + } + if out := AppendQuoteRuneToASCII([]byte("abc"), tt.in); string(out) != "abc"+tt.ascii { + t.Errorf("AppendQuoteRuneToASCII(%q, %U) = %s, want %s", "abc", tt.in, out, "abc"+tt.ascii) + } + } +} + +func TestQuoteRuneToGraphic(t *testing.T) { + for _, tt := range quoterunetests { + if out := QuoteRuneToGraphic(tt.in); out != tt.graphic { + t.Errorf("QuoteRuneToGraphic(%U) = %s, want %s", tt.in, out, tt.graphic) + } + if out := AppendQuoteRuneToGraphic([]byte("abc"), tt.in); string(out) != "abc"+tt.graphic { + t.Errorf("AppendQuoteRuneToGraphic(%q, %U) = %s, want %s", "abc", tt.in, out, "abc"+tt.graphic) + } + } +} + +type canBackquoteTest struct { + in string + out bool +} + +var canbackquotetests = []canBackquoteTest{ + {"`", false}, + {string(rune(0)), false}, + {string(rune(1)), false}, + {string(rune(2)), false}, + {string(rune(3)), false}, + {string(rune(4)), false}, + {string(rune(5)), false}, + {string(rune(6)), false}, + {string(rune(7)), false}, + {string(rune(8)), false}, + {string(rune(9)), true}, // \t + {string(rune(10)), false}, + {string(rune(11)), false}, + {string(rune(12)), false}, + {string(rune(13)), false}, + {string(rune(14)), false}, + {string(rune(15)), false}, + {string(rune(16)), false}, + {string(rune(17)), false}, + {string(rune(18)), false}, + {string(rune(19)), false}, + {string(rune(20)), false}, + {string(rune(21)), false}, + {string(rune(22)), false}, + {string(rune(23)), false}, + {string(rune(24)), false}, + {string(rune(25)), false}, + {string(rune(26)), false}, + {string(rune(27)), false}, + {string(rune(28)), false}, + {string(rune(29)), false}, + {string(rune(30)), false}, + {string(rune(31)), false}, + {string(rune(0x7F)), false}, + {`' !"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, true}, + {`0123456789`, true}, + {`ABCDEFGHIJKLMNOPQRSTUVWXYZ`, true}, + {`abcdefghijklmnopqrstuvwxyz`, true}, + {`☺`, true}, + {"\x80", false}, + {"a\xe0\xa0z", false}, + {"\ufeffabc", false}, + {"a\ufeffz", false}, +} + +func TestCanBackquote(t *testing.T) { + for _, tt := range canbackquotetests { + if out := CanBackquote(tt.in); out != tt.out { + t.Errorf("CanBackquote(%q) = %v, want %v", tt.in, out, tt.out) + } + } +} + +type unQuoteTest struct { + in string + out string +} + +var unquotetests = []unQuoteTest{ + {`""`, ""}, + {`"a"`, "a"}, + {`"abc"`, "abc"}, + {`"☺"`, "☺"}, + {`"hello world"`, "hello world"}, + {`"\xFF"`, "\xFF"}, + {`"\377"`, "\377"}, + {`"\u1234"`, "\u1234"}, + {`"\U00010111"`, "\U00010111"}, + {`"\U0001011111"`, "\U0001011111"}, + {`"\a\b\f\n\r\t\v\\\""`, "\a\b\f\n\r\t\v\\\""}, + {`"'"`, "'"}, + + {`'a'`, "a"}, + {`'☹'`, "☹"}, + {`'\a'`, "\a"}, + {`'\x10'`, "\x10"}, + {`'\377'`, "\377"}, + {`'\u1234'`, "\u1234"}, + {`'\U00010111'`, "\U00010111"}, + {`'\t'`, "\t"}, + {`' '`, " "}, + {`'\''`, "'"}, + {`'"'`, "\""}, + + {"``", ``}, + {"`a`", `a`}, + {"`abc`", `abc`}, + {"`☺`", `☺`}, + {"`hello world`", `hello world`}, + {"`\\xFF`", `\xFF`}, + {"`\\377`", `\377`}, + {"`\\`", `\`}, + {"`\n`", "\n"}, + {"` `", ` `}, + {"` `", ` `}, + {"`a\rb`", "ab"}, +} + +var misquoted = []string{ + ``, + `"`, + `"a`, + `"'`, + `b"`, + `"\"`, + `"\9"`, + `"\19"`, + `"\129"`, + `'\'`, + `'\9'`, + `'\19'`, + `'\129'`, + `'ab'`, + `"\x1!"`, + `"\U12345678"`, + `"\z"`, + "`", + "`xxx", + "``x\r", + "`\"", + `"\'"`, + `'\"'`, + "\"\n\"", + "\"\\n\n\"", + "'\n'", + `"\udead"`, + `"\ud83d\ude4f"`, +} + +func TestUnquote(t *testing.T) { + for _, tt := range unquotetests { + testUnquote(t, tt.in, tt.out, nil) + } + for _, tt := range quotetests { + testUnquote(t, tt.out, tt.in, nil) + } + for _, s := range misquoted { + testUnquote(t, s, "", ErrSyntax) + } +} + +// Issue 23685: invalid UTF-8 should not go through the fast path. +func TestUnquoteInvalidUTF8(t *testing.T) { + tests := []struct { + in string + + // one of: + want string + wantErr error + }{ + {in: `"foo"`, want: "foo"}, + {in: `"foo`, wantErr: ErrSyntax}, + {in: `"` + "\xc0" + `"`, want: "\xef\xbf\xbd"}, + {in: `"a` + "\xc0" + `"`, want: "a\xef\xbf\xbd"}, + {in: `"\t` + "\xc0" + `"`, want: "\t\xef\xbf\xbd"}, + } + for _, tt := range tests { + testUnquote(t, tt.in, tt.want, tt.wantErr) + } +} + +func testUnquote(t *testing.T, in, want string, wantErr error) { + // Test Unquote. + got, gotErr := Unquote(in) + if got != want || gotErr != wantErr { + t.Errorf("Unquote(%q) = (%q, %v), want (%q, %v)", in, got, gotErr, want, wantErr) + } + + // Test QuotedPrefix. + // Adding an arbitrary suffix should not change the result of QuotedPrefix + // assume that the suffix doesn't accidentally terminate a truncated input. + if gotErr == nil { + want = in + } + suffix := "\n\r\\\"`'" // special characters for quoted strings + if len(in) > 0 { + suffix = strings.ReplaceAll(suffix, in[:1], "") + } + in += suffix + got, gotErr = QuotedPrefix(in) + if gotErr == nil && wantErr != nil { + _, wantErr = Unquote(got) // original input had trailing junk, reparse with only valid prefix + want = got + } + if got != want || gotErr != wantErr { + t.Errorf("QuotedPrefix(%q) = (%q, %v), want (%q, %v)", in, got, gotErr, want, wantErr) + } +} + +func BenchmarkUnquoteEasy(b *testing.B) { + for i := 0; i < b.N; i++ { + Unquote(`"Give me a rock, paper and scissors and I will move the world."`) + } +} + +func BenchmarkUnquoteHard(b *testing.B) { + for i := 0; i < b.N; i++ { + Unquote(`"\x47ive me a \x72ock, \x70aper and \x73cissors and \x49 will move the world."`) + } +} diff --git a/gnovm/stdlibs/strconv/strconv.gno b/gnovm/stdlibs/strconv/strconv.gno deleted file mode 100644 index bc7b5d8d1b6..00000000000 --- a/gnovm/stdlibs/strconv/strconv.gno +++ /dev/null @@ -1,10 +0,0 @@ -package strconv - -func Itoa(n int) string // injected -func AppendUint(dst []byte, i uint64, base int) []byte // injected -func Atoi(s string) (int, error) // injected -func CanBackquote(s string) bool // injected -func FormatInt(i int64, base int) string // injected -func FormatUint(i uint64, base int) string // injected -func Quote(s string) string // injected -func QuoteToASCII(s string) string // injected diff --git a/gnovm/stdlibs/strconv/strconv.go b/gnovm/stdlibs/strconv/strconv.go deleted file mode 100644 index 782a63e84b6..00000000000 --- a/gnovm/stdlibs/strconv/strconv.go +++ /dev/null @@ -1,12 +0,0 @@ -package strconv - -import "strconv" - -func Itoa(n int) string { return strconv.Itoa(n) } -func AppendUint(dst []byte, i uint64, base int) []byte { return strconv.AppendUint(dst, i, base) } -func Atoi(s string) (int, error) { return strconv.Atoi(s) } -func CanBackquote(s string) bool { return strconv.CanBackquote(s) } -func FormatInt(i int64, base int) string { return strconv.FormatInt(i, base) } -func FormatUint(i uint64, base int) string { return strconv.FormatUint(i, base) } -func Quote(s string) string { return strconv.Quote(s) } -func QuoteToASCII(r string) string { return strconv.QuoteToASCII(r) } diff --git a/gnovm/stdlibs/strconv/strconv_test.gno b/gnovm/stdlibs/strconv/strconv_test.gno new file mode 100644 index 00000000000..5421ae84a93 --- /dev/null +++ b/gnovm/stdlibs/strconv/strconv_test.gno @@ -0,0 +1,156 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strconv + +import ( + "strings" + "testing" +) + +var ( + globalBuf [64]byte + nextToOne = "1.00000000000000011102230246251565404236316680908203125" + strings.Repeat("0", 10000) + "1" + oneMB = make([]byte, 1e6) + + mallocTest = []struct { + count int + desc string + fn func() + }{ + {0, `AppendInt(localBuf[:0], 123, 10)`, func() { + var localBuf [64]byte + AppendInt(localBuf[:0], 123, 10) + }}, + {0, `AppendInt(globalBuf[:0], 123, 10)`, func() { AppendInt(globalBuf[:0], 123, 10) }}, + {0, `AppendFloat(localBuf[:0], 1.23, 'g', 5, 64)`, func() { + var localBuf [64]byte + AppendFloat(localBuf[:0], 1.23, 'g', 5, 64) + }}, + {0, `AppendFloat(globalBuf[:0], 1.23, 'g', 5, 64)`, func() { AppendFloat(globalBuf[:0], 1.23, 'g', 5, 64) }}, + // In practice we see 7 for the next one, but allow some slop. + // Before pre-allocation in appendQuotedWith, we saw 39. + {10, `AppendQuoteToASCII(nil, oneMB)`, func() { AppendQuoteToASCII(nil, string(oneMB)) }}, + {0, `ParseFloat("123.45", 64)`, func() { ParseFloat("123.45", 64) }}, + {0, `ParseFloat("123.456789123456789", 64)`, func() { ParseFloat("123.456789123456789", 64) }}, + {0, `ParseFloat("1.000000000000000111022302462515654042363166809082031251", 64)`, func() { + ParseFloat("1.000000000000000111022302462515654042363166809082031251", 64) + }}, + {0, `ParseFloat("1.0000000000000001110223024625156540423631668090820312500...001", 64)`, func() { + ParseFloat(nextToOne, 64) + }}, + } +) + +// XXX: removed due to lack of AllocsPerRun +// func TestCountMallocs(t *testing.T) { +// if testing.Short() { +// t.Skip("skipping malloc count in short mode") +// } +// // Allocate a big messy buffer for AppendQuoteToASCII's test. +// oneMB = make([]byte, 1e6) +// for i := range oneMB { +// oneMB[i] = byte(i) +// } +// for _, mt := range mallocTest { +// allocs := testing.AllocsPerRun(100, mt.fn) +// if max := float64(mt.count); allocs > max { +// t.Errorf("%s: %v allocs, want <=%v", mt.desc, allocs, max) +// } +// } +// } + +// Sink makes sure the compiler cannot optimize away the benchmarks. +var Sink struct { + Bool bool + Int int + Int64 int64 + Uint64 uint64 + Float64 float64 + Error error + Bytes []byte +} + +/* XXX: removed due to lack of AllocsPerRun +func TestAllocationsFromBytes(t *testing.T) { + const runsPerTest = 100 + bytes := struct{ Bool, Number, String, Buffer []byte }{ + Bool: []byte("false"), + Number: []byte("123456789"), + String: []byte("hello, world!"), + Buffer: make([]byte, 1024), + } + + checkNoAllocs := func(f func()) func(t *testing.T) { + return func(t *testing.T) { + t.Helper() + if allocs := testing.AllocsPerRun(runsPerTest, f); allocs != 0 { + t.Errorf("got %v allocs, want 0 allocs", allocs) + } + } + } + + t.Run("Atoi", checkNoAllocs(func() { + Sink.Int, Sink.Error = Atoi(string(bytes.Number)) + })) + t.Run("ParseBool", checkNoAllocs(func() { + Sink.Bool, Sink.Error = ParseBool(string(bytes.Bool)) + })) + t.Run("ParseInt", checkNoAllocs(func() { + Sink.Int64, Sink.Error = ParseInt(string(bytes.Number), 10, 64) + })) + t.Run("ParseUint", checkNoAllocs(func() { + Sink.Uint64, Sink.Error = ParseUint(string(bytes.Number), 10, 64) + })) + t.Run("ParseFloat", checkNoAllocs(func() { + Sink.Float64, Sink.Error = ParseFloat(string(bytes.Number), 64) + })) + t.Run("ParseComplex", checkNoAllocs(func() { + Sink.Complex128, Sink.Error = ParseComplex(string(bytes.Number), 128) + })) + t.Run("CanBackquote", checkNoAllocs(func() { + Sink.Bool = CanBackquote(string(bytes.String)) + })) + t.Run("AppendQuote", checkNoAllocs(func() { + Sink.Bytes = AppendQuote(bytes.Buffer[:0], string(bytes.String)) + })) + t.Run("AppendQuoteToASCII", checkNoAllocs(func() { + Sink.Bytes = AppendQuoteToASCII(bytes.Buffer[:0], string(bytes.String)) + })) + t.Run("AppendQuoteToGraphic", checkNoAllocs(func() { + Sink.Bytes = AppendQuoteToGraphic(bytes.Buffer[:0], string(bytes.String)) + })) +} +*/ + +func TestErrorPrefixes(t *testing.T) { + _, errInt := Atoi("INVALID") + _, errBool := ParseBool("INVALID") + _, errFloat := ParseFloat("INVALID", 64) + _, errInt64 := ParseInt("INVALID", 10, 64) + _, errUint64 := ParseUint("INVALID", 10, 64) + + vectors := []struct { + err error // Input error + want string // Function name wanted + }{ + {errInt, "Atoi"}, + {errBool, "ParseBool"}, + {errFloat, "ParseFloat"}, + {errInt64, "ParseInt"}, + {errUint64, "ParseUint"}, + } + + for _, v := range vectors { + nerr, ok := v.err.(*NumError) + if !ok { + t.Errorf("test %s, error was not a *NumError", v.want) + continue + } + if got := nerr.Func; got != v.want { + t.Errorf("mismatching Func: got %s, want %s", got, v.want) + } + } + +} diff --git a/gnovm/stdlibs/unicode/example_test.gno b/gnovm/stdlibs/unicode/example_test.gno index 3ab11a4b5d2..bd2920dfb56 100644 --- a/gnovm/stdlibs/unicode/example_test.gno +++ b/gnovm/stdlibs/unicode/example_test.gno @@ -116,7 +116,7 @@ func ExampleSimpleFold() { fmt.Printf("%#U\n", unicode.SimpleFold('A')) // 'a' fmt.Printf("%#U\n", unicode.SimpleFold('a')) // 'A' fmt.Printf("%#U\n", unicode.SimpleFold('K')) // 'k' - fmt.Printf("%#U\n", unicode.SimpleFold('k')) // '\u212A' (Kelvin symbol, K) + fmt.Printf("%#U\n", unicode.SimpleFold('k')) // '\u212A' (Kelvin symbol, K) fmt.Printf("%#U\n", unicode.SimpleFold('\u212A')) // 'K' fmt.Printf("%#U\n", unicode.SimpleFold('1')) // '1' @@ -124,7 +124,7 @@ func ExampleSimpleFold() { // U+0061 'a' // U+0041 'A' // U+006B 'k' - // U+212A 'K' + // U+212A 'K' // U+004B 'K' // U+0031 '1' } @@ -194,3 +194,63 @@ func ExampleSpecialCase() { // U+0130 'İ' // U+0130 'İ' } + +func ExampleIsDigit() { + fmt.Printf("%t\n", unicode.IsDigit('৩')) + fmt.Printf("%t\n", unicode.IsDigit('A')) + // Output: + // true + // false +} + +func ExampleIsNumber() { + fmt.Printf("%t\n", unicode.IsNumber('Ⅷ')) + fmt.Printf("%t\n", unicode.IsNumber('A')) + // Output: + // true + // false +} + +func ExampleIsLetter() { + fmt.Printf("%t\n", unicode.IsLetter('A')) + fmt.Printf("%t\n", unicode.IsLetter('7')) + // Output: + // true + // false +} + +func ExampleIsLower() { + fmt.Printf("%t\n", unicode.IsLower('a')) + fmt.Printf("%t\n", unicode.IsLower('A')) + // Output: + // true + // false +} + +func ExampleIsUpper() { + fmt.Printf("%t\n", unicode.IsUpper('A')) + fmt.Printf("%t\n", unicode.IsUpper('a')) + // Output: + // true + // false +} + +func ExampleIsTitle() { + fmt.Printf("%t\n", unicode.IsTitle('Dž')) + fmt.Printf("%t\n", unicode.IsTitle('a')) + // Output: + // true + // false +} + +func ExampleIsSpace() { + fmt.Printf("%t\n", unicode.IsSpace(' ')) + fmt.Printf("%t\n", unicode.IsSpace('\n')) + fmt.Printf("%t\n", unicode.IsSpace('\t')) + fmt.Printf("%t\n", unicode.IsSpace('a')) + // Output: + // true + // true + // true + // false +} diff --git a/gnovm/stdlibs/unicode/letter.gno b/gnovm/stdlibs/unicode/letter.gno index aa1039aa38d..f3f8e529648 100644 --- a/gnovm/stdlibs/unicode/letter.gno +++ b/gnovm/stdlibs/unicode/letter.gno @@ -331,7 +331,7 @@ type foldPair struct { // SimpleFold('a') = 'A' // // SimpleFold('K') = 'k' -// SimpleFold('k') = '\u212A' (Kelvin symbol, K) +// SimpleFold('k') = '\u212A' (Kelvin symbol, K) // SimpleFold('\u212A') = 'K' // // SimpleFold('1') = '1' diff --git a/gnovm/stdlibs/unicode/tables.gno b/gnovm/stdlibs/unicode/tables.gno index a57e0ca67cb..b3d65d9d5c1 100644 --- a/gnovm/stdlibs/unicode/tables.gno +++ b/gnovm/stdlibs/unicode/tables.gno @@ -3,7 +3,7 @@ package unicode // Version is the Unicode edition from which the tables are derived. -const Version = "13.0.0" +const Version = "15.0.0" // Categories is the set of Unicode category tables. var Categories = map[string]*RangeTable{ @@ -52,7 +52,8 @@ var _C = &RangeTable{ {0x00ad, 0x0600, 1363}, {0x0601, 0x0605, 1}, {0x061c, 0x06dd, 193}, - {0x070f, 0x08e2, 467}, + {0x070f, 0x0890, 385}, + {0x0891, 0x08e2, 81}, {0x180e, 0x200b, 2045}, {0x200c, 0x200f, 1}, {0x202a, 0x202e, 1}, @@ -64,7 +65,7 @@ var _C = &RangeTable{ }, R32: []Range32{ {0x110bd, 0x110cd, 16}, - {0x13430, 0x13438, 1}, + {0x13430, 0x1343f, 1}, {0x1bca0, 0x1bca3, 1}, {0x1d173, 0x1d17a, 1}, {0xe0001, 0xe0020, 31}, @@ -88,7 +89,8 @@ var _Cf = &RangeTable{ {0x00ad, 0x0600, 1363}, {0x0601, 0x0605, 1}, {0x061c, 0x06dd, 193}, - {0x070f, 0x08e2, 467}, + {0x070f, 0x0890, 385}, + {0x0891, 0x08e2, 81}, {0x180e, 0x200b, 2045}, {0x200c, 0x200f, 1}, {0x202a, 0x202e, 1}, @@ -99,7 +101,7 @@ var _Cf = &RangeTable{ }, R32: []Range32{ {0x110bd, 0x110cd, 16}, - {0x13430, 0x13438, 1}, + {0x13430, 0x1343f, 1}, {0x1bca0, 0x1bca3, 1}, {0x1d173, 0x1d17a, 1}, {0xe0001, 0xe0020, 31}, @@ -169,8 +171,9 @@ var _L = &RangeTable{ {0x0828, 0x0840, 24}, {0x0841, 0x0858, 1}, {0x0860, 0x086a, 1}, - {0x08a0, 0x08b4, 1}, - {0x08b6, 0x08c7, 1}, + {0x0870, 0x0887, 1}, + {0x0889, 0x088e, 1}, + {0x08a0, 0x08c9, 1}, {0x0904, 0x0939, 1}, {0x093d, 0x0950, 19}, {0x0958, 0x0961, 1}, @@ -231,17 +234,18 @@ var _L = &RangeTable{ {0x0c2a, 0x0c39, 1}, {0x0c3d, 0x0c58, 27}, {0x0c59, 0x0c5a, 1}, - {0x0c60, 0x0c61, 1}, - {0x0c80, 0x0c85, 5}, - {0x0c86, 0x0c8c, 1}, + {0x0c5d, 0x0c60, 3}, + {0x0c61, 0x0c80, 31}, + {0x0c85, 0x0c8c, 1}, {0x0c8e, 0x0c90, 1}, {0x0c92, 0x0ca8, 1}, {0x0caa, 0x0cb3, 1}, {0x0cb5, 0x0cb9, 1}, - {0x0cbd, 0x0cde, 33}, - {0x0ce0, 0x0ce1, 1}, - {0x0cf1, 0x0cf2, 1}, - {0x0d04, 0x0d0c, 1}, + {0x0cbd, 0x0cdd, 32}, + {0x0cde, 0x0ce0, 2}, + {0x0ce1, 0x0cf1, 16}, + {0x0cf2, 0x0d04, 18}, + {0x0d05, 0x0d0c, 1}, {0x0d0e, 0x0d10, 1}, {0x0d12, 0x0d3a, 1}, {0x0d3d, 0x0d4e, 17}, @@ -307,9 +311,8 @@ var _L = &RangeTable{ {0x1681, 0x169a, 1}, {0x16a0, 0x16ea, 1}, {0x16f1, 0x16f8, 1}, - {0x1700, 0x170c, 1}, - {0x170e, 0x1711, 1}, - {0x1720, 0x1731, 1}, + {0x1700, 0x1711, 1}, + {0x171f, 0x1731, 1}, {0x1740, 0x1751, 1}, {0x1760, 0x176c, 1}, {0x176e, 0x1770, 1}, @@ -329,7 +332,7 @@ var _L = &RangeTable{ {0x1a20, 0x1a54, 1}, {0x1aa7, 0x1b05, 94}, {0x1b06, 0x1b33, 1}, - {0x1b45, 0x1b4b, 1}, + {0x1b45, 0x1b4c, 1}, {0x1b83, 0x1ba0, 1}, {0x1bae, 0x1baf, 1}, {0x1bba, 0x1be5, 1}, @@ -374,9 +377,7 @@ var _L = &RangeTable{ {0x2145, 0x2149, 1}, {0x214e, 0x2183, 53}, {0x2184, 0x2c00, 2684}, - {0x2c01, 0x2c2e, 1}, - {0x2c30, 0x2c5e, 1}, - {0x2c60, 0x2ce4, 1}, + {0x2c01, 0x2ce4, 1}, {0x2ceb, 0x2cee, 1}, {0x2cf2, 0x2cf3, 1}, {0x2d00, 0x2d25, 1}, @@ -405,8 +406,7 @@ var _L = &RangeTable{ {0x31a0, 0x31bf, 1}, {0x31f0, 0x31ff, 1}, {0x3400, 0x4dbf, 1}, - {0x4e00, 0x9ffc, 1}, - {0xa000, 0xa48c, 1}, + {0x4e00, 0xa48c, 1}, {0xa4d0, 0xa4fd, 1}, {0xa500, 0xa60c, 1}, {0xa610, 0xa61f, 1}, @@ -416,9 +416,11 @@ var _L = &RangeTable{ {0xa6a0, 0xa6e5, 1}, {0xa717, 0xa71f, 1}, {0xa722, 0xa788, 1}, - {0xa78b, 0xa7bf, 1}, - {0xa7c2, 0xa7ca, 1}, - {0xa7f5, 0xa801, 1}, + {0xa78b, 0xa7ca, 1}, + {0xa7d0, 0xa7d1, 1}, + {0xa7d3, 0xa7d5, 2}, + {0xa7d6, 0xa7d9, 1}, + {0xa7f2, 0xa801, 1}, {0xa803, 0xa805, 1}, {0xa807, 0xa80a, 1}, {0xa80c, 0xa822, 1}, @@ -507,9 +509,20 @@ var _L = &RangeTable{ {0x104d8, 0x104fb, 1}, {0x10500, 0x10527, 1}, {0x10530, 0x10563, 1}, + {0x10570, 0x1057a, 1}, + {0x1057c, 0x1058a, 1}, + {0x1058c, 0x10592, 1}, + {0x10594, 0x10595, 1}, + {0x10597, 0x105a1, 1}, + {0x105a3, 0x105b1, 1}, + {0x105b3, 0x105b9, 1}, + {0x105bb, 0x105bc, 1}, {0x10600, 0x10736, 1}, {0x10740, 0x10755, 1}, {0x10760, 0x10767, 1}, + {0x10780, 0x10785, 1}, + {0x10787, 0x107b0, 1}, + {0x107b2, 0x107ba, 1}, {0x10800, 0x10805, 1}, {0x10808, 0x1080a, 2}, {0x1080b, 0x10835, 1}, @@ -545,10 +558,13 @@ var _L = &RangeTable{ {0x10f00, 0x10f1c, 1}, {0x10f27, 0x10f30, 9}, {0x10f31, 0x10f45, 1}, + {0x10f70, 0x10f81, 1}, {0x10fb0, 0x10fc4, 1}, {0x10fe0, 0x10ff6, 1}, {0x11003, 0x11037, 1}, - {0x11083, 0x110af, 1}, + {0x11071, 0x11072, 1}, + {0x11075, 0x11083, 14}, + {0x11084, 0x110af, 1}, {0x110d0, 0x110e8, 1}, {0x11103, 0x11126, 1}, {0x11144, 0x11147, 3}, @@ -559,6 +575,7 @@ var _L = &RangeTable{ {0x111da, 0x111dc, 2}, {0x11200, 0x11211, 1}, {0x11213, 0x1122b, 1}, + {0x1123f, 0x11240, 1}, {0x11280, 0x11286, 1}, {0x11288, 0x1128a, 2}, {0x1128b, 0x1128d, 1}, @@ -586,6 +603,7 @@ var _L = &RangeTable{ {0x11681, 0x116aa, 1}, {0x116b8, 0x11700, 72}, {0x11701, 0x1171a, 1}, + {0x11740, 0x11746, 1}, {0x11800, 0x1182b, 1}, {0x118a0, 0x118df, 1}, {0x118ff, 0x11906, 1}, @@ -601,8 +619,8 @@ var _L = &RangeTable{ {0x11a0c, 0x11a32, 1}, {0x11a3a, 0x11a50, 22}, {0x11a5c, 0x11a89, 1}, - {0x11a9d, 0x11ac0, 35}, - {0x11ac1, 0x11af8, 1}, + {0x11a9d, 0x11ab0, 19}, + {0x11ab1, 0x11af8, 1}, {0x11c00, 0x11c08, 1}, {0x11c0a, 0x11c2e, 1}, {0x11c40, 0x11c72, 50}, @@ -616,13 +634,19 @@ var _L = &RangeTable{ {0x11d6a, 0x11d89, 1}, {0x11d98, 0x11ee0, 328}, {0x11ee1, 0x11ef2, 1}, + {0x11f02, 0x11f04, 2}, + {0x11f05, 0x11f10, 1}, + {0x11f12, 0x11f33, 1}, {0x11fb0, 0x12000, 80}, {0x12001, 0x12399, 1}, {0x12480, 0x12543, 1}, - {0x13000, 0x1342e, 1}, + {0x12f90, 0x12ff0, 1}, + {0x13000, 0x1342f, 1}, + {0x13441, 0x13446, 1}, {0x14400, 0x14646, 1}, {0x16800, 0x16a38, 1}, {0x16a40, 0x16a5e, 1}, + {0x16a70, 0x16abe, 1}, {0x16ad0, 0x16aed, 1}, {0x16b00, 0x16b2f, 1}, {0x16b40, 0x16b43, 1}, @@ -637,9 +661,14 @@ var _L = &RangeTable{ {0x17001, 0x187f7, 1}, {0x18800, 0x18cd5, 1}, {0x18d00, 0x18d08, 1}, - {0x1b000, 0x1b11e, 1}, - {0x1b150, 0x1b152, 1}, - {0x1b164, 0x1b167, 1}, + {0x1aff0, 0x1aff3, 1}, + {0x1aff5, 0x1affb, 1}, + {0x1affd, 0x1affe, 1}, + {0x1b000, 0x1b122, 1}, + {0x1b132, 0x1b150, 30}, + {0x1b151, 0x1b152, 1}, + {0x1b155, 0x1b164, 15}, + {0x1b165, 0x1b167, 1}, {0x1b170, 0x1b2fb, 1}, {0x1bc00, 0x1bc6a, 1}, {0x1bc70, 0x1bc7c, 1}, @@ -675,10 +704,19 @@ var _L = &RangeTable{ {0x1d78a, 0x1d7a8, 1}, {0x1d7aa, 0x1d7c2, 1}, {0x1d7c4, 0x1d7cb, 1}, + {0x1df00, 0x1df1e, 1}, + {0x1df25, 0x1df2a, 1}, + {0x1e030, 0x1e06d, 1}, {0x1e100, 0x1e12c, 1}, {0x1e137, 0x1e13d, 1}, - {0x1e14e, 0x1e2c0, 370}, - {0x1e2c1, 0x1e2eb, 1}, + {0x1e14e, 0x1e290, 322}, + {0x1e291, 0x1e2ad, 1}, + {0x1e2c0, 0x1e2eb, 1}, + {0x1e4d0, 0x1e4eb, 1}, + {0x1e7e0, 0x1e7e6, 1}, + {0x1e7e8, 0x1e7eb, 1}, + {0x1e7ed, 0x1e7ee, 1}, + {0x1e7f0, 0x1e7fe, 1}, {0x1e800, 0x1e8c4, 1}, {0x1e900, 0x1e943, 1}, {0x1e94b, 0x1ee00, 1205}, @@ -706,13 +744,14 @@ var _L = &RangeTable{ {0x1eea1, 0x1eea3, 1}, {0x1eea5, 0x1eea9, 1}, {0x1eeab, 0x1eebb, 1}, - {0x20000, 0x2a6dd, 1}, - {0x2a700, 0x2b734, 1}, + {0x20000, 0x2a6df, 1}, + {0x2a700, 0x2b739, 1}, {0x2b740, 0x2b81d, 1}, {0x2b820, 0x2cea1, 1}, {0x2ceb0, 0x2ebe0, 1}, {0x2f800, 0x2fa1d, 1}, {0x30000, 0x3134a, 1}, + {0x31350, 0x323af, 1}, }, LatinOffset: 6, } @@ -807,7 +846,7 @@ var _Ll = &RangeTable{ {0x213c, 0x213d, 1}, {0x2146, 0x2149, 1}, {0x214e, 0x2184, 54}, - {0x2c30, 0x2c5e, 1}, + {0x2c30, 0x2c5f, 1}, {0x2c61, 0x2c65, 4}, {0x2c66, 0x2c6c, 2}, {0x2c71, 0x2c73, 2}, @@ -831,11 +870,11 @@ var _Ll = &RangeTable{ {0xa794, 0xa795, 1}, {0xa797, 0xa7a9, 2}, {0xa7af, 0xa7b5, 6}, - {0xa7b7, 0xa7bf, 2}, - {0xa7c3, 0xa7c8, 5}, - {0xa7ca, 0xa7f6, 44}, - {0xa7fa, 0xab30, 822}, - {0xab31, 0xab5a, 1}, + {0xa7b7, 0xa7c3, 2}, + {0xa7c8, 0xa7ca, 2}, + {0xa7d1, 0xa7d9, 2}, + {0xa7f6, 0xa7fa, 4}, + {0xab30, 0xab5a, 1}, {0xab60, 0xab68, 1}, {0xab70, 0xabbf, 1}, {0xfb00, 0xfb06, 1}, @@ -845,6 +884,10 @@ var _Ll = &RangeTable{ R32: []Range32{ {0x10428, 0x1044f, 1}, {0x104d8, 0x104fb, 1}, + {0x10597, 0x105a1, 1}, + {0x105a3, 0x105b1, 1}, + {0x105b3, 0x105b9, 1}, + {0x105bb, 0x105bc, 1}, {0x10cc0, 0x10cf2, 1}, {0x118c0, 0x118df, 1}, {0x16e60, 0x16e7f, 1}, @@ -875,8 +918,11 @@ var _Ll = &RangeTable{ {0x1d78a, 0x1d78f, 1}, {0x1d7aa, 0x1d7c2, 1}, {0x1d7c4, 0x1d7c9, 1}, - {0x1d7cb, 0x1e922, 4439}, - {0x1e923, 0x1e943, 1}, + {0x1d7cb, 0x1df00, 1845}, + {0x1df01, 0x1df09, 1}, + {0x1df0b, 0x1df1e, 1}, + {0x1df25, 0x1df2a, 1}, + {0x1e922, 0x1e943, 1}, }, LatinOffset: 4, } @@ -893,11 +939,11 @@ var _Lm = &RangeTable{ {0x07f4, 0x07f5, 1}, {0x07fa, 0x081a, 32}, {0x0824, 0x0828, 4}, - {0x0971, 0x0e46, 1237}, - {0x0ec6, 0x10fc, 566}, - {0x17d7, 0x1843, 108}, - {0x1aa7, 0x1c78, 465}, - {0x1c79, 0x1c7d, 1}, + {0x08c9, 0x0971, 168}, + {0x0e46, 0x0ec6, 128}, + {0x10fc, 0x17d7, 1755}, + {0x1843, 0x1aa7, 612}, + {0x1c78, 0x1c7d, 1}, {0x1d2c, 0x1d6a, 1}, {0x1d78, 0x1d9b, 35}, {0x1d9c, 0x1dbf, 1}, @@ -916,6 +962,7 @@ var _Lm = &RangeTable{ {0xa69c, 0xa69d, 1}, {0xa717, 0xa71f, 1}, {0xa770, 0xa788, 24}, + {0xa7f2, 0xa7f4, 1}, {0xa7f8, 0xa7f9, 1}, {0xa9cf, 0xa9e6, 23}, {0xaa70, 0xaadd, 109}, @@ -925,12 +972,19 @@ var _Lm = &RangeTable{ {0xff9e, 0xff9f, 1}, }, R32: []Range32{ + {0x10780, 0x10785, 1}, + {0x10787, 0x107b0, 1}, + {0x107b2, 0x107ba, 1}, {0x16b40, 0x16b43, 1}, {0x16f93, 0x16f9f, 1}, {0x16fe0, 0x16fe1, 1}, - {0x16fe3, 0x1e137, 29012}, - {0x1e138, 0x1e13d, 1}, - {0x1e94b, 0x1e94b, 1}, + {0x16fe3, 0x1aff0, 16397}, + {0x1aff1, 0x1aff3, 1}, + {0x1aff5, 0x1affb, 1}, + {0x1affd, 0x1affe, 1}, + {0x1e030, 0x1e06d, 1}, + {0x1e137, 0x1e13d, 1}, + {0x1e4eb, 0x1e94b, 1120}, }, } @@ -957,8 +1011,9 @@ var _Lo = &RangeTable{ {0x0800, 0x0815, 1}, {0x0840, 0x0858, 1}, {0x0860, 0x086a, 1}, - {0x08a0, 0x08b4, 1}, - {0x08b6, 0x08c7, 1}, + {0x0870, 0x0887, 1}, + {0x0889, 0x088e, 1}, + {0x08a0, 0x08c8, 1}, {0x0904, 0x0939, 1}, {0x093d, 0x0950, 19}, {0x0958, 0x0961, 1}, @@ -1019,17 +1074,18 @@ var _Lo = &RangeTable{ {0x0c2a, 0x0c39, 1}, {0x0c3d, 0x0c58, 27}, {0x0c59, 0x0c5a, 1}, - {0x0c60, 0x0c61, 1}, - {0x0c80, 0x0c85, 5}, - {0x0c86, 0x0c8c, 1}, + {0x0c5d, 0x0c60, 3}, + {0x0c61, 0x0c80, 31}, + {0x0c85, 0x0c8c, 1}, {0x0c8e, 0x0c90, 1}, {0x0c92, 0x0ca8, 1}, {0x0caa, 0x0cb3, 1}, {0x0cb5, 0x0cb9, 1}, - {0x0cbd, 0x0cde, 33}, - {0x0ce0, 0x0ce1, 1}, - {0x0cf1, 0x0cf2, 1}, - {0x0d04, 0x0d0c, 1}, + {0x0cbd, 0x0cdd, 32}, + {0x0cde, 0x0ce0, 2}, + {0x0ce1, 0x0cf1, 16}, + {0x0cf2, 0x0d04, 18}, + {0x0d05, 0x0d0c, 1}, {0x0d0e, 0x0d10, 1}, {0x0d12, 0x0d3a, 1}, {0x0d3d, 0x0d4e, 17}, @@ -1089,9 +1145,8 @@ var _Lo = &RangeTable{ {0x1681, 0x169a, 1}, {0x16a0, 0x16ea, 1}, {0x16f1, 0x16f8, 1}, - {0x1700, 0x170c, 1}, - {0x170e, 0x1711, 1}, - {0x1720, 0x1731, 1}, + {0x1700, 0x1711, 1}, + {0x171f, 0x1731, 1}, {0x1740, 0x1751, 1}, {0x1760, 0x176c, 1}, {0x176e, 0x1770, 1}, @@ -1111,7 +1166,7 @@ var _Lo = &RangeTable{ {0x1a00, 0x1a16, 1}, {0x1a20, 0x1a54, 1}, {0x1b05, 0x1b33, 1}, - {0x1b45, 0x1b4b, 1}, + {0x1b45, 0x1b4c, 1}, {0x1b83, 0x1ba0, 1}, {0x1bae, 0x1baf, 1}, {0x1bba, 0x1be5, 1}, @@ -1143,8 +1198,7 @@ var _Lo = &RangeTable{ {0x31a0, 0x31bf, 1}, {0x31f0, 0x31ff, 1}, {0x3400, 0x4dbf, 1}, - {0x4e00, 0x9ffc, 1}, - {0xa000, 0xa014, 1}, + {0x4e00, 0xa014, 1}, {0xa016, 0xa48c, 1}, {0xa4d0, 0xa4f7, 1}, {0xa500, 0xa60b, 1}, @@ -1272,10 +1326,13 @@ var _Lo = &RangeTable{ {0x10f00, 0x10f1c, 1}, {0x10f27, 0x10f30, 9}, {0x10f31, 0x10f45, 1}, + {0x10f70, 0x10f81, 1}, {0x10fb0, 0x10fc4, 1}, {0x10fe0, 0x10ff6, 1}, {0x11003, 0x11037, 1}, - {0x11083, 0x110af, 1}, + {0x11071, 0x11072, 1}, + {0x11075, 0x11083, 14}, + {0x11084, 0x110af, 1}, {0x110d0, 0x110e8, 1}, {0x11103, 0x11126, 1}, {0x11144, 0x11147, 3}, @@ -1286,6 +1343,7 @@ var _Lo = &RangeTable{ {0x111da, 0x111dc, 2}, {0x11200, 0x11211, 1}, {0x11213, 0x1122b, 1}, + {0x1123f, 0x11240, 1}, {0x11280, 0x11286, 1}, {0x11288, 0x1128a, 2}, {0x1128b, 0x1128d, 1}, @@ -1313,6 +1371,7 @@ var _Lo = &RangeTable{ {0x11681, 0x116aa, 1}, {0x116b8, 0x11700, 72}, {0x11701, 0x1171a, 1}, + {0x11740, 0x11746, 1}, {0x11800, 0x1182b, 1}, {0x118ff, 0x11906, 1}, {0x11909, 0x1190c, 3}, @@ -1327,8 +1386,8 @@ var _Lo = &RangeTable{ {0x11a0c, 0x11a32, 1}, {0x11a3a, 0x11a50, 22}, {0x11a5c, 0x11a89, 1}, - {0x11a9d, 0x11ac0, 35}, - {0x11ac1, 0x11af8, 1}, + {0x11a9d, 0x11ab0, 19}, + {0x11ab1, 0x11af8, 1}, {0x11c00, 0x11c08, 1}, {0x11c0a, 0x11c2e, 1}, {0x11c40, 0x11c72, 50}, @@ -1342,13 +1401,19 @@ var _Lo = &RangeTable{ {0x11d6a, 0x11d89, 1}, {0x11d98, 0x11ee0, 328}, {0x11ee1, 0x11ef2, 1}, + {0x11f02, 0x11f04, 2}, + {0x11f05, 0x11f10, 1}, + {0x11f12, 0x11f33, 1}, {0x11fb0, 0x12000, 80}, {0x12001, 0x12399, 1}, {0x12480, 0x12543, 1}, - {0x13000, 0x1342e, 1}, + {0x12f90, 0x12ff0, 1}, + {0x13000, 0x1342f, 1}, + {0x13441, 0x13446, 1}, {0x14400, 0x14646, 1}, {0x16800, 0x16a38, 1}, {0x16a40, 0x16a5e, 1}, + {0x16a70, 0x16abe, 1}, {0x16ad0, 0x16aed, 1}, {0x16b00, 0x16b2f, 1}, {0x16b63, 0x16b77, 1}, @@ -1358,17 +1423,26 @@ var _Lo = &RangeTable{ {0x17001, 0x187f7, 1}, {0x18800, 0x18cd5, 1}, {0x18d00, 0x18d08, 1}, - {0x1b000, 0x1b11e, 1}, - {0x1b150, 0x1b152, 1}, - {0x1b164, 0x1b167, 1}, + {0x1b000, 0x1b122, 1}, + {0x1b132, 0x1b150, 30}, + {0x1b151, 0x1b152, 1}, + {0x1b155, 0x1b164, 15}, + {0x1b165, 0x1b167, 1}, {0x1b170, 0x1b2fb, 1}, {0x1bc00, 0x1bc6a, 1}, {0x1bc70, 0x1bc7c, 1}, {0x1bc80, 0x1bc88, 1}, {0x1bc90, 0x1bc99, 1}, - {0x1e100, 0x1e12c, 1}, - {0x1e14e, 0x1e2c0, 370}, - {0x1e2c1, 0x1e2eb, 1}, + {0x1df0a, 0x1e100, 502}, + {0x1e101, 0x1e12c, 1}, + {0x1e14e, 0x1e290, 322}, + {0x1e291, 0x1e2ad, 1}, + {0x1e2c0, 0x1e2eb, 1}, + {0x1e4d0, 0x1e4ea, 1}, + {0x1e7e0, 0x1e7e6, 1}, + {0x1e7e8, 0x1e7eb, 1}, + {0x1e7ed, 0x1e7ee, 1}, + {0x1e7f0, 0x1e7fe, 1}, {0x1e800, 0x1e8c4, 1}, {0x1ee00, 0x1ee03, 1}, {0x1ee05, 0x1ee1f, 1}, @@ -1394,13 +1468,14 @@ var _Lo = &RangeTable{ {0x1eea1, 0x1eea3, 1}, {0x1eea5, 0x1eea9, 1}, {0x1eeab, 0x1eebb, 1}, - {0x20000, 0x2a6dd, 1}, - {0x2a700, 0x2b734, 1}, + {0x20000, 0x2a6df, 1}, + {0x2a700, 0x2b739, 1}, {0x2b740, 0x2b81d, 1}, {0x2b820, 0x2cea1, 1}, {0x2ceb0, 0x2ebe0, 1}, {0x2f800, 0x2fa1d, 1}, {0x30000, 0x3134a, 1}, + {0x31350, 0x323af, 1}, }, LatinOffset: 1, } @@ -1501,7 +1576,7 @@ var _Lu = &RangeTable{ {0x2130, 0x2133, 1}, {0x213e, 0x213f, 1}, {0x2145, 0x2183, 62}, - {0x2c00, 0x2c2e, 1}, + {0x2c00, 0x2c2f, 1}, {0x2c60, 0x2c62, 2}, {0x2c63, 0x2c64, 1}, {0x2c67, 0x2c6d, 2}, @@ -1522,15 +1597,20 @@ var _Lu = &RangeTable{ {0xa796, 0xa7aa, 2}, {0xa7ab, 0xa7ae, 1}, {0xa7b0, 0xa7b4, 1}, - {0xa7b6, 0xa7be, 2}, - {0xa7c2, 0xa7c4, 2}, + {0xa7b6, 0xa7c4, 2}, {0xa7c5, 0xa7c7, 1}, - {0xa7c9, 0xa7f5, 44}, - {0xff21, 0xff3a, 1}, + {0xa7c9, 0xa7d0, 7}, + {0xa7d6, 0xa7d8, 2}, + {0xa7f5, 0xff21, 22316}, + {0xff22, 0xff3a, 1}, }, R32: []Range32{ {0x10400, 0x10427, 1}, {0x104b0, 0x104d3, 1}, + {0x10570, 0x1057a, 1}, + {0x1057c, 0x1058a, 1}, + {0x1058c, 0x10592, 1}, + {0x10594, 0x10595, 1}, {0x10c80, 0x10cb2, 1}, {0x118a0, 0x118bf, 1}, {0x16e40, 0x16e5f, 1}, @@ -1594,7 +1674,8 @@ var _M = &RangeTable{ {0x0825, 0x0827, 1}, {0x0829, 0x082d, 1}, {0x0859, 0x085b, 1}, - {0x08d3, 0x08e1, 1}, + {0x0898, 0x089f, 1}, + {0x08ca, 0x08e1, 1}, {0x08e3, 0x0903, 1}, {0x093a, 0x093c, 1}, {0x093e, 0x094f, 1}, @@ -1634,7 +1715,8 @@ var _M = &RangeTable{ {0x0bca, 0x0bcd, 1}, {0x0bd7, 0x0c00, 41}, {0x0c01, 0x0c04, 1}, - {0x0c3e, 0x0c44, 1}, + {0x0c3c, 0x0c3e, 2}, + {0x0c3f, 0x0c44, 1}, {0x0c46, 0x0c48, 1}, {0x0c4a, 0x0c4d, 1}, {0x0c55, 0x0c56, 1}, @@ -1646,7 +1728,8 @@ var _M = &RangeTable{ {0x0cca, 0x0ccd, 1}, {0x0cd5, 0x0cd6, 1}, {0x0ce2, 0x0ce3, 1}, - {0x0d00, 0x0d03, 1}, + {0x0cf3, 0x0d00, 13}, + {0x0d01, 0x0d03, 1}, {0x0d3b, 0x0d3c, 1}, {0x0d3e, 0x0d44, 1}, {0x0d46, 0x0d48, 1}, @@ -1664,7 +1747,7 @@ var _M = &RangeTable{ {0x0e47, 0x0e4e, 1}, {0x0eb1, 0x0eb4, 3}, {0x0eb5, 0x0ebc, 1}, - {0x0ec8, 0x0ecd, 1}, + {0x0ec8, 0x0ece, 1}, {0x0f18, 0x0f19, 1}, {0x0f35, 0x0f39, 2}, {0x0f3e, 0x0f3f, 1}, @@ -1683,22 +1766,22 @@ var _M = &RangeTable{ {0x108f, 0x109a, 11}, {0x109b, 0x109d, 1}, {0x135d, 0x135f, 1}, - {0x1712, 0x1714, 1}, + {0x1712, 0x1715, 1}, {0x1732, 0x1734, 1}, {0x1752, 0x1753, 1}, {0x1772, 0x1773, 1}, {0x17b4, 0x17d3, 1}, {0x17dd, 0x180b, 46}, {0x180c, 0x180d, 1}, - {0x1885, 0x1886, 1}, - {0x18a9, 0x1920, 119}, - {0x1921, 0x192b, 1}, + {0x180f, 0x1885, 118}, + {0x1886, 0x18a9, 35}, + {0x1920, 0x192b, 1}, {0x1930, 0x193b, 1}, {0x1a17, 0x1a1b, 1}, {0x1a55, 0x1a5e, 1}, {0x1a60, 0x1a7c, 1}, {0x1a7f, 0x1ab0, 49}, - {0x1ab1, 0x1ac0, 1}, + {0x1ab1, 0x1ace, 1}, {0x1b00, 0x1b04, 1}, {0x1b34, 0x1b44, 1}, {0x1b6b, 0x1b73, 1}, @@ -1710,8 +1793,7 @@ var _M = &RangeTable{ {0x1cd4, 0x1ce8, 1}, {0x1ced, 0x1cf4, 7}, {0x1cf7, 0x1cf9, 1}, - {0x1dc0, 0x1df9, 1}, - {0x1dfb, 0x1dff, 1}, + {0x1dc0, 0x1dff, 1}, {0x20d0, 0x20f0, 1}, {0x2cef, 0x2cf1, 1}, {0x2d7f, 0x2de0, 97}, @@ -1763,12 +1845,17 @@ var _M = &RangeTable{ {0x10ae6, 0x10d24, 574}, {0x10d25, 0x10d27, 1}, {0x10eab, 0x10eac, 1}, + {0x10efd, 0x10eff, 1}, {0x10f46, 0x10f50, 1}, + {0x10f82, 0x10f85, 1}, {0x11000, 0x11002, 1}, {0x11038, 0x11046, 1}, - {0x1107f, 0x11082, 1}, + {0x11070, 0x11073, 3}, + {0x11074, 0x1107f, 11}, + {0x11080, 0x11082, 1}, {0x110b0, 0x110ba, 1}, - {0x11100, 0x11102, 1}, + {0x110c2, 0x11100, 62}, + {0x11101, 0x11102, 1}, {0x11127, 0x11134, 1}, {0x11145, 0x11146, 1}, {0x11173, 0x11180, 13}, @@ -1777,8 +1864,8 @@ var _M = &RangeTable{ {0x111c9, 0x111cc, 1}, {0x111ce, 0x111cf, 1}, {0x1122c, 0x11237, 1}, - {0x1123e, 0x112df, 161}, - {0x112e0, 0x112ea, 1}, + {0x1123e, 0x11241, 3}, + {0x112df, 0x112ea, 1}, {0x11300, 0x11303, 1}, {0x1133b, 0x1133c, 1}, {0x1133e, 0x11344, 1}, @@ -1825,6 +1912,12 @@ var _M = &RangeTable{ {0x11d90, 0x11d91, 1}, {0x11d93, 0x11d97, 1}, {0x11ef3, 0x11ef6, 1}, + {0x11f00, 0x11f01, 1}, + {0x11f03, 0x11f34, 49}, + {0x11f35, 0x11f3a, 1}, + {0x11f3e, 0x11f42, 1}, + {0x13440, 0x13447, 7}, + {0x13448, 0x13455, 1}, {0x16af0, 0x16af4, 1}, {0x16b30, 0x16b36, 1}, {0x16f4f, 0x16f51, 2}, @@ -1832,8 +1925,10 @@ var _M = &RangeTable{ {0x16f8f, 0x16f92, 1}, {0x16fe4, 0x16ff0, 12}, {0x16ff1, 0x1bc9d, 19628}, - {0x1bc9e, 0x1d165, 5319}, - {0x1d166, 0x1d169, 1}, + {0x1bc9e, 0x1cf00, 4706}, + {0x1cf01, 0x1cf2d, 1}, + {0x1cf30, 0x1cf46, 1}, + {0x1d165, 0x1d169, 1}, {0x1d16d, 0x1d172, 1}, {0x1d17b, 0x1d182, 1}, {0x1d185, 0x1d18b, 1}, @@ -1849,8 +1944,11 @@ var _M = &RangeTable{ {0x1e01b, 0x1e021, 1}, {0x1e023, 0x1e024, 1}, {0x1e026, 0x1e02a, 1}, - {0x1e130, 0x1e136, 1}, - {0x1e2ec, 0x1e2ef, 1}, + {0x1e08f, 0x1e130, 161}, + {0x1e131, 0x1e136, 1}, + {0x1e2ae, 0x1e2ec, 62}, + {0x1e2ed, 0x1e2ef, 1}, + {0x1e4ec, 0x1e4ef, 1}, {0x1e8d0, 0x1e8d6, 1}, {0x1e944, 0x1e94a, 1}, {0xe0100, 0xe01ef, 1}, @@ -1890,8 +1988,9 @@ var _Mc = &RangeTable{ {0x0cc7, 0x0cc8, 1}, {0x0cca, 0x0ccb, 1}, {0x0cd5, 0x0cd6, 1}, - {0x0d02, 0x0d03, 1}, - {0x0d3e, 0x0d40, 1}, + {0x0cf3, 0x0d02, 15}, + {0x0d03, 0x0d3e, 59}, + {0x0d3f, 0x0d40, 1}, {0x0d46, 0x0d48, 1}, {0x0d4a, 0x0d4c, 1}, {0x0d57, 0x0d82, 43}, @@ -1911,6 +2010,7 @@ var _Mc = &RangeTable{ {0x1087, 0x108c, 1}, {0x108f, 0x109a, 11}, {0x109b, 0x109c, 1}, + {0x1715, 0x1734, 31}, {0x17b6, 0x17be, 8}, {0x17bf, 0x17c5, 1}, {0x17c7, 0x17c8, 1}, @@ -2009,7 +2109,10 @@ var _Mc = &RangeTable{ {0x11d8a, 0x11d8e, 1}, {0x11d93, 0x11d94, 1}, {0x11d96, 0x11ef5, 351}, - {0x11ef6, 0x16f51, 20571}, + {0x11ef6, 0x11f03, 13}, + {0x11f34, 0x11f35, 1}, + {0x11f3e, 0x11f3f, 1}, + {0x11f41, 0x16f51, 20496}, {0x16f52, 0x16f87, 1}, {0x16ff0, 0x16ff1, 1}, {0x1d165, 0x1d166, 1}, @@ -2052,7 +2155,8 @@ var _Mn = &RangeTable{ {0x0825, 0x0827, 1}, {0x0829, 0x082d, 1}, {0x0859, 0x085b, 1}, - {0x08d3, 0x08e1, 1}, + {0x0898, 0x089f, 1}, + {0x08ca, 0x08e1, 1}, {0x08e3, 0x0902, 1}, {0x093a, 0x093c, 2}, {0x0941, 0x0948, 1}, @@ -2085,7 +2189,8 @@ var _Mn = &RangeTable{ {0x0b63, 0x0b82, 31}, {0x0bc0, 0x0bcd, 13}, {0x0c00, 0x0c04, 4}, - {0x0c3e, 0x0c40, 1}, + {0x0c3c, 0x0c3e, 2}, + {0x0c3f, 0x0c40, 1}, {0x0c46, 0x0c48, 1}, {0x0c4a, 0x0c4d, 1}, {0x0c55, 0x0c56, 1}, @@ -2106,7 +2211,7 @@ var _Mn = &RangeTable{ {0x0e47, 0x0e4e, 1}, {0x0eb1, 0x0eb4, 3}, {0x0eb5, 0x0ebc, 1}, - {0x0ec8, 0x0ecd, 1}, + {0x0ec8, 0x0ece, 1}, {0x0f18, 0x0f19, 1}, {0x0f35, 0x0f39, 2}, {0x0f71, 0x0f7e, 1}, @@ -2127,7 +2232,7 @@ var _Mn = &RangeTable{ {0x109d, 0x135d, 704}, {0x135e, 0x135f, 1}, {0x1712, 0x1714, 1}, - {0x1732, 0x1734, 1}, + {0x1732, 0x1733, 1}, {0x1752, 0x1753, 1}, {0x1772, 0x1773, 1}, {0x17b4, 0x17b5, 1}, @@ -2136,9 +2241,9 @@ var _Mn = &RangeTable{ {0x17ca, 0x17d3, 1}, {0x17dd, 0x180b, 46}, {0x180c, 0x180d, 1}, - {0x1885, 0x1886, 1}, - {0x18a9, 0x1920, 119}, - {0x1921, 0x1922, 1}, + {0x180f, 0x1885, 118}, + {0x1886, 0x18a9, 35}, + {0x1920, 0x1922, 1}, {0x1927, 0x1928, 1}, {0x1932, 0x1939, 7}, {0x193a, 0x193b, 1}, @@ -2150,7 +2255,7 @@ var _Mn = &RangeTable{ {0x1a73, 0x1a7c, 1}, {0x1a7f, 0x1ab0, 49}, {0x1ab1, 0x1abd, 1}, - {0x1abf, 0x1ac0, 1}, + {0x1abf, 0x1ace, 1}, {0x1b00, 0x1b03, 1}, {0x1b34, 0x1b36, 2}, {0x1b37, 0x1b3a, 1}, @@ -2170,8 +2275,7 @@ var _Mn = &RangeTable{ {0x1ce2, 0x1ce8, 1}, {0x1ced, 0x1cf4, 7}, {0x1cf8, 0x1cf9, 1}, - {0x1dc0, 0x1df9, 1}, - {0x1dfb, 0x1dff, 1}, + {0x1dc0, 0x1dff, 1}, {0x20d0, 0x20dc, 1}, {0x20e1, 0x20e5, 4}, {0x20e6, 0x20f0, 1}, @@ -2223,13 +2327,18 @@ var _Mn = &RangeTable{ {0x10ae6, 0x10d24, 574}, {0x10d25, 0x10d27, 1}, {0x10eab, 0x10eac, 1}, + {0x10efd, 0x10eff, 1}, {0x10f46, 0x10f50, 1}, + {0x10f82, 0x10f85, 1}, {0x11001, 0x11038, 55}, {0x11039, 0x11046, 1}, - {0x1107f, 0x11081, 1}, + {0x11070, 0x11073, 3}, + {0x11074, 0x1107f, 11}, + {0x11080, 0x11081, 1}, {0x110b3, 0x110b6, 1}, {0x110b9, 0x110ba, 1}, - {0x11100, 0x11102, 1}, + {0x110c2, 0x11100, 62}, + {0x11101, 0x11102, 1}, {0x11127, 0x1112b, 1}, {0x1112d, 0x11134, 1}, {0x11173, 0x11180, 13}, @@ -2240,8 +2349,8 @@ var _Mn = &RangeTable{ {0x11230, 0x11231, 1}, {0x11234, 0x11236, 2}, {0x11237, 0x1123e, 7}, - {0x112df, 0x112e3, 4}, - {0x112e4, 0x112ea, 1}, + {0x11241, 0x112df, 158}, + {0x112e3, 0x112ea, 1}, {0x11300, 0x11301, 1}, {0x1133b, 0x1133c, 1}, {0x11340, 0x11366, 38}, @@ -2296,14 +2405,21 @@ var _Mn = &RangeTable{ {0x11d47, 0x11d90, 73}, {0x11d91, 0x11d95, 4}, {0x11d97, 0x11ef3, 348}, - {0x11ef4, 0x16af0, 19452}, - {0x16af1, 0x16af4, 1}, + {0x11ef4, 0x11f00, 12}, + {0x11f01, 0x11f36, 53}, + {0x11f37, 0x11f3a, 1}, + {0x11f40, 0x11f42, 2}, + {0x13440, 0x13447, 7}, + {0x13448, 0x13455, 1}, + {0x16af0, 0x16af4, 1}, {0x16b30, 0x16b36, 1}, {0x16f4f, 0x16f8f, 64}, {0x16f90, 0x16f92, 1}, {0x16fe4, 0x1bc9d, 19641}, - {0x1bc9e, 0x1d167, 5321}, - {0x1d168, 0x1d169, 1}, + {0x1bc9e, 0x1cf00, 4706}, + {0x1cf01, 0x1cf2d, 1}, + {0x1cf30, 0x1cf46, 1}, + {0x1d167, 0x1d169, 1}, {0x1d17b, 0x1d182, 1}, {0x1d185, 0x1d18b, 1}, {0x1d1aa, 0x1d1ad, 1}, @@ -2318,8 +2434,11 @@ var _Mn = &RangeTable{ {0x1e01b, 0x1e021, 1}, {0x1e023, 0x1e024, 1}, {0x1e026, 0x1e02a, 1}, - {0x1e130, 0x1e136, 1}, - {0x1e2ec, 0x1e2ef, 1}, + {0x1e08f, 0x1e130, 161}, + {0x1e131, 0x1e136, 1}, + {0x1e2ae, 0x1e2ec, 62}, + {0x1e2ed, 0x1e2ef, 1}, + {0x1e4ec, 0x1e4ef, 1}, {0x1e8d0, 0x1e8d6, 1}, {0x1e944, 0x1e94a, 1}, {0xe0100, 0xe01ef, 1}, @@ -2441,17 +2560,21 @@ var _N = &RangeTable{ {0x11c50, 0x11c6c, 1}, {0x11d50, 0x11d59, 1}, {0x11da0, 0x11da9, 1}, + {0x11f50, 0x11f59, 1}, {0x11fc0, 0x11fd4, 1}, {0x12400, 0x1246e, 1}, {0x16a60, 0x16a69, 1}, + {0x16ac0, 0x16ac9, 1}, {0x16b50, 0x16b59, 1}, {0x16b5b, 0x16b61, 1}, {0x16e80, 0x16e96, 1}, + {0x1d2c0, 0x1d2d3, 1}, {0x1d2e0, 0x1d2f3, 1}, {0x1d360, 0x1d378, 1}, {0x1d7ce, 0x1d7ff, 1}, {0x1e140, 0x1e149, 1}, {0x1e2f0, 0x1e2f9, 1}, + {0x1e4f0, 0x1e4f9, 1}, {0x1e8c7, 0x1e8cf, 1}, {0x1e950, 0x1e959, 1}, {0x1ec71, 0x1ecab, 1}, @@ -2523,11 +2646,14 @@ var _Nd = &RangeTable{ {0x11c50, 0x11c59, 1}, {0x11d50, 0x11d59, 1}, {0x11da0, 0x11da9, 1}, + {0x11f50, 0x11f59, 1}, {0x16a60, 0x16a69, 1}, + {0x16ac0, 0x16ac9, 1}, {0x16b50, 0x16b59, 1}, {0x1d7ce, 0x1d7ff, 1}, {0x1e140, 0x1e149, 1}, {0x1e2f0, 0x1e2f9, 1}, + {0x1e4f0, 0x1e4f9, 1}, {0x1e950, 0x1e959, 1}, {0x1fbf0, 0x1fbf9, 1}, }, @@ -2617,6 +2743,7 @@ var _No = &RangeTable{ {0x11fc0, 0x11fd4, 1}, {0x16b5b, 0x16b61, 1}, {0x16e80, 0x16e96, 1}, + {0x1d2c0, 0x1d2d3, 1}, {0x1d2e0, 0x1d2f3, 1}, {0x1d360, 0x1d378, 1}, {0x1e8c7, 0x1e8cf, 1}, @@ -2651,9 +2778,9 @@ var _P = &RangeTable{ {0x05f3, 0x05f4, 1}, {0x0609, 0x060a, 1}, {0x060c, 0x060d, 1}, - {0x061b, 0x061e, 3}, - {0x061f, 0x066a, 75}, - {0x066b, 0x066d, 1}, + {0x061b, 0x061d, 2}, + {0x061e, 0x061f, 1}, + {0x066a, 0x066d, 1}, {0x06d4, 0x0700, 44}, {0x0701, 0x070d, 1}, {0x07f7, 0x07f9, 1}, @@ -2686,6 +2813,7 @@ var _P = &RangeTable{ {0x1aa0, 0x1aa6, 1}, {0x1aa8, 0x1aad, 1}, {0x1b5a, 0x1b60, 1}, + {0x1b7d, 0x1b7e, 1}, {0x1bfc, 0x1bff, 1}, {0x1c3b, 0x1c3f, 1}, {0x1c7e, 0x1c7f, 1}, @@ -2710,8 +2838,8 @@ var _P = &RangeTable{ {0x2d70, 0x2e00, 144}, {0x2e01, 0x2e2e, 1}, {0x2e30, 0x2e4f, 1}, - {0x2e52, 0x3001, 431}, - {0x3002, 0x3003, 1}, + {0x2e52, 0x2e5d, 1}, + {0x3001, 0x3003, 1}, {0x3008, 0x3011, 1}, {0x3014, 0x301f, 1}, {0x3030, 0x303d, 13}, @@ -2759,6 +2887,7 @@ var _P = &RangeTable{ {0x10b99, 0x10b9c, 1}, {0x10ead, 0x10f55, 168}, {0x10f56, 0x10f59, 1}, + {0x10f86, 0x10f89, 1}, {0x11047, 0x1104d, 1}, {0x110bb, 0x110bc, 1}, {0x110be, 0x110c1, 1}, @@ -2775,18 +2904,22 @@ var _P = &RangeTable{ {0x115c1, 0x115d7, 1}, {0x11641, 0x11643, 1}, {0x11660, 0x1166c, 1}, - {0x1173c, 0x1173e, 1}, + {0x116b9, 0x1173c, 131}, + {0x1173d, 0x1173e, 1}, {0x1183b, 0x11944, 265}, {0x11945, 0x11946, 1}, {0x119e2, 0x11a3f, 93}, {0x11a40, 0x11a46, 1}, {0x11a9a, 0x11a9c, 1}, {0x11a9e, 0x11aa2, 1}, + {0x11b00, 0x11b09, 1}, {0x11c41, 0x11c45, 1}, {0x11c70, 0x11c71, 1}, {0x11ef7, 0x11ef8, 1}, + {0x11f43, 0x11f4f, 1}, {0x11fff, 0x12470, 1137}, {0x12471, 0x12474, 1}, + {0x12ff1, 0x12ff2, 1}, {0x16a6e, 0x16a6f, 1}, {0x16af5, 0x16b37, 66}, {0x16b38, 0x16b3b, 1}, @@ -2817,11 +2950,11 @@ var _Pd = &RangeTable{ {0x2011, 0x2015, 1}, {0x2e17, 0x2e1a, 3}, {0x2e3a, 0x2e3b, 1}, - {0x2e40, 0x301c, 476}, - {0x3030, 0x30a0, 112}, - {0xfe31, 0xfe32, 1}, - {0xfe58, 0xfe63, 11}, - {0xff0d, 0xff0d, 1}, + {0x2e40, 0x2e5d, 29}, + {0x301c, 0x3030, 20}, + {0x30a0, 0xfe31, 52625}, + {0xfe32, 0xfe58, 38}, + {0xfe63, 0xff0d, 170}, }, R32: []Range32{ {0x10ead, 0x10ead, 1}, @@ -2843,6 +2976,7 @@ var _Pe = &RangeTable{ {0x29d9, 0x29db, 2}, {0x29fd, 0x2e23, 1062}, {0x2e25, 0x2e29, 2}, + {0x2e56, 0x2e5c, 2}, {0x3009, 0x3011, 2}, {0x3015, 0x301b, 2}, {0x301e, 0x301f, 1}, @@ -2895,9 +3029,9 @@ var _Po = &RangeTable{ {0x05f3, 0x05f4, 1}, {0x0609, 0x060a, 1}, {0x060c, 0x060d, 1}, - {0x061b, 0x061e, 3}, - {0x061f, 0x066a, 75}, - {0x066b, 0x066d, 1}, + {0x061b, 0x061d, 2}, + {0x061e, 0x061f, 1}, + {0x066a, 0x066d, 1}, {0x06d4, 0x0700, 44}, {0x0701, 0x070d, 1}, {0x07f7, 0x07f9, 1}, @@ -2928,6 +3062,7 @@ var _Po = &RangeTable{ {0x1aa0, 0x1aa6, 1}, {0x1aa8, 0x1aad, 1}, {0x1b5a, 0x1b60, 1}, + {0x1b7d, 0x1b7e, 1}, {0x1bfc, 0x1bff, 1}, {0x1c3b, 0x1c3f, 1}, {0x1c7e, 0x1c7f, 1}, @@ -2956,8 +3091,8 @@ var _Po = &RangeTable{ {0x2e3c, 0x2e3f, 1}, {0x2e41, 0x2e43, 2}, {0x2e44, 0x2e4f, 1}, - {0x2e52, 0x3001, 431}, - {0x3002, 0x3003, 1}, + {0x2e52, 0x2e54, 1}, + {0x3001, 0x3003, 1}, {0x303d, 0x30fb, 190}, {0xa4fe, 0xa4ff, 1}, {0xa60d, 0xa60f, 1}, @@ -3003,6 +3138,7 @@ var _Po = &RangeTable{ {0x10b39, 0x10b3f, 1}, {0x10b99, 0x10b9c, 1}, {0x10f55, 0x10f59, 1}, + {0x10f86, 0x10f89, 1}, {0x11047, 0x1104d, 1}, {0x110bb, 0x110bc, 1}, {0x110be, 0x110c1, 1}, @@ -3019,18 +3155,22 @@ var _Po = &RangeTable{ {0x115c1, 0x115d7, 1}, {0x11641, 0x11643, 1}, {0x11660, 0x1166c, 1}, - {0x1173c, 0x1173e, 1}, + {0x116b9, 0x1173c, 131}, + {0x1173d, 0x1173e, 1}, {0x1183b, 0x11944, 265}, {0x11945, 0x11946, 1}, {0x119e2, 0x11a3f, 93}, {0x11a40, 0x11a46, 1}, {0x11a9a, 0x11a9c, 1}, {0x11a9e, 0x11aa2, 1}, + {0x11b00, 0x11b09, 1}, {0x11c41, 0x11c45, 1}, {0x11c70, 0x11c71, 1}, {0x11ef7, 0x11ef8, 1}, + {0x11f43, 0x11f4f, 1}, {0x11fff, 0x12470, 1137}, {0x12471, 0x12474, 1}, + {0x12ff1, 0x12ff2, 1}, {0x16a6e, 0x16a6f, 1}, {0x16af5, 0x16b37, 66}, {0x16b38, 0x16b3b, 1}, @@ -3059,8 +3199,9 @@ var _Ps = &RangeTable{ {0x29d8, 0x29da, 2}, {0x29fc, 0x2e22, 1062}, {0x2e24, 0x2e28, 2}, - {0x2e42, 0x3008, 454}, - {0x300a, 0x3010, 2}, + {0x2e42, 0x2e55, 19}, + {0x2e57, 0x2e5b, 2}, + {0x3008, 0x3010, 2}, {0x3014, 0x301a, 2}, {0x301d, 0xfd3f, 52514}, {0xfe17, 0xfe35, 30}, @@ -3101,10 +3242,11 @@ var _S = &RangeTable{ {0x06e9, 0x06fd, 20}, {0x06fe, 0x07f6, 248}, {0x07fe, 0x07ff, 1}, - {0x09f2, 0x09f3, 1}, - {0x09fa, 0x09fb, 1}, - {0x0af1, 0x0b70, 127}, - {0x0bf3, 0x0bfa, 1}, + {0x0888, 0x09f2, 362}, + {0x09f3, 0x09fa, 7}, + {0x09fb, 0x0af1, 246}, + {0x0b70, 0x0bf3, 131}, + {0x0bf4, 0x0bfa, 1}, {0x0c7f, 0x0d4f, 208}, {0x0d79, 0x0e3f, 198}, {0x0f01, 0x0f03, 1}, @@ -3132,7 +3274,7 @@ var _S = &RangeTable{ {0x2044, 0x2052, 14}, {0x207a, 0x207c, 1}, {0x208a, 0x208c, 1}, - {0x20a0, 0x20bf, 1}, + {0x20a0, 0x20c0, 1}, {0x2100, 0x2101, 1}, {0x2103, 0x2106, 1}, {0x2108, 0x2109, 1}, @@ -3190,8 +3332,10 @@ var _S = &RangeTable{ {0xaa77, 0xaa79, 1}, {0xab5b, 0xab6a, 15}, {0xab6b, 0xfb29, 20414}, - {0xfbb2, 0xfbc1, 1}, - {0xfdfc, 0xfdfd, 1}, + {0xfbb2, 0xfbc2, 1}, + {0xfd40, 0xfd4f, 1}, + {0xfdcf, 0xfdfc, 45}, + {0xfdfd, 0xfdff, 1}, {0xfe62, 0xfe64, 2}, {0xfe65, 0xfe66, 1}, {0xfe69, 0xff04, 155}, @@ -3215,13 +3359,14 @@ var _S = &RangeTable{ {0x11fd5, 0x11ff1, 1}, {0x16b3c, 0x16b3f, 1}, {0x16b45, 0x1bc9c, 20823}, + {0x1cf50, 0x1cfc3, 1}, {0x1d000, 0x1d0f5, 1}, {0x1d100, 0x1d126, 1}, {0x1d129, 0x1d164, 1}, {0x1d16a, 0x1d16c, 1}, {0x1d183, 0x1d184, 1}, {0x1d18c, 0x1d1a9, 1}, - {0x1d1ae, 0x1d1e8, 1}, + {0x1d1ae, 0x1d1ea, 1}, {0x1d200, 0x1d241, 1}, {0x1d245, 0x1d300, 187}, {0x1d301, 0x1d356, 1}, @@ -3252,28 +3397,27 @@ var _S = &RangeTable{ {0x1f250, 0x1f251, 1}, {0x1f260, 0x1f265, 1}, {0x1f300, 0x1f6d7, 1}, - {0x1f6e0, 0x1f6ec, 1}, + {0x1f6dc, 0x1f6ec, 1}, {0x1f6f0, 0x1f6fc, 1}, - {0x1f700, 0x1f773, 1}, - {0x1f780, 0x1f7d8, 1}, + {0x1f700, 0x1f776, 1}, + {0x1f77b, 0x1f7d9, 1}, {0x1f7e0, 0x1f7eb, 1}, - {0x1f800, 0x1f80b, 1}, + {0x1f7f0, 0x1f800, 16}, + {0x1f801, 0x1f80b, 1}, {0x1f810, 0x1f847, 1}, {0x1f850, 0x1f859, 1}, {0x1f860, 0x1f887, 1}, {0x1f890, 0x1f8ad, 1}, {0x1f8b0, 0x1f8b1, 1}, - {0x1f900, 0x1f978, 1}, - {0x1f97a, 0x1f9cb, 1}, - {0x1f9cd, 0x1fa53, 1}, + {0x1f900, 0x1fa53, 1}, {0x1fa60, 0x1fa6d, 1}, - {0x1fa70, 0x1fa74, 1}, - {0x1fa78, 0x1fa7a, 1}, - {0x1fa80, 0x1fa86, 1}, - {0x1fa90, 0x1faa8, 1}, - {0x1fab0, 0x1fab6, 1}, - {0x1fac0, 0x1fac2, 1}, - {0x1fad0, 0x1fad6, 1}, + {0x1fa70, 0x1fa7c, 1}, + {0x1fa80, 0x1fa88, 1}, + {0x1fa90, 0x1fabd, 1}, + {0x1fabf, 0x1fac5, 1}, + {0x1face, 0x1fadb, 1}, + {0x1fae0, 0x1fae8, 1}, + {0x1faf0, 0x1faf8, 1}, {0x1fb00, 0x1fb92, 1}, {0x1fb94, 0x1fbca, 1}, }, @@ -3290,7 +3434,7 @@ var _Sc = &RangeTable{ {0x09fb, 0x0af1, 246}, {0x0bf9, 0x0e3f, 582}, {0x17db, 0x20a0, 2245}, - {0x20a1, 0x20bf, 1}, + {0x20a1, 0x20c0, 1}, {0xa838, 0xfdfc, 21956}, {0xfe69, 0xff04, 155}, {0xffe0, 0xffe1, 1}, @@ -3314,8 +3458,9 @@ var _Sk = &RangeTable{ {0x02ed, 0x02ef, 2}, {0x02f0, 0x02ff, 1}, {0x0375, 0x0384, 15}, - {0x0385, 0x1fbd, 7224}, - {0x1fbf, 0x1fc1, 1}, + {0x0385, 0x0888, 1283}, + {0x1fbd, 0x1fbf, 2}, + {0x1fc0, 0x1fc1, 1}, {0x1fcd, 0x1fcf, 1}, {0x1fdd, 0x1fdf, 1}, {0x1fed, 0x1fef, 1}, @@ -3326,7 +3471,7 @@ var _Sk = &RangeTable{ {0xa789, 0xa78a, 1}, {0xab5b, 0xab6a, 15}, {0xab6b, 0xfbb2, 20551}, - {0xfbb3, 0xfbc1, 1}, + {0xfbb3, 0xfbc2, 1}, {0xff3e, 0xff40, 2}, {0xffe3, 0xffe3, 1}, }, @@ -3488,10 +3633,12 @@ var _So = &RangeTable{ {0xa836, 0xa837, 1}, {0xa839, 0xaa77, 574}, {0xaa78, 0xaa79, 1}, - {0xfdfd, 0xffe4, 487}, - {0xffe8, 0xffed, 5}, - {0xffee, 0xfffc, 14}, - {0xfffd, 0xfffd, 1}, + {0xfd40, 0xfd4f, 1}, + {0xfdcf, 0xfdfd, 46}, + {0xfdfe, 0xfdff, 1}, + {0xffe4, 0xffe8, 4}, + {0xffed, 0xffee, 1}, + {0xfffc, 0xfffd, 1}, }, R32: []Range32{ {0x10137, 0x1013f, 1}, @@ -3506,13 +3653,14 @@ var _So = &RangeTable{ {0x11fe1, 0x11ff1, 1}, {0x16b3c, 0x16b3f, 1}, {0x16b45, 0x1bc9c, 20823}, + {0x1cf50, 0x1cfc3, 1}, {0x1d000, 0x1d0f5, 1}, {0x1d100, 0x1d126, 1}, {0x1d129, 0x1d164, 1}, {0x1d16a, 0x1d16c, 1}, {0x1d183, 0x1d184, 1}, {0x1d18c, 0x1d1a9, 1}, - {0x1d1ae, 0x1d1e8, 1}, + {0x1d1ae, 0x1d1ea, 1}, {0x1d200, 0x1d241, 1}, {0x1d245, 0x1d300, 187}, {0x1d301, 0x1d356, 1}, @@ -3537,28 +3685,27 @@ var _So = &RangeTable{ {0x1f260, 0x1f265, 1}, {0x1f300, 0x1f3fa, 1}, {0x1f400, 0x1f6d7, 1}, - {0x1f6e0, 0x1f6ec, 1}, + {0x1f6dc, 0x1f6ec, 1}, {0x1f6f0, 0x1f6fc, 1}, - {0x1f700, 0x1f773, 1}, - {0x1f780, 0x1f7d8, 1}, + {0x1f700, 0x1f776, 1}, + {0x1f77b, 0x1f7d9, 1}, {0x1f7e0, 0x1f7eb, 1}, - {0x1f800, 0x1f80b, 1}, + {0x1f7f0, 0x1f800, 16}, + {0x1f801, 0x1f80b, 1}, {0x1f810, 0x1f847, 1}, {0x1f850, 0x1f859, 1}, {0x1f860, 0x1f887, 1}, {0x1f890, 0x1f8ad, 1}, {0x1f8b0, 0x1f8b1, 1}, - {0x1f900, 0x1f978, 1}, - {0x1f97a, 0x1f9cb, 1}, - {0x1f9cd, 0x1fa53, 1}, + {0x1f900, 0x1fa53, 1}, {0x1fa60, 0x1fa6d, 1}, - {0x1fa70, 0x1fa74, 1}, - {0x1fa78, 0x1fa7a, 1}, - {0x1fa80, 0x1fa86, 1}, - {0x1fa90, 0x1faa8, 1}, - {0x1fab0, 0x1fab6, 1}, - {0x1fac0, 0x1fac2, 1}, - {0x1fad0, 0x1fad6, 1}, + {0x1fa70, 0x1fa7c, 1}, + {0x1fa80, 0x1fa88, 1}, + {0x1fa90, 0x1fabd, 1}, + {0x1fabf, 0x1fac5, 1}, + {0x1face, 0x1fadb, 1}, + {0x1fae0, 0x1fae8, 1}, + {0x1faf0, 0x1faf8, 1}, {0x1fb00, 0x1fb92, 1}, {0x1fb94, 0x1fbca, 1}, }, @@ -3681,6 +3828,7 @@ var Scripts = map[string]*RangeTable{ "Coptic": Coptic, "Cuneiform": Cuneiform, "Cypriot": Cypriot, + "Cypro_Minoan": Cypro_Minoan, "Cyrillic": Cyrillic, "Deseret": Deseret, "Devanagari": Devanagari, @@ -3714,6 +3862,7 @@ var Scripts = map[string]*RangeTable{ "Kaithi": Kaithi, "Kannada": Kannada, "Katakana": Katakana, + "Kawi": Kawi, "Kayah_Li": Kayah_Li, "Kharoshthi": Kharoshthi, "Khitan_Small_Script": Khitan_Small_Script, @@ -3748,6 +3897,7 @@ var Scripts = map[string]*RangeTable{ "Multani": Multani, "Myanmar": Myanmar, "Nabataean": Nabataean, + "Nag_Mundari": Nag_Mundari, "Nandinagari": Nandinagari, "New_Tai_Lue": New_Tai_Lue, "Newa": Newa, @@ -3764,6 +3914,7 @@ var Scripts = map[string]*RangeTable{ "Old_Sogdian": Old_Sogdian, "Old_South_Arabian": Old_South_Arabian, "Old_Turkic": Old_Turkic, + "Old_Uyghur": Old_Uyghur, "Oriya": Oriya, "Osage": Osage, "Osmanya": Osmanya, @@ -3795,6 +3946,7 @@ var Scripts = map[string]*RangeTable{ "Tai_Viet": Tai_Viet, "Takri": Takri, "Tamil": Tamil, + "Tangsa": Tangsa, "Tangut": Tangut, "Telugu": Telugu, "Thaana": Thaana, @@ -3802,8 +3954,10 @@ var Scripts = map[string]*RangeTable{ "Tibetan": Tibetan, "Tifinagh": Tifinagh, "Tirhuta": Tirhuta, + "Toto": Toto, "Ugaritic": Ugaritic, "Vai": Vai, + "Vithkuqi": Vithkuqi, "Wancho": Wancho, "Warang_Citi": Warang_Citi, "Yezidi": Yezidi, @@ -3825,7 +3979,7 @@ var _Ahom = &RangeTable{ R32: []Range32{ {0x11700, 0x1171a, 1}, {0x1171d, 0x1172b, 1}, - {0x11730, 0x1173f, 1}, + {0x11730, 0x11746, 1}, }, } @@ -3841,27 +3995,29 @@ var _Arabic = &RangeTable{ {0x0600, 0x0604, 1}, {0x0606, 0x060b, 1}, {0x060d, 0x061a, 1}, - {0x061c, 0x0620, 2}, - {0x0621, 0x063f, 1}, + {0x061c, 0x061e, 1}, + {0x0620, 0x063f, 1}, {0x0641, 0x064a, 1}, {0x0656, 0x066f, 1}, {0x0671, 0x06dc, 1}, {0x06de, 0x06ff, 1}, {0x0750, 0x077f, 1}, - {0x08a0, 0x08b4, 1}, - {0x08b6, 0x08c7, 1}, - {0x08d3, 0x08e1, 1}, + {0x0870, 0x088e, 1}, + {0x0890, 0x0891, 1}, + {0x0898, 0x08e1, 1}, {0x08e3, 0x08ff, 1}, - {0xfb50, 0xfbc1, 1}, + {0xfb50, 0xfbc2, 1}, {0xfbd3, 0xfd3d, 1}, - {0xfd50, 0xfd8f, 1}, + {0xfd40, 0xfd8f, 1}, {0xfd92, 0xfdc7, 1}, - {0xfdf0, 0xfdfd, 1}, + {0xfdcf, 0xfdf0, 33}, + {0xfdf1, 0xfdff, 1}, {0xfe70, 0xfe74, 1}, {0xfe76, 0xfefc, 1}, }, R32: []Range32{ {0x10e60, 0x10e7e, 1}, + {0x10efd, 0x10eff, 1}, {0x1ee00, 0x1ee03, 1}, {0x1ee05, 0x1ee1f, 1}, {0x1ee21, 0x1ee22, 1}, @@ -3909,8 +4065,8 @@ var _Avestan = &RangeTable{ var _Balinese = &RangeTable{ R16: []Range16{ - {0x1b00, 0x1b4b, 1}, - {0x1b50, 0x1b7c, 1}, + {0x1b00, 0x1b4c, 1}, + {0x1b50, 0x1b7e, 1}, }, } @@ -3979,7 +4135,7 @@ var _Brahmi = &RangeTable{ R16: []Range16{}, R32: []Range32{ {0x11000, 0x1104d, 1}, - {0x11052, 0x1106f, 1}, + {0x11052, 0x11075, 1}, {0x1107f, 0x1107f, 1}, }, } @@ -4008,6 +4164,9 @@ var _Canadian_Aboriginal = &RangeTable{ {0x1400, 0x167f, 1}, {0x18b0, 0x18f5, 1}, }, + R32: []Range32{ + {0x11ab0, 0x11abf, 1}, + }, } var _Carian = &RangeTable{ @@ -4091,7 +4250,7 @@ var _Common = &RangeTable{ {0x2066, 0x2070, 1}, {0x2074, 0x207e, 1}, {0x2080, 0x208e, 1}, - {0x20a0, 0x20bf, 1}, + {0x20a0, 0x20c0, 1}, {0x2100, 0x2125, 1}, {0x2127, 0x2129, 1}, {0x212c, 0x2131, 1}, @@ -4104,7 +4263,7 @@ var _Common = &RangeTable{ {0x2900, 0x2b73, 1}, {0x2b76, 0x2b95, 1}, {0x2b97, 0x2bff, 1}, - {0x2e00, 0x2e52, 1}, + {0x2e00, 0x2e5d, 1}, {0x2ff0, 0x2ffb, 1}, {0x3000, 0x3004, 1}, {0x3006, 0x3008, 2}, @@ -4149,15 +4308,16 @@ var _Common = &RangeTable{ {0x10190, 0x1019c, 1}, {0x101d0, 0x101fc, 1}, {0x102e1, 0x102fb, 1}, - {0x16fe2, 0x16fe3, 1}, {0x1bca0, 0x1bca3, 1}, + {0x1cf50, 0x1cfc3, 1}, {0x1d000, 0x1d0f5, 1}, {0x1d100, 0x1d126, 1}, {0x1d129, 0x1d166, 1}, {0x1d16a, 0x1d17a, 1}, {0x1d183, 0x1d184, 1}, {0x1d18c, 0x1d1a9, 1}, - {0x1d1ae, 0x1d1e8, 1}, + {0x1d1ae, 0x1d1ea, 1}, + {0x1d2c0, 0x1d2d3, 1}, {0x1d2e0, 0x1d2f3, 1}, {0x1d300, 0x1d356, 1}, {0x1d360, 0x1d378, 1}, @@ -4198,28 +4358,27 @@ var _Common = &RangeTable{ {0x1f250, 0x1f251, 1}, {0x1f260, 0x1f265, 1}, {0x1f300, 0x1f6d7, 1}, - {0x1f6e0, 0x1f6ec, 1}, + {0x1f6dc, 0x1f6ec, 1}, {0x1f6f0, 0x1f6fc, 1}, - {0x1f700, 0x1f773, 1}, - {0x1f780, 0x1f7d8, 1}, + {0x1f700, 0x1f776, 1}, + {0x1f77b, 0x1f7d9, 1}, {0x1f7e0, 0x1f7eb, 1}, - {0x1f800, 0x1f80b, 1}, + {0x1f7f0, 0x1f800, 16}, + {0x1f801, 0x1f80b, 1}, {0x1f810, 0x1f847, 1}, {0x1f850, 0x1f859, 1}, {0x1f860, 0x1f887, 1}, {0x1f890, 0x1f8ad, 1}, {0x1f8b0, 0x1f8b1, 1}, - {0x1f900, 0x1f978, 1}, - {0x1f97a, 0x1f9cb, 1}, - {0x1f9cd, 0x1fa53, 1}, + {0x1f900, 0x1fa53, 1}, {0x1fa60, 0x1fa6d, 1}, - {0x1fa70, 0x1fa74, 1}, - {0x1fa78, 0x1fa7a, 1}, - {0x1fa80, 0x1fa86, 1}, - {0x1fa90, 0x1faa8, 1}, - {0x1fab0, 0x1fab6, 1}, - {0x1fac0, 0x1fac2, 1}, - {0x1fad0, 0x1fad6, 1}, + {0x1fa70, 0x1fa7c, 1}, + {0x1fa80, 0x1fa88, 1}, + {0x1fa90, 0x1fabd, 1}, + {0x1fabf, 0x1fac5, 1}, + {0x1face, 0x1fadb, 1}, + {0x1fae0, 0x1fae8, 1}, + {0x1faf0, 0x1faf8, 1}, {0x1fb00, 0x1fb92, 1}, {0x1fb94, 0x1fbca, 1}, {0x1fbf0, 0x1fbf9, 1}, @@ -4258,6 +4417,13 @@ var _Cypriot = &RangeTable{ }, } +var _Cypro_Minoan = &RangeTable{ + R16: []Range16{}, + R32: []Range32{ + {0x12f90, 0x12ff2, 1}, + }, +} + var _Cyrillic = &RangeTable{ R16: []Range16{ {0x0400, 0x0484, 1}, @@ -4268,6 +4434,10 @@ var _Cyrillic = &RangeTable{ {0xa640, 0xa69f, 1}, {0xfe2e, 0xfe2f, 1}, }, + R32: []Range32{ + {0x1e030, 0x1e06d, 1}, + {0x1e08f, 0x1e08f, 1}, + }, } var _Deseret = &RangeTable{ @@ -4284,6 +4454,9 @@ var _Devanagari = &RangeTable{ {0x0966, 0x097f, 1}, {0xa8e0, 0xa8ff, 1}, }, + R32: []Range32{ + {0x11b00, 0x11b09, 1}, + }, } var _Dives_Akuru = &RangeTable{ @@ -4321,8 +4494,7 @@ var _Duployan = &RangeTable{ var _Egyptian_Hieroglyphs = &RangeTable{ R16: []Range16{}, R32: []Range32{ - {0x13000, 0x1342e, 1}, - {0x13430, 0x13438, 1}, + {0x13000, 0x13455, 1}, }, } @@ -4375,6 +4547,12 @@ var _Ethiopic = &RangeTable{ {0xab20, 0xab26, 1}, {0xab28, 0xab2e, 1}, }, + R32: []Range32{ + {0x1e7e0, 0x1e7e6, 1}, + {0x1e7e8, 0x1e7eb, 1}, + {0x1e7ed, 0x1e7ee, 1}, + {0x1e7f0, 0x1e7fe, 1}, + }, } var _Georgian = &RangeTable{ @@ -4392,8 +4570,7 @@ var _Georgian = &RangeTable{ var _Glagolitic = &RangeTable{ R16: []Range16{ - {0x2c00, 0x2c2e, 1}, - {0x2c30, 0x2c5e, 1}, + {0x2c00, 0x2c5f, 1}, }, R32: []Range32{ {0x1e000, 0x1e006, 1}, @@ -4531,19 +4708,21 @@ var _Han = &RangeTable{ {0x3021, 0x3029, 1}, {0x3038, 0x303b, 1}, {0x3400, 0x4dbf, 1}, - {0x4e00, 0x9ffc, 1}, + {0x4e00, 0x9fff, 1}, {0xf900, 0xfa6d, 1}, {0xfa70, 0xfad9, 1}, }, R32: []Range32{ + {0x16fe2, 0x16fe3, 1}, {0x16ff0, 0x16ff1, 1}, - {0x20000, 0x2a6dd, 1}, - {0x2a700, 0x2b734, 1}, + {0x20000, 0x2a6df, 1}, + {0x2a700, 0x2b739, 1}, {0x2b740, 0x2b81d, 1}, {0x2b820, 0x2cea1, 1}, {0x2ceb0, 0x2ebe0, 1}, {0x2f800, 0x2fa1d, 1}, {0x30000, 0x3134a, 1}, + {0x31350, 0x323af, 1}, }, } @@ -4609,8 +4788,9 @@ var _Hiragana = &RangeTable{ {0x309d, 0x309f, 1}, }, R32: []Range32{ - {0x1b001, 0x1b11e, 1}, - {0x1b150, 0x1b152, 1}, + {0x1b001, 0x1b11f, 1}, + {0x1b132, 0x1b150, 30}, + {0x1b151, 0x1b152, 1}, {0x1f200, 0x1f200, 1}, }, } @@ -4630,14 +4810,13 @@ var _Inherited = &RangeTable{ {0x064b, 0x0655, 1}, {0x0670, 0x0951, 737}, {0x0952, 0x0954, 1}, - {0x1ab0, 0x1ac0, 1}, + {0x1ab0, 0x1ace, 1}, {0x1cd0, 0x1cd2, 1}, {0x1cd4, 0x1ce0, 1}, {0x1ce2, 0x1ce8, 1}, {0x1ced, 0x1cf4, 7}, {0x1cf8, 0x1cf9, 1}, - {0x1dc0, 0x1df9, 1}, - {0x1dfb, 0x1dff, 1}, + {0x1dc0, 0x1dff, 1}, {0x200c, 0x200d, 1}, {0x20d0, 0x20f0, 1}, {0x302a, 0x302d, 1}, @@ -4647,8 +4826,10 @@ var _Inherited = &RangeTable{ }, R32: []Range32{ {0x101fd, 0x102e0, 227}, - {0x1133b, 0x1d167, 48684}, - {0x1d168, 0x1d169, 1}, + {0x1133b, 0x1cf00, 48069}, + {0x1cf01, 0x1cf2d, 1}, + {0x1cf30, 0x1cf46, 1}, + {0x1d167, 0x1d169, 1}, {0x1d17b, 0x1d182, 1}, {0x1d185, 0x1d18b, 1}, {0x1d1aa, 0x1d1ad, 1}, @@ -4683,7 +4864,7 @@ var _Javanese = &RangeTable{ var _Kaithi = &RangeTable{ R16: []Range16{}, R32: []Range32{ - {0x11080, 0x110c1, 1}, + {0x11080, 0x110c2, 1}, {0x110cd, 0x110cd, 1}, }, } @@ -4699,10 +4880,10 @@ var _Kannada = &RangeTable{ {0x0cc6, 0x0cc8, 1}, {0x0cca, 0x0ccd, 1}, {0x0cd5, 0x0cd6, 1}, - {0x0cde, 0x0ce0, 2}, - {0x0ce1, 0x0ce3, 1}, + {0x0cdd, 0x0cde, 1}, + {0x0ce0, 0x0ce3, 1}, {0x0ce6, 0x0cef, 1}, - {0x0cf1, 0x0cf2, 1}, + {0x0cf1, 0x0cf3, 1}, }, } @@ -4717,11 +4898,25 @@ var _Katakana = &RangeTable{ {0xff71, 0xff9d, 1}, }, R32: []Range32{ - {0x1b000, 0x1b164, 356}, + {0x1aff0, 0x1aff3, 1}, + {0x1aff5, 0x1affb, 1}, + {0x1affd, 0x1affe, 1}, + {0x1b000, 0x1b120, 288}, + {0x1b121, 0x1b122, 1}, + {0x1b155, 0x1b164, 15}, {0x1b165, 0x1b167, 1}, }, } +var _Kawi = &RangeTable{ + R16: []Range16{}, + R32: []Range32{ + {0x11f00, 0x11f10, 1}, + {0x11f12, 0x11f3a, 1}, + {0x11f3e, 0x11f59, 1}, + }, +} + var _Kayah_Li = &RangeTable{ R16: []Range16{ {0xa900, 0xa92d, 1}, @@ -4764,7 +4959,7 @@ var _Khojki = &RangeTable{ R16: []Range16{}, R32: []Range32{ {0x11200, 0x11211, 1}, - {0x11213, 0x1123e, 1}, + {0x11213, 0x11241, 1}, }, } @@ -4786,7 +4981,7 @@ var _Lao = &RangeTable{ {0x0ea8, 0x0ebd, 1}, {0x0ec0, 0x0ec4, 1}, {0x0ec6, 0x0ec8, 2}, - {0x0ec9, 0x0ecd, 1}, + {0x0ec9, 0x0ece, 1}, {0x0ed0, 0x0ed9, 1}, {0x0edc, 0x0edf, 1}, }, @@ -4814,9 +5009,11 @@ var _Latin = &RangeTable{ {0x2160, 0x2188, 1}, {0x2c60, 0x2c7f, 1}, {0xa722, 0xa787, 1}, - {0xa78b, 0xa7bf, 1}, - {0xa7c2, 0xa7ca, 1}, - {0xa7f5, 0xa7ff, 1}, + {0xa78b, 0xa7ca, 1}, + {0xa7d0, 0xa7d1, 1}, + {0xa7d3, 0xa7d5, 2}, + {0xa7d6, 0xa7d9, 1}, + {0xa7f2, 0xa7ff, 1}, {0xab30, 0xab5a, 1}, {0xab5c, 0xab64, 1}, {0xab66, 0xab69, 1}, @@ -4824,6 +5021,13 @@ var _Latin = &RangeTable{ {0xff21, 0xff3a, 1}, {0xff41, 0xff5a, 1}, }, + R32: []Range32{ + {0x10780, 0x10785, 1}, + {0x10787, 0x107b0, 1}, + {0x107b2, 0x107ba, 1}, + {0x1df00, 0x1df1e, 1}, + {0x1df25, 0x1df2a, 1}, + }, LatinOffset: 5, } @@ -5014,8 +5218,7 @@ var _Mongolian = &RangeTable{ R16: []Range16{ {0x1800, 0x1801, 1}, {0x1804, 0x1806, 2}, - {0x1807, 0x180e, 1}, - {0x1810, 0x1819, 1}, + {0x1807, 0x1819, 1}, {0x1820, 0x1878, 1}, {0x1880, 0x18aa, 1}, }, @@ -5060,6 +5263,13 @@ var _Nabataean = &RangeTable{ }, } +var _Nag_Mundari = &RangeTable{ + R16: []Range16{}, + R32: []Range32{ + {0x1e4d0, 0x1e4f9, 1}, + }, +} + var _Nandinagari = &RangeTable{ R16: []Range16{}, R32: []Range32{ @@ -5183,6 +5393,13 @@ var _Old_Turkic = &RangeTable{ }, } +var _Old_Uyghur = &RangeTable{ + R16: []Range16{}, + R32: []Range32{ + {0x10f70, 0x10f89, 1}, + }, +} + var _Oriya = &RangeTable{ R16: []Range16{ {0x0b01, 0x0b03, 1}, @@ -5391,8 +5608,8 @@ var _Syriac = &RangeTable{ var _Tagalog = &RangeTable{ R16: []Range16{ - {0x1700, 0x170c, 1}, - {0x170e, 0x1714, 1}, + {0x1700, 0x1715, 1}, + {0x171f, 0x171f, 1}, }, } @@ -5431,7 +5648,7 @@ var _Tai_Viet = &RangeTable{ var _Takri = &RangeTable{ R16: []Range16{}, R32: []Range32{ - {0x11680, 0x116b8, 1}, + {0x11680, 0x116b9, 1}, {0x116c0, 0x116c9, 1}, }, } @@ -5460,6 +5677,14 @@ var _Tamil = &RangeTable{ }, } +var _Tangsa = &RangeTable{ + R16: []Range16{}, + R32: []Range32{ + {0x16a70, 0x16abe, 1}, + {0x16ac0, 0x16ac9, 1}, + }, +} + var _Tangut = &RangeTable{ R16: []Range16{}, R32: []Range32{ @@ -5476,12 +5701,13 @@ var _Telugu = &RangeTable{ {0x0c0e, 0x0c10, 1}, {0x0c12, 0x0c28, 1}, {0x0c2a, 0x0c39, 1}, - {0x0c3d, 0x0c44, 1}, + {0x0c3c, 0x0c44, 1}, {0x0c46, 0x0c48, 1}, {0x0c4a, 0x0c4d, 1}, {0x0c55, 0x0c56, 1}, {0x0c58, 0x0c5a, 1}, - {0x0c60, 0x0c63, 1}, + {0x0c5d, 0x0c60, 3}, + {0x0c61, 0x0c63, 1}, {0x0c66, 0x0c6f, 1}, {0x0c77, 0x0c7f, 1}, }, @@ -5528,6 +5754,13 @@ var _Tirhuta = &RangeTable{ }, } +var _Toto = &RangeTable{ + R16: []Range16{}, + R32: []Range32{ + {0x1e290, 0x1e2ae, 1}, + }, +} + var _Ugaritic = &RangeTable{ R16: []Range16{}, R32: []Range32{ @@ -5542,6 +5775,20 @@ var _Vai = &RangeTable{ }, } +var _Vithkuqi = &RangeTable{ + R16: []Range16{}, + R32: []Range32{ + {0x10570, 0x1057a, 1}, + {0x1057c, 0x1058a, 1}, + {0x1058c, 0x10592, 1}, + {0x10594, 0x10595, 1}, + {0x10597, 0x105a1, 1}, + {0x105a3, 0x105b1, 1}, + {0x105b3, 0x105b9, 1}, + {0x105bb, 0x105bc, 1}, + }, +} + var _Wancho = &RangeTable{ R16: []Range16{}, R32: []Range32{ @@ -5611,6 +5858,7 @@ var ( Coptic = _Coptic // Coptic is the set of Unicode characters in script Coptic. Cuneiform = _Cuneiform // Cuneiform is the set of Unicode characters in script Cuneiform. Cypriot = _Cypriot // Cypriot is the set of Unicode characters in script Cypriot. + Cypro_Minoan = _Cypro_Minoan // Cypro_Minoan is the set of Unicode characters in script Cypro_Minoan. Cyrillic = _Cyrillic // Cyrillic is the set of Unicode characters in script Cyrillic. Deseret = _Deseret // Deseret is the set of Unicode characters in script Deseret. Devanagari = _Devanagari // Devanagari is the set of Unicode characters in script Devanagari. @@ -5644,6 +5892,7 @@ var ( Kaithi = _Kaithi // Kaithi is the set of Unicode characters in script Kaithi. Kannada = _Kannada // Kannada is the set of Unicode characters in script Kannada. Katakana = _Katakana // Katakana is the set of Unicode characters in script Katakana. + Kawi = _Kawi // Kawi is the set of Unicode characters in script Kawi. Kayah_Li = _Kayah_Li // Kayah_Li is the set of Unicode characters in script Kayah_Li. Kharoshthi = _Kharoshthi // Kharoshthi is the set of Unicode characters in script Kharoshthi. Khitan_Small_Script = _Khitan_Small_Script // Khitan_Small_Script is the set of Unicode characters in script Khitan_Small_Script. @@ -5678,6 +5927,7 @@ var ( Multani = _Multani // Multani is the set of Unicode characters in script Multani. Myanmar = _Myanmar // Myanmar is the set of Unicode characters in script Myanmar. Nabataean = _Nabataean // Nabataean is the set of Unicode characters in script Nabataean. + Nag_Mundari = _Nag_Mundari // Nag_Mundari is the set of Unicode characters in script Nag_Mundari. Nandinagari = _Nandinagari // Nandinagari is the set of Unicode characters in script Nandinagari. New_Tai_Lue = _New_Tai_Lue // New_Tai_Lue is the set of Unicode characters in script New_Tai_Lue. Newa = _Newa // Newa is the set of Unicode characters in script Newa. @@ -5694,6 +5944,7 @@ var ( Old_Sogdian = _Old_Sogdian // Old_Sogdian is the set of Unicode characters in script Old_Sogdian. Old_South_Arabian = _Old_South_Arabian // Old_South_Arabian is the set of Unicode characters in script Old_South_Arabian. Old_Turkic = _Old_Turkic // Old_Turkic is the set of Unicode characters in script Old_Turkic. + Old_Uyghur = _Old_Uyghur // Old_Uyghur is the set of Unicode characters in script Old_Uyghur. Oriya = _Oriya // Oriya is the set of Unicode characters in script Oriya. Osage = _Osage // Osage is the set of Unicode characters in script Osage. Osmanya = _Osmanya // Osmanya is the set of Unicode characters in script Osmanya. @@ -5725,6 +5976,7 @@ var ( Tai_Viet = _Tai_Viet // Tai_Viet is the set of Unicode characters in script Tai_Viet. Takri = _Takri // Takri is the set of Unicode characters in script Takri. Tamil = _Tamil // Tamil is the set of Unicode characters in script Tamil. + Tangsa = _Tangsa // Tangsa is the set of Unicode characters in script Tangsa. Tangut = _Tangut // Tangut is the set of Unicode characters in script Tangut. Telugu = _Telugu // Telugu is the set of Unicode characters in script Telugu. Thaana = _Thaana // Thaana is the set of Unicode characters in script Thaana. @@ -5732,8 +5984,10 @@ var ( Tibetan = _Tibetan // Tibetan is the set of Unicode characters in script Tibetan. Tifinagh = _Tifinagh // Tifinagh is the set of Unicode characters in script Tifinagh. Tirhuta = _Tirhuta // Tirhuta is the set of Unicode characters in script Tirhuta. + Toto = _Toto // Toto is the set of Unicode characters in script Toto. Ugaritic = _Ugaritic // Ugaritic is the set of Unicode characters in script Ugaritic. Vai = _Vai // Vai is the set of Unicode characters in script Vai. + Vithkuqi = _Vithkuqi // Vithkuqi is the set of Unicode characters in script Vithkuqi. Wancho = _Wancho // Wancho is the set of Unicode characters in script Wancho. Warang_Citi = _Warang_Citi // Warang_Citi is the set of Unicode characters in script Warang_Citi. Yezidi = _Yezidi // Yezidi is the set of Unicode characters in script Yezidi. @@ -5808,11 +6062,11 @@ var _Dash = &RangeTable{ {0x208b, 0x2212, 391}, {0x2e17, 0x2e1a, 3}, {0x2e3a, 0x2e3b, 1}, - {0x2e40, 0x301c, 476}, - {0x3030, 0x30a0, 112}, - {0xfe31, 0xfe32, 1}, - {0xfe58, 0xfe63, 11}, - {0xff0d, 0xff0d, 1}, + {0x2e40, 0x2e5d, 29}, + {0x301c, 0x3030, 20}, + {0x30a0, 0xfe31, 52625}, + {0xfe32, 0xfe58, 38}, + {0xfe63, 0xff0d, 170}, }, R32: []Range32{ {0x10ead, 0x10ead, 1}, @@ -5859,6 +6113,8 @@ var _Diacritic = &RangeTable{ {0x07a6, 0x07b0, 1}, {0x07eb, 0x07f5, 1}, {0x0818, 0x0819, 1}, + {0x0898, 0x089f, 1}, + {0x08c9, 0x08d2, 1}, {0x08e3, 0x08fe, 1}, {0x093c, 0x094d, 17}, {0x0951, 0x0954, 1}, @@ -5869,10 +6125,10 @@ var _Diacritic = &RangeTable{ {0x0afe, 0x0aff, 1}, {0x0b3c, 0x0b4d, 17}, {0x0b55, 0x0bcd, 120}, - {0x0c4d, 0x0cbc, 111}, - {0x0ccd, 0x0d3b, 110}, - {0x0d3c, 0x0d4d, 17}, - {0x0dca, 0x0e47, 125}, + {0x0c3c, 0x0c4d, 17}, + {0x0cbc, 0x0ccd, 17}, + {0x0d3b, 0x0d3c, 1}, + {0x0d4d, 0x0e47, 125}, {0x0e48, 0x0e4c, 1}, {0x0e4e, 0x0eba, 108}, {0x0ec8, 0x0ecc, 1}, @@ -5889,12 +6145,14 @@ var _Diacritic = &RangeTable{ {0x108f, 0x109a, 11}, {0x109b, 0x135d, 706}, {0x135e, 0x135f, 1}, + {0x1714, 0x1715, 1}, {0x17c9, 0x17d3, 1}, {0x17dd, 0x1939, 348}, {0x193a, 0x193b, 1}, {0x1a75, 0x1a7c, 1}, {0x1a7f, 0x1ab0, 49}, - {0x1ab1, 0x1abd, 1}, + {0x1ab1, 0x1abe, 1}, + {0x1ac1, 0x1acb, 1}, {0x1b34, 0x1b44, 16}, {0x1b6b, 0x1b73, 1}, {0x1baa, 0x1bab, 1}, @@ -5905,8 +6163,7 @@ var _Diacritic = &RangeTable{ {0x1cf7, 0x1cf9, 1}, {0x1d2c, 0x1d6a, 1}, {0x1dc4, 0x1dcf, 1}, - {0x1df5, 0x1df9, 1}, - {0x1dfd, 0x1dff, 1}, + {0x1df5, 0x1dff, 1}, {0x1fbd, 0x1fbf, 2}, {0x1fc0, 0x1fc1, 1}, {0x1fcd, 0x1fcf, 1}, @@ -5943,10 +6200,16 @@ var _Diacritic = &RangeTable{ {0xff9f, 0xffe3, 68}, }, R32: []Range32{ - {0x102e0, 0x10ae5, 2053}, - {0x10ae6, 0x10d22, 572}, - {0x10d23, 0x10d27, 1}, + {0x102e0, 0x10780, 1184}, + {0x10781, 0x10785, 1}, + {0x10787, 0x107b0, 1}, + {0x107b2, 0x107ba, 1}, + {0x10ae5, 0x10ae6, 1}, + {0x10d22, 0x10d27, 1}, + {0x10efd, 0x10eff, 1}, {0x10f46, 0x10f50, 1}, + {0x10f82, 0x10f85, 1}, + {0x11046, 0x11070, 42}, {0x110b9, 0x110ba, 1}, {0x11133, 0x11134, 1}, {0x11173, 0x111c0, 77}, @@ -5968,17 +6231,25 @@ var _Diacritic = &RangeTable{ {0x11a99, 0x11c3f, 422}, {0x11d42, 0x11d44, 2}, {0x11d45, 0x11d97, 82}, + {0x13447, 0x13455, 1}, {0x16af0, 0x16af4, 1}, {0x16b30, 0x16b36, 1}, {0x16f8f, 0x16f9f, 1}, {0x16ff0, 0x16ff1, 1}, + {0x1aff0, 0x1aff3, 1}, + {0x1aff5, 0x1affb, 1}, + {0x1affd, 0x1affe, 1}, + {0x1cf00, 0x1cf2d, 1}, + {0x1cf30, 0x1cf46, 1}, {0x1d167, 0x1d169, 1}, {0x1d16d, 0x1d172, 1}, {0x1d17b, 0x1d182, 1}, {0x1d185, 0x1d18b, 1}, {0x1d1aa, 0x1d1ad, 1}, + {0x1e030, 0x1e06d, 1}, {0x1e130, 0x1e136, 1}, - {0x1e2ec, 0x1e2ef, 1}, + {0x1e2ae, 0x1e2ec, 62}, + {0x1e2ed, 0x1e2ef, 1}, {0x1e8d0, 0x1e8d6, 1}, {0x1e944, 0x1e946, 1}, {0x1e948, 0x1e94a, 1}, @@ -6005,6 +6276,7 @@ var _Extender = &RangeTable{ {0xff70, 0xff70, 1}, }, R32: []Range32{ + {0x10781, 0x10782, 1}, {0x1135d, 0x115c6, 617}, {0x115c7, 0x115c8, 1}, {0x11a98, 0x16b42, 20650}, @@ -6058,7 +6330,7 @@ var _Ideographic = &RangeTable{ {0x3021, 0x3029, 1}, {0x3038, 0x303a, 1}, {0x3400, 0x4dbf, 1}, - {0x4e00, 0x9ffc, 1}, + {0x4e00, 0x9fff, 1}, {0xf900, 0xfa6d, 1}, {0xfa70, 0xfad9, 1}, }, @@ -6068,13 +6340,14 @@ var _Ideographic = &RangeTable{ {0x18800, 0x18cd5, 1}, {0x18d00, 0x18d08, 1}, {0x1b170, 0x1b2fb, 1}, - {0x20000, 0x2a6dd, 1}, - {0x2a700, 0x2b734, 1}, + {0x20000, 0x2a6df, 1}, + {0x2a700, 0x2b739, 1}, {0x2b740, 0x2b81d, 1}, {0x2b820, 0x2cea1, 1}, {0x2ceb0, 0x2ebe0, 1}, {0x2f800, 0x2fa1d, 1}, {0x30000, 0x3134a, 1}, + {0x31350, 0x323af, 1}, }, } @@ -6178,7 +6451,7 @@ var _Other_Alphabetic = &RangeTable{ {0x0bc6, 0x0bc8, 1}, {0x0bca, 0x0bcc, 1}, {0x0bd7, 0x0c00, 41}, - {0x0c01, 0x0c03, 1}, + {0x0c01, 0x0c04, 1}, {0x0c3e, 0x0c44, 1}, {0x0c46, 0x0c48, 1}, {0x0c4a, 0x0c4c, 1}, @@ -6190,7 +6463,8 @@ var _Other_Alphabetic = &RangeTable{ {0x0cca, 0x0ccc, 1}, {0x0cd5, 0x0cd6, 1}, {0x0ce2, 0x0ce3, 1}, - {0x0d00, 0x0d03, 1}, + {0x0cf3, 0x0d00, 13}, + {0x0d01, 0x0d03, 1}, {0x0d3e, 0x0d44, 1}, {0x0d46, 0x0d48, 1}, {0x0d4a, 0x0d4c, 1}, @@ -6207,7 +6481,7 @@ var _Other_Alphabetic = &RangeTable{ {0x0eb4, 0x0eb9, 1}, {0x0ebb, 0x0ebc, 1}, {0x0ecd, 0x0f71, 164}, - {0x0f72, 0x0f81, 1}, + {0x0f72, 0x0f83, 1}, {0x0f8d, 0x0f97, 1}, {0x0f99, 0x0fbc, 1}, {0x102b, 0x1036, 1}, @@ -6234,6 +6508,7 @@ var _Other_Alphabetic = &RangeTable{ {0x1a55, 0x1a5e, 1}, {0x1a61, 0x1a74, 1}, {0x1abf, 0x1ac0, 1}, + {0x1acc, 0x1ace, 1}, {0x1b00, 0x1b04, 1}, {0x1b35, 0x1b43, 1}, {0x1b80, 0x1b82, 1}, @@ -6278,9 +6553,11 @@ var _Other_Alphabetic = &RangeTable{ {0x10eab, 0x10eac, 1}, {0x11000, 0x11002, 1}, {0x11038, 0x11045, 1}, - {0x11082, 0x110b0, 46}, - {0x110b1, 0x110b8, 1}, - {0x11100, 0x11102, 1}, + {0x11073, 0x11074, 1}, + {0x11080, 0x11082, 1}, + {0x110b0, 0x110b8, 1}, + {0x110c2, 0x11100, 62}, + {0x11101, 0x11102, 1}, {0x11127, 0x11132, 1}, {0x11145, 0x11146, 1}, {0x11180, 0x11182, 1}, @@ -6288,7 +6565,8 @@ var _Other_Alphabetic = &RangeTable{ {0x111ce, 0x111cf, 1}, {0x1122c, 0x11234, 1}, {0x11237, 0x1123e, 7}, - {0x112df, 0x112e8, 1}, + {0x11241, 0x112df, 158}, + {0x112e0, 0x112e8, 1}, {0x11300, 0x11303, 1}, {0x1133e, 0x11344, 1}, {0x11347, 0x11348, 1}, @@ -6331,6 +6609,10 @@ var _Other_Alphabetic = &RangeTable{ {0x11d90, 0x11d91, 1}, {0x11d93, 0x11d96, 1}, {0x11ef3, 0x11ef6, 1}, + {0x11f00, 0x11f01, 1}, + {0x11f03, 0x11f34, 49}, + {0x11f35, 0x11f3a, 1}, + {0x11f3e, 0x11f40, 1}, {0x16f4f, 0x16f51, 2}, {0x16f52, 0x16f87, 1}, {0x16f8f, 0x16f92, 1}, @@ -6341,8 +6623,8 @@ var _Other_Alphabetic = &RangeTable{ {0x1e01b, 0x1e021, 1}, {0x1e023, 0x1e024, 1}, {0x1e026, 0x1e02a, 1}, - {0x1e947, 0x1f130, 2025}, - {0x1f131, 0x1f149, 1}, + {0x1e08f, 0x1e947, 2232}, + {0x1f130, 0x1f149, 1}, {0x1f150, 0x1f169, 1}, {0x1f170, 0x1f189, 1}, }, @@ -6410,7 +6692,8 @@ var _Other_Lowercase = &RangeTable{ {0x02c0, 0x02c1, 1}, {0x02e0, 0x02e4, 1}, {0x0345, 0x037a, 53}, - {0x1d2c, 0x1d6a, 1}, + {0x10fc, 0x1d2c, 3120}, + {0x1d2d, 0x1d6a, 1}, {0x1d78, 0x1d9b, 35}, {0x1d9c, 0x1dbf, 1}, {0x2071, 0x207f, 14}, @@ -6419,9 +6702,18 @@ var _Other_Lowercase = &RangeTable{ {0x24d0, 0x24e9, 1}, {0x2c7c, 0x2c7d, 1}, {0xa69c, 0xa69d, 1}, - {0xa770, 0xa7f8, 136}, - {0xa7f9, 0xab5c, 867}, - {0xab5d, 0xab5f, 1}, + {0xa770, 0xa7f2, 130}, + {0xa7f3, 0xa7f4, 1}, + {0xa7f8, 0xa7f9, 1}, + {0xab5c, 0xab5f, 1}, + {0xab69, 0xab69, 1}, + }, + R32: []Range32{ + {0x10780, 0x10783, 3}, + {0x10784, 0x10785, 1}, + {0x10787, 0x107b0, 1}, + {0x107b2, 0x107ba, 1}, + {0x1e030, 0x1e06d, 1}, }, LatinOffset: 1, } @@ -6607,6 +6899,7 @@ var _Prepended_Concatenation_Mark = &RangeTable{ R16: []Range16{ {0x0600, 0x0605, 1}, {0x06dd, 0x070f, 50}, + {0x0890, 0x0891, 1}, {0x08e2, 0x08e2, 1}, }, R32: []Range32{ @@ -6649,7 +6942,7 @@ var _Sentence_Terminal = &RangeTable{ R16: []Range16{ {0x0021, 0x002e, 13}, {0x003f, 0x0589, 1354}, - {0x061e, 0x061f, 1}, + {0x061d, 0x061f, 1}, {0x06d4, 0x0700, 44}, {0x0701, 0x0702, 1}, {0x07f9, 0x0837, 62}, @@ -6665,11 +6958,13 @@ var _Sentence_Terminal = &RangeTable{ {0x1aa9, 0x1aab, 1}, {0x1b5a, 0x1b5b, 1}, {0x1b5e, 0x1b5f, 1}, + {0x1b7d, 0x1b7e, 1}, {0x1c3b, 0x1c3c, 1}, {0x1c7e, 0x1c7f, 1}, {0x203c, 0x203d, 1}, {0x2047, 0x2049, 1}, {0x2e2e, 0x2e3c, 14}, + {0x2e53, 0x2e54, 1}, {0x3002, 0xa4ff, 29949}, {0xa60e, 0xa60f, 1}, {0xa6f3, 0xa6f7, 4}, @@ -6687,6 +6982,7 @@ var _Sentence_Terminal = &RangeTable{ R32: []Range32{ {0x10a56, 0x10a57, 1}, {0x10f55, 0x10f59, 1}, + {0x10f86, 0x10f89, 1}, {0x11047, 0x11048, 1}, {0x110be, 0x110c1, 1}, {0x11141, 0x11143, 1}, @@ -6705,6 +7001,7 @@ var _Sentence_Terminal = &RangeTable{ {0x11a9b, 0x11a9c, 1}, {0x11c41, 0x11c42, 1}, {0x11ef7, 0x11ef8, 1}, + {0x11f43, 0x11f44, 1}, {0x16a6e, 0x16a6f, 1}, {0x16af5, 0x16b37, 66}, {0x16b38, 0x16b44, 12}, @@ -6741,6 +7038,8 @@ var _Soft_Dotted = &RangeTable{ {0x1d62a, 0x1d62b, 1}, {0x1d65e, 0x1d65f, 1}, {0x1d692, 0x1d693, 1}, + {0x1df1a, 0x1e04c, 306}, + {0x1e04d, 0x1e068, 27}, }, LatinOffset: 1, } @@ -6753,7 +7052,7 @@ var _Terminal_Punctuation = &RangeTable{ {0x037e, 0x0387, 9}, {0x0589, 0x05c3, 58}, {0x060c, 0x061b, 15}, - {0x061e, 0x061f, 1}, + {0x061d, 0x061f, 1}, {0x06d4, 0x0700, 44}, {0x0701, 0x070a, 1}, {0x070c, 0x07f8, 236}, @@ -6776,6 +7075,7 @@ var _Terminal_Punctuation = &RangeTable{ {0x1aa8, 0x1aab, 1}, {0x1b5a, 0x1b5b, 1}, {0x1b5d, 0x1b5f, 1}, + {0x1b7d, 0x1b7e, 1}, {0x1c3b, 0x1c3f, 1}, {0x1c7e, 0x1c7f, 1}, {0x203c, 0x203d, 1}, @@ -6783,6 +7083,7 @@ var _Terminal_Punctuation = &RangeTable{ {0x2e2e, 0x2e3c, 14}, {0x2e41, 0x2e4c, 11}, {0x2e4e, 0x2e4f, 1}, + {0x2e53, 0x2e54, 1}, {0x3001, 0x3002, 1}, {0xa4fe, 0xa4ff, 1}, {0xa60d, 0xa60f, 1}, @@ -6809,6 +7110,7 @@ var _Terminal_Punctuation = &RangeTable{ {0x10b3a, 0x10b3f, 1}, {0x10b99, 0x10b9c, 1}, {0x10f55, 0x10f59, 1}, + {0x10f86, 0x10f89, 1}, {0x11047, 0x1104d, 1}, {0x110be, 0x110c1, 1}, {0x11141, 0x11143, 1}, @@ -6829,7 +7131,8 @@ var _Terminal_Punctuation = &RangeTable{ {0x11aa1, 0x11aa2, 1}, {0x11c41, 0x11c43, 1}, {0x11c71, 0x11ef7, 646}, - {0x11ef8, 0x12470, 1400}, + {0x11ef8, 0x11f43, 75}, + {0x11f44, 0x12470, 1324}, {0x12471, 0x12474, 1}, {0x16a6e, 0x16a6f, 1}, {0x16af5, 0x16b37, 66}, @@ -6844,7 +7147,7 @@ var _Terminal_Punctuation = &RangeTable{ var _Unified_Ideograph = &RangeTable{ R16: []Range16{ {0x3400, 0x4dbf, 1}, - {0x4e00, 0x9ffc, 1}, + {0x4e00, 0x9fff, 1}, {0xfa0e, 0xfa0f, 1}, {0xfa11, 0xfa13, 2}, {0xfa14, 0xfa1f, 11}, @@ -6853,19 +7156,21 @@ var _Unified_Ideograph = &RangeTable{ {0xfa28, 0xfa29, 1}, }, R32: []Range32{ - {0x20000, 0x2a6dd, 1}, - {0x2a700, 0x2b734, 1}, + {0x20000, 0x2a6df, 1}, + {0x2a700, 0x2b739, 1}, {0x2b740, 0x2b81d, 1}, {0x2b820, 0x2cea1, 1}, {0x2ceb0, 0x2ebe0, 1}, {0x30000, 0x3134a, 1}, + {0x31350, 0x323af, 1}, }, } var _Variation_Selector = &RangeTable{ R16: []Range16{ {0x180b, 0x180d, 1}, - {0xfe00, 0xfe0f, 1}, + {0x180f, 0xfe00, 58865}, + {0xfe01, 0xfe0f, 1}, }, R32: []Range32{ {0xe0100, 0xe01ef, 1}, @@ -7182,8 +7487,8 @@ var _CaseRanges = []CaseRange{ {0x2183, 0x2184, d{UpperLower, UpperLower, UpperLower}}, {0x24B6, 0x24CF, d{0, 26, 0}}, {0x24D0, 0x24E9, d{-26, 0, -26}}, - {0x2C00, 0x2C2E, d{0, 48, 0}}, - {0x2C30, 0x2C5E, d{-48, 0, -48}}, + {0x2C00, 0x2C2F, d{0, 48, 0}}, + {0x2C30, 0x2C5F, d{-48, 0, -48}}, {0x2C60, 0x2C61, d{UpperLower, UpperLower, UpperLower}}, {0x2C62, 0x2C62, d{0, -10743, 0}}, {0x2C63, 0x2C63, d{0, -3814, 0}}, @@ -7225,12 +7530,13 @@ var _CaseRanges = []CaseRange{ {0xA7B1, 0xA7B1, d{0, -42282, 0}}, {0xA7B2, 0xA7B2, d{0, -42261, 0}}, {0xA7B3, 0xA7B3, d{0, 928, 0}}, - {0xA7B4, 0xA7BF, d{UpperLower, UpperLower, UpperLower}}, - {0xA7C2, 0xA7C3, d{UpperLower, UpperLower, UpperLower}}, + {0xA7B4, 0xA7C3, d{UpperLower, UpperLower, UpperLower}}, {0xA7C4, 0xA7C4, d{0, -48, 0}}, {0xA7C5, 0xA7C5, d{0, -42307, 0}}, {0xA7C6, 0xA7C6, d{0, -35384, 0}}, {0xA7C7, 0xA7CA, d{UpperLower, UpperLower, UpperLower}}, + {0xA7D0, 0xA7D1, d{UpperLower, UpperLower, UpperLower}}, + {0xA7D6, 0xA7D9, d{UpperLower, UpperLower, UpperLower}}, {0xA7F5, 0xA7F6, d{UpperLower, UpperLower, UpperLower}}, {0xAB53, 0xAB53, d{-928, 0, -928}}, {0xAB70, 0xABBF, d{-38864, 0, -38864}}, @@ -7240,6 +7546,14 @@ var _CaseRanges = []CaseRange{ {0x10428, 0x1044F, d{-40, 0, -40}}, {0x104B0, 0x104D3, d{0, 40, 0}}, {0x104D8, 0x104FB, d{-40, 0, -40}}, + {0x10570, 0x1057A, d{0, 39, 0}}, + {0x1057C, 0x1058A, d{0, 39, 0}}, + {0x1058C, 0x10592, d{0, 39, 0}}, + {0x10594, 0x10595, d{0, 39, 0}}, + {0x10597, 0x105A1, d{-39, 0, -39}}, + {0x105A3, 0x105B1, d{-39, 0, -39}}, + {0x105B3, 0x105B9, d{-39, 0, -39}}, + {0x105BB, 0x105BC, d{-39, 0, -39}}, {0x10C80, 0x10CB2, d{0, 64, 0}}, {0x10CC0, 0x10CF2, d{-64, 0, -64}}, {0x118A0, 0x118BF, d{0, 32, 0}}, @@ -7378,7 +7692,7 @@ var properties = [MaxLatin1 + 1]uint8{ 0x7C: pS | pp, // '|' 0x7D: pP | pp, // '}' 0x7E: pS | pp, // '~' - 0x7F: pC, // '\u007f' + 0x7F: pC, // '\x7f' 0x80: pC, // '\u0080' 0x81: pC, // '\u0081' 0x82: pC, // '\u0082' @@ -7833,7 +8147,7 @@ var foldLl = &RangeTable{ {0x2126, 0x212a, 4}, {0x212b, 0x2132, 7}, {0x2183, 0x2c00, 2685}, - {0x2c01, 0x2c2e, 1}, + {0x2c01, 0x2c2f, 1}, {0x2c60, 0x2c62, 2}, {0x2c63, 0x2c64, 1}, {0x2c67, 0x2c6d, 2}, @@ -7854,15 +8168,20 @@ var foldLl = &RangeTable{ {0xa796, 0xa7aa, 2}, {0xa7ab, 0xa7ae, 1}, {0xa7b0, 0xa7b4, 1}, - {0xa7b6, 0xa7be, 2}, - {0xa7c2, 0xa7c4, 2}, + {0xa7b6, 0xa7c4, 2}, {0xa7c5, 0xa7c7, 1}, - {0xa7c9, 0xa7f5, 44}, - {0xff21, 0xff3a, 1}, + {0xa7c9, 0xa7d0, 7}, + {0xa7d6, 0xa7d8, 2}, + {0xa7f5, 0xff21, 22316}, + {0xff22, 0xff3a, 1}, }, R32: []Range32{ {0x10400, 0x10427, 1}, {0x104b0, 0x104d3, 1}, + {0x10570, 0x1057a, 1}, + {0x1057c, 0x1058a, 1}, + {0x1058c, 0x10592, 1}, + {0x10594, 0x10595, 1}, {0x10c80, 0x10cb2, 1}, {0x118a0, 0x118bf, 1}, {0x16e40, 0x16e5f, 1}, @@ -7971,7 +8290,7 @@ var foldLu = &RangeTable{ {0x1fd1, 0x1fe0, 15}, {0x1fe1, 0x1fe5, 4}, {0x214e, 0x2184, 54}, - {0x2c30, 0x2c5e, 1}, + {0x2c30, 0x2c5f, 1}, {0x2c61, 0x2c65, 4}, {0x2c66, 0x2c6c, 2}, {0x2c73, 0x2c76, 3}, @@ -7989,9 +8308,10 @@ var foldLu = &RangeTable{ {0xa78c, 0xa791, 5}, {0xa793, 0xa794, 1}, {0xa797, 0xa7a9, 2}, - {0xa7b5, 0xa7bf, 2}, - {0xa7c3, 0xa7c8, 5}, - {0xa7ca, 0xa7f6, 44}, + {0xa7b5, 0xa7c3, 2}, + {0xa7c8, 0xa7ca, 2}, + {0xa7d1, 0xa7d7, 6}, + {0xa7d9, 0xa7f6, 29}, {0xab53, 0xab70, 29}, {0xab71, 0xabbf, 1}, {0xff41, 0xff5a, 1}, @@ -7999,6 +8319,10 @@ var foldLu = &RangeTable{ R32: []Range32{ {0x10428, 0x1044f, 1}, {0x104d8, 0x104fb, 1}, + {0x10597, 0x105a1, 1}, + {0x105a3, 0x105b1, 1}, + {0x105b3, 0x105b9, 1}, + {0x105bb, 0x105bc, 1}, {0x10cc0, 0x10cf2, 1}, {0x118c0, 0x118df, 1}, {0x16e60, 0x16e7f, 1}, @@ -8050,7 +8374,7 @@ var foldInherited = &RangeTable{ }, } -// Range entries: 3499 16-bit, 1820 32-bit, 5319 total. -// Range bytes: 20994 16-bit, 21840 32-bit, 42834 total. +// Range entries: 3535 16-bit, 2031 32-bit, 5566 total. +// Range bytes: 21210 16-bit, 24372 32-bit, 45582 total. // Fold orbit bytes: 88 pairs, 352 bytes diff --git a/gnovm/stdlibs/unicode/utf8/example_test.gno b/gnovm/stdlibs/unicode/utf8/example_test.gno index 17d6e8d2114..fe434c94767 100644 --- a/gnovm/stdlibs/unicode/utf8/example_test.gno +++ b/gnovm/stdlibs/unicode/utf8/example_test.gno @@ -49,6 +49,7 @@ func ExampleDecodeLastRuneInString() { // l 1 // e 1 // H 1 + } func ExampleDecodeRune() { @@ -213,3 +214,13 @@ func ExampleValidString() { // true // false } + +func ExampleAppendRune() { + buf1 := utf8.AppendRune(nil, 0x10000) + buf2 := utf8.AppendRune([]byte("init"), 0x10000) + fmt.Println(string(buf1)) + fmt.Println(string(buf2)) + // Output: + // 𐀀 + // init𐀀 +} diff --git a/gnovm/stdlibs/unicode/utf8/utf8.gno b/gnovm/stdlibs/unicode/utf8/utf8.gno index 9c70281488d..71d6bf18d01 100644 --- a/gnovm/stdlibs/unicode/utf8/utf8.gno +++ b/gnovm/stdlibs/unicode/utf8/utf8.gno @@ -141,7 +141,7 @@ func FullRuneInString(s string) bool { } // DecodeRune unpacks the first UTF-8 encoding in p and returns the rune and -// its width in bytes. If p is empty it returns (RuneError, 0). Otherwise, if +// its width in bytes. If p is empty it returns ([RuneError], 0). Otherwise, if // the encoding is invalid, it returns (RuneError, 1). Both are impossible // results for correct, non-empty UTF-8. // @@ -188,8 +188,8 @@ func DecodeRune(p []byte) (r rune, size int) { return rune(p0&mask4)<<18 | rune(b1&maskx)<<12 | rune(b2&maskx)<<6 | rune(b3&maskx), 4 } -// DecodeRuneInString is like DecodeRune but its input is a string. If s is -// empty it returns (RuneError, 0). Otherwise, if the encoding is invalid, it +// DecodeRuneInString is like [DecodeRune] but its input is a string. If s is +// empty it returns ([RuneError], 0). Otherwise, if the encoding is invalid, it // returns (RuneError, 1). Both are impossible results for correct, non-empty // UTF-8. // @@ -237,7 +237,7 @@ func DecodeRuneInString(s string) (r rune, size int) { } // DecodeLastRune unpacks the last UTF-8 encoding in p and returns the rune and -// its width in bytes. If p is empty it returns (RuneError, 0). Otherwise, if +// its width in bytes. If p is empty it returns ([RuneError], 0). Otherwise, if // the encoding is invalid, it returns (RuneError, 1). Both are impossible // results for correct, non-empty UTF-8. // @@ -276,8 +276,8 @@ func DecodeLastRune(p []byte) (r rune, size int) { return r, size } -// DecodeLastRuneInString is like DecodeLastRune but its input is a string. If -// s is empty it returns (RuneError, 0). Otherwise, if the encoding is invalid, +// DecodeLastRuneInString is like [DecodeLastRune] but its input is a string. If +// s is empty it returns ([RuneError], 0). Otherwise, if the encoding is invalid, // it returns (RuneError, 1). Both are impossible results for correct, // non-empty UTF-8. // @@ -337,7 +337,7 @@ func RuneLen(r rune) int { } // EncodeRune writes into p (which must be large enough) the UTF-8 encoding of the rune. -// If the rune is out of range, it writes the encoding of RuneError. +// If the rune is out of range, it writes the encoding of [RuneError]. // It returns the number of bytes written. func EncodeRune(p []byte, r rune) int { // Negative values are erroneous. Making it unsigned addresses the problem. @@ -352,13 +352,7 @@ func EncodeRune(p []byte, r rune) int { return 2 case i > MaxRune, surrogateMin <= i && i <= surrogateMax: r = RuneError - // XXX fallthrough not implemented - // fallthrough - _ = p[2] // eliminate bounds checks - p[0] = t3 | byte(r>>12) - p[1] = tx | byte(r>>6)&maskx - p[2] = tx | byte(r)&maskx - return 3 + fallthrough case i <= rune3Max: _ = p[2] // eliminate bounds checks p[0] = t3 | byte(r>>12) @@ -375,6 +369,32 @@ func EncodeRune(p []byte, r rune) int { } } +// AppendRune appends the UTF-8 encoding of r to the end of p and +// returns the extended buffer. If the rune is out of range, +// it appends the encoding of [RuneError]. +func AppendRune(p []byte, r rune) []byte { + // This function is inlineable for fast handling of ASCII. + if uint32(r) <= rune1Max { + return append(p, byte(r)) + } + return appendRuneNonASCII(p, r) +} + +func appendRuneNonASCII(p []byte, r rune) []byte { + // Negative values are erroneous. Making it unsigned addresses the problem. + switch i := uint32(r); { + case i <= rune2Max: + return append(p, t2|byte(r>>6), tx|byte(r)&maskx) + case i > MaxRune, surrogateMin <= i && i <= surrogateMax: + r = RuneError + fallthrough + case i <= rune3Max: + return append(p, t3|byte(r>>12), tx|byte(r>>6)&maskx, tx|byte(r)&maskx) + default: + return append(p, t4|byte(r>>18), tx|byte(r>>12)&maskx, tx|byte(r>>6)&maskx, tx|byte(r)&maskx) + } +} + // RuneCount returns the number of runes in p. Erroneous and short // encodings are treated as single runes of width 1 byte. func RuneCount(p []byte) int { @@ -413,7 +433,7 @@ func RuneCount(p []byte) int { return n } -// RuneCountInString is like RuneCount but its input is a string. +// RuneCountInString is like [RuneCount] but its input is a string. func RuneCountInString(s string) (n int) { ns := len(s) for i := 0; i < ns; n++ { @@ -455,6 +475,11 @@ func RuneStart(b byte) bool { return b&0xC0 != 0x80 } // Valid reports whether p consists entirely of valid UTF-8-encoded runes. func Valid(p []byte) bool { + // This optimization avoids the need to recompute the capacity + // when generating code for p[8:], bringing it to parity with + // ValidString, which was 20% faster on long ASCII strings. + p = p[:len(p):len(p)] + // Fast path. Check for and skip 8 bytes of ASCII characters per iteration. for len(p) >= 8 { // Combining two 32 bit loads allows the same code to be used diff --git a/gnovm/stdlibs/unicode/utf8/utf8_test.gno b/gnovm/stdlibs/unicode/utf8/utf8_test.gno index 7fecb778975..0384b7a88e9 100644 --- a/gnovm/stdlibs/unicode/utf8/utf8_test.gno +++ b/gnovm/stdlibs/unicode/utf8/utf8_test.gno @@ -127,6 +127,17 @@ func TestEncodeRune(t *testing.T) { } } +func TestAppendRune(t *testing.T) { + for _, m := range utf8map { + if buf := utf8.AppendRune(nil, m.r); string(buf) != m.str { + t.Errorf("AppendRune(nil, %#04x) = %s, want %s", m.r, buf, m.str) + } + if buf := utf8.AppendRune([]byte("init"), m.r); string(buf) != "init"+m.str { + t.Errorf("AppendRune(init, %#04x) = %s, want %s", m.r, buf, "init"+m.str) + } + } +} + func TestDecodeRune(t *testing.T) { for _, m := range utf8map { b := []byte(m.str) diff --git a/gnovm/tests/files/break0.gno b/gnovm/tests/files/break0.gno new file mode 100644 index 00000000000..17d68dc1dbf --- /dev/null +++ b/gnovm/tests/files/break0.gno @@ -0,0 +1,8 @@ +package main + +func main() { + break +} + +// Error: +// main/files/break0.gno:4:2: cannot break with no parent loop or switch diff --git a/gnovm/tests/files/cont3.gno b/gnovm/tests/files/cont3.gno new file mode 100644 index 00000000000..8a305d4ceb2 --- /dev/null +++ b/gnovm/tests/files/cont3.gno @@ -0,0 +1,8 @@ +package main + +func main() { + continue +} + +// Error: +// main/files/cont3.gno:4:2: cannot continue with no parent loop diff --git a/gnovm/tests/files/for20.gno b/gnovm/tests/files/for20.gno new file mode 100644 index 00000000000..ad9f1f124d0 --- /dev/null +++ b/gnovm/tests/files/for20.gno @@ -0,0 +1,15 @@ +package main + +func main() { + // Ensure `break` works also when we have a label for the for loop. + +loop: + for { + break + } + + println("hey") +} + +// Output: +// hey diff --git a/gnovm/tests/files/redeclaration10.gno b/gnovm/tests/files/redeclaration10.gno index 01584b1755c..afbf3c6a607 100644 --- a/gnovm/tests/files/redeclaration10.gno +++ b/gnovm/tests/files/redeclaration10.gno @@ -6,7 +6,5 @@ func main() { println("should not happen") } -// XXX show what was redeclared. - // Error: -// running package "github.com/gnolang/gno/_test/redeclaration3": duplicate declarations not allowed +// running package "github.com/gnolang/gno/_test/redeclaration3": redeclarations for identifiers: "a.method" diff --git a/gnovm/tests/files/redeclaration6.gno b/gnovm/tests/files/redeclaration6.gno index 25e36fa61aa..74e762604ba 100644 --- a/gnovm/tests/files/redeclaration6.gno +++ b/gnovm/tests/files/redeclaration6.gno @@ -6,7 +6,5 @@ func main() { println("should not happen") } -// XXX show what was redeclared. - // Error: -// running package "github.com/gnolang/gno/_test/redeclaration1": duplicate declarations not allowed +// running package "github.com/gnolang/gno/_test/redeclaration1": redeclarations for identifiers: "a" diff --git a/gnovm/tests/files/redeclaration8.gno b/gnovm/tests/files/redeclaration8.gno index d0e5b958030..51c8871a4f2 100644 --- a/gnovm/tests/files/redeclaration8.gno +++ b/gnovm/tests/files/redeclaration8.gno @@ -6,7 +6,5 @@ func main() { println("should not happen") } -// XXX show what was redeclared. - // Error: -// running package "github.com/gnolang/gno/_test/redeclaration2": duplicate declarations not allowed +// running package "github.com/gnolang/gno/_test/redeclaration2": redeclarations for identifiers: "a" diff --git a/gnovm/tests/imports.go b/gnovm/tests/imports.go index 30f410fa8d5..b8532253ce3 100644 --- a/gnovm/tests/imports.go +++ b/gnovm/tests/imports.go @@ -246,6 +246,15 @@ func TestStore(rootDir, filesPath string, stdin io.Reader, stdout, stderr io.Wri pkg.DefineGoNativeType(reflect.TypeOf(time.Month(0))) pkg.DefineGoNativeValue("LoadLocation", time.LoadLocation) return pkg, pkg.NewPackage() + case "strconv": + pkg := gno.NewPackageNode("strconv", pkgPath, nil) + pkg.DefineGoNativeValue("Itoa", strconv.Itoa) + pkg.DefineGoNativeValue("Atoi", strconv.Atoi) + pkg.DefineGoNativeValue("ParseInt", strconv.ParseInt) + pkg.DefineGoNativeValue("Quote", strconv.Quote) + pkg.DefineGoNativeValue("FormatUint", strconv.FormatUint) + pkg.DefineGoNativeType(reflect.TypeOf(strconv.NumError{})) + return pkg, pkg.NewPackage() case "strings": pkg := gno.NewPackageNode("strings", pkgPath, nil) pkg.DefineGoNativeValue("Split", strings.Split) @@ -418,7 +427,6 @@ func TestStore(rootDir, filesPath string, stdin io.Reader, stdout, stderr io.Wri resStore = gno.NewStore(nil, baseStore, iavlStore) resStore.SetPackageGetter(getPackage) resStore.SetNativeStore(teststdlibs.NativeStore) - resStore.SetPackageInjector(testPackageInjector) resStore.SetStrictGo2GnoMapping(false) return } @@ -465,19 +473,6 @@ func loadStdlib(rootDir, pkgPath string, store gno.Store, stdout io.Writer) (*gn return m2.RunMemPackageWithOverrides(memPkg, save) } -func testPackageInjector(store gno.Store, pn *gno.PackageNode) { - // Test specific injections: - switch pn.PkgPath { - case "strconv": - // NOTE: Itoa and Atoi are already injected - // from stdlibs.InjectNatives. - pn.DefineGoNativeType(reflect.TypeOf(strconv.NumError{})) - pn.DefineGoNativeValue("ParseInt", strconv.ParseInt) - } -} - -// ---------------------------------------- - type dummyReader struct{} func (*dummyReader) Read(b []byte) (n int, err error) {