From f378ed9a741d2f4b2b554a20bde5d5bcb844d508 Mon Sep 17 00:00:00 2001 From: Simone Gotti Date: Tue, 17 Feb 2015 16:56:53 +0100 Subject: [PATCH] godeps: Add github.com/cznic/ql. --- Godeps/Godeps.json | 36 + .../src/github.com/camlistore/lock/.gitignore | 1 + .../src/github.com/camlistore/lock/COPYING | 202 + .../src/github.com/camlistore/lock/README.txt | 3 + .../src/github.com/camlistore/lock/lock.go | 158 + .../camlistore/lock/lock_appengine.go | 32 + .../camlistore/lock/lock_darwin_amd64.go | 80 + .../camlistore/lock/lock_freebsd.go | 79 + .../camlistore/lock/lock_linux_amd64.go | 80 + .../camlistore/lock/lock_linux_arm.go | 81 + .../github.com/camlistore/lock/lock_plan9.go | 55 + .../camlistore/lock/lock_sigzero.go | 26 + .../github.com/camlistore/lock/lock_test.go | 131 + .../src/github.com/cznic/bufs/AUTHORS | 11 + .../src/github.com/cznic/bufs/CONTRIBUTORS | 9 + .../src/github.com/cznic/bufs/LICENSE | 27 + .../src/github.com/cznic/bufs/Makefile | 31 + .../src/github.com/cznic/bufs/README.md | 8 + .../src/github.com/cznic/bufs/bufs.go | 391 + .../src/github.com/cznic/bufs/bufs_test.go | 174 + .../src/github.com/cznic/exp/lldb/2pc.go | 324 + .../src/github.com/cznic/exp/lldb/2pc_docs.go | 44 + .../src/github.com/cznic/exp/lldb/2pc_test.go | 285 + .../src/github.com/cznic/exp/lldb/AUTHORS | 11 + .../github.com/cznic/exp/lldb/CONTRIBUTORS | 9 + .../src/github.com/cznic/exp/lldb/LICENSE | 27 + .../src/github.com/cznic/exp/lldb/Makefile | 45 + .../src/github.com/cznic/exp/lldb/README.md | 8 + .../src/github.com/cznic/exp/lldb/all_test.go | 43 + .../src/github.com/cznic/exp/lldb/btree.go | 2276 ++++ .../github.com/cznic/exp/lldb/btree_test.go | 1887 ++++ .../src/github.com/cznic/exp/lldb/errors.go | 170 + .../src/github.com/cznic/exp/lldb/falloc.go | 1970 ++++ .../github.com/cznic/exp/lldb/falloc_test.go | 1833 ++++ .../src/github.com/cznic/exp/lldb/filer.go | 192 + .../github.com/cznic/exp/lldb/filer_test.go | 764 ++ .../src/github.com/cznic/exp/lldb/gb.go | 812 ++ .../src/github.com/cznic/exp/lldb/gb_test.go | 364 + .../src/github.com/cznic/exp/lldb/lldb.go | 155 + .../github.com/cznic/exp/lldb/lldb_test.go | 217 + .../src/github.com/cznic/exp/lldb/memfiler.go | 344 + .../cznic/exp/lldb/memfiler_test.go | 132 + .../src/github.com/cznic/exp/lldb/osfiler.go | 130 + .../cznic/exp/lldb/simplefilefiler.go | 123 + .../src/github.com/cznic/exp/lldb/xact.go | 629 ++ .../github.com/cznic/exp/lldb/xact_test.go | 400 + .../src/github.com/cznic/fileutil/AUTHORS | 14 + .../github.com/cznic/fileutil/CONTRIBUTORS | 14 + .../src/github.com/cznic/fileutil/LICENSE | 27 + .../src/github.com/cznic/fileutil/Makefile | 27 + .../src/github.com/cznic/fileutil/README | 16 + .../src/github.com/cznic/fileutil/all_test.go | 39 + .../github.com/cznic/fileutil/falloc/LICENSE | 27 + .../github.com/cznic/fileutil/falloc/README | 5 + .../cznic/fileutil/falloc/all_test.go | 3105 ++++++ .../github.com/cznic/fileutil/falloc/docs.go | 251 + .../github.com/cznic/fileutil/falloc/error.go | 130 + .../cznic/fileutil/falloc/falloc.go | 676 ++ .../cznic/fileutil/falloc/test_deps.go | 16 + .../src/github.com/cznic/fileutil/fileutil.go | 223 + .../github.com/cznic/fileutil/fileutil_arm.go | 25 + .../cznic/fileutil/fileutil_darwin.go | 25 + .../cznic/fileutil/fileutil_freebsd.go | 25 + .../cznic/fileutil/fileutil_linux.go | 96 + .../cznic/fileutil/fileutil_openbsd.go | 25 + .../cznic/fileutil/fileutil_plan9.go | 25 + .../cznic/fileutil/fileutil_solaris.go | 27 + .../cznic/fileutil/fileutil_windows.go | 183 + .../src/github.com/cznic/fileutil/hdb/LICENSE | 27 + .../src/github.com/cznic/fileutil/hdb/README | 5 + .../github.com/cznic/fileutil/hdb/all_test.go | 15 + .../src/github.com/cznic/fileutil/hdb/hdb.go | 153 + .../cznic/fileutil/hdb/test_deps.go | 13 + .../github.com/cznic/fileutil/punch_test.go | 55 + .../github.com/cznic/fileutil/storage/LICENSE | 27 + .../github.com/cznic/fileutil/storage/README | 5 + .../cznic/fileutil/storage/all_test.go | 22 + .../cznic/fileutil/storage/cache.go | 322 + .../cznic/fileutil/storage/cache_test.go | 83 + .../cznic/fileutil/storage/dev_test.go | 18 + .../github.com/cznic/fileutil/storage/file.go | 50 + .../github.com/cznic/fileutil/storage/mem.go | 161 + .../cznic/fileutil/storage/mem_test.go | 15 + .../cznic/fileutil/storage/probe.go | 74 + .../cznic/fileutil/storage/probe_test.go | 86 + .../cznic/fileutil/storage/storage.go | 141 + .../cznic/fileutil/storage/test_deps.go | 13 + .../github.com/cznic/fileutil/test_deps.go | 13 + .../src/github.com/cznic/mathutil/AUTHORS | 12 + .../github.com/cznic/mathutil/CONTRIBUTORS | 10 + .../src/github.com/cznic/mathutil/LICENSE | 27 + .../src/github.com/cznic/mathutil/Makefile | 31 + .../src/github.com/cznic/mathutil/README | 10 + .../src/github.com/cznic/mathutil/all_test.go | 3530 ++++++ .../src/github.com/cznic/mathutil/bits.go | 207 + .../src/github.com/cznic/mathutil/envelope.go | 46 + .../cznic/mathutil/example/.gitignore | 2 + .../cznic/mathutil/example/example.go | 48 + .../cznic/mathutil/example2/.gitignore | 2 + .../cznic/mathutil/example2/example2.go | 66 + .../cznic/mathutil/example3/.gitignore | 2 + .../cznic/mathutil/example3/example3.go | 43 + .../cznic/mathutil/example4/main.go | 90 + .../cznic/mathutil/example4/results | 55 + .../src/github.com/cznic/mathutil/ff/main.go | 83 + .../src/github.com/cznic/mathutil/mathutil.go | 829 ++ .../cznic/mathutil/mersenne/AUTHORS | 11 + .../cznic/mathutil/mersenne/CONTRIBUTORS | 9 + .../cznic/mathutil/mersenne/LICENSE | 27 + .../cznic/mathutil/mersenne/Makefile | 24 + .../github.com/cznic/mathutil/mersenne/README | 2 + .../cznic/mathutil/mersenne/all_test.go | 943 ++ .../cznic/mathutil/mersenne/mersenne.go | 296 + .../cznic/mathutil/nist-sts-2-1-1-report | 267 + .../src/github.com/cznic/mathutil/permute.go | 39 + .../src/github.com/cznic/mathutil/primes.go | 342 + .../src/github.com/cznic/mathutil/rat.go | 27 + .../src/github.com/cznic/mathutil/rnd.go | 383 + .../src/github.com/cznic/mathutil/tables.go | 6995 ++++++++++++ .../github.com/cznic/mathutil/test_deps.go | 11 + .../src/github.com/cznic/ql/AUTHORS | 11 + .../src/github.com/cznic/ql/CONTRIBUTORS | 11 + .../src/github.com/cznic/ql/LICENSE | 27 + .../src/github.com/cznic/ql/Makefile | 74 + .../src/github.com/cznic/ql/README.md | 21 + .../src/github.com/cznic/ql/all_test.go | 2720 +++++ .../src/github.com/cznic/ql/benchcmp | 1 + .../src/github.com/cznic/ql/blob.go | 140 + .../src/github.com/cznic/ql/btree.go | 725 ++ .../src/github.com/cznic/ql/builtin.go | 878 ++ .../src/github.com/cznic/ql/coerce.go | 290 + .../src/github.com/cznic/ql/design/doc.go | 298 + .../_workspace/src/github.com/cznic/ql/doc.go | 2295 ++++ .../src/github.com/cznic/ql/driver.go | 528 + .../src/github.com/cznic/ql/driver/Makefile | 40 + .../github.com/cznic/ql/driver/all_test.go | 202 + .../src/github.com/cznic/ql/driver/driver.go | 61 + .../src/github.com/cznic/ql/errors.go | 18 + .../_workspace/src/github.com/cznic/ql/etc.go | 2798 +++++ .../src/github.com/cznic/ql/expr.go | 3653 +++++++ .../src/github.com/cznic/ql/file.go | 1258 +++ .../src/github.com/cznic/ql/helper.go | 338 + .../src/github.com/cznic/ql/httpfs.go | 302 + .../src/github.com/cznic/ql/httpfs_test.go | 547 + .../src/github.com/cznic/ql/introspection.go | 625 ++ .../github.com/cznic/ql/introspection_test.go | 1073 ++ .../_workspace/src/github.com/cznic/ql/mem.go | 1270 +++ .../src/github.com/cznic/ql/parser.go | 2061 ++++ .../src/github.com/cznic/ql/parser.y | 1062 ++ .../src/github.com/cznic/ql/parser_test.go | 193 + .../src/github.com/cznic/ql/ql.ebnf | 218 + .../_workspace/src/github.com/cznic/ql/ql.go | 2162 ++++ .../_workspace/src/github.com/cznic/ql/ql.y | 1573 +++ .../.34a8b4c1ad933745146fdbfef3073706ee571625 | 0 .../.f630cc97640448d8f823924a7df3ca00e4d9e53b | 0 .../src/github.com/cznic/ql/ql/Makefile | 24 + .../src/github.com/cznic/ql/ql/README.md | 10 + .../src/github.com/cznic/ql/ql/main.go | 200 + .../_workspace/src/github.com/cznic/ql/ql/ql | Bin 0 -> 10535847 bytes .../src/github.com/cznic/ql/ql/ql.db | Bin 0 -> 160 bytes .../src/github.com/cznic/ql/scanner.go | 3788 +++++++ .../src/github.com/cznic/ql/scanner.l | 444 + .../src/github.com/cznic/ql/scanner_test.go | 86 + .../src/github.com/cznic/ql/stmt.go | 900 ++ .../src/github.com/cznic/ql/storage.go | 669 ++ .../src/github.com/cznic/ql/storage_test.go | 330 + .../src/github.com/cznic/ql/testdata.ql | 9462 +++++++++++++++++ .../src/github.com/cznic/sortutil/AUTHORS | 11 + .../github.com/cznic/sortutil/CONTRIBUTORS | 10 + .../src/github.com/cznic/sortutil/LICENSE | 27 + .../src/github.com/cznic/sortutil/Makefile | 35 + .../src/github.com/cznic/sortutil/README | 4 + .../src/github.com/cznic/sortutil/all_test.go | 360 + .../src/github.com/cznic/sortutil/sortutil.go | 227 + .../src/github.com/cznic/strutil/AUTHORS | 12 + .../src/github.com/cznic/strutil/CONTRIBUTORS | 9 + .../src/github.com/cznic/strutil/LICENSE | 27 + .../src/github.com/cznic/strutil/Makefile | 37 + .../src/github.com/cznic/strutil/README | 8 + .../src/github.com/cznic/strutil/all_test.go | 83 + .../src/github.com/cznic/strutil/strutil.go | 428 + .../src/github.com/cznic/zappy/AUTHORS | 12 + .../src/github.com/cznic/zappy/CONTRIBUTORS | 10 + .../src/github.com/cznic/zappy/LICENSE | 27 + .../src/github.com/cznic/zappy/Makefile | 30 + .../src/github.com/cznic/zappy/README.md | 9 + .../github.com/cznic/zappy/SNAPPY-GO-LICENSE | 27 + .../src/github.com/cznic/zappy/all_test.go | 379 + .../src/github.com/cznic/zappy/decode.go | 38 + .../src/github.com/cznic/zappy/decode_cgo.go | 121 + .../github.com/cznic/zappy/decode_nocgo.go | 89 + .../src/github.com/cznic/zappy/encode.go | 37 + .../src/github.com/cznic/zappy/encode_cgo.go | 140 + .../github.com/cznic/zappy/encode_nocgo.go | 92 + .../src/github.com/cznic/zappy/purego.sh | 11 + .../src/github.com/cznic/zappy/zappy.go | 241 + 196 files changed, 81504 insertions(+) create mode 100644 Godeps/_workspace/src/github.com/camlistore/lock/.gitignore create mode 100644 Godeps/_workspace/src/github.com/camlistore/lock/COPYING create mode 100644 Godeps/_workspace/src/github.com/camlistore/lock/README.txt create mode 100644 Godeps/_workspace/src/github.com/camlistore/lock/lock.go create mode 100644 Godeps/_workspace/src/github.com/camlistore/lock/lock_appengine.go create mode 100644 Godeps/_workspace/src/github.com/camlistore/lock/lock_darwin_amd64.go create mode 100644 Godeps/_workspace/src/github.com/camlistore/lock/lock_freebsd.go create mode 100644 Godeps/_workspace/src/github.com/camlistore/lock/lock_linux_amd64.go create mode 100644 Godeps/_workspace/src/github.com/camlistore/lock/lock_linux_arm.go create mode 100644 Godeps/_workspace/src/github.com/camlistore/lock/lock_plan9.go create mode 100644 Godeps/_workspace/src/github.com/camlistore/lock/lock_sigzero.go create mode 100644 Godeps/_workspace/src/github.com/camlistore/lock/lock_test.go create mode 100644 Godeps/_workspace/src/github.com/cznic/bufs/AUTHORS create mode 100644 Godeps/_workspace/src/github.com/cznic/bufs/CONTRIBUTORS create mode 100644 Godeps/_workspace/src/github.com/cznic/bufs/LICENSE create mode 100644 Godeps/_workspace/src/github.com/cznic/bufs/Makefile create mode 100644 Godeps/_workspace/src/github.com/cznic/bufs/README.md create mode 100644 Godeps/_workspace/src/github.com/cznic/bufs/bufs.go create mode 100644 Godeps/_workspace/src/github.com/cznic/bufs/bufs_test.go create mode 100644 Godeps/_workspace/src/github.com/cznic/exp/lldb/2pc.go create mode 100644 Godeps/_workspace/src/github.com/cznic/exp/lldb/2pc_docs.go create mode 100644 Godeps/_workspace/src/github.com/cznic/exp/lldb/2pc_test.go create mode 100644 Godeps/_workspace/src/github.com/cznic/exp/lldb/AUTHORS create mode 100644 Godeps/_workspace/src/github.com/cznic/exp/lldb/CONTRIBUTORS create mode 100644 Godeps/_workspace/src/github.com/cznic/exp/lldb/LICENSE create mode 100644 Godeps/_workspace/src/github.com/cznic/exp/lldb/Makefile create mode 100644 Godeps/_workspace/src/github.com/cznic/exp/lldb/README.md create mode 100644 Godeps/_workspace/src/github.com/cznic/exp/lldb/all_test.go create mode 100644 Godeps/_workspace/src/github.com/cznic/exp/lldb/btree.go create mode 100644 Godeps/_workspace/src/github.com/cznic/exp/lldb/btree_test.go create mode 100644 Godeps/_workspace/src/github.com/cznic/exp/lldb/errors.go create mode 100644 Godeps/_workspace/src/github.com/cznic/exp/lldb/falloc.go create mode 100644 Godeps/_workspace/src/github.com/cznic/exp/lldb/falloc_test.go create mode 100644 Godeps/_workspace/src/github.com/cznic/exp/lldb/filer.go create mode 100644 Godeps/_workspace/src/github.com/cznic/exp/lldb/filer_test.go create mode 100644 Godeps/_workspace/src/github.com/cznic/exp/lldb/gb.go create mode 100644 Godeps/_workspace/src/github.com/cznic/exp/lldb/gb_test.go create mode 100644 Godeps/_workspace/src/github.com/cznic/exp/lldb/lldb.go create mode 100644 Godeps/_workspace/src/github.com/cznic/exp/lldb/lldb_test.go create mode 100644 Godeps/_workspace/src/github.com/cznic/exp/lldb/memfiler.go create mode 100644 Godeps/_workspace/src/github.com/cznic/exp/lldb/memfiler_test.go create mode 100644 Godeps/_workspace/src/github.com/cznic/exp/lldb/osfiler.go create mode 100644 Godeps/_workspace/src/github.com/cznic/exp/lldb/simplefilefiler.go create mode 100644 Godeps/_workspace/src/github.com/cznic/exp/lldb/xact.go create mode 100644 Godeps/_workspace/src/github.com/cznic/exp/lldb/xact_test.go create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/AUTHORS create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/CONTRIBUTORS create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/LICENSE create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/Makefile create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/README create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/all_test.go create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/falloc/LICENSE create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/falloc/README create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/falloc/all_test.go create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/falloc/docs.go create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/falloc/error.go create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/falloc/falloc.go create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/falloc/test_deps.go create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/fileutil.go create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/fileutil_arm.go create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/fileutil_darwin.go create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/fileutil_freebsd.go create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/fileutil_linux.go create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/fileutil_openbsd.go create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/fileutil_plan9.go create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/fileutil_solaris.go create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/fileutil_windows.go create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/hdb/LICENSE create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/hdb/README create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/hdb/all_test.go create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/hdb/hdb.go create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/hdb/test_deps.go create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/punch_test.go create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/storage/LICENSE create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/storage/README create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/storage/all_test.go create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/storage/cache.go create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/storage/cache_test.go create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/storage/dev_test.go create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/storage/file.go create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/storage/mem.go create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/storage/mem_test.go create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/storage/probe.go create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/storage/probe_test.go create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/storage/storage.go create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/storage/test_deps.go create mode 100644 Godeps/_workspace/src/github.com/cznic/fileutil/test_deps.go create mode 100644 Godeps/_workspace/src/github.com/cznic/mathutil/AUTHORS create mode 100644 Godeps/_workspace/src/github.com/cznic/mathutil/CONTRIBUTORS create mode 100644 Godeps/_workspace/src/github.com/cznic/mathutil/LICENSE create mode 100644 Godeps/_workspace/src/github.com/cznic/mathutil/Makefile create mode 100644 Godeps/_workspace/src/github.com/cznic/mathutil/README create mode 100644 Godeps/_workspace/src/github.com/cznic/mathutil/all_test.go create mode 100644 Godeps/_workspace/src/github.com/cznic/mathutil/bits.go create mode 100644 Godeps/_workspace/src/github.com/cznic/mathutil/envelope.go create mode 100644 Godeps/_workspace/src/github.com/cznic/mathutil/example/.gitignore create mode 100644 Godeps/_workspace/src/github.com/cznic/mathutil/example/example.go create mode 100644 Godeps/_workspace/src/github.com/cznic/mathutil/example2/.gitignore create mode 100644 Godeps/_workspace/src/github.com/cznic/mathutil/example2/example2.go create mode 100644 Godeps/_workspace/src/github.com/cznic/mathutil/example3/.gitignore create mode 100644 Godeps/_workspace/src/github.com/cznic/mathutil/example3/example3.go create mode 100644 Godeps/_workspace/src/github.com/cznic/mathutil/example4/main.go create mode 100644 Godeps/_workspace/src/github.com/cznic/mathutil/example4/results create mode 100644 Godeps/_workspace/src/github.com/cznic/mathutil/ff/main.go create mode 100644 Godeps/_workspace/src/github.com/cznic/mathutil/mathutil.go create mode 100644 Godeps/_workspace/src/github.com/cznic/mathutil/mersenne/AUTHORS create mode 100644 Godeps/_workspace/src/github.com/cznic/mathutil/mersenne/CONTRIBUTORS create mode 100644 Godeps/_workspace/src/github.com/cznic/mathutil/mersenne/LICENSE create mode 100644 Godeps/_workspace/src/github.com/cznic/mathutil/mersenne/Makefile create mode 100644 Godeps/_workspace/src/github.com/cznic/mathutil/mersenne/README create mode 100644 Godeps/_workspace/src/github.com/cznic/mathutil/mersenne/all_test.go create mode 100644 Godeps/_workspace/src/github.com/cznic/mathutil/mersenne/mersenne.go create mode 100644 Godeps/_workspace/src/github.com/cznic/mathutil/nist-sts-2-1-1-report create mode 100644 Godeps/_workspace/src/github.com/cznic/mathutil/permute.go create mode 100644 Godeps/_workspace/src/github.com/cznic/mathutil/primes.go create mode 100644 Godeps/_workspace/src/github.com/cznic/mathutil/rat.go create mode 100644 Godeps/_workspace/src/github.com/cznic/mathutil/rnd.go create mode 100644 Godeps/_workspace/src/github.com/cznic/mathutil/tables.go create mode 100644 Godeps/_workspace/src/github.com/cznic/mathutil/test_deps.go create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/AUTHORS create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/CONTRIBUTORS create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/LICENSE create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/Makefile create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/README.md create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/all_test.go create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/benchcmp create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/blob.go create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/btree.go create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/builtin.go create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/coerce.go create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/design/doc.go create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/doc.go create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/driver.go create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/driver/Makefile create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/driver/all_test.go create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/driver/driver.go create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/errors.go create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/etc.go create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/expr.go create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/file.go create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/helper.go create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/httpfs.go create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/httpfs_test.go create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/introspection.go create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/introspection_test.go create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/mem.go create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/parser.go create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/parser.y create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/parser_test.go create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/ql.ebnf create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/ql.go create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/ql.y create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/ql/.34a8b4c1ad933745146fdbfef3073706ee571625 create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/ql/.f630cc97640448d8f823924a7df3ca00e4d9e53b create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/ql/Makefile create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/ql/README.md create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/ql/main.go create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/ql/ql create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/ql/ql.db create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/scanner.go create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/scanner.l create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/scanner_test.go create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/stmt.go create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/storage.go create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/storage_test.go create mode 100644 Godeps/_workspace/src/github.com/cznic/ql/testdata.ql create mode 100644 Godeps/_workspace/src/github.com/cznic/sortutil/AUTHORS create mode 100644 Godeps/_workspace/src/github.com/cznic/sortutil/CONTRIBUTORS create mode 100644 Godeps/_workspace/src/github.com/cznic/sortutil/LICENSE create mode 100644 Godeps/_workspace/src/github.com/cznic/sortutil/Makefile create mode 100644 Godeps/_workspace/src/github.com/cznic/sortutil/README create mode 100644 Godeps/_workspace/src/github.com/cznic/sortutil/all_test.go create mode 100644 Godeps/_workspace/src/github.com/cznic/sortutil/sortutil.go create mode 100644 Godeps/_workspace/src/github.com/cznic/strutil/AUTHORS create mode 100644 Godeps/_workspace/src/github.com/cznic/strutil/CONTRIBUTORS create mode 100644 Godeps/_workspace/src/github.com/cznic/strutil/LICENSE create mode 100644 Godeps/_workspace/src/github.com/cznic/strutil/Makefile create mode 100644 Godeps/_workspace/src/github.com/cznic/strutil/README create mode 100644 Godeps/_workspace/src/github.com/cznic/strutil/all_test.go create mode 100644 Godeps/_workspace/src/github.com/cznic/strutil/strutil.go create mode 100644 Godeps/_workspace/src/github.com/cznic/zappy/AUTHORS create mode 100644 Godeps/_workspace/src/github.com/cznic/zappy/CONTRIBUTORS create mode 100644 Godeps/_workspace/src/github.com/cznic/zappy/LICENSE create mode 100644 Godeps/_workspace/src/github.com/cznic/zappy/Makefile create mode 100644 Godeps/_workspace/src/github.com/cznic/zappy/README.md create mode 100644 Godeps/_workspace/src/github.com/cznic/zappy/SNAPPY-GO-LICENSE create mode 100644 Godeps/_workspace/src/github.com/cznic/zappy/all_test.go create mode 100644 Godeps/_workspace/src/github.com/cznic/zappy/decode.go create mode 100644 Godeps/_workspace/src/github.com/cznic/zappy/decode_cgo.go create mode 100644 Godeps/_workspace/src/github.com/cznic/zappy/decode_nocgo.go create mode 100644 Godeps/_workspace/src/github.com/cznic/zappy/encode.go create mode 100644 Godeps/_workspace/src/github.com/cznic/zappy/encode_cgo.go create mode 100644 Godeps/_workspace/src/github.com/cznic/zappy/encode_nocgo.go create mode 100644 Godeps/_workspace/src/github.com/cznic/zappy/purego.sh create mode 100644 Godeps/_workspace/src/github.com/cznic/zappy/zappy.go diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 8f03291..9ac4212 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -47,6 +47,10 @@ "ImportPath": "github.com/coreos/go-iptables/iptables", "Rev": "83dfad0f13fd7310fb3c1cb8563248d8d604b95b" }, + { + "ImportPath": "github.com/camlistore/lock", + "Rev": "ae27720f340952636b826119b58130b9c1a847a0" + }, { "ImportPath": "github.com/coreos/go-semver/semver", "Rev": "6fe83ccda8fb9b7549c9ab4ba47f47858bc950aa" @@ -56,6 +60,38 @@ "Comment": "v2-41-g415a79c4bfa3", "Rev": "415a79c4bfa377b484b16c632347b3925a0f35ff" }, + { + "ImportPath": "github.com/cznic/bufs", + "Rev": "3dcccbd7064a1689f9c093a988ea11ac00e21f51" + }, + { + "ImportPath": "github.com/cznic/exp/lldb", + "Rev": "9b0e4be12fbdb7b843e0a658a04c35d160371789" + }, + { + "ImportPath": "github.com/cznic/fileutil", + "Rev": "21ae57c9dce724a15e88bd9cd46d5668f3e880a5" + }, + { + "ImportPath": "github.com/cznic/mathutil", + "Rev": "250d0b9d3304c5ea0c4cfc7d9efc7ee528b81f3b" + }, + { + "ImportPath": "github.com/cznic/ql", + "Rev": "fc1b91b82089d3f132fbed8a7c9f349c3133eb96" + }, + { + "ImportPath": "github.com/cznic/sortutil", + "Rev": "d4401851b4c370f979b842fa1e45e0b3b718b391" + }, + { + "ImportPath": "github.com/cznic/strutil", + "Rev": "97bc31f80ac4c9fa9c5dc5fea74c383858988ea2" + }, + { + "ImportPath": "github.com/cznic/zappy", + "Rev": "47331054e4f96186e3ff772877c0443909368a45" + }, { "ImportPath": "github.com/gorilla/context", "Rev": "50c25fb3b2b3b3cc724e9b6ac75fb44b3bccd0da" diff --git a/Godeps/_workspace/src/github.com/camlistore/lock/.gitignore b/Godeps/_workspace/src/github.com/camlistore/lock/.gitignore new file mode 100644 index 0000000..b25c15b --- /dev/null +++ b/Godeps/_workspace/src/github.com/camlistore/lock/.gitignore @@ -0,0 +1 @@ +*~ diff --git a/Godeps/_workspace/src/github.com/camlistore/lock/COPYING b/Godeps/_workspace/src/github.com/camlistore/lock/COPYING new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Godeps/_workspace/src/github.com/camlistore/lock/COPYING @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Godeps/_workspace/src/github.com/camlistore/lock/README.txt b/Godeps/_workspace/src/github.com/camlistore/lock/README.txt new file mode 100644 index 0000000..a9eeb33 --- /dev/null +++ b/Godeps/_workspace/src/github.com/camlistore/lock/README.txt @@ -0,0 +1,3 @@ +File locking library. + +See http://godoc.org/github.com/camlistore/lock diff --git a/Godeps/_workspace/src/github.com/camlistore/lock/lock.go b/Godeps/_workspace/src/github.com/camlistore/lock/lock.go new file mode 100644 index 0000000..6268527 --- /dev/null +++ b/Godeps/_workspace/src/github.com/camlistore/lock/lock.go @@ -0,0 +1,158 @@ +/* +Copyright 2013 The Go Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package lock + +import ( + "encoding/json" + "fmt" + "io" + "os" + "path/filepath" + "sync" +) + +// Lock locks the given file, creating the file if necessary. If the +// file already exists, it must have zero size or an error is returned. +// The lock is an exclusive lock (a write lock), but locked files +// should neither be read from nor written to. Such files should have +// zero size and only exist to co-ordinate ownership across processes. +// +// A nil Closer is returned if an error occurred. Otherwise, close that +// Closer to release the lock. +// +// On Linux, FreeBSD and OSX, a lock has the same semantics as fcntl(2)'s +// advisory locks. In particular, closing any other file descriptor for the +// same file will release the lock prematurely. +// +// Attempting to lock a file that is already locked by the current process +// has undefined behavior. +// +// On other operating systems, lock will fallback to using the presence and +// content of a file named name + '.lock' to implement locking behavior. +func Lock(name string) (io.Closer, error) { + return lockFn(name) +} + +var lockFn = lockPortable + +// Portable version not using fcntl. Doesn't handle crashes as gracefully, +// since it can leave stale lock files. +// TODO: write pid of owner to lock file and on race see if pid is +// still alive? +func lockPortable(name string) (io.Closer, error) { + absName, err := filepath.Abs(name) + if err != nil { + return nil, fmt.Errorf("can't Lock file %q: can't find abs path: %v", name, err) + } + fi, err := os.Stat(absName) + if err == nil && fi.Size() > 0 { + if isStaleLock(absName) { + os.Remove(absName) + } else { + return nil, fmt.Errorf("can't Lock file %q: has non-zero size", name) + } + } + f, err := os.OpenFile(absName, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_EXCL, 0666) + if err != nil { + return nil, fmt.Errorf("failed to create lock file %s %v", absName, err) + } + if err := json.NewEncoder(f).Encode(&pidLockMeta{OwnerPID: os.Getpid()}); err != nil { + return nil, err + } + return &lockCloser{f: f, abs: absName}, nil +} + +type pidLockMeta struct { + OwnerPID int +} + +func isStaleLock(path string) bool { + f, err := os.Open(path) + if err != nil { + return false + } + defer f.Close() + var meta pidLockMeta + if json.NewDecoder(f).Decode(&meta) != nil { + return false + } + if meta.OwnerPID == 0 { + return false + } + p, err := os.FindProcess(meta.OwnerPID) + if err != nil { + // e.g. on Windows + return true + } + // On unix, os.FindProcess always is true, so we have to send + // it a signal to see if it's alive. + if signalZero != nil { + if p.Signal(signalZero) != nil { + return true + } + } + return false +} + +var signalZero os.Signal // nil or set by lock_sigzero.go + +type lockCloser struct { + f *os.File + abs string + once sync.Once + err error +} + +func (lc *lockCloser) Close() error { + lc.once.Do(lc.close) + return lc.err +} + +func (lc *lockCloser) close() { + if err := lc.f.Close(); err != nil { + lc.err = err + } + if err := os.Remove(lc.abs); err != nil { + lc.err = err + } +} + +var ( + lockmu sync.Mutex + locked = map[string]bool{} // abs path -> true +) + +// unlocker is used by the darwin and linux implementations with fcntl +// advisory locks. +type unlocker struct { + f *os.File + abs string +} + +func (u *unlocker) Close() error { + lockmu.Lock() + // Remove is not necessary but it's nice for us to clean up. + // If we do do this, though, it needs to be before the + // u.f.Close below. + os.Remove(u.abs) + if err := u.f.Close(); err != nil { + return err + } + delete(locked, u.abs) + lockmu.Unlock() + return nil +} diff --git a/Godeps/_workspace/src/github.com/camlistore/lock/lock_appengine.go b/Godeps/_workspace/src/github.com/camlistore/lock/lock_appengine.go new file mode 100644 index 0000000..ab4cad6 --- /dev/null +++ b/Godeps/_workspace/src/github.com/camlistore/lock/lock_appengine.go @@ -0,0 +1,32 @@ +// +build appengine + +/* +Copyright 2013 The Go Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package lock + +import ( + "errors" + "io" +) + +func init() { + lockFn = lockAppEngine +} + +func lockAppEngine(name string) (io.Closer, error) { + return nil, errors.New("Lock not available on App Engine") +} diff --git a/Godeps/_workspace/src/github.com/camlistore/lock/lock_darwin_amd64.go b/Godeps/_workspace/src/github.com/camlistore/lock/lock_darwin_amd64.go new file mode 100644 index 0000000..9fea51f --- /dev/null +++ b/Godeps/_workspace/src/github.com/camlistore/lock/lock_darwin_amd64.go @@ -0,0 +1,80 @@ +// +build darwin,amd64 +// +build !appengine + +/* +Copyright 2013 The Go Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package lock + +import ( + "fmt" + "io" + "os" + "path/filepath" + "syscall" + "unsafe" +) + +func init() { + lockFn = lockFcntl +} + +func lockFcntl(name string) (io.Closer, error) { + abs, err := filepath.Abs(name) + if err != nil { + return nil, err + } + lockmu.Lock() + if locked[abs] { + lockmu.Unlock() + return nil, fmt.Errorf("file %q already locked", abs) + } + locked[abs] = true + lockmu.Unlock() + + fi, err := os.Stat(name) + if err == nil && fi.Size() > 0 { + return nil, fmt.Errorf("can't Lock file %q: has non-zero size", name) + } + + f, err := os.Create(name) + if err != nil { + return nil, fmt.Errorf("Lock Create of %s (abs: %s) failed: %v", name, abs, err) + } + + // This type matches C's "struct flock" defined in /usr/include/sys/fcntl.h. + // TODO: move this into the standard syscall package. + k := struct { + Start uint64 // sizeof(off_t): 8 + Len uint64 // sizeof(off_t): 8 + Pid uint32 // sizeof(pid_t): 4 + Type uint16 // sizeof(short): 2 + Whence uint16 // sizeof(short): 2 + }{ + Type: syscall.F_WRLCK, + Whence: uint16(os.SEEK_SET), + Start: 0, + Len: 0, // 0 means to lock the entire file. + Pid: uint32(os.Getpid()), + } + + _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, f.Fd(), uintptr(syscall.F_SETLK), uintptr(unsafe.Pointer(&k))) + if errno != 0 { + f.Close() + return nil, errno + } + return &unlocker{f, abs}, nil +} diff --git a/Godeps/_workspace/src/github.com/camlistore/lock/lock_freebsd.go b/Godeps/_workspace/src/github.com/camlistore/lock/lock_freebsd.go new file mode 100644 index 0000000..d3835d6 --- /dev/null +++ b/Godeps/_workspace/src/github.com/camlistore/lock/lock_freebsd.go @@ -0,0 +1,79 @@ +/* +Copyright 2013 The Go Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package lock + +import ( + "fmt" + "io" + "os" + "path/filepath" + "syscall" + "unsafe" +) + +func init() { + lockFn = lockFcntl +} + +func lockFcntl(name string) (io.Closer, error) { + abs, err := filepath.Abs(name) + if err != nil { + return nil, err + } + lockmu.Lock() + if locked[abs] { + lockmu.Unlock() + return nil, fmt.Errorf("file %q already locked", abs) + } + locked[abs] = true + lockmu.Unlock() + + fi, err := os.Stat(name) + if err == nil && fi.Size() > 0 { + return nil, fmt.Errorf("can't Lock file %q: has non-zero size", name) + } + + f, err := os.Create(name) + if err != nil { + return nil, err + } + + // This type matches C's "struct flock" defined in /usr/include/fcntl.h. + // TODO: move this into the standard syscall package. + k := struct { + Start int64 /* off_t starting offset */ + Len int64 /* off_t len = 0 means until end of file */ + Pid int32 /* pid_t lock owner */ + Type int16 /* short lock type: read/write, etc. */ + Whence int16 /* short type of l_start */ + Sysid int32 /* int remote system id or zero for local */ + }{ + Start: 0, + Len: 0, // 0 means to lock the entire file. + Pid: int32(os.Getpid()), + Type: syscall.F_WRLCK, + Whence: int16(os.SEEK_SET), + Sysid: 0, + } + + _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, f.Fd(), uintptr(syscall.F_SETLK), uintptr(unsafe.Pointer(&k))) + if errno != 0 { + f.Close() + return nil, errno + } + return &unlocker{f, abs}, nil +} diff --git a/Godeps/_workspace/src/github.com/camlistore/lock/lock_linux_amd64.go b/Godeps/_workspace/src/github.com/camlistore/lock/lock_linux_amd64.go new file mode 100644 index 0000000..3a7eb00 --- /dev/null +++ b/Godeps/_workspace/src/github.com/camlistore/lock/lock_linux_amd64.go @@ -0,0 +1,80 @@ +// +build linux,amd64 +// +build !appengine + +/* +Copyright 2013 The Go Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package lock + +import ( + "fmt" + "io" + "os" + "path/filepath" + "syscall" + "unsafe" +) + +func init() { + lockFn = lockFcntl +} + +func lockFcntl(name string) (io.Closer, error) { + abs, err := filepath.Abs(name) + if err != nil { + return nil, err + } + lockmu.Lock() + if locked[abs] { + lockmu.Unlock() + return nil, fmt.Errorf("file %q already locked", abs) + } + locked[abs] = true + lockmu.Unlock() + + fi, err := os.Stat(name) + if err == nil && fi.Size() > 0 { + return nil, fmt.Errorf("can't Lock file %q: has non-zero size", name) + } + + f, err := os.Create(name) + if err != nil { + return nil, err + } + + // This type matches C's "struct flock" defined in /usr/include/bits/fcntl.h. + // TODO: move this into the standard syscall package. + k := struct { + Type uint32 + Whence uint32 + Start uint64 + Len uint64 + Pid uint32 + }{ + Type: syscall.F_WRLCK, + Whence: uint32(os.SEEK_SET), + Start: 0, + Len: 0, // 0 means to lock the entire file. + Pid: uint32(os.Getpid()), + } + + _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, f.Fd(), uintptr(syscall.F_SETLK), uintptr(unsafe.Pointer(&k))) + if errno != 0 { + f.Close() + return nil, errno + } + return &unlocker{f, abs}, nil +} diff --git a/Godeps/_workspace/src/github.com/camlistore/lock/lock_linux_arm.go b/Godeps/_workspace/src/github.com/camlistore/lock/lock_linux_arm.go new file mode 100644 index 0000000..c2a0a10 --- /dev/null +++ b/Godeps/_workspace/src/github.com/camlistore/lock/lock_linux_arm.go @@ -0,0 +1,81 @@ +// +build linux,arm +// +build !appengine + +/* +Copyright 2013 The Go Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package lock + +import ( + "fmt" + "io" + "os" + "path/filepath" + "syscall" + "unsafe" +) + +func init() { + lockFn = lockFcntl +} + +func lockFcntl(name string) (io.Closer, error) { + abs, err := filepath.Abs(name) + if err != nil { + return nil, err + } + lockmu.Lock() + if locked[abs] { + lockmu.Unlock() + return nil, fmt.Errorf("file %q already locked", abs) + } + locked[abs] = true + lockmu.Unlock() + + fi, err := os.Stat(name) + if err == nil && fi.Size() > 0 { + return nil, fmt.Errorf("can't Lock file %q: has non-zero size", name) + } + + f, err := os.Create(name) + if err != nil { + return nil, err + } + + // This type matches C's "struct flock" defined in /usr/include/bits/fcntl.h. + // TODO: move this into the standard syscall package. + k := struct { + Type uint16 + Whence uint16 + Start uint32 + Len uint32 + Pid uint32 + }{ + Type: syscall.F_WRLCK, + Whence: uint16(os.SEEK_SET), + Start: 0, + Len: 0, // 0 means to lock the entire file. + Pid: uint32(os.Getpid()), + } + + const F_SETLK = 6 // actual value. syscall package is wrong: golang.org/issue/7059 + _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, f.Fd(), uintptr(F_SETLK), uintptr(unsafe.Pointer(&k))) + if errno != 0 { + f.Close() + return nil, errno + } + return &unlocker{f, abs}, nil +} diff --git a/Godeps/_workspace/src/github.com/camlistore/lock/lock_plan9.go b/Godeps/_workspace/src/github.com/camlistore/lock/lock_plan9.go new file mode 100644 index 0000000..bdf4e22 --- /dev/null +++ b/Godeps/_workspace/src/github.com/camlistore/lock/lock_plan9.go @@ -0,0 +1,55 @@ +/* +Copyright 2013 The Go Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package lock + +import ( + "fmt" + "io" + "os" + "path/filepath" +) + +func init() { + lockFn = lockPlan9 +} + +func lockPlan9(name string) (io.Closer, error) { + var f *os.File + abs, err := filepath.Abs(name) + if err != nil { + return nil, err + } + lockmu.Lock() + if locked[abs] { + lockmu.Unlock() + return nil, fmt.Errorf("file %q already locked", abs) + } + locked[abs] = true + lockmu.Unlock() + + fi, err := os.Stat(name) + if err == nil && fi.Size() > 0 { + return nil, fmt.Errorf("can't Lock file %q: has non-zero size", name) + } + + f, err = os.OpenFile(name, os.O_RDWR|os.O_CREATE, os.ModeExclusive|0644) + if err != nil { + return nil, fmt.Errorf("Lock Create of %s (abs: %s) failed: %v", name, abs, err) + } + + return &unlocker{f, abs}, nil +} diff --git a/Godeps/_workspace/src/github.com/camlistore/lock/lock_sigzero.go b/Godeps/_workspace/src/github.com/camlistore/lock/lock_sigzero.go new file mode 100644 index 0000000..fd3ba2d --- /dev/null +++ b/Godeps/_workspace/src/github.com/camlistore/lock/lock_sigzero.go @@ -0,0 +1,26 @@ +// +build !appengine +// +build linux darwin freebsd openbsd netbsd dragonfly + +/* +Copyright 2013 The Go Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package lock + +import "syscall" + +func init() { + signalZero = syscall.Signal(0) +} diff --git a/Godeps/_workspace/src/github.com/camlistore/lock/lock_test.go b/Godeps/_workspace/src/github.com/camlistore/lock/lock_test.go new file mode 100644 index 0000000..518d2f0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/camlistore/lock/lock_test.go @@ -0,0 +1,131 @@ +/* +Copyright 2013 The Go Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package lock + +import ( + "fmt" + "io/ioutil" + "log" + "os" + "os/exec" + "path/filepath" + "strconv" + "testing" +) + +func TestLock(t *testing.T) { + testLock(t, false) +} + +func TestLockPortable(t *testing.T) { + testLock(t, true) +} + +func TestLockInChild(t *testing.T) { + f := os.Getenv("TEST_LOCK_FILE") + if f == "" { + // not child + return + } + lock := Lock + if v, _ := strconv.ParseBool(os.Getenv("TEST_LOCK_PORTABLE")); v { + lock = lockPortable + } + + lk, err := lock(f) + if err != nil { + log.Fatalf("Lock failed: %v", err) + } + + if v, _ := strconv.ParseBool(os.Getenv("TEST_LOCK_CRASH")); v { + // Simulate a crash, or at least not unlocking the + // lock. We still exit 0 just to simplify the parent + // process exec code. + os.Exit(0) + } + lk.Close() +} + +func testLock(t *testing.T, portable bool) { + lock := Lock + if portable { + lock = lockPortable + } + + td, err := ioutil.TempDir("", "") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(td) + + path := filepath.Join(td, "foo.lock") + + childLock := func(crash bool) error { + cmd := exec.Command(os.Args[0], "-test.run=LockInChild$") + cmd.Env = []string{"TEST_LOCK_FILE=" + path} + if portable { + cmd.Env = append(cmd.Env, "TEST_LOCK_PORTABLE=1") + } + if crash { + cmd.Env = append(cmd.Env, "TEST_LOCK_CRASH=1") + } + out, err := cmd.CombinedOutput() + t.Logf("Child output: %q (err %v)", out, err) + if err != nil { + return fmt.Errorf("Child Process lock of %s failed: %v %s", path, err, out) + } + return nil + } + + t.Logf("Locking in crashing child...") + if err := childLock(true); err != nil { + t.Fatalf("first lock in child process: %v", err) + } + + t.Logf("Locking+unlocking in child...") + if err := childLock(false); err != nil { + t.Fatalf("lock in child process after crashing child: %v", err) + } + + t.Logf("Locking in parent...") + lk1, err := lock(path) + if err != nil { + t.Fatal(err) + } + + t.Logf("Again in parent...") + _, err = lock(path) + if err == nil { + t.Fatal("expected second lock to fail") + } + + t.Logf("Locking in child...") + if childLock(false) == nil { + t.Fatalf("expected lock in child process to fail") + } + + t.Logf("Unlocking lock in parent") + if err := lk1.Close(); err != nil { + t.Fatal(err) + } + + lk3, err := lock(path) + if err != nil { + t.Fatal(err) + } + lk3.Close() +} diff --git a/Godeps/_workspace/src/github.com/cznic/bufs/AUTHORS b/Godeps/_workspace/src/github.com/cznic/bufs/AUTHORS new file mode 100644 index 0000000..0078f5f --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/bufs/AUTHORS @@ -0,0 +1,11 @@ +# This file lists authors for copyright purposes. This file is distinct from +# the CONTRIBUTORS files. See the latter for an explanation. +# +# Names should be added to this file as: +# Name or Organization +# +# The email address is not required for organizations. +# +# Please keep the list sorted. + +Jan Mercl <0xjnml@gmail.com> diff --git a/Godeps/_workspace/src/github.com/cznic/bufs/CONTRIBUTORS b/Godeps/_workspace/src/github.com/cznic/bufs/CONTRIBUTORS new file mode 100644 index 0000000..5e86f06 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/bufs/CONTRIBUTORS @@ -0,0 +1,9 @@ +# This file lists people who contributed code to this repository. The AUTHORS +# file lists the copyright holders; this file lists people. +# +# Names should be added to this file like so: +# Name +# +# Please keep the list sorted. + +Jan Mercl <0xjnml@gmail.com> diff --git a/Godeps/_workspace/src/github.com/cznic/bufs/LICENSE b/Godeps/_workspace/src/github.com/cznic/bufs/LICENSE new file mode 100644 index 0000000..7d80fe2 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/bufs/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2014 The bufs Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the names of the authors nor the names of the +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Godeps/_workspace/src/github.com/cznic/bufs/Makefile b/Godeps/_workspace/src/github.com/cznic/bufs/Makefile new file mode 100644 index 0000000..c98c23d --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/bufs/Makefile @@ -0,0 +1,31 @@ +# Copyright 2014 The bufs Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +all: clean + go fmt + go test -i + go test + go build + go vet + golint . + go install + make todo + +todo: + @grep -n ^[[:space:]]*_[[:space:]]*=[[:space:]][[:alnum:]] *.go || true + @grep -n TODO *.go || true + @grep -n FIXME *.go || true + @grep -n BUG *.go || true + +clean: + rm -f bufs.test mem.out *~ + +demo: + go test -bench . -benchmem + go test -c + ./bufs.test -test.v -test.run Foo -test.memprofile mem.out \ + -test.memprofilerate 1 + go tool pprof bufs.test mem.out --alloc_space --nodefraction 0.0001 \ + --edgefraction 0 -web + @echo "Note: Foo vs FooBufs allocated memory is in hundreds of MBs vs 8 kB." diff --git a/Godeps/_workspace/src/github.com/cznic/bufs/README.md b/Godeps/_workspace/src/github.com/cznic/bufs/README.md new file mode 100644 index 0000000..3f3d56f --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/bufs/README.md @@ -0,0 +1,8 @@ +bufs +==== + +Package bufs implements a simple buffer cache. + + installation: go get github.com/cznic/bufs + +documentation: http://godoc.org/github.com/cznic/bufs diff --git a/Godeps/_workspace/src/github.com/cznic/bufs/bufs.go b/Godeps/_workspace/src/github.com/cznic/bufs/bufs.go new file mode 100644 index 0000000..f4e0eee --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/bufs/bufs.go @@ -0,0 +1,391 @@ +// Copyright 2014 The bufs 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 bufs implements a simple buffer cache. +// +// The intended use scheme is like: +// +// type Foo struct { +// buffers bufs.Buffers +// ... +// } +// +// // Bar can call Qux, but not the other way around (in this example). +// const maxFooDepth = 2 +// +// func NewFoo() *Foo { +// return &Foo{buffers: bufs.New(maxFooDepth), ...} +// } +// +// func (f *Foo) Bar(n int) { +// buf := f.buffers.Alloc(n) // needed locally for computation and/or I/O +// defer f.buffers.Free() +// ... +// f.Qux(whatever) +// } +// +// func (f *Foo) Qux(n int) { +// buf := f.buffers.Alloc(n) // needed locally for computation and/or I/O +// defer f.buffers.Free() +// ... +// } +// +// The whole idea behind 'bufs' is that when calling e.g. Foo.Bar N times, then +// normally, without using 'bufs', there will be 2*N (in this example) []byte +// buffers allocated. While using 'bufs', only 2 buffers (in this example) +// will ever be created. For large N it can be a substantial difference. +// +// It's not a good idea to use Buffers to cache too big buffers. The cost of +// having a cached buffer is that the buffer is naturally not eligible for +// garbage collection. Of course, that holds only while the Foo instance is +// reachable, in the above example. +// +// The buffer count limit is intentionally "hard" (read panicking), although +// configurable in New(). The rationale is to prevent recursive calls, using +// Alloc, to cause excessive, "static" memory consumption. Tune the limit +// carefully or do not use Buffers from within [mutually] recursive functions +// where the nesting depth is not realistically bounded to some rather small +// number. +// +// Buffers cannot guarantee improvements to you program performance. There may +// be a gain in case where they fit well. Firm grasp on what your code is +// actually doing, when and in what order is essential to proper use of +// Buffers. It's _highly_ recommended to first do profiling and memory +// profiling before even thinking about using 'bufs'. The real world example, +// and cause for this package, was a first correct, yet no optimizations done +// version of a program; producing few MB of useful data while allocating 20+GB +// of memory. Of course the garbage collector properly kicked in, yet the +// memory abuse caused ~80+% of run time to be spent memory management. The +// program _was_ expected to be slow in its still development phase, but the +// bottleneck was guessed to be in I/O. Actually the hard disk was waiting for +// the billions bytes being allocated and zeroed. Garbage collect on low +// memory, rinse and repeat. +// +// In the provided tests, TestFoo and TestFooBufs do the same simulated work, +// except the later uses Buffers while the former does not. Suggested test runs +// which show the differences: +// +// $ go test -bench . -benchmem +// +// or +// +// $ go test -c +// $ ./bufs.test -test.v -test.run Foo -test.memprofile mem.out -test.memprofilerate 1 +// $ go tool pprof bufs.test mem.out --alloc_space --nodefraction 0.0001 --edgefraction 0 -web +// $ # Note: Foo vs FooBufs allocated memory is in hundreds of MBs vs 8 kB. +// +// or +// +// $ make demo # same as all of the above +// +// +// NOTE: Alloc/Free calls must be properly nested in the same way as in for +// example BeginTransaction/EndTransaction pairs. If your code can panic then +// the pairing should be enforced by deferred calls. +// +// NOTE: Buffers objects do not allocate any space until requested by Alloc, +// the mechanism works on demand only. +// +// FAQ: Why the 'bufs' package name? +// +// Package name 'bufs' was intentionally chosen instead of the perhaps more +// conventional 'buf'. There are already too many 'buf' named things in the +// code out there and that'll be a source of a lot of trouble. It's a bit +// similar situation as in the case of package "strings" (not "string"). +package bufs + +import ( + "errors" + "sort" + "sync" +) + +// Buffers type represents a buffer ([]byte) cache. +// +// NOTE: Do not modify Buffers directly, use only its methods. Do not create +// additional values (copies) of Buffers, that'll break its functionality. Use +// a pointer instead to refer to a single instance from different +// places/scopes. +type Buffers [][]byte + +// New returns a newly created instance of Buffers with a maximum capacity of n +// buffers. +// +// NOTE: 'bufs.New(n)' is the same as 'make(bufs.Buffers, n)'. +func New(n int) Buffers { + return make(Buffers, n) +} + +// Alloc will return a buffer such that len(r) == n. It will firstly try to +// find an existing and unused buffer of big enough size. Only when there is no +// such, then one of the buffer slots is reallocated to a bigger size. +// +// It's okay to use append with buffers returned by Alloc. But it can cause +// allocation in that case and will again be producing load for the garbage +// collector. The best use of Alloc is for I/O buffers where the needed size of +// the buffer is figured out at some point of the code path in a 'final size' +// sense. Another real world example are compression/decompression buffers. +// +// NOTE: The buffer returned by Alloc _is not_ zeroed. That's okay for e.g. +// passing a buffer to io.Reader. If you need a zeroed buffer use Calloc. +// +// NOTE: Buffers returned from Alloc _must not_ be exposed/returned to your +// clients. Those buffers are intended to be used strictly internally, within +// the methods of some "object". +// +// NOTE: Alloc will panic if there are no buffers (buffer slots) left. +func (p *Buffers) Alloc(n int) (r []byte) { + b := *p + if len(b) == 0 { + panic(errors.New("Buffers.Alloc: out of buffers")) + } + + biggest, best, biggestI, bestI := -1, -1, -1, -1 + for i, v := range b { + //ln := len(v) + // The above was correct, buts it's just confusing. It worked + // because not the buffers, but slices of them are returned in + // the 'if best >= n' code path. + ln := cap(v) + + if ln >= biggest { + biggest, biggestI = ln, i + } + + if ln >= n && (bestI < 0 || best > ln) { + best, bestI = ln, i + if ln == n { + break + } + } + } + + last := len(b) - 1 + if best >= n { + r = b[bestI] + b[last], b[bestI] = b[bestI], b[last] + *p = b[:last] + return r[:n] + } + + r = make([]byte, n, overCommit(n)) + b[biggestI] = r + b[last], b[biggestI] = b[biggestI], b[last] + *p = b[:last] + return +} + +// Calloc will acquire a buffer using Alloc and then clears it to zeros. The +// zeroing goes up to n, not cap(r). +func (p *Buffers) Calloc(n int) (r []byte) { + r = p.Alloc(n) + for i := range r { + r[i] = 0 + } + return +} + +// Free makes the lastly allocated by Alloc buffer free (available) again for +// Alloc. +// +// NOTE: Improper Free invocations, like in the sequence {New, Alloc, Free, +// Free}, will panic. +func (p *Buffers) Free() { + b := *p + b = b[:len(b)+1] + *p = b +} + +// Stats reports memory consumed by Buffers, without accounting for some +// (smallish) additional overhead. +func (p *Buffers) Stats() (bytes int) { + b := *p + b = b[:cap(b)] + for _, v := range b { + bytes += cap(v) + } + return +} + +// Cache caches buffers ([]byte). A zero value of Cache is ready for use. +// +// NOTE: Do not modify a Cache directly, use only its methods. Do not create +// additional values (copies) of a Cache, that'll break its functionality. Use +// a pointer instead to refer to a single instance from different +// places/scopes. +type Cache [][]byte + +// Get returns a buffer ([]byte) of length n. If no such buffer is cached then +// a biggest cached buffer is resized to have length n and returned. If there +// are no cached items at all, Get returns a newly allocated buffer. +// +// In other words the cache policy is: +// +// - If the cache is empty, the buffer must be newly created and returned. +// Cache remains empty. +// +// - If a buffer of sufficient size is found in the cache, remove it from the +// cache and return it. +// +// - Otherwise the cache is non empty, but no cached buffer is big enough. +// Enlarge the biggest cached buffer, remove it from the cache and return it. +// This provide cached buffers size adjustment based on demand. +// +// In short, if the cache is not empty, Get guarantees to make it always one +// item less. This rules prevent uncontrolled cache grow in some scenarios. +// The older policy was not preventing that. Another advantage is better cached +// buffers sizes "auto tuning", although not in every possible use case. +// +// NOTE: The buffer returned by Get _is not guaranteed_ to be zeroed. That's +// okay for e.g. passing a buffer to io.Reader. If you need a zeroed buffer +// use Cget. +func (c *Cache) Get(n int) []byte { + r, _ := c.get(n) + return r +} + +func (c *Cache) get(n int) (r []byte, isZeroed bool) { + s := *c + lens := len(s) + if lens == 0 { + r, isZeroed = make([]byte, n, overCommit(n)), true + return + } + + i := sort.Search(lens, func(x int) bool { return len(s[x]) >= n }) + if i == lens { + i-- + s[i] = make([]byte, n, overCommit(n)) + } + r = s[i][:n] + copy(s[i:], s[i+1:]) + s[lens-1] = nil + s = s[:lens-1] + *c = s + return r, false +} + +// Cget will acquire a buffer using Get and then clears it to zeros. The +// zeroing goes up to n, not cap(r). +func (c *Cache) Cget(n int) (r []byte) { + r, ok := c.get(n) + if ok { + return + } + + for i := range r { + r[i] = 0 + } + return +} + +// Put caches b for possible later reuse (via Get). No other references to b's +// backing array may exist. Otherwise a big mess is sooner or later inevitable. +func (c *Cache) Put(b []byte) { + b = b[:cap(b)] + lenb := len(b) + if lenb == 0 { + return + } + + s := *c + lens := len(s) + i := sort.Search(lens, func(x int) bool { return len(s[x]) >= lenb }) + s = append(s, nil) + copy(s[i+1:], s[i:]) + s[i] = b + *c = s + return +} + +// Stats reports memory consumed by a Cache, without accounting for some +// (smallish) additional overhead. 'n' is the number of cached buffers, bytes +// is their combined capacity. +func (c Cache) Stats() (n, bytes int) { + n = len(c) + for _, v := range c { + bytes += cap(v) + } + return +} + +// CCache is a Cache which is safe for concurrent use by multiple goroutines. +type CCache struct { + c Cache + mu sync.Mutex +} + +// Get returns a buffer ([]byte) of length n. If no such buffer is cached then +// a biggest cached buffer is resized to have length n and returned. If there +// are no cached items at all, Get returns a newly allocated buffer. +// +// In other words the cache policy is: +// +// - If the cache is empty, the buffer must be newly created and returned. +// Cache remains empty. +// +// - If a buffer of sufficient size is found in the cache, remove it from the +// cache and return it. +// +// - Otherwise the cache is non empty, but no cached buffer is big enough. +// Enlarge the biggest cached buffer, remove it from the cache and return it. +// This provide cached buffers size adjustment based on demand. +// +// In short, if the cache is not empty, Get guarantees to make it always one +// item less. This rules prevent uncontrolled cache grow in some scenarios. +// The older policy was not preventing that. Another advantage is better cached +// buffers sizes "auto tuning", although not in every possible use case. +// +// NOTE: The buffer returned by Get _is not guaranteed_ to be zeroed. That's +// okay for e.g. passing a buffer to io.Reader. If you need a zeroed buffer +// use Cget. +func (c *CCache) Get(n int) []byte { + c.mu.Lock() + r, _ := c.c.get(n) + c.mu.Unlock() + return r +} + +// Cget will acquire a buffer using Get and then clears it to zeros. The +// zeroing goes up to n, not cap(r). +func (c *CCache) Cget(n int) (r []byte) { + c.mu.Lock() + r = c.c.Cget(n) + c.mu.Unlock() + return +} + +// Put caches b for possible later reuse (via Get). No other references to b's +// backing array may exist. Otherwise a big mess is sooner or later inevitable. +func (c *CCache) Put(b []byte) { + c.mu.Lock() + c.c.Put(b) + c.mu.Unlock() +} + +// Stats reports memory consumed by a Cache, without accounting for some +// (smallish) additional overhead. 'n' is the number of cached buffers, bytes +// is their combined capacity. +func (c *CCache) Stats() (n, bytes int) { + c.mu.Lock() + n, bytes = c.c.Stats() + c.mu.Unlock() + return +} + +// GCache is a ready to use global instance of a CCache. +var GCache CCache + +func overCommit(n int) int { + switch { + case n < 8: + return 8 + case n < 1e5: + return 2 * n + case n < 1e6: + return 3 * n / 2 + default: + return n + } +} diff --git a/Godeps/_workspace/src/github.com/cznic/bufs/bufs_test.go b/Godeps/_workspace/src/github.com/cznic/bufs/bufs_test.go new file mode 100644 index 0000000..62400b0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/bufs/bufs_test.go @@ -0,0 +1,174 @@ +// Copyright 2014 The bufs 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 bufs + +import ( + "fmt" + "path" + "runtime" + "testing" +) + +var dbg = func(s string, va ...interface{}) { + _, fn, fl, _ := runtime.Caller(1) + fmt.Printf("%s:%d: ", path.Base(fn), fl) + fmt.Printf(s, va...) + fmt.Println() +} + +func Test0(t *testing.T) { + b := New(0) + defer func() { + recover() + }() + + b.Alloc(1) + t.Fatal("unexpected success") +} + +func Test1(t *testing.T) { + b := New(1) + expected := false + defer func() { + if e := recover(); e != nil && !expected { + t.Fatal(fmt.Errorf("%v", e)) + } + }() + + b.Alloc(1) + expected = true + b.Alloc(1) + t.Fatal("unexpected success") +} + +func Test2(t *testing.T) { + b := New(1) + expected := false + defer func() { + if e := recover(); e != nil && !expected { + t.Fatal(fmt.Errorf("%v", e)) + } + }() + + b.Alloc(1) + b.Free() + b.Alloc(1) + expected = true + b.Alloc(1) + t.Fatal("unexpected success") +} + +func Test3(t *testing.T) { + b := New(1) + expected := false + defer func() { + if e := recover(); e != nil && !expected { + t.Fatal(fmt.Errorf("%v", e)) + } + }() + + b.Alloc(1) + b.Free() + expected = true + b.Free() + t.Fatal("unexpected success") +} + +const ( + N = 1e5 + bufSize = 1 << 12 +) + +type Foo struct { + result []byte +} + +func NewFoo() *Foo { + return &Foo{} +} + +func (f *Foo) Bar(n int) { + buf := make([]byte, n) + sum := 0 + for _, v := range buf { + sum += int(v) + } + f.result = append(f.result, byte(sum)) + f.Qux(n) +} + +func (f *Foo) Qux(n int) { + buf := make([]byte, n) + sum := 0 + for _, v := range buf { + sum += int(v) + } + f.result = append(f.result, byte(sum)) +} + +type FooBufs struct { + buffers Buffers + result []byte +} + +const maxFooDepth = 2 + +func NewFooBufs() *FooBufs { + return &FooBufs{buffers: New(maxFooDepth)} +} + +func (f *FooBufs) Bar(n int) { + buf := f.buffers.Alloc(n) + defer f.buffers.Free() + + sum := 0 + for _, v := range buf { + sum += int(v) + } + f.result = append(f.result, byte(sum)) + f.Qux(n) +} + +func (f *FooBufs) Qux(n int) { + buf := f.buffers.Alloc(n) + defer f.buffers.Free() + + sum := 0 + for _, v := range buf { + sum += int(v) + } + f.result = append(f.result, byte(sum)) +} + +func TestFoo(t *testing.T) { + foo := NewFoo() + for i := 0; i < N; i++ { + foo.Bar(bufSize) + } +} + +func TestFooBufs(t *testing.T) { + foo := NewFooBufs() + for i := 0; i < N; i++ { + foo.Bar(bufSize) + } + t.Log("buffers.Stats()", foo.buffers.Stats()) +} + +func BenchmarkFoo(b *testing.B) { + b.SetBytes(2 * bufSize) + foo := NewFoo() + for i := 0; i < b.N; i++ { + foo.Bar(bufSize) + } +} + +func BenchmarkFooBufs(b *testing.B) { + b.SetBytes(2 * bufSize) + foo := NewFooBufs() + for i := 0; i < b.N; i++ { + foo.Bar(bufSize) + } +} diff --git a/Godeps/_workspace/src/github.com/cznic/exp/lldb/2pc.go b/Godeps/_workspace/src/github.com/cznic/exp/lldb/2pc.go new file mode 100644 index 0000000..b4b203a --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/exp/lldb/2pc.go @@ -0,0 +1,324 @@ +// Copyright 2014 The lldb Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Two Phase Commit & Structural ACID + +package lldb + +import ( + "bufio" + "encoding/binary" + "fmt" + "io" + "os" + + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/fileutil" + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/mathutil" +) + +var _ Filer = &ACIDFiler0{} // Ensure ACIDFiler0 is a Filer + +type acidWrite struct { + b []byte + off int64 +} + +type acidWriter0 ACIDFiler0 + +func (a *acidWriter0) WriteAt(b []byte, off int64) (n int, err error) { + f := (*ACIDFiler0)(a) + if f.bwal == nil { // new epoch + f.data = f.data[:0] + f.bwal = bufio.NewWriter(f.wal) + if err = a.writePacket([]interface{}{wpt00Header, walTypeACIDFiler0, ""}); err != nil { + return + } + } + + if err = a.writePacket([]interface{}{wpt00WriteData, b, off}); err != nil { + return + } + + f.data = append(f.data, acidWrite{b, off}) + return len(b), nil +} + +func (a *acidWriter0) writePacket(items []interface{}) (err error) { + f := (*ACIDFiler0)(a) + b, err := EncodeScalars(items...) + if err != nil { + return + } + + var b4 [4]byte + binary.BigEndian.PutUint32(b4[:], uint32(len(b))) + if _, err = f.bwal.Write(b4[:]); err != nil { + return + } + + if _, err = f.bwal.Write(b); err != nil { + return + } + + if m := (4 + len(b)) % 16; m != 0 { + var pad [15]byte + _, err = f.bwal.Write(pad[:16-m]) + } + return +} + +// WAL Packet Tags +const ( + wpt00Header = iota + wpt00WriteData + wpt00Checkpoint +) + +const ( + walTypeACIDFiler0 = iota +) + +// ACIDFiler0 is a very simple, synchronous implementation of 2PC. It uses a +// single write ahead log file to provide the structural atomicity +// (BeginUpdate/EndUpdate/Rollback) and durability (DB can be recovered from +// WAL if a crash occurred). +// +// ACIDFiler0 is a Filer. +// +// NOTE: Durable synchronous 2PC involves three fsyncs in this implementation +// (WAL, DB, zero truncated WAL). Where possible, it's recommended to collect +// transactions for, say one second before performing the two phase commit as +// the typical performance for rotational hard disks is about few tens of +// fsyncs per second atmost. For an example of such collective transaction +// approach please see the colecting FSM STT in Dbm's documentation[1]. +// +// [1]: http://godoc.org/github.com/cznic/exp/dbm +type ACIDFiler0 struct { + *RollbackFiler + wal *os.File + bwal *bufio.Writer + data []acidWrite + testHook bool // keeps WAL untruncated (once) + peakWal int64 // tracks WAL maximum used size + peakBitFilerPages int // track maximum transaction memory +} + +// NewACIDFiler0 returns a newly created ACIDFiler0 with WAL in wal. +// +// If the WAL is zero sized then a previous clean shutdown of db is taken for +// granted and no recovery procedure is taken. +// +// If the WAL is of non zero size then it is checked for having a +// commited/fully finished transaction not yet been reflected in db. If such +// transaction exists it's committed to db. If the recovery process finishes +// successfully, the WAL is truncated to zero size and fsync'ed prior to return +// from NewACIDFiler0. +func NewACIDFiler(db Filer, wal *os.File) (r *ACIDFiler0, err error) { + fi, err := wal.Stat() + if err != nil { + return + } + + r = &ACIDFiler0{wal: wal} + + if fi.Size() != 0 { + if err = r.recoverDb(db); err != nil { + return + } + } + + acidWriter := (*acidWriter0)(r) + + if r.RollbackFiler, err = NewRollbackFiler( + db, + func(sz int64) (err error) { + // Checkpoint + if err = acidWriter.writePacket([]interface{}{wpt00Checkpoint, sz}); err != nil { + return + } + + if err = r.bwal.Flush(); err != nil { + return + } + + r.bwal = nil + + if err = r.wal.Sync(); err != nil { + return + } + + wfi, err := r.wal.Stat() + switch err != nil { + case true: + // unexpected, but ignored + case false: + r.peakWal = mathutil.MaxInt64(wfi.Size(), r.peakWal) + } + + // Phase 1 commit complete + + for _, v := range r.data { + if _, err := db.WriteAt(v.b, v.off); err != nil { + return err + } + } + + if err = db.Truncate(sz); err != nil { + return + } + + if err = db.Sync(); err != nil { + return + } + + // Phase 2 commit complete + + if !r.testHook { + if err = r.wal.Truncate(0); err != nil { + return + } + + if _, err = r.wal.Seek(0, 0); err != nil { + return + } + } + + r.testHook = false + return r.wal.Sync() + + }, + acidWriter, + ); err != nil { + return + } + + return r, nil +} + +// PeakWALSize reports the maximum size WAL has ever used. +func (a ACIDFiler0) PeakWALSize() int64 { + return a.peakWal +} + +func (a *ACIDFiler0) readPacket(f *bufio.Reader) (items []interface{}, err error) { + var b4 [4]byte + n, err := io.ReadAtLeast(f, b4[:], 4) + if n != 4 { + return + } + + ln := int(binary.BigEndian.Uint32(b4[:])) + m := (4 + ln) % 16 + padd := (16 - m) % 16 + b := make([]byte, ln+padd) + if n, err = io.ReadAtLeast(f, b, len(b)); n != len(b) { + return + } + + return DecodeScalars(b[:ln]) +} + +func (a *ACIDFiler0) recoverDb(db Filer) (err error) { + fi, err := a.wal.Stat() + if err != nil { + return &ErrILSEQ{Type: ErrInvalidWAL, Name: a.wal.Name(), More: err} + } + + if sz := fi.Size(); sz%16 != 0 { + return &ErrILSEQ{Type: ErrFileSize, Name: a.wal.Name(), Arg: sz} + } + + f := bufio.NewReader(a.wal) + items, err := a.readPacket(f) + if err != nil { + return + } + + if len(items) != 3 || items[0] != int64(wpt00Header) || items[1] != int64(walTypeACIDFiler0) { + return &ErrILSEQ{Type: ErrInvalidWAL, Name: a.wal.Name(), More: fmt.Sprintf("invalid packet items %#v", items)} + } + + tr := NewBTree(nil) + + for { + items, err = a.readPacket(f) + if err != nil { + return + } + + if len(items) < 2 { + return &ErrILSEQ{Type: ErrInvalidWAL, Name: a.wal.Name(), More: fmt.Sprintf("too few packet items %#v", items)} + } + + switch items[0] { + case int64(wpt00WriteData): + if len(items) != 3 { + return &ErrILSEQ{Type: ErrInvalidWAL, Name: a.wal.Name(), More: fmt.Sprintf("invalid data packet items %#v", items)} + } + + b, off := items[1].([]byte), items[2].(int64) + var key [8]byte + binary.BigEndian.PutUint64(key[:], uint64(off)) + if err = tr.Set(key[:], b); err != nil { + return + } + case int64(wpt00Checkpoint): + var b1 [1]byte + if n, err := f.Read(b1[:]); n != 0 || err == nil { + return &ErrILSEQ{Type: ErrInvalidWAL, Name: a.wal.Name(), More: fmt.Sprintf("checkpoint n %d, err %v", n, err)} + } + + if len(items) != 2 { + return &ErrILSEQ{Type: ErrInvalidWAL, Name: a.wal.Name(), More: fmt.Sprintf("checkpoint packet invalid items %#v", items)} + } + + sz := items[1].(int64) + enum, err := tr.seekFirst() + if err != nil { + return err + } + + for { + k, v, err := enum.current() + if err != nil { + if fileutil.IsEOF(err) { + break + } + + return err + } + + if _, err = db.WriteAt(v, int64(binary.BigEndian.Uint64(k))); err != nil { + return err + } + + if err = enum.next(); err != nil { + if fileutil.IsEOF(err) { + break + } + + return err + } + } + + if err = db.Truncate(sz); err != nil { + return err + } + + if err = db.Sync(); err != nil { + return err + } + + // Recovery complete + + if err = a.wal.Truncate(0); err != nil { + return err + } + + return a.wal.Sync() + default: + return &ErrILSEQ{Type: ErrInvalidWAL, Name: a.wal.Name(), More: fmt.Sprintf("packet tag %v", items[0])} + } + } +} diff --git a/Godeps/_workspace/src/github.com/cznic/exp/lldb/2pc_docs.go b/Godeps/_workspace/src/github.com/cznic/exp/lldb/2pc_docs.go new file mode 100644 index 0000000..02c993b --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/exp/lldb/2pc_docs.go @@ -0,0 +1,44 @@ +// Copyright 2014 The lldb Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +/* + +Anatomy of a WAL file + +WAL file + A sequence of packets + +WAL packet, parts in slice notation + [0:4], 4 bytes: N uint32 // network byte order + [4:4+N], N bytes: payload []byte // gb encoded scalars + +Packets, including the 4 byte 'size' prefix, MUST BE padded to size == 0 (mod +16). The values of the padding bytes MUST BE zero. + +Encoded scalars first item is a packet type number (packet tag). The meaning of +any other item(s) of the payload depends on the packet tag. + +Packet definitions + + {wpt00Header int, typ int, s string} + typ: Must be zero (ACIDFiler0 file). + s: Any comment string, empty string is okay. + + This packet must be present only once - as the first packet of + a WAL file. + + {wpt00WriteData int, b []byte, off int64} + Write data (WriteAt(b, off)). + + {wpt00Checkpoint int, sz int64} + Checkpoint (Truncate(sz)). + + This packet must be present only once - as the last packet of + a WAL file. + +*/ + +package lldb + +//TODO optimize bitfiler/wal/2pc data above final size diff --git a/Godeps/_workspace/src/github.com/cznic/exp/lldb/2pc_test.go b/Godeps/_workspace/src/github.com/cznic/exp/lldb/2pc_test.go new file mode 100644 index 0000000..81dd8db --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/exp/lldb/2pc_test.go @@ -0,0 +1,285 @@ +// Copyright 2014 The lldb Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Two Phase Commit & Structural ACID + +package lldb + +import ( + "bytes" + "encoding/binary" + "io/ioutil" + "math/rand" + "os" + "testing" + + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/mathutil" +) + +var _ Filer = &truncFiler{} + +type truncFiler struct { + f Filer + fake *MemFiler + totalWritten int // Including silently dropped + realWritten int + limit int // -1: unlimited, n: silently stop writing after limit bytes +} + +func NewTruncFiler(f Filer, limit int) *truncFiler { + return &truncFiler{f: f, fake: NewMemFiler(), limit: limit} +} + +func (f *truncFiler) BeginUpdate() error { panic("internal error") } +func (f *truncFiler) Close() error { return f.f.Close() } +func (f *truncFiler) EndUpdate() error { panic("internal error") } +func (f *truncFiler) Name() string { return f.f.Name() } +func (f *truncFiler) PunchHole(off, sz int64) error { panic("internal error") } +func (f *truncFiler) ReadAt(b []byte, off int64) (int, error) { return f.fake.ReadAt(b, off) } +func (f *truncFiler) Rollback() error { panic("internal error") } +func (f *truncFiler) Size() (int64, error) { return f.fake.Size() } +func (f *truncFiler) Sync() error { return f.f.Sync() } + +func (f *truncFiler) Truncate(sz int64) error { + f.fake.Truncate(sz) + return f.f.Truncate(sz) +} + +func (f *truncFiler) WriteAt(b []byte, off int64) (n int, err error) { + rq := len(b) + n = f.totalWritten + if lim := f.limit; lim >= 0 && n+rq > lim { + over := n + rq - lim + rq -= over + rq = mathutil.Max(rq, 0) + } + + if n, err = f.fake.WriteAt(b, off); err != nil { + return + } + + f.totalWritten += n + if rq != 0 { + n, err := f.f.WriteAt(b[:rq], off) + if err != nil { + return n, err + } + f.realWritten += n + } + return +} + +// Verify memory BTrees don't have maxRq limits. +func TestACID0MemBTreeCaps(t *testing.T) { + rng := rand.New(rand.NewSource(42)) + tr := NewBTree(nil) + b := make([]byte, 2*maxRq) + for i := range b { + b[i] = byte(rng.Int()) + } + + if err := tr.Set(nil, b); err != nil { + t.Fatal(len(b), err) + } + + g, err := tr.Get(nil, nil) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(g, b) { + t.Fatal("data mismatach") + } +} + +func TestACIDFiler0(t *testing.T) { + const SZ = 1 << 17 + + // Phase 1: Create a DB, fill with it with data. + + wal, err := ioutil.TempFile("", "test-acidfiler0-wal-") + if err != nil { + t.Fatal(err) + } + + if !*oKeep { + defer os.Remove(wal.Name()) + } + + db, err := ioutil.TempFile("", "test-acidfiler0-db-") + if err != nil { + t.Fatal(err) + } + + dbName := db.Name() + if !*oKeep { + defer os.Remove(db.Name()) + } + + realFiler := NewSimpleFileFiler(db) + truncFiler := NewTruncFiler(realFiler, -1) + acidFiler, err := NewACIDFiler(truncFiler, wal) + if err != nil { + t.Error(err) + return + } + + if err = acidFiler.BeginUpdate(); err != nil { + t.Error(err) + return + } + + a, err := NewAllocator(acidFiler, &Options{}) + if err != nil { + t.Error(err) + return + } + + a.Compress = true + + tr, h, err := CreateBTree(a, nil) + if h != 1 || err != nil { + t.Error(h, err) + return + } + + rng := rand.New(rand.NewSource(42)) + var key, val [8]byte + ref := map[int64]int64{} + + for { + sz, err := acidFiler.Size() + if err != nil { + t.Error(err) + return + } + + if sz > SZ { + break + } + + k, v := rng.Int63(), rng.Int63() + ref[k] = v + binary.BigEndian.PutUint64(key[:], uint64(k)) + binary.BigEndian.PutUint64(val[:], uint64(v)) + if err := tr.Set(key[:], val[:]); err != nil { + t.Error(err) + return + } + } + + acidFiler.testHook = true // keep WAL + + if err := acidFiler.EndUpdate(); err != nil { + t.Error(err) + return + } + + if err := acidFiler.Close(); err != nil { + t.Error(err) + return + } + + if err := wal.Sync(); err != nil { + t.Error(err) + return + } + + if _, err = wal.Seek(0, 0); err != nil { + t.Error(err) + return + } + + // Phase 2: Reopen and verify structure and data. + db, err = os.OpenFile(dbName, os.O_RDWR, 0666) + if err != nil { + t.Error(err) + return + } + + filer := NewSimpleFileFiler(db) + a, err = NewAllocator(filer, &Options{}) + if err != nil { + t.Error(err) + return + } + + if err = a.Verify(NewMemFiler(), nil, nil); err != nil { + t.Error(err) + return + } + + tr, err = OpenBTree(a, nil, 1) + for k, v := range ref { + binary.BigEndian.PutUint64(key[:], uint64(k)) + binary.BigEndian.PutUint64(val[:], uint64(v)) + var b []byte + b, err = tr.Get(b, key[:]) + if err != nil || b == nil || !bytes.Equal(b, val[:]) { + t.Error(err, b, val[:]) + return + } + } + + okImage, err := ioutil.ReadFile(dbName) + if err != nil { + t.Error(err) + return + } + + // Phase 3: Simulate a crash + sz, err := filer.Size() + if err != nil { + t.Error(err) + return + } + + sz /= 2 + if err := db.Truncate(sz); err != nil { + t.Error(err) + return + } + + z := make([]byte, sz/3) + n, err := db.WriteAt(z, sz/3) + if n != len(z) { + t.Error(n, err) + return + } + + if err := db.Sync(); err != nil { + t.Error(err) + return + } + + // Phase 4: Open the corrupted DB + filer = NewSimpleFileFiler(db) + acidFiler, err = NewACIDFiler(filer, wal) + if err != nil { + t.Error(err) + return + } + + if err = acidFiler.Sync(); err != nil { + t.Error(err) + return + } + + if err = acidFiler.Close(); err != nil { + t.Error(err) + return + } + + // Phase 5: Verify DB was recovered. + newImage, err := ioutil.ReadFile(dbName) + if err != nil { + t.Error(err) + return + } + + if !bytes.Equal(okImage, newImage) { + t.Error(err) + return + } +} diff --git a/Godeps/_workspace/src/github.com/cznic/exp/lldb/AUTHORS b/Godeps/_workspace/src/github.com/cznic/exp/lldb/AUTHORS new file mode 100644 index 0000000..0078f5f --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/exp/lldb/AUTHORS @@ -0,0 +1,11 @@ +# This file lists authors for copyright purposes. This file is distinct from +# the CONTRIBUTORS files. See the latter for an explanation. +# +# Names should be added to this file as: +# Name or Organization +# +# The email address is not required for organizations. +# +# Please keep the list sorted. + +Jan Mercl <0xjnml@gmail.com> diff --git a/Godeps/_workspace/src/github.com/cznic/exp/lldb/CONTRIBUTORS b/Godeps/_workspace/src/github.com/cznic/exp/lldb/CONTRIBUTORS new file mode 100644 index 0000000..5e86f06 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/exp/lldb/CONTRIBUTORS @@ -0,0 +1,9 @@ +# This file lists people who contributed code to this repository. The AUTHORS +# file lists the copyright holders; this file lists people. +# +# Names should be added to this file like so: +# Name +# +# Please keep the list sorted. + +Jan Mercl <0xjnml@gmail.com> diff --git a/Godeps/_workspace/src/github.com/cznic/exp/lldb/LICENSE b/Godeps/_workspace/src/github.com/cznic/exp/lldb/LICENSE new file mode 100644 index 0000000..27e4447 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/exp/lldb/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2014 The lldb Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the names of the authors nor the names of the +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Godeps/_workspace/src/github.com/cznic/exp/lldb/Makefile b/Godeps/_workspace/src/github.com/cznic/exp/lldb/Makefile new file mode 100644 index 0000000..cd8248a --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/exp/lldb/Makefile @@ -0,0 +1,45 @@ +# Copyright 2014 The lldb Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +.PHONY: all editor clean cover nuke + +testbin=lldb.test +grep=--include=*.go + +all: editor + go build + go vet + golint . + go install + make todo + +clean: + go clean + rm -f *~ cov cov.html bad-dump good-dump lldb.test old.txt new.txt \ + test-acidfiler0-* _test.db _wal + +cover: + t=$(shell tempfile) ; go test -coverprofile $$t && go tool cover -html $$t && unlink $$t + +editor: + go fmt + go test -i + go test -timeout 1h + +mem: + go test -c + ./$(testbin) -test.bench . -test.memprofile mem.out -test.memprofilerate 1 -test.timeout 24h + go tool pprof --lines --web --alloc_space $(testbin) mem.out + +nuke: clean + go clean -i + +todo: + @grep -nr $(grep) BUG * || true + @grep -nr $(grep) LATER * || true + @grep -nr $(grep) MAYBE * || true + @grep -nr $(grep) TODO * || true + @grep -nr $(grep) FIXME * || true + @grep -nr $(grep) ^[[:space:]]*_[[:space:]]*=[[:space:]][[:alpha:]][[:alnum:]]* * || true + @grep -nr $(grep) println * || true diff --git a/Godeps/_workspace/src/github.com/cznic/exp/lldb/README.md b/Godeps/_workspace/src/github.com/cznic/exp/lldb/README.md new file mode 100644 index 0000000..470bf54 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/exp/lldb/README.md @@ -0,0 +1,8 @@ +lldb +==== + +Package lldb (WIP) implements a low level database engine. + +Installation: $ go get github.com/cznic/exp/lldb + +Documentation: [godoc.org/github.com/cznic/exp/lldb](http://godoc.org/github.com/cznic/exp/lldb) diff --git a/Godeps/_workspace/src/github.com/cznic/exp/lldb/all_test.go b/Godeps/_workspace/src/github.com/cznic/exp/lldb/all_test.go new file mode 100644 index 0000000..451302d --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/exp/lldb/all_test.go @@ -0,0 +1,43 @@ +// Copyright 2014 The lldb 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 lldb + +import ( + "encoding/hex" + "io/ioutil" + "os" + "path/filepath" + "runtime" + "time" +) + +const ( + testDbName = "_test.db" + walName = "_wal" +) + +func now() time.Time { return time.Now() } + +func hdump(b []byte) string { + return hex.Dump(b) +} + +func die() { + os.Exit(1) +} + +func stack() string { + buf := make([]byte, 1<<16) + return string(buf[:runtime.Stack(buf, false)]) +} + +func temp() (dir, name string) { + dir, err := ioutil.TempDir("", "test-lldb-") + if err != nil { + panic(err) + } + + return dir, filepath.Join(dir, "test.tmp") +} diff --git a/Godeps/_workspace/src/github.com/cznic/exp/lldb/btree.go b/Godeps/_workspace/src/github.com/cznic/exp/lldb/btree.go new file mode 100644 index 0000000..ce61502 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/exp/lldb/btree.go @@ -0,0 +1,2276 @@ +// Copyright 2014 The lldb 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 lldb + +import ( + "bytes" + "errors" + "fmt" + "io" + "sort" + "strings" + + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/bufs" + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/fileutil" + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/sortutil" +) + +const ( + kData = 256 // [1, 512] + kIndex = 256 // [2, 2048] + kKV = 19 // Size of the key/value field in btreeDataPage + kSz = kKV - 1 - 7 // Content prefix size + kH = kKV - 7 // Content field offset for handle + tagBTreeDataPage = 1 + tagBTreeIndexPage = 0 +) + +// BTree is a B+tree[1][2], i.e. a variant which speeds up +// enumeration/iteration of the BTree. According to its origin it can be +// volatile (backed only by memory) or non-volatile (backed by a non-volatile +// Allocator). +// +// The specific implementation of BTrees in this package are B+trees with +// delayed split/concatenation (discussed in e.g. [3]). +// +// Note: No BTree methods returns io.EOF for physical Filer reads/writes. The +// io.EOF is returned only by bTreeEnumerator methods to indicate "no more K-V +// pair". +// +// [1]: http://en.wikipedia.org/wiki/B+tree +// [2]: http://zgking.com:8080/home/donghui/publications/books/dshandbook_BTree.pdf +// [3]: http://people.cs.aau.dk/~simas/aalg06/UbiquitBtree.pdf +type BTree struct { + store btreeStore + root btree + collate func(a, b []byte) int + serial uint64 +} + +// NewBTree returns a new, memory-only BTree. +func NewBTree(collate func(a, b []byte) int) *BTree { + store := newMemBTreeStore() + root, err := newBTree(store) + if err != nil { // should not happen + panic(err.Error()) + } + + return &BTree{store, root, collate, 0} +} + +// IsMem reports if t is a memory only BTree. +func (t *BTree) IsMem() (r bool) { + _, r = t.store.(*memBTreeStore) + return +} + +// Clear empties the tree. +func (t *BTree) Clear() (err error) { + if t == nil { + err = errors.New("BTree method invoked on nil receiver") + return + } + + t.serial++ + return t.root.clear(t.store) +} + +// Delete deletes key and its associated value from the tree. +func (t *BTree) Delete(key []byte) (err error) { + if t == nil { + err = errors.New("BTree method invoked on nil receiver") + return + } + + t.serial++ + _, err = t.root.extract(t.store, nil, t.collate, key) + return +} + +// DeleteAny deletes one key and its associated value from the tree. If the +// tree is empty on return then empty is true. +func (t *BTree) DeleteAny() (empty bool, err error) { + if t == nil { + err = errors.New("BTree method invoked on nil receiver") + return + } + + t.serial++ + return t.root.deleteAny(t.store) +} + +func elem(v interface{}) string { + switch x := v.(type) { + default: + panic("internal error") + case nil: + return "nil" + case bool: + if x { + return "true" + } + + return "false" + case int64: + return fmt.Sprint(x) + case uint64: + return fmt.Sprint(x) + case float64: + s := fmt.Sprintf("%g", x) + if !strings.Contains(s, ".") { + s += "." + } + return s + case complex128: + s := fmt.Sprint(x) + return s[1 : len(s)-1] + case []byte: + return fmt.Sprintf("[]byte{% 02x}", x) + case string: + return fmt.Sprintf("%q", x) + } +} + +// Dump outputs a human readable dump of t to w. It is usable iff t keys and +// values are encoded scalars (see EncodeScalars). Intended use is only for +// examples or debugging. Some type information is lost in the rendering, for +// example a float value '17.' and an integer value '17' may both output as +// '17'. +func (t *BTree) Dump(w io.Writer) (err error) { + enum, err := t.seekFirst() + if err != nil { + return + } + + for { + bkey, bval, err := enum.current() + if err != nil { + return err + } + + key, err := DecodeScalars(bkey) + if err != nil { + return err + } + + val, err := DecodeScalars(bval) + if err != nil { + return err + } + + kk := []string{} + if key == nil { + kk = []string{"null"} + } + for _, v := range key { + kk = append(kk, elem(v)) + } + vv := []string{} + if val == nil { + vv = []string{"null"} + } + for _, v := range val { + vv = append(vv, elem(v)) + } + skey := strings.Join(kk, ", ") + sval := strings.Join(vv, ", ") + if len(vv) > 1 { + sval = fmt.Sprintf("[]interface{%s}", sval) + } + if _, err = fmt.Fprintf(w, "%s → %s\n", skey, sval); err != nil { + return err + } + + err = enum.next() + if err != nil { + if fileutil.IsEOF(err) { + err = nil + break + } + + return err + } + } + return +} + +// Extract is a combination of Get and Delete. If the key exists in the tree, +// it is returned (like Get) and also deleted from a tree in a more efficient +// way which doesn't walk it twice. The returned slice may be a sub-slice of +// buf if buf was large enough to hold the entire content. Otherwise, a newly +// allocated slice will be returned. It is valid to pass a nil buf. +func (t *BTree) Extract(buf, key []byte) (value []byte, err error) { + if t == nil { + err = errors.New("BTree method invoked on nil receiver") + return + } + + t.serial++ + return t.root.extract(t.store, buf, t.collate, key) +} + +// First returns the first KV pair of the tree, if it exists. Otherwise key == nil +// and value == nil. +func (t *BTree) First() (key, value []byte, err error) { + if t == nil { + err = errors.New("BTree method invoked on nil receiver") + return + } + + var p btreeDataPage + if _, p, err = t.root.first(t.store); err != nil || p == nil { + return + } + + if key, err = p.key(t.store, 0); err != nil { + return + } + + value, err = p.value(t.store, 0) + return +} + +// Get returns the value associated with key, or nil if no such value exists. +// The returned slice may be a sub-slice of buf if buf was large enough to hold +// the entire content. Otherwise, a newly allocated slice will be returned. +// It is valid to pass a nil buf. +func (t *BTree) Get(buf, key []byte) (value []byte, err error) { + if t == nil { + err = errors.New("BTree method invoked on nil receiver") + return + } + + buffer := bufs.GCache.Get(maxBuf) + defer bufs.GCache.Put(buffer) + if buffer, err = t.root.get(t.store, buffer, t.collate, key); buffer == nil || err != nil { + return + } + + value = need(len(buffer), buf) + copy(value, buffer) + return +} + +// Handle reports t's handle. +func (t *BTree) Handle() int64 { + return int64(t.root) +} + +// Last returns the last KV pair of the tree, if it exists. Otherwise key == nil +// and value == nil. +func (t *BTree) Last() (key, value []byte, err error) { + if t == nil { + err = errors.New("BTree method invoked on nil receiver") + return + } + + var p btreeDataPage + if _, p, err = t.root.last(t.store); err != nil || p == nil { + return + } + + index := p.len() - 1 + if key, err = p.key(t.store, index); err != nil { + return + } + + value, err = p.value(t.store, index) + return +} + +// Put combines Get and Set in a more efficient way where the tree is walked +// only once. The upd(ater) receives the current (key, old-value), if that +// exists or (key, nil) otherwise. It can then return a (new-value, true, nil) +// to create or overwrite the existing value in the KV pair, or (whatever, +// false, nil) if it decides not to create or not to update the value of the KV +// pair. +// +// tree.Set(k, v) +// +// conceptually equals +// +// tree.Put(k, func(k, v []byte){ return v, true }([]byte, bool)) +// +// modulo the differing return values. +// +// The returned slice may be a sub-slice of buf if buf was large enough to hold +// the entire content. Otherwise, a newly allocated slice will be returned. +// It is valid to pass a nil buf. +func (t *BTree) Put(buf, key []byte, upd func(key, old []byte) (new []byte, write bool, err error)) (old []byte, written bool, err error) { + if t == nil { + err = errors.New("BTree method invoked on nil receiver") + return + } + + t.serial++ + return t.root.put2(buf, t.store, t.collate, key, upd) +} + +// Seek returns an Enumerator with "position" or an error of any. Normally the +// position is on a KV pair such that key >= KV.key. Then hit is key == KV.key. +// The position is possibly "after" the last KV pair, but that is not an error. +func (t *BTree) Seek(key []byte) (enum *BTreeEnumerator, hit bool, err error) { + enum0, hit, err := t.seek(key) + if err != nil { + return + } + + enum = &BTreeEnumerator{ + enum: enum0, + firstHit: hit, + key: append([]byte(nil), key...), + } + return +} + +func (t *BTree) seek(key []byte) (enum *bTreeEnumerator, hit bool, err error) { + if t == nil { + err = errors.New("BTree method invoked on nil receiver") + return + } + + r := &bTreeEnumerator{t: t, collate: t.collate, serial: t.serial} + if r.p, r.index, hit, err = t.root.seek(t.store, r.collate, key); err != nil { + return + } + + enum = r + return +} + +// IndexSeek returns an Enumerator with "position" or an error of any. Normally +// the position is on a KV pair such that key >= KV.key. Then hit is key == +// KV.key. The position is possibly "after" the last KV pair, but that is not +// an error. The collate function originally passed to CreateBTree is used for +// enumerating the tree but a custom collate function c is used for IndexSeek. +func (t *BTree) IndexSeek(key []byte, c func(a, b []byte) int) (enum *BTreeEnumerator, hit bool, err error) { //TODO +test + enum0, hit, err := t.indexSeek(key, c) + if err != nil { + return + } + + enum = &BTreeEnumerator{ + enum: enum0, + firstHit: hit, + key: append([]byte(nil), key...), + } + return +} + +func (t *BTree) indexSeek(key []byte, c func(a, b []byte) int) (enum *bTreeEnumerator, hit bool, err error) { + if t == nil { + err = errors.New("BTree method invoked on nil receiver") + return + } + + r := &bTreeEnumerator{t: t, collate: t.collate, serial: t.serial} + if r.p, r.index, hit, err = t.root.seek(t.store, c, key); err != nil { + return + } + + enum = r + return +} + +// seekFirst returns an enumerator positioned on the first KV pair in the tree, +// if any. For an empty tree, err == io.EOF is returend. +func (t *BTree) SeekFirst() (enum *BTreeEnumerator, err error) { + enum0, err := t.seekFirst() + if err != nil { + return + } + + var key []byte + if key, _, err = enum0.current(); err != nil { + return + } + + enum = &BTreeEnumerator{ + enum: enum0, + firstHit: true, + key: append([]byte(nil), key...), + } + return +} + +func (t *BTree) seekFirst() (enum *bTreeEnumerator, err error) { + if t == nil { + err = errors.New("BTree method invoked on nil receiver") + return + } + + var p btreeDataPage + if _, p, err = t.root.first(t.store); err == nil && p == nil { + err = io.EOF + } + if err != nil { + return + } + + return &bTreeEnumerator{t: t, collate: t.collate, p: p, index: 0, serial: t.serial}, nil +} + +// seekLast returns an enumerator positioned on the last KV pair in the tree, +// if any. For an empty tree, err == io.EOF is returend. +func (t *BTree) SeekLast() (enum *BTreeEnumerator, err error) { + enum0, err := t.seekLast() + if err != nil { + return + } + + var key []byte + if key, _, err = enum0.current(); err != nil { + return + } + + enum = &BTreeEnumerator{ + enum: enum0, + firstHit: true, + key: append([]byte(nil), key...), + } + return +} + +func (t *BTree) seekLast() (enum *bTreeEnumerator, err error) { + if t == nil { + err = errors.New("BTree method invoked on nil receiver") + return + } + + var p btreeDataPage + if _, p, err = t.root.last(t.store); err == nil && p == nil { + err = io.EOF + } + if err != nil { + return + } + + return &bTreeEnumerator{t: t, collate: t.collate, p: p, index: p.len() - 1, serial: t.serial}, nil +} + +// Set sets the value associated with key. Any previous value, if existed, is +// overwritten by the new one. +func (t *BTree) Set(key, value []byte) (err error) { + if t == nil { + err = errors.New("BTree method invoked on nil receiver") + return + } + + t.serial++ + dst := bufs.GCache.Get(maxBuf) + _, err = t.root.put(dst, t.store, t.collate, key, value, true) + bufs.GCache.Put(dst) + return +} + +// bTreeEnumerator is a closure of a BTree and a position. It is returned from +// BTree.seek. +// +// NOTE: bTreeEnumerator cannot be used after its BTree was mutated after the +// bTreeEnumerator was acquired from any of the seek, seekFirst, seekLast +// methods. +type bTreeEnumerator struct { + t *BTree + collate func(a, b []byte) int + p btreeDataPage + index int + serial uint64 +} + +// Current returns the KV pair the enumerator is currently positioned on. If +// the position is before the first KV pair in the tree or after the last KV +// pair in the tree then err == io.EOF is returned. +// +// If the enumerator has been invalidated by updating the tree, ErrINVAL is +// returned. +func (e *bTreeEnumerator) current() (key, value []byte, err error) { + if e == nil { + err = errors.New("bTreeEnumerator method invoked on nil receiver") + return + } + + if e.serial != e.t.serial { + err = &ErrINVAL{Src: "bTreeEnumerator invalidated by updating the tree"} + return + } + + if e.p == nil || e.index == e.p.len() { + return nil, nil, io.EOF + } + + if key, err = e.p.key(e.t.store, e.index); err != nil { + return + } + + value, err = e.p.value(e.t.store, e.index) + return +} + +// Next attempts to position the enumerator onto the next KV pair wrt the +// current position. If there is no "next" KV pair, io.EOF is returned. +// +// If the enumerator has been invalidated by updating the tree, ErrINVAL is +// returned. +func (e *bTreeEnumerator) next() (err error) { + if e == nil { + err = errors.New("bTreeEnumerator method invoked on nil receiver") + return + } + + if e.serial != e.t.serial { + err = &ErrINVAL{Src: "bTreeEnumerator invalidated by updating the tree"} + return + } + + if e.p == nil { + return io.EOF + } + + switch { + case e.index < e.p.len()-1: + e.index++ + default: + ph := e.p.next() + if ph == 0 { + err = io.EOF + break + } + + if e.p, err = e.t.store.Get(e.p, ph); err != nil { + e.p = nil + return + } + e.index = 0 + } + return +} + +// Prev attempts to position the enumerator onto the previous KV pair wrt the +// current position. If there is no "previous" KV pair, io.EOF is returned. +// +// If the enumerator has been invalidated by updating the tree, ErrINVAL is +// returned. +func (e *bTreeEnumerator) prev() (err error) { + if e == nil { + err = errors.New("bTreeEnumerator method invoked on nil receiver") + return + } + + if e.serial != e.t.serial { + err = &ErrINVAL{Src: "bTreeEnumerator invalidated by updating the tree"} + return + } + + if e.p == nil { + return io.EOF + } + + switch { + case e.index > 0: + e.index-- + default: + ph := e.p.prev() + if ph == 0 { + err = io.EOF + break + } + + if e.p, err = e.t.store.Get(e.p, ph); err != nil { + e.p = nil + return + } + e.index = e.p.len() - 1 + } + return +} + +// BTreeEnumerator captures the state of enumerating a tree. It is returned +// from the Seek* methods. The enumerator is aware of any mutations made to +// the tree in the process of enumerating it and automatically resumes the +// enumeration. +type BTreeEnumerator struct { + enum *bTreeEnumerator + err error + key []byte + firstHit bool +} + +// Next returns the currently enumerated KV pair, if it exists and moves to the +// next KV in the key collation order. If there is no KV pair to return, err == +// io.EOF is returned. +func (e *BTreeEnumerator) Next() (key, value []byte, err error) { + if err = e.err; err != nil { + return + } + + canRetry := true +retry: + if key, value, err = e.enum.current(); err != nil { + if _, ok := err.(*ErrINVAL); !ok || !canRetry { + e.err = err + return + } + + canRetry = false + var hit bool + if e.enum, hit, err = e.enum.t.seek(e.key); err != nil { + e.err = err + return + } + + if !e.firstHit && hit { + err = e.enum.next() + if err != nil { + e.err = err + return + } + } + + goto retry + } + + e.firstHit = false + e.key = append([]byte(nil), key...) + e.err = e.enum.next() + return +} + +// Prev returns the currently enumerated KV pair, if it exists and moves to the +// previous KV in the key collation order. If there is no KV pair to return, +// err == io.EOF is returned. +func (e *BTreeEnumerator) Prev() (key, value []byte, err error) { + if err = e.err; err != nil { + return + } + + canRetry := true +retry: + if key, value, err = e.enum.current(); err != nil { + if _, ok := err.(*ErrINVAL); !ok || !canRetry { + e.err = err + return + } + + canRetry = false + var hit bool + if e.enum, hit, err = e.enum.t.seek(e.key); err != nil { + e.err = err + return + } + + if !e.firstHit && hit { + err = e.enum.prev() + if err != nil { + e.err = err + return + } + } + + goto retry + } + + e.firstHit = false + e.key = append([]byte(nil), key...) + e.err = e.enum.prev() + return +} + +// CreateBTree creates a new BTree in store. It returns the tree, its (freshly +// assigned) handle (for OpenBTree or RemoveBTree) or an error, if any. +func CreateBTree(store *Allocator, collate func(a, b []byte) int) (bt *BTree, handle int64, err error) { + r := &BTree{store: store, collate: collate} + if r.root, err = newBTree(store); err != nil { + return + } + + return r, int64(r.root), nil +} + +// OpenBTree opens a store's BTree using handle. It returns the tree or an +// error, if any. The same tree may be opened more than once, but operations on +// the separate instances should not ever overlap or void the other instances. +// However, the intended API usage is to open the same tree handle only once +// (handled by some upper layer "dispatcher"). +func OpenBTree(store *Allocator, collate func(a, b []byte) int, handle int64) (bt *BTree, err error) { + r := &BTree{store: store, root: btree(handle), collate: collate} + b := bufs.GCache.Get(7) + defer bufs.GCache.Put(b) + if b, err = store.Get(b, handle); err != nil { + return + } + + if len(b) != 7 { + return nil, &ErrILSEQ{Off: h2off(handle), More: "btree.go:671"} + } + + return r, nil +} + +// RemoveBTree removes tree, represented by handle from store. Empty trees are +// cheap, each uses only few bytes of the store. If there's a chance that a +// tree will eventually get reused (non empty again), it's recommended to +// not/never remove it. One advantage of such approach is a stable handle of +// such tree. +func RemoveBTree(store *Allocator, handle int64) (err error) { + tree, err := OpenBTree(store, nil, handle) + if err != nil { + return + } + + if err = tree.Clear(); err != nil { + return + } + + return store.Free(handle) +} + +type btreeStore interface { + Alloc(b []byte) (handle int64, err error) + Free(handle int64) (err error) + Get(dst []byte, handle int64) (b []byte, err error) + Realloc(handle int64, b []byte) (err error) +} + +// Read only zero bytes +var zeros [2 * kKV]byte + +func init() { + if kData < 1 || kData > 512 { + panic(fmt.Errorf("kData %d: out of limits", kData)) + } + + if kIndex < 2 || kIndex > 2048 { + panic(fmt.Errorf("kIndex %d: out of limits", kIndex)) + } + + if kKV < 8 || kKV > 23 { + panic(fmt.Errorf("kKV %d: out of limits", kKV)) + } + + if n := len(zeros); n < 15 { + panic(fmt.Errorf("not enough zeros: %d", n)) + } +} + +type memBTreeStore struct { + h int64 + m map[int64][]byte +} + +func newMemBTreeStore() *memBTreeStore { + return &memBTreeStore{h: 0, m: map[int64][]byte{}} +} + +func (s *memBTreeStore) String() string { + var a sortutil.Int64Slice + for k := range s.m { + a = append(a, k) + } + sort.Sort(a) + var sa []string + for _, k := range a { + sa = append(sa, fmt.Sprintf("%#x:|% x|", k, s.m[k])) + } + return strings.Join(sa, "\n") +} + +func (s *memBTreeStore) Alloc(b []byte) (handle int64, err error) { + s.h++ + handle = s.h + s.m[handle] = bpack(b) + return +} + +func (s *memBTreeStore) Free(handle int64) (err error) { + if _, ok := s.m[handle]; !ok { + return &ErrILSEQ{Type: ErrOther, Off: h2off(handle), More: "btree.go:754"} + } + + delete(s.m, handle) + return +} + +func (s *memBTreeStore) Get(dst []byte, handle int64) (b []byte, err error) { + r, ok := s.m[handle] + if !ok { + return nil, &ErrILSEQ{Type: ErrOther, Off: h2off(handle), More: "btree.go:764"} + } + + b = need(len(r), dst) + copy(b, r) + return +} + +func (s *memBTreeStore) Realloc(handle int64, b []byte) (err error) { + if _, ok := s.m[handle]; !ok { + return &ErrILSEQ{Type: ErrOther, Off: h2off(handle), More: "btree.go:774"} + } + + s.m[handle] = bpack(b) + return +} + +/* + +0...0 (1 bytes): +Flag + + 0 + +---+ + | 0 | + +---+ + +0 indicates an index page + +1...count*14-1 +"array" of items, 14 bytes each. Count of items in kIndex-1..2*kIndex+2 + + Count = (len(raw) - 8) / 14 + + 0..6 7..13 + +-------+----------+ + | Child | DataPage | + +-------+----------+ + + Child == handle of a child index page + DataPage == handle of a data page + +Offsets into the raw []byte: +Child[X] == 1+14*X +DataPage[X] == 8+14*X + +*/ +type btreeIndexPage []byte + +func newBTreeIndexPage(leftmostChild int64) (p btreeIndexPage) { + p = bufs.GCache.Get(1 + (kIndex+1)*2*7)[:8] + p[0] = tagBTreeIndexPage + h2b(p[1:], leftmostChild) + return +} + +func (p btreeIndexPage) len() int { + return (len(p) - 8) / 14 +} + +func (p btreeIndexPage) child(index int) int64 { + return b2h(p[1+14*index:]) +} + +func (p btreeIndexPage) setChild(index int, dp int64) { + h2b(p[1+14*index:], dp) +} + +func (p btreeIndexPage) dataPage(index int) int64 { + return b2h(p[8+14*index:]) +} + +func (p btreeIndexPage) setDataPage(index int, dp int64) { + h2b(p[8+14*index:], dp) +} + +func (q btreeIndexPage) insert(index int) btreeIndexPage { + switch len0 := q.len(); { + case index < len0: + has := len(q) + need := has + 14 + switch { + case cap(q) >= need: + q = q[:need] + default: + q = append(q, zeros[:14]...) + } + copy(q[8+14*(index+1):8+14*(index+1)+2*(len0-index)*7], q[8+14*index:]) + case index == len0: + has := len(q) + need := has + 14 + switch { + case cap(q) >= need: + q = q[:need] + default: + q = append(q, zeros[:14]...) + } + } + return q +} + +func (p btreeIndexPage) insert3(index int, dataPage, child int64) btreeIndexPage { + p = p.insert(index) + p.setDataPage(index, dataPage) + p.setChild(index+1, child) + return p +} + +func (p btreeIndexPage) cmp(a btreeStore, c func(a, b []byte) int, keyA []byte, keyBIndex int) (int, error) { + b := bufs.GCache.Get(maxBuf) + defer bufs.GCache.Put(b) + dp, err := a.Get(b, p.dataPage(keyBIndex)) + if err != nil { + return 0, err + } + + return btreeDataPage(dp).cmp(a, c, keyA, 0) +} + +func (q btreeIndexPage) setLen(n int) btreeIndexPage { + q = q[:cap(q)] + need := 8 + 14*n + if need < len(q) { + return q[:need] + } + return append(q, make([]byte, need-len(q))...) +} + +func (p btreeIndexPage) split(a btreeStore, root btree, ph *int64, parent int64, parentIndex int, index *int) (btreeIndexPage, error) { + right := newBTreeIndexPage(0) + canRecycle := true + defer func() { + if canRecycle { + bufs.GCache.Put(right) + } + }() + right = right.setLen(kIndex) + copy(right[1:1+(2*kIndex+1)*7], p[1+14*(kIndex+1):]) + p = p.setLen(kIndex) + if err := a.Realloc(*ph, p); err != nil { + return nil, err + } + + rh, err := a.Alloc(right) + if err != nil { + return nil, err + } + + if parentIndex >= 0 { + var pp btreeIndexPage = bufs.GCache.Get(maxBuf) + defer bufs.GCache.Put(pp) + if pp, err = a.Get(pp, parent); err != nil { + return nil, err + } + pp = pp.insert3(parentIndex, p.dataPage(kIndex), rh) + if err = a.Realloc(parent, pp); err != nil { + return nil, err + } + + } else { + nr := newBTreeIndexPage(*ph) + defer bufs.GCache.Put(nr) + nr = nr.insert3(0, p.dataPage(kIndex), rh) + nrh, err := a.Alloc(nr) + if err != nil { + return nil, err + } + + if err = a.Realloc(int64(root), h2b(make([]byte, 7), nrh)); err != nil { + return nil, err + } + } + if *index > kIndex { + p = right + canRecycle = false + *ph = rh + *index -= kIndex + 1 + } + return p, nil +} + +// p is dirty on return +func (p btreeIndexPage) extract(index int) btreeIndexPage { + n := p.len() - 1 + if index < n { + sz := (n-index)*14 + 7 + copy(p[1+14*index:1+14*index+sz], p[1+14*(index+1):]) + } + return p.setLen(n) +} + +// must persist all changes made +func (p btreeIndexPage) underflow(a btreeStore, root, iroot, parent int64, ph *int64, parentIndex int, index *int) (btreeIndexPage, error) { + lh, rh, err := checkSiblings(a, parent, parentIndex) + if err != nil { + return nil, err + } + + var left btreeIndexPage = bufs.GCache.Get(maxBuf) + defer bufs.GCache.Put(left) + + if lh != 0 { + if left, err = a.Get(left, lh); err != nil { + return nil, err + } + + if lc := btreeIndexPage(left).len(); lc > kIndex { + var pp = bufs.GCache.Get(maxBuf) + defer bufs.GCache.Put(pp) + if pp, err = a.Get(pp, parent); err != nil { + return nil, err + } + + pc := p.len() + p = p.setLen(pc + 1) + di, si, sz := 1+1*14, 1+0*14, (2*pc+1)*7 + copy(p[di:di+sz], p[si:]) + p.setChild(0, btreeIndexPage(left).child(lc)) + p.setDataPage(0, btreeIndexPage(pp).dataPage(parentIndex-1)) + *index++ + btreeIndexPage(pp).setDataPage(parentIndex-1, btreeIndexPage(left).dataPage(lc-1)) + left = left.setLen(lc - 1) + if err = a.Realloc(parent, pp); err != nil { + return nil, err + } + + if err = a.Realloc(*ph, p); err != nil { + return nil, err + } + + return p, a.Realloc(lh, left) + } + } + + if rh != 0 { + right := bufs.GCache.Get(maxBuf) + defer bufs.GCache.Put(right) + if right, err = a.Get(right, rh); err != nil { + return nil, err + } + + if rc := btreeIndexPage(right).len(); rc > kIndex { + pp := bufs.GCache.Get(maxBuf) + defer bufs.GCache.Put(pp) + if pp, err = a.Get(pp, parent); err != nil { + return nil, err + } + + pc := p.len() + p = p.setLen(pc + 1) + p.setDataPage(pc, btreeIndexPage(pp).dataPage(parentIndex)) + pc++ + p.setChild(pc, btreeIndexPage(right).child(0)) + btreeIndexPage(pp).setDataPage(parentIndex, btreeIndexPage(right).dataPage(0)) + di, si, sz := 1+0*14, 1+1*14, (2*rc+1)*7 + copy(right[di:di+sz], right[si:]) + right = btreeIndexPage(right).setLen(rc - 1) + if err = a.Realloc(parent, pp); err != nil { + return nil, err + } + + if err = a.Realloc(*ph, p); err != nil { + return nil, err + } + + return p, a.Realloc(rh, right) + } + } + + if lh != 0 { + *index += left.len() + 1 + if left, err = left.concat(a, root, iroot, parent, lh, *ph, parentIndex-1); err != nil { + return p, err + } + + p, *ph = left, lh + return p, nil + } + + return p.concat(a, root, iroot, parent, *ph, rh, parentIndex) +} + +// must persist all changes made +func (p btreeIndexPage) concat(a btreeStore, root, iroot, parent, ph, rh int64, parentIndex int) (btreeIndexPage, error) { + pp := bufs.GCache.Get(maxBuf) + defer bufs.GCache.Put(pp) + pp, err := a.Get(pp, parent) + if err != nil { + return nil, err + } + + right := bufs.GCache.Get(maxBuf) + defer bufs.GCache.Put(right) + if right, err = a.Get(right, rh); err != nil { + return nil, err + } + + pc := p.len() + rc := btreeIndexPage(right).len() + p = p.setLen(pc + rc + 1) + p.setDataPage(pc, btreeIndexPage(pp).dataPage(parentIndex)) + di, si, sz := 1+14*(pc+1), 1+0*14, (2*rc+1)*7 + copy(p[di:di+sz], right[si:]) + if err := a.Realloc(ph, p); err != nil { + return nil, err + } + + if err := a.Free(rh); err != nil { + return nil, err + } + + if pc := btreeIndexPage(pp).len(); pc > 1 { + if parentIndex < pc-1 { + di, si, sz := 8+parentIndex*14, 8+(parentIndex+1)*14, 2*(pc-1-parentIndex)*7 + copy(pp[di:si+sz], pp[si:]) + } + pp = btreeIndexPage(pp).setLen(pc - 1) + return p, a.Realloc(parent, pp) + } + + if err := a.Free(iroot); err != nil { + return nil, err + } + + b7 := bufs.GCache.Get(7) + defer bufs.GCache.Put(b7) + return p, a.Realloc(root, h2b(b7[:7], ph)) +} + +/* + +0...0 (1 bytes): +Flag + + 0 + +---+ + | 1 | + +---+ + +1 indicates a data page + +1...14 (14 bytes) + + 1..7 8..14 + +------+------+ + | Prev | Next | + +------+------+ + + Prev, Next == Handles of the data pages doubly linked list + + Count = (len(raw) - 15) / (2*kKV) + +15...count*2*kKV-1 +"array" of items, 2*kKV bytes each. Count of items in kData-1..2*kData + +Item + 0..kKV-1 kKV..2*kKV-1 + +----------+--------------+ + | Key | Value | + +----------+--------------+ + +Key/Value encoding + +Length 0...kKV-1 + + 0 1...N N+1...kKV-1 + +---+---------+-------------+ + | N | Data | Padding | + +---+---------+-------------+ + + N == content length + Data == Key or Value content + Padding == MUST be zero bytes + +Length >= kKV + + 0 1...kkV-8 kKV-7...kkV-1 + +------+-----------+--------------+ + | 0xFF | Data | H | + +------+-----------+--------------+ + + Data == Key or Value content, first kKV-7 bytes + H == Handle to THE REST of the content, w/o the first bytes in Data. + +Offsets into the raw []byte: +Key[X] == 15+2*kKV*X +Value[X] == 15+kKV+2*kKV*X +*/ +type btreeDataPage []byte + +func newBTreeDataPage() (p btreeDataPage) { + p = bufs.GCache.Cget(1 + 2*7 + (kData+1)*2*kKV)[:1+2*7] + p[0] = tagBTreeDataPage + return +} + +func newBTreeDataPageAlloc(a btreeStore) (p btreeDataPage, h int64, err error) { + p = newBTreeDataPage() + h, err = a.Alloc(p) + return +} + +func (p btreeDataPage) len() int { + return (len(p) - 15) / (2 * kKV) +} + +func (q btreeDataPage) setLen(n int) btreeDataPage { + q = q[:cap(q)] + need := 15 + 2*kKV*n + if need < len(q) { + return q[:need] + } + return append(q, make([]byte, need-len(q))...) +} + +func (p btreeDataPage) prev() int64 { + return b2h(p[1:]) +} + +func (p btreeDataPage) next() int64 { + return b2h(p[8:]) +} + +func (p btreeDataPage) setPrev(h int64) { + h2b(p[1:], h) +} + +func (p btreeDataPage) setNext(h int64) { + h2b(p[8:], h) +} + +func (q btreeDataPage) insert(index int) btreeDataPage { + switch len0 := q.len(); { + case index < len0: + has := len(q) + need := has + 2*kKV + switch { + case cap(q) >= need: + q = q[:need] + default: + q = append(q, zeros[:2*kKV]...) + } + q.copy(q, index+1, index, len0-index) + return q + case index == len0: + has := len(q) + need := has + 2*kKV + switch { + case cap(q) >= need: + return q[:need] + default: + return append(q, zeros[:2*kKV]...) + } + } + panic("internal error") +} + +func (p btreeDataPage) contentField(off int) (b []byte, h int64) { + p = p[off:] + switch n := int(p[0]); { + case n >= kKV: // content has a handle + b = append([]byte(nil), p[1:1+kSz]...) + h = b2h(p[kH:]) + default: // content is embedded + b, h = append([]byte(nil), p[1:1+n]...), 0 + } + return +} + +func (p btreeDataPage) content(a btreeStore, off int) (b []byte, err error) { + b, h := p.contentField(off) + if h == 0 { + return + } + + // content has a handle + b2, err := a.Get(nil, h) //TODO buffers: Later, not a public API + if err != nil { + return nil, err + } + + return append(b, b2...), nil +} + +func (p btreeDataPage) setContent(a btreeStore, off int, b []byte) (err error) { + p = p[off:] + switch { + case p[0] >= kKV: // existing content has a handle + switch n := len(b); { + case n < kKV: + p[0] = byte(n) + if err = a.Free(b2h(p[kH:])); err != nil { + return + } + copy(p[1:], b) + default: + // reuse handle + copy(p[1:1+kSz], b) + return a.Realloc(b2h(p[kH:]), b[kSz:]) + } + default: // existing content is embedded + switch n := len(b); { + case n < kKV: + p[0] = byte(n) + copy(p[1:], b) + default: + p[0] = 0xff + copy(p[1:1+kSz], b) + h, err := a.Alloc(b[kSz:]) + if err != nil { + return err + } + + h2b(p[kH:], h) + } + } + return +} + +func (p btreeDataPage) keyField(index int) (b []byte, h int64) { + return p.contentField(15 + 2*kKV*index) +} + +func (p btreeDataPage) key(a btreeStore, index int) (b []byte, err error) { + return p.content(a, 15+2*kKV*index) +} + +func (p btreeDataPage) valueField(index int) (b []byte, h int64) { + return p.contentField(15 + kKV + 2*kKV*index) +} + +func (p btreeDataPage) value(a btreeStore, index int) (b []byte, err error) { + return p.content(a, 15+kKV+2*kKV*index) +} + +func (p btreeDataPage) valueCopy(a btreeStore, index int) (b []byte, err error) { + if b, err = p.content(a, 15+kKV+2*kKV*index); err != nil { + return + } + + return append([]byte(nil), b...), nil +} + +func (p btreeDataPage) setKey(a btreeStore, index int, key []byte) (err error) { + return p.setContent(a, 15+2*kKV*index, key) +} + +func (p btreeDataPage) setValue(a btreeStore, index int, value []byte) (err error) { + return p.setContent(a, 15+kKV+2*kKV*index, value) +} + +func (p btreeDataPage) cmp(a btreeStore, c func(a, b []byte) int, keyA []byte, keyBIndex int) (y int, err error) { + var keyB []byte + if keyB, err = p.content(a, 15+2*kKV*keyBIndex); err != nil { + return + } + + return c(keyA, keyB), nil +} + +func (p btreeDataPage) copy(src btreeDataPage, di, si, n int) { + do, so := 15+2*kKV*di, 15+2*kKV*si + copy(p[do:do+2*kKV*n], src[so:]) +} + +// {p,left} dirty on exit +func (p btreeDataPage) moveLeft(left btreeDataPage, n int) (btreeDataPage, btreeDataPage) { + nl, np := left.len(), p.len() + left = left.setLen(nl + n) + left.copy(p, nl, 0, n) + p.copy(p, 0, n, np-n) + return p.setLen(np - n), left +} + +func (p btreeDataPage) moveRight(right btreeDataPage, n int) (btreeDataPage, btreeDataPage) { + nr, np := right.len(), p.len() + right = right.setLen(nr + n) + right.copy(right, n, 0, nr) + right.copy(p, 0, np-n, n) + return p.setLen(np - n), right +} + +func (p btreeDataPage) insertItem(a btreeStore, index int, key, value []byte) (btreeDataPage, error) { + p = p.insert(index) + di, sz := 15+2*kKV*index, 2*kKV + copy(p[di:di+sz], zeros[:sz]) + if err := p.setKey(a, index, key); err != nil { + return nil, err + } + return p, p.setValue(a, index, value) +} + +func (p btreeDataPage) split(a btreeStore, root, ph, parent int64, parentIndex, index int, key, value []byte) (btreeDataPage, error) { + right, rh, err := newBTreeDataPageAlloc(a) + // fails defer bufs.GCache.Put(right) + if err != nil { + return nil, err + } + + if next := p.next(); next != 0 { + right.setNext(p.next()) + nxh := right.next() + nx := bufs.GCache.Get(maxBuf) + defer bufs.GCache.Put(nx) + if nx, err = a.Get(nx, nxh); err != nil { + return nil, err + } + + btreeDataPage(nx).setPrev(rh) + if err = a.Realloc(nxh, nx); err != nil { + return nil, err + } + } + + p.setNext(rh) + right.setPrev(ph) + right = right.setLen(kData) + right.copy(p, 0, kData, kData) + p = p.setLen(kData) + + if parentIndex >= 0 { + var pp btreeIndexPage = bufs.GCache.Get(maxBuf) + defer bufs.GCache.Put(pp) + if pp, err = a.Get(pp, parent); err != nil { + return nil, err + } + + pp = pp.insert3(parentIndex, rh, rh) + if err = a.Realloc(parent, pp); err != nil { + return nil, err + } + + } else { + nr := newBTreeIndexPage(ph) + defer bufs.GCache.Put(nr) + nr = nr.insert3(0, rh, rh) + nrh, err := a.Alloc(nr) + if err != nil { + return nil, err + } + + if err = a.Realloc(root, h2b(make([]byte, 7), nrh)); err != nil { + return nil, err + } + + } + if index > kData { + if right, err = right.insertItem(a, index-kData, key, value); err != nil { + return nil, err + } + } else { + if p, err = p.insertItem(a, index, key, value); err != nil { + return nil, err + } + } + if err = a.Realloc(ph, p); err != nil { + return nil, err + } + + return p, a.Realloc(rh, right) +} + +func (p btreeDataPage) overflow(a btreeStore, root, ph, parent int64, parentIndex, index int, key, value []byte) (btreeDataPage, error) { + leftH, rightH, err := checkSiblings(a, parent, parentIndex) + if err != nil { + return nil, err + } + + if leftH != 0 { + left := btreeDataPage(bufs.GCache.Get(maxBuf)) + defer bufs.GCache.Put(left) + if left, err = a.Get(left, leftH); err != nil { + return nil, err + } + + if left.len() < 2*kData { + + p, left = p.moveLeft(left, 1) + if err = a.Realloc(leftH, left); err != nil { + return nil, err + } + + if p, err = p.insertItem(a, index-1, key, value); err != nil { + return nil, err + } + + return p, a.Realloc(ph, p) + } + } + + if rightH != 0 { + right := btreeDataPage(bufs.GCache.Get(maxBuf)) + defer bufs.GCache.Put(right) + if right, err = a.Get(right, rightH); err != nil { + return nil, err + } + + if right.len() < 2*kData { + if index < 2*kData { + p, right = p.moveRight(right, 1) + if err = a.Realloc(rightH, right); err != nil { + return nil, err + } + + if p, err = p.insertItem(a, index, key, value); err != nil { + return nil, err + } + + return p, a.Realloc(ph, p) + } else { + if right, err = right.insertItem(a, 0, key, value); err != nil { + return nil, err + } + + return p, a.Realloc(rightH, right) + } + } + } + return p.split(a, root, ph, parent, parentIndex, index, key, value) +} + +func (p btreeDataPage) swap(a btreeStore, di int, value []byte, canOverwrite bool) (oldValue []byte, err error) { + if oldValue, err = p.value(a, di); err != nil { + return + } + + if !canOverwrite { + return + } + + oldValue = append([]byte(nil), oldValue...) + err = p.setValue(a, di, value) + return +} + +type btreePage []byte + +func (p btreePage) isIndex() bool { + return p[0] == tagBTreeIndexPage +} + +func (p btreePage) len() int { + if p.isIndex() { + return btreeIndexPage(p).len() + } + + return btreeDataPage(p).len() +} + +func (p btreePage) find(a btreeStore, c func(a, b []byte) int, key []byte) (index int, ok bool, err error) { + l := 0 + h := p.len() - 1 + isIndex := p.isIndex() + if c == nil { + c = bytes.Compare + } + for l <= h { + index = (l + h) >> 1 + var cmp int + if isIndex { + if cmp, err = btreeIndexPage(p).cmp(a, c, key, index); err != nil { + return + } + } else { + if cmp, err = btreeDataPage(p).cmp(a, c, key, index); err != nil { + return + } + } + switch ok = cmp == 0; { + case cmp > 0: + l = index + 1 + case ok: + return + default: + h = index - 1 + } + } + return l, false, nil +} + +// p is dirty after extract! +func (p btreeDataPage) extract(a btreeStore, index int) (btreeDataPage, []byte, error) { + value, err := p.valueCopy(a, index) + if err != nil { + return nil, nil, err + } + + if _, h := p.keyField(index); h != 0 { + if err = a.Free(h); err != nil { + return nil, nil, err + } + } + + if _, h := p.valueField(index); h != 0 { + if err = a.Free(h); err != nil { + return nil, nil, err + } + } + + n := p.len() - 1 + if index < n { + p.copy(p, index, index+1, n-index) + } + return p.setLen(n), value, nil +} + +func checkSiblings(a btreeStore, parent int64, parentIndex int) (left, right int64, err error) { + if parentIndex >= 0 { + var p btreeIndexPage = bufs.GCache.Get(maxBuf) + defer bufs.GCache.Put(p) + if p, err = a.Get(p, parent); err != nil { + return + } + + if parentIndex > 0 { + left = p.child(parentIndex - 1) + } + if parentIndex < p.len() { + right = p.child(parentIndex + 1) + } + } + return +} + +// underflow must persist all changes made. +func (p btreeDataPage) underflow(a btreeStore, root, iroot, parent, ph int64, parentIndex int) (err error) { + lh, rh, err := checkSiblings(a, parent, parentIndex) + if err != nil { + return err + } + + if lh != 0 { + left := bufs.GCache.Get(maxBuf) + defer bufs.GCache.Put(left) + if left, err = a.Get(left, lh); err != nil { + return err + } + + if btreeDataPage(left).len()+p.len() >= 2*kData { + left, p = btreeDataPage(left).moveRight(p, 1) + if err = a.Realloc(lh, left); err != nil { + return err + } + + return a.Realloc(ph, p) + } + } + + if rh != 0 { + right := bufs.GCache.Get(maxBuf) + defer bufs.GCache.Put(right) + if right, err = a.Get(right, rh); err != nil { + return err + } + + if p.len()+btreeDataPage(right).len() > 2*kData { + right, p = btreeDataPage(right).moveLeft(p, 1) + if err = a.Realloc(rh, right); err != nil { + return err + } + + return a.Realloc(ph, p) + } + } + + if lh != 0 { + left := bufs.GCache.Get(maxBuf) + defer bufs.GCache.Put(left) + if left, err = a.Get(left, lh); err != nil { + return err + } + + if err = a.Realloc(ph, p); err != nil { + return err + } + + return btreeDataPage(left).concat(a, root, iroot, parent, lh, ph, parentIndex-1) + } + + return p.concat(a, root, iroot, parent, ph, rh, parentIndex) +} + +// concat must persist all changes made. +func (p btreeDataPage) concat(a btreeStore, root, iroot, parent, ph, rh int64, parentIndex int) (err error) { + right := bufs.GCache.Get(maxBuf) + defer bufs.GCache.Put(right) + if right, err = a.Get(right, rh); err != nil { + return err + } + + right, p = btreeDataPage(right).moveLeft(p, btreeDataPage(right).len()) + nxh := btreeDataPage(right).next() + if nxh != 0 { + nx := bufs.GCache.Get(maxBuf) + defer bufs.GCache.Put(nx) + if nx, err = a.Get(nx, nxh); err != nil { + return err + } + + btreeDataPage(nx).setPrev(ph) + if err = a.Realloc(nxh, nx); err != nil { + return err + } + } + p.setNext(nxh) + if err = a.Free(rh); err != nil { + return err + } + + pp := bufs.GCache.Get(maxBuf) + defer bufs.GCache.Put(pp) + if pp, err = a.Get(pp, parent); err != nil { + return err + } + + if btreeIndexPage(pp).len() > 1 { + pp = btreeIndexPage(pp).extract(parentIndex) + btreeIndexPage(pp).setChild(parentIndex, ph) + if err = a.Realloc(parent, pp); err != nil { + return err + } + + return a.Realloc(ph, p) + } + + if err = a.Free(iroot); err != nil { + return err + } + + if err = a.Realloc(ph, p); err != nil { + return err + } + + var b7 [7]byte + return a.Realloc(root, h2b(b7[:], ph)) +} + +// external "root" is stable and contains the real root. +type btree int64 + +func newBTree(a btreeStore) (btree, error) { + r, err := a.Alloc(zeros[:7]) + return btree(r), err +} + +func (root btree) String(a btreeStore) string { + r := bufs.GCache.Get(16) + defer bufs.GCache.Put(r) + r, err := a.Get(r, int64(root)) + if err != nil { + panic(err) + } + + iroot := b2h(r) + m := map[int64]bool{int64(root): true} + + s := []string{fmt.Sprintf("tree %#x -> %#x\n====", root, iroot)} + if iroot == 0 { + return s[0] + } + + var f func(int64, string) + f = func(h int64, ind string) { + if m[h] { + return + } + + m[h] = true + var b btreePage = bufs.GCache.Get(maxBuf) + defer bufs.GCache.Put(b) + var err error + if b, err = a.Get(b, h); err != nil { + panic(err) + } + + s = append(s, fmt.Sprintf("%s@%#x", ind, h)) + switch b.isIndex() { + case true: + da := []int64{} + b := btreeIndexPage(b) + for i := 0; i < b.len(); i++ { + c, d := b.child(i), b.dataPage(i) + s = append(s, fmt.Sprintf("%schild[%d] %#x dataPage[%d] %#x", ind, i, c, i, d)) + da = append(da, c) + da = append(da, d) + } + i := b.len() + c := b.child(i) + s = append(s, fmt.Sprintf("%schild[%d] %#x", ind, i, c)) + for _, c := range da { + f(c, ind+" ") + } + f(c, ind+" ") + case false: + b := btreeDataPage(b) + s = append(s, fmt.Sprintf("%sprev %#x next %#x", ind, b.prev(), b.next())) + for i := 0; i < b.len(); i++ { + k, err := b.key(a, i) + if err != nil { + panic(err) + } + + v, err := b.value(a, i) + if err != nil { + panic(err) + } + + s = append(s, fmt.Sprintf("%sK[%d]|% x| V[%d]|% x|", ind, i, k, i, v)) + } + } + } + + f(int64(iroot), "") + return strings.Join(s, "\n") +} + +func (root btree) put(dst []byte, a btreeStore, c func(a, b []byte) int, key, value []byte, canOverwrite bool) (prev []byte, err error) { + prev, _, err = root.put2(dst, a, c, key, func(key, old []byte) (new []byte, write bool, err error) { + new, write = value, true + return + }) + return +} + +func (root btree) put2(dst []byte, a btreeStore, c func(a, b []byte) int, key []byte, upd func(key, old []byte) (new []byte, write bool, err error)) (old []byte, written bool, err error) { + var r, value []byte + if r, err = a.Get(dst, int64(root)); err != nil { + return + } + + iroot := b2h(r) + var h int64 + if iroot == 0 { + p := newBTreeDataPage() + defer bufs.GCache.Put(p) + if value, written, err = upd(key, nil); err != nil || !written { + return + } + + if p, err = p.insertItem(a, 0, key, value); err != nil { + return + } + + h, err = a.Alloc(p) + if err != nil { + return nil, true, err + } + + err = a.Realloc(int64(root), h2b(r, h)[:7]) + return + } + + parentIndex := -1 + var parent int64 + ph := iroot + + p := bufs.GCache.Get(maxBuf) + defer bufs.GCache.Put(p) + + for { + if p, err = a.Get(p[:cap(p)], ph); err != nil { + return + } + + var index int + var ok bool + + if index, ok, err = btreePage(p).find(a, c, key); err != nil { + return + } + + switch { + case ok: // Key found + if btreePage(p).isIndex() { + ph = btreeIndexPage(p).dataPage(index) + if p, err = a.Get(p, ph); err != nil { + return + } + + if old, err = btreeDataPage(p).valueCopy(a, 0); err != nil { + return + } + + if value, written, err = upd(key, old); err != nil || !written { + return + } + + if _, err = btreeDataPage(p).swap(a, 0, value, true); err != nil { + return + } + + err = a.Realloc(ph, p) + return + } + + if old, err = btreeDataPage(p).valueCopy(a, index); err != nil { + return + } + + if value, written, err = upd(key, old); err != nil || !written { + return + } + + if _, err = btreeDataPage(p).swap(a, index, value, true); err != nil { + return + } + + err = a.Realloc(ph, p) + return + case btreePage(p).isIndex(): + if btreePage(p).len() > 2*kIndex { + if p, err = btreeIndexPage(p).split(a, root, &ph, parent, parentIndex, &index); err != nil { + return + } + } + parentIndex = index + parent = ph + ph = btreeIndexPage(p).child(index) + default: + if value, written, err = upd(key, nil); err != nil || !written { + return + } + + if btreePage(p).len() < 2*kData { // page is not full + if p, err = btreeDataPage(p).insertItem(a, index, key, value); err != nil { + return + } + + err = a.Realloc(ph, p) + return + } + + // page is full + p, err = btreeDataPage(p).overflow(a, int64(root), ph, parent, parentIndex, index, key, value) + return + } + } +} + +//TODO actually use 'dst' to return 'value' +func (root btree) get(a btreeStore, dst []byte, c func(a, b []byte) int, key []byte) (b []byte, err error) { + var r []byte + if r, err = a.Get(dst, int64(root)); err != nil { + return + } + + iroot := b2h(r) + if iroot == 0 { + return + } + + ph := iroot + + for { + var p btreePage + if p, err = a.Get(p, ph); err != nil { + return + } + + var index int + var ok bool + if index, ok, err = p.find(a, c, key); err != nil { + return + } + + switch { + case ok: + if p.isIndex() { + dh := btreeIndexPage(p).dataPage(index) + dp, err := a.Get(dst, dh) + if err != nil { + return nil, err + } + + return btreeDataPage(dp).value(a, 0) + } + + return btreeDataPage(p).value(a, index) + case p.isIndex(): + ph = btreeIndexPage(p).child(index) + default: + return + } + } +} + +//TODO actually use 'dst' to return 'value' +func (root btree) extract(a btreeStore, dst []byte, c func(a, b []byte) int, key []byte) (value []byte, err error) { + var r []byte + if r, err = a.Get(dst, int64(root)); err != nil { + return + } + + iroot := b2h(r) + if iroot == 0 { + return + } + + ph := iroot + parentIndex := -1 + var parent int64 + + p := bufs.GCache.Get(maxBuf) + defer bufs.GCache.Put(p) + + for { + if p, err = a.Get(p[:cap(p)], ph); err != nil { + return + } + + var index int + var ok bool + if index, ok, err = btreePage(p).find(a, c, key); err != nil { + return + } + + if ok { + if btreePage(p).isIndex() { + dph := btreeIndexPage(p).dataPage(index) + dp, err := a.Get(dst, dph) + if err != nil { + return nil, err + } + + if btreeDataPage(dp).len() > kData { + if dp, value, err = btreeDataPage(dp).extract(a, 0); err != nil { + return nil, err + } + + return value, a.Realloc(dph, dp) + } + + if btreeIndexPage(p).len() < kIndex && ph != iroot { + var err error + if p, err = btreeIndexPage(p).underflow(a, int64(root), iroot, parent, &ph, parentIndex, &index); err != nil { + return nil, err + } + } + parentIndex = index + 1 + parent = ph + ph = btreeIndexPage(p).child(parentIndex) + continue + } + + p, value, err = btreeDataPage(p).extract(a, index) + if btreePage(p).len() >= kData { + err = a.Realloc(ph, p) + return + } + + if ph != iroot { + err = btreeDataPage(p).underflow(a, int64(root), iroot, parent, ph, parentIndex) + return + } + + if btreePage(p).len() == 0 { + if err = a.Free(ph); err != nil { + return + } + + err = a.Realloc(int64(root), zeros[:7]) + return + } + err = a.Realloc(ph, p) + return + } + + if !btreePage(p).isIndex() { + return + } + + if btreePage(p).len() < kIndex && ph != iroot { + if p, err = btreeIndexPage(p).underflow(a, int64(root), iroot, parent, &ph, parentIndex, &index); err != nil { + return nil, err + } + } + parentIndex = index + parent = ph + ph = btreeIndexPage(p).child(index) + } +} + +func (root btree) deleteAny(a btreeStore) (bool, error) { + r := bufs.GCache.Get(7) + defer bufs.GCache.Put(r) + var err error + if r, err = a.Get(r, int64(root)); err != nil { + return false, err + } + + iroot := b2h(r) + if iroot == 0 { + return true, nil + } + + ph := iroot + parentIndex := -1 + var parent int64 + p := bufs.GCache.Get(maxBuf) + defer bufs.GCache.Put(p) + + for { + if p, err = a.Get(p, ph); err != nil { + return false, err + } + + index := btreePage(p).len() / 2 + if btreePage(p).isIndex() { + dph := btreeIndexPage(p).dataPage(index) + dp := bufs.GCache.Get(maxBuf) + defer bufs.GCache.Put(dp) + if dp, err = a.Get(dp, dph); err != nil { + return false, err + } + + if btreeDataPage(dp).len() > kData { + if dp, _, err = btreeDataPage(dp).extract(a, 0); err != nil { + return false, err + } + + return false, a.Realloc(dph, dp) + } + + if btreeIndexPage(p).len() < kIndex && ph != iroot { + if p, err = btreeIndexPage(p).underflow(a, int64(root), iroot, parent, &ph, parentIndex, &index); err != nil { + return false, err + } + } + parentIndex = index + 1 + parent = ph + ph = btreeIndexPage(p).child(parentIndex) + continue + } + + p, _, err = btreeDataPage(p).extract(a, index) + if btreePage(p).len() >= kData { + err = a.Realloc(ph, p) + return false, err + } + + if ph != iroot { + err = btreeDataPage(p).underflow(a, int64(root), iroot, parent, ph, parentIndex) + return false, err + } + + if btreePage(p).len() == 0 { + if err = a.Free(ph); err != nil { + return true, err + } + + return true, a.Realloc(int64(root), zeros[:7]) + } + + return false, a.Realloc(ph, p) + } +} + +func (root btree) first(a btreeStore) (ph int64, p btreeDataPage, err error) { + r := bufs.GCache.Get(7) + defer bufs.GCache.Put(r) + if r, err = a.Get(r, int64(root)); err != nil { + return + } + + for ph = b2h(r); ph != 0; ph = btreeIndexPage(p).child(0) { + if p, err = a.Get(p, ph); err != nil { + return + } + + if !btreePage(p).isIndex() { + break + } + } + + return +} + +func (root btree) last(a btreeStore) (ph int64, p btreeDataPage, err error) { + r := bufs.GCache.Get(7) + defer bufs.GCache.Put(r) + if r, err = a.Get(r, int64(root)); err != nil { + return + } + + for ph = b2h(r); ph != 0; ph = btreeIndexPage(p).child(btreeIndexPage(p).len()) { + if p, err = a.Get(p, ph); err != nil { + return + } + + if !btreePage(p).isIndex() { + break + } + } + + return +} + +// key >= p[index].key +func (root btree) seek(a btreeStore, c func(a, b []byte) int, key []byte) (p btreeDataPage, index int, equal bool, err error) { + r := bufs.GCache.Get(7) + defer bufs.GCache.Put(r) + if r, err = a.Get(r, int64(root)); err != nil { + return + } + + for ph := b2h(r); ph != 0; ph = btreeIndexPage(p).child(index) { + if p, err = a.Get(p, ph); err != nil { + break + } + + if index, equal, err = btreePage(p).find(a, c, key); err != nil { + break + } + + if equal { + if !btreePage(p).isIndex() { + break + } + + p, err = a.Get(p, btreeIndexPage(p).dataPage(index)) + index = 0 + break + } + + if !btreePage(p).isIndex() { + break + } + } + return +} + +func (root btree) clear(a btreeStore) (err error) { + r := bufs.GCache.Get(7) + defer bufs.GCache.Put(r) + if r, err = a.Get(r, int64(root)); err != nil { + return + } + + iroot := b2h(r) + if iroot == 0 { + return + } + + if err = root.clear2(a, iroot); err != nil { + return + } + + var b [7]byte + return a.Realloc(int64(root), b[:]) +} + +func (root btree) clear2(a btreeStore, ph int64) (err error) { + var p = bufs.GCache.Get(maxBuf) + defer bufs.GCache.Put(p) + if p, err = a.Get(p, ph); err != nil { + return + } + + switch btreePage(p).isIndex() { + case true: + ip := btreeIndexPage(p) + for i := 0; i <= ip.len(); i++ { + root.clear2(a, ip.child(i)) + + } + case false: + dp := btreeDataPage(p) + for i := 0; i < dp.len(); i++ { + if err = dp.setKey(a, i, nil); err != nil { + return + } + + if err = dp.setValue(a, i, nil); err != nil { + return + } + } + } + return a.Free(ph) +} diff --git a/Godeps/_workspace/src/github.com/cznic/exp/lldb/btree_test.go b/Godeps/_workspace/src/github.com/cznic/exp/lldb/btree_test.go new file mode 100644 index 0000000..1884ef8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/exp/lldb/btree_test.go @@ -0,0 +1,1887 @@ +// Copyright 2014 The lldb 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 lldb + +import ( + "bytes" + "encoding/binary" + "encoding/hex" + "flag" + "fmt" + "math" + "math/rand" + "os" + "runtime" + "testing" + + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/fileutil" + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/mathutil" +) + +var ( + testFrom = flag.Uint("from", 0, "test I [-from, -N)") + noGrow = flag.Bool("noGrow", false, "check only embeded keys/values") +) + +func verifyPageLinks(a btreeStore, tree btree, n int) (err error) { + var p btreeDataPage + var ph int64 + if ph, p, err = tree.first(a); err != nil { + return + } + + if n == 0 { + if ph != 0 || p != nil { + return fmt.Errorf("first() should returned nil page") + } + + ph2, p2, err := tree.last(a) + if err != nil { + return err + } + + if ph2 != 0 || p2 != nil { + return fmt.Errorf("last() should returned nil page") + } + + } + + n0 := n + var prev int64 + var lastKey []byte + for ph != 0 { + if p, err = a.Get(nil, ph); err != nil { + return + } + + if g, e := p.prev(), prev; g != e { + return fmt.Errorf("broken L-R DLL chain: p %d p.prev %d, exp %d", ph, g, e) + } + + for i := 0; i < p.len(); i++ { + key, err := p.key(a, i) + if err != nil { + return err + } + + if key == nil { + return fmt.Errorf("nil key") + } + + if lastKey != nil && !(bytes.Compare(lastKey, key) < 0) { + return fmt.Errorf("L-R key ordering broken") + } + + lastKey = key + n-- + } + + prev, ph = ph, p.next() + } + + if n != 0 { + return fmt.Errorf("# of keys off by %d (L-R)", n) + } + + n = n0 + if ph, p, err = tree.last(a); err != nil { + return + } + + lastKey = nil + var next int64 + + for ph != 0 { + if p, err = a.Get(nil, ph); err != nil { + return + } + + if g, e := p.next(), next; g != e { + return fmt.Errorf("broken R-L DLL chain") + } + + for i := p.len() - 1; i >= 0; i-- { + key, err := p.key(a, i) + if err != nil { + return err + } + + if key == nil { + return fmt.Errorf("nil key") + } + + if lastKey != nil && !(bytes.Compare(key, lastKey) < 0) { + return fmt.Errorf("R-L key ordering broken") + } + + lastKey = key + n-- + } + + next, ph = ph, p.prev() + } + + if n != 0 { + return fmt.Errorf("# of keys off by %d (R-L)", n) + } + + return +} + +func testBTreePut1(t *testing.T, nf func() btreeStore, grow, from, to, xor int64) (tree btree) { + if *noGrow { + grow = 0 + } + + a := nf() + if a == nil { + t.Fatal(a) + } + + var err error + tree, err = newBTree(a) + if err != nil { + t.Fatal(err) + } + + if err := verifyPageLinks(a, tree, 0); err != nil { + t.Fatal(err) + } + + // Write and read back + var k, v, prevValue [7]byte + + n := 0 + for i := from; i < to; i++ { + h2b(k[:], 0x0100000000+i^xor) + h2b(v[:], 0x0200000000+i^xor) + kk := append(make([]byte, grow*i), k[:]...) + vv := append(make([]byte, grow*i), v[:]...) + prev, err := tree.put(nil, a, nil, kk, vv, true) + if err != nil || len(prev) != 0 { + t.Fatal(i, prev, err) + } + + var buf []byte + if buf, err = tree.get(a, nil, nil, kk); err != nil { + t.Fatal(err) + } + + if !bytes.Equal(buf, vv) { + t.Fatalf("\nK %sG %sE %s%s", hex.Dump(kk), hex.Dump(buf), hex.Dump(vv), tree.String(a)) + } + + n++ + } + + if err := verifyPageLinks(a, tree, n); err != nil { + t.Fatalf("%s\n%s", err, tree.String(a)) + } + + // Overwrite, read and extract + for i := from; i < to; i++ { + h2b(k[:], 0x0100000000+i^xor) + h2b(prevValue[:], 0x0200000000+i^xor) + h2b(v[:], 0x0300000000+i^xor) + kk := append(make([]byte, grow*i), k[:]...) + vv := append(make([]byte, grow*i), v[:]...) + expPrev := append(make([]byte, grow*i), prevValue[:]...) + gotPrev, err := tree.put(nil, a, nil, kk, vv, true) + if err != nil { + t.Fatal(i, err) + } + + if !bytes.Equal(gotPrev, expPrev) { + t.Fatalf("\nK %sG %sE %s%s", hex.Dump(kk), hex.Dump(gotPrev), hex.Dump(expPrev), tree.String(a)) + } + + var buf []byte + if buf, err = tree.get(a, nil, nil, kk); err != nil { + t.Fatal(err) + } + + if !bytes.Equal(buf, vv) { + t.Fatalf("\n%s%s%s%s", hex.Dump(kk), hex.Dump(buf), hex.Dump(vv), tree.String(a)) + } + + buf = nil + if buf, err = tree.extract(a, nil, nil, kk); err != nil { + t.Fatal(err) + } + + if !bytes.Equal(buf, vv) { + t.Fatalf("i %d, from [%d, %d)\nK %sG %sE %s%s", i, from, to, hex.Dump(kk), hex.Dump(buf), hex.Dump(vv), tree.String(a)) + } + + buf = nil + if buf, err = tree.get(a, nil, nil, kk); err != nil { + t.Fatal(err) + } + + if buf != nil { + t.Fatalf("\nK %sB %s%s", hex.Dump(kk), hex.Dump(buf), tree.String(a)) + } + + buf = nil + if buf, err = tree.extract(a, nil, nil, kk); err != nil { + t.Fatal(err) + } + + if buf != nil { + t.Fatalf("\n%s\n%s%s", hex.Dump(kk), hex.Dump(buf), tree.String(a)) + } + + n-- + if err := verifyPageLinks(a, tree, n); err != nil { + t.Fatalf("%s\n%s", err, tree.String(a)) + } + } + + return +} + +var xors = [...]int64{0, 0xffffffff, 0x55555555, 0xaaaaaaaa} + +func TestBTreePutGetExtract(t *testing.T) { + N := int64(3 * kData) + from := int64(*testFrom) + + for grow := 0; grow < 2; grow++ { + for _, x := range xors { + var s *memBTreeStore + tree := testBTreePut1(t, func() btreeStore { s = newMemBTreeStore(); return s }, int64(grow), from, N, x) + if err := verifyPageLinks(s, tree, 0); err != nil { + t.Fatal(err) + } + + if g, e := len(s.m), 1; g != e { + t.Fatalf("leak(s) %d %d\n%s", g, e, s) + } + } + } +} + +func testBTreePut2(t *testing.T, nf func() btreeStore, grow, n int) (tree btree) { + if *noGrow { + grow = 0 + } + rng, err := mathutil.NewFC32(math.MinInt32, math.MaxInt32, true) + if err != nil { + t.Fatal(err) + } + + a := nf() + if a == nil { + t.Fatal(a) + } + + tree, err = newBTree(a) + if err != nil { + t.Fatal(err) + } + + var k, v [7]byte + for i := 0; i < n; i++ { + ik, iv := int64(rng.Next()), int64(rng.Next()) + h2b(k[:], ik) + h2b(v[:], iv) + kk := append(make([]byte, grow*i), k[:]...) + vv := append(make([]byte, grow*i), v[:]...) + prev, err := tree.put(nil, a, nil, kk, vv, true) + if err != nil || len(prev) != 0 { + t.Fatal(i, prev, err) + } + + var buf []byte + if buf, err = tree.get(a, nil, nil, kk); err != nil { + t.Fatal(err) + } + + if !bytes.Equal(buf, vv) { + t.Fatalf("\n%s%s%s%s", hex.Dump(kk), hex.Dump(buf), hex.Dump(vv), tree.String(a)) + } + } + + if err := verifyPageLinks(a, tree, n); err != nil { + t.Fatalf("%s\n%s\n", err, tree.String(a)) + } + + rng.Seek(0) + for i := 0; i < n; i++ { + ik, iv := int64(rng.Next()), int64(rng.Next()) + h2b(k[:], ik) + h2b(v[:], iv) + kk := append(make([]byte, grow*i), k[:]...) + vv := append(make([]byte, grow*i), v[:]...) + var buf []byte + buf, err := tree.extract(a, nil, nil, kk) + if err != nil { + t.Fatal(i, err) + } + + if !bytes.Equal(buf, vv) { + t.Fatalf("\n%s\n%s\n%s\n%s", hex.Dump(kk), hex.Dump(buf), hex.Dump(vv), tree.String(a)) + } + + if err := verifyPageLinks(a, tree, n-i-1); err != nil { + t.Fatalf("%s\n%s", err, tree.String(a)) + } + } + + return +} + +func TestBTreePutGetExtractRnd(t *testing.T) { + N := *testN + + for grow := 0; grow < 2; grow++ { + var s *memBTreeStore + tree := testBTreePut2(t, func() btreeStore { s = newMemBTreeStore(); return s }, grow, N) + if err := verifyPageLinks(s, tree, 0); err != nil { + t.Fatal(err) + } + + if g, e := len(s.m), 1; g != e { + t.Fatalf("leak(s) %d %d\n%s", g, e, s) + } + } +} + +func benchmarkBTreePut(b *testing.B, v []byte) { + b.StopTimer() + rng := rand.New(rand.NewSource(42)) + ka := make([][7]byte, b.N) + for _, v := range ka { + h2b(v[:], int64(rng.Int63())) + } + a := newMemBTreeStore() + tree, err := newBTree(a) + if err != nil { + b.Fatal(err) + } + + runtime.GC() + b.StartTimer() + for _, k := range ka { + tree.put(nil, a, bytes.Compare, k[:], v, true) + } +} + +func BenchmarkBTreePut1(b *testing.B) { + v := make([]byte, 1) + benchmarkBTreePut(b, v) +} + +func BenchmarkBTreePut8(b *testing.B) { + v := make([]byte, 8) + benchmarkBTreePut(b, v) +} + +func BenchmarkBTreePut16(b *testing.B) { + v := make([]byte, 16) + benchmarkBTreePut(b, v) +} + +func BenchmarkBTreePut32(b *testing.B) { + v := make([]byte, 32) + benchmarkBTreePut(b, v) +} + +func benchmarkBTreeGet(b *testing.B, v []byte) { + b.StopTimer() + rng := rand.New(rand.NewSource(42)) + ka := make([][7]byte, b.N) + for _, v := range ka { + h2b(v[:], int64(rng.Int63())) + } + a := newMemBTreeStore() + tree, err := newBTree(a) + if err != nil { + b.Fatal(err) + } + + for _, k := range ka { + tree.put(nil, a, bytes.Compare, k[:], v, true) + } + buf := make([]byte, len(v)) + runtime.GC() + b.StartTimer() + for _, k := range ka { + tree.get(a, buf, bytes.Compare, k[:]) + } +} + +func BenchmarkBTreeGet1(b *testing.B) { + v := make([]byte, 1) + benchmarkBTreeGet(b, v) +} + +func BenchmarkBTreeGet8(b *testing.B) { + v := make([]byte, 8) + benchmarkBTreeGet(b, v) +} + +func BenchmarkBTreeGet16(b *testing.B) { + v := make([]byte, 16) + benchmarkBTreeGet(b, v) +} + +func BenchmarkBTreeGet32(b *testing.B) { + v := make([]byte, 32) + benchmarkBTreeGet(b, v) +} + +func TestbTreeSeek(t *testing.T) { + N := int64(*testN) + + tree := NewBTree(nil) + + // Fill + for i := int64(1); i <= N; i++ { + tree.Set(enc8(10*i), enc8(10*i+1)) + } + + // Check + a, root := tree.store, tree.root + for i := int64(1); i <= N; i++ { + // Exact match + lowKey := enc8(10*i - 1) + key := enc8(10 * i) + highKey := enc8(10*i + 1) + p, index, eq, err := root.seek(a, nil, key) + if err != nil { + t.Fatal(err) + } + + if !eq { + t.Fatal(i) + } + + if btreePage(p).isIndex() { + t.Fatal(i, "need btreeDataPage") + } + + dp := btreeDataPage(p) + n := dp.len() + if n < 0 || n > 2*kData { + t.Fatal(i, n) + } + + if index < 0 || index >= n { + t.Fatal(index) + } + + g, err := dp.key(a, index) + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(g, key) { + t.Fatal(i) + } + + g, err = dp.value(a, index) + if err != nil { + t.Fatal(err) + } + + value := enc8(10*i + 1) + if !bytes.Equal(g, value) { + t.Fatal(i) + } + + // Nonexistent "low" key. Search for 9 should return the key 10. + p, index, eq, err = root.seek(a, nil, lowKey) + if err != nil { + t.Fatal(err) + } + + if eq { + t.Fatal(i) + } + + if btreePage(p).isIndex() { + t.Fatal(i, "need btreeDataPage") + } + + dp = btreeDataPage(p) + n = dp.len() + if n < 0 || n > 2*kData { + t.Fatal(i, n) + } + + if index < 0 || index > n { + t.Fatal(index, n) + } + + if index == n { + ph := dp.next() + index = 0 + if dp, err = a.Get(p, ph); err != nil { + t.Fatal(err) + } + } + + g, err = dp.key(a, index) + if err != nil { + t.Fatal(err) + } + + expKey := key + if !bytes.Equal(g, expKey) { + fmt.Println(root.String(a)) + //t.Fatalf("%d low|% x| g|% x| e|% x|", i, lowKey, g, expKey) + } + + g, err = dp.value(a, index) + if err != nil { + t.Fatal(err) + } + + value = enc8(10*i + 1) + if !bytes.Equal(g, value) { + t.Fatal(i) + } + + // Nonexistent "high" key. Search for 11 should return the key 20. + p, index, eq, err = root.seek(a, nil, highKey) + if err != nil { + t.Fatal(err) + } + + if eq { + t.Fatal(i) + } + + if btreePage(p).isIndex() { + t.Fatal(i, "need btreeDataPage") + } + + dp = btreeDataPage(p) + n = dp.len() + if n < 0 || n > 2*kData { + t.Fatal(i, n) + } + + if index < 0 || index > n { + t.Fatal(index, n) + } + + if index == n { + ph := dp.next() + if i == N { + if ph != 0 { + t.Fatal(ph) + } + + continue + } + + index = 0 + if dp, err = a.Get(p, ph); err != nil { + t.Fatal(err) + } + } + + g, err = dp.key(a, index) + if err != nil { + t.Fatal(err) + } + + expKey = enc8(10 * (i + 1)) + if !bytes.Equal(g, expKey) { + //fmt.Println(root.String(a)) + t.Fatalf("%d low|% x| g|% x| e|% x|", i, lowKey, g, expKey) + } + + g, err = dp.value(a, index) + if err != nil { + t.Fatal(err) + } + + value = enc8(10*(i+1) + 1) + if !bytes.Equal(g, value) { + t.Fatal(i) + } + + } +} + +func enc8(n int64) []byte { + var b [8]byte + h2b(b[:], n) + return b[:] +} + +func dec8(b []byte) (int64, error) { + if len(b) != 0 { + return 0, fmt.Errorf("dec8: len != 8 but %d", len(b)) + } + + return b2h(b), nil +} + +func TestbTreeNext(t *testing.T) { + N := int64(*testN) + + tree := NewBTree(nil) + enum, _, err := tree.seek(enc8(0)) + if err != nil { + t.Fatal(err) + } + + if _, _, err = enum.current(); !fileutil.IsEOF(err) { + t.Fatal(err) + } + + if err = enum.next(); !fileutil.IsEOF(err) { + t.Fatal(err) + } + + if err = enum.prev(); !fileutil.IsEOF(err) { + t.Fatal(err) + } + + // Fill + for i := int64(1); i <= N; i++ { + tree.Set(enc8(10*i), enc8(10*i+1)) + } + + var eq bool + + enum, eq, err = tree.seek(enc8(0)) + if err != nil { + t.Fatal(err) + } + + if eq { + t.Fatal(eq) + } + + // index: 0 + if _, _, err = enum.current(); err != nil { + t.Fatal(err) + } + + if err = enum.next(); N > 1 && err != nil { + t.Fatal(err) + } + + enum, eq, err = tree.seek(enc8(N * 10)) + if err != nil { + t.Fatal(err) + } + + if !eq { + t.Fatal(eq) + } + + // index: N-1 + if _, _, err = enum.current(); err != nil { + t.Fatal(err) + } + + if err = enum.next(); N > 1 && !fileutil.IsEOF(err) { + t.Fatal(err) + } + + enum, eq, err = tree.seek(enc8(N*10 + 1)) + if err != nil { + t.Fatal(err) + } + + if eq { + t.Fatal(eq) + } + + // index: N + if _, _, err = enum.current(); !fileutil.IsEOF(err) { + t.Fatal(err) + } + + if err = enum.next(); N > 1 && !fileutil.IsEOF(err) { + t.Fatal(err) + } + + enum, _, err = tree.seek(enc8(0)) + if err != nil { + t.Fatal(err) + } + + for i := int64(1); i <= N; i++ { + expKey, expValue := enc8(10*i), enc8(10*i+1) + k, v, err := enum.current() + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(k, expKey) { + t.Fatal(i) + } + + if !bytes.Equal(v, expValue) { + t.Fatal(i) + } + + switch { + case i == N: + if err := enum.next(); !fileutil.IsEOF(err) { + t.Fatal(err) + } + default: + if err := enum.next(); err != nil { + t.Fatal(err) + } + } + } +} + +func TestbTreePrev(t *testing.T) { + N := int64(*testN) + + tree := NewBTree(nil) + enum, _, err := tree.seek(enc8(0)) + if err != nil { + t.Fatal(err) + } + + if _, _, err = enum.current(); !fileutil.IsEOF(err) { + t.Fatal(err) + } + + if err = enum.next(); !fileutil.IsEOF(err) { + t.Fatal(err) + } + + if err = enum.prev(); !fileutil.IsEOF(err) { + t.Fatal(err) + } + + // Fill + for i := int64(1); i <= N; i++ { + tree.Set(enc8(10*i), enc8(10*i+1)) + } + + var eq bool + + enum, eq, err = tree.seek(enc8(0)) + if err != nil { + t.Fatal(err) + } + + if eq { + t.Fatal(eq) + } + + // index: 0 + if _, _, err = enum.current(); err != nil { + t.Fatal(err) + } + + if err = enum.prev(); !fileutil.IsEOF(err) { + t.Fatal(err) + } + + enum, eq, err = tree.seek(enc8(N * 10)) + if err != nil { + t.Fatal(err) + } + + if !eq { + t.Fatal(eq) + } + + // index: N-1 + if _, _, err = enum.current(); err != nil { + t.Fatal(err) + } + + if err = enum.prev(); N > 1 && err != nil { + t.Fatal(err) + } + + enum, eq, err = tree.seek(enc8(N*10 + 1)) + if err != nil { + t.Fatal(err) + } + + if eq { + t.Fatal(eq) + } + + // index: N + if _, _, err = enum.current(); !fileutil.IsEOF(err) { + t.Fatal(err) + } + + if err = enum.prev(); err != nil { + t.Fatal(err) + } + + enum, _, err = tree.seek(enc8(N * 10)) + if err != nil { + t.Fatal(err) + } + + for i := N; i >= 1; i-- { + expKey, expValue := enc8(10*i), enc8(10*i+1) + k, v, err := enum.current() + if err != nil { + t.Fatal(err) + } + + if !bytes.Equal(k, expKey) { + t.Fatalf("%d k|% x| expK|% x| %s\n", i, k, expKey, tree.root.String(tree.store)) + } + + if !bytes.Equal(v, expValue) { + t.Fatal(i) + } + + switch { + case i == 1: + if err := enum.prev(); !fileutil.IsEOF(err) { + t.Fatal(err) + } + default: + if err := enum.prev(); err != nil { + t.Fatal(i, err) + } + } + } +} + +func TestBTreeClear(t *testing.T) { + N := int64(*testN) + + var err error + var p []byte + for n := int64(0); n <= N; n = n*3/2 + 1 { + tree := NewBTree(nil) + for i := int64(0); i < n; i++ { + k := append(make([]byte, kKV), enc8(10*i+1)...) + v := append(make([]byte, kKV+1), enc8(10*i+2)...) + if err = tree.Set(k, v); err != nil { + t.Fatal(err) + } + } + + if err = tree.Clear(); err != nil { + t.Fatal(err) + } + + if g, e := len(tree.store.(*memBTreeStore).m), 1; g != e { + t.Fatalf("%v %v %v\n%s", n, g, e, tree.store.(*memBTreeStore).String()) + } + + if p, err = tree.store.Get(p, 1); err != nil { + t.Fatal(err) + } + + if g, e := p, zeros[:7]; len(g) != 0 && !bytes.Equal(g, e) { + t.Fatalf("|% x| |% x|", g, e) + } + } +} + +func TestBTreeRemove(t *testing.T) { + N := int64(*testN) + + for n := int64(0); n <= N; n = n*3/2 + 1 { + f := NewMemFiler() + store, err := NewAllocator(f, &Options{}) + if err != nil { + t.Fatal(err) + } + + sz0, err := f.Size() + if err != nil { + t.Fatal(err) + } + + tree, handle, err := CreateBTree(store, nil) + if err != nil { + t.Fatal(err) + } + + for i := int64(0); i < n; i++ { + k := append(make([]byte, kKV), enc8(10*i+1)...) + v := append(make([]byte, kKV+1), enc8(10*i+2)...) + if err = tree.Set(k, v); err != nil { + t.Fatal(err) + } + } + + if err = RemoveBTree(store, handle); err != nil { + t.Fatal(err) + } + + sz, err := f.Size() + if err != nil { + t.Fatal(err) + } + + if g, e := sz-sz0, int64(0); g != e { + t.Fatal(g, e) + } + } +} + +func collate(a, b []byte) (r int) { + da, err := DecodeScalars(a) + if err != nil { + panic(err) + } + + db, err := DecodeScalars(b) + if err != nil { + panic(err) + } + + r, err = Collate(da, db, nil) + if err != nil { + panic(err) + } + + return +} + +func TestBTreeCollatingBug(t *testing.T) { + tree := NewBTree(collate) + + date, err := EncodeScalars("Date") + if err != nil { + t.Fatal(err) + } + + customer, err := EncodeScalars("Customer") + if err != nil { + t.Fatal(err) + } + + if g, e := collate(customer, date), -1; g != e { + t.Fatal(g, e) + } + + if g, e := collate(date, customer), 1; g != e { + t.Fatal(g, e) + } + + err = tree.Set(date, nil) + if err != nil { + t.Fatal(err) + } + + err = tree.Set(customer, nil) + if err != nil { + t.Fatal(err) + } + + var b bytes.Buffer + tree.Dump(&b) + t.Logf("\n%s", b.String()) + + key, _, err := tree.First() + if err != nil { + t.Fatal(err) + } + + if g, e := key, customer; !bytes.Equal(g, e) { + t.Fatal(g, e) + } + +} + +func TestExtract(t *testing.T) { // Test of the exported wrapper only, .extract tested elsewhere + bt := NewBTree(nil) + bt.Set([]byte("a"), []byte("b")) + bt.Set([]byte("c"), []byte("d")) + bt.Set([]byte("e"), []byte("f")) + + if v, err := bt.Get(nil, []byte("a")); string(v) != "b" || err != nil { + t.Fatal(v, err) + } + + if v, err := bt.Get(nil, []byte("c")); string(v) != "d" || err != nil { + t.Fatal(v, err) + } + + if v, err := bt.Get(nil, []byte("e")); string(v) != "f" || err != nil { + t.Fatal(v, err) + } + + if v, err := bt.Extract(nil, []byte("c")); string(v) != "d" || err != nil { + t.Fatal(v, err) + } + + if v, err := bt.Get(nil, []byte("a")); string(v) != "b" || err != nil { + t.Fatal(v, err) + } + + if v, err := bt.Get(nil, []byte("c")); v != nil || err != nil { + t.Fatal(v, err) + } + + if v, err := bt.Get(nil, []byte("e")); string(v) != "f" || err != nil { + t.Fatal(v, err) + } +} + +func TestFirst(t *testing.T) { + bt := NewBTree(nil) + + if k, v, err := bt.First(); k != nil || v != nil || err != nil { + t.Fatal(k, v, err) + } + + bt.Set([]byte("a"), []byte("b")) + bt.Set([]byte("c"), []byte("d")) + + if k, v, err := bt.First(); string(k) != "a" || string(v) != "b" || err != nil { + t.Fatal(k, v, err) + } + + if err := bt.Delete([]byte("a")); err != nil { + t.Fatal(err) + } + + if k, v, err := bt.First(); string(k) != "c" || string(v) != "d" || err != nil { + t.Fatal(k, v, err) + } + + if err := bt.Delete([]byte("c")); err != nil { + t.Fatal(err) + } + + if k, v, err := bt.First(); k != nil || v != nil || err != nil { + t.Fatal(k, v, err) + } +} + +func TestLast(t *testing.T) { + bt := NewBTree(nil) + + if k, v, err := bt.First(); k != nil || v != nil || err != nil { + t.Fatal(k, v, err) + } + + bt.Set([]byte("a"), []byte("b")) + bt.Set([]byte("c"), []byte("d")) + + if k, v, err := bt.Last(); string(k) != "c" || string(v) != "d" || err != nil { + t.Fatal(k, v, err) + } + + if err := bt.Delete([]byte("c")); err != nil { + t.Fatal(err) + } + + if k, v, err := bt.First(); string(k) != "a" || string(v) != "b" || err != nil { + t.Fatal(k, v, err) + } + + if err := bt.Delete([]byte("a")); err != nil { + t.Fatal(err) + } + + if k, v, err := bt.First(); k != nil || v != nil || err != nil { + t.Fatal(k, v, err) + } +} + +func TestseekFirst(t *testing.T) { + bt := NewBTree(nil) + + enum, err := bt.seekFirst() + if !fileutil.IsEOF(err) { + t.Fatal(err) + } + + bt.Set([]byte("c"), []byte("d")) + enum, err = bt.seekFirst() + if err != nil { + t.Fatal(err) + } + + err = enum.prev() + if !fileutil.IsEOF(err) { + t.Fatal(err) + } + + err = enum.next() + if !fileutil.IsEOF(err) { + t.Fatal(err) + } + + k, v, err := enum.current() + if err != nil { + t.Fatal(err) + } + + if string(k) != "c" || string(v) != "d" { + t.Fatal(k, v) + } + + bt.Set([]byte("a"), []byte("b")) + enum, err = bt.seekFirst() + if err != nil { + t.Fatal(err) + } + + err = enum.prev() + if !fileutil.IsEOF(err) { + t.Fatal(err) + } + + k, v, err = enum.current() + if err != nil { + t.Fatal(err) + } + + if string(k) != "a" || string(v) != "b" { + t.Fatal(k, v) + } + + err = enum.next() + if err != nil { + t.Fatal(err) + } + + k, v, err = enum.current() + if err != nil { + t.Fatal(err) + } + + if string(k) != "c" || string(v) != "d" { + t.Fatal(k, v) + } +} + +func TestseekLast(t *testing.T) { + bt := NewBTree(nil) + + enum, err := bt.seekFirst() + if !fileutil.IsEOF(err) { + t.Fatal(err) + } + + bt.Set([]byte("a"), []byte("b")) + enum, err = bt.seekFirst() + if err != nil { + t.Fatal(err) + } + + err = enum.prev() + if !fileutil.IsEOF(err) { + t.Fatal(err) + } + + err = enum.next() + if !fileutil.IsEOF(err) { + t.Fatal(err) + } + + k, v, err := enum.current() + if err != nil { + t.Fatal(err) + } + + if string(k) != "a" || string(v) != "b" { + t.Fatal(k, v) + } + + bt.Set([]byte("c"), []byte("d")) + enum, err = bt.seekLast() + if err != nil { + t.Fatal(err) + } + + err = enum.next() + if !fileutil.IsEOF(err) { + t.Fatal(err) + } + + k, v, err = enum.current() + if err != nil { + t.Fatal(err) + } + + if string(k) != "c" || string(v) != "d" { + t.Fatal(k, v) + } + + err = enum.prev() + if err != nil { + t.Fatal(err) + } + + k, v, err = enum.current() + if err != nil { + t.Fatal(err) + } + + if string(k) != "a" || string(v) != "b" { + t.Fatal(k, v) + } +} + +func TestDeleteAny(t *testing.T) { + const N = 1e4 + rng := rand.New(rand.NewSource(42)) + ref := map[uint32]bool{} + tr := NewBTree(nil) + data := []byte{42} + var key [4]byte + for i := 0; i < N; i++ { + k := uint32(rng.Int()) + binary.LittleEndian.PutUint32(key[:], k) + if err := tr.Set(key[:], data); err != nil { + t.Fatal(err) + } + + ref[k] = true + } + + for i := len(ref); i != 0; i-- { + empty, err := tr.DeleteAny() + if err != nil { + t.Fatal(err) + } + + if empty && i != 1 { + t.Fatal(i) + } + } +} + +func benchmarkBTreeSetFiler(b *testing.B, f Filer, sz int) { + if err := f.BeginUpdate(); err != nil { + b.Error(err) + return + } + + a, err := NewAllocator(f, &Options{}) + if err != nil { + b.Error(err) + return + } + + tr, _, err := CreateBTree(a, nil) + if err != nil { + f.EndUpdate() + b.Error(err) + return + } + + if err = f.EndUpdate(); err != nil { + b.Error(err) + return + } + + keys := make([][8]byte, b.N) + for i := range keys { + binary.BigEndian.PutUint64(keys[i][:], uint64(i)) + } + v := make([]byte, sz) + runtime.GC() + b.ResetTimer() + for _, k := range keys { + if err = f.BeginUpdate(); err != nil { + b.Error(err) + return + } + + if err := tr.Set(k[:], v); err != nil { + f.EndUpdate() + b.Error(err) + return + } + + if err = f.EndUpdate(); err != nil { + b.Error(err) + return + } + } +} + +func benchmarkBTreeSetMemFiler(b *testing.B, sz int) { + f := NewMemFiler() + benchmarkBTreeSetFiler(b, f, sz) +} + +func BenchmarkBTreeSetMemFiler0(b *testing.B) { + benchmarkBTreeSetMemFiler(b, 0) +} + +func BenchmarkBTreeSetMemFiler1e1(b *testing.B) { + benchmarkBTreeSetMemFiler(b, 1e1) +} + +func BenchmarkBTreeSetMemFiler1e2(b *testing.B) { + benchmarkBTreeSetMemFiler(b, 1e2) +} + +func BenchmarkBTreeSetMemFiler1e3(b *testing.B) { + benchmarkBTreeSetMemFiler(b, 1e3) +} + +func benchmarkBTreeSetSimpleFileFiler(b *testing.B, sz int) { + dir, testDbName := temp() + defer os.RemoveAll(dir) + + f, err := os.OpenFile(testDbName, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0600) + if err != nil { + b.Fatal(err) + } + + defer f.Close() + + benchmarkBTreeSetFiler(b, NewSimpleFileFiler(f), sz) +} + +func BenchmarkBTreeSetSimpleFileFiler0(b *testing.B) { + benchmarkBTreeSetSimpleFileFiler(b, 0) +} + +func BenchmarkBTreeSetSimpleFileFiler1e1(b *testing.B) { + benchmarkBTreeSetSimpleFileFiler(b, 1e1) +} + +func BenchmarkBTreeSetSimpleFileFiler1e2(b *testing.B) { + benchmarkBTreeSetSimpleFileFiler(b, 1e2) +} + +func BenchmarkBTreeSetSimpleFileFiler1e3(b *testing.B) { + benchmarkBTreeSetSimpleFileFiler(b, 1e3) +} + +func benchmarkBTreeSetRollbackFiler(b *testing.B, sz int) { + dir, testDbName := temp() + defer os.RemoveAll(dir) + + f, err := os.OpenFile(testDbName, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0600) + if err != nil { + b.Fatal(err) + } + + defer f.Close() + + g := NewSimpleFileFiler(f) + var filer *RollbackFiler + if filer, err = NewRollbackFiler( + g, + func(sz int64) error { + if err = g.Truncate(sz); err != nil { + return err + } + + return g.Sync() + }, + g, + ); err != nil { + b.Error(err) + return + } + + benchmarkBTreeSetFiler(b, filer, sz) +} + +func BenchmarkBTreeSetRollbackFiler0(b *testing.B) { + benchmarkBTreeSetRollbackFiler(b, 0) +} + +func BenchmarkBTreeSetRollbackFiler1e1(b *testing.B) { + benchmarkBTreeSetRollbackFiler(b, 1e1) +} + +func BenchmarkBTreeSetRollbackFiler1e2(b *testing.B) { + benchmarkBTreeSetRollbackFiler(b, 1e2) +} + +func BenchmarkBTreeSetRollbackFiler1e3(b *testing.B) { + benchmarkBTreeSetRollbackFiler(b, 1e3) +} + +func benchmarkBTreeSetACIDFiler(b *testing.B, sz int) { + dir, testDbName := temp() + defer os.RemoveAll(dir) + + f, err := os.OpenFile(testDbName, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0600) + if err != nil { + b.Fatal(err) + } + + defer f.Close() + + wal, err := os.OpenFile(testDbName+".wal", os.O_CREATE|os.O_EXCL|os.O_RDWR, 0600) + if err != nil { + b.Fatal(err) + } + + defer wal.Close() + + filer, err := NewACIDFiler(NewSimpleFileFiler(f), wal) + if err != nil { + b.Error(err) + return + } + + benchmarkBTreeSetFiler(b, filer, sz) +} + +func BenchmarkBTreeSetACIDFiler0(b *testing.B) { + benchmarkBTreeSetACIDFiler(b, 0) +} + +func BenchmarkBTreeSetACIDFiler1e1(b *testing.B) { + benchmarkBTreeSetACIDFiler(b, 1e1) +} + +func BenchmarkBTreeSetACIDFiler1e2(b *testing.B) { + benchmarkBTreeSetACIDFiler(b, 1e2) +} + +func BenchmarkBTreeSetACIDFiler1e3(b *testing.B) { + benchmarkBTreeSetACIDFiler(b, 1e3) +} + +func testbTreeEnumeratorInvalidating(t *testing.T, mutate func(b *BTree) error) { + b := NewBTree(nil) + if err := b.Set([]byte{1}, []byte{2}); err != nil { + t.Fatal(err) + } + + if err := b.Set([]byte{3}, []byte{4}); err != nil { + t.Fatal(err) + } + + e, err := b.seekFirst() + if err != nil { + t.Fatal(err) + } + + if _, _, err = e.current(); err != nil { + t.Fatal(err) + } + + if err = e.next(); err != nil { + t.Fatal(err) + } + + if err = e.prev(); err != nil { + t.Fatal(err) + } + + if err = mutate(b); err != nil { + t.Fatal(err) + } + + if _, _, err = e.current(); err == nil { + t.Fatal(err) + } + + if _, ok := err.(*ErrINVAL); !ok { + t.Fatalf("%T", err) + } + + err = e.next() + if err == nil { + t.Fatal(err) + } + + if _, ok := err.(*ErrINVAL); !ok { + t.Fatalf("%T", err) + } + + err = e.prev() + if err == nil { + t.Fatal(err) + } + + if _, ok := err.(*ErrINVAL); !ok { + t.Fatalf("%T", err) + } + +} + +func TestBTreeEnumeratorInvalidating(t *testing.T) { + testbTreeEnumeratorInvalidating(t, func(b *BTree) error { return b.Clear() }) + testbTreeEnumeratorInvalidating(t, func(b *BTree) error { return b.Delete([]byte{1}) }) + testbTreeEnumeratorInvalidating(t, func(b *BTree) error { _, err := b.DeleteAny(); return err }) + testbTreeEnumeratorInvalidating(t, func(b *BTree) error { _, err := b.Extract(nil, []byte{1}); return err }) + testbTreeEnumeratorInvalidating(t, func(b *BTree) error { + _, _, err := b.Put( + nil, + []byte{1}, + func(k, o []byte) ([]byte, bool, error) { return nil, false, nil }, + ) + return err + }) + testbTreeEnumeratorInvalidating(t, func(b *BTree) error { return b.Set([]byte{4}, []byte{5}) }) +} + +func n2b(n int) []byte { + var b [8]byte + binary.BigEndian.PutUint64(b[:], uint64(n)) + return b[:] +} + +func b2n(b []byte) int { + if len(b) != 8 { + return mathutil.MinInt + } + + return int(binary.BigEndian.Uint64(b)) +} + +func TestBTreeSeekNext(t *testing.T) { + // seeking within 3 keys: 10, 20, 30 + table := []struct { + k int + hit bool + keys []int + }{ + {5, false, []int{10, 20, 30}}, + {10, true, []int{10, 20, 30}}, + {15, false, []int{20, 30}}, + {20, true, []int{20, 30}}, + {25, false, []int{30}}, + {30, true, []int{30}}, + {35, false, []int{}}, + } + + for i, test := range table { + up := test.keys + db := NewBTree(nil) + + if err := db.Set(n2b(10), n2b(100)); err != nil { + t.Fatal(i, err) + } + + if err := db.Set(n2b(20), n2b(200)); err != nil { + t.Fatal(i, err) + } + + if err := db.Set(n2b(30), n2b(300)); err != nil { + t.Fatal(i, err) + } + + for brokenSerial := 0; brokenSerial < 16; brokenSerial++ { + en, hit, err := db.Seek(n2b(test.k)) + if err != nil { + t.Fatal(err) + } + + if g, e := hit, test.hit; g != e { + t.Fatal(i, g, e) + } + + j := 0 + for { + if brokenSerial&(1<= len(up) { + t.Fatal(i, j, brokenSerial) + } + + if g, e := b2n(k), up[j]; g != e { + t.Fatal(i, j, brokenSerial, g, e) + } + + if g, e := len(v), 8; g != e { + t.Fatal(i, g, e) + } + + if g, e := b2n(v), 10*up[j]; g != e { + t.Fatal(i, g, e) + } + + j++ + + } + + if g, e := j, len(up); g != e { + t.Fatal(i, j, g, e) + } + } + + } +} + +func TestBTreeSeekPrev(t *testing.T) { + // seeking within 3 keys: 10, 20, 30 + table := []struct { + k int + hit bool + keys []int + }{ + {5, false, []int{10}}, + {10, true, []int{10}}, + {15, false, []int{20, 10}}, + {20, true, []int{20, 10}}, + {25, false, []int{30, 20, 10}}, + {30, true, []int{30, 20, 10}}, + {35, false, []int{}}, + } + + for i, test := range table { + down := test.keys + db := NewBTree(nil) + if err := db.Set(n2b(10), n2b(100)); err != nil { + t.Fatal(i, err) + } + + if err := db.Set(n2b(20), n2b(200)); err != nil { + t.Fatal(i, err) + } + + if err := db.Set(n2b(30), n2b(300)); err != nil { + t.Fatal(i, err) + } + + for brokenSerial := 0; brokenSerial < 16; brokenSerial++ { + en, hit, err := db.Seek(n2b(test.k)) + if err != nil { + t.Fatal(err) + } + + if g, e := hit, test.hit; g != e { + t.Fatal(i, g, e) + } + + j := 0 + for { + if brokenSerial&(1<= len(down) { + t.Fatal(i, j, brokenSerial) + } + + if g, e := b2n(k), down[j]; g != e { + t.Fatal(i, j, brokenSerial, g, e) + } + + if g, e := len(v), 8; g != e { + t.Fatal(i, g, e) + } + + if g, e := b2n(v), 10*down[j]; g != e { + t.Fatal(i, g, e) + } + + j++ + + } + + if g, e := j, len(down); g != e { + t.Fatal(i, j, g, e) + } + } + + } +} + +func TestBTreeSeekFirst(t *testing.T) { + db := NewBTree(nil) + en, err := db.SeekFirst() + if err == nil { + t.Fatal(err) + } + + if err := db.Set(n2b(100), n2b(1000)); err != nil { + t.Fatal(err) + } + + if en, err = db.SeekFirst(); err != nil { + t.Fatal(err) + } + + k, v, err := en.Next() + if err != nil { + t.Fatal(err) + } + + if g, e := b2n(k), 100; g != e { + t.Fatal(g, e) + } + + if g, e := b2n(v), 1000; g != e { + t.Fatal(g, e) + } + + if err := db.Set(n2b(110), n2b(1100)); err != nil { + t.Fatal(err) + } + + if en, err = db.SeekFirst(); err != nil { + t.Fatal(err) + } + + if k, v, err = en.Next(); err != nil { + t.Fatal(err) + } + + if g, e := b2n(k), 100; g != e { + t.Fatal(g, e) + } + + if g, e := b2n(v), 1000; g != e { + t.Fatal(g, e) + } + + if err := db.Set(n2b(90), n2b(900)); err != nil { + t.Fatal(err) + } + + if en, err = db.SeekFirst(); err != nil { + t.Fatal(err) + } + + if k, v, err = en.Next(); err != nil { + t.Fatal(err) + } + + if g, e := b2n(k), 90; g != e { + t.Fatal(g, e) + } + + if g, e := b2n(v), 900; g != e { + t.Fatal(g, e) + } + +} + +func TestBTreeSeekLast(t *testing.T) { + db := NewBTree(nil) + en, err := db.SeekLast() + if err == nil { + t.Fatal(err) + } + + if err := db.Set(n2b(100), n2b(1000)); err != nil { + t.Fatal(err) + } + + if en, err = db.SeekLast(); err != nil { + t.Fatal(err) + } + + k, v, err := en.Next() + if err != nil { + t.Fatal(err) + } + + if g, e := b2n(k), 100; g != e { + t.Fatal(g, e) + } + + if g, e := b2n(v), 1000; g != e { + t.Fatal(g, e) + } + + if err := db.Set(n2b(90), n2b(900)); err != nil { + t.Fatal(err) + } + + if en, err = db.SeekLast(); err != nil { + t.Fatal(err) + } + + if k, v, err = en.Next(); err != nil { + t.Fatal(err) + } + + if g, e := b2n(k), 100; g != e { + t.Fatal(g, e) + } + + if g, e := b2n(v), 1000; g != e { + t.Fatal(g, e) + } + + if err := db.Set(n2b(110), n2b(1100)); err != nil { + t.Fatal(err) + } + + if en, err = db.SeekLast(); err != nil { + t.Fatal(err) + } + + if k, v, err = en.Next(); err != nil { + t.Fatal(err) + } + + if g, e := b2n(k), 110; g != e { + t.Fatal(g, e) + } + + if g, e := b2n(v), 1100; g != e { + t.Fatal(g, e) + } + +} + +// https://code.google.com/p/camlistore/issues/detail?id=216 +func TestBug216(t *testing.T) { + const S = 2*kKV + 2 // 2*kKV+1 ok + const N = 300000 + rng, err := mathutil.NewFC32(math.MinInt32, math.MaxInt32, true) + if err != nil { + t.Fatal(err) + } + k := make([]byte, S/2) + v := make([]byte, S-S/2) + tr := NewBTree(nil) + for i := 0; i < N; i++ { + for i := range k { + k[i] = byte(rng.Next()) + } + for i := range v { + v[i] = byte(rng.Next()) + } + + if err := tr.Set(h2b(k, int64(i)), h2b(v, int64(i))); err != nil { + t.Fatal(i, err) + } + + if (i+1)%10000 == 0 { + //dbg("%v", i+1) + } + } +} diff --git a/Godeps/_workspace/src/github.com/cznic/exp/lldb/errors.go b/Godeps/_workspace/src/github.com/cznic/exp/lldb/errors.go new file mode 100644 index 0000000..7dffe7f --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/exp/lldb/errors.go @@ -0,0 +1,170 @@ +// Copyright 2014 The lldb Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Some errors returned by this package. +// +// Note that this package can return more errors than declared here, for +// example io.EOF from Filer.ReadAt(). + +package lldb + +import ( + "fmt" +) + +// ErrDecodeScalars is possibly returned from DecodeScalars +type ErrDecodeScalars struct { + B []byte // Data being decoded + I int // offending offset +} + +// Error implements the built in error type. +func (e *ErrDecodeScalars) Error() string { + return fmt.Sprintf("DecodeScalars: corrupted data @ %d/%d", e.I, len(e.B)) +} + +// ErrINVAL reports invalid values passed as parameters, for example negative +// offsets where only non-negative ones are allowed or read from the DB. +type ErrINVAL struct { + Src string + Val interface{} +} + +// Error implements the built in error type. +func (e *ErrINVAL) Error() string { + return fmt.Sprintf("%s: %+v", e.Src, e.Val) +} + +// ErrPERM is for example reported when a Filer is closed while BeginUpdate(s) +// are not balanced with EndUpdate(s)/Rollback(s) or when EndUpdate or Rollback +// is invoked which is not paired with a BeginUpdate. +type ErrPERM struct { + Src string +} + +// Error implements the built in error type. +func (e *ErrPERM) Error() string { + return fmt.Sprintf("%s: Operation not permitted", string(e.Src)) +} + +// ErrTag represents an ErrILSEQ kind. +type ErrType int + +// ErrILSEQ types +const ( + ErrOther ErrType = iota + + ErrAdjacentFree // Adjacent free blocks (.Off and .Arg) + ErrDecompress // Used compressed block: corrupted compression + ErrExpFreeTag // Expected a free block tag, got .Arg + ErrExpUsedTag // Expected a used block tag, got .Arg + ErrFLT // Free block is invalid or referenced multiple times + ErrFLTLoad // FLT truncated to .Off, need size >= .Arg + ErrFLTSize // Free block size (.Arg) doesn't belong to its list min size: .Arg2 + ErrFileSize // File .Name size (.Arg) != 0 (mod 16) + ErrFreeChaining // Free block, .prev.next doesn't point back to this block + ErrFreeTailBlock // Last block is free + ErrHead // Head of a free block list has non zero Prev (.Arg) + ErrInvalidRelocTarget // Reloc doesn't target (.Arg) a short or long used block + ErrInvalidWAL // Corrupted write ahead log. .Name: file name, .More: more + ErrLongFreeBlkTooLong // Long free block spans beyond EOF, size .Arg + ErrLongFreeBlkTooShort // Long free block must have at least 2 atoms, got only .Arg + ErrLongFreeNextBeyondEOF // Long free block .Next (.Arg) spans beyond EOF + ErrLongFreePrevBeyondEOF // Long free block .Prev (.Arg) spans beyond EOF + ErrLongFreeTailTag // Expected a long free block tail tag, got .Arg + ErrLostFreeBlock // Free block is not in any FLT list + ErrNullReloc // Used reloc block with nil target + ErrRelocBeyondEOF // Used reloc points (.Arg) beyond EOF + ErrShortFreeTailTag // Expected a short free block tail tag, got .Arg + ErrSmall // Request for a free block (.Arg) returned a too small one (.Arg2) at .Off + ErrTailTag // Block at .Off has invalid tail CC (compression code) tag, got .Arg + ErrUnexpReloc // Unexpected reloc block referred to from reloc block .Arg + ErrVerifyPadding // Used block has nonzero padding + ErrVerifyTailSize // Long free block size .Arg but tail size .Arg2 + ErrVerifyUsedSpan // Used block size (.Arg) spans beyond EOF +) + +// ErrILSEQ reports a corrupted file format. Details in fields according to Type. +type ErrILSEQ struct { + Type ErrType + Off int64 + Arg int64 + Arg2 int64 + Arg3 int64 + Name string + More interface{} +} + +// Error implements the built in error type. +func (e *ErrILSEQ) Error() string { + switch e.Type { + case ErrAdjacentFree: + return fmt.Sprintf("Adjacent free blocks at offset %#x and %#x", e.Off, e.Arg) + case ErrDecompress: + return fmt.Sprintf("Compressed block at offset %#x: Corrupted compressed content", e.Off) + case ErrExpFreeTag: + return fmt.Sprintf("Block at offset %#x: Expected a free block tag, got %#2x", e.Off, e.Arg) + case ErrExpUsedTag: + return fmt.Sprintf("Block at ofset %#x: Expected a used block tag, got %#2x", e.Off, e.Arg) + case ErrFLT: + return fmt.Sprintf("Free block at offset %#x is invalid or referenced multiple times", e.Off) + case ErrFLTLoad: + return fmt.Sprintf("FLT truncated to size %d, expected at least %d", e.Off, e.Arg) + case ErrFLTSize: + return fmt.Sprintf("Free block at offset %#x has size (%#x) should be at least (%#x)", e.Off, e.Arg, e.Arg2) + case ErrFileSize: + return fmt.Sprintf("File %q size (%#x) != 0 (mod 16)", e.Name, e.Arg) + case ErrFreeChaining: + return fmt.Sprintf("Free block at offset %#x: .prev.next doesn point back here.", e.Off) + case ErrFreeTailBlock: + return fmt.Sprintf("Free block at offset %#x: Cannot be last file block", e.Off) + case ErrHead: + return fmt.Sprintf("Block at offset %#x: Head of free block list has non zero .prev %#x", e.Off, e.Arg) + case ErrInvalidRelocTarget: + return fmt.Sprintf("Used reloc block at offset %#x: Target (%#x) is not a short or long used block", e.Off, e.Arg) + case ErrInvalidWAL: + return fmt.Sprintf("Corrupted write ahead log file: %q %v", e.Name, e.More) + case ErrLongFreeBlkTooLong: + return fmt.Sprintf("Long free block at offset %#x: Size (%#x) beyond EOF", e.Off, e.Arg) + case ErrLongFreeBlkTooShort: + return fmt.Sprintf("Long free block at offset %#x: Size (%#x) too small", e.Off, e.Arg) + case ErrLongFreeNextBeyondEOF: + return fmt.Sprintf("Long free block at offset %#x: Next (%#x) points beyond EOF", e.Off, e.Arg) + case ErrLongFreePrevBeyondEOF: + return fmt.Sprintf("Long free block at offset %#x: Prev (%#x) points beyond EOF", e.Off, e.Arg) + case ErrLongFreeTailTag: + return fmt.Sprintf("Block at offset %#x: Expected long free tail tag, got %#2x", e.Off, e.Arg) + case ErrLostFreeBlock: + return fmt.Sprintf("Free block at offset %#x: not in any FLT list", e.Off) + case ErrNullReloc: + return fmt.Sprintf("Used reloc block at offset %#x: Nil target", e.Off) + case ErrRelocBeyondEOF: + return fmt.Sprintf("Used reloc block at offset %#x: Link (%#x) points beyond EOF", e.Off, e.Arg) + case ErrShortFreeTailTag: + return fmt.Sprintf("Block at offset %#x: Expected short free tail tag, got %#2x", e.Off, e.Arg) + case ErrSmall: + return fmt.Sprintf("Request for of free block of size %d returned a too small (%d) one at offset %#x", e.Arg, e.Arg2, e.Off) + case ErrTailTag: + return fmt.Sprintf("Block at offset %#x: Invalid tail CC tag, got %#2x", e.Off, e.Arg) + case ErrUnexpReloc: + return fmt.Sprintf("Block at offset %#x: Unexpected reloc block. Referred to from reloc block at offset %#x", e.Off, e.Arg) + case ErrVerifyPadding: + return fmt.Sprintf("Used block at offset %#x: Nonzero padding", e.Off) + case ErrVerifyTailSize: + return fmt.Sprintf("Long free block at offset %#x: Size %#x, but tail size %#x", e.Off, e.Arg, e.Arg2) + case ErrVerifyUsedSpan: + return fmt.Sprintf("Used block at offset %#x: Size %#x spans beyond EOF", e.Off, e.Arg) + } + + more := "" + if e.More != nil { + more = fmt.Sprintf(", %v", e.More) + } + off := "" + if e.Off != 0 { + off = fmt.Sprintf(", off: %#x", e.Off) + } + + return fmt.Sprintf("Error%s%s", off, more) +} diff --git a/Godeps/_workspace/src/github.com/cznic/exp/lldb/falloc.go b/Godeps/_workspace/src/github.com/cznic/exp/lldb/falloc.go new file mode 100644 index 0000000..33c378b --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/exp/lldb/falloc.go @@ -0,0 +1,1970 @@ +// Copyright 2014 The lldb Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// The storage space management. + +package lldb + +import ( + "bytes" + "errors" + "fmt" + "io" + "sort" + "strings" + + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/bufs" + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/mathutil" + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/zappy" +) + +const ( + maxBuf = maxRq + 20 // bufs,Buffers.Alloc +) + +// Options are passed to the NewAllocator to amend some configuration. The +// compatibility promise is the same as of struct types in the Go standard +// library - introducing changes can be made only by adding new exported +// fields, which is backward compatible as long as client code uses field names +// to assign values of imported struct types literals. +// +// NOTE: No options are currently defined. +type Options struct{} + +// AllocStats record statistics about a Filer. It can be optionally filled by +// Allocator.Verify, if successful. +type AllocStats struct { + Handles int64 // total valid handles in use + Compression int64 // number of compressed blocks + TotalAtoms int64 // total number of atoms == AllocAtoms + FreeAtoms + AllocBytes int64 // bytes allocated (after decompression, if/where used) + AllocAtoms int64 // atoms allocated/used, including relocation atoms + Relocations int64 // number of relocated used blocks + FreeAtoms int64 // atoms unused + AllocMap map[int64]int64 // allocated block size in atoms -> count of such blocks + FreeMap map[int64]int64 // free block size in atoms -> count of such blocks +} + +/* + +Allocator implements "raw" storage space management (allocation and +deallocation) for a low level of a DB engine. The storage is an abstraction +provided by a Filer. + +The terms MUST or MUST NOT, if/where used in the documentation of Allocator, +written in all caps as seen here, are a requirement for any possible +alternative implementations aiming for compatibility with this one. + +Filer file + +A Filer file, or simply 'file', is a linear, contiguous sequence of blocks. +Blocks may be either free (currently unused) or allocated (currently used). +Some blocks may eventually become virtual in a sense as they may not be +realized in the storage (sparse files). + +Free Lists Table + +File starts with a FLT. This table records heads of 14 doubly linked free +lists. The zero based index (I) vs minimal size of free blocks in that list, +except the last one which registers free blocks of size 4112+ atoms: + + MinSize == 2^I + + For example 0 -> 1, 1 -> 2, ... 12 -> 4096. + +Each entry in the FLT is 8 bytes in netwtork order, MSB MUST be zero, ie. the +slot value is effectively only 7 bytes. The value is the handle of the head of +the respective doubly linked free list. The FLT size is 14*8 == 112(0x70) +bytes. If the free blocks list for any particular size is empty, the respective +FLT slot is zero. Sizes of free blocks in one list MUST NOT overlap with sizes +of free lists in other list. For example, even though a free block of size 2 +technically is of minimal size >= 1, it MUST NOT be put to the list for slot 0 +(minimal size 1), but in slot 1( minimal size 2). + + slot 0: sizes [1, 2) + slot 1: sizes [2, 4) + slot 2: sizes [4, 8) + ... + slot 11: sizes [2048, 4096) + slot 12: sizes [4096, 4112) + slot 13: sizes [4112, inf) + +The last FLT slot collects all free blocks bigger than its minimal size. That +still respects the 'no overlap' invariant. + +File blocks + +A block is a linear, contiguous sequence of atoms. The first and last atoms of +a block provide information about, for example, whether the block is free or +used, what is the size of the block, etc. Details are discussed elsewhere. The +first block of a file starts immediately after FLT, ie. at file offset +112(0x70). + +Block atoms + +An atom is a fixed size piece of a block (and thus of a file too); it is 16 +bytes long. A consequence is that for a valid file: + + filesize == 0 (mod 16) + +The first atom of the first block is considered to be atom #1. + +Block handles + +A handle is an integer referring to a block. The reference is the number of the +atom the block starts with. Put in other way: + + handle == offset/16 - 6 + offset == 16 * (handle + 6) + +`offset` is the offset of the first byte of the block, measured in bytes +- as in fseek(3). Handle has type `int64`, but only the lower 7 bytes may be +nonzero while referring to a block, both in code as well as when persisted in +the the file's internal bookkeeping structures - see 'Block types' bellow. So a +handle is effectively only `uint56`. This also means that the maximum usable +size of a file is 2^56 atoms. That is 2^60 bytes == 1 exabyte (10^18 bytes). + +Nil handles + +A handle with numeric value of '0' refers to no block. + +Zero padding + +A padding is used to round-up a block size to be a whole number of atoms. Any +padding, if present, MUST be all zero bytes. Note that the size of padding is +in [0, 15]. + +Content wiping + +When a block is deallocated, its data content is not wiped as the added +overhead may be substantial while not necessarily needed. Client code should +however overwrite the content of any block having sensitive data with eg. zeros +(good compression) - before deallocating the block. + +Block tags + +Every block is tagged in its first byte (a head tag) and last byte (tail tag). +Block types are: + + 1. Short content used block (head tags 0x00-0xFB) + 2. Long content used block (head tag 0xFC) + 3. Relocated used block (head tag 0xFD) + 4. Short, single atom, free block (head tag 0xFE) + 5. Long free block (head tag 0xFF) + +Note: Relocated used block, 3. above (head tag 0xFD) MUST NOT refer to blocks +other then 1. or 2. above (head tags 0x00-0xFC). + +Content blocks + +Used blocks (head tags 0x00-0xFC) tail tag distinguish used/unused block and if +content is compressed or not. + +Content compression + +The tail flag of an used block is one of + + CC == 0 // Content is not compressed. + CC == 1 // Content is in zappy compression format. + +If compression of written content is enabled, there are two cases: If +compressed size < original size then the compressed content should be written +if it will save at least one atom of the block. If compressed size >= original +size then the compressed content should not be used. + +It's recommended to use compression. For example the BTrees implementation +assumes compression is used. Using compression may cause a slowdown in some +cases while it may as well cause a speedup. + +Short content block + +Short content block carries content of length between N == 0(0x00) and N == +251(0xFB) bytes. + + |<-first atom start ... last atom end->| + +---++-- ... --+-- ... --++------+ + | 0 || 1... | 0x*...0x*E || 0x*F | + +---++-- ... --+-- ... --++------+ + | N || content | padding || CC | + +---++-- ... --+-- ... --++------+ + + A == (N+1)/16 + 1 // The number of atoms in the block [1, 16] + padding == 15 - (N+1)%16 // Length of the zero padding + +Long content block + +Long content block carries content of length between N == 252(0xFC) and N == +65787(0x100FB) bytes. + + |<-first atom start ... last atom end->| + +------++------+-- ... --+-- ... --++------+ + | 0 || 1..2 | 3... | 0x*...0x*E || 0x*F | + +------++------+-- ... --+-- ... --++------+ + | 0xFC || M | content | padding || CC | + +------++------+-- ... --+-- ... --++------+ + + A == (N+3)/16 + 1 // The number of atoms in the block [16, 4112] + M == N % 0x10000 // Stored as 2 bytes in network byte order + padding == 15 - (N+3)%16 // Length of the zero padding + +Relocated used block + +Relocated block allows to permanently assign a handle to some content and +resize the content anytime afterwards without having to update all the possible +existing references; the handle can be constant while the content size may be +dynamic. When relocating a block, any space left by the original block content, +above this single atom block, MUST be reclaimed. + +Relocations MUST point only to a used short or long block == blocks with tags +0x00...0xFC. + + +------++------+---------++----+ + | 0 || 1..7 | 8...14 || 15 | + +------++------+---------++----+ + | 0xFD || H | padding || 0 | + +------++------+---------++----+ + +H is the handle of the relocated block in network byte order. + +Free blocks + +Free blocks are the result of space deallocation. Free blocks are organized in +one or more doubly linked lists, abstracted by the FLT interface. Free blocks +MUST be "registered" by putting them in such list. Allocator MUST reuse a big +enough free block, if such exists, before growing the file size. When a free +block is created by deallocation or reallocation it MUST be joined with any +adjacently existing free blocks before "registering". If the resulting free +block is now a last block of a file, the free block MUST be discarded and the +file size MUST be truncated accordingly instead. Put differently, there MUST +NOT ever be a free block at the file end. + +A single free atom + +Is an unused block of size 1 atom. + + +------++------+--------++------+ + | 0 || 1..7 | 8...14 || 15 | + +------++------+--------++------+ + | 0xFE || P | N || 0xFE | + +------++------+--------++------+ + +P and N, stored in network byte order, are the previous and next free block +handles in the doubly linked list to which this free block belongs. + +A long unused block + +Is an unused block of size > 1 atom. + + +------++------+-------+---------+- ... -+----------++------+ + | 0 || 1..7 | 8..14 | 15...21 | | Z-7..Z-1 || Z | + +------++------+-------+---------+- ... -+----------++------+ + | 0xFF || S | P | N | Leak | S || 0xFF | + +------++------+-------+---------+- ... -+----------++------+ + + Z == 16 * S - 1 + +S is the size of this unused block in atoms. P and N are the previous and next +free block handles in the doubly linked list to which this free block belongs. +Leak contains any data the block had before deallocating this block. See also +the subtitle 'Content wiping' above. S, P and N are stored in network byte +order. Large free blocks may trigger a consideration of file hole punching of +the Leak field - for some value of 'large'. + +Note: Allocator methods vs CRUD[1]: + + Alloc [C]reate + Get [R]ead + Realloc [U]pdate + Free [D]elete + +Note: No Allocator method returns io.EOF. + + [1]: http://en.wikipedia.org/wiki/Create,_read,_update_and_delete + +*/ +type Allocator struct { + f Filer + flt flt + Compress bool // enables content compression + cache cache + m map[int64]*node + lru lst + expHit int64 + expMiss int64 + cacheSz int + hit uint16 + miss uint16 +} + +// NewAllocator returns a new Allocator. To open an existing file, pass its +// Filer. To create a "new" file, pass a Filer which file is of zero size. +func NewAllocator(f Filer, opts *Options) (a *Allocator, err error) { + if opts == nil { // Enforce *Options is always passed + return nil, errors.New("NewAllocator: nil opts passed") + } + + a = &Allocator{ + f: f, + cacheSz: 10, + } + + a.cinit() + switch x := f.(type) { + case *RollbackFiler: + x.afterRollback = func() error { + a.cinit() + return a.flt.load(a.f, 0) + } + case *ACIDFiler0: + x.RollbackFiler.afterRollback = func() error { + a.cinit() + return a.flt.load(a.f, 0) + } + } + + sz, err := f.Size() + if err != nil { + return + } + + a.flt.init() + if sz == 0 { + var b [fltSz]byte + if err = a.f.BeginUpdate(); err != nil { + return + } + + if _, err = f.WriteAt(b[:], 0); err != nil { + a.f.Rollback() + return + } + + return a, a.f.EndUpdate() + } + + return a, a.flt.load(f, 0) +} + +// CacheStats reports cache statistics. +// +//TODO return a struct perhaps. +func (a *Allocator) CacheStats() (buffersUsed, buffersTotal int, bytesUsed, bytesTotal, hits, misses int64) { + buffersUsed = len(a.m) + buffersTotal = buffersUsed + len(a.cache) + bytesUsed = a.lru.size() + bytesTotal = bytesUsed + a.cache.size() + hits = a.expHit + misses = a.expMiss + return +} + +func (a *Allocator) cinit() { + for h, n := range a.m { + a.cache.put(a.lru.remove(n)) + delete(a.m, h) + } + if a.m == nil { + a.m = map[int64]*node{} + } +} + +func (a *Allocator) cadd(b []byte, h int64) { + if len(a.m) < a.cacheSz { + n := a.cache.get(len(b)) + n.h = h + copy(n.b, b) + a.m[h] = a.lru.pushFront(n) + return + } + + // cache full + delete(a.m, a.cache.put(a.lru.removeBack()).h) + n := a.cache.get(len(b)) + n.h = h + copy(n.b, b) + a.m[h] = a.lru.pushFront(n) + return +} + +func (a *Allocator) cfree(h int64) { + n, ok := a.m[h] + if !ok { // must have been evicted + return + } + + a.cache.put(a.lru.remove(n)) + delete(a.m, h) +} + +// Alloc allocates storage space for b and returns the handle of the new block +// with content set to b or an error, if any. The returned handle is valid only +// while the block is used - until the block is deallocated. No two valid +// handles share the same value within the same Filer, but any value of a +// handle not referring to any used block may become valid any time as a result +// of Alloc. +// +// Invoking Alloc on an empty Allocator is guaranteed to return handle with +// value 1. The intended use of content of handle 1 is a root "directory" of +// other data held by an Allocator. +// +// Passing handles not obtained initially from Alloc or not anymore valid to +// any other Allocator methods can result in an irreparably corrupted database. +func (a *Allocator) Alloc(b []byte) (handle int64, err error) { + buf := bufs.GCache.Get(zappy.MaxEncodedLen(len(b))) + defer bufs.GCache.Put(buf) + buf, _, cc, err := a.makeUsedBlock(buf, b) + if err != nil { + return + } + + if handle, err = a.alloc(buf, cc); err == nil { + a.cadd(b, handle) + } + return +} + +func (a *Allocator) alloc(b []byte, cc byte) (h int64, err error) { + rqAtoms := n2atoms(len(b)) + if h = a.flt.find(rqAtoms); h == 0 { // must grow + var sz int64 + if sz, err = a.f.Size(); err != nil { + return + } + + h = off2h(sz) + err = a.writeUsedBlock(h, cc, b) + return + } + + // Handle is the first item of a free blocks list. + tag, s, prev, next, err := a.nfo(h) + if err != nil { + return + } + + if tag != tagFreeShort && tag != tagFreeLong { + err = &ErrILSEQ{Type: ErrExpFreeTag, Off: h2off(h), Arg: int64(tag)} + return + } + + if prev != 0 { + err = &ErrILSEQ{Type: ErrHead, Off: h2off(h), Arg: prev} + return + } + + if s < int64(rqAtoms) { + err = &ErrILSEQ{Type: ErrSmall, Arg: int64(rqAtoms), Arg2: s, Off: h2off(h)} + return + } + + if err = a.unlink(h, s, prev, next); err != nil { + return + } + + if s > int64(rqAtoms) { + freeH := h + int64(rqAtoms) + freeAtoms := s - int64(rqAtoms) + if err = a.link(freeH, freeAtoms); err != nil { + return + } + } + return h, a.writeUsedBlock(h, cc, b) +} + +// Free deallocates the block referred to by handle or returns an error, if +// any. +// +// After Free succeeds, handle is invalid and must not be used. +// +// Handle must have been obtained initially from Alloc and must be still valid, +// otherwise a database may get irreparably corrupted. +func (a *Allocator) Free(handle int64) (err error) { + if handle <= 0 || handle > maxHandle { + return &ErrINVAL{"Allocator.Free: handle out of limits", handle} + } + + a.cfree(handle) + return a.free(handle, 0, true) +} + +func (a *Allocator) free(h, from int64, acceptRelocs bool) (err error) { + tag, atoms, _, n, err := a.nfo(h) + if err != nil { + return + } + + switch tag { + default: + // nop + case tagUsedLong: + // nop + case tagUsedRelocated: + if !acceptRelocs { + return &ErrILSEQ{Type: ErrUnexpReloc, Off: h2off(h), Arg: h2off(from)} + } + + if err = a.free(n, h, false); err != nil { + return + } + case tagFreeShort, tagFreeLong: + return &ErrINVAL{"Allocator.Free: attempt to free a free block at off", h2off(h)} + } + + return a.free2(h, atoms) +} + +func (a *Allocator) free2(h, atoms int64) (err error) { + sz, err := a.f.Size() + if err != nil { + return + } + + ltag, latoms, lp, ln, err := a.leftNfo(h) + if err != nil { + return + } + + if ltag != tagFreeShort && ltag != tagFreeLong { + latoms = 0 + } + + var rtag byte + var ratoms, rp, rn int64 + + isTail := h2off(h)+atoms*16 == sz + if !isTail { + if rtag, ratoms, rp, rn, err = a.nfo(h + atoms); err != nil { + return + } + } + + if rtag != tagFreeShort && rtag != tagFreeLong { + ratoms = 0 + } + + switch { + case latoms == 0 && ratoms == 0: + // -> isolated <- + if isTail { // cut tail + return a.f.Truncate(h2off(h)) + } + + return a.link(h, atoms) + case latoms == 0 && ratoms != 0: + // right join -> + if err = a.unlink(h+atoms, ratoms, rp, rn); err != nil { + return + } + + return a.link(h, atoms+ratoms) + case latoms != 0 && ratoms == 0: + // <- left join + if err = a.unlink(h-latoms, latoms, lp, ln); err != nil { + return + } + + if isTail { + return a.f.Truncate(h2off(h - latoms)) + } + + return a.link(h-latoms, latoms+atoms) + } + + // case latoms != 0 && ratoms != 0: + // <- middle join -> + lh, rh := h-latoms, h+atoms + if err = a.unlink(lh, latoms, lp, ln); err != nil { + return + } + + // Prev unlink may have invalidated rp or rn + if _, _, rp, rn, err = a.nfo(rh); err != nil { + return + } + + if err = a.unlink(rh, ratoms, rp, rn); err != nil { + return + } + + return a.link(h-latoms, latoms+atoms+ratoms) +} + +// Add a free block h to the appropriate free list +func (a *Allocator) link(h, atoms int64) (err error) { + if err = a.makeFree(h, atoms, 0, a.flt.head(atoms)); err != nil { + return + } + + return a.flt.setHead(h, atoms, a.f) +} + +// Remove free block h from the free list +func (a *Allocator) unlink(h, atoms, p, n int64) (err error) { + switch { + case p == 0 && n == 0: + // single item list, must be head + return a.flt.setHead(0, atoms, a.f) + case p == 0 && n != 0: + // head of list (has next item[s]) + if err = a.prev(n, 0); err != nil { + return + } + + // new head + return a.flt.setHead(n, atoms, a.f) + case p != 0 && n == 0: + // last item in list + return a.next(p, 0) + } + // case p != 0 && n != 0: + // intermediate item in a list + if err = a.next(p, n); err != nil { + return + } + + return a.prev(n, p) +} + +//TODO remove ? +// Return len(slice) == n, reuse src if possible. +func need(n int, src []byte) []byte { + if cap(src) < n { + bufs.GCache.Put(src) + return bufs.GCache.Get(n) + } + + return src[:n] +} + +// Get returns the data content of a block referred to by handle or an error if +// any. The returned slice may be a sub-slice of buf if buf was large enough +// to hold the entire content. Otherwise, a newly allocated slice will be +// returned. It is valid to pass a nil buf. +// +// If the content was stored using compression then it is transparently +// returned decompressed. +// +// Handle must have been obtained initially from Alloc and must be still valid, +// otherwise invalid data may be returned without detecting the error. +func (a *Allocator) Get(buf []byte, handle int64) (b []byte, err error) { + buf = buf[:cap(buf)] + if n, ok := a.m[handle]; ok { + a.lru.moveToFront(n) + b = need(len(n.b), buf) + copy(b, n.b) + a.expHit++ + a.hit++ + return + } + + a.expMiss++ + a.miss++ + if a.miss > 10 && len(a.m) < 500 { + if 100*a.hit/a.miss < 95 { + a.cacheSz++ + } + a.hit, a.miss = 0, 0 + } + defer func(h int64) { + if err == nil { + a.cadd(b, h) + } + }(handle) + + first := bufs.GCache.Get(16) + defer bufs.GCache.Put(first) + relocated := false + relocSrc := handle +reloc: + if handle <= 0 || handle > maxHandle { + return nil, &ErrINVAL{"Allocator.Get: handle out of limits", handle} + } + + off := h2off(handle) + if err = a.read(first, off); err != nil { + return + } + + switch tag := first[0]; tag { + default: + dlen := int(tag) + atoms := n2atoms(dlen) + switch atoms { + case 1: + switch tag := first[15]; tag { + default: + return nil, &ErrILSEQ{Type: ErrTailTag, Off: off, Arg: int64(tag)} + case tagNotCompressed: + b = need(dlen, buf) + copy(b, first[1:]) + return + case tagCompressed: + return zappy.Decode(buf, first[1:dlen+1]) + } + default: + cc := bufs.GCache.Get(1) + defer bufs.GCache.Put(cc) + dlen := int(tag) + atoms := n2atoms(dlen) + tailOff := off + 16*int64(atoms) - 1 + if err = a.read(cc, tailOff); err != nil { + return + } + + switch tag := cc[0]; tag { + default: + return nil, &ErrILSEQ{Type: ErrTailTag, Off: off, Arg: int64(tag)} + case tagNotCompressed: + b = need(dlen, buf) + off += 1 + if err = a.read(b, off); err != nil { + b = buf[:0] + } + return + case tagCompressed: + zbuf := bufs.GCache.Get(dlen) + defer bufs.GCache.Put(zbuf) + off += 1 + if err = a.read(zbuf, off); err != nil { + return buf[:0], err + } + + return zappy.Decode(buf, zbuf) + } + } + case 0: + return buf[:0], nil + case tagUsedLong: + cc := bufs.GCache.Get(1) + defer bufs.GCache.Put(cc) + dlen := m2n(int(first[1])<<8 | int(first[2])) + atoms := n2atoms(dlen) + tailOff := off + 16*int64(atoms) - 1 + if err = a.read(cc, tailOff); err != nil { + return + } + + switch tag := cc[0]; tag { + default: + return nil, &ErrILSEQ{Type: ErrTailTag, Off: off, Arg: int64(tag)} + case tagNotCompressed: + b = need(dlen, buf) + off += 3 + if err = a.read(b, off); err != nil { + b = buf[:0] + } + return + case tagCompressed: + zbuf := bufs.GCache.Get(dlen) + defer bufs.GCache.Put(zbuf) + off += 3 + if err = a.read(zbuf, off); err != nil { + return buf[:0], err + } + + return zappy.Decode(buf, zbuf) + } + case tagFreeShort, tagFreeLong: + return nil, &ErrILSEQ{Type: ErrExpUsedTag, Off: off, Arg: int64(tag)} + case tagUsedRelocated: + if relocated { + return nil, &ErrILSEQ{Type: ErrUnexpReloc, Off: off, Arg: relocSrc} + } + + handle = b2h(first[1:]) + relocated = true + goto reloc + } +} + +var reallocTestHook bool + +// Realloc sets the content of a block referred to by handle or returns an +// error, if any. +// +// Handle must have been obtained initially from Alloc and must be still valid, +// otherwise a database may get irreparably corrupted. +func (a *Allocator) Realloc(handle int64, b []byte) (err error) { + if handle <= 0 || handle > maxHandle { + return &ErrINVAL{"Realloc: handle out of limits", handle} + } + + a.cfree(handle) + if err = a.realloc(handle, b); err != nil { + return + } + + if reallocTestHook { + if err = cacheAudit(a.m, &a.lru); err != nil { + return + } + } + + a.cadd(b, handle) + return +} + +func (a *Allocator) realloc(handle int64, b []byte) (err error) { + var dlen, needAtoms0 int + + b8 := bufs.GCache.Get(8) + defer bufs.GCache.Put(b8) + dst := bufs.GCache.Get(zappy.MaxEncodedLen(len(b))) + defer bufs.GCache.Put(dst) + b, needAtoms0, cc, err := a.makeUsedBlock(dst, b) + if err != nil { + return + } + + needAtoms := int64(needAtoms0) + off := h2off(handle) + if err = a.read(b8[:], off); err != nil { + return + } + + switch tag := b8[0]; tag { + default: + dlen = int(b8[0]) + case tagUsedLong: + dlen = m2n(int(b8[1])<<8 | int(b8[2])) + case tagUsedRelocated: + if err = a.free(b2h(b8[1:]), handle, false); err != nil { + return err + } + + dlen = 0 + case tagFreeShort, tagFreeLong: + return &ErrINVAL{"Allocator.Realloc: invalid handle", handle} + } + + atoms := int64(n2atoms(dlen)) +retry: + switch { + case needAtoms < atoms: + // in place shrink + if err = a.writeUsedBlock(handle, cc, b); err != nil { + return + } + + fh, fa := handle+needAtoms, atoms-needAtoms + sz, err := a.f.Size() + if err != nil { + return err + } + + if h2off(fh)+16*fa == sz { + return a.f.Truncate(h2off(fh)) + } + + return a.free2(fh, fa) + case needAtoms == atoms: + // in place replace + return a.writeUsedBlock(handle, cc, b) + } + + // case needAtoms > atoms: + // in place extend or relocate + var sz int64 + if sz, err = a.f.Size(); err != nil { + return + } + + off = h2off(handle) + switch { + case off+atoms*16 == sz: + // relocating tail block - shortcut + return a.writeUsedBlock(handle, cc, b) + default: + if off+atoms*16 < sz { + // handle is not a tail block, check right neighbour + rh := handle + atoms + rtag, ratoms, p, n, e := a.nfo(rh) + if e != nil { + return e + } + + if rtag == tagFreeShort || rtag == tagFreeLong { + // Right neighbour is a free block + if needAtoms <= atoms+ratoms { + // can expand in place + if err = a.unlink(rh, ratoms, p, n); err != nil { + return + } + + atoms += ratoms + goto retry + + } + } + } + } + + if atoms > 1 { + if err = a.realloc(handle, nil); err != nil { + return + } + } + + var newH int64 + if newH, err = a.alloc(b, cc); err != nil { + return err + } + + rb := bufs.GCache.Cget(16) + defer bufs.GCache.Put(rb) + rb[0] = tagUsedRelocated + h2b(rb[1:], newH) + if err = a.writeAt(rb[:], h2off(handle)); err != nil { + return + } + + return a.writeUsedBlock(newH, cc, b) +} + +func (a *Allocator) writeAt(b []byte, off int64) (err error) { + var n int + if n, err = a.f.WriteAt(b, off); err != nil { + return + } + + if n != len(b) { + err = io.ErrShortWrite + } + return +} + +func (a *Allocator) write(off int64, b ...[]byte) (err error) { + rq := 0 + for _, part := range b { + rq += len(part) + } + buf := bufs.GCache.Get(rq) + defer bufs.GCache.Put(buf) + buf = buf[:0] + for _, part := range b { + buf = append(buf, part...) + } + return a.writeAt(buf, off) +} + +func (a *Allocator) read(b []byte, off int64) (err error) { + var rn int + if rn, err = a.f.ReadAt(b, off); rn != len(b) { + return &ErrILSEQ{Type: ErrOther, Off: off, More: err} + } + + return nil +} + +// nfo returns h's tag. If it's a free block then return also (s)ize (in +// atoms), (p)rev and (n)ext. If it's a used block then only (s)ize is returned +// (again in atoms). If it's a used relocate block then (n)ext is set to the +// relocation target handle. +func (a *Allocator) nfo(h int64) (tag byte, s, p, n int64, err error) { + off := h2off(h) + rq := int64(22) + sz, err := a.f.Size() + if err != nil { + return + } + + if off+rq >= sz { + if rq = sz - off; rq < 15 { + err = io.ErrUnexpectedEOF + return + } + } + + buf := bufs.GCache.Get(22) + defer bufs.GCache.Put(buf) + if err = a.read(buf[:rq], off); err != nil { + return + } + + switch tag = buf[0]; tag { + default: + s = int64(n2atoms(int(tag))) + case tagUsedLong: + s = int64(n2atoms(m2n(int(buf[1])<<8 | int(buf[2])))) + case tagFreeLong: + if rq < 22 { + err = io.ErrUnexpectedEOF + return + } + + s, p, n = b2h(buf[1:]), b2h(buf[8:]), b2h(buf[15:]) + case tagUsedRelocated: + s, n = 1, b2h(buf[1:]) + case tagFreeShort: + s, p, n = 1, b2h(buf[1:]), b2h(buf[8:]) + } + return +} + +// leftNfo returns nfo for h's left neighbor if h > 1 and the left neighbor is +// a free block. Otherwise all zero values are returned instead. +func (a *Allocator) leftNfo(h int64) (tag byte, s, p, n int64, err error) { + if !(h > 1) { + return + } + + buf := bufs.GCache.Get(8) + defer bufs.GCache.Put(buf) + off := h2off(h) + if err = a.read(buf[:], off-8); err != nil { + return + } + + switch tag := buf[7]; tag { + case tagFreeShort: + return a.nfo(h - 1) + case tagFreeLong: + return a.nfo(h - b2h(buf[:])) + } + return +} + +// Set h.prev = p +func (a *Allocator) prev(h, p int64) (err error) { + b := bufs.GCache.Get(7) + defer bufs.GCache.Put(b) + off := h2off(h) + if err = a.read(b[:1], off); err != nil { + return + } + + switch tag := b[0]; tag { + default: + return &ErrILSEQ{Type: ErrExpFreeTag, Off: off, Arg: int64(tag)} + case tagFreeShort: + off += 1 + case tagFreeLong: + off += 8 + } + return a.writeAt(h2b(b[:7], p), off) +} + +// Set h.next = n +func (a *Allocator) next(h, n int64) (err error) { + b := bufs.GCache.Get(7) + defer bufs.GCache.Put(b) + off := h2off(h) + if err = a.read(b[:1], off); err != nil { + return + } + + switch tag := b[0]; tag { + default: + return &ErrILSEQ{Type: ErrExpFreeTag, Off: off, Arg: int64(tag)} + case tagFreeShort: + off += 8 + case tagFreeLong: + off += 15 + } + return a.writeAt(h2b(b[:7], n), off) +} + +// Make the filer image @h a free block. +func (a *Allocator) makeFree(h, atoms, prev, next int64) (err error) { + buf := bufs.GCache.Get(22) + defer bufs.GCache.Put(buf) + switch { + case atoms == 1: + buf[0], buf[15] = tagFreeShort, tagFreeShort + h2b(buf[1:], prev) + h2b(buf[8:], next) + if err = a.write(h2off(h), buf[:16]); err != nil { + return + } + default: + + buf[0] = tagFreeLong + h2b(buf[1:], atoms) + h2b(buf[8:], prev) + h2b(buf[15:], next) + if err = a.write(h2off(h), buf[:22]); err != nil { + return + } + + h2b(buf[:], atoms) + buf[7] = tagFreeLong + if err = a.write(h2off(h+atoms)-8, buf[:8]); err != nil { + return + } + } + if prev != 0 { + if err = a.next(prev, h); err != nil { + return + } + } + + if next != 0 { + err = a.prev(next, h) + } + return +} + +func (a *Allocator) makeUsedBlock(dst []byte, b []byte) (w []byte, rqAtoms int, cc byte, err error) { + cc = tagNotCompressed + w = b + + var n int + if n = len(b); n > maxRq { + return nil, 0, 0, &ErrINVAL{"Allocator.makeUsedBlock: content size out of limits", n} + } + + rqAtoms = n2atoms(n) + if a.Compress && n > 14 { // attempt compression + if dst, err = zappy.Encode(dst, b); err != nil { + return + } + + n2 := len(dst) + if rqAtoms2 := n2atoms(n2); rqAtoms2 < rqAtoms { // compression saved at least a single atom + w, n, rqAtoms, cc = dst, n2, rqAtoms2, tagCompressed + } + } + return +} + +func (a *Allocator) writeUsedBlock(h int64, cc byte, b []byte) (err error) { + n := len(b) + rq := n2atoms(n) << 4 + buf := bufs.GCache.Get(rq) + defer bufs.GCache.Put(buf) + switch n <= maxShort { + case true: + buf[0] = byte(n) + copy(buf[1:], b) + case false: + m := n2m(n) + buf[0], buf[1], buf[2] = tagUsedLong, byte(m>>8), byte(m) + copy(buf[3:], b) + } + if p := n2padding(n); p != 0 { + copy(buf[rq-1-p:], zeros[:]) + } + buf[rq-1] = cc + return a.writeAt(buf, h2off(h)) +} + +func (a *Allocator) verifyUnused(h, totalAtoms int64, tag byte, log func(error) bool, fast bool) (atoms, prev, next int64, err error) { + switch tag { + default: + panic("internal error") + case tagFreeShort: + var b [16]byte + off := h2off(h) + if err = a.read(b[:], off); err != nil { + return + } + + if b[15] != tagFreeShort { + err = &ErrILSEQ{Type: ErrShortFreeTailTag, Off: off, Arg: int64(b[15])} + log(err) + return + } + + atoms, prev, next = 1, b2h(b[1:]), b2h(b[8:]) + case tagFreeLong: + var b [22]byte + off := h2off(h) + if err = a.read(b[:], off); err != nil { + return + } + + atoms, prev, next = b2h(b[1:]), b2h(b[8:]), b2h(b[15:]) + if fast { + return + } + + if atoms < 2 { + err = &ErrILSEQ{Type: ErrLongFreeBlkTooShort, Off: off, Arg: int64(atoms)} + break + } + + if h+atoms-1 > totalAtoms { + err = &ErrILSEQ{Type: ErrLongFreeBlkTooLong, Off: off, Arg: atoms} + break + } + + if prev > totalAtoms { + err = &ErrILSEQ{Type: ErrLongFreePrevBeyondEOF, Off: off, Arg: next} + break + } + + if next > totalAtoms { + err = &ErrILSEQ{Type: ErrLongFreeNextBeyondEOF, Off: off, Arg: next} + break + } + + toff := h2off(h+atoms) - 8 + if err = a.read(b[:8], toff); err != nil { + return + } + + if b[7] != tag { + err = &ErrILSEQ{Type: ErrLongFreeTailTag, Off: off, Arg: int64(b[7])} + break + } + + if s2 := b2h(b[:]); s2 != atoms { + err = &ErrILSEQ{Type: ErrVerifyTailSize, Off: off, Arg: atoms, Arg2: s2} + break + } + + } + if err != nil { + log(err) + } + return +} + +func (a *Allocator) verifyUsed(h, totalAtoms int64, tag byte, buf, ubuf []byte, log func(error) bool, fast bool) (compressed bool, dlen int, atoms, link int64, err error) { + var ( + padding int + doff int64 + padZeros [15]byte + tailBuf [16]byte + ) + + switch tag { + default: // Short used + dlen = int(tag) + atoms = int64((dlen+1)/16) + 1 + padding = 15 - (dlen+1)%16 + doff = h2off(h) + 1 + case tagUsedLong: + off := h2off(h) + 1 + var b2 [2]byte + if err = a.read(b2[:], off); err != nil { + return + } + + dlen = m2n(int(b2[0])<<8 | int(b2[1])) + atoms = int64((dlen+3)/16) + 1 + padding = 15 - (dlen+3)%16 + doff = h2off(h) + 3 + case tagUsedRelocated: + dlen = 7 + atoms = 1 + padding = 7 + doff = h2off(h) + 1 + case tagFreeShort, tagFreeLong: + panic("internal error") + } + + if fast { + if tag == tagUsedRelocated { + dlen = 0 + if err = a.read(buf[:7], doff); err != nil { + return + } + + link = b2h(buf) + } + + return false, dlen, atoms, link, nil + } + + if ok := h+atoms-1 <= totalAtoms; !ok { // invalid last block + err = &ErrILSEQ{Type: ErrVerifyUsedSpan, Off: h2off(h), Arg: atoms} + log(err) + return + } + + tailsz := 1 + padding + off := h2off(h) + 16*atoms - int64(tailsz) + if err = a.read(tailBuf[:tailsz], off); err != nil { + return false, 0, 0, 0, err + } + + if ok := bytes.Equal(padZeros[:padding], tailBuf[:padding]); !ok { + err = &ErrILSEQ{Type: ErrVerifyPadding, Off: h2off(h)} + log(err) + return + } + + var cc byte + switch cc = tailBuf[padding]; cc { + default: + err = &ErrILSEQ{Type: ErrTailTag, Off: h2off(h)} + log(err) + return + case tagCompressed: + compressed = true + if tag == tagUsedRelocated { + err = &ErrILSEQ{Type: ErrTailTag, Off: h2off(h)} + log(err) + return + } + + fallthrough + case tagNotCompressed: + if err = a.read(buf[:dlen], doff); err != nil { + return false, 0, 0, 0, err + } + } + + if cc == tagCompressed { + if ubuf, err = zappy.Decode(ubuf, buf[:dlen]); err != nil || len(ubuf) > maxRq { + err = &ErrILSEQ{Type: ErrDecompress, Off: h2off(h)} + log(err) + return + } + + dlen = len(ubuf) + } + + if tag == tagUsedRelocated { + link = b2h(buf) + if link == 0 { + err = &ErrILSEQ{Type: ErrNullReloc, Off: h2off(h)} + log(err) + return + } + + if link > totalAtoms { // invalid last block + err = &ErrILSEQ{Type: ErrRelocBeyondEOF, Off: h2off(h), Arg: link} + log(err) + return + } + } + + return +} + +var nolog = func(error) bool { return false } + +// Verify attempts to find any structural errors in a Filer wrt the +// organization of it as defined by Allocator. 'bitmap' is a scratch pad for +// necessary bookkeeping and will grow to at most to Allocator's +// Filer.Size()/128 (0,78%). Any problems found are reported to 'log' except +// non verify related errors like disk read fails etc. If 'log' returns false +// or the error doesn't allow to (reliably) continue, the verification process +// is stopped and an error is returned from the Verify function. Passing a nil +// log works like providing a log function always returning false. Any +// non-structural errors, like for instance Filer read errors, are NOT reported +// to 'log', but returned as the Verify's return value, because Verify cannot +// proceed in such cases. Verify returns nil only if it fully completed +// verifying Allocator's Filer without detecting any error. +// +// It is recommended to limit the number reported problems by returning false +// from 'log' after reaching some limit. Huge and corrupted DB can produce an +// overwhelming error report dataset. +// +// The verifying process will scan the whole DB at least 3 times (a trade +// between processing space and time consumed). It doesn't read the content of +// free blocks above the head/tail info bytes. If the 3rd phase detects lost +// free space, then a 4th scan (a faster one) is performed to precisely report +// all of them. +// +// If the DB/Filer to be verified is reasonably small, respective if its +// size/128 can comfortably fit within process's free memory, then it is +// recommended to consider using a MemFiler for the bit map. +// +// Statistics are returned via 'stats' if non nil. The statistics are valid +// only if Verify succeeded, ie. it didn't reported anything to log and it +// returned a nil error. +func (a *Allocator) Verify(bitmap Filer, log func(error) bool, stats *AllocStats) (err error) { + if log == nil { + log = nolog + } + + n, err := bitmap.Size() + if err != nil { + return + } + + if n != 0 { + return &ErrINVAL{"Allocator.Verify: bit map initial size non zero (%d)", n} + } + + var bits int64 + bitMask := [8]byte{1, 2, 4, 8, 16, 32, 64, 128} + byteBuf := []byte{0} + + //DONE + // +performance, this implementation is hopefully correct but _very_ + // naive, probably good as a prototype only. Use maybe a MemFiler + // "cache" etc. + // ---- + // Turns out the OS caching is as effective as it can probably get. + bit := func(on bool, h int64) (wasOn bool, err error) { + m := bitMask[h&7] + off := h >> 3 + var v byte + sz, err := bitmap.Size() + if err != nil { + return + } + + if off < sz { + if n, err := bitmap.ReadAt(byteBuf, off); n != 1 { + return false, &ErrILSEQ{Type: ErrOther, Off: off, More: fmt.Errorf("Allocator.Verify - reading bitmap: %s", err)} + } + + v = byteBuf[0] + } + switch wasOn = v&m != 0; on { + case true: + if !wasOn { + v |= m + bits++ + } + case false: + if wasOn { + v ^= m + bits-- + } + } + byteBuf[0] = v + if n, err := bitmap.WriteAt(byteBuf, off); n != 1 || err != nil { + return false, &ErrILSEQ{Type: ErrOther, Off: off, More: fmt.Errorf("Allocator.Verify - writing bitmap: %s", err)} + } + + return + } + + // Phase 1 - sequentially scan a.f to reliably determine block + // boundaries. Set a bit for every block start. + var ( + buf, ubuf [maxRq]byte + prevH, h, atoms int64 + wasOn bool + tag byte + st = AllocStats{ + AllocMap: map[int64]int64{}, + FreeMap: map[int64]int64{}, + } + dlen int + ) + + fsz, err := a.f.Size() + if err != nil { + return + } + + ok := fsz%16 == 0 + totalAtoms := (fsz - fltSz) / atomLen + if !ok { + err = &ErrILSEQ{Type: ErrFileSize, Name: a.f.Name(), Arg: fsz} + log(err) + return + } + + st.TotalAtoms = totalAtoms + prevTag := -1 + lastH := int64(-1) + + for h = 1; h <= totalAtoms; h += atoms { + prevH = h // For checking last block == used + + off := h2off(h) + if err = a.read(buf[:1], off); err != nil { + return + } + + switch tag = buf[0]; tag { + default: // Short used + fallthrough + case tagUsedLong, tagUsedRelocated: + var compressed bool + if compressed, dlen, atoms, _, err = a.verifyUsed(h, totalAtoms, tag, buf[:], ubuf[:], log, false); err != nil { + return + } + + if compressed { + st.Compression++ + } + st.AllocAtoms += atoms + switch { + case tag == tagUsedRelocated: + st.AllocMap[1]++ + st.Relocations++ + default: + st.AllocMap[atoms]++ + st.AllocBytes += int64(dlen) + st.Handles++ + } + case tagFreeShort, tagFreeLong: + if prevTag == tagFreeShort || prevTag == tagFreeLong { + err = &ErrILSEQ{Type: ErrAdjacentFree, Off: h2off(lastH), Arg: off} + log(err) + return + } + + if atoms, _, _, err = a.verifyUnused(h, totalAtoms, tag, log, false); err != nil { + return + } + + st.FreeMap[atoms]++ + st.FreeAtoms += atoms + } + + if wasOn, err = bit(true, h); err != nil { + return + } + + if wasOn { + panic("internal error") + } + + prevTag = int(tag) + lastH = h + } + + if totalAtoms != 0 && (tag == tagFreeShort || tag == tagFreeLong) { + err = &ErrILSEQ{Type: ErrFreeTailBlock, Off: h2off(prevH)} + log(err) + return + } + + // Phase 2 - check used blocks, turn off the map bit for every used + // block. + for h = 1; h <= totalAtoms; h += atoms { + off := h2off(h) + if err = a.read(buf[:1], off); err != nil { + return + } + + var link int64 + switch tag = buf[0]; tag { + default: // Short used + fallthrough + case tagUsedLong, tagUsedRelocated: + if _, _, atoms, link, err = a.verifyUsed(h, totalAtoms, tag, buf[:], ubuf[:], log, true); err != nil { + return + } + case tagFreeShort, tagFreeLong: + if atoms, _, _, err = a.verifyUnused(h, totalAtoms, tag, log, true); err != nil { + return + } + } + + turnoff := true + switch tag { + case tagUsedRelocated: + if err = a.read(buf[:1], h2off(link)); err != nil { + return + } + + switch linkedTag := buf[0]; linkedTag { + case tagFreeShort, tagFreeLong, tagUsedRelocated: + err = &ErrILSEQ{Type: ErrInvalidRelocTarget, Off: off, Arg: link} + log(err) + return + } + + case tagFreeShort, tagFreeLong: + turnoff = false + } + + if !turnoff { + continue + } + + if wasOn, err = bit(false, h); err != nil { + return + } + + if !wasOn { + panic("internal error") + } + + } + + // Phase 3 - using the flt check heads link to proper free blocks. For + // every free block, walk the list, verify the {next, prev} links and + // turn the respective map bit off. After processing all free lists, + // the map bits count should be zero. Otherwise there are "lost" free + // blocks. + + var prev, next, fprev, fnext int64 + rep := a.flt + + for _, list := range rep { + prev, next = 0, list.head + for ; next != 0; prev, next = next, fnext { + if wasOn, err = bit(false, next); err != nil { + return + } + + if !wasOn { + err = &ErrILSEQ{Type: ErrFLT, Off: h2off(next), Arg: h} + log(err) + return + } + + off := h2off(next) + if err = a.read(buf[:1], off); err != nil { + return + } + + switch tag = buf[0]; tag { + default: + panic("internal error") + case tagFreeShort, tagFreeLong: + if atoms, fprev, fnext, err = a.verifyUnused(next, totalAtoms, tag, log, true); err != nil { + return + } + + if min := list.minSize; atoms < min { + err = &ErrILSEQ{Type: ErrFLTSize, Off: h2off(next), Arg: atoms, Arg2: min} + log(err) + return + } + + if fprev != prev { + err = &ErrILSEQ{Type: ErrFreeChaining, Off: h2off(next)} + log(err) + return + } + } + } + + } + + if bits == 0 { // Verify succeeded + if stats != nil { + *stats = st + } + return + } + + // Phase 4 - if after phase 3 there are lost free blocks, report all of + // them to 'log' + for i := range ubuf { // setup zeros for compares + ubuf[i] = 0 + } + + var off, lh int64 + rem, err := bitmap.Size() + if err != nil { + return err + } + + for rem != 0 { + rq := int(mathutil.MinInt64(64*1024, rem)) + var n int + if n, err = bitmap.ReadAt(buf[:rq], off); n != rq { + return &ErrILSEQ{Type: ErrOther, Off: off, More: fmt.Errorf("bitmap ReadAt(size %d, off %#x): %s", rq, off, err)} + } + + if !bytes.Equal(buf[:rq], ubuf[:rq]) { + for d, v := range buf[:rq] { + if v != 0 { + for i, m := range bitMask { + if v&m != 0 { + lh = 8*(off+int64(d)) + int64(i) + err = &ErrILSEQ{Type: ErrLostFreeBlock, Off: h2off(lh)} + log(err) + return + } + } + } + } + } + + off += int64(rq) + rem -= int64(rq) + } + + return +} + +type fltSlot struct { + head int64 + minSize int64 +} + +func (f fltSlot) String() string { + return fmt.Sprintf("head %#x, minSize %#x\n", f.head, f.minSize) +} + +type flt [14]fltSlot + +func (f *flt) init() { + sz := 1 + for i := range *f { + f[i].minSize, f[i].head = int64(sz), 0 + sz <<= 1 + } + f[13].minSize = 4112 +} + +func (f *flt) load(fi Filer, off int64) (err error) { + b := bufs.GCache.Get(fltSz) + defer bufs.GCache.Put(b) + if _, err = fi.ReadAt(b[:], off); err != nil { + return + } + + for i := range *f { + off := 8*i + 1 + f[i].head = b2h(b[off:]) + } + return +} + +func (f *flt) find(rq int) (h int64) { + switch { + case rq < 1: + panic(rq) + case rq >= maxFLTRq: + h, f[13].head = f[13].head, 0 + return + default: + g := f[mathutil.Log2Uint16(uint16(rq)):] + for i := range g { + p := &g[i] + if rq <= int(p.minSize) { + if h = p.head; h != 0 { + p.head = 0 + return + } + } + } + return + } +} + +func (f *flt) head(atoms int64) (h int64) { + switch { + case atoms < 1: + panic(atoms) + case atoms >= maxFLTRq: + return f[13].head + default: + lg := mathutil.Log2Uint16(uint16(atoms)) + g := f[lg:] + for i := range g { + if atoms < g[i+1].minSize { + return g[i].head + } + } + panic("internal error") + } +} + +func (f *flt) setHead(h, atoms int64, fi Filer) (err error) { + switch { + case atoms < 1: + panic(atoms) + case atoms >= maxFLTRq: + b := bufs.GCache.Get(7) + defer bufs.GCache.Put(b) + if _, err = fi.WriteAt(h2b(b[:], h), 8*13+1); err != nil { + return + } + + f[13].head = h + return + default: + lg := mathutil.Log2Uint16(uint16(atoms)) + g := f[lg:] + for i := range f { + if atoms < g[i+1].minSize { + b := bufs.GCache.Get(7) + defer bufs.GCache.Put(b) + if _, err = fi.WriteAt(h2b(b[:], h), 8*int64(i+lg)+1); err != nil { + return + } + + g[i].head = h + return + } + } + panic("internal error") + } +} + +func (f *flt) String() string { + a := []string{} + for i, v := range *f { + a = append(a, fmt.Sprintf("[%2d] %s", i, v)) + } + return strings.Join(a, "") +} + +type node struct { + b []byte + h int64 + prev, next *node +} + +type cache []*node + +func (c *cache) get(n int) *node { + r, _ := c.get2(n) + return r +} + +func (c *cache) get2(n int) (r *node, isZeroed bool) { + s := *c + lens := len(s) + if lens == 0 { + return &node{b: make([]byte, n, mathutil.Min(2*n, maxBuf))}, true + } + + i := sort.Search(lens, func(x int) bool { return len(s[x].b) >= n }) + if i == lens { + i-- + s[i].b, isZeroed = make([]byte, n, mathutil.Min(2*n, maxBuf)), true + } + + r = s[i] + r.b = r.b[:n] + copy(s[i:], s[i+1:]) + s = s[:lens-1] + *c = s + return +} + +func (c *cache) cget(n int) (r *node) { + r, ok := c.get2(n) + if ok { + return + } + + for i := range r.b { + r.b[i] = 0 + } + return +} + +func (c *cache) size() (sz int64) { + for _, n := range *c { + sz += int64(cap(n.b)) + } + return +} + +func (c *cache) put(n *node) *node { + s := *c + n.b = n.b[:cap(n.b)] + lenb := len(n.b) + lens := len(s) + i := sort.Search(lens, func(x int) bool { return len(s[x].b) >= lenb }) + s = append(s, nil) + copy(s[i+1:], s[i:]) + s[i] = n + *c = s + return n +} + +type lst struct { + front, back *node +} + +func (l *lst) pushFront(n *node) *node { + if l.front == nil { + l.front, l.back, n.prev, n.next = n, n, nil, nil + return n + } + + n.prev, n.next, l.front.prev, l.front = nil, l.front, n, n + return n +} + +func (l *lst) remove(n *node) *node { + if n.prev == nil { + l.front = n.next + } else { + n.prev.next = n.next + } + if n.next == nil { + l.back = n.prev + } else { + n.next.prev = n.prev + } + n.prev, n.next = nil, nil + return n +} + +func (l *lst) removeBack() *node { + return l.remove(l.back) +} + +func (l *lst) moveToFront(n *node) *node { + return l.pushFront(l.remove(n)) +} + +func (l *lst) size() (sz int64) { + for n := l.front; n != nil; n = n.next { + sz += int64(cap(n.b)) + } + return +} + +func cacheAudit(m map[int64]*node, l *lst) (err error) { + cnt := 0 + for h, n := range m { + if g, e := n.h, h; g != e { + return fmt.Errorf("cacheAudit: invalid node handle %d != %d", g, e) + } + + if cnt, err = l.audit(n, true); err != nil { + return + } + } + + if g, e := cnt, len(m); g != e { + return fmt.Errorf("cacheAudit: invalid cache size %d != %d", g, e) + } + + return +} + +func (l *lst) audit(n *node, onList bool) (cnt int, err error) { + if !onList && (n.prev != nil || n.next != nil) { + return -1, fmt.Errorf("lst.audit: free node with non nil linkage") + } + + if l.front == nil && l.back != nil || l.back == nil && l.front != nil { + return -1, fmt.Errorf("lst.audit: one of .front/.back is nil while the other is non nil") + } + + if l.front == l.back && l.front != nil { + x := l.front + if x.prev != nil || x.next != nil { + return -1, fmt.Errorf("lst.audit: single node has non nil linkage") + } + + if onList && x != n { + return -1, fmt.Errorf("lst.audit: single node is alien") + } + } + + seen := false + var prev *node + x := l.front + for x != nil { + cnt++ + if x.prev != prev { + return -1, fmt.Errorf("lst.audit: broken .prev linkage") + } + + if x == n { + seen = true + } + + prev = x + x = x.next + } + + if prev != l.back { + return -1, fmt.Errorf("lst.audit: broken .back linkage") + } + + if onList && !seen { + return -1, fmt.Errorf("lst.audit: node missing in list") + } + + if !onList && seen { + return -1, fmt.Errorf("lst.audit: node should not be on the list") + } + + return +} diff --git a/Godeps/_workspace/src/github.com/cznic/exp/lldb/falloc_test.go b/Godeps/_workspace/src/github.com/cznic/exp/lldb/falloc_test.go new file mode 100644 index 0000000..7c0b7e1 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/exp/lldb/falloc_test.go @@ -0,0 +1,1833 @@ +// Copyright 2014 The lldb 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 lldb + +import ( + "bytes" + "encoding/hex" + "flag" + "fmt" + "math/rand" + "os" + "runtime" + "sort" + "strings" + "testing" + "time" + + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/bufs" + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/sortutil" + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/zappy" +) + +var ( + allocRndTestLimit = flag.Uint("lim", 2*maxShort, "Allocator rnd test initial blocks size limit") + allocRndTestHardLimit = flag.Uint("hlim", 0, "Allocator rnd test initial blocks size hard limit") + testN = flag.Int("N", 128, "Allocator rnd test block count") + allocRndDump = flag.Bool("dump", false, "Produce dump files on TestAllocatorRnd crash") + oKeep = flag.Bool("keep", false, "do not delete testing DB/WAL (where applicable)") +) + +func init() { + reallocTestHook = true +} + +func mfBytes(f Filer) []byte { + var b bytes.Buffer + if _, err := f.(*MemFiler).WriteTo(&b); err != nil { + panic(err) + } + + return b.Bytes() +} + +// Paranoid Allocator, automatically verifies whenever possible. +type pAllocator struct { + *Allocator + errors []error + logger func(error) bool + lastKnownGood *MemFiler + lastKnownGoodFLT flt + lastOp string + stats AllocStats +} + +func newPAllocator(f Filer) (*pAllocator, error) { + a, err := NewAllocator(f, &Options{}) + if err != nil { + return nil, err + } + + r := &pAllocator{Allocator: a, lastKnownGood: NewMemFiler()} + r.logger = func(err error) bool { + r.errors = append(r.errors, err) + return len(r.errors) < 100 + } + + return r, nil +} + +func (a *pAllocator) err() error { + var n int + if n = len(a.errors); n == 0 { + return nil + } + + s := make([]string, n) + for i, e := range a.errors { + s[i] = e.Error() + } + return fmt.Errorf("\n%s", strings.Join(s, "\n")) +} + +func (a *pAllocator) preMortem(s string) { + var e error + if e := a.lastKnownGood.Truncate(0); e != nil { + panic(e) + } + b := mfBytes(a.Allocator.f) + if _, e = a.lastKnownGood.WriteAt(b, 0); e != nil { + return + } + a.lastKnownGoodFLT = a.flt + a.lastOp = s +} + +func (a *pAllocator) Alloc(b []byte) (handle int64, err error) { + if *allocRndDump { + a.preMortem("") + defer func() { a.lastOp = fmt.Sprintf("Alloc(%d bytes): h %#x", len(b), handle) }() + } + + if handle, err = a.Allocator.Alloc(b); err != nil { + return + } + + if err = a.Allocator.Verify(NewMemFiler(), a.logger, &a.stats); err != nil { + err = fmt.Errorf("'%s': %v", err, a.err()) + return + } + + err = a.err() + return +} + +func (a *pAllocator) Free(handle int64) (err error) { + if *allocRndDump { + a.preMortem(fmt.Sprintf("Free(h %#x)", handle)) + } + + if err = a.Allocator.Free(handle); err != nil { + return + } + + if err = a.Allocator.Verify(NewMemFiler(), a.logger, &a.stats); err != nil { + err = fmt.Errorf("'%s': %v", err, a.err()) + return + } + + err = a.err() + return +} + +func (a *pAllocator) Realloc(handle int64, b []byte) (err error) { + if *allocRndDump { + a.preMortem(fmt.Sprintf("Realloc(h %#x, %d bytes)", handle, len(b))) + } + + if err = a.Allocator.Realloc(handle, b); err != nil { + return + } + + if err = cacheAudit(a.Allocator.m, &a.Allocator.lru); err != nil { + return + } + + if err = a.Allocator.Verify(NewMemFiler(), a.logger, &a.stats); err != nil { + err = fmt.Errorf("'%s': %v", err, a.err()) + return + } + + err = a.err() + return +} + +func dump(a *pAllocator, t *testing.T) { + m := a.f.(*MemFiler) + sz, err := m.Size() + if err != nil { + t.Fatal(err) + } + + t.Logf("MemFiler.Size() == %d(%#x)", sz, sz) + if !*allocRndDump { + return + } + + fn := "good-dump" + f, err := os.Create(fn) + if err != nil { + t.Fatal(err) + } + + defer f.Close() + sz, err = a.lastKnownGood.WriteTo(f) + if err != nil { + t.Error(err) + return + } + + t.Logf("%d(%#x) writen to %q", sz, sz, fn) + + fn = "bad-dump" + g, err := os.Create(fn) + if err != nil { + t.Fatal(err) + } + + defer g.Close() + sz, err = m.WriteTo(g) + if err != nil { + t.Error(err) + return + } + + t.Logf("%d(%#x) writen to %q", sz, sz, fn) + + t.Log("Last known good FLT") + for _, slot := range a.lastKnownGoodFLT { + if h := slot.head; h != 0 { + t.Logf("min %d head %#x off %#x", slot.minSize, h, h2off(h)) + } + } + + t.Log("Current FLT") + r := a.flt + for _, slot := range r { + if h := slot.head; h != 0 { + t.Logf("min %d head %#x off %#x", slot.minSize, h, h2off(h)) + } + } + t.Logf("Last op: %q", a.lastOp) +} + +func init() { + if *testN <= 0 { + *testN = 1 + } +} + +func TestVerify0(t *testing.T) { + // All must fail + tab := []string{ + + // 0: Reloc, links beyond EOF + "" + + "fd 00 00 00 00 00 00 02 00 00 00 00 00 00 00 00", + // 1: Reloc, links beyond EOF + "" + + "fd 00 00 00 00 00 00 03 00 00 00 00 00 00 00 00" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", + // 2: Reloc, broken target + "" + + "fd 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", + // 3: Free block at file tail + "" + + "fe 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fe", + // 4: Free block at file tail + "" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "fe 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fe", + // 5: Reloc, invalid target 0xfe + "" + + "fd 00 00 00 00 00 00 02 00 00 00 00 00 00 00 00" + + "fe 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fe" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", + // 6: Reloc, invalid target 0xfd + "" + + "fd 00 00 00 00 00 00 02 00 00 00 00 00 00 00 00" + + "fd 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", + // 7: Lost free block @ 0x00 + "" + + "fe 00 00 00 00 00 00 02 00 00 00 00 00 00 00 fe" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", + // 8: Lost free block @ 0x10 + "" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "fe 00 00 00 00 00 00 02 00 00 00 00 00 00 00 fe" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", + // 9: Invalid padding + "" + + "00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00", + // 10: Invalid padding + "" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00", + // 11: Invalid padding + "" + + "01 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00", + // 12: Invalid padding + "" + + "01 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00", + // 13: Invalid padding + "" + + "0d 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00", + // 14: Invalid CC (tail tag) + "" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02", + // 15: Invalid CC (tail tag) + "" + + "fd 00 00 00 00 00 00 02 00 00 00 00 00 00 00 01", + // 16: Cannot decompress + "" + + "0e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01", + // 17: Invalid reloc target + "" + + "fd 00 00 00 00 00 00 03 00 00 00 00 00 00 00 00" + + "ff 00 00 00 00 00 00 02 00 00 00 00 00 00 00 00" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 ff" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", + // 18: Invalid tail tag @1 + "" + + "fe 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", + // 19: Invalid size @1 + "" + + "ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ff" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", + // 20: Invalid size @1 + "" + + "ff 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 ff" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", + // 21: Invalid size @1 + "" + + "ff 00 00 00 00 00 00 04 00 00 00 00 00 00 00 00" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 ff" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", + // 22: Invalid .next @1 + "" + + "ff 00 00 00 00 00 00 02 00 00 00 00 00 00 00 00" + + "00 00 00 00 00 04 00 00 00 00 00 00 00 00 02 ff" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", + // 23: Invalid .prev @1 + "" + + "ff 00 00 00 00 00 00 02 00 00 00 00 00 00 04 00" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 ff" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", + // 24: Invalid tail tag @1 + "" + + "ff 00 00 00 00 00 00 02 00 00 00 00 00 00 00 00" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 fe" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", + // 25: Invalid tail size @1 + "" + + "ff 00 00 00 00 00 00 02 00 00 00 00 00 00 00 00" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ff" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", + // 26: Invalid tail size @1 + "" + + "ff 00 00 00 00 00 00 02 00 00 00 00 00 00 00 00" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 ff" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", + // 27: Invalid tail size @1 + "" + + "ff 00 00 00 00 00 00 02 00 00 00 00 00 00 00 00" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 03 ff" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", + // 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f + } + + for i, test := range tab { + errors := []error{} + + f := NewMemFiler() + b := s2b(test) + b = append(make([]byte, fltSz), b...) + n := len(b) + if n == 0 { + t.Fatal(n) + } + + if m, err := f.ReadFrom(bytes.NewBuffer(b)); m != int64(n) || err != nil { + t.Fatal(m, err) + } + + sz, err := f.Size() + if err != nil { + t.Fatal(err) + } + + if g, e := sz, int64(n); g != e { + t.Fatal(g, e) + } + + a, err := newPAllocator(f) + if err != nil { + t.Fatal(err) + } + + err = a.Verify( + NewMemFiler(), + func(err error) bool { + if err == nil { + t.Fatal("nil error") + } + errors = append(errors, err) + return false + }, + nil, + ) + if err == nil { + t.Fatal(i, "unexpected success") + } + + t.Log(i, err, errors) + } +} + +func TestVerify1(t *testing.T) { + f := NewMemFiler() + bitmap := NewMemFiler() + if n, err := bitmap.WriteAt([]byte{0}, 0); n != 1 || err != nil { + t.Fatal(n, err) + } + + a, err := newPAllocator(f) + if err != nil { + t.Fatal(err) + } + + if err := a.Verify( + bitmap, + func(error) bool { + panic("intrnal error") + }, + nil, + ); err == nil { + t.Fatal("unexpected success") + } +} + +func repDump(a flt) string { + b := []string{} + for _, v := range a { + if h := v.head; h != 0 { + b = append(b, fmt.Sprintf("min:%d, h:%d", v.minSize, h)) + } + } + return strings.Join(b, ";") +} + +func TestVerify2(t *testing.T) { + // All must fail for the fixed (see bellow) FLT.Report() + tab := []string{ + + // 0: FLT broken linkage (missing free blocks @2,4) + "" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", + // 1: FLT broken linkage (missing free block @4) + "" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "fe 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fe" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", + // 2: bad size @4 + "" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "fe 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fe" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "fe 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fe" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", + // // 3: bad size @4 + "" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "fe 00 00 00 00 00 00 00 00 00 00 00 00 00 04 fe" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "ff 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 ff" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", + // // 4: bad .next @6 from @2 + "" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "fe 00 00 00 00 00 00 00 00 00 00 00 00 00 06 fe" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "ff 00 00 00 00 00 00 02 00 00 00 00 00 00 00 00" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 ff" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "fe 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fe" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", + // // 5: bad .prev @7 + "" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "fe 00 00 00 00 00 00 00 00 00 00 00 00 00 07 fe" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "ff 00 00 00 00 00 00 02 00 00 00 00 00 00 00 00" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 ff" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "fe 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fe" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", + // // 6: bad .next @7 + "" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "fe 00 00 00 00 00 00 00 00 00 00 00 00 00 07 fe" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "ff 00 00 00 00 00 00 02 00 00 00 00 00 00 00 00" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 ff" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "fe 00 00 00 00 00 00 02 00 00 00 00 00 00 07 fe" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", + // // 7: bad .next @5 + "" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "fe 00 00 00 00 00 00 00 00 00 00 00 00 00 07 fe" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "ff 00 00 00 00 00 00 02 00 00 00 00 00 00 00 00" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 ff" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "fe 00 00 00 00 00 00 02 00 00 00 00 00 00 01 fe" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", + // // 8: bad chaining + "" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "fe 00 00 00 00 00 00 00 00 00 00 00 00 00 07 fe" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "ff 00 00 00 00 00 00 02 00 00 00 00 00 00 00 00" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 ff" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "fe 00 00 00 00 00 00 02 00 00 00 00 00 00 01 fe" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", + // // 9: lost free block @8 + "" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "fe 00 00 00 00 00 00 00 00 00 00 00 00 00 0f fe" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "ff 00 00 00 00 00 00 02 00 00 00 00 00 00 00 00" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 ff" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "fe 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fe" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "fe 00 00 00 00 00 00 02 00 00 00 00 00 00 00 fe" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", + // 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f + } + + for i, test := range tab { + errors := []error{} + + f := NewMemFiler() + b := s2b(test) + b = append(make([]byte, fltSz), b...) + n := len(b) + if n == 0 { + t.Fatal(n) + } + + if m, err := f.ReadFrom(bytes.NewBuffer(b)); m != int64(n) || err != nil { + t.Fatal(m, err) + } + + sz, err := f.Size() + if err != nil { + t.Fatal(err) + } + + if g, e := sz, int64(n); g != e { + t.Fatal(g, e) + } + + a, err := newPAllocator(f) + if err != nil { + t.Fatal(err) + } + + a.flt.setHead(2, 1, a.f) + a.flt.setHead(4, 2, a.f) + err = a.Verify( + NewMemFiler(), + func(err error) bool { + if err == nil { + t.Fatal("nil error") + } + t.Log(i, "logged: ", err) + errors = append(errors, err) + return true + }, + nil, + ) + if err == nil { + t.Fatal(i, "unexpected success") + } + + t.Log(i, err, errors) + } +} + +// Allocation in an empty DB. +func TestAllocatorAlloc0(t *testing.T) { + tab := []struct { + h int64 + b, f, fc string + }{ + {1, // len 0 + "" + + "", + "" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", + "" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"}, + {1, // len 1 + "" + + "42", + "" + + "01 42 00 00 00 00 00 00 00 00 00 00 00 00 00 00", + "" + + "01 42 00 00 00 00 00 00 00 00 00 00 00 00 00 00"}, + {1, // max single atom, not compressible + "" + + "01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e", + "" + + "0e 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 00", + "" + + "0e 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 00"}, + {1, // max single atom, compressible, but not eligible for it + "" + + "01 02 03 04 05 06 07 08 99 01 02 03 04 05", + "" + + "0e 01 02 03 04 05 06 07 08 99 01 02 03 04 05 00", + "" + + "0e 01 02 03 04 05 06 07 08 99 01 02 03 04 05 00"}, + {1, // > 1 atom, not compressible + "" + + "01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f", + "" + + "0f 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00", + "" + + "0f 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"}, + {1, // > 1 atom, compressible + "" + + "01 02 03 04 05 06 07 08 99 01 02 03 04 05 06 07" + + "08", + "" + + "11 01 02 03 04 05 06 07 08 99 01 02 03 04 05 06" + + "07 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00", + "" + + "0e 11 12 01 02 03 04 05 06 07 08 99 01 0d 09 01"}, + {1, // longest short + "" + + "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" + + "10 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" + + "20 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" + + "30 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" + + "40 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" + + "50 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" + + "60 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" + + "70 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" + + "80 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" + + "90 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" + + "a0 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" + + "b0 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" + + "c0 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" + + "d0 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" + + "e0 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" + + "f0 01 02 03 04 05 06 07 08 09 0a", + "" + + "" + + "fb 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e" + + "0f 10 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e" + + "0f 20 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e" + + "0f 30 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e" + + "0f 40 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e" + + "0f 50 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e" + + "0f 60 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e" + + "0f 70 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e" + + "0f 80 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e" + + "0f 90 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e" + + "0f a0 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e" + + "0f b0 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e" + + "0f c0 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e" + + "0f d0 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e" + + "0f e0 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e" + + "0f f0 01 02 03 04 05 06 07 08 09 0a 00 00 00 00", + "" + + "" + + "4e fb 01 20 00 01 02 03 04 05 06 07 08 09 0a 0b" + + "0c 0d 0e 0f 10 1d 10 00 20 1d 10 00 30 1d 10 00" + + "40 1d 10 00 50 1d 10 00 60 1d 10 00 70 1d 10 00" + + "80 1d 10 00 90 1d 10 00 a0 1d 10 00 b0 1d 10 00" + + "c0 1d 10 00 d0 1d 10 00 e0 1d 10 00 f0 13 10 01"}, + + {1, // shortest long + "" + + "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" + + "10 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" + + "20 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" + + "30 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" + + "40 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" + + "50 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" + + "60 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" + + "70 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" + + "80 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" + + "90 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" + + "a0 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" + + "b0 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" + + "c0 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" + + "d0 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" + + "e0 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f" + + "f0 01 02 03 04 05 06 07 08 09 0a 0b", + "" + + "" + + "fc 00 fc 00 01 02 03 04 05 06 07 08 09 0a 0b 0c" + + "0d 0e 0f 10 01 02 03 04 05 06 07 08 09 0a 0b 0c" + + "0d 0e 0f 20 01 02 03 04 05 06 07 08 09 0a 0b 0c" + + "0d 0e 0f 30 01 02 03 04 05 06 07 08 09 0a 0b 0c" + + "0d 0e 0f 40 01 02 03 04 05 06 07 08 09 0a 0b 0c" + + "0d 0e 0f 50 01 02 03 04 05 06 07 08 09 0a 0b 0c" + + "0d 0e 0f 60 01 02 03 04 05 06 07 08 09 0a 0b 0c" + + "0d 0e 0f 70 01 02 03 04 05 06 07 08 09 0a 0b 0c" + + "0d 0e 0f 80 01 02 03 04 05 06 07 08 09 0a 0b 0c" + + "0d 0e 0f 90 01 02 03 04 05 06 07 08 09 0a 0b 0c" + + "0d 0e 0f a0 01 02 03 04 05 06 07 08 09 0a 0b 0c" + + "0d 0e 0f b0 01 02 03 04 05 06 07 08 09 0a 0b 0c" + + "0d 0e 0f c0 01 02 03 04 05 06 07 08 09 0a 0b 0c" + + "0d 0e 0f d0 01 02 03 04 05 06 07 08 09 0a 0b 0c" + + "0d 0e 0f e0 01 02 03 04 05 06 07 08 09 0a 0b 0c" + + "0d 0e 0f f0 01 02 03 04 05 06 07 08 09 0a 0b 00", + "" + + "" + + "4e fc 01 20 00 01 02 03 04 05 06 07 08 09 0a 0b" + + "0c 0d 0e 0f 10 1d 10 00 20 1d 10 00 30 1d 10 00" + + "40 1d 10 00 50 1d 10 00 60 1d 10 00 70 1d 10 00" + + "80 1d 10 00 90 1d 10 00 a0 1d 10 00 b0 1d 10 00" + + "c0 1d 10 00 d0 1d 10 00 e0 1d 10 00 f0 15 10 01"}, + } + + for i, test := range tab { + f := func(compress bool, e []byte) { + f := NewMemFiler() + a, err := newPAllocator(f) + if err != nil { + t.Fatal(err) + } + + a.Compress = compress + h, err := a.Alloc(s2b(test.b)) + if err != nil { + t.Fatalf("%d %#v\n%s", i, err, hex.Dump(mfBytes(f))) + } + + if g, e := h, test.h; g != e { + t.Fatal(i, g, e) + } + + g := mfBytes(f) + if g = g[fltSz:]; !bytes.Equal(g, e) { + t.Fatalf("\ni: %d compress: %t\ng:\n%se:\n%s", i, compress, hex.Dump(g), hex.Dump(e)) + } + } + f(false, s2b(test.f)) + f(true, s2b(test.fc)) + } +} + +func TestAllocatorMakeUsedBlock(t *testing.T) { + f := NewMemFiler() + a, err := NewAllocator(f, &Options{}) + if err != nil { + t.Fatal(err) + } + + dst := bufs.GCache.Get(zappy.MaxEncodedLen(maxRq + 1)) + defer bufs.GCache.Put(dst) + if _, _, _, err := a.makeUsedBlock(dst, make([]byte, maxRq)); err != nil { + t.Fatal(err) + } + + if _, _, _, err := a.makeUsedBlock(dst, make([]byte, maxRq+1)); err == nil { + t.Fatal("unexpected success") + } +} + +func stableRef(m map[int64][]byte) (r []struct { + h int64 + b []byte +}) { + a := make(sortutil.Int64Slice, 0, len(m)) + for k := range m { + a = append(a, k) + } + sort.Sort(a) + for _, v := range a { + r = append(r, struct { + h int64 + b []byte + }{v, m[v]}) + } + return +} + +func TestAllocatorRnd(t *testing.T) { + N := *testN + + for cc := 0; cc < 2; cc++ { + rng := rand.New(rand.NewSource(42)) + f := NewMemFiler() + a, err := newPAllocator(f) + if err != nil { + t.Fatal(err) + } + + balance := 0 + + bad := func() bool { + if a.Compress { + return false + } + + actual := a.stats.TotalAtoms - a.stats.FreeAtoms - a.stats.Relocations + if int64(balance) != actual { + t.Logf("balance: %d, actual %d\n%#v", balance, actual, a.stats) + return true + } + + return false + } + + if cc != 0 { + a.Compress = true + } + ref := map[int64][]byte{} + + for pass := 0; pass < 2; pass++ { + + // A) Alloc N blocks + for i := 0; i < N; i++ { + rq := rng.Int31n(int32(*allocRndTestLimit)) + if rq%127 == 0 { + rq = 3 * maxRq / 4 + } + if rq%11 == 0 { + rq %= 23 + } + if hl := *allocRndTestHardLimit; hl != 0 { + rq = rq % int32(hl) + } + b := make([]byte, rq) + for j := range b { + b[j] = byte(rng.Int()) + } + if rq > 300 { + for i := 100; i < 200; i++ { + b[i] = 'A' // give compression a chance + } + } + + balance += n2atoms(len(b)) + h, err := a.Alloc(b) + if err != nil || bad() { + dump(a, t) + t.Fatalf( + "A) N %d, kind %d, pass %d, i:%d, len(b):%d(%#x), err %v", + N, 0, pass, i, len(b), len(b), err, + ) + } + + ref[h] = b + } + + var rb []byte + + // B) Check them back + for h, wb := range ref { + if rb, err = a.Get(rb, h); err != nil { + dump(a, t) + t.Fatal("B)", err) + } + + if !bytes.Equal(rb, wb) { + dump(a, t) + t.Fatalf("B) h %d", h) + } + } + + nf := 0 + // C) Free every third block + for _, v := range stableRef(ref) { + h, b := v.h, v.b + if rng.Int()%3 != 0 { + continue + } + + balance -= n2atoms(len(b)) + if err = a.Free(h); err != nil || bad() { + dump(a, t) + t.Fatal(err) + } + + delete(ref, h) + nf++ + } + + // D) Check them back + for h, wb := range ref { + if rb, err = a.Get(rb, h); err != nil { + dump(a, t) + t.Fatal("D)", err) + } + + if !bytes.Equal(rb, wb) { + dump(a, t) + t.Fatalf("D) h %d", h) + } + } + + // E) Resize every block remaining + for _, v := range stableRef(ref) { + h, wb := v.h, append([]byte(nil), v.b...) + len0 := len(wb) + switch rng.Int() & 1 { + case 0: + wb = wb[:len(wb)*3/4] + case 1: + wb = append(wb, wb...) + } + if len(wb) > maxRq { + wb = wb[:maxRq] + } + + for j := range wb { + wb[j] = byte(rng.Int()) + } + if len(wb) > 300 { + for i := 100; i < 200; i++ { + wb[i] = 'D' // give compression a chance + } + } + a0, a1 := n2atoms(len0), n2atoms(len(wb)) + balance = balance - a0 + a1 + if err := a.Realloc(h, wb); err != nil || bad() { + dump(a, t) + t.Fatalf( + "D) h:%#x, len(b):%#4x, len(wb): %#x, err %v", + h, len0, len(wb), err, + ) + } + + if err = cacheAudit(a.m, &a.lru); err != nil { + t.Fatal(err) + } + + ref[h] = wb + } + + // F) Check them back + for h, wb := range ref { + if rb, err = a.Get(rb, h); err != nil { + dump(a, t) + t.Fatal("E)", err) + } + + if !bytes.Equal(rb, wb) { + dump(a, t) + t.Fatalf("E) h %d", h) + } + } + } + + if cc == 0 { + sz, err := f.Size() + if err != nil { + t.Fatal(err) + } + + t.Logf( + "kind %d, AllocAtoms %7d, AllocBytes %7d, FreeAtoms %7d, Relocations %7d, TotalAtoms %7d, f.Size %7d, space eff %.2f%%", + 0, a.stats.AllocAtoms, a.stats.AllocBytes, a.stats.FreeAtoms, a.stats.Relocations, a.stats.TotalAtoms, sz, 100*float64(a.stats.AllocBytes)/float64(sz), + ) + } + // Free everything + for h, b := range ref { + balance -= n2atoms(len(b)) + if err = a.Free(h); err != nil || bad() { + dump(a, t) + t.Fatal(err) + } + } + + sz, err := a.f.Size() + if err != nil { + t.Fatal(err) + } + + if g, e := sz, int64(fltSz); g != e { + dump(a, t) + t.Fatal(g, e) + } + } +} + +func TestRollbackAllocator(t *testing.T) { + f := NewMemFiler() + var r *RollbackFiler + r, err := NewRollbackFiler(f, + func(sz int64) (err error) { + if err = f.Truncate(sz); err != nil { + return err + } + + return f.Sync() + }, + f, + ) + if err != nil { + t.Fatal(err) + } + + if err := r.BeginUpdate(); err != nil { // BeginUpdate 0->1 + t.Fatal(err) + } + + a, err := NewAllocator(r, &Options{}) + if err != nil { + t.Fatal(err) + } + + h, err := a.Alloc(nil) + if err != nil { + t.Fatal(err) + } + + if h != 1 { + t.Fatal(h) + } + + // | 1 | + + h, err = a.Alloc(nil) + if err != nil { + t.Fatal(err) + } + + if h != 2 { + t.Fatal(h) + } + + // | 1 | 2 | + h, err = a.Alloc(nil) + if err != nil { + t.Fatal(err) + } + + if h != 3 { + t.Fatal(h) + } + + // | 1 | 2 | 3 | + if err = a.Free(2); err != nil { + t.Fatal(err) + } + + // | 1 | free | 3 | + if err := r.BeginUpdate(); err != nil { // BeginUpdate 1->2 + t.Fatal(err) + } + + h, err = a.Alloc(nil) + if err != nil { + t.Fatal(err) + } + + if h != 2 { + t.Fatal(h) + } + + // | 1 | 2 | 3 | + if err := r.Rollback(); err != nil { // Rollback 2->1 + t.Fatal(err) + } + + // | 1 | free | 3 | + h, err = a.Alloc(nil) + if err != nil { + t.Fatal(err) + } + + if h != 2 { + t.Fatal(h) + } + + // | 1 | 2 | 3 | + if err := a.Verify(NewMemFiler(), nil, nil); err != nil { + t.Fatal(err) + } +} + +func benchmarkAllocatorAlloc(b *testing.B, f Filer, sz int) { + if err := f.BeginUpdate(); err != nil { + b.Error(err) + return + } + + a, err := NewAllocator(f, &Options{}) + if err != nil { + b.Error(err) + return + } + + if err = f.EndUpdate(); err != nil { + b.Error(err) + return + } + + v := make([]byte, sz) + runtime.GC() + b.ResetTimer() + for i := 0; i < b.N; i++ { + if err = f.BeginUpdate(); err != nil { + b.Error(err) + return + } + + if h, err := a.Alloc(v); h <= 0 || err != nil { + f.EndUpdate() + b.Error(h, err) + return + } + + if err = f.EndUpdate(); err != nil { + b.Error(err) + return + } + } +} + +func benchmarkAllocatorAllocMemFiler(b *testing.B, sz int) { + f := NewMemFiler() + benchmarkAllocatorAlloc(b, f, sz) +} + +func BenchmarkAllocatorAllocMemFiler1e0(b *testing.B) { + benchmarkAllocatorAllocMemFiler(b, 0) +} + +func BenchmarkAllocatorAllocMemFiler1e1(b *testing.B) { + benchmarkAllocatorAllocMemFiler(b, 1e1) +} + +func BenchmarkAllocatorAllocMemFiler1e2(b *testing.B) { + benchmarkAllocatorAllocMemFiler(b, 1e2) +} + +func BenchmarkAllocatorAllocMemFiler1e3(b *testing.B) { + benchmarkAllocatorAllocMemFiler(b, 1e3) +} + +func benchmarkAllocatorAllocSimpleFileFiler(b *testing.B, sz int) { + dir, testDbName := temp() + defer os.RemoveAll(dir) + + f, err := os.OpenFile(testDbName, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0600) + if err != nil { + b.Fatal(err) + } + + defer f.Close() + + benchmarkAllocatorAlloc(b, NewSimpleFileFiler(f), sz) +} + +func BenchmarkAllocatorAllocSimpleFileFiler0(b *testing.B) { + benchmarkAllocatorAllocSimpleFileFiler(b, 0) +} + +func BenchmarkAllocatorAllocSimpleFileFiler1e1(b *testing.B) { + benchmarkAllocatorAllocSimpleFileFiler(b, 1e1) +} + +func BenchmarkAllocatorAllocSimpleFileFiler1e2(b *testing.B) { + benchmarkAllocatorAllocSimpleFileFiler(b, 1e2) +} + +func BenchmarkAllocatorAllocSimpleFileFiler1e3(b *testing.B) { + benchmarkAllocatorAllocSimpleFileFiler(b, 1e3) +} + +func benchmarkAllocatorAllocRollbackFiler(b *testing.B, sz int) { + dir, testDbName := temp() + defer os.RemoveAll(dir) + + f, err := os.OpenFile(testDbName, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0600) + if err != nil { + b.Fatal(err) + } + + defer f.Close() + + g := NewSimpleFileFiler(f) + var filer *RollbackFiler + if filer, err = NewRollbackFiler( + g, + func(sz int64) error { + if err = g.Truncate(sz); err != nil { + return err + } + + return g.Sync() + }, + g, + ); err != nil { + b.Error(err) + return + } + + benchmarkAllocatorAlloc(b, filer, sz) +} + +func BenchmarkAllocatorAllocRollbackFiler0(b *testing.B) { + benchmarkAllocatorAllocRollbackFiler(b, 0) +} + +func BenchmarkAllocatorAllocRollbackFiler1e1(b *testing.B) { + benchmarkAllocatorAllocRollbackFiler(b, 1e1) +} + +func BenchmarkAllocatorAllocRollbackFiler1e2(b *testing.B) { + benchmarkAllocatorAllocRollbackFiler(b, 1e2) +} + +func BenchmarkAllocatorAllocRollbackFiler1e3(b *testing.B) { + benchmarkAllocatorAllocRollbackFiler(b, 1e3) +} + +func benchmarkAllocatorAllocACIDFiler(b *testing.B, sz int) { + dir, testDbName := temp() + defer os.RemoveAll(dir) + + f, err := os.OpenFile(testDbName, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0600) + if err != nil { + b.Fatal(err) + } + + defer f.Close() + + wal, err := os.OpenFile(testDbName+".wal", os.O_CREATE|os.O_EXCL|os.O_RDWR, 0600) + if err != nil { + b.Fatal(err) + } + + defer wal.Close() + + filer, err := NewACIDFiler(NewSimpleFileFiler(f), wal) + if err != nil { + b.Error(err) + return + } + + benchmarkAllocatorAlloc(b, filer, sz) +} + +func BenchmarkAllocatorAllocACIDFiler0(b *testing.B) { + benchmarkAllocatorAllocACIDFiler(b, 0) +} + +func BenchmarkAllocatorAllocACIDFiler1e1(b *testing.B) { + benchmarkAllocatorAllocACIDFiler(b, 1e1) +} + +func BenchmarkAllocatorAllocACIDFiler1e2(b *testing.B) { + benchmarkAllocatorAllocACIDFiler(b, 1e2) +} + +func BenchmarkAllocatorAllocACIDFiler1e3(b *testing.B) { + benchmarkAllocatorAllocACIDFiler(b, 1e3) +} + +func benchmarkAllocatorRndFree(b *testing.B, f Filer, sz int) { + if err := f.BeginUpdate(); err != nil { + b.Error(err) + return + } + + a, err := NewAllocator(f, &Options{}) + if err != nil { + b.Error(err) + return + } + + if err = f.EndUpdate(); err != nil { + b.Error(err) + return + } + + v := make([]byte, sz) + ref := map[int64]struct{}{} + for i := 0; i < b.N; i++ { + if err = f.BeginUpdate(); err != nil { + b.Error(err) + return + } + + h, err := a.Alloc(v) + if h <= 0 || err != nil { + f.EndUpdate() + b.Error(h, err) + return + } + + ref[h] = struct{}{} + + if err = f.EndUpdate(); err != nil { + b.Error(err) + return + } + } + runtime.GC() + b.ResetTimer() + for h := range ref { + if err = f.BeginUpdate(); err != nil { + b.Error(err) + return + } + + if err = a.Free(h); err != nil { + f.EndUpdate() + b.Error(h, err) + return + } + + if err = f.EndUpdate(); err != nil { + b.Error(err) + return + } + } +} + +func benchmarkAllocatorRndFreeMemFiler(b *testing.B, sz int) { + f := NewMemFiler() + benchmarkAllocatorRndFree(b, f, sz) +} + +func BenchmarkAllocatorRndFreeMemFiler0(b *testing.B) { + benchmarkAllocatorRndFreeMemFiler(b, 0) +} + +func BenchmarkAllocatorRndFreeMemFiler1e1(b *testing.B) { + benchmarkAllocatorRndFreeMemFiler(b, 1e1) +} + +func BenchmarkAllocatorRndFreeMemFiler1e2(b *testing.B) { + benchmarkAllocatorRndFreeMemFiler(b, 1e2) +} + +func BenchmarkAllocatorRndFreeMemFiler1e3(b *testing.B) { + benchmarkAllocatorRndFreeMemFiler(b, 1e3) +} + +func benchmarkAllocatorRndFreeSimpleFileFiler(b *testing.B, sz int) { + dir, testDbName := temp() + defer os.RemoveAll(dir) + + f, err := os.OpenFile(testDbName, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0600) + if err != nil { + b.Fatal(err) + } + + defer f.Close() + + benchmarkAllocatorRndFree(b, NewSimpleFileFiler(f), sz) +} + +func BenchmarkAllocatorRndFreeSimpleFileFiler0(b *testing.B) { + benchmarkAllocatorRndFreeSimpleFileFiler(b, 0) +} + +func BenchmarkAllocatorRndFreeSimpleFileFiler1e1(b *testing.B) { + benchmarkAllocatorRndFreeSimpleFileFiler(b, 1e1) +} + +func BenchmarkAllocatorRndFreeSimpleFileFiler1e2(b *testing.B) { + benchmarkAllocatorRndFreeSimpleFileFiler(b, 1e2) +} + +func BenchmarkAllocatorRndFreeSimpleFileFiler1e3(b *testing.B) { + benchmarkAllocatorRndFreeSimpleFileFiler(b, 1e3) +} + +func benchmarkAllocatorRndFreeRollbackFiler(b *testing.B, sz int) { + dir, testDbName := temp() + defer os.RemoveAll(dir) + + f, err := os.OpenFile(testDbName, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0600) + if err != nil { + b.Fatal(err) + } + + defer f.Close() + + g := NewSimpleFileFiler(f) + var filer *RollbackFiler + if filer, err = NewRollbackFiler( + g, + func(sz int64) error { + if err = g.Truncate(sz); err != nil { + return err + } + + return g.Sync() + }, + g, + ); err != nil { + b.Error(err) + return + } + + benchmarkAllocatorRndFree(b, filer, sz) +} + +func BenchmarkAllocatorRndFreeRollbackFiler0(b *testing.B) { + benchmarkAllocatorRndFreeRollbackFiler(b, 0) +} + +func BenchmarkAllocatorRndFreeRollbackFiler1e1(b *testing.B) { + benchmarkAllocatorRndFreeRollbackFiler(b, 1e1) +} + +func BenchmarkAllocatorRndFreeRollbackFiler1e2(b *testing.B) { + benchmarkAllocatorRndFreeRollbackFiler(b, 1e2) +} + +func BenchmarkAllocatorRndFreeRollbackFiler1e3(b *testing.B) { + benchmarkAllocatorRndFreeRollbackFiler(b, 1e3) +} + +func benchmarkAllocatorRndFreeACIDFiler(b *testing.B, sz int) { + dir, testDbName := temp() + defer os.RemoveAll(dir) + + f, err := os.OpenFile(testDbName, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0600) + if err != nil { + b.Fatal(err) + } + + defer f.Close() + + wal, err := os.OpenFile(testDbName+".wal", os.O_CREATE|os.O_EXCL|os.O_RDWR, 0600) + if err != nil { + b.Fatal(err) + } + + defer wal.Close() + + filer, err := NewACIDFiler(NewSimpleFileFiler(f), wal) + if err != nil { + b.Error(err) + return + } + + benchmarkAllocatorRndFree(b, filer, sz) +} + +func BenchmarkAllocatorRndFreeACIDFiler0(b *testing.B) { + benchmarkAllocatorRndFreeACIDFiler(b, 0) +} + +func BenchmarkAllocatorRndFreeACIDFiler1e1(b *testing.B) { + benchmarkAllocatorRndFreeACIDFiler(b, 1e1) +} + +func BenchmarkAllocatorRndFreeACIDFiler1e2(b *testing.B) { + benchmarkAllocatorRndFreeACIDFiler(b, 1e2) +} + +func BenchmarkAllocatorRndFreeACIDFiler1e3(b *testing.B) { + benchmarkAllocatorRndFreeACIDFiler(b, 1e3) +} + +func benchmarkAllocatorRndGet(b *testing.B, f Filer, sz int) { + if err := f.BeginUpdate(); err != nil { + b.Error(err) + return + } + + a, err := NewAllocator(f, &Options{}) + if err != nil { + b.Error(err) + return + } + + if err = f.EndUpdate(); err != nil { + b.Error(err) + return + } + + v := make([]byte, sz) + ref := map[int64]struct{}{} + if err = f.BeginUpdate(); err != nil { + b.Error(err) + return + } + + for i := 0; i < b.N; i++ { + h, err := a.Alloc(v) + if h <= 0 || err != nil { + f.EndUpdate() + b.Error(h, err) + return + } + + ref[h] = struct{}{} + + } + if err = f.EndUpdate(); err != nil { + b.Error(err) + return + } + + runtime.GC() + b.ResetTimer() + for h := range ref { + if err = f.BeginUpdate(); err != nil { + b.Error(err) + return + } + + if _, err = a.Get(v, h); err != nil { + f.EndUpdate() + b.Error(h, err) + return + } + + if err = f.EndUpdate(); err != nil { + b.Error(err) + return + } + } +} + +func benchmarkAllocatorRndGetMemFiler(b *testing.B, sz int) { + f := NewMemFiler() + benchmarkAllocatorRndGet(b, f, sz) +} + +func BenchmarkAllocatorRndGetMemFiler0(b *testing.B) { + benchmarkAllocatorRndGetMemFiler(b, 0) +} + +func BenchmarkAllocatorRndGetMemFiler1e1(b *testing.B) { + benchmarkAllocatorRndGetMemFiler(b, 1e1) +} + +func BenchmarkAllocatorRndGetMemFiler1e2(b *testing.B) { + benchmarkAllocatorRndGetMemFiler(b, 1e2) +} + +func BenchmarkAllocatorRndGetMemFiler1e3(b *testing.B) { + benchmarkAllocatorRndGetMemFiler(b, 1e3) +} + +func benchmarkAllocatorRndGetSimpleFileFiler(b *testing.B, sz int) { + os.Remove(testDbName) + <-time.After(5 * time.Second) + f, err := os.OpenFile(testDbName, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0600) + if err != nil { + b.Fatal(err) + } + + defer func() { + f.Close() + os.Remove(testDbName) + }() + + benchmarkAllocatorRndGet(b, NewSimpleFileFiler(f), sz) +} + +func BenchmarkAllocatorRndGetSimpleFileFiler0(b *testing.B) { + benchmarkAllocatorRndGetSimpleFileFiler(b, 0) +} + +func BenchmarkAllocatorRndGetSimpleFileFiler1e1(b *testing.B) { + benchmarkAllocatorRndGetSimpleFileFiler(b, 1e1) +} + +func BenchmarkAllocatorRndGetSimpleFileFiler1e2(b *testing.B) { + benchmarkAllocatorRndGetSimpleFileFiler(b, 1e2) +} + +func BenchmarkAllocatorRndGetSimpleFileFiler1e3(b *testing.B) { + benchmarkAllocatorRndGetSimpleFileFiler(b, 1e3) +} + +func benchmarkAllocatorRndGetRollbackFiler(b *testing.B, sz int) { + os.Remove(testDbName) + f, err := os.OpenFile(testDbName, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0600) + if err != nil { + b.Fatal(err) + } + + defer func() { + f.Close() + os.Remove(testDbName) + }() + + g := NewSimpleFileFiler(f) + var filer *RollbackFiler + if filer, err = NewRollbackFiler( + g, + func(sz int64) error { + if err = g.Truncate(sz); err != nil { + return err + } + + return g.Sync() + }, + g, + ); err != nil { + b.Error(err) + return + } + + benchmarkAllocatorRndGet(b, filer, sz) +} + +func BenchmarkAllocatorRndGetRollbackFiler0(b *testing.B) { + benchmarkAllocatorRndGetRollbackFiler(b, 0) +} + +func BenchmarkAllocatorRndGetRollbackFiler1e1(b *testing.B) { + benchmarkAllocatorRndGetRollbackFiler(b, 1e1) +} + +func BenchmarkAllocatorRndGetRollbackFiler1e2(b *testing.B) { + benchmarkAllocatorRndGetRollbackFiler(b, 1e2) +} + +func BenchmarkAllocatorRndGetRollbackFiler1e3(b *testing.B) { + benchmarkAllocatorRndGetRollbackFiler(b, 1e3) +} + +func benchmarkAllocatorRndGetACIDFiler(b *testing.B, sz int) { + os.Remove(testDbName) + os.Remove(walName) + f, err := os.OpenFile(testDbName, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0600) + if err != nil { + b.Fatal(err) + } + + defer func() { + f.Close() + os.Remove(testDbName) + }() + + wal, err := os.OpenFile(walName, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0600) + if err != nil { + b.Fatal(err) + } + + defer func() { + wal.Close() + os.Remove(walName) + }() + + filer, err := NewACIDFiler(NewSimpleFileFiler(f), wal) + if err != nil { + b.Error(err) + return + } + + benchmarkAllocatorRndGet(b, filer, sz) +} + +func BenchmarkAllocatorRndGetACIDFiler0(b *testing.B) { + benchmarkAllocatorRndGetACIDFiler(b, 0) +} + +func BenchmarkAllocatorRndGetACIDFiler1e1(b *testing.B) { + benchmarkAllocatorRndGetACIDFiler(b, 1e1) +} + +func BenchmarkAllocatorRndGetACIDFiler1e2(b *testing.B) { + benchmarkAllocatorRndGetACIDFiler(b, 1e2) +} + +func BenchmarkAllocatorRndGetACIDFiler1e3(b *testing.B) { + benchmarkAllocatorRndGetACIDFiler(b, 1e3) +} + +func TestFltFind(t *testing.T) { + var f flt + + f.init() + if h := f.find(1); h != 0 { + t.Fatal(h) + } + + // [0] + f.init() + f[0].head = 1 + if h := f.find(1); h != 1 || f[0].head != 0 { + t.Fatal(h) + } + + f.init() + f[0].head = 1 + if h := f.find(2); h != 0 || f[0].head == 0 { + t.Fatal(h) + } + + // [1] + f.init() + f[1].head = 1 + if h := f.find(1); h != 1 || f[1].head != 0 { + t.Fatal("\n", f, h) + } + + f.init() + f[1].head = 1 + if h := f.find(2); h != 1 || f[1].head != 0 { + t.Fatal(f, h) + } + + f.init() + f[1].head = 1 + if h := f.find(3); h != 0 || f[1].head == 0 { + t.Fatal(h) + } + + // [2] + f.init() + f[2].head = 1 + if h := f.find(1); h != 1 || f[2].head != 0 { + t.Fatal(h) + } + + f.init() + f[2].head = 1 + if h := f.find(2); h != 1 || f[2].head != 0 { + t.Fatal(h) + } + + f.init() + f[2].head = 1 + if h := f.find(3); h != 1 || f[2].head != 0 { + t.Fatal(h) + } + + f.init() + f[2].head = 1 + if h := f.find(4); h != 1 || f[2].head != 0 { + t.Fatal(h) + } + + f.init() + f[2].head = 1 + if h := f.find(5); h != 0 || f[2].head == 0 { + t.Fatal(h) + } +} + +func TestFltHead(t *testing.T) { + var f flt + f.init() + if h := f.head(1); h != 0 { + t.Fatal(h) + } + + // [0] + f.init() + f[0].head = 1 + if h := f.head(1); h != 1 { + t.Fatal(h) + } + + f.init() + f[0].head = 1 + if h := f.head(2); h != 0 { + t.Fatal(h) + } + + // [1] + f.init() + f[1].head = 1 + if h := f.head(1); h != 0 { + t.Fatal(h) + } + + f.init() + f[1].head = 1 + if h := f.head(2); h != 1 { + t.Fatal(h) + } + + f.init() + f[1].head = 1 + if h := f.head(3); h != 1 { + t.Fatal(h) + } + + f.init() + f[1].head = 1 + if h := f.head(4); h != 0 { + t.Fatal(h) + } + + // [2] + f.init() + f[2].head = 1 + if h := f.head(1); h != 0 { + t.Fatal(h) + } + + f.init() + f[2].head = 1 + if h := f.head(2); h != 0 { + t.Fatal(h) + } + + f.init() + f[2].head = 1 + if h := f.head(3); h != 0 { + t.Fatal(h) + } + + f.init() + f[2].head = 1 + if h := f.head(4); h != 1 { + t.Fatal(h) + } + + f.init() + f[2].head = 1 + if h := f.head(5); h != 1 { + t.Fatal(h) + } + + f.init() + f[2].head = 1 + if h := f.head(6); h != 1 { + t.Fatal(h) + } + + f.init() + f[2].head = 1 + if h := f.head(7); h != 1 { + t.Fatal(h) + } + + f.init() + f[2].head = 1 + if h := f.head(8); h != 0 { + t.Fatal(h) + } + +} diff --git a/Godeps/_workspace/src/github.com/cznic/exp/lldb/filer.go b/Godeps/_workspace/src/github.com/cznic/exp/lldb/filer.go new file mode 100644 index 0000000..ceea04e --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/exp/lldb/filer.go @@ -0,0 +1,192 @@ +// Copyright 2014 The lldb Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// An abstraction of file like (persistent) storage with optional (abstracted) +// support for structural integrity. + +package lldb + +import ( + "fmt" + + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/mathutil" +) + +func doubleTrouble(first, second error) error { + return fmt.Errorf("%q. Additionally, while attempting to recover (rollback): %q", first, second) +} + +// A Filer is a []byte-like model of a file or similar entity. It may +// optionally implement support for structural transaction safety. In contrast +// to a file stream, a Filer is not sequentially accessible. ReadAt and WriteAt +// are always "addressed" by an offset and are assumed to perform atomically. +// A Filer is not safe for concurrent access, it's designed for consumption by +// the other objects in package, which should use a Filer from one goroutine +// only or via a mutex. BeginUpdate, EndUpdate and Rollback must be either all +// implemented by a Filer for structural integrity - or they should be all +// no-ops; where/if that requirement is relaxed. +// +// If a Filer wraps another Filer implementation, it usually invokes the same +// methods on the "inner" one, after some possible argument translations etc. +// If a Filer implements the structural transactions handling methods +// (BeginUpdate, EndUpdate and Rollback) as no-ops _and_ wraps another Filer: +// it then still MUST invoke those methods on the inner Filer. This is +// important for the case where a RollbackFiler exists somewhere down the +// chain. It's also important for an Allocator - to know when it must +// invalidate its FLT cache. +type Filer interface { + // BeginUpdate increments the "nesting" counter (initially zero). Every + // call to BeginUpdate must be eventually "balanced" by exactly one of + // EndUpdate or Rollback. Calls to BeginUpdate may nest. + BeginUpdate() error + + // Analogous to os.File.Close(). + Close() error + + // EndUpdate decrements the "nesting" counter. If it's zero after that + // then assume the "storage" has reached structural integrity (after a + // batch of partial updates). If a Filer implements some support for + // that (write ahead log, journal, etc.) then the appropriate actions + // are to be taken for nesting == 0. Invocation of an unbalanced + // EndUpdate is an error. + EndUpdate() error + + // Analogous to os.File.Name(). + Name() string + + // PunchHole deallocates space inside a "file" in the byte range + // starting at off and continuing for size bytes. The actual hole + // created by PunchHole may be smaller than requested. The Filer size + // (as reported by `Size()` does not change when hole punching, even + // when punching the end of a file off. In contrast to the Linux + // implementation of FALLOC_FL_PUNCH_HOLE in `fallocate`(2); a Filer is + // free not only to ignore `PunchHole()` (implement it as a nop), but + // additionally no guarantees about the content of the hole, when + // eventually read back, are required, i.e. any data, not only zeros, + // can be read from the "hole", including just anything what was left + // there - with all of the possible security problems. + PunchHole(off, size int64) error + + // As os.File.ReadAt. Note: `off` is an absolute "file pointer" + // address and cannot be negative even when a Filer is a InnerFiler. + ReadAt(b []byte, off int64) (n int, err error) + + // Rollback cancels and undoes the innermost pending update level. + // Rollback decrements the "nesting" counter. If a Filer implements + // some support for keeping structural integrity (write ahead log, + // journal, etc.) then the appropriate actions are to be taken. + // Invocation of an unbalanced Rollback is an error. + Rollback() error + + // Analogous to os.File.FileInfo().Size(). + Size() (int64, error) + + // Analogous to os.Sync(). + Sync() (err error) + + // Analogous to os.File.Truncate(). + Truncate(size int64) error + + // Analogous to os.File.WriteAt(). Note: `off` is an absolute "file + // pointer" address and cannot be negative even when a Filer is a + // InnerFiler. + WriteAt(b []byte, off int64) (n int, err error) +} + +var _ Filer = &InnerFiler{} // Ensure InnerFiler is a Filer. + +// A InnerFiler is a Filer with added addressing/size translation. +type InnerFiler struct { + outer Filer + off int64 +} + +// NewInnerFiler returns a new InnerFiler wrapped by `outer` in a way which +// adds `off` to every access. +// +// For example, considering: +// +// inner := NewInnerFiler(outer, 10) +// +// then +// +// inner.WriteAt([]byte{42}, 4) +// +// translates to +// +// outer.WriteAt([]byte{42}, 14) +// +// But an attempt to emulate +// +// outer.WriteAt([]byte{17}, 9) +// +// by +// +// inner.WriteAt([]byte{17}, -1) +// +// will fail as the `off` parameter can never be < 0. Also note that +// +// inner.Size() == outer.Size() - off, +// +// i.e. `inner` pretends no `outer` exists. Finally, after e.g. +// +// inner.Truncate(7) +// outer.Size() == 17 +// +// will be true. +func NewInnerFiler(outer Filer, off int64) *InnerFiler { return &InnerFiler{outer, off} } + +// BeginUpdate implements Filer. +func (f *InnerFiler) BeginUpdate() error { return f.outer.BeginUpdate() } + +// Close implements Filer. +func (f *InnerFiler) Close() (err error) { return f.outer.Close() } + +// EndUpdate implements Filer. +func (f *InnerFiler) EndUpdate() error { return f.outer.EndUpdate() } + +// Name implements Filer. +func (f *InnerFiler) Name() string { return f.outer.Name() } + +// PunchHole implements Filer. `off`, `size` must be >= 0. +func (f *InnerFiler) PunchHole(off, size int64) error { return f.outer.PunchHole(f.off+off, size) } + +// ReadAt implements Filer. `off` must be >= 0. +func (f *InnerFiler) ReadAt(b []byte, off int64) (n int, err error) { + if off < 0 { + return 0, &ErrINVAL{f.outer.Name() + ":ReadAt invalid off", off} + } + + return f.outer.ReadAt(b, f.off+off) +} + +// Rollback implements Filer. +func (f *InnerFiler) Rollback() error { return f.outer.Rollback() } + +// Size implements Filer. +func (f *InnerFiler) Size() (int64, error) { + sz, err := f.outer.Size() + if err != nil { + return 0, err + } + + return mathutil.MaxInt64(sz-f.off, 0), nil +} + +// Sync() implements Filer. +func (f *InnerFiler) Sync() (err error) { + return f.outer.Sync() +} + +// Truncate implements Filer. +func (f *InnerFiler) Truncate(size int64) error { return f.outer.Truncate(size + f.off) } + +// WriteAt implements Filer. `off` must be >= 0. +func (f *InnerFiler) WriteAt(b []byte, off int64) (n int, err error) { + if off < 0 { + return 0, &ErrINVAL{f.outer.Name() + ":WriteAt invalid off", off} + } + + return f.outer.WriteAt(b, f.off+off) +} diff --git a/Godeps/_workspace/src/github.com/cznic/exp/lldb/filer_test.go b/Godeps/_workspace/src/github.com/cznic/exp/lldb/filer_test.go new file mode 100644 index 0000000..9543200 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/exp/lldb/filer_test.go @@ -0,0 +1,764 @@ +// Copyright 2014 The lldb 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 lldb + +import ( + "bytes" + "encoding/hex" + "io/ioutil" + "math/rand" + "os" + "runtime" + "testing" + + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/fileutil" +) + +// Bench knobs. +const ( + filerTestChunkSize = 32e3 + filerTotalSize = 10e6 +) + +type newFunc func() Filer + +type testFileFiler struct { + Filer +} + +func (t *testFileFiler) Close() (err error) { + n := t.Name() + err = t.Filer.Close() + if errDel := os.Remove(n); errDel != nil && err == nil { + err = errDel + } + return +} + +var ( + newFileFiler = func() Filer { + file, err := ioutil.TempFile("", "lldb-test-file") + if err != nil { + panic(err) + } + + return &testFileFiler{NewSimpleFileFiler(file)} + } + + newOSFileFiler = func() Filer { + file, err := ioutil.TempFile("", "lldb-test-osfile") + if err != nil { + panic(err) + } + + return &testFileFiler{NewOSFiler(file)} + } + + newMemFiler = func() Filer { + return NewMemFiler() + } + + nwBitFiler = func() Filer { + f, err := newBitFiler(NewMemFiler()) + if err != nil { + panic(err) + } + + return f + } + + newRollbackFiler = func() Filer { + f := NewMemFiler() + + var r Filer + + checkpoint := func(sz int64) (err error) { + return f.Truncate(sz) + } + + r, err := NewRollbackFiler(f, checkpoint, f) + if err != nil { + panic(err) + } + + return r + } +) + +func TestFilerNesting(t *testing.T) { + testFilerNesting(t, newFileFiler) + testFilerNesting(t, newOSFileFiler) + testFilerNesting(t, newMemFiler) + testFilerNesting(t, newRollbackFiler) +} + +func testFilerNesting(t *testing.T, nf newFunc) { + // Check {Create, Close} works. + f := nf() + t.Log(f.Name()) + if err := f.Close(); err != nil { + t.Fatal(err) + } + + // Check {Create, EndUpdate} doesn't work. + f = nf() + t.Log(f.Name()) + if err := f.EndUpdate(); err == nil { + f.Close() + t.Fatal("unexpected success") + } + + if err := f.Close(); err != nil { + t.Fatal(err) + } + + // Check {Create, BeginUpdate, Close} doesn't work. + f = nf() + t.Log(f.Name()) + f.BeginUpdate() + + if err := f.Close(); err == nil { + t.Fatal("unexpected success") + } + + // Check {Create, BeginUpdate, EndUpdate, Close} works. + f = nf() + t.Log(f.Name()) + f.BeginUpdate() + if err := f.EndUpdate(); err != nil { + f.Close() + t.Fatal(err) + } + + if err := f.Close(); err != nil { + t.Fatal(err) + } +} + +func TestFilerTruncate(t *testing.T) { + testFilerTruncate(t, newFileFiler) + testFilerTruncate(t, newOSFileFiler) + testFilerTruncate(t, newMemFiler) + testFilerTruncate(t, nwBitFiler) + testFilerTruncate(t, newRollbackFiler) +} + +func testFilerTruncate(t *testing.T, nf newFunc) { + f := nf() + t.Log(f.Name()) + defer func() { + if err := f.Close(); err != nil { + t.Error(err) + } + }() + + if _, ok := f.(*RollbackFiler); ok { + if err := f.BeginUpdate(); err != nil { + t.Fatal(err) + } + + defer func() { + if err := f.EndUpdate(); err != nil { + t.Error(err) + } + }() + } + + // Check Truncate works. + sz := int64(1e6) + if err := f.Truncate(sz); err != nil { + t.Error(err) + return + } + + fsz, err := f.Size() + if err != nil { + t.Error(err) + return + } + + if g, e := fsz, sz; g != e { + t.Error(g, e) + return + } + + sz *= 2 + if err := f.Truncate(sz); err != nil { + t.Error(err) + return + } + + fsz, err = f.Size() + if err != nil { + t.Error(err) + return + } + + if g, e := fsz, sz; g != e { + t.Error(g, e) + return + } + + sz = 0 + if err := f.Truncate(sz); err != nil { + t.Error(err) + return + } + + fsz, err = f.Size() + if err != nil { + t.Error(err) + return + } + + if g, e := fsz, sz; g != e { + t.Error(g, e) + return + } + + // Check Truncate(-1) doesn't work. + sz = -1 + if err := f.Truncate(sz); err == nil { + t.Error(err) + return + } + +} + +func TestFilerReadAtWriteAt(t *testing.T) { + testFilerReadAtWriteAt(t, newFileFiler) + testFilerReadAtWriteAt(t, newOSFileFiler) + testFilerReadAtWriteAt(t, newMemFiler) + testFilerReadAtWriteAt(t, nwBitFiler) + testFilerReadAtWriteAt(t, newRollbackFiler) +} + +func testFilerReadAtWriteAt(t *testing.T, nf newFunc) { + f := nf() + t.Log(f.Name()) + defer func() { + if err := f.Close(); err != nil { + t.Error(err) + } + }() + + if _, ok := f.(*RollbackFiler); ok { + if err := f.BeginUpdate(); err != nil { + t.Fatal(err) + } + + defer func() { + if err := f.EndUpdate(); err != nil { + t.Error(err) + } + }() + } + + const ( + N = 1 << 16 + M = 2e2 + ) + + s := make([]byte, N) + e := make([]byte, N) + rnd := rand.New(rand.NewSource(42)) + for i := range e { + s[i] = byte(rnd.Intn(256)) + } + n2 := 0 + for i := 0; i < M; i++ { + var from, to int + for { + from = rnd.Intn(N) + to = rnd.Intn(N) + if from != to { + break + } + } + if from > to { + from, to = to, from + } + for i := range s[from:to] { + s[from+i] = byte(rnd.Intn(256)) + } + copy(e[from:to], s[from:to]) + if to > n2 { + n2 = to + } + n, err := f.WriteAt(s[from:to], int64(from)) + if err != nil { + t.Error(err) + return + } + + if g, e := n, to-from; g != e { + t.Error(g, e) + return + } + } + + fsz, err := f.Size() + if err != nil { + t.Error(err) + return + } + + if g, e := fsz, int64(n2); g != e { + t.Error(g, e) + return + } + + b := make([]byte, n2) + for i := 0; i <= M; i++ { + from := rnd.Intn(n2) + to := rnd.Intn(n2) + if from > to { + from, to = to, from + } + if i == M { + from, to = 0, n2 + } + n, err := f.ReadAt(b[from:to], int64(from)) + if err != nil && (!fileutil.IsEOF(err) && n != 0) { + fsz, err = f.Size() + if err != nil { + t.Error(err) + return + } + + t.Error(fsz, from, to, err) + return + } + + if g, e := n, to-from; g != e { + t.Error(g, e) + return + } + + if g, e := b[from:to], e[from:to]; !bytes.Equal(g, e) { + if x, ok := f.(*MemFiler); ok { + for i := int64(0); i <= 3; i++ { + t.Logf("pg %d\n----\n%s", i, hex.Dump(x.m[i][:])) + } + } + t.Errorf( + "i %d from %d to %d len(g) %d len(e) %d\n---- got ----\n%s\n---- exp ----\n%s", + i, from, to, len(g), len(e), hex.Dump(g), hex.Dump(e), + ) + return + } + } + + mf, ok := f.(*MemFiler) + if !ok { + return + } + + buf := &bytes.Buffer{} + if _, err := mf.WriteTo(buf); err != nil { + t.Error(err) + return + } + + if g, e := buf.Bytes(), e[:n2]; !bytes.Equal(g, e) { + t.Errorf("\nlen %d\n%s\nlen %d\n%s", len(g), hex.Dump(g), len(e), hex.Dump(e)) + return + } + + if err := mf.Truncate(0); err != nil { + t.Error(err) + return + } + + if _, err := mf.ReadFrom(buf); err != nil { + t.Error(err) + return + } + + roundTrip := make([]byte, n2) + if n, err := mf.ReadAt(roundTrip, 0); err != nil && n == 0 { + t.Error(err) + return + } + + if g, e := roundTrip, e[:n2]; !bytes.Equal(g, e) { + t.Errorf("\nlen %d\n%s\nlen %d\n%s", len(g), hex.Dump(g), len(e), hex.Dump(e)) + return + } +} + +func TestInnerFiler(t *testing.T) { + testInnerFiler(t, newFileFiler) + testInnerFiler(t, newOSFileFiler) + testInnerFiler(t, newMemFiler) + testInnerFiler(t, nwBitFiler) + testInnerFiler(t, newRollbackFiler) +} + +func testInnerFiler(t *testing.T, nf newFunc) { + const ( + HDR_SIZE = 42 + LONG_OFF = 3330 + ) + outer := nf() + t.Log(outer.Name()) + inner := NewInnerFiler(outer, HDR_SIZE) + defer func() { + if err := outer.Close(); err != nil { + t.Error(err) + } + }() + + if _, ok := outer.(*RollbackFiler); ok { + if err := outer.BeginUpdate(); err != nil { + t.Fatal(err) + } + + defer func() { + if err := outer.EndUpdate(); err != nil { + t.Error(err) + } + }() + } + + b := []byte{2, 5, 11} + n, err := inner.WriteAt(b, -1) + if err == nil { + t.Error("unexpected success") + return + } + + n, err = inner.ReadAt(make([]byte, 10), -1) + if err == nil { + t.Error("unexpected success") + return + } + + n, err = inner.WriteAt(b, 0) + if err != nil { + t.Error(err) + return + } + + if g, e := n, len(b); g != e { + t.Error(g, e) + return + } + + osz, err := outer.Size() + if err != nil { + t.Error(err) + return + } + + if g, e := osz, int64(HDR_SIZE+3); g != e { + t.Error(g, e) + return + } + + isz, err := inner.Size() + if err != nil { + t.Error(err) + return + } + + if g, e := isz, int64(3); g != e { + t.Error(g, e) + return + } + + rbuf := make([]byte, 3) + if n, err = outer.ReadAt(rbuf, 0); err != nil && n == 0 { + t.Error(err) + return + } + + if g, e := n, len(rbuf); g != e { + t.Error(g, e) + return + } + + if g, e := rbuf, make([]byte, 3); !bytes.Equal(g, e) { + t.Error(g, e) + } + + rbuf = make([]byte, 3) + if n, err = outer.ReadAt(rbuf, HDR_SIZE); err != nil && n == 0 { + t.Error(err) + return + } + + if g, e := n, len(rbuf); g != e { + t.Error(g, e) + return + } + + if g, e := rbuf, []byte{2, 5, 11}; !bytes.Equal(g, e) { + t.Error(g, e) + } + + rbuf = make([]byte, 3) + if n, err = inner.ReadAt(rbuf, 0); err != nil && n == 0 { + t.Error(err) + return + } + + if g, e := n, len(rbuf); g != e { + t.Error(g, e) + return + } + + if g, e := rbuf, []byte{2, 5, 11}; !bytes.Equal(g, e) { + t.Error(g, e) + } + + b = []byte{22, 55, 111} + if n, err = inner.WriteAt(b, LONG_OFF); err != nil { + t.Error(err) + return + } + + if g, e := n, len(b); g != e { + t.Error(g, e) + return + } + + osz, err = outer.Size() + if err != nil { + t.Error(err) + return + } + + if g, e := osz, int64(HDR_SIZE+LONG_OFF+3); g != e { + t.Error(g, e) + return + } + + isz, err = inner.Size() + if err != nil { + t.Error(err) + return + } + + if g, e := isz, int64(LONG_OFF+3); g != e { + t.Error(g, e) + return + } + + rbuf = make([]byte, 3) + if n, err = outer.ReadAt(rbuf, HDR_SIZE+LONG_OFF); err != nil && n == 0 { + t.Error(err) + return + } + + if g, e := n, len(rbuf); g != e { + t.Error(g, e) + return + } + + if g, e := rbuf, []byte{22, 55, 111}; !bytes.Equal(g, e) { + t.Error(g, e) + } + + rbuf = make([]byte, 3) + if n, err = inner.ReadAt(rbuf, LONG_OFF); err != nil && n == 0 { + t.Error(err) + return + } + + if g, e := n, len(rbuf); g != e { + t.Error(g, e) + return + } + + if g, e := rbuf, []byte{22, 55, 111}; !bytes.Equal(g, e) { + t.Error(g, e) + return + } + + if err = inner.Truncate(1); err != nil { + t.Error(err) + return + } + + isz, err = inner.Size() + if err != nil { + t.Error(err) + return + } + + if g, e := isz, int64(1); g != e { + t.Error(g, e) + return + } + + osz, err = outer.Size() + if err != nil { + t.Error(err) + return + } + + if g, e := osz, int64(HDR_SIZE+1); g != e { + t.Error(g, e) + return + } +} + +func TestFileReadAtHole(t *testing.T) { + testFileReadAtHole(t, newFileFiler) + testFileReadAtHole(t, newOSFileFiler) + testFileReadAtHole(t, newMemFiler) + testFileReadAtHole(t, nwBitFiler) + testFileReadAtHole(t, newRollbackFiler) +} + +func testFileReadAtHole(t *testing.T, nf newFunc) { + f := nf() + t.Log(f.Name()) + defer func() { + if err := f.Close(); err != nil { + t.Error(err) + } + }() + + if _, ok := f.(*RollbackFiler); ok { + if err := f.BeginUpdate(); err != nil { + t.Fatal(err) + } + + defer func() { + if err := f.EndUpdate(); err != nil { + t.Error(err) + } + }() + } + + n, err := f.WriteAt([]byte{1}, 40000) + if err != nil { + t.Error(err) + return + } + + if n != 1 { + t.Error(n) + return + } + + n, err = f.ReadAt(make([]byte, 1000), 20000) + if err != nil { + t.Error(err) + return + } + + if n != 1000 { + t.Error(n) + return + } +} + +func BenchmarkMemFilerWrSeq(b *testing.B) { + b.StopTimer() + buf := make([]byte, filerTestChunkSize) + for i := range buf { + buf[i] = byte(rand.Int()) + } + f := newMemFiler() + runtime.GC() + b.StartTimer() + var ofs int64 + for i := 0; i < b.N; i++ { + _, err := f.WriteAt(buf, ofs) + if err != nil { + b.Fatal(err) + } + + ofs = (ofs + filerTestChunkSize) % filerTotalSize + } +} + +func BenchmarkMemFilerRdSeq(b *testing.B) { + b.StopTimer() + buf := make([]byte, filerTestChunkSize) + for i := range buf { + buf[i] = byte(rand.Int()) + } + f := newMemFiler() + var ofs int64 + for i := 0; i < b.N; i++ { + _, err := f.WriteAt(buf, ofs) + if err != nil { + b.Fatal(err) + } + + ofs = (ofs + filerTestChunkSize) % filerTotalSize + } + runtime.GC() + b.StartTimer() + ofs = 0 + for i := 0; i < b.N; i++ { + n, err := f.ReadAt(buf, ofs) + if err != nil && n == 0 { + b.Fatal(err) + } + + ofs = (ofs + filerTestChunkSize) % filerTotalSize + } +} + +func BenchmarkMemFilerWrRand(b *testing.B) { + b.StopTimer() + rng := rand.New(rand.NewSource(42)) + f := newMemFiler() + var bytes int64 + + var ofs, runs []int + for i := 0; i < b.N; i++ { + ofs = append(ofs, rng.Intn(1<<31-1)) + runs = append(runs, rng.Intn(1<<31-1)%(2*pgSize)) + } + data := make([]byte, 2*pgSize) + for i := range data { + data[i] = byte(rng.Int()) + } + + runtime.GC() + b.StartTimer() + for i, v := range ofs { + n := runs[i] + bytes += int64(n) + f.WriteAt(data[:n], int64(v)) + } + b.StopTimer() +} + +func BenchmarkMemFilerRdRand(b *testing.B) { + b.StopTimer() + rng := rand.New(rand.NewSource(42)) + f := newMemFiler() + var bytes int64 + + var ofs, runs []int + for i := 0; i < b.N; i++ { + ofs = append(ofs, rng.Intn(1<<31-1)) + runs = append(runs, rng.Intn(1<<31-1)%(2*pgSize)) + } + data := make([]byte, 2*pgSize) + for i := range data { + data[i] = byte(rng.Int()) + } + + for i, v := range ofs { + n := runs[i] + bytes += int64(n) + f.WriteAt(data[:n], int64(v)) + } + + runtime.GC() + b.StartTimer() + for _, v := range ofs { + f.ReadAt(data, int64(v)) + } + b.StopTimer() +} diff --git a/Godeps/_workspace/src/github.com/cznic/exp/lldb/gb.go b/Godeps/_workspace/src/github.com/cznic/exp/lldb/gb.go new file mode 100644 index 0000000..d41c69e --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/exp/lldb/gb.go @@ -0,0 +1,812 @@ +// Copyright 2014 The lldb Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Utilities to encode/decode and collate Go predeclared scalar types (and the +// typeless nil and []byte). The encoding format is a variation of the one +// used by the "encoding/gob" package. + +package lldb + +import ( + "bytes" + "fmt" + "math" + + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/mathutil" +) + +const ( + gbNull = iota // 0x00 + gbFalse // 0x01 + gbTrue // 0x02 + gbFloat0 // 0x03 + gbFloat1 // 0x04 + gbFloat2 // 0x05 + gbFloat3 // 0x06 + gbFloat4 // 0x07 + gbFloat5 // 0x08 + gbFloat6 // 0x09 + gbFloat7 // 0x0a + gbFloat8 // 0x0b + gbComplex0 // 0x0c + gbComplex1 // 0x0d + gbComplex2 // 0x0e + gbComplex3 // 0x0f + gbComplex4 // 0x10 + gbComplex5 // 0x11 + gbComplex6 // 0x12 + gbComplex7 // 0x13 + gbComplex8 // 0x14 + gbBytes00 // 0x15 + gbBytes01 // 0x16 + gbBytes02 // 0x17 + gbBytes03 // 0x18 + gbBytes04 // 0x19 + gbBytes05 // 0x1a + gbBytes06 // 0x1b + gbBytes07 // 0x1c + gbBytes08 // 0x1d + gbBytes09 // 0x1e + gbBytes10 // 0x1f + gbBytes11 // 0x20 + gbBytes12 // 0x21 + gbBytes13 // 0x22 + gbBytes14 // 0x23 + gbBytes15 // 0x24 + gbBytes16 // 0x25 + gbBytes17 // Ox26 + gbBytes1 // 0x27 + gbBytes2 // 0x28: Offset by one to allow 64kB sized []byte. + gbString00 // 0x29 + gbString01 // 0x2a + gbString02 // 0x2b + gbString03 // 0x2c + gbString04 // 0x2d + gbString05 // 0x2e + gbString06 // 0x2f + gbString07 // 0x30 + gbString08 // 0x31 + gbString09 // 0x32 + gbString10 // 0x33 + gbString11 // 0x34 + gbString12 // 0x35 + gbString13 // 0x36 + gbString14 // 0x37 + gbString15 // 0x38 + gbString16 // 0x39 + gbString17 // 0x3a + gbString1 // 0x3b + gbString2 // 0x3c + gbUintP1 // 0x3d + gbUintP2 // 0x3e + gbUintP3 // 0x3f + gbUintP4 // 0x40 + gbUintP5 // 0x41 + gbUintP6 // 0x42 + gbUintP7 // 0x43 + gbUintP8 // 0x44 + gbIntM8 // 0x45 + gbIntM7 // 0x46 + gbIntM6 // 0x47 + gbIntM5 // 0x48 + gbIntM4 // 0x49 + gbIntM3 // 0x4a + gbIntM2 // 0x4b + gbIntM1 // 0x4c + gbIntP1 // 0x4d + gbIntP2 // 0x4e + gbIntP3 // 0x4f + gbIntP4 // 0x50 + gbIntP5 // 0x51 + gbIntP6 // 0x52 + gbIntP7 // 0x53 + gbIntP8 // 0x54 + gbInt0 // 0x55 + + gbIntMax = 255 - gbInt0 // 0xff == 170 +) + +// EncodeScalars encodes a vector of predeclared scalar type values to a +// []byte, making it suitable to store it as a "record" in a DB or to use it as +// a key of a BTree. +func EncodeScalars(scalars ...interface{}) (b []byte, err error) { + for _, scalar := range scalars { + switch x := scalar.(type) { + default: + return nil, &ErrINVAL{"EncodeScalars: unsupported type", fmt.Sprintf("%T in `%#v`", x, scalars)} + + case nil: + b = append(b, gbNull) + + case bool: + switch x { + case false: + b = append(b, gbFalse) + case true: + b = append(b, gbTrue) + } + + case float32: + encFloat(float64(x), &b) + case float64: + encFloat(x, &b) + + case complex64: + encComplex(complex128(x), &b) + case complex128: + encComplex(x, &b) + + case string: + n := len(x) + if n <= 17 { + b = append(b, byte(gbString00+n)) + b = append(b, []byte(x)...) + break + } + + if n > 65535 { + return nil, fmt.Errorf("EncodeScalars: cannot encode string of length %d (limit 65536)", n) + } + + pref := byte(gbString1) + if n > 255 { + pref++ + } + b = append(b, pref) + encUint0(uint64(n), &b) + b = append(b, []byte(x)...) + + case int8: + encInt(int64(x), &b) + case int16: + encInt(int64(x), &b) + case int32: + encInt(int64(x), &b) + case int64: + encInt(x, &b) + case int: + encInt(int64(x), &b) + + case uint8: + encUint(uint64(x), &b) + case uint16: + encUint(uint64(x), &b) + case uint32: + encUint(uint64(x), &b) + case uint64: + encUint(x, &b) + case uint: + encUint(uint64(x), &b) + case []byte: + n := len(x) + if n <= 17 { + b = append(b, byte(gbBytes00+n)) + b = append(b, []byte(x)...) + break + } + + if n > 655356 { + return nil, fmt.Errorf("EncodeScalars: cannot encode []byte of length %d (limit 65536)", n) + } + + pref := byte(gbBytes1) + if n > 255 { + pref++ + } + b = append(b, pref) + if n <= 255 { + b = append(b, byte(n)) + } else { + n-- + b = append(b, byte(n>>8), byte(n)) + } + b = append(b, x...) + } + } + return +} + +func encComplex(f complex128, b *[]byte) { + encFloatPrefix(gbComplex0, real(f), b) + encFloatPrefix(gbComplex0, imag(f), b) +} + +func encFloatPrefix(prefix byte, f float64, b *[]byte) { + u := math.Float64bits(f) + var n uint64 + for i := 0; i < 8; i++ { + n <<= 8 + n |= u & 0xFF + u >>= 8 + } + bits := mathutil.BitLenUint64(n) + if bits == 0 { + *b = append(*b, prefix) + return + } + + // 0 1 2 3 4 5 6 7 8 9 + // . 1 1 1 1 1 1 1 1 2 + encUintPrefix(prefix+1+byte((bits-1)>>3), n, b) +} + +func encFloat(f float64, b *[]byte) { + encFloatPrefix(gbFloat0, f, b) +} + +func encUint0(n uint64, b *[]byte) { + switch { + case n <= 0xff: + *b = append(*b, byte(n)) + case n <= 0xffff: + *b = append(*b, byte(n>>8), byte(n)) + case n <= 0xffffff: + *b = append(*b, byte(n>>16), byte(n>>8), byte(n)) + case n <= 0xffffffff: + *b = append(*b, byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) + case n <= 0xffffffffff: + *b = append(*b, byte(n>>32), byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) + case n <= 0xffffffffffff: + *b = append(*b, byte(n>>40), byte(n>>32), byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) + case n <= 0xffffffffffffff: + *b = append(*b, byte(n>>48), byte(n>>40), byte(n>>32), byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) + case n <= math.MaxUint64: + *b = append(*b, byte(n>>56), byte(n>>48), byte(n>>40), byte(n>>32), byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) + } +} + +func encUintPrefix(prefix byte, n uint64, b *[]byte) { + *b = append(*b, prefix) + encUint0(n, b) +} + +func encUint(n uint64, b *[]byte) { + bits := mathutil.Max(1, mathutil.BitLenUint64(n)) + encUintPrefix(gbUintP1+byte((bits-1)>>3), n, b) +} + +func encInt(n int64, b *[]byte) { + switch { + case n < -0x100000000000000: + *b = append(*b, byte(gbIntM8), byte(n>>56), byte(n>>48), byte(n>>40), byte(n>>32), byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) + case n < -0x1000000000000: + *b = append(*b, byte(gbIntM7), byte(n>>48), byte(n>>40), byte(n>>32), byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) + case n < -0x10000000000: + *b = append(*b, byte(gbIntM6), byte(n>>40), byte(n>>32), byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) + case n < -0x100000000: + *b = append(*b, byte(gbIntM5), byte(n>>32), byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) + case n < -0x1000000: + *b = append(*b, byte(gbIntM4), byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) + case n < -0x10000: + *b = append(*b, byte(gbIntM3), byte(n>>16), byte(n>>8), byte(n)) + case n < -0x100: + *b = append(*b, byte(gbIntM2), byte(n>>8), byte(n)) + case n < 0: + *b = append(*b, byte(gbIntM1), byte(n)) + case n <= gbIntMax: + *b = append(*b, byte(gbInt0+n)) + case n <= 0xff: + *b = append(*b, gbIntP1, byte(n)) + case n <= 0xffff: + *b = append(*b, gbIntP2, byte(n>>8), byte(n)) + case n <= 0xffffff: + *b = append(*b, gbIntP3, byte(n>>16), byte(n>>8), byte(n)) + case n <= 0xffffffff: + *b = append(*b, gbIntP4, byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) + case n <= 0xffffffffff: + *b = append(*b, gbIntP5, byte(n>>32), byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) + case n <= 0xffffffffffff: + *b = append(*b, gbIntP6, byte(n>>40), byte(n>>32), byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) + case n <= 0xffffffffffffff: + *b = append(*b, gbIntP7, byte(n>>48), byte(n>>40), byte(n>>32), byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) + case n <= 0x7fffffffffffffff: + *b = append(*b, gbIntP8, byte(n>>56), byte(n>>48), byte(n>>40), byte(n>>32), byte(n>>24), byte(n>>16), byte(n>>8), byte(n)) + } +} + +func decodeFloat(b []byte) float64 { + var u uint64 + for i, v := range b { + u |= uint64(v) << uint((i+8-len(b))*8) + } + return math.Float64frombits(u) +} + +// DecodeScalars decodes a []byte produced by EncodeScalars. +func DecodeScalars(b []byte) (scalars []interface{}, err error) { + b0 := b + for len(b) != 0 { + switch tag := b[0]; tag { + //default: + //return nil, fmt.Errorf("tag %d(%#x) not supported", b[0], b[0]) + case gbNull: + scalars = append(scalars, nil) + b = b[1:] + case gbFalse: + scalars = append(scalars, false) + b = b[1:] + case gbTrue: + scalars = append(scalars, true) + b = b[1:] + case gbFloat0: + scalars = append(scalars, 0.0) + b = b[1:] + case gbFloat1, gbFloat2, gbFloat3, gbFloat4, gbFloat5, gbFloat6, gbFloat7, gbFloat8: + n := 1 + int(tag) - gbFloat0 + if len(b) < n-1 { + goto corrupted + } + + scalars = append(scalars, decodeFloat(b[1:n])) + b = b[n:] + case gbComplex0, gbComplex1, gbComplex2, gbComplex3, gbComplex4, gbComplex5, gbComplex6, gbComplex7, gbComplex8: + n := 1 + int(tag) - gbComplex0 + if len(b) < n-1 { + goto corrupted + } + + re := decodeFloat(b[1:n]) + b = b[n:] + + if len(b) == 0 { + goto corrupted + } + + tag = b[0] + if tag < gbComplex0 || tag > gbComplex8 { + goto corrupted + } + + n = 1 + int(tag) - gbComplex0 + if len(b) < n-1 { + goto corrupted + } + + scalars = append(scalars, complex(re, decodeFloat(b[1:n]))) + b = b[n:] + case gbBytes00, gbBytes01, gbBytes02, gbBytes03, gbBytes04, + gbBytes05, gbBytes06, gbBytes07, gbBytes08, gbBytes09, + gbBytes10, gbBytes11, gbBytes12, gbBytes13, gbBytes14, + gbBytes15, gbBytes16, gbBytes17: + n := int(tag - gbBytes00) + if len(b) < n+1 { + goto corrupted + } + + scalars = append(scalars, append([]byte(nil), b[1:n+1]...)) + b = b[n+1:] + case gbBytes1: + if len(b) < 2 { + goto corrupted + } + + n := int(b[1]) + b = b[2:] + if len(b) < n { + goto corrupted + } + + scalars = append(scalars, append([]byte(nil), b[:n]...)) + b = b[n:] + case gbBytes2: + if len(b) < 3 { + goto corrupted + } + + n := int(b[1])<<8 | int(b[2]) + 1 + b = b[3:] + if len(b) < n { + goto corrupted + } + + scalars = append(scalars, append([]byte(nil), b[:n]...)) + b = b[n:] + case gbString00, gbString01, gbString02, gbString03, gbString04, + gbString05, gbString06, gbString07, gbString08, gbString09, + gbString10, gbString11, gbString12, gbString13, gbString14, + gbString15, gbString16, gbString17: + n := int(tag - gbString00) + if len(b) < n+1 { + goto corrupted + } + + scalars = append(scalars, string(b[1:n+1])) + b = b[n+1:] + case gbString1: + if len(b) < 2 { + goto corrupted + } + + n := int(b[1]) + b = b[2:] + if len(b) < n { + goto corrupted + } + + scalars = append(scalars, string(b[:n])) + b = b[n:] + case gbString2: + if len(b) < 3 { + goto corrupted + } + + n := int(b[1])<<8 | int(b[2]) + b = b[3:] + if len(b) < n { + goto corrupted + } + + scalars = append(scalars, string(b[:n])) + b = b[n:] + case gbUintP1, gbUintP2, gbUintP3, gbUintP4, gbUintP5, gbUintP6, gbUintP7, gbUintP8: + b = b[1:] + n := 1 + int(tag) - gbUintP1 + if len(b) < n { + goto corrupted + } + + var u uint64 + for _, v := range b[:n] { + u = u<<8 | uint64(v) + } + scalars = append(scalars, u) + b = b[n:] + case gbIntM8, gbIntM7, gbIntM6, gbIntM5, gbIntM4, gbIntM3, gbIntM2, gbIntM1: + b = b[1:] + n := 8 - (int(tag) - gbIntM8) + if len(b) < n { + goto corrupted + } + u := uint64(math.MaxUint64) + for _, v := range b[:n] { + u = u<<8 | uint64(v) + } + scalars = append(scalars, int64(u)) + b = b[n:] + case gbIntP1, gbIntP2, gbIntP3, gbIntP4, gbIntP5, gbIntP6, gbIntP7, gbIntP8: + b = b[1:] + n := 1 + int(tag) - gbIntP1 + if len(b) < n { + goto corrupted + } + + i := int64(0) + for _, v := range b[:n] { + i = i<<8 | int64(v) + } + scalars = append(scalars, i) + b = b[n:] + default: + scalars = append(scalars, int64(b[0])-gbInt0) + b = b[1:] + } + } + return append([]interface{}(nil), scalars...), nil + +corrupted: + return nil, &ErrDecodeScalars{append([]byte(nil), b0...), len(b0) - len(b)} +} + +func collateComplex(x, y complex128) int { + switch rx, ry := real(x), real(y); { + case rx < ry: + return -1 + case rx == ry: + switch ix, iy := imag(x), imag(y); { + case ix < iy: + return -1 + case ix == iy: + return 0 + case ix > iy: + return 1 + } + } + //case rx > ry: + return 1 +} + +func collateFloat(x, y float64) int { + switch { + case x < y: + return -1 + case x == y: + return 0 + } + //case x > y: + return 1 +} + +func collateInt(x, y int64) int { + switch { + case x < y: + return -1 + case x == y: + return 0 + } + //case x > y: + return 1 +} + +func collateUint(x, y uint64) int { + switch { + case x < y: + return -1 + case x == y: + return 0 + } + //case x > y: + return 1 +} + +func collateIntUint(x int64, y uint64) int { + if y > math.MaxInt64 { + return -1 + } + + return collateInt(x, int64(y)) +} + +func collateUintInt(x uint64, y int64) int { + return -collateIntUint(y, x) +} + +func collateType(i interface{}) (r interface{}, err error) { + switch x := i.(type) { + default: + return nil, fmt.Errorf("invalid collate type %T", x) + case nil: + return i, nil + case bool: + return i, nil + case int8: + return int64(x), nil + case int16: + return int64(x), nil + case int32: + return int64(x), nil + case int64: + return i, nil + case int: + return int64(x), nil + case uint8: + return uint64(x), nil + case uint16: + return uint64(x), nil + case uint32: + return uint64(x), nil + case uint64: + return i, nil + case uint: + return uint64(x), nil + case float32: + return float64(x), nil + case float64: + return i, nil + case complex64: + return complex128(x), nil + case complex128: + return i, nil + case []byte: + return i, nil + case string: + return i, nil + } +} + +// Collate collates two arrays of Go predeclared scalar types (and the typeless +// nil or []byte). If any other type appears in x or y, Collate will return a +// non nil error. String items are collated using strCollate or lexically +// byte-wise (as when using Go comparison operators) when strCollate is nil. +// []byte items are collated using bytes.Compare. +// +// Collate returns: +// +// -1 if x < y +// 0 if x == y +// +1 if x > y +// +// The same value as defined above must be returned from strCollate. +// +// The "outer" ordering is: nil, bool, number, []byte, string. IOW, nil is +// "smaller" than anything else except other nil, numbers collate before +// []byte, []byte collate before strings, etc. +// +// Integers and real numbers collate as expected in math. However, complex +// numbers are not ordered in Go. Here the ordering is defined: Complex numbers +// are in comparison considered first only by their real part. Iff the result +// is equality then the imaginary part is used to determine the ordering. In +// this "second order" comparing, integers and real numbers are considered as +// complex numbers with a zero imaginary part. +func Collate(x, y []interface{}, strCollate func(string, string) int) (r int, err error) { + nx, ny := len(x), len(y) + + switch { + case nx == 0 && ny != 0: + return -1, nil + case nx == 0 && ny == 0: + return 0, nil + case nx != 0 && ny == 0: + return 1, nil + } + + r = 1 + if nx > ny { + x, y, r = y, x, -r + } + + var c int + for i, xi0 := range x { + yi0 := y[i] + xi, err := collateType(xi0) + if err != nil { + return 0, err + } + + yi, err := collateType(yi0) + if err != nil { + return 0, err + } + + switch x := xi.(type) { + default: + panic(fmt.Errorf("internal error: %T", x)) + + case nil: + switch yi.(type) { + case nil: + // nop + default: + return -r, nil + } + + case bool: + switch y := yi.(type) { + case nil: + return r, nil + case bool: + switch { + case !x && y: + return -r, nil + case x == y: + // nop + case x && !y: + return r, nil + } + default: + return -r, nil + } + + case int64: + switch y := yi.(type) { + case nil, bool: + return r, nil + case int64: + c = collateInt(x, y) + case uint64: + c = collateIntUint(x, y) + case float64: + c = collateFloat(float64(x), y) + case complex128: + c = collateComplex(complex(float64(x), 0), y) + case []byte: + return -r, nil + case string: + return -r, nil + } + + if c != 0 { + return c * r, nil + } + + case uint64: + switch y := yi.(type) { + case nil, bool: + return r, nil + case int64: + c = collateUintInt(x, y) + case uint64: + c = collateUint(x, y) + case float64: + c = collateFloat(float64(x), y) + case complex128: + c = collateComplex(complex(float64(x), 0), y) + case []byte: + return -r, nil + case string: + return -r, nil + } + + if c != 0 { + return c * r, nil + } + + case float64: + switch y := yi.(type) { + case nil, bool: + return r, nil + case int64: + c = collateFloat(x, float64(y)) + case uint64: + c = collateFloat(x, float64(y)) + case float64: + c = collateFloat(x, y) + case complex128: + c = collateComplex(complex(x, 0), y) + case []byte: + return -r, nil + case string: + return -r, nil + } + + if c != 0 { + return c * r, nil + } + + case complex128: + switch y := yi.(type) { + case nil, bool: + return r, nil + case int64: + c = collateComplex(x, complex(float64(y), 0)) + case uint64: + c = collateComplex(x, complex(float64(y), 0)) + case float64: + c = collateComplex(x, complex(y, 0)) + case complex128: + c = collateComplex(x, y) + case []byte: + return -r, nil + case string: + return -r, nil + } + + if c != 0 { + return c * r, nil + } + + case []byte: + switch y := yi.(type) { + case nil, bool, int64, uint64, float64, complex128: + return r, nil + case []byte: + c = bytes.Compare(x, y) + case string: + return -r, nil + } + + if c != 0 { + return c * r, nil + } + + case string: + switch y := yi.(type) { + case nil, bool, int64, uint64, float64, complex128: + return r, nil + case []byte: + return r, nil + case string: + switch { + case strCollate != nil: + c = strCollate(x, y) + case x < y: + return -r, nil + case x == y: + c = 0 + case x > y: + return r, nil + } + } + + if c != 0 { + return c * r, nil + } + } + } + + if nx == ny { + return 0, nil + } + + return -r, nil +} diff --git a/Godeps/_workspace/src/github.com/cznic/exp/lldb/gb_test.go b/Godeps/_workspace/src/github.com/cznic/exp/lldb/gb_test.go new file mode 100644 index 0000000..a9923ca --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/exp/lldb/gb_test.go @@ -0,0 +1,364 @@ +// Copyright 2014 The lldb Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Utilities to encode/decode and collate Go predeclared scalar types. The +// encoding format reused the one used by the "encoding/gob" package. + +package lldb + +import ( + "bytes" + "math" + "testing" +) + +const s256 = "" + + "0123456789abcdef" + + "0123456789abcdef" + + "0123456789abcdef" + + "0123456789abcdef" + + "0123456789abcdef" + + "0123456789abcdef" + + "0123456789abcdef" + + "0123456789abcdef" + + "0123456789abcdef" + + "0123456789abcdef" + + "0123456789abcdef" + + "0123456789abcdef" + + "0123456789abcdef" + + "0123456789abcdef" + + "0123456789abcdef" + + "0123456789abcdef" + +func TestEncodeDecodeScalars(t *testing.T) { + table := []struct{ v, exp interface{} }{ + {nil, "00"}, + {false, "01"}, + {true, "02"}, + {math.Float64frombits(0), []byte{gbFloat0}}, + {17., []byte{gbFloat2, 0x31, 0x40}}, + {math.Float64frombits(0x4031320000000000), []byte{gbFloat3, 0x32, 0x31, 0x40}}, + {math.Float64frombits(0x4031323300000000), []byte{gbFloat4, 0x33, 0x32, 0x31, 0x40}}, + {math.Float64frombits(0x4031323334000000), []byte{gbFloat5, 0x34, 0x33, 0x32, 0x31, 0x40}}, + {math.Float64frombits(0x4031323334350000), []byte{gbFloat6, 0x35, 0x34, 0x33, 0x32, 0x31, 0x40}}, + {math.Float64frombits(0x4031323334353600), []byte{gbFloat7, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x40}}, + {math.Float64frombits(0x4031323334353637), []byte{gbFloat8, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x40}}, + {0 + 0i, []byte{gbComplex0, gbComplex0}}, + {17 + 17i, []byte{gbComplex2, 0x31, 0x40, gbComplex2, 0x31, 0x40}}, + {complex(math.Float64frombits(0x4041420000000000), math.Float64frombits(0x4031320000000000)), []byte{gbComplex3, 0x42, 0x41, 0x40, gbComplex3, 0x32, 0x31, 0x40}}, + {complex(math.Float64frombits(0x4041424300000000), math.Float64frombits(0x4031323300000000)), []byte{gbComplex4, 0x43, 0x42, 0x41, 0x40, gbComplex4, 0x33, 0x32, 0x31, 0x40}}, + {complex(math.Float64frombits(0x4041424344000000), math.Float64frombits(0x4031323334000000)), []byte{gbComplex5, 0x44, 0x43, 0x42, 0x41, 0x40, gbComplex5, 0x34, 0x33, 0x32, 0x31, 0x40}}, + {complex(math.Float64frombits(0x4041424344450000), math.Float64frombits(0x4031323334350000)), []byte{gbComplex6, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, gbComplex6, 0x35, 0x34, 0x33, 0x32, 0x31, 0x40}}, + {complex(math.Float64frombits(0x4041424344454600), math.Float64frombits(0x4031323334353600)), []byte{gbComplex7, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, gbComplex7, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x40}}, + {complex(math.Float64frombits(0x4041424344454647), math.Float64frombits(0x4031323334353637)), []byte{gbComplex8, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, gbComplex8, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x40}}, + {[]byte(""), []byte{gbBytes00}}, + {[]byte("f"), []byte{gbBytes01, 'f'}}, + {[]byte("fo"), []byte{gbBytes02, 'f', 'o'}}, + {[]byte("0123456789abcdefx"), []byte{gbBytes17, '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'x'}}, + {[]byte("0123456789abcdefxy"), []byte{gbBytes1, 18, '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'x', 'y'}}, + {[]byte(s256[:255]), append([]byte{gbBytes1, 0xff}, []byte(s256[:255])...)}, + {[]byte(s256), append([]byte{gbBytes2, 0x00, 0xff}, []byte(s256)...)}, + {"", []byte{gbString00}}, + {"f", []byte{gbString01, 'f'}}, + {"fo", []byte{gbString02, 'f', 'o'}}, + {"0123456789abcdefx", []byte{gbString17, '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'x'}}, + {"0123456789abcdefxy", []byte{gbString1, 18, '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'x', 'y'}}, + {s256[:255], append([]byte{gbString1, 0xff}, []byte(s256[:255])...)}, + {s256, append([]byte{gbString2, 0x01, 0x00}, []byte(s256)...)}, + {uint64(0xff), []byte{gbUintP1, 255}}, + {uint64(0xffff), []byte{gbUintP2, 255, 255}}, + {uint64(0xffffff), []byte{gbUintP3, 255, 255, 255}}, + {uint64(0xffffffff), []byte{gbUintP4, 255, 255, 255, 255}}, + {uint64(0xffffffffff), []byte{gbUintP5, 255, 255, 255, 255, 255}}, + {uint64(0xffffffffffff), []byte{gbUintP6, 255, 255, 255, 255, 255, 255}}, + {uint64(0xffffffffffffff), []byte{gbUintP7, 255, 255, 255, 255, 255, 255, 255}}, + {uint64(0xffffffffffffffff), []byte{gbUintP8, 255, 255, 255, 255, 255, 255, 255, 255}}, + {int64(math.MinInt64), []byte{gbIntM8, 128, 0, 0, 0, 0, 0, 0, 0}}, + {-int64(0x100000000000000), []byte{gbIntM7, 0, 0, 0, 0, 0, 0, 0}}, + {-int64(0x1000000000000), []byte{gbIntM6, 0, 0, 0, 0, 0, 0}}, + {-int64(0x10000000000), []byte{gbIntM5, 0, 0, 0, 0, 0}}, + {-int64(0x100000000), []byte{gbIntM4, 0, 0, 0, 0}}, + {-int64(0x1000000), []byte{gbIntM3, 0, 0, 0}}, + {-int64(0x10000), []byte{gbIntM2, 0, 0}}, + {-int64(0x100), []byte{gbIntM1, 0}}, + {-int64(0xff), []byte{gbIntM1, 1}}, + {-int64(1), []byte{gbIntM1, 255}}, + {int64(gbIntMax + 1), []byte{gbIntP1, gbIntMax + 1}}, + {int64(0xff), []byte{gbIntP1, 255}}, + {int64(0xffff), []byte{gbIntP2, 255, 255}}, + {int64(0xffffff), []byte{gbIntP3, 255, 255, 255}}, + {int64(0xffffffff), []byte{gbIntP4, 255, 255, 255, 255}}, + {int64(0xffffffffff), []byte{gbIntP5, 255, 255, 255, 255, 255}}, + {int64(0xffffffffffff), []byte{gbIntP6, 255, 255, 255, 255, 255, 255}}, + {int64(0xffffffffffffff), []byte{gbIntP7, 255, 255, 255, 255, 255, 255, 255}}, + {int64(0x7fffffffffffffff), []byte{gbIntP8, 127, 255, 255, 255, 255, 255, 255, 255}}, + {int64(0), []byte{0 + gbInt0}}, + {int64(1), []byte{1 + gbInt0}}, + {int64(2), []byte{2 + gbInt0}}, + {int64(gbIntMax - 2), "fd"}, + {int64(gbIntMax - 1), "fe"}, + {int64(gbIntMax), "ff"}, + } + + for i, v := range table { + g, err := EncodeScalars(v.v) + if err != nil { + t.Fatal(i, err) + } + + var e []byte + switch x := v.exp.(type) { + case string: + e = s2b(x) + case []byte: + e = x + } + + if !bytes.Equal(g, e) { + t.Fatalf("%d %v\n|% 02x|\n|% 02x|", i, v.v, g, e) + } + + t.Logf("%#v |% 02x|", v.v, g) + + dec, err := DecodeScalars(g) + if err != nil { + t.Fatal(err) + } + + if g, e := len(dec), 1; g != e { + t.Fatalf("%d %d %#v", g, e, dec) + } + + if g, ok := dec[0].([]byte); ok { + if e := v.v.([]byte); !bytes.Equal(g, e) { + t.Fatal(g, e) + } + + continue + } + + if g, e := dec[0], v.v; g != e { + t.Fatal(g, e) + } + } +} + +func strcmp(a, b string) (r int) { + if a < b { + return -1 + } + + if a == b { + return 0 + } + + return 1 +} + +func TestCollateScalars(t *testing.T) { + // all cases must return -1 + table := []struct{ x, y []interface{} }{ + {[]interface{}{}, []interface{}{1}}, + {[]interface{}{1}, []interface{}{2}}, + {[]interface{}{1, 2}, []interface{}{2, 3}}, + + {[]interface{}{nil}, []interface{}{nil, true}}, + {[]interface{}{nil}, []interface{}{false}}, + {[]interface{}{nil}, []interface{}{nil, 1}}, + {[]interface{}{nil}, []interface{}{1}}, + {[]interface{}{nil}, []interface{}{nil, uint(1)}}, + {[]interface{}{nil}, []interface{}{uint(1)}}, + {[]interface{}{nil}, []interface{}{nil, 3.14}}, + {[]interface{}{nil}, []interface{}{3.14}}, + {[]interface{}{nil}, []interface{}{nil, 3.14 + 1i}}, + {[]interface{}{nil}, []interface{}{3.14 + 1i}}, + {[]interface{}{nil}, []interface{}{nil, []byte("foo")}}, + {[]interface{}{nil}, []interface{}{[]byte("foo")}}, + {[]interface{}{nil}, []interface{}{nil, "foo"}}, + {[]interface{}{nil}, []interface{}{"foo"}}, + + {[]interface{}{false}, []interface{}{false, false}}, + {[]interface{}{false}, []interface{}{false, true}}, + {[]interface{}{false}, []interface{}{true}}, + {[]interface{}{false}, []interface{}{false, 1}}, + {[]interface{}{false}, []interface{}{1}}, + {[]interface{}{false}, []interface{}{false, uint(1)}}, + {[]interface{}{false}, []interface{}{uint(1)}}, + {[]interface{}{false}, []interface{}{false, 1.5}}, + {[]interface{}{false}, []interface{}{1.5}}, + {[]interface{}{false}, []interface{}{false, 1.5 + 3i}}, + {[]interface{}{false}, []interface{}{1.5 + 3i}}, + {[]interface{}{false}, []interface{}{false, []byte("foo")}}, + {[]interface{}{false}, []interface{}{[]byte("foo")}}, + {[]interface{}{false}, []interface{}{false, "foo"}}, + {[]interface{}{false}, []interface{}{"foo"}}, + + {[]interface{}{1}, []interface{}{1, 2}}, + {[]interface{}{1}, []interface{}{1, 1}}, + {[]interface{}{1}, []interface{}{1, uint(2)}}, + {[]interface{}{1}, []interface{}{uint(2)}}, + {[]interface{}{1}, []interface{}{1, 1.1}}, + {[]interface{}{1}, []interface{}{1.1}}, + {[]interface{}{1}, []interface{}{1, 1.1 + 2i}}, + {[]interface{}{1}, []interface{}{1.1 + 2i}}, + {[]interface{}{1}, []interface{}{1, []byte("foo")}}, + {[]interface{}{1}, []interface{}{[]byte("foo")}}, + {[]interface{}{1}, []interface{}{1, "foo"}}, + {[]interface{}{1}, []interface{}{"foo"}}, + + {[]interface{}{uint(1)}, []interface{}{uint(1), uint(1)}}, + {[]interface{}{uint(1)}, []interface{}{uint(2)}}, + {[]interface{}{uint(1)}, []interface{}{uint(1), 2.}}, + {[]interface{}{uint(1)}, []interface{}{2.}}, + {[]interface{}{uint(1)}, []interface{}{uint(1), 2. + 0i}}, + {[]interface{}{uint(1)}, []interface{}{2. + 0i}}, + {[]interface{}{uint(1)}, []interface{}{uint(1), []byte("foo")}}, + {[]interface{}{uint(1)}, []interface{}{[]byte("foo")}}, + {[]interface{}{uint(1)}, []interface{}{uint(1), "foo"}}, + {[]interface{}{uint(1)}, []interface{}{"foo"}}, + + {[]interface{}{1.}, []interface{}{1., 1}}, + {[]interface{}{1.}, []interface{}{2}}, + {[]interface{}{1.}, []interface{}{1., uint(1)}}, + {[]interface{}{1.}, []interface{}{uint(2)}}, + {[]interface{}{1.}, []interface{}{1., 1.}}, + {[]interface{}{1.}, []interface{}{1.1}}, + {[]interface{}{1.}, []interface{}{1., []byte("foo")}}, + {[]interface{}{1.}, []interface{}{[]byte("foo")}}, + {[]interface{}{1.}, []interface{}{1., "foo"}}, + {[]interface{}{1.}, []interface{}{"foo"}}, + + {[]interface{}{1 + 2i}, []interface{}{1 + 2i, 1}}, + {[]interface{}{1 + 2i}, []interface{}{2}}, + {[]interface{}{1 + 2i}, []interface{}{1 + 2i, uint(1)}}, + {[]interface{}{1 + 2i}, []interface{}{uint(2)}}, + {[]interface{}{1 + 2i}, []interface{}{1 + 2i, 1.1}}, + {[]interface{}{1 + 2i}, []interface{}{1.1}}, + {[]interface{}{1 + 2i}, []interface{}{1 + 2i, []byte("foo")}}, + {[]interface{}{1 + 2i}, []interface{}{[]byte("foo")}}, + {[]interface{}{1 + 2i}, []interface{}{1 + 2i, "foo"}}, + {[]interface{}{1 + 2i}, []interface{}{"foo"}}, + + {[]interface{}{[]byte("bar")}, []interface{}{[]byte("bar"), []byte("bar")}}, + {[]interface{}{[]byte("bar")}, []interface{}{[]byte("foo")}}, + {[]interface{}{[]byte("bar")}, []interface{}{[]byte("c")}}, + {[]interface{}{[]byte("bar")}, []interface{}{[]byte("bas")}}, + {[]interface{}{[]byte("bar")}, []interface{}{[]byte("bara")}}, + + {[]interface{}{[]byte("bar")}, []interface{}{"bap"}}, + {[]interface{}{[]byte("bar")}, []interface{}{"bar"}}, + {[]interface{}{[]byte("bar")}, []interface{}{"bas"}}, + + {[]interface{}{"bar"}, []interface{}{"bar", "bar"}}, + {[]interface{}{"bar"}, []interface{}{"foo"}}, + {[]interface{}{"bar"}, []interface{}{"c"}}, + {[]interface{}{"bar"}, []interface{}{"bas"}}, + {[]interface{}{"bar"}, []interface{}{"bara"}}, + + {[]interface{}{1 + 2i}, []interface{}{1 + 3i}}, + {[]interface{}{int64(math.MaxInt64)}, []interface{}{uint64(math.MaxInt64 + 1)}}, + {[]interface{}{int8(1)}, []interface{}{int16(2)}}, + {[]interface{}{int32(1)}, []interface{}{uint8(2)}}, + {[]interface{}{uint16(1)}, []interface{}{uint32(2)}}, + {[]interface{}{float32(1)}, []interface{}{complex(float32(2), 0)}}, + + // resolved bugs + {[]interface{}{"Customer"}, []interface{}{"Date"}}, + {[]interface{}{"Customer"}, []interface{}{"Items", 1, "Quantity"}}, + } + + more := []interface{}{42, nil, 1, uint(2), 3.0, 4 + 5i, "..."} + + collate := func(x, y []interface{}, strCollate func(string, string) int) (r int) { + var err error + r, err = Collate(x, y, strCollate) + if err != nil { + t.Fatal(err) + } + + return + } + + for _, scf := range []func(string, string) int{nil, strcmp} { + for _, prefix := range more { + for i, test := range table { + var x, y []interface{} + if prefix != 42 { + x = append(x, prefix) + y = append(y, prefix) + } + x = append(x, test.x...) + y = append(y, test.y...) + + // cmp(x, y) == -1 + if g, e := collate(x, y, scf), -1; g != e { + t.Fatal(i, g, e, x, y) + } + + // cmp(y, x) == 1 + if g, e := collate(y, x, scf), 1; g != e { + t.Fatal(i, g, e, y, x) + } + + src := x + for ix := len(src) - 1; ix > 0; ix-- { + if g, e := collate(src[:ix], src[:ix], scf), 0; g != e { + t.Fatal(ix, g, e) + } + + if g, e := collate(src[:ix], src, scf), -1; g != e { + t.Fatal(ix, g, e) + } + + } + + src = y + for ix := len(src) - 1; ix > 0; ix-- { + if g, e := collate(src[:ix], src[:ix], scf), 0; g != e { + t.Fatal(ix, g, e) + } + + if g, e := collate(src[:ix], src, scf), -1; g != e { + t.Fatal(ix, g, e) + } + + } + } + } + } +} + +func TestEncodingBug(t *testing.T) { + bits := uint64(0) + for i := 0; i <= 64; i++ { + encoded, err := EncodeScalars(math.Float64frombits(bits)) + if err != nil { + t.Fatal(err) + } + + t.Logf("bits %016x, enc |% x|", bits, encoded) + decoded, err := DecodeScalars(encoded) + if err != nil { + t.Fatal(err) + } + + if g, e := len(decoded), 1; g != e { + t.Fatal(g, e) + } + + f, ok := decoded[0].(float64) + if !ok { + t.Fatal(err) + } + + if g, e := math.Float64bits(f), bits; g != e { + t.Fatal(err) + } + + t.Log(f) + + bits >>= 1 + bits |= 1 << 63 + } +} diff --git a/Godeps/_workspace/src/github.com/cznic/exp/lldb/lldb.go b/Godeps/_workspace/src/github.com/cznic/exp/lldb/lldb.go new file mode 100644 index 0000000..8f77ec8 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/exp/lldb/lldb.go @@ -0,0 +1,155 @@ +// Copyright 2014 The lldb 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 lldb (WIP) implements a low level database engine. The database +// model used could be considered a specific implementation of some small(est) +// intersection of models listed in [1]. As a settled term is lacking, it'll be +// called here a 'Virtual memory model' (VMM). +// +// Experimental release notes +// +// This is an experimental release. Don't open a DB from two applications or +// two instances of an application - it will get corrupted (no file locking is +// implemented and this task is delegated to lldb's clients). +// +// WARNING: THE LLDB API IS SUBJECT TO CHANGE. +// +// Filers +// +// A Filer is an abstraction of storage. A Filer may be a part of some process' +// virtual address space, an OS file, a networked, remote file etc. Persistence +// of the storage is optional, opaque to VMM and it is specific to a concrete +// Filer implementation. +// +// Space management +// +// Mechanism to allocate, reallocate (resize), deallocate (and later reclaim +// the unused) contiguous parts of a Filer, called blocks. Blocks are +// identified and referred to by a handle, an int64. +// +// BTrees +// +// In addition to the VMM like services, lldb provides volatile and +// non-volatile BTrees. Keys and values of a BTree are limited in size to 64kB +// each (a bit more actually). Support for larger keys/values, if desired, can +// be built atop a BTree to certain limits. +// +// Handles vs pointers +// +// A handle is the abstracted storage counterpart of a memory address. There +// is one fundamental difference, though. Resizing a block never results in a +// change to the handle which refers to the resized block, so a handle is more +// akin to an unique numeric id/key. Yet it shares one property of pointers - +// handles can be associated again with blocks after the original handle block +// was deallocated. In other words, a handle uniqueness domain is the state of +// the database and is not something comparable to e.g. an ever growing +// numbering sequence. +// +// Also, as with memory pointers, dangling handles can be created and blocks +// overwritten when such handles are used. Using a zero handle to refer to a +// block will not panic; however, the resulting error is effectively the same +// exceptional situation as dereferencing a nil pointer. +// +// Blocks +// +// Allocated/used blocks, are limited in size to only a little bit more than +// 64kB. Bigger semantic entities/structures must be built in lldb's client +// code. The content of a block has no semantics attached, it's only a fully +// opaque `[]byte`. +// +// Scalars +// +// Use of "scalars" applies to EncodeScalars, DecodeScalars and Collate. Those +// first two "to bytes" and "from bytes" functions are suggested for handling +// multi-valued Allocator content items and/or keys/values of BTrees (using +// Collate for keys). Types called "scalar" are: +// +// nil (the typeless one) +// bool +// all integral types: [u]int8, [u]int16, [u]int32, [u]int, [u]int64 +// all floating point types: float32, float64 +// all complex types: complex64, complex128 +// []byte (64kB max) +// string (64kb max) +// +// Specific implementations +// +// Included are concrete implementations of some of the VMM interfaces included +// to ease serving simple client code or for testing and possibly as an +// example. More details in the documentation of such implementations. +// +// [1]: http://en.wikipedia.org/wiki/Database_model +package lldb + +const ( + fltSz = 0x70 // size of the FLT + maxShort = 251 + maxRq = 65787 + maxFLTRq = 4112 + maxHandle = 1<<56 - 1 + atomLen = 16 + tagUsedLong = 0xfc + tagUsedRelocated = 0xfd + tagFreeShort = 0xfe + tagFreeLong = 0xff + tagNotCompressed = 0 + tagCompressed = 1 +) + +// Content size n -> blocksize in atoms. +func n2atoms(n int) int { + if n > maxShort { + n += 2 + } + return (n+1)/16 + 1 +} + +// Content size n -> number of padding zeros. +func n2padding(n int) int { + if n > maxShort { + n += 2 + } + return 15 - (n+1)&15 +} + +// Handle <-> offset +func h2off(h int64) int64 { return (h + 6) * 16 } +func off2h(off int64) int64 { return off/16 - 6 } + +// Get a 7B int64 from b +func b2h(b []byte) (h int64) { + for _, v := range b[:7] { + h = h<<8 | int64(v) + } + return +} + +// Put a 7B int64 into b +func h2b(b []byte, h int64) []byte { + for i := range b[:7] { + b[i], h = byte(h>>48), h<<8 + } + return b +} + +// Content length N (must be in [252, 65787]) to long used block M field. +func n2m(n int) (m int) { + return n % 0x10000 +} + +// Long used block M (must be in [0, 65535]) field to content length N. +func m2n(m int) (n int) { + if m <= maxShort { + m += 0x10000 + } + return m +} + +func bpack(a []byte) []byte { + if cap(a) > len(a) { + return append([]byte(nil), a...) + } + + return a +} diff --git a/Godeps/_workspace/src/github.com/cznic/exp/lldb/lldb_test.go b/Godeps/_workspace/src/github.com/cznic/exp/lldb/lldb_test.go new file mode 100644 index 0000000..408125a --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/exp/lldb/lldb_test.go @@ -0,0 +1,217 @@ +// Copyright 2014 The lldb 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 lldb + +import ( + "bytes" + "encoding/hex" + "fmt" + "path" + "runtime" + "strings" + "testing" +) + +var dbg = func(s string, va ...interface{}) { + _, fn, fl, _ := runtime.Caller(1) + fmt.Printf("%s:%d: ", path.Base(fn), fl) + fmt.Printf(s+"\n", va...) +} + +func use(...interface{}) {} + +func TestN2Atoms(t *testing.T) { + tab := []struct{ n, a int }{ + {0, 1}, + {1, 1}, + {2, 1}, + {3, 1}, + {4, 1}, + {5, 1}, + {6, 1}, + {7, 1}, + {8, 1}, + {9, 1}, + {10, 1}, + {11, 1}, + {12, 1}, + {13, 1}, + {14, 1}, + + {15, 2}, + {16, 2}, + {17, 2}, + {18, 2}, + {19, 2}, + {20, 2}, + {21, 2}, + {22, 2}, + {23, 2}, + {24, 2}, + {25, 2}, + {26, 2}, + {27, 2}, + {28, 2}, + {29, 2}, + {30, 2}, + + {31, 3}, + + {252, 16}, + {253, 17}, + {254, 17}, + {255, 17}, + {256, 17}, + {257, 17}, + {258, 17}, + {259, 17}, + {260, 17}, + {261, 17}, + {262, 17}, + {263, 17}, + {264, 17}, + {265, 17}, + {266, 17}, + {267, 17}, + {268, 17}, + {269, 18}, + {65532, 4096}, + {65533, 4097}, + {65787, 4112}, + } + + for i, test := range tab { + if g, e := n2atoms(test.n), test.a; g != e { + t.Errorf("(%d) %d %d %d", i, test.n, g, e) + } + } +} + +func TestN2Padding(t *testing.T) { + tab := []struct{ n, p int }{ + {0, 14}, + {1, 13}, + {2, 12}, + {3, 11}, + {4, 10}, + {5, 9}, + {6, 8}, + {7, 7}, + {8, 6}, + {9, 5}, + {10, 4}, + {11, 3}, + {12, 2}, + {13, 1}, + {14, 0}, + + {15, 15}, + {16, 14}, + {17, 13}, + {18, 12}, + {19, 11}, + {20, 10}, + {21, 9}, + {22, 8}, + {23, 7}, + {24, 6}, + {25, 5}, + {26, 4}, + {27, 3}, + {28, 2}, + {29, 1}, + {30, 0}, + + {31, 15}, + + {252, 0}, + {253, 15}, + {254, 14}, + {255, 13}, + {256, 12}, + {257, 11}, + {258, 10}, + {259, 9}, + {260, 8}, + {261, 7}, + {262, 6}, + {263, 5}, + {264, 4}, + {265, 3}, + {266, 2}, + {267, 1}, + {268, 0}, + {269, 15}, + } + + for i, test := range tab { + if g, e := n2padding(test.n), test.p; g != e { + t.Errorf("(%d) %d %d %d", i, test.n, g, e) + } + } +} + +func TestH2Off(t *testing.T) { + tab := []struct{ h, off int64 }{ + {-1, fltSz - 32}, + {0, fltSz - 16}, + {1, fltSz + 0}, + {2, fltSz + 16}, + {3, fltSz + 32}, + } + + for i, test := range tab { + if g, e := h2off(test.h), test.off; g != e { + t.Error("h2off", i, g, e) + } + if g, e := off2h(test.off), test.h; g != e { + t.Error("off2h", i, g, e) + } + } +} + +func TestB2H(t *testing.T) { + tab := []struct { + b []byte + h int64 + }{ + {[]byte{0, 0, 0, 0, 0, 0, 0}, 0}, + {[]byte{0, 0, 0, 0, 0, 0, 1}, 1}, + {[]byte{0, 0, 0, 0, 0, 0, 1, 2}, 1}, + {[]byte{0, 0, 0, 0, 0, 0x32, 0x10}, 0x3210}, + {[]byte{0, 0, 0, 0, 0x54, 0x32, 0x10}, 0x543210}, + {[]byte{0, 0, 0, 0x76, 0x54, 0x32, 0x10}, 0x76543210}, + {[]byte{0, 0, 0x98, 0x76, 0x54, 0x32, 0x10}, 0x9876543210}, + {[]byte{0, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10}, 0xba9876543210}, + {[]byte{0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10}, 0xdcba9876543210}, + } + + for i, test := range tab { + if g, e := b2h(test.b), test.h; g != e { + t.Errorf("b2h: %d %#8x %#8x", i, g, e) + } + var g [7]byte + h2b(g[:], test.h) + if e := test.b; !bytes.Equal(g[:], e[:7]) { + t.Errorf("b2h: %d g: % 0x e: % 0x", i, g, e) + } + } +} + +func s2b(s string) []byte { + if s == "" { + return nil + } + + s = strings.Replace(s, " ", "", -1) + if n := len(s) & 1; n != 0 { + panic(n) + } + b, err := hex.DecodeString(s) + if err != nil { + panic(err) + } + return b +} diff --git a/Godeps/_workspace/src/github.com/cznic/exp/lldb/memfiler.go b/Godeps/_workspace/src/github.com/cznic/exp/lldb/memfiler.go new file mode 100644 index 0000000..4b2e220 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/exp/lldb/memfiler.go @@ -0,0 +1,344 @@ +// Copyright 2014 The lldb Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// A memory-only implementation of Filer. + +/* + +pgBits: 8 +BenchmarkMemFilerWrSeq 100000 19430 ns/op 1646.93 MB/s +BenchmarkMemFilerRdSeq 100000 17390 ns/op 1840.13 MB/s +BenchmarkMemFilerWrRand 1000000 1903 ns/op 133.94 MB/s +BenchmarkMemFilerRdRand 1000000 1153 ns/op 221.16 MB/s + +pgBits: 9 +BenchmarkMemFilerWrSeq 100000 16195 ns/op 1975.80 MB/s +BenchmarkMemFilerRdSeq 200000 13011 ns/op 2459.39 MB/s +BenchmarkMemFilerWrRand 1000000 2248 ns/op 227.28 MB/s +BenchmarkMemFilerRdRand 1000000 1177 ns/op 433.94 MB/s + +pgBits: 10 +BenchmarkMemFilerWrSeq 100000 16169 ns/op 1979.04 MB/s +BenchmarkMemFilerRdSeq 200000 12673 ns/op 2524.91 MB/s +BenchmarkMemFilerWrRand 1000000 5550 ns/op 184.30 MB/s +BenchmarkMemFilerRdRand 1000000 1699 ns/op 601.79 MB/s + +pgBits: 11 +BenchmarkMemFilerWrSeq 100000 13449 ns/op 2379.31 MB/s +BenchmarkMemFilerRdSeq 200000 12058 ns/op 2653.80 MB/s +BenchmarkMemFilerWrRand 500000 4335 ns/op 471.47 MB/s +BenchmarkMemFilerRdRand 1000000 2843 ns/op 719.47 MB/s + +pgBits: 12 +BenchmarkMemFilerWrSeq 200000 11976 ns/op 2672.00 MB/s +BenchmarkMemFilerRdSeq 200000 12255 ns/op 2611.06 MB/s +BenchmarkMemFilerWrRand 200000 8058 ns/op 507.14 MB/s +BenchmarkMemFilerRdRand 500000 4365 ns/op 936.15 MB/s + +pgBits: 13 +BenchmarkMemFilerWrSeq 200000 10852 ns/op 2948.69 MB/s +BenchmarkMemFilerRdSeq 200000 11561 ns/op 2767.77 MB/s +BenchmarkMemFilerWrRand 200000 9748 ns/op 840.15 MB/s +BenchmarkMemFilerRdRand 500000 7236 ns/op 1131.59 MB/s + +pgBits: 14 +BenchmarkMemFilerWrSeq 200000 10328 ns/op 3098.12 MB/s +BenchmarkMemFilerRdSeq 200000 11292 ns/op 2833.66 MB/s +BenchmarkMemFilerWrRand 100000 16768 ns/op 978.75 MB/s +BenchmarkMemFilerRdRand 200000 13033 ns/op 1258.43 MB/s + +pgBits: 15 +BenchmarkMemFilerWrSeq 200000 10309 ns/op 3103.93 MB/s +BenchmarkMemFilerRdSeq 200000 11126 ns/op 2876.12 MB/s +BenchmarkMemFilerWrRand 50000 31985 ns/op 1021.74 MB/s +BenchmarkMemFilerRdRand 100000 25217 ns/op 1297.65 MB/s + +pgBits: 16 +BenchmarkMemFilerWrSeq 200000 10324 ns/op 3099.45 MB/s +BenchmarkMemFilerRdSeq 200000 11201 ns/op 2856.80 MB/s +BenchmarkMemFilerWrRand 20000 55226 ns/op 1184.76 MB/s +BenchmarkMemFilerRdRand 50000 48316 ns/op 1355.16 MB/s + +pgBits: 17 +BenchmarkMemFilerWrSeq 200000 10377 ns/op 3083.53 MB/s +BenchmarkMemFilerRdSeq 200000 11018 ns/op 2904.18 MB/s +BenchmarkMemFilerWrRand 10000 143425 ns/op 913.12 MB/s +BenchmarkMemFilerRdRand 20000 95267 ns/op 1376.99 MB/s + +pgBits: 18 +BenchmarkMemFilerWrSeq 200000 10312 ns/op 3102.96 MB/s +BenchmarkMemFilerRdSeq 200000 11069 ns/op 2890.84 MB/s +BenchmarkMemFilerWrRand 5000 280910 ns/op 934.14 MB/s +BenchmarkMemFilerRdRand 10000 188500 ns/op 1388.17 MB/s + +*/ + +package lldb + +import ( + "bytes" + "fmt" + "io" + + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/fileutil" + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/mathutil" +) + +const ( + pgBits = 16 + pgSize = 1 << pgBits + pgMask = pgSize - 1 +) + +var _ Filer = &MemFiler{} // Ensure MemFiler is a Filer. + +type memFilerMap map[int64]*[pgSize]byte + +// MemFiler is a memory backed Filer. It implements BeginUpdate, EndUpdate and +// Rollback as no-ops. MemFiler is not automatically persistent, but it has +// ReadFrom and WriteTo methods. +type MemFiler struct { + m memFilerMap + nest int + size int64 +} + +// NewMemFiler returns a new MemFiler. +func NewMemFiler() *MemFiler { + return &MemFiler{m: memFilerMap{}} +} + +// BeginUpdate implements Filer. +func (f *MemFiler) BeginUpdate() error { + f.nest++ + return nil +} + +// Close implements Filer. +func (f *MemFiler) Close() (err error) { + if f.nest != 0 { + return &ErrPERM{(f.Name() + ":Close")} + } + + return +} + +// EndUpdate implements Filer. +func (f *MemFiler) EndUpdate() (err error) { + if f.nest == 0 { + return &ErrPERM{(f.Name() + ": EndUpdate")} + } + + f.nest-- + return +} + +// Name implements Filer. +func (f *MemFiler) Name() string { + return fmt.Sprintf("%p.memfiler", f) +} + +// PunchHole implements Filer. +func (f *MemFiler) PunchHole(off, size int64) (err error) { + if off < 0 { + return &ErrINVAL{f.Name() + ": PunchHole off", off} + } + + if size < 0 || off+size > f.size { + return &ErrINVAL{f.Name() + ": PunchHole size", size} + } + + first := off >> pgBits + if off&pgMask != 0 { + first++ + } + off += size - 1 + last := off >> pgBits + if off&pgMask != 0 { + last-- + } + if limit := f.size >> pgBits; last > limit { + last = limit + } + for pg := first; pg <= last; pg++ { + delete(f.m, pg) + } + return +} + +var zeroPage [pgSize]byte + +// ReadAt implements Filer. +func (f *MemFiler) ReadAt(b []byte, off int64) (n int, err error) { + avail := f.size - off + pgI := off >> pgBits + pgO := int(off & pgMask) + rem := len(b) + if int64(rem) >= avail { + rem = int(avail) + err = io.EOF + } + for rem != 0 && avail > 0 { + pg := f.m[pgI] + if pg == nil { + pg = &zeroPage + } + nc := copy(b[:mathutil.Min(rem, pgSize)], pg[pgO:]) + pgI++ + pgO = 0 + rem -= nc + n += nc + b = b[nc:] + } + return +} + +// ReadFrom is a helper to populate MemFiler's content from r. 'n' reports the +// number of bytes read from 'r'. +func (f *MemFiler) ReadFrom(r io.Reader) (n int64, err error) { + if err = f.Truncate(0); err != nil { + return + } + + var ( + b [pgSize]byte + rn int + off int64 + ) + + var rerr error + for rerr == nil { + if rn, rerr = r.Read(b[:]); rn != 0 { + f.WriteAt(b[:rn], off) + off += int64(rn) + n += int64(rn) + } + } + if !fileutil.IsEOF(rerr) { + err = rerr + } + return +} + +// Rollback implements Filer. +func (f *MemFiler) Rollback() (err error) { return } + +// Size implements Filer. +func (f *MemFiler) Size() (int64, error) { + return f.size, nil +} + +// Sync implements Filer. +func (f *MemFiler) Sync() error { + return nil +} + +// Truncate implements Filer. +func (f *MemFiler) Truncate(size int64) (err error) { + switch { + case size < 0: + return &ErrINVAL{"Truncate size", size} + case size == 0: + f.m = memFilerMap{} + f.size = 0 + return + } + + first := size >> pgBits + if size&pgMask != 0 { + first++ + } + last := f.size >> pgBits + if f.size&pgMask != 0 { + last++ + } + for ; first < last; first++ { + delete(f.m, first) + } + + f.size = size + return +} + +// WriteAt implements Filer. +func (f *MemFiler) WriteAt(b []byte, off int64) (n int, err error) { + pgI := off >> pgBits + pgO := int(off & pgMask) + n = len(b) + rem := n + var nc int + for rem != 0 { + if pgO == 0 && rem >= pgSize && bytes.Equal(b[:pgSize], zeroPage[:]) { + delete(f.m, pgI) + nc = pgSize + } else { + pg := f.m[pgI] + if pg == nil { + pg = new([pgSize]byte) + f.m[pgI] = pg + } + nc = copy((*pg)[pgO:], b) + } + pgI++ + pgO = 0 + rem -= nc + b = b[nc:] + } + f.size = mathutil.MaxInt64(f.size, off+int64(n)) + return +} + +// WriteTo is a helper to copy/persist MemFiler's content to w. If w is also +// an io.WriterAt then WriteTo may attempt to _not_ write any big, for some +// value of big, runs of zeros, i.e. it will attempt to punch holes, where +// possible, in `w` if that happens to be a freshly created or to zero length +// truncated OS file. 'n' reports the number of bytes written to 'w'. +func (f *MemFiler) WriteTo(w io.Writer) (n int64, err error) { + var ( + b [pgSize]byte + wn, rn int + off int64 + rerr error + ) + + if wa, ok := w.(io.WriterAt); ok { + lastPgI := f.size >> pgBits + for pgI := int64(0); pgI <= lastPgI; pgI++ { + sz := pgSize + if pgI == lastPgI { + sz = int(f.size & pgMask) + } + pg := f.m[pgI] + if pg != nil { + wn, err = wa.WriteAt(pg[:sz], off) + if err != nil { + return + } + + n += int64(wn) + off += int64(sz) + if wn != sz { + return n, io.ErrShortWrite + } + } + } + return + } + + var werr error + for rerr == nil { + if rn, rerr = f.ReadAt(b[:], off); rn != 0 { + off += int64(rn) + if wn, werr = w.Write(b[:rn]); werr != nil { + return n, werr + } + + n += int64(wn) + } + } + if !fileutil.IsEOF(rerr) { + err = rerr + } + return +} diff --git a/Godeps/_workspace/src/github.com/cznic/exp/lldb/memfiler_test.go b/Godeps/_workspace/src/github.com/cznic/exp/lldb/memfiler_test.go new file mode 100644 index 0000000..319f4bb --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/exp/lldb/memfiler_test.go @@ -0,0 +1,132 @@ +// Copyright 2014 The lldb 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 lldb + +import ( + "bytes" + "math/rand" + "testing" +) + +// Test automatic page releasing (hole punching) of zero pages +func TestMemFilerWriteAt(t *testing.T) { + f := NewMemFiler() + + // Add page index 0 + if _, err := f.WriteAt([]byte{1}, 0); err != nil { + t.Fatal(err) + } + + if g, e := len(f.m), 1; g != e { + t.Fatal(g, e) + } + + // Add page index 1 + if _, err := f.WriteAt([]byte{2}, pgSize); err != nil { + t.Fatal(err) + } + + if g, e := len(f.m), 2; g != e { + t.Fatal(g, e) + } + + // Add page index 2 + if _, err := f.WriteAt([]byte{3}, 2*pgSize); err != nil { + t.Fatal(err) + } + + if g, e := len(f.m), 3; g != e { + t.Fatal(g, e) + } + + // Remove page index 1 + if _, err := f.WriteAt(make([]byte, 2*pgSize), pgSize/2); err != nil { + t.Fatal(err) + } + + if g, e := len(f.m), 2; g != e { + t.Logf("%#v", f.m) + t.Fatal(g, e) + } + + if err := f.Truncate(1); err != nil { + t.Fatal(err) + } + + if g, e := len(f.m), 1; g != e { + t.Logf("%#v", f.m) + t.Fatal(g, e) + } + + if err := f.Truncate(0); err != nil { + t.Fatal(err) + } + + if g, e := len(f.m), 0; g != e { + t.Logf("%#v", f.m) + t.Fatal(g, e) + } +} + +func TestMemFilerWriteTo(t *testing.T) { + const max = 1e5 + var b [max]byte + rng := rand.New(rand.NewSource(42)) + for sz := 0; sz < 1e5; sz += 2053 { + for i := range b[:sz] { + b[i] = byte(rng.Int()) + } + f := NewMemFiler() + if n, err := f.WriteAt(b[:sz], 0); n != sz || err != nil { + t.Fatal(n, err) + } + + var buf bytes.Buffer + if n, err := f.WriteTo(&buf); n != int64(sz) || err != nil { + t.Fatal(n, err) + } + + if !bytes.Equal(b[:sz], buf.Bytes()) { + t.Fatal("content differs") + } + } +} + +func TestMemFilerReadFromWriteTo(t *testing.T) { + const ( + sz = 1e2 * pgSize + hole = 1e1 * pgSize + ) + rng := rand.New(rand.NewSource(42)) + data := make([]byte, sz) + for i := range data { + data[i] = byte(rng.Int()) + } + f := NewMemFiler() + buf := bytes.NewBuffer(data) + if n, err := f.ReadFrom(buf); n != int64(len(data)) || err != nil { + t.Fatal(n, err) + } + + buf = bytes.NewBuffer(nil) + if n, err := f.WriteTo(buf); n != int64(len(data)) || err != nil { + t.Fatal(n, err) + } + + rd := buf.Bytes() + if !bytes.Equal(data, rd) { + t.Fatal("corrupted data") + } + + n0 := len(f.m) + data = make([]byte, hole) + f.WriteAt(data, sz/2) + n := len(f.m) + t.Log(n0, n) + d := n0 - n + if d*pgSize < hole-2 || d*pgSize > hole { + t.Fatal(n0, n, d) + } +} diff --git a/Godeps/_workspace/src/github.com/cznic/exp/lldb/osfiler.go b/Godeps/_workspace/src/github.com/cznic/exp/lldb/osfiler.go new file mode 100644 index 0000000..edce1c7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/exp/lldb/osfiler.go @@ -0,0 +1,130 @@ +// Copyright 2014 The lldb 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 lldb + +import ( + "io" + "os" + + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/mathutil" +) + +var _ Filer = (*OSFiler)(nil) + +// OSFile is an os.File like minimal set of methods allowing to construct a +// Filer. +type OSFile interface { + Name() string + Stat() (fi os.FileInfo, err error) + Sync() (err error) + Truncate(size int64) (err error) + io.Closer + io.Reader + io.ReaderAt + io.Seeker + io.Writer + io.WriterAt +} + +// OSFiler is like a SimpleFileFiler but based on an OSFile. +type OSFiler struct { + f OSFile + nest int + size int64 // not set if < 0 +} + +// NewOSFiler returns a Filer from an OSFile. This Filer is like the +// SimpleFileFiler, it does not implement the transaction related methods. +func NewOSFiler(f OSFile) (r *OSFiler) { + return &OSFiler{ + f: f, + size: -1, + } +} + +// BeginUpdate implements Filer. +func (f *OSFiler) BeginUpdate() (err error) { + f.nest++ + return nil +} + +// Close implements Filer. +func (f *OSFiler) Close() (err error) { + if f.nest != 0 { + return &ErrPERM{(f.Name() + ":Close")} + } + + return f.f.Close() +} + +// EndUpdate implements Filer. +func (f *OSFiler) EndUpdate() (err error) { + if f.nest == 0 { + return &ErrPERM{(f.Name() + ":EndUpdate")} + } + + f.nest-- + return +} + +// Name implements Filer. +func (f *OSFiler) Name() string { + return f.f.Name() +} + +// PunchHole implements Filer. +func (f *OSFiler) PunchHole(off, size int64) (err error) { + return +} + +// ReadAt implements Filer. +func (f *OSFiler) ReadAt(b []byte, off int64) (n int, err error) { + return f.f.ReadAt(b, off) +} + +// Rollback implements Filer. +func (f *OSFiler) Rollback() (err error) { return } + +// Size implements Filer. +func (f *OSFiler) Size() (n int64, err error) { + if f.size < 0 { // boot + fi, err := f.f.Stat() + if err != nil { + return 0, err + } + + f.size = fi.Size() + } + return f.size, nil +} + +// Sync implements Filer. +func (f *OSFiler) Sync() (err error) { + return f.f.Sync() +} + +// Truncate implements Filer. +func (f *OSFiler) Truncate(size int64) (err error) { + if size < 0 { + return &ErrINVAL{"Truncate size", size} + } + + f.size = size + return f.f.Truncate(size) +} + +// WriteAt implements Filer. +func (f *OSFiler) WriteAt(b []byte, off int64) (n int, err error) { + if f.size < 0 { // boot + fi, err := os.Stat(f.f.Name()) + if err != nil { + return 0, err + } + + f.size = fi.Size() + } + f.size = mathutil.MaxInt64(f.size, int64(len(b))+off) + return f.f.WriteAt(b, off) +} diff --git a/Godeps/_workspace/src/github.com/cznic/exp/lldb/simplefilefiler.go b/Godeps/_workspace/src/github.com/cznic/exp/lldb/simplefilefiler.go new file mode 100644 index 0000000..02ee78f --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/exp/lldb/simplefilefiler.go @@ -0,0 +1,123 @@ +// Copyright 2014 The lldb Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// A basic os.File backed Filer. + +package lldb + +import ( + "os" + + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/fileutil" + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/mathutil" +) + +var _ Filer = &SimpleFileFiler{} // Ensure SimpleFileFiler is a Filer. + +// SimpleFileFiler is an os.File backed Filer intended for use where structural +// consistency can be reached by other means (SimpleFileFiler is for example +// wrapped in eg. an RollbackFiler or ACIDFiler0) or where persistence is not +// required (temporary/working data sets). +// +// SimpleFileFiler is the most simple os.File backed Filer implementation as it +// does not really implement BeginUpdate and EndUpdate/Rollback in any way +// which would protect the structural integrity of data. If misused e.g. as a +// real database storage w/o other measures, it can easily cause data loss +// when, for example, a power outage occurs or the updating process terminates +// abruptly. +type SimpleFileFiler struct { + file *os.File + nest int + size int64 // not set if < 0 +} + +// NewSimpleFileFiler returns a new SimpleFileFiler. +func NewSimpleFileFiler(f *os.File) *SimpleFileFiler { + return &SimpleFileFiler{file: f, size: -1} +} + +// BeginUpdate implements Filer. +func (f *SimpleFileFiler) BeginUpdate() error { + f.nest++ + return nil +} + +// Close implements Filer. +func (f *SimpleFileFiler) Close() (err error) { + if f.nest != 0 { + return &ErrPERM{(f.Name() + ":Close")} + } + + return f.file.Close() +} + +// EndUpdate implements Filer. +func (f *SimpleFileFiler) EndUpdate() (err error) { + if f.nest == 0 { + return &ErrPERM{(f.Name() + ":EndUpdate")} + } + + f.nest-- + return +} + +// Name implements Filer. +func (f *SimpleFileFiler) Name() string { + return f.file.Name() +} + +// PunchHole implements Filer. +func (f *SimpleFileFiler) PunchHole(off, size int64) (err error) { + return fileutil.PunchHole(f.file, off, size) +} + +// ReadAt implements Filer. +func (f *SimpleFileFiler) ReadAt(b []byte, off int64) (n int, err error) { + return f.file.ReadAt(b, off) +} + +// Rollback implements Filer. +func (f *SimpleFileFiler) Rollback() (err error) { return } + +// Size implements Filer. +func (f *SimpleFileFiler) Size() (int64, error) { + if f.size < 0 { // boot + fi, err := os.Stat(f.file.Name()) + if err != nil { + return 0, err + } + + f.size = fi.Size() + } + return f.size, nil +} + +// Sync implements Filer. +func (f *SimpleFileFiler) Sync() error { + return f.file.Sync() +} + +// Truncate implements Filer. +func (f *SimpleFileFiler) Truncate(size int64) (err error) { + if size < 0 { + return &ErrINVAL{"Truncate size", size} + } + + f.size = size + return f.file.Truncate(size) +} + +// WriteAt implements Filer. +func (f *SimpleFileFiler) WriteAt(b []byte, off int64) (n int, err error) { + if f.size < 0 { // boot + fi, err := os.Stat(f.file.Name()) + if err != nil { + return 0, err + } + + f.size = fi.Size() + } + f.size = mathutil.MaxInt64(f.size, int64(len(b))+off) + return f.file.WriteAt(b, off) +} diff --git a/Godeps/_workspace/src/github.com/cznic/exp/lldb/xact.go b/Godeps/_workspace/src/github.com/cznic/exp/lldb/xact.go new file mode 100644 index 0000000..b29fe6a --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/exp/lldb/xact.go @@ -0,0 +1,629 @@ +// Copyright 2014 The lldb Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Structural transactions. + +package lldb + +//DONE+ TransactionalMemoryFiler +// ---- +// Use NewRollbackFiler(myMemFiler, ...) + +/* + +bfBits: 3 +BenchmarkRollbackFiler 20000000 102 ns/op 9.73 MB/s + +bfBits: 4 +BenchmarkRollbackFiler 50000000 55.7 ns/op 17.95 MB/s + +bfBits: 5 +BenchmarkRollbackFiler 100000000 32.2 ns/op 31.06 MB/s + +bfBits: 6 +BenchmarkRollbackFiler 100000000 20.6 ns/op 48.46 MB/s + +bfBits: 7 +BenchmarkRollbackFiler 100000000 15.1 ns/op 66.12 MB/s + +bfBits: 8 +BenchmarkRollbackFiler 100000000 10.5 ns/op 95.66 MB/s + +bfBits: 9 +BenchmarkRollbackFiler 200000000 8.02 ns/op 124.74 MB/s + +bfBits: 10 +BenchmarkRollbackFiler 200000000 9.25 ns/op 108.09 MB/s + +bfBits: 11 +BenchmarkRollbackFiler 100000000 11.7 ns/op 85.47 MB/s + +bfBits: 12 +BenchmarkRollbackFiler 100000000 17.2 ns/op 57.99 MB/s + +bfBits: 13 +BenchmarkRollbackFiler 100000000 32.7 ns/op 30.58 MB/s + +bfBits: 14 +BenchmarkRollbackFiler 50000000 39.6 ns/op 25.27 MB/s + +*/ + +import ( + "fmt" + "io" + "sync" + + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/fileutil" + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/mathutil" +) + +var ( + _ Filer = &bitFiler{} // Ensure bitFiler is a Filer. + _ Filer = &RollbackFiler{} // ditto +) + +const ( + bfBits = 9 + bfSize = 1 << bfBits + bfMask = bfSize - 1 +) + +var ( + bitmask = [8]byte{1, 2, 4, 8, 16, 32, 64, 128} + bitZeroPage bitPage + allDirtyFlags [bfSize >> 3]byte +) + +func init() { + for i := range allDirtyFlags { + allDirtyFlags[i] = 0xff + } +} + +type ( + bitPage struct { + prev, next *bitPage + data [bfSize]byte + flags [bfSize >> 3]byte + dirty bool + } + + bitFilerMap map[int64]*bitPage + + bitFiler struct { + parent Filer + m bitFilerMap + size int64 + } +) + +func newBitFiler(parent Filer) (f *bitFiler, err error) { + sz, err := parent.Size() + if err != nil { + return + } + + return &bitFiler{parent: parent, m: bitFilerMap{}, size: sz}, nil +} + +func (f *bitFiler) BeginUpdate() error { panic("internal error") } +func (f *bitFiler) EndUpdate() error { panic("internal error") } +func (f *bitFiler) Rollback() error { panic("internal error") } +func (f *bitFiler) Sync() error { panic("internal error") } + +func (f *bitFiler) Close() (err error) { return } +func (f *bitFiler) Name() string { return fmt.Sprintf("%p.bitfiler", f) } +func (f *bitFiler) Size() (int64, error) { return f.size, nil } + +func (f *bitFiler) PunchHole(off, size int64) (err error) { + first := off >> bfBits + if off&bfMask != 0 { + first++ + } + off += size - 1 + last := off >> bfBits + if off&bfMask != 0 { + last-- + } + if limit := f.size >> bfBits; last > limit { + last = limit + } + for pgI := first; pgI <= last; pgI++ { + pg := &bitPage{} + pg.flags = allDirtyFlags + f.m[pgI] = pg + } + return +} + +func (f *bitFiler) ReadAt(b []byte, off int64) (n int, err error) { + avail := f.size - off + pgI := off >> bfBits + pgO := int(off & bfMask) + rem := len(b) + if int64(rem) >= avail { + rem = int(avail) + err = io.EOF + } + for rem != 0 && avail > 0 { + pg := f.m[pgI] + if pg == nil { + pg = &bitPage{} + if f.parent != nil { + _, err = f.parent.ReadAt(pg.data[:], off&^bfMask) + if err != nil && !fileutil.IsEOF(err) { + return + } + + err = nil + } + f.m[pgI] = pg + } + nc := copy(b[:mathutil.Min(rem, bfSize)], pg.data[pgO:]) + pgI++ + pgO = 0 + rem -= nc + n += nc + b = b[nc:] + off += int64(nc) + } + return +} + +func (f *bitFiler) Truncate(size int64) (err error) { + switch { + case size < 0: + return &ErrINVAL{"Truncate size", size} + case size == 0: + f.m = bitFilerMap{} + f.size = 0 + return + } + + first := size >> bfBits + if size&bfMask != 0 { + first++ + } + last := f.size >> bfBits + if f.size&bfMask != 0 { + last++ + } + for ; first < last; first++ { + delete(f.m, first) + } + + f.size = size + return +} + +func (f *bitFiler) WriteAt(b []byte, off int64) (n int, err error) { + off0 := off + pgI := off >> bfBits + pgO := int(off & bfMask) + n = len(b) + rem := n + var nc int + for rem != 0 { + pg := f.m[pgI] + if pg == nil { + pg = &bitPage{} + if f.parent != nil { + _, err = f.parent.ReadAt(pg.data[:], off&^bfMask) + if err != nil && !fileutil.IsEOF(err) { + return + } + + err = nil + } + f.m[pgI] = pg + } + nc = copy(pg.data[pgO:], b) + pgI++ + pg.dirty = true + for i := pgO; i < pgO+nc; i++ { + pg.flags[i>>3] |= bitmask[i&7] + } + pgO = 0 + rem -= nc + b = b[nc:] + off += int64(nc) + } + f.size = mathutil.MaxInt64(f.size, off0+int64(n)) + return +} + +func (f *bitFiler) link() { + for pgI, pg := range f.m { + nx, ok := f.m[pgI+1] + if !ok || !nx.dirty { + continue + } + + nx.prev, pg.next = pg, nx + } +} + +func (f *bitFiler) dumpDirty(w io.WriterAt) (nwr int, err error) { + f.link() + for pgI, pg := range f.m { + if !pg.dirty { + continue + } + + for pg.prev != nil && pg.prev.dirty { + pg = pg.prev + pgI-- + } + + for pg != nil && pg.dirty { + last := false + var off int64 + first := -1 + for i := 0; i < bfSize; i++ { + flag := pg.flags[i>>3]&bitmask[i&7] != 0 + switch { + case flag && !last: // Leading edge detected + off = pgI<= 0 { + i := bfSize + n, err := w.WriteAt(pg.data[first:i], off) + if n != i-first { + return 0, err + } + + nwr++ + } + + pg.dirty = false + pg = pg.next + pgI++ + } + } + return +} + +// RollbackFiler is a Filer implementing structural transaction handling. +// Structural transactions should be small and short lived because all non +// committed data are held in memory until committed or discarded by a +// Rollback. +// +// While using RollbackFiler, every intended update of the wrapped Filler, by +// WriteAt, Truncate or PunchHole, _must_ be made within a transaction. +// Attempts to do it outside of a transaction will return ErrPERM. OTOH, +// invoking ReadAt outside of a transaction is not a problem. +// +// No nested transactions: All updates within a transaction are held in memory. +// On a matching EndUpdate the updates held in memory are actually written to +// the wrapped Filer. +// +// Nested transactions: Correct data will be seen from RollbackFiler when any +// level of a nested transaction is rollbacked. The actual writing to the +// wrapped Filer happens only when the outer most transaction nesting level is +// closed. +// +// Invoking Rollback is an alternative to EndUpdate. It discards all changes +// made at the current transaction level and returns the "state" (possibly not +// yet persisted) of the Filer to what it was before the corresponding +// BeginUpdate. +// +// During an open transaction, all reads (using ReadAt) are "dirty" reads, +// seeing the uncommitted changes made to the Filer's data. +// +// Lldb databases should be based upon a RollbackFiler. +// +// With a wrapped MemFiler one gets transactional memory. With, for example a +// wrapped disk based SimpleFileFiler it protects against at least some HW +// errors - if Rollback is properly invoked on such failures and/or if there's +// some WAL or 2PC or whatever other safe mechanism based recovery procedure +// used by the client. +// +// The "real" writes to the wrapped Filer (or WAL instead) go through the +// writerAt supplied to NewRollbackFiler. +// +// List of functions/methods which are recommended to be wrapped in a +// BeginUpdate/EndUpdate structural transaction: +// +// Allocator.Alloc +// Allocator.Free +// Allocator.Realloc +// +// CreateBTree +// RemoveBTree +// BTree.Clear +// BTree.Delete +// BTree.DeleteAny +// BTree.Clear +// BTree.Extract +// BTree.Get (it can mutate the DB) +// BTree.Put +// BTree.Set +// +// NOTE: RollbackFiler is a generic solution intended to wrap Filers provided +// by this package which do not implement any of the transactional methods. +// RollbackFiler thus _does not_ invoke any of the transactional methods of its +// wrapped Filer. +// +// RollbackFiler is safe for concurrent use by multiple goroutines. +type RollbackFiler struct { + mu sync.RWMutex + inCallback bool + inCallbackMu sync.RWMutex + bitFiler *bitFiler + checkpoint func(int64) error + closed bool + f Filer + parent Filer + tlevel int // transaction nesting level, 0 == not in transaction + writerAt io.WriterAt + + // afterRollback, if not nil, is called after performing Rollback + // without errros. + afterRollback func() error +} + +// NewRollbackFiler returns a RollbackFiler wrapping f. +// +// The checkpoint parameter +// +// The checkpoint function is called after closing (by EndUpdate) the upper +// most level open transaction if all calls of writerAt were successful and the +// DB (or eg. a WAL) is thus now in a consistent state (virtually, in the ideal +// world with no write caches, no HW failures, no process crashes, ...). +// +// NOTE: In, for example, a 2PC it is necessary to reflect also the sz +// parameter as the new file size (as in the parameter to Truncate). All +// changes were successfully written already by writerAt before invoking +// checkpoint. +// +// The writerAt parameter +// +// The writerAt interface is used to commit the updates of the wrapped Filer. +// If any invocation of writerAt fails then a non nil error will be returned +// from EndUpdate and checkpoint will _not_ ne called. Neither is necessary to +// call Rollback. The rule of thumb: The [structural] transaction [level] is +// closed by invoking exactly once one of EndUpdate _or_ Rollback. +// +// It is presumed that writerAt uses WAL or 2PC or whatever other safe +// mechanism to physically commit the updates. +// +// Updates performed by invocations of writerAt are byte-precise, but not +// necessarily maximum possible length precise. IOW, for example an update +// crossing page boundaries may be performed by more than one writerAt +// invocation. No offset sorting is performed. This may change if it proves +// to be a problem. Such change would be considered backward compatible. +// +// NOTE: Using RollbackFiler, but failing to ever invoke a matching "closing" +// EndUpdate after an "opening" BeginUpdate means neither writerAt or +// checkpoint will ever get called - with all the possible data loss +// consequences. +func NewRollbackFiler(f Filer, checkpoint func(sz int64) error, writerAt io.WriterAt) (r *RollbackFiler, err error) { + if f == nil || checkpoint == nil || writerAt == nil { + return nil, &ErrINVAL{Src: "lldb.NewRollbackFiler, nil argument"} + } + + return &RollbackFiler{ + checkpoint: checkpoint, + f: f, + writerAt: writerAt, + }, nil +} + +// Implements Filer. +func (r *RollbackFiler) BeginUpdate() (err error) { + r.mu.Lock() + defer r.mu.Unlock() + + parent := r.f + if r.tlevel != 0 { + parent = r.bitFiler + } + r.bitFiler, err = newBitFiler(parent) + if err != nil { + return + } + + r.tlevel++ + return +} + +// Implements Filer. +// +// Close will return an error if not invoked at nesting level 0. However, to +// allow emergency closing from eg. a signal handler; if Close is invoked +// within an open transaction(s), it rollbacks any non committed open +// transactions and performs the Close operation. +// +// IOW: Regardless of the transaction nesting level the Close is always +// performed but any uncommitted transaction data are lost. +func (r *RollbackFiler) Close() (err error) { + r.mu.Lock() + defer r.mu.Unlock() + + if r.closed { + return &ErrPERM{r.f.Name() + ": Already closed"} + } + + r.closed = true + if err = r.f.Close(); err != nil { + return + } + + if r.tlevel != 0 { + err = &ErrPERM{r.f.Name() + ": Close inside an open transaction"} + } + + return +} + +// Implements Filer. +func (r *RollbackFiler) EndUpdate() (err error) { + r.mu.Lock() + defer r.mu.Unlock() + + if r.tlevel == 0 { + return &ErrPERM{r.f.Name() + " : EndUpdate outside of a transaction"} + } + + sz, err := r.size() // Cannot call .Size() -> deadlock + if err != nil { + return + } + + r.tlevel-- + bf := r.bitFiler + parent := bf.parent + w := r.writerAt + if r.tlevel != 0 { + w = parent + } + nwr, err := bf.dumpDirty(w) + if err != nil { + return + } + + switch { + case r.tlevel == 0: + r.bitFiler = nil + if nwr == 0 { + return + } + + return r.checkpoint(sz) + default: + r.bitFiler = parent.(*bitFiler) + sz, _ := bf.Size() // bitFiler.Size() never returns err != nil + return parent.Truncate(sz) + } +} + +// Implements Filer. +func (r *RollbackFiler) Name() string { + r.mu.RLock() + defer r.mu.RUnlock() + + return r.f.Name() +} + +// Implements Filer. +func (r *RollbackFiler) PunchHole(off, size int64) error { + r.mu.Lock() + defer r.mu.Unlock() + + if r.tlevel == 0 { + return &ErrPERM{r.f.Name() + ": PunchHole outside of a transaction"} + } + + if off < 0 { + return &ErrINVAL{r.f.Name() + ": PunchHole off", off} + } + + if size < 0 || off+size > r.bitFiler.size { + return &ErrINVAL{r.f.Name() + ": PunchHole size", size} + } + + return r.bitFiler.PunchHole(off, size) +} + +// Implements Filer. +func (r *RollbackFiler) ReadAt(b []byte, off int64) (n int, err error) { + r.inCallbackMu.RLock() + defer r.inCallbackMu.RUnlock() + if !r.inCallback { + r.mu.RLock() + defer r.mu.RUnlock() + } + if r.tlevel == 0 { + return r.f.ReadAt(b, off) + } + + return r.bitFiler.ReadAt(b, off) +} + +// Implements Filer. +func (r *RollbackFiler) Rollback() (err error) { + r.mu.Lock() + defer r.mu.Unlock() + + if r.tlevel == 0 { + return &ErrPERM{r.f.Name() + ": Rollback outside of a transaction"} + } + + if r.tlevel > 1 { + r.bitFiler = r.bitFiler.parent.(*bitFiler) + } + r.tlevel-- + if f := r.afterRollback; f != nil { + r.inCallbackMu.Lock() + r.inCallback = true + r.inCallbackMu.Unlock() + defer func() { + r.inCallbackMu.Lock() + r.inCallback = false + r.inCallbackMu.Unlock() + }() + return f() + } + return +} + +func (r *RollbackFiler) size() (sz int64, err error) { + if r.tlevel == 0 { + return r.f.Size() + } + + return r.bitFiler.Size() +} + +// Implements Filer. +func (r *RollbackFiler) Size() (sz int64, err error) { + r.mu.Lock() + defer r.mu.Unlock() + + return r.size() +} + +// Implements Filer. +func (r *RollbackFiler) Sync() error { + r.mu.Lock() + defer r.mu.Unlock() + + return r.f.Sync() +} + +// Implements Filer. +func (r *RollbackFiler) Truncate(size int64) error { + r.mu.Lock() + defer r.mu.Unlock() + + if r.tlevel == 0 { + return &ErrPERM{r.f.Name() + ": Truncate outside of a transaction"} + } + + return r.bitFiler.Truncate(size) +} + +// Implements Filer. +func (r *RollbackFiler) WriteAt(b []byte, off int64) (n int, err error) { + r.mu.Lock() + defer r.mu.Unlock() + + if r.tlevel == 0 { + return 0, &ErrPERM{r.f.Name() + ": WriteAt outside of a transaction"} + } + + return r.bitFiler.WriteAt(b, off) +} diff --git a/Godeps/_workspace/src/github.com/cznic/exp/lldb/xact_test.go b/Godeps/_workspace/src/github.com/cznic/exp/lldb/xact_test.go new file mode 100644 index 0000000..8a008d7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/exp/lldb/xact_test.go @@ -0,0 +1,400 @@ +// Copyright 2014 The lldb 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 lldb + +import ( + "bytes" + "encoding/hex" + "fmt" + "io" + "math/rand" + "testing" + + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/fileutil" + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/mathutil" +) + +func (f *bitFiler) dump(w io.Writer) { + fmt.Fprintf(w, "bitFiler @ %p, size: %d(%#x)\n", f, f.size, f.size) + for k, v := range f.m { + fmt.Fprintf(w, "bitPage @ %p: pgI %d(%#x): %#v\n", v, k, k, *v) + } +} + +func filerBytes(f Filer) []byte { + sz, err := f.Size() + if err != nil { + panic(err) + } + + b := make([]byte, int(sz)) + n, err := f.ReadAt(b, 0) + if n != len(b) { + panic(fmt.Errorf("sz %d n %d err %v", sz, n, err)) + } + + return b +} + +func cmpFilerBytes(t *testing.T, fg, fe Filer) { + g, e := filerBytes(fg), filerBytes(fe) + if !bytes.Equal(g, e) { + t.Fatalf("Filer content doesn't match: got\n%sexp:\n%s", hex.Dump(g), hex.Dump(e)) + } +} + +func TestRollbackFiler0(t *testing.T) { + var r *RollbackFiler + f, g := NewMemFiler(), NewMemFiler() + + checkpoint := func(sz int64) (err error) { + return f.Truncate(sz) + } + + r, err := NewRollbackFiler(f, checkpoint, f) + if err != nil { + t.Fatal(err) + } + + if err = r.BeginUpdate(); err != nil { + t.Fatal(err) + } + + if err = r.EndUpdate(); err != nil { + t.Fatal(err) + } + + cmpFilerBytes(t, f, g) +} + +func TestRollbackFiler1(t *testing.T) { + const ( + N = 1e6 + O = 1234 + ) + + var r *RollbackFiler + f, g := NewMemFiler(), NewMemFiler() + + checkpoint := func(sz int64) (err error) { + return f.Truncate(sz) + } + + r, err := NewRollbackFiler(f, checkpoint, f) + if err != nil { + t.Fatal(err) + } + + if err = r.BeginUpdate(); err != nil { + t.Fatal(err) + } + + rng := rand.New(rand.NewSource(42)) + b := make([]byte, N) + for i := range b { + b[i] = byte(rng.Int()) + } + + if _, err = g.WriteAt(b, O); err != nil { + t.Fatal(err) + } + + if _, err = r.WriteAt(b, O); err != nil { + t.Fatal(err) + } + + b = filerBytes(f) + if n := len(b); n != 0 { + t.Fatal(n) + } + + if err = r.EndUpdate(); err != nil { + t.Fatal(err) + } + + cmpFilerBytes(t, f, g) +} + +func TestRollbackFiler2(t *testing.T) { + const ( + N = 1e6 + O = 1234 + ) + + var r *RollbackFiler + f, g := NewMemFiler(), NewMemFiler() + + checkpoint := func(sz int64) (err error) { + return f.Truncate(sz) + } + + r, err := NewRollbackFiler(f, checkpoint, f) + if err != nil { + t.Fatal(err) + } + + if err = r.BeginUpdate(); err != nil { + t.Fatal(err) + } + + rng := rand.New(rand.NewSource(42)) + b := make([]byte, N) + for i := range b { + b[i] = byte(rng.Int()) + } + + if _, err = r.WriteAt(b, O); err != nil { + t.Fatal(err) + } + + b = filerBytes(f) + if n := len(b); n != 0 { + t.Fatal(n) + } + + if err = r.Rollback(); err != nil { + t.Fatal(err) + } + + cmpFilerBytes(t, f, g) +} + +func rndBytes(rng *rand.Rand, n int) []byte { + r := make([]byte, n) + for i := range r { + r[i] = byte(rng.Int()) + } + return r +} + +func TestRollbackFiler3(t *testing.T) { + var r *RollbackFiler + f := NewMemFiler() + + checkpoint := func(sz int64) (err error) { + return f.Truncate(sz) + } + + r, err := NewRollbackFiler(f, checkpoint, f) + if err != nil { + t.Fatal(err) + } + + n, err := r.ReadAt([]byte{0}, 0) + if n != 0 || !fileutil.IsEOF(err) { + t.Fatal(n, err) + } + + n, err = r.ReadAt([]byte{0}, 1e6) + if n != 0 || !fileutil.IsEOF(err) { + t.Fatal(n, err) + } + + if err = r.BeginUpdate(); err != nil { // BeginUpdate: 0 -> 1 + t.Fatal(err) + } + + rng := rand.New(rand.NewSource(42)) + + buf := rndBytes(rng, 100) + if n, err := r.WriteAt(buf, 1e6); n != 100 || err != nil { + t.Fatal(err) + } + + buf = make([]byte, 100) + if n, err := r.ReadAt(buf, 1e6-200); n != 100 || err != nil { + t.Fatal(err) + } + + for i, v := range buf { + if v != 0 { + t.Fatal(i, v) + } + } + + if err := r.Truncate(1e5); err != nil { + t.Fatal(err) + } + + if err = r.BeginUpdate(); err != nil { // BeginUpdate: 1 -> 2 + t.Fatal(err) + } + + if n, err := r.ReadAt(buf, 1e6); n != 0 || err == nil { + t.Fatal(n, err) + } + + if err := r.Truncate(2e6); err != nil { + t.Fatal(err) + } + + if err = r.BeginUpdate(); err != nil { // BeginUpdate: 2 -> 3 + t.Fatal(err) + } + + if n, err := r.ReadAt(buf, 1e6); n == 0 || err != nil { + t.Fatal(n, err) + } + + for i, v := range buf { + if v != 0 { + t.Fatal(i, v) + } + } +} + +func TestRollbackFiler4(t *testing.T) { + const ( + maxSize = 1e6 + maxChange = maxSize/100 + 4 + maxChanges = 10 + maxNest = 3 + ) + + var r *RollbackFiler + f := NewMemFiler() + + checkpoint := func(sz int64) (err error) { + return f.Truncate(sz) + } + + r, err := NewRollbackFiler(f, checkpoint, f) + if err != nil { + t.Fatal(err) + } + + rng := rand.New(rand.NewSource(42)) + + ref := make([]byte, 2*maxSize) + for i := range ref { + ref[i] = byte(rng.Int()) + } + + var finalSize int + + var fn func(int, int, []byte) (int, []byte) + fn = func(nest, inSize int, in []byte) (outSize int, out []byte) { + defer func() { + for i := outSize; i < len(out); i++ { + out[i] = 0 + } + finalSize = mathutil.Max(finalSize, outSize) + }() + + out = make([]byte, len(in), 2*maxSize) + copy(out, in) + if err := r.BeginUpdate(); err != nil { + t.Fatal(err) + } + + for i := 0; i < maxChanges; i++ { + changeLen := rng.Intn(maxChange) + 4 + changeOff := rng.Intn(maxSize * 3 / 2) + b := make([]byte, changeLen) + for i := range b { + b[i] = byte(rng.Int()) + } + if n, err := r.WriteAt(b, int64(changeOff)); n != len(b) || err != nil { + t.Fatal(n, len(b), err) + } + } + + if err := r.Rollback(); err != nil { + t.Fatal(err) + } + + if err := r.BeginUpdate(); err != nil { + t.Fatal(err) + } + + for i := 0; i < maxChanges; i++ { + changeLen := rng.Intn(maxChange) + 4 + changeOff := rng.Intn(maxSize * 3 / 2) + b := make([]byte, changeLen) + for i := range b { + b[i] = byte(rng.Int()) + } + if n, err := r.WriteAt(b, int64(changeOff)); n != len(b) || err != nil { + t.Fatal(n, len(b), err) + } + copy(out[changeOff:], b) + copy(ref[changeOff:], b) + } + + newSize := rng.Intn(maxSize*3/2) + 4 + if nest == maxNest { + if err := r.EndUpdate(); err != nil { + t.Fatal(err) + } + + return newSize, out + } + + outSize, out = fn(nest+1, newSize, out) + if err := r.EndUpdate(); err != nil { + t.Fatal(err) + } + + return + } + + sz, result := fn(0, maxSize, ref) + if g, e := sz, finalSize; g != e { + t.Fatal(err) + } + + g, e := result[:sz], ref[:sz] + if !bytes.Equal(g, e) { + if len(g) == len(e) { + x := make([]byte, len(g)) + for i := range x { + if g[i] != e[i] { + x[i] = 'X' + } + } + //t.Logf("Data diff\n%s", hex.Dump(x)) + } + //t.Fatalf("Data don't match: got\n%sexp:\n%s", hex.Dump(g), hex.Dump(e)) + t.Fatalf("Data don't match") + } +} + +func BenchmarkRollbackFiler(b *testing.B) { + rng := rand.New(rand.NewSource(42)) + type t struct { + off int64 + b []byte + } + a := []t{} + for rem := b.N; rem > 0; { + off := rng.Int63() + n := mathutil.Min(rng.Intn(1e3)+1, rem) + a = append(a, t{off, rndBytes(rng, n)}) + rem -= n + } + + var r *RollbackFiler + f := NewMemFiler() + + checkpoint := func(sz int64) (err error) { + return f.Truncate(sz) + } + + r, err := NewRollbackFiler(f, checkpoint, f) + if err != nil { + b.Fatal(err) + } + + if err := r.BeginUpdate(); err != nil { + b.Fatal(err) + } + + b.ResetTimer() + for _, v := range a { + if _, err := r.WriteAt(v.b, v.off); err != nil { + b.Fatal(err) + } + } +} diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/AUTHORS b/Godeps/_workspace/src/github.com/cznic/fileutil/AUTHORS new file mode 100644 index 0000000..288ea0b --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/AUTHORS @@ -0,0 +1,14 @@ +# This file lists authors for copyright purposes. This file is distinct from +# the CONTRIBUTORS files. See the latter for an explanation. +# +# Names should be added to this file as: +# Name or Organization +# +# The email address is not required for organizations. +# +# Please keep the list sorted. + +CZ.NIC z.s.p.o. +Jan Mercl <0xjnml@gmail.com> +Aaron Bieber + diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/CONTRIBUTORS b/Godeps/_workspace/src/github.com/cznic/fileutil/CONTRIBUTORS new file mode 100644 index 0000000..223b21a --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/CONTRIBUTORS @@ -0,0 +1,14 @@ +# This file lists people who contributed code to this repository. The AUTHORS +# file lists the copyright holders; this file lists people. +# +# Names should be added to this file like so: +# Name +# +# Please keep the list sorted. + +Bill Thiede +Gary Burd +Jan Mercl <0xjnml@gmail.com> +Nick Owens +Tamás Gulácsi +Aaron Bieber diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/LICENSE b/Godeps/_workspace/src/github.com/cznic/fileutil/LICENSE new file mode 100644 index 0000000..50bbdd2 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2014 The fileutil Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the names of the authors nor the names of the +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/Makefile b/Godeps/_workspace/src/github.com/cznic/fileutil/Makefile new file mode 100644 index 0000000..5849cc2 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/Makefile @@ -0,0 +1,27 @@ +# Copyright (c) 2014 The fileutil authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +.PHONY: all clean editor todo + +all: editor + go vet + golint . + go install + make todo + +editor: + go fmt + go test -i + go test + go build + +todo: + @grep -n ^[[:space:]]*_[[:space:]]*=[[:space:]][[:alpha:]][[:alnum:]]* *.go || true + @grep -n TODO *.go || true + @grep -n BUG *.go || true + @grep -n println *.go || true + +clean: + @go clean + rm -f y.output diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/README b/Godeps/_workspace/src/github.com/cznic/fileutil/README new file mode 100644 index 0000000..f43d5f0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/README @@ -0,0 +1,16 @@ +This is a goinstall-able mirror of modified code already published at: +http://git.nic.cz/redmine/projects/gofileutil/repository + +Packages in this repository: + +Install: $go get github.com/cznic/fileutil +Godocs: http://godoc.org/github.com/cznic/fileutil + +Install: $go get github.com/cznic/fileutil/storage +Godocs: http://godoc.org/github.com/cznic/fileutil/storage + +Install: $go get github.com/cznic/fileutil/falloc +Godocs: http://godoc.org/github.com/cznic/fileutil/falloc + +Install: $go get github.com/cznic/fileutil/hdb +Godocs: http://godoc.org/github.com/cznic/fileutil/hdb diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/all_test.go b/Godeps/_workspace/src/github.com/cznic/fileutil/all_test.go new file mode 100644 index 0000000..21a8fa9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/all_test.go @@ -0,0 +1,39 @@ +// Copyright (c) 2014 The fileutil 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 fileutil + +import ( + "os" + "path/filepath" + "strings" + "testing" +) + +func TestTempFile(t *testing.T) { + f, err := TempFile("", "abc", "mno.xyz") + if err != nil { + t.Fatal(err) + } + + n := f.Name() + t.Log(n) + defer func() { + f.Close() + os.Remove(n) + }() + + base := filepath.Base(n) + if base == "abcmno.xyz" { + t.Fatal(base) + } + + if !strings.HasPrefix(base, "abc") { + t.Fatal(base) + } + + if !strings.HasSuffix(base, "mno.xyz") { + t.Fatal(base) + } +} diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/falloc/LICENSE b/Godeps/_workspace/src/github.com/cznic/fileutil/falloc/LICENSE new file mode 100644 index 0000000..1e92e33 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/falloc/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2011 CZ.NIC z.s.p.o. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of CZ.NIC nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/falloc/README b/Godeps/_workspace/src/github.com/cznic/fileutil/falloc/README new file mode 100644 index 0000000..23313fc --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/falloc/README @@ -0,0 +1,5 @@ +This is a goinstall-able mirror of modified code already published at: +https://git.nic.cz/redmine/projects/gofileutil/repository/show/falloc + +Install: $go get github.com/cznic/fileutil/falloc +Godocs: http://gopkgdoc.appspot.com/pkg/github.com/cznic/fileutil/falloc diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/falloc/all_test.go b/Godeps/_workspace/src/github.com/cznic/fileutil/falloc/all_test.go new file mode 100644 index 0000000..3be9206 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/falloc/all_test.go @@ -0,0 +1,3105 @@ +// Copyright (c) 2011 CZ.NIC z.s.p.o. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// blame: jnml, labs.nic.cz + +package falloc + +import ( + "bytes" + "errors" + "flag" + "fmt" + "io/ioutil" + "log" + "math" + "os" + "path/filepath" + "runtime" + "testing" + "time" + + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/fileutil" + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/fileutil/storage" + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/mathutil" +) + +var ( + blockFlag = flag.Uint("block", 256, "block size for some of the dev tests") + cacheTotalFlag = flag.Int64("cachemax", 1<<25, "cache total bytes") + cachedFlag = flag.Bool("cache", false, "enable caching store") + devFlag = flag.Bool("dev", false, "enable dev tests") + dropFlag = flag.Bool("drop", false, "drop system file cache for some of the dev tests before measurement") + fadviseFlag = flag.Bool("fadvise", false, "hint kernel about random file access") + nFlag = flag.Int("n", 1, "parameter for some of the dev tests") + probeFlag = flag.Bool("probe", false, "report store probe statistics") + optGo = flag.Int("go", 3, "GOMAXPROCS") +) + +func init() { + flag.Parse() + runtime.GOMAXPROCS(*optGo) +} + +func temp() (dir, name string) { + dir, err := ioutil.TempDir("", "test-falloc-") + if err != nil { + panic(err) + } + + name = filepath.Join(dir, "test.db") + return dir, name +} + +type balancedAcid struct { + storage.Accessor + nesting int +} + +func newBalancedAcid(store storage.Accessor) storage.Accessor { + return &balancedAcid{store, 0} +} + +func (b *balancedAcid) BeginUpdate() error { + if b.nesting < 0 { + return errors.New("BeginUpdate with nesting < 0") + } + + b.nesting++ + return nil +} + +func (b *balancedAcid) EndUpdate() error { + if b.nesting <= 0 { + return errors.New("EndUpdate with nesting <= 0") + } + + b.nesting-- + return nil +} + +func (b *balancedAcid) Close() error { + if b.nesting != 1 { + return fmt.Errorf("before Close(): nesting %d %p", b.nesting, b) + } + + if err := b.Accessor.Close(); err != nil { + return err + } + + if b.nesting != 1 { + return fmt.Errorf("after Close(): nesting %d", b.nesting) + } + + return nil +} + +func fopen(fn string) (f *File, err error) { + var store storage.Accessor + if store, err = storage.OpenFile(fn, os.O_RDWR, 0666); err != nil { + return + } + + var advise func(int64, int, bool) + if *fadviseFlag { + file := store.(*storage.FileAccessor).File + if err = fileutil.Fadvise(file, 0, 0, fileutil.POSIX_FADV_RANDOM); err != nil { + return + } + advise = func(off int64, len int, write bool) { + if err = fileutil.Fadvise(file, off, off+int64(len), fileutil.POSIX_FADV_DONTNEED); err != nil { + log.Fatal("advisor advise err", err) + } + } + } + + var prob *storage.Probe + if *probeFlag { + prob = storage.NewProbe(store, nil) + store = prob + } + if *cachedFlag { + if store, err = storage.NewCache(store, *cacheTotalFlag, advise); err != nil { + return + } + + if *probeFlag { + store = storage.NewProbe(store, prob) + } + } + f, err = Open(newBalancedAcid(store)) + return +} + +func fcreate(fn string) (f *File, err error) { + var store storage.Accessor + if store, err = storage.OpenFile(fn, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666); err != nil { + return + } + + var advise func(int64, int, bool) + if *fadviseFlag { + file := store.(*storage.FileAccessor).File + if err = fileutil.Fadvise(file, 0, 0, fileutil.POSIX_FADV_RANDOM); err != nil { + return + } + advise = func(off int64, len int, write bool) { + if err = fileutil.Fadvise(file, off, off+int64(len), fileutil.POSIX_FADV_DONTNEED); err != nil { + log.Fatal("advisor advise err", err) + } + } + } + + var prob *storage.Probe + if *probeFlag { + prob = storage.NewProbe(store, nil) + store = prob + } + if *cachedFlag { + if store, err = storage.NewCache(store, *cacheTotalFlag, advise); err != nil { + return + } + + if *probeFlag { + store = storage.NewProbe(store, prob) + } + } + f, err = New(newBalancedAcid(store)) + return +} + +func probed(t *testing.T, f *File) { + if f == nil { + return + } + + dump := func(p *storage.Probe) { + t.Logf("OpsRd %d OpsWr %d BytesRd %d(avg %.1f) BytesWr %d(avg %.1f) SectorsRd %d(%d, +%d, x%.2f) SectorsWr %d(%d, +%d, x%.2f)", + p.OpsRd, p.OpsWr, + p.BytesRd, float64(p.BytesRd)/float64(p.OpsRd), + p.BytesWr, float64(p.BytesWr)/float64(p.OpsWr), + p.SectorsRd, + p.SectorsRd<<9, + p.SectorsRd<<9-p.BytesRd, + float64(p.SectorsRd<<9)/float64(p.BytesRd), + p.SectorsWr, + p.SectorsWr<<9, + p.SectorsWr<<9-p.BytesWr, + float64(p.SectorsWr<<9)/float64(p.BytesWr), + ) + } + + if ph, ok := f.Accessor().(*storage.Probe); ok { + dump(ph) + if c, ok := ph.Accessor.(*storage.Cache); ok { + if pl, ok := c.Accessor().(*storage.Probe); ok { + dump(pl) + } + } + } +} + +func (f *File) audit() (usedblocks, totalblocks int64, err error) { + defer func() { + if e := recover(); e != nil { + err = e.(error) + } + }() + + fi, err := f.f.Stat() + if err != nil { + panic(err) + } + + freemap := map[int64]int64{} + fp := int64(0) + buf := make([]byte, 22) + freeblocks := int64(0) + + // linear scan + for fp < fi.Size() { + totalblocks++ + typ, size := f.getInfo(fp >> 4) + f.read(buf[:1], fp+size<<4-1) + last := buf[0] + switch { + default: + panic("internal error") + case typ == 0: + if last != 0 { + panic(fmt.Errorf("@%#x used empty, last @%#x: %#x != 0", fp, fp+size<<4-1, last)) + } + case typ >= 0x1 && typ <= 0xed: + if last >= 0xfe { + panic(fmt.Errorf("@%#x used short, last @%#x: %#x > 0xfe", fp, fp+size<<4-1, last)) + } + case typ >= 0xee && typ <= 0xfb: + if last > 1 { + panic(fmt.Errorf("@%#x used esc short, last @%#x: %#x > 1", fp, fp+size<<4-1, last)) + } + case typ == 0xfc: + f.read(buf[:2], fp+1) + switch n := int(buf[0])<<8 + int(buf[1]); { + default: + panic(fmt.Errorf("@%#x used long, illegal content length %#x < 0xee(238)", fp, n)) + case n >= 0xee && n <= 0xf0f0: + if last >= 0xfe { + panic(fmt.Errorf("@%#x used long, last @%#x: %#x > 0xfe", fp, fp+size<<4-1, last)) + } + case n >= 0xf0f1 && n <= 0xffff: + if last > 1 { + panic(fmt.Errorf("@%#x used esc long, last @%#x: %#x > 1", fp, fp+size<<4-1, last)) + } + } + case typ == 0xfd: + if last != 0 { + panic(fmt.Errorf("@%#x reloc, last @%#x: %#x != 0", fp, fp+size<<4-1, last)) + } + + var target int64 + f.read(buf[:7], fp+1) + (*Handle)(&target).Get(buf) + if target >= f.atoms { + panic(fmt.Errorf("@%#x illegal reloc, target %#x > f.atoms(%#x)", fp, target, f.atoms)) + } + + ttyp, _ := f.getInfo(target) + if ttyp >= 0xfe { + panic(fmt.Errorf("@%#x reloc, points to unused @%#x", fp, target)) + } + + if ttyp == 0xfd { + panic(fmt.Errorf("@%#x reloc, points to reloc @%#x", fp, target)) + } + case typ == 0xfe: + if size < 2 { + panic(fmt.Errorf("@%#x illegal free block, atoms %d < 2", fp, size)) + } + + if fp>>4 < f.canfree { + panic(fmt.Errorf("@%#x illegal free block @ < f.canfree", fp)) + } + + f.read(buf[:22], fp) + var prev, next, sz int64 + (*Handle)(&prev).Get(buf[1:]) + (*Handle)(&next).Get(buf[8:]) + f.checkPrevNext(fp, prev, next) + f.read(buf[:7], fp+size<<4-8) + (*Handle)(&sz).Get(buf) + if sz != size { + panic(fmt.Errorf("@%#x mismatch size, %d != %d", fp, sz, size)) + } + + if last != 0xfe { + panic(fmt.Errorf("@%#x free atom, last @%#x: %#x != 0xff", fp, fp+size<<4-1, last)) + } + freemap[fp>>4] = size + freeblocks++ + case typ == 0xff: + f.read(buf[:14], fp+1) + var prev, next int64 + (*Handle)(&prev).Get(buf) + (*Handle)(&next).Get(buf[7:]) + f.checkPrevNext(fp, prev, next) + if last != 0xff { + panic(fmt.Errorf("@%#x free atom, last @%#x: %#x != 0xff", fp, fp+size<<4-1, last)) + } + freemap[fp>>4] = size + freeblocks++ + } + fp += size << 4 + } + usedblocks = totalblocks - freeblocks + + // check free table + for size := len(f.freetab) - 1; size > 0; size-- { + var prev, next, fprev int64 + this := f.freetab[size] + for this != 0 { + sz, ok := freemap[this] + if !ok { + panic(fmt.Errorf("bad freetab[%d] item @%#x", size, this)) + } + + delete(freemap, this) + + if sz < int64(size) { + panic(fmt.Errorf("bad freetab[%d] item size @%#x %d", size, this, sz)) + } + + if sz == 1 { + f.read(buf[:15], this<<4) + (*Handle)(&fprev).Get(buf[1:]) + if fprev != prev { + panic(fmt.Errorf("bad fprev %#x, exp %#x", fprev, prev)) + } + + (*Handle)(&next).Get(buf[8:]) + } else { + f.read(buf, this<<4) + (*Handle)(&fprev).Get(buf[1:]) + if fprev != prev { + panic(fmt.Errorf("bad fprev %#x, exp %#x", fprev, prev)) + } + var fsz int64 + (*Handle)(&fsz).Get(buf[15:]) + if fsz != sz { + panic(fmt.Errorf("bad fsz %d @%#x, exp %#x", fsz, this<<4, sz)) + } + + (*Handle)(&next).Get(buf[8:]) + } + + prev, this = this, next + } + } + + if n := len(freemap); n != 0 { + for h, s := range freemap { + panic(fmt.Errorf("%d lost free blocks in freemap, e.g. %d free atoms @%#x", n, s, h)) + } + } + + return + +} + +func (f *File) checkPrevNext(fp, prev, next int64) { + if prev != 0 && prev < f.canfree { + panic(fmt.Errorf("@%#x illegal free atom, prev %#x < f.canfree(%#x)", fp, prev, f.canfree)) + } + + if prev >= f.atoms { + panic(fmt.Errorf("@%#x illegal free atom, prev %#x > f.atoms", fp, prev)) + } + + if next != 0 && next < f.canfree { + panic(fmt.Errorf("@%#x illegal free atom, next %#x < f.canfree(%#x)", fp, next, f.canfree)) + } + + if next >= f.atoms { + panic(fmt.Errorf("@%#x illegal free atom, next %#x > f.atoms", fp, next)) + } +} + +func reaudit(t *testing.T, f *File, fn string) (of *File) { + var err error + if _, _, err := f.audit(); err != nil { + t.Fatal(err) + } + + if err := f.Close(); err != nil { + t.Fatal(err) + } + + f = nil + runtime.GC() + if of, err = fopen(fn); err != nil { + t.Fatal(err) + } + + if _, _, err := of.audit(); err != nil { + t.Fatal(err) + } + + return +} + +func TestCreate(t *testing.T) { + dir, name := temp() + defer os.RemoveAll(dir) + + f, err := fcreate(name) + if err != nil { + t.Fatal(err) + } + + defer func() { + err := os.Remove(name) + if err != nil { + t.Fatal(err) + } + }() + + f.Accessor().Sync() + probed(t, f) + if err = f.Close(); err != nil { + t.Log(f.f.(*balancedAcid).nesting) + t.Fatal(err) + } + + b, err := ioutil.ReadFile(name) + if err != nil { + t.Fatal(err) + } + + x := b[:16] + if !bytes.Equal(x, hdr) { + t.Fatalf("\n% x\n% x", x, hdr) + } + + x = b[16:32] + if !bytes.Equal(x, empty) { + t.Fatalf("\n% x\n% x", x, hdr) + } +} + +func TestOpen(t *testing.T) { + dir, name := temp() + defer os.RemoveAll(dir) + + f, err := fcreate(name) + if err != nil { + t.Fatal(err) + } + + defer func() { + probed(t, f) + ec := f.Close() + er := os.Remove(name) + if ec != nil { + t.Fatal(ec) + } + + if er != nil { + t.Fatal(er) + } + }() + + if err := f.Close(); err != nil { + t.Fatal(err) + } + + if f, err = fopen(name); err != nil { + t.Fatal(err) + } + + for i, p := range f.freetab { + if p != 0 { + t.Fatal(i+1, p) + } + } +} + +func alloc(f *File, b []byte) (y int64) { + if h, err := f.Alloc(b); err != nil { + panic(err) + } else { + y = int64(h) + } + return +} + +func realloc(f *File, atom int64, b []byte, keepHandle bool) (y int64) { + if h, err := f.Realloc(Handle(atom), b, keepHandle); err != nil { + panic(err) + } else { + y = int64(h) + } + return +} + +func testContentEncodingDecoding(t *testing.T, min, max int) { + dir, name := temp() + defer os.RemoveAll(dir) + + f, err := fcreate(name) + if err != nil { + t.Fatal(err) + } + + defer func() { + ec := f.Close() + er := os.Remove(name) + if ec != nil { + t.Fatal(ec) + } + + if er != nil { + t.Fatal(er) + } + }() + + b := make([]byte, max) + r, err := mathutil.NewFC32(math.MinInt32, math.MaxInt32, true) + if err != nil { + t.Fatal(err) + } + + blocks := int64(3) + a := make([]int64, 0, 4*(max-min+1)) + for cl := min; cl <= max; cl++ { + src := b[:cl] + for i := range src { + b[i] = byte(r.Next()) + } + a = append(a, alloc(f, src)) + blocks++ + if cl == 0 { + continue + } + + for i := range src { + b[i] = byte(r.Next()) + } + src[cl-1] = 0xfd + a = append(a, alloc(f, src)) + blocks++ + for i := range src { + b[i] = byte(r.Next()) + } + src[cl-1] = 0xfe + a = append(a, alloc(f, src)) + blocks++ + for i := range src { + b[i] = byte(r.Next()) + } + src[cl-1] = 0xff + a = append(a, alloc(f, src)) + blocks++ + } + + f.Accessor().Sync() + probed(t, f) + if err := f.Close(); err != nil { + t.Fatal(err) + } + + f = nil + runtime.GC() + if f, err = fopen(name); err != nil { + t.Fatal(err) + } + + r.Seek(0) + ai := 0 + for cl := min; cl <= max; cl++ { + h := a[ai] + ai++ + src := b[:cl] + for i := range src { + b[i] = byte(r.Next()) + } + got, _ := f.readUsed(h) + if !bytes.Equal(src, got) { + t.Fatalf("cl %d atom %#x\nexp % x\ngot % x", cl, h, src, got) + } + if cl == 0 { + continue + } + + for i := range src { + b[i] = byte(r.Next()) + } + src[cl-1] = 0xfd + h = a[ai] + ai++ + got, _ = f.readUsed(h) + if !bytes.Equal(src, got) { + t.Fatalf("cl %d atom %#x\nexp % x\ngot % x", cl, h, src, got) + } + + for i := range src { + b[i] = byte(r.Next()) + } + src[cl-1] = 0xfe + h = a[ai] + ai++ + got, _ = f.readUsed(h) + if !bytes.Equal(src, got) { + t.Fatalf("cl %d atom %#x\nexp % x\ngot % x", cl, h, src, got) + } + + for i := range src { + b[i] = byte(r.Next()) + } + src[cl-1] = 0xff + h = a[ai] + ai++ + got, _ = f.readUsed(h) + if !bytes.Equal(src, got) { + t.Fatalf("cl %d atom %#x\nexp % x\ngot % x", cl, h, src, got) + } + } + + auditblocks, _, err := f.audit() + if err != nil { + t.Fatal(err) + } + + if auditblocks != blocks { + t.Fatal(auditblocks, blocks) + } + + if f = reaudit(t, f, name); err != nil { + t.Fatal(err) + } +} + +func TestContentEncodingDecoding(t *testing.T) { + testContentEncodingDecoding(t, 0, 1024) + testContentEncodingDecoding(t, 61680-17, 61680) +} + +type freeItem struct { + size int64 + head int64 +} + +func (f *File) reportFree() (report []freeItem) { + for size, head := range f.freetab { + if size != 0 && head != 0 { + report = append(report, freeItem{int64(size), head}) + } + } + return +} + +func free(f *File, h int64) { + if err := f.Free(Handle(h)); err != nil { + panic(err) + } +} + +func testFreeTail(t *testing.T, b []byte) { + dir, name := temp() + defer os.RemoveAll(dir) + + f, err := fcreate(name) + if err != nil { + t.Fatal(err) + } + + defer func() { + ec := f.Close() + er := os.Remove(name) + if ec != nil { + t.Fatal(ec) + } + + if er != nil { + t.Fatal(er) + } + }() + + fs0 := f.atoms + used0, total0, err := f.audit() + if err != nil { + panic(err) + } + + if used0 != total0 { + t.Fatal(used0, total0) + } + + handle := alloc(f, b) + free(f, handle) + if fs1 := f.atoms; fs1 != fs0 { + t.Fatal(fs1, fs0) + } + + if rep := f.reportFree(); len(rep) != 0 { + t.Fatal(rep) + } + + if err := f.Close(); err != nil { + t.Fatal(err) + } + + f = nil + runtime.GC() + if f, err = fopen(name); err != nil { + t.Fatal(err) + } + + used, total, err := f.audit() + if err != nil { + panic(err) + } + + if used != used0 { + t.Fatal(used, used0) + } + + if total != total0 { + t.Fatal(total, total0) + } +} + +func TestFreeTail(t *testing.T) { + b := make([]byte, 61680) + for n := 0; n <= 253+16; n++ { + data := b[:n] + testFreeTail(t, data) + if n == 0 { + continue + } + + data[n-1] = 0xff + testFreeTail(t, data) + data[n-1] = 0 + } + + for n := 61680 - 16; n <= 61680; n++ { + data := b[:n] + testFreeTail(t, data) + data[n-1] = 0xff + testFreeTail(t, data) + data[n-1] = 0 + } +} + +func testFreeTail2(t *testing.T, b []byte) { + dir, name := temp() + defer os.RemoveAll(dir) + + f, err := fcreate(name) + if err != nil { + t.Fatal(err) + } + + defer func() { + ec := f.Close() + er := os.Remove(name) + if ec != nil { + t.Fatal(ec) + } + + if er != nil { + t.Fatal(er) + } + }() + + fs0 := f.atoms + used0, total0, err := f.audit() + if err != nil { + panic(err) + } + + if used0 != total0 { + t.Fatal(used0, total0) + } + + handle := alloc(f, b) + handle2 := alloc(f, b) + free(f, handle) + free(f, handle2) + if fs1 := f.atoms; fs1 != fs0 { + t.Fatal(fs1, fs0) + } + + if rep := f.reportFree(); len(rep) != 0 { + t.Fatal(rep) + } + + if err := f.Close(); err != nil { + t.Fatal(err) + } + + f = nil + runtime.GC() + if f, err = fopen(name); err != nil { + t.Fatal(err) + } + + used, total, err := f.audit() + if err != nil { + panic(err) + } + + if used != used0 { + t.Fatal(used, used0) + } + + if total != total0 { + t.Fatal(total, total0) + } +} + +func TestFreeTail2(t *testing.T) { + b := make([]byte, 61680) + for n := 0; n <= 253+16; n++ { + data := b[:n] + testFreeTail2(t, data) + if n == 0 { + continue + } + + data[n-1] = 0xff + testFreeTail2(t, data) + data[n-1] = 0 + } + + for n := 61680 - 16; n <= 61680; n++ { + data := b[:n] + testFreeTail2(t, data) + data[n-1] = 0xff + testFreeTail2(t, data) + data[n-1] = 0 + } +} + +func testFreeIsolated(t *testing.T, b []byte) { + dir, name := temp() + defer os.RemoveAll(dir) + + f, err := fcreate(name) + if err != nil { + t.Fatal(err) + } + + defer func() { + ec := f.Close() + er := os.Remove(name) + if ec != nil { + t.Fatal(ec) + } + + if er != nil { + t.Fatal(er) + } + }() + + rqAtoms := rq2Atoms(len(b)) + left := alloc(f, nil) + handle := alloc(f, b) + right := alloc(f, nil) + + fs0 := f.atoms + used0, total0, err := f.audit() + if err != nil { + panic(err) + } + + if used0 != total0 { + t.Fatal(used0, total0) + } + + free(f, handle) + if fs1 := f.atoms; fs1 != fs0 { + t.Fatal(fs1, fs0) + } + + rep := f.reportFree() + if len(rep) != 1 { + t.Fatal(rep) + } + + if x := rep[0]; x.size != rqAtoms || x.head != handle { + t.Fatal(x) + } + + used, total, err := f.audit() + if err != nil { + panic(err) + } + + if n, free := f.getSize(left); n != 1 || free { + t.Fatal(n, free) + } + + if n, free := f.getSize(right); n != 1 || free { + t.Fatal(n, free) + } + + if used != used0-1 { + t.Fatal(used, used0) + } + + if total != total0 { + t.Fatal(total, total0) + } + + if free := total - used; free != 1 { + t.Fatal(free) + } + + // verify persisted file correct + if err := f.Close(); err != nil { + t.Fatal(err) + } + + f = nil + runtime.GC() + if f, err = fopen(name); err != nil { + t.Fatal(err) + } + + if fs1 := f.atoms; fs1 != fs0 { + t.Fatal(fs1, fs0) + } + + rep = f.reportFree() + if len(rep) != 1 { + t.Fatal(rep) + } + + if x := rep[0]; x.size != rqAtoms || x.head != handle { + t.Fatal(x) + } + + used, total, err = f.audit() + if err != nil { + panic(err) + } + + if n, free := f.getSize(left); n != 1 || free { + t.Fatal(n, free) + } + + if n, free := f.getSize(right); n != 1 || free { + t.Fatal(n, free) + } + + if used != used0-1 { + t.Fatal(used, used0) + } + + if total != total0 { + t.Fatal(total, total0) + } + + if free := total - used; free != 1 { + t.Fatal(free) + } + +} + +func TestFreeIsolated(t *testing.T) { + b := make([]byte, 61680) + for n := 0; n <= 253+16; n++ { + data := b[:n] + testFreeIsolated(t, data) + } + + for n := 61680 - 16; n <= 61680; n++ { + data := b[:n] + testFreeIsolated(t, data) + } +} + +func testFreeBlockList(t *testing.T, a, b int) { + var h [2]int64 + + t.Log(a, b) + dir, name := temp() + defer os.RemoveAll(dir) + + f, err := fcreate(name) + if err != nil { + t.Fatal(err) + } + + defer func() { + if f != nil { + if err := f.Close(); err != nil { + t.Fatal(err) + } + } + + f = nil + runtime.GC() + os.Remove(name) + }() + + used0, total0, err := f.audit() + if err != nil { + t.Fatal(err) + } + + alloc(f, nil) + h[0] = alloc(f, nil) + alloc(f, nil) + h[1] = alloc(f, nil) + alloc(f, nil) + + if err := f.Close(); err != nil { + t.Fatal(err) + } + + f = nil + runtime.GC() + if f, err = fopen(name); err != nil { + t.Fatal(err) + } + + used, total, err := f.audit() + if err != nil { + t.Fatal(err) + } + + if used-used0 != 5 || total-total0 != 5 || used != total { + t.Fatal(used0, total0, used, total) + } + + free(f, h[a]) + free(f, h[b]) + + used, total, err = f.audit() + if err != nil { + t.Fatal(err) + } + + if used-used0 != 3 || total-total0 != 5 || total-used != 2 { + t.Fatal(used0, total0, used, total) + } + + if err := f.Close(); err != nil { + t.Fatal(err) + } + + f = nil + runtime.GC() + if f, err = fopen(name); err != nil { + t.Fatal(err) + } + + used, total, err = f.audit() + if err != nil { + t.Fatal(err) + } + + if used-used0 != 3 || total-total0 != 5 || total-used != 2 { + t.Fatal(used0, total0, used, total) + } +} + +func TestFreeBlockList(t *testing.T) { + testFreeBlockList(t, 0, 1) + testFreeBlockList(t, 1, 0) +} + +func testFreeBlockList2(t *testing.T, a, b, c int) { + var h [3]int64 + + dir, name := temp() + defer os.RemoveAll(dir) + + f, err := fcreate(name) + if err != nil { + t.Fatal(err) + } + + defer func() { + if f != nil { + if err := f.Close(); err != nil { + t.Fatal(err) + } + } + + f = nil + runtime.GC() + os.Remove(name) + }() + + used0, total0, err := f.audit() + if err != nil { + t.Fatal(err) + } + + alloc(f, nil) + h[0] = alloc(f, nil) + alloc(f, nil) + h[1] = alloc(f, nil) + alloc(f, nil) + h[2] = alloc(f, nil) + alloc(f, nil) + + if err := f.Close(); err != nil { + t.Fatal(err) + } + + f = nil + runtime.GC() + if f, err = fopen(name); err != nil { + t.Fatal(err) + } + + used, total, err := f.audit() + if err != nil { + t.Fatal(err) + } + + if used-used0 != 7 || total-total0 != 7 || used != total { + t.Fatal(used0, total0, used, total) + } + + free(f, h[a]) + free(f, h[b]) + free(f, h[c]) + + used, total, err = f.audit() + if err != nil { + t.Fatal(err) + } + + if used-used0 != 4 || total-total0 != 7 || total-used != 3 { + t.Fatal(used0, total0, used, total) + } + + if err := f.Close(); err != nil { + t.Fatal(err) + } + + f = nil + runtime.GC() + if f, err = fopen(name); err != nil { + t.Fatal(err) + } + + used, total, err = f.audit() + if err != nil { + t.Fatal(err) + } + + if used-used0 != 4 || total-total0 != 7 || total-used != 3 { + t.Fatal(used0, total0, used, total) + } +} + +func TestFreeBlockList2(t *testing.T) { + testFreeBlockList2(t, 0, 1, 2) + testFreeBlockList2(t, 0, 2, 1) + testFreeBlockList2(t, 1, 0, 2) + testFreeBlockList2(t, 1, 2, 0) + testFreeBlockList2(t, 2, 0, 1) + testFreeBlockList2(t, 2, 1, 0) +} + +var crng *mathutil.FC32 + +func init() { + var err error + if crng, err = mathutil.NewFC32(0, math.MaxInt32, true); err != nil { + panic(err) + } +} + +func content(b []byte, h int64) (c []byte) { + crng.Seed(h) + crng.Seek(0) + c = b[:crng.Next()%61681] + for i := range c { + c[i] = byte(crng.Next()) + } + return +} + +func testFreeBlockList3(t *testing.T, n, mod int) { + rng, err := mathutil.NewFC32(0, n-1, true) + if err != nil { + t.Fatal(err) + } + + dir, name := temp() + defer os.RemoveAll(dir) + + f, err := fcreate(name) + if err != nil { + t.Fatal(err) + } + + defer func() { + if f != nil { + if err := f.Close(); err != nil { + t.Fatal(err) + } + } + + f = nil + runtime.GC() + os.Remove(name) + }() + + ha := make([]int64, n) + b := make([]byte, 61680) + for i := range ha { + h := f.atoms + ha[i] = h + c := content(b, h) + if alloc(f, c) != h { + t.Fatal(h) + } + } + f = reaudit(t, f, name) + del := map[int64]bool{} + for _ = range ha { + i := rng.Next() + if i%mod != 0 { + h := ha[i] + free(f, h) + del[h] = true + } + } + f = reaudit(t, f, name) + for _, h := range ha { + if !del[h] { + exp := content(b, h) + got, _ := f.readUsed(h) + if !bytes.Equal(exp, got) { + t.Fatal(len(got), len(exp)) + } + } + } +} + +func TestFreeBlockList3(t *testing.T) { + testFreeBlockList3(t, 111, 1) + testFreeBlockList3(t, 151, 2) + testFreeBlockList3(t, 170, 3) + testFreeBlockList3(t, 170, 4) +} + +func TestRealloc1(t *testing.T) { + dir, name := temp() + defer os.RemoveAll(dir) + + f, err := fcreate(name) + if err != nil { + t.Fatal(err) + } + + defer func() { + if f != nil { + if err := f.Close(); err != nil { + t.Fatal(err) + } + } + + f = nil + runtime.GC() + os.Remove(name) + }() + + b := make([]byte, 61680) + c := content(b, 10) + + h10 := alloc(f, nil) + h20 := alloc(f, nil) + + used0, total0, err := f.audit() + if err != nil { + t.Fatal(err) + } + + exp := c[:15] + if handle := realloc(f, h10, exp, false); handle != h10 { + t.Fatal(handle, h10) + } + + if got, _ := f.readUsed(h10); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + if got, _ := f.readUsed(h20); len(got) != 0 { + t.Fatal(len(got), 0) + } + + f = reaudit(t, f, name) + + if got, _ := f.readUsed(h10); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + if got, _ := f.readUsed(h20); len(got) != 0 { + t.Fatal(len(got), 0) + } + + used, total, err := f.audit() + if err != nil { + t.Fatal(err) + } + + if difused, diftotal, free := used-used0, total-total0, total-used; difused != 0 || diftotal != 0 || free != 0 { + t.Fatal(difused, diftotal, free) + } +} + +func TestRealloc1Keep(t *testing.T) { + dir, name := temp() + defer os.RemoveAll(dir) + + f, err := fcreate(name) + if err != nil { + t.Fatal(err) + } + + defer func() { + if f != nil { + if err := f.Close(); err != nil { + t.Fatal(err) + } + } + + f = nil + runtime.GC() + os.Remove(name) + }() + + b := make([]byte, 61680) + c := content(b, 10) + + h10 := alloc(f, nil) + h20 := alloc(f, nil) + + used0, total0, err := f.audit() + if err != nil { + t.Fatal(err) + } + + exp := c[:15] + if handle := realloc(f, h10, exp, true); handle != h10 { + t.Fatal(handle, h10) + } + + if got, _ := f.readUsed(h10); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + if got, _ := f.readUsed(h20); len(got) != 0 { + t.Fatal(len(got), 0) + } + + f = reaudit(t, f, name) + + if got, _ := f.readUsed(h10); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + if got, _ := f.readUsed(h20); len(got) != 0 { + t.Fatal(len(got), 0) + } + + used, total, err := f.audit() + if err != nil { + t.Fatal(err) + } + + if difused, diftotal, free := used-used0, total-total0, total-used; difused != 0 || diftotal != 0 || free != 0 { + t.Fatal(difused, diftotal, free) + } +} + +func TestRealloc2(t *testing.T) { + dir, name := temp() + defer os.RemoveAll(dir) + + f, err := fcreate(name) + if err != nil { + t.Fatal(err) + } + + defer func() { + if f != nil { + if err := f.Close(); err != nil { + t.Fatal(err) + } + } + + f = nil + runtime.GC() + os.Remove(name) + }() + + b := make([]byte, 61680) + c := content(b, 10) + + h10 := alloc(f, c[:31]) + h20 := alloc(f, nil) + + used0, total0, err := f.audit() + if err != nil { + t.Fatal(err) + } + + exp := c[:15] + if handle := realloc(f, h10, exp, false); handle != h10 { + t.Fatal(handle, h10) + } + + if got, _ := f.readUsed(h10); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + if got, _ := f.readUsed(h20); len(got) != 0 { + t.Fatal(len(got), 0) + } + + f = reaudit(t, f, name) + + if got, _ := f.readUsed(h10); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + if got, _ := f.readUsed(h20); len(got) != 0 { + t.Fatal(len(got), 0) + } + + used, total, err := f.audit() + if err != nil { + t.Fatal(err) + } + + if difused, diftotal, free := used-used0, total-total0, total-used; difused != 0 || diftotal != 1 || free != 1 { + t.Fatal(difused, diftotal, free) + } +} + +func TestRealloc2Keep(t *testing.T) { + dir, name := temp() + defer os.RemoveAll(dir) + + f, err := fcreate(name) + if err != nil { + t.Fatal(err) + } + + defer func() { + if f != nil { + if err := f.Close(); err != nil { + t.Fatal(err) + } + } + + f = nil + runtime.GC() + os.Remove(name) + }() + + b := make([]byte, 61680) + c := content(b, 10) + + h10 := alloc(f, c[:31]) + h20 := alloc(f, nil) + + used0, total0, err := f.audit() + if err != nil { + t.Fatal(err) + } + + exp := c[:15] + if handle := realloc(f, h10, exp, true); handle != h10 { + t.Fatal(handle, h10) + } + + if got, _ := f.readUsed(h10); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + if got, _ := f.readUsed(h20); len(got) != 0 { + t.Fatal(len(got), 0) + } + + f = reaudit(t, f, name) + + if got, _ := f.readUsed(h10); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + if got, _ := f.readUsed(h20); len(got) != 0 { + t.Fatal(len(got), 0) + } + + used, total, err := f.audit() + if err != nil { + t.Fatal(err) + } + + if difused, diftotal, free := used-used0, total-total0, total-used; difused != 0 || diftotal != 1 || free != 1 { + t.Fatal(difused, diftotal, free) + } +} + +func TestRealloc3(t *testing.T) { + dir, name := temp() + defer os.RemoveAll(dir) + + f, err := fcreate(name) + if err != nil { + t.Fatal(err) + } + + defer func() { + if f != nil { + if err := f.Close(); err != nil { + t.Fatal(err) + } + } + + f = nil + runtime.GC() + os.Remove(name) + }() + + b := make([]byte, 61680) + c := content(b, 10) + + h10 := alloc(f, nil) + h20 := alloc(f, nil) + + used0, total0, err := f.audit() + if err != nil { + t.Fatal(err) + } + + exp := c[:31] + var handle int64 + if handle = realloc(f, h10, exp, false); handle == h10 { + t.Fatal(handle, h10) + } + + if got, _ := f.readUsed(handle); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + if got, _ := f.readUsed(h20); len(got) != 0 { + t.Fatal(len(got), 0) + } + + f = reaudit(t, f, name) + + if got, _ := f.readUsed(handle); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + if got, _ := f.readUsed(h20); len(got) != 0 { + t.Fatal(len(got), 0) + } + + used, total, err := f.audit() + if err != nil { + t.Fatal(err) + } + + if difused, diftotal, free := used-used0, total-total0, total-used; difused != 0 || diftotal != 1 || free != 1 { + t.Fatal(difused, diftotal, free) + } +} + +func TestRealloc3Keep(t *testing.T) { + dir, name := temp() + defer os.RemoveAll(dir) + + f, err := fcreate(name) + if err != nil { + t.Fatal(err) + } + + defer func() { + if f != nil { + if err := f.Close(); err != nil { + t.Fatal(err) + } + } + + f = nil + runtime.GC() + os.Remove(name) + }() + + b := make([]byte, 61680) + c := content(b, 10) + + h10 := alloc(f, nil) + h20 := alloc(f, nil) + + used0, total0, err := f.audit() + if err != nil { + t.Fatal(err) + } + + exp := c[:31] + var handle int64 + if handle = realloc(f, h10, exp, true); handle != h10 { + t.Fatal(handle, h10) + } + + if got, _ := f.readUsed(handle); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + if got, _ := f.readUsed(h20); len(got) != 0 { + t.Fatal(len(got), 0) + } + + f = reaudit(t, f, name) + + if got, _ := f.readUsed(handle); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + if got, _ := f.readUsed(h20); len(got) != 0 { + t.Fatal(len(got), 0) + } + + used, total, err := f.audit() + if err != nil { + t.Fatal(err) + } + + if difused, diftotal, free := used-used0, total-total0, total-used; difused != 1 || diftotal != 1 || free != 0 { + t.Fatal(difused, diftotal, free) + } +} + +func TestRealloc4Keep(t *testing.T) { + dir, name := temp() + defer os.RemoveAll(dir) + + f, err := fcreate(name) + if err != nil { + t.Fatal(err) + } + + defer func() { + if f != nil { + if err := f.Close(); err != nil { + t.Fatal(err) + } + } + + f = nil + runtime.GC() + os.Remove(name) + }() + + b := make([]byte, 61680) + c := content(b, 10) + + h10 := alloc(f, c[:31]) + h20 := alloc(f, nil) + + used0, total0, err := f.audit() + if err != nil { + t.Fatal(err) + } + + exp := c[:47] + var handle int64 + if handle = realloc(f, h10, exp, true); handle != h10 { + t.Fatal(handle, h10) + } + + if got, _ := f.readUsed(handle); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + if got, _ := f.readUsed(h20); len(got) != 0 { + t.Fatal(len(got), 0) + } + + f = reaudit(t, f, name) + + if got, _ := f.readUsed(handle); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + if got, _ := f.readUsed(h20); len(got) != 0 { + t.Fatal(len(got), 0) + } + + used, total, err := f.audit() + if err != nil { + t.Fatal(err) + } + + if difused, diftotal, free := used-used0, total-total0, total-used; difused != 1 || diftotal != 2 || free != 1 { + t.Fatal(difused, diftotal, free) + } +} + +func TestRealloc5(t *testing.T) { + dir, name := temp() + defer os.RemoveAll(dir) + + f, err := fcreate(name) + if err != nil { + t.Fatal(err) + } + + defer func() { + if f != nil { + if err := f.Close(); err != nil { + t.Fatal(err) + } + } + + f = nil + runtime.GC() + os.Remove(name) + }() + + b := make([]byte, 61680) + c := content(b, 10) + + h10 := alloc(f, nil) + h15 := alloc(f, nil) + h20 := alloc(f, nil) + + used0, total0, err := f.audit() + if err != nil { + t.Fatal(err) + } + + free(f, h15) + exp := c[:31] + var handle int64 + if handle = realloc(f, h10, exp, false); handle != h10 { + t.Fatal(handle, h10) + } + + if got, _ := f.readUsed(handle); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + if got, _ := f.readUsed(h20); len(got) != 0 { + t.Fatal(len(got), 0) + } + + f = reaudit(t, f, name) + + if got, _ := f.readUsed(handle); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + if got, _ := f.readUsed(h20); len(got) != 0 { + t.Fatal(len(got), 0) + } + + used, total, err := f.audit() + if err != nil { + t.Fatal(err) + } + + if difused, diftotal, free := used-used0, total-total0, total-used; difused != -1 || diftotal != -1 || free != 0 { + t.Fatal(difused, diftotal, free) + } +} + +func TestRealloc5Keep(t *testing.T) { + dir, name := temp() + defer os.RemoveAll(dir) + + f, err := fcreate(name) + if err != nil { + t.Fatal(err) + } + + defer func() { + if f != nil { + if err := f.Close(); err != nil { + t.Fatal(err) + } + } + + f = nil + runtime.GC() + os.Remove(name) + }() + + b := make([]byte, 61680) + c := content(b, 10) + + h10 := alloc(f, nil) + h15 := alloc(f, nil) + h20 := alloc(f, nil) + + used0, total0, err := f.audit() + if err != nil { + t.Fatal(err) + } + + free(f, h15) + exp := c[:31] + var handle int64 + if handle = realloc(f, h10, exp, true); handle != h10 { + t.Fatal(handle, h10) + } + + if got, _ := f.readUsed(handle); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + if got, _ := f.readUsed(h20); len(got) != 0 { + t.Fatal(len(got), 0) + } + + f = reaudit(t, f, name) + + if got, _ := f.readUsed(handle); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + if got, _ := f.readUsed(h20); len(got) != 0 { + t.Fatal(len(got), 0) + } + + used, total, err := f.audit() + if err != nil { + t.Fatal(err) + } + + if difused, diftotal, free := used-used0, total-total0, total-used; difused != -1 || diftotal != -1 || free != 0 { + t.Fatal(difused, diftotal, free) + } +} + +func TestRealloc6(t *testing.T) { + dir, name := temp() + defer os.RemoveAll(dir) + + f, err := fcreate(name) + if err != nil { + t.Fatal(err) + } + + defer func() { + if f != nil { + if err := f.Close(); err != nil { + t.Fatal(err) + } + } + + f = nil + runtime.GC() + os.Remove(name) + }() + + b := make([]byte, 61680) + c := content(b, 10) + + h10 := alloc(f, nil) + h15 := alloc(f, c[:31]) + h20 := alloc(f, nil) + + used0, total0, err := f.audit() + if err != nil { + t.Fatal(err) + } + + free(f, h15) + exp := c[:31] + var handle int64 + if handle = realloc(f, h10, exp, false); handle != h10 { + t.Fatal(handle, h10) + } + + if got, _ := f.readUsed(handle); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + if got, _ := f.readUsed(h20); len(got) != 0 { + t.Fatal(len(got), 0) + } + + f = reaudit(t, f, name) + + if got, _ := f.readUsed(handle); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + if got, _ := f.readUsed(h20); len(got) != 0 { + t.Fatal(len(got), 0) + } + + used, total, err := f.audit() + if err != nil { + t.Fatal(err) + } + + if difused, diftotal, free := used-used0, total-total0, total-used; difused != -1 || diftotal != 0 || free != 1 { + t.Fatal(difused, diftotal, free) + } +} + +func TestRealloc6Keep(t *testing.T) { + dir, name := temp() + defer os.RemoveAll(dir) + + f, err := fcreate(name) + if err != nil { + t.Fatal(err) + } + + defer func() { + if f != nil { + if err := f.Close(); err != nil { + t.Fatal(err) + } + } + + f = nil + runtime.GC() + os.Remove(name) + }() + + b := make([]byte, 61680) + c := content(b, 10) + + h10 := alloc(f, nil) + h15 := alloc(f, c[:31]) + h20 := alloc(f, nil) + + used0, total0, err := f.audit() + if err != nil { + t.Fatal(err) + } + + free(f, h15) + exp := c[:31] + var handle int64 + if handle = realloc(f, h10, exp, true); handle != h10 { + t.Fatal(handle, h10) + } + + if got, _ := f.readUsed(handle); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + if got, _ := f.readUsed(h20); len(got) != 0 { + t.Fatal(len(got), 0) + } + + f = reaudit(t, f, name) + + if got, _ := f.readUsed(handle); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + if got, _ := f.readUsed(h20); len(got) != 0 { + t.Fatal(len(got), 0) + } + + used, total, err := f.audit() + if err != nil { + t.Fatal(err) + } + + if difused, diftotal, free := used-used0, total-total0, total-used; difused != -1 || diftotal != 0 || free != 1 { + t.Fatal(difused, diftotal, free) + } +} + +func TestRelocRealloc1(t *testing.T) { + dir, name := temp() + defer os.RemoveAll(dir) + + f, err := fcreate(name) + if err != nil { + t.Fatal(err) + } + + defer func() { + if f != nil { + if err := f.Close(); err != nil { + t.Fatal(err) + } + } + + f = nil + runtime.GC() + os.Remove(name) + }() + + b := make([]byte, 61680) + + h10 := alloc(f, nil) + h20 := alloc(f, nil) + var handle int64 + if handle = realloc(f, h10, b[:31], true); handle != h10 { + t.Fatal(handle, h10) + } + + used0, total0, err := f.audit() // c+3, c+3 + if err != nil { + t.Fatal(err) + } + + c := content(b, 10) + exp := c[:15] + if handle = realloc(f, h10, exp, false); handle != h10 { + t.Fatal(handle, h10) + } + + if got, _ := f.readUsed(h10); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + if got, _ := f.readUsed(h20); len(got) != 0 { + t.Fatal(len(got), 0) + } + + f = reaudit(t, f, name) + + if got, _ := f.readUsed(h10); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + if got, _ := f.readUsed(h20); len(got) != 0 { + t.Fatal(len(got), 0) + } + + used, total, err := f.audit() // c+2, c+2 + if err != nil { + t.Fatal(err) + } + + if difused, diftotal, free := used-used0, total-total0, total-used; difused != -1 || diftotal != -1 || free != 0 { + t.Fatal(difused, diftotal, free) + } +} + +func TestRelocRealloc1Keep(t *testing.T) { + dir, name := temp() + defer os.RemoveAll(dir) + + f, err := fcreate(name) + if err != nil { + t.Fatal(err) + } + + defer func() { + if f != nil { + if err := f.Close(); err != nil { + t.Fatal(err) + } + } + + f = nil + runtime.GC() + os.Remove(name) + }() + + b := make([]byte, 61680) + + h10 := alloc(f, nil) + h20 := alloc(f, nil) + var handle int64 + if handle = realloc(f, h10, b[:31], true); handle != h10 { + t.Fatal(handle, h10) + } + + used0, total0, err := f.audit() // c+3, c+3 + if err != nil { + t.Fatal(err) + } + + c := content(b, 10) + exp := c[:15] + if handle = realloc(f, h10, exp, true); handle != h10 { + t.Fatal(handle, h10) + } + + if got, _ := f.readUsed(h10); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + if got, _ := f.readUsed(h20); len(got) != 0 { + t.Fatal(len(got), 0) + } + + f = reaudit(t, f, name) + + if got, _ := f.readUsed(h10); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + if got, _ := f.readUsed(h20); len(got) != 0 { + t.Fatal(len(got), 0) + } + + used, total, err := f.audit() // c+2, c+2 + if err != nil { + t.Fatal(err) + } + + if difused, diftotal, free := used-used0, total-total0, total-used; difused != -1 || diftotal != -1 || free != 0 { + t.Fatal(difused, diftotal, free) + } +} + +func TestRelocRealloc2(t *testing.T) { + dir, name := temp() + defer os.RemoveAll(dir) + + f, err := fcreate(name) + if err != nil { + t.Fatal(err) + } + + defer func() { + if f != nil { + if err := f.Close(); err != nil { + t.Fatal(err) + } + } + + f = nil + runtime.GC() + os.Remove(name) + }() + + b := make([]byte, 61680) + + h10 := alloc(f, nil) + h20 := alloc(f, nil) + var handle int64 + if handle = realloc(f, h10, b[:31], true); handle != h10 { + t.Fatal(handle, h10) + } + + free(f, h20) + + used0, total0, err := f.audit() // c+2, c+3 + if err != nil { + t.Fatal(err) + } + + c := content(b, 10) + exp := c[:31] + if handle = realloc(f, h10, exp, false); handle != h10 { + t.Fatal(handle, h10) + } + + if got, _ := f.readUsed(h10); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + f = reaudit(t, f, name) + + if got, _ := f.readUsed(h10); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + used, total, err := f.audit() // c+1, c+1 + if err != nil { + t.Fatal(err) + } + + if difused, diftotal, free := used-used0, total-total0, total-used; difused != -1 || diftotal != -2 || free != 0 { + t.Fatal(difused, diftotal, free) + } +} + +func TestRelocRealloc2Keep(t *testing.T) { + dir, name := temp() + defer os.RemoveAll(dir) + + f, err := fcreate(name) + if err != nil { + t.Fatal(err) + } + + defer func() { + if f != nil { + if err := f.Close(); err != nil { + t.Fatal(err) + } + } + + f = nil + runtime.GC() + os.Remove(name) + }() + + b := make([]byte, 61680) + + h10 := alloc(f, nil) + h20 := alloc(f, nil) + var handle int64 + if handle = realloc(f, h10, b[:31], true); handle != h10 { + t.Fatal(handle, h10) + } + + free(f, h20) + + used0, total0, err := f.audit() // c+2, c+3 + if err != nil { + t.Fatal(err) + } + + c := content(b, 10) + exp := c[:31] + if handle = realloc(f, h10, exp, true); handle != h10 { + t.Fatal(handle, h10) + } + + if got, _ := f.readUsed(h10); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + f = reaudit(t, f, name) + + if got, _ := f.readUsed(h10); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + used, total, err := f.audit() // c+1, c+1 + if err != nil { + t.Fatal(err) + } + + if difused, diftotal, free := used-used0, total-total0, total-used; difused != -1 || diftotal != -2 || free != 0 { + t.Fatal(difused, diftotal, free) + } +} + +func TestRelocRealloc3(t *testing.T) { + dir, name := temp() + defer os.RemoveAll(dir) + + f, err := fcreate(name) + if err != nil { + t.Fatal(err) + } + + defer func() { + if f != nil { + if err := f.Close(); err != nil { + t.Fatal(err) + } + } + + f = nil + runtime.GC() + os.Remove(name) + }() + + b := make([]byte, 61680) + + h10 := alloc(f, nil) + h20 := alloc(f, b[:31]) + var handle int64 + if handle = realloc(f, h10, b[:31], true); handle != h10 { + t.Fatal(handle, h10) + } + + free(f, h20) + + used0, total0, err := f.audit() // c+2, c+3 + if err != nil { + t.Fatal(err) + } + + c := content(b, 10) + exp := c[:31] + if handle = realloc(f, h10, exp, false); handle != h10 { + t.Fatal(handle, h10) + } + + if got, _ := f.readUsed(h10); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + f = reaudit(t, f, name) + + if got, _ := f.readUsed(h10); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + used, total, err := f.audit() // c+1, c+1 + if err != nil { + t.Fatal(err) + } + + if difused, diftotal, free := used-used0, total-total0, total-used; difused != -1 || diftotal != -2 || free != 0 { + t.Fatal(difused, diftotal, free) + } +} + +func TestRelocRealloc3Keep(t *testing.T) { + dir, name := temp() + defer os.RemoveAll(dir) + + f, err := fcreate(name) + if err != nil { + t.Fatal(err) + } + + defer func() { + if f != nil { + if err := f.Close(); err != nil { + t.Fatal(err) + } + } + + f = nil + runtime.GC() + os.Remove(name) + }() + + b := make([]byte, 61680) + + h10 := alloc(f, nil) + h20 := alloc(f, b[:31]) + var handle int64 + if handle = realloc(f, h10, b[:31], true); handle != h10 { + t.Fatal(handle, h10) + } + + free(f, h20) + + used0, total0, err := f.audit() // c+2, c+3 + if err != nil { + t.Fatal(err) + } + + c := content(b, 10) + exp := c[:31] + if handle = realloc(f, h10, exp, true); handle != h10 { + t.Fatal(handle, h10) + } + + if got, _ := f.readUsed(h10); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + f = reaudit(t, f, name) + + if got, _ := f.readUsed(h10); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + used, total, err := f.audit() // c+1, c+1 + if err != nil { + t.Fatal(err) + } + + if difused, diftotal, free := used-used0, total-total0, total-used; difused != -1 || diftotal != -2 || free != 0 { + t.Fatal(difused, diftotal, free) + } +} + +func TestRelocRealloc4(t *testing.T) { + dir, name := temp() + defer os.RemoveAll(dir) + + f, err := fcreate(name) + if err != nil { + t.Fatal(err) + } + + defer func() { + if f != nil { + if err := f.Close(); err != nil { + t.Fatal(err) + } + } + + f = nil + runtime.GC() + os.Remove(name) + }() + + b := make([]byte, 61680) + + h10 := alloc(f, nil) + _ = alloc(f, nil) + var handle int64 + if handle = realloc(f, h10, b[:47], true); handle != h10 { + t.Fatal(handle, h10) + } + + _ = alloc(f, nil) + + if handle = realloc(f, h10, b[:31], true); handle != h10 { + t.Fatal(handle, h10) + } + + used0, total0, err := f.audit() // c+4, c+5 + if err != nil { + t.Fatal(err) + } + + c := content(b, 10) + exp := c[:47] + if handle = realloc(f, h10, exp, false); handle != h10 { + t.Fatal(handle, h10) + } + + if got, _ := f.readUsed(h10); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + f = reaudit(t, f, name) + + if got, _ := f.readUsed(h10); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + used, total, err := f.audit() // c+4, c+4 + if err != nil { + t.Fatal(err) + } + + if difused, diftotal, free := used-used0, total-total0, total-used; difused != 0 || diftotal != -1 || free != 0 { + t.Fatal(difused, diftotal, free) + } +} + +func TestRelocRealloc4Keep(t *testing.T) { + dir, name := temp() + defer os.RemoveAll(dir) + + f, err := fcreate(name) + if err != nil { + t.Fatal(err) + } + + defer func() { + if f != nil { + if err := f.Close(); err != nil { + t.Fatal(err) + } + } + + f = nil + runtime.GC() + os.Remove(name) + }() + + b := make([]byte, 61680) + + h10 := alloc(f, nil) + _ = alloc(f, nil) + var handle int64 + if handle = realloc(f, h10, b[:47], true); handle != h10 { + t.Fatal(handle, h10) + } + + _ = alloc(f, nil) + + if handle = realloc(f, h10, b[:31], true); handle != h10 { + t.Fatal(handle, h10) + } + + used0, total0, err := f.audit() // c+4, c+5 + if err != nil { + t.Fatal(err) + } + + c := content(b, 10) + exp := c[:47] + if handle = realloc(f, h10, exp, true); handle != h10 { + t.Fatal(handle, h10) + } + + if got, _ := f.readUsed(h10); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + f = reaudit(t, f, name) + + if got, _ := f.readUsed(h10); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + used, total, err := f.audit() // c+4, c+4 + if err != nil { + t.Fatal(err) + } + + if difused, diftotal, free := used-used0, total-total0, total-used; difused != 0 || diftotal != -1 || free != 0 { + t.Fatal(difused, diftotal, free) + } +} + +func TestRelocRealloc5(t *testing.T) { + dir, name := temp() + defer os.RemoveAll(dir) + + f, err := fcreate(name) + if err != nil { + t.Fatal(err) + } + + defer func() { + if f != nil { + if err := f.Close(); err != nil { + t.Fatal(err) + } + } + + f = nil + runtime.GC() + os.Remove(name) + }() + + b := make([]byte, 61680) + + h10 := alloc(f, nil) + _ = alloc(f, nil) + var handle int64 + if handle = realloc(f, h10, b[:31], true); handle != h10 { + t.Fatal(handle, h10) + } + + _ = alloc(f, nil) + + used0, total0, err := f.audit() // c+4, c+4 + if err != nil { + t.Fatal(err) + } + + c := content(b, 10) + exp := c[:47] + if handle = realloc(f, h10, exp, false); handle != h10 { + t.Fatal(handle, h10) + } + + if got, _ := f.readUsed(h10); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + f = reaudit(t, f, name) + + if got, _ := f.readUsed(h10); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + used, total, err := f.audit() // c+4, c+5 + if err != nil { + t.Fatal(err) + } + + if difused, diftotal, free := used-used0, total-total0, total-used; difused != 0 || diftotal != 1 || free != 1 { + t.Fatal(difused, diftotal, free) + } +} + +func TestRelocRealloc5Keep(t *testing.T) { + dir, name := temp() + defer os.RemoveAll(dir) + + f, err := fcreate(name) + if err != nil { + t.Fatal(err) + } + + defer func() { + if f != nil { + if err := f.Close(); err != nil { + t.Fatal(err) + } + } + + f = nil + runtime.GC() + os.Remove(name) + }() + + b := make([]byte, 61680) + + h10 := alloc(f, nil) + _ = alloc(f, nil) + var handle int64 + if handle = realloc(f, h10, b[:31], true); handle != h10 { + t.Fatal(handle, h10) + } + + _ = alloc(f, nil) + + used0, total0, err := f.audit() // c+4, c+4 + if err != nil { + t.Fatal(err) + } + + c := content(b, 10) + exp := c[:47] + if handle = realloc(f, h10, exp, true); handle != h10 { + t.Fatal(handle, h10) + } + + if got, _ := f.readUsed(h10); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + f = reaudit(t, f, name) + + if got, _ := f.readUsed(h10); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + used, total, err := f.audit() // c+4, c+5 + if err != nil { + t.Fatal(err) + } + + if difused, diftotal, free := used-used0, total-total0, total-used; difused != 0 || diftotal != 1 || free != 1 { + t.Fatal(difused, diftotal, free) + } +} + +func TestRelocRealloc6(t *testing.T) { + dir, name := temp() + defer os.RemoveAll(dir) + + f, err := fcreate(name) + if err != nil { + t.Fatal(err) + } + + defer func() { + if f != nil { + if err := f.Close(); err != nil { + t.Fatal(err) + } + } + + f = nil + runtime.GC() + os.Remove(name) + }() + + b := make([]byte, 61680) + + h10 := alloc(f, b[:31]) + h20 := alloc(f, nil) + _ = alloc(f, nil) + free(f, h20) + + used0, total0, err := f.audit() // c+2, c+3 + if err != nil { + t.Fatal(err) + } + + c := content(b, 10) + exp := c[:15] + if handle := realloc(f, h10, exp, false); handle != h10 { + t.Fatal(handle, h10) + } + + if got, _ := f.readUsed(h10); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + f = reaudit(t, f, name) + + if got, _ := f.readUsed(h10); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + used, total, err := f.audit() // c+2, c+3 + if err != nil { + t.Fatal(err) + } + + if difused, diftotal, free := used-used0, total-total0, total-used; difused != 0 || diftotal != 0 || free != 1 { + t.Fatal(difused, diftotal, free) + } +} + +func TestRelocRealloc6Keep(t *testing.T) { + dir, name := temp() + defer os.RemoveAll(dir) + + f, err := fcreate(name) + if err != nil { + t.Fatal(err) + } + + defer func() { + if f != nil { + if err := f.Close(); err != nil { + t.Fatal(err) + } + } + + f = nil + runtime.GC() + os.Remove(name) + }() + + b := make([]byte, 61680) + + h10 := alloc(f, b[:31]) + h20 := alloc(f, nil) + _ = alloc(f, nil) + free(f, h20) + + used0, total0, err := f.audit() // c+2, c+3 + if err != nil { + t.Fatal(err) + } + + c := content(b, 10) + exp := c[:15] + if handle := realloc(f, h10, exp, true); handle != h10 { + t.Fatal(handle, h10) + } + + if got, _ := f.readUsed(h10); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + f = reaudit(t, f, name) + + if got, _ := f.readUsed(h10); !bytes.Equal(got, exp) { + t.Fatal(len(got), len(exp)) + } + + used, total, err := f.audit() // c+2, c+3 + if err != nil { + t.Fatal(err) + } + + if difused, diftotal, free := used-used0, total-total0, total-used; difused != 0 || diftotal != 0 || free != 1 { + t.Fatal(difused, diftotal, free) + } +} + +func TestFreespaceReuse(t *testing.T) { + dir, name := temp() + defer os.RemoveAll(dir) + + f, err := fcreate(name) + if err != nil { + t.Fatal(err) + } + + defer func() { + if f != nil { + if err := f.Close(); err != nil { + t.Fatal(err) + } + } + + f = nil + runtime.GC() + os.Remove(name) + }() + + b := make([]byte, 61680) + c := content(b, 10) + + c10 := c[0 : 0+15] + c20 := c[16:63] + c50 := c[64 : 64+15] + h10 := alloc(f, c10) + h201 := alloc(f, nil) + h202 := alloc(f, nil) + h203 := alloc(f, nil) + h50 := alloc(f, c50) + free(f, h201) + free(f, h202) + free(f, h203) + used0, total0, err := f.audit() // c+2, c+3 + if err != nil { + t.Fatal(err) + } + + h20 := alloc(f, c20) + + if got, _ := f.readUsed(h10); !bytes.Equal(got, c10) { + t.Fatal() + } + + if got, _ := f.readUsed(h20); !bytes.Equal(got, c20) { + t.Fatal() + } + + if got, _ := f.readUsed(h50); !bytes.Equal(got, c50) { + t.Fatal() + } + + f = reaudit(t, f, name) + + if got, _ := f.readUsed(h10); !bytes.Equal(got, c10) { + t.Fatal() + } + + if got, _ := f.readUsed(h20); !bytes.Equal(got, c20) { + t.Fatal() + } + + if got, _ := f.readUsed(h50); !bytes.Equal(got, c50) { + t.Fatal() + } + + used, total, err := f.audit() // c+3, c+3 + if err != nil { + t.Fatal(err) + } + + if difused, diftotal, free := used-used0, total-total0, total-used; difused != 1 || diftotal != 0 || free != 0 { + t.Fatal(difused, diftotal, free) + } +} + +func TestFreespaceReuse2(t *testing.T) { + dir, name := temp() + defer os.RemoveAll(dir) + + f, err := fcreate(name) + if err != nil { + t.Fatal(err) + } + + defer func() { + if f != nil { + if err := f.Close(); err != nil { + t.Fatal(err) + } + } + + f = nil + runtime.GC() + os.Remove(name) + }() + + b := make([]byte, 61680) + c := content(b, 10) + + c10 := c[0 : 0+15] + c20 := c[16:47] + c50 := c[64 : 64+15] + h10 := alloc(f, c10) + h201 := alloc(f, nil) + h202 := alloc(f, nil) + h203 := alloc(f, nil) + h50 := alloc(f, c50) + free(f, h201) + free(f, h202) + free(f, h203) + used0, total0, err := f.audit() // c+2, c+3 + if err != nil { + t.Fatal(err) + } + + h20 := alloc(f, c20) + + if got, _ := f.readUsed(h10); !bytes.Equal(got, c10) { + t.Fatal() + } + + if got, _ := f.readUsed(h20); !bytes.Equal(got, c20) { + t.Fatal() + } + + if got, _ := f.readUsed(h50); !bytes.Equal(got, c50) { + t.Fatal() + } + + f = reaudit(t, f, name) + + if got, _ := f.readUsed(h10); !bytes.Equal(got, c10) { + t.Fatal() + } + + if got, _ := f.readUsed(h20); !bytes.Equal(got, c20) { + t.Fatal() + } + + if got, _ := f.readUsed(h50); !bytes.Equal(got, c50) { + t.Fatal() + } + + used, total, err := f.audit() // c+3, c+4 + if err != nil { + t.Fatal(err) + } + + if difused, diftotal, free := used-used0, total-total0, total-used; difused != 1 || diftotal != 1 || free != 1 { + t.Fatal(difused, diftotal, free) + } +} + +func testBug1(t *testing.T, swap bool) { + // Free lists table item for size 3856 points to list of free blocks + // NOT of size 3856 but at least 3856. + + dir, name := temp() + defer os.RemoveAll(dir) + + f, err := fcreate(name) + if err != nil { + t.Fatal(err) + } + + defer func() { + if f != nil { + if err := f.Close(); err != nil { + t.Fatal(err) + } + } + + f = nil + runtime.GC() + os.Remove(name) + }() + + _ = alloc(f, nil) + b := make([]byte, 61680) + f1 := alloc(f, b) + f2 := alloc(f, b) + _ = alloc(f, nil) + + used0, total0, err := f.audit() // c+4, c+4 + if err != nil { + t.Fatal(err) + } + + if swap { + f1, f2 = f2, f1 + } + free(f, f1) + free(f, f2) + _ = alloc(f, nil) + + f = reaudit(t, f, name) + + used, total, err := f.audit() // c+3, c+4 + if err != nil { + t.Fatal(err) + } + + if difused, diftotal, free := used-used0, total-total0, total-used; difused != -1 || diftotal != 0 || free != 1 { + t.Fatal(difused, diftotal, free) + } +} + +func TestBug1(t *testing.T) { + testBug1(t, false) + testBug1(t, true) +} + +func TestMix(t *testing.T) { + if testing.Short() { + t.Log("skipped") + return + } + + const ( + n = 1 << 10 + ) + + if testing.Short() { + t.Log("skipped") + return + } + + t.Log(n) + dir, name := temp() + defer os.RemoveAll(dir) + + f, err := fcreate(name) + if err != nil { + t.Fatal(err) + } + + defer func() { + if f != nil { + if err := f.Close(); err != nil { + t.Fatal(err) + } + } + + f = nil + runtime.GC() + os.Remove(name) + }() + + b := make([]byte, 61680) + rng, err := mathutil.NewFC32(0, n-1, true) + if err != nil { + t.Fatal(err) + } + + ha := make([]int64, n) + payload := 0 + + t0 := time.Now() + // Alloc n block with upper half of content + for _ = range ha { + r := rng.Next() + c := content(b, int64(r)) + c = c[len(c)/2:] + ha[r] = alloc(f, c) + payload += len(c) + } + dt := float64(time.Now().Sub(t0)) / 1e9 + t.Logf("write time A %.3g", dt) + + // verify + f = reaudit(t, f, name) + t.Logf("size A %d for %d bytes (fill factor %3.1f%%)", f.atoms<<4, payload, 100*float64(payload)/float64(f.atoms<<4)) + t0 = time.Now() + for _ = range ha { + r := rng.Next() + c := content(b, int64(r)) + c = c[len(c)/2:] + if got, _ := f.readUsed(ha[r]); !bytes.Equal(got, c) { + t.Fatal() + } + } + dt = float64(time.Now().Sub(t0)) / 1e9 + t.Logf("read time A %.3g", dt) + // free half of the blocks + t0 = time.Now() + for i := 0; i < n/2; i++ { + free(f, ha[i]) + ha[i] = 0 + } + dt = float64(time.Now().Sub(t0)) / 1e9 + t.Logf("free time A %.3g", dt) + + // verify + f = reaudit(t, f, name) + t.Logf("size B %d (freeing half of the blocks)", f.atoms<<4) + t0 = time.Now() + for _ = range ha { + r := rng.Next() + h := ha[r] + if h == 0 { + continue + } + + c := content(b, int64(r)) + c = c[len(c)/2:] + if got, _ := f.readUsed(h); !bytes.Equal(got, c) { + t.Fatal() + } + } + dt = float64(time.Now().Sub(t0)) / 1e9 + t.Logf("read time B %.3g", dt) + + // reloc extend + t0 = time.Now() + for _ = range ha { + r := rng.Next() + h := ha[r] + if h == 0 { + continue + } + + c := content(b, int64(r)) + //f = reaudit(t, f, name) + if h2 := realloc(f, h, c, true); h2 != h { + t.Fatal() + } + } + dt = float64(time.Now().Sub(t0)) / 1e9 + t.Logf("realoc time B %.3g", dt) + + // verify + f = reaudit(t, f, name) + t.Logf("size C %d for %d bytes (reallocated all used blocks to double size, fill factor %3.1f%%", f.atoms<<4, payload, 100*float64(payload)/float64(f.atoms<<4)) + + t0 = time.Now() + for _ = range ha { + r := rng.Next() + h := ha[r] + if h == 0 { + continue + } + + c := content(b, int64(r)) + if got, _ := f.readUsed(ha[r]); !bytes.Equal(got, c) { + t.Fatal() + } + } + dt = float64(time.Now().Sub(t0)) / 1e9 + t.Logf("read time C %.3g", dt) +} diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/falloc/docs.go b/Godeps/_workspace/src/github.com/cznic/fileutil/falloc/docs.go new file mode 100644 index 0000000..21772fc --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/falloc/docs.go @@ -0,0 +1,251 @@ +// Copyright (c) 2011 CZ.NIC z.s.p.o. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// blame: jnml, labs.nic.cz + +/* + +WIP: Package falloc provides allocation/deallocation of space within a +file/store (WIP, unstable API). + +Overall structure: + File == n blocks. + Block == n atoms. + Atom == 16 bytes. + +x6..x0 == least significant 7 bytes of a 64 bit integer, highest (7th) byte is +0 and is not stored in the file. + +Block first byte + +Aka block type tag. + +------------------------------------------------------------------------------ + +0xFF: Free atom (free block of size 1). + +------++---------++---------++------+ + | 0 || 1...7 || 8...14 || 15 | + +------++---------++---------++------+ + | 0xFF || p6...p0 || n6...n0 || 0xFF | + +------++---------++---------++------+ + +Link to the previous free block (atom addressed) is p6...p0, next dtto in +n6...n0. Doubly linked lists of "compatible" free blocks allows for free space +reclaiming and merging. "Compatible" == of size at least some K. Heads of all +such lists are organized per K or intervals of Ks elsewhere. + +------------------------------------------------------------------------------ + +0xFE: Free block, size == s6...s0 atoms. + +------++---------++---------++---------++-- + | +0 || 1...7 || 8...14 || 15...21 || 22...16*size-1 + +------++---------++---------++---------++-- + | 0xFE || p6...p0 || n6...n0 || s6...s0 || ... + +------++---------++---------++---------++-- + +Prev and next links as in the 0xFF first byte case. End of this block - see +"Block last byte": 0xFE bellow. Data between == undefined. + +------------------------------------------------------------------------------ + +0xFD: Relocated block. + +------++---------++-----------++------+ + | 0 || 1...7 || 8...14 || 15 | + +------++---------++-----------++------+ + | 0xFD || r6...r0 || undefined || 0x00 | // == used block + +------++---------++-----------++------+ + +Relocation link is r6..r0 == atom address. Relocations MUST NOT chain and MUST +point to a "content" block, i.e. one with the first byte in 0x00...0xFC. + +Relocated block allows to permanently assign a handle/file pointer ("atom" +address) to some content and resize the content anytime afterwards w/o having +to update all the possible existing references to the original handle. + +------------------------------------------------------------------------------ + +0xFC: Used long block. + +------++---------++--------------------++---------+---+ + | 0 || 1...2 || 3...N+2 || | | + +------++---------++--------------------++---------+---+ + | 0xFC || n1...n0 || N bytes of content || padding | Z | + +------++---------++--------------------++---------+---+ + +This block type is used for content of length in N == 238...61680 bytes. N is +encoded as a 2 byte unsigned integer n1..n0 in network byte order. Values +bellow 238 are reserved, those content lengths are to be carried by the +0x00..0xFB block types. + + 1. n in 0x00EE...0xF0F0 is used for content under the same rules + as in the 0x01..0xED type. + + 2. If the last byte of the content is not the last byte of an atom then + the last byte of the block is 0x00. + + 3. If the last byte of the content IS the last byte of an atom: + + 3.1 If the last byte of content is in 0x00..0xFD then everything is OK. + + 3.2 If the last byte of content is 0xFE or 0xFF then the escape + via n > 0xF0F0 MUST be used AND the block's last byte is 0x00 or 0x01, + meaning value 0xFE and 0xFF respectively. + + 4. n in 0xF0F1...0xFFFF is like the escaped 0xEE..0xFB block. + N == 13 + 16(n - 0xF0F1). + +Discussion of the padding and Z fields - see the 0x01..0xED block type. + +------------------------------------------------------------------------------ + +0xEE...0xFB: Used escaped short block. + +---++----------------------++---+ + | 0 || 1...N-1 || | + +---++----------------------++---+ + | X || N-1 bytes of content || Z | + +---++----------------------++---+ + +N == 15 + 16(X - 0xEE). Z is the content last byte encoded as follows. + +case Z == 0x00: The last byte of content is 0xFE + +case Z == 0x01: The last byte of content is 0xFF + +------------------------------------------------------------------------------ + +0x01...0xED: Used short block. + +---++--------------------++---------+---+ + | 0 || 1...N || | | + +---++--------------------++---------+---+ + | N || N bytes of content || padding | Z | + +---++--------------------++---------+---+ + +This block type is used for content of length in 1...237 bytes. The value of +the "padding" field, if of non zero length, is undefined. + +If the last byte of content is the last byte of an atom (== its file byte +offset & 0xF == 0xF) then such last byte MUST be in 0x00...0xFD. + +If the last byte of content is the last byte of an atom AND the last byte of +content is 0xFE or 0xFF then the short escape block type (0xEE...0xFB) MUST be +used. + +If the last byte of content is not the last byte of an atom, then the last byte +of such block, i.e. the Z field, which is also a last byte of some atom, MUST +be 0x00 (i.e. the used block marker). Other "tail" values are reserved. + +------------------------------------------------------------------------------ + +0x00: Used empty block. + +------++-----------++------+ + | 0 || 1...14 || 15 | + +------++-----------++------+ + | 0x00 || undefined || 0x00 | // == used block, other "tail" values reserved. + +------++-----------++------+ + +All of the rules for 0x01..0xED applies. Depicted only for its different +semantics (e.g. an allocated [existing] string but with length of zero). + +============================================================================== + +Block last byte + +------------------------------------------------------------------------------ + +0xFF: Free atom. Layout - see "Block first byte": FF. + +------------------------------------------------------------------------------ + +0xFE: Free block, size n atoms. Preceding 7 bytes == size (s6...s0) of the free +block in atoms, network byte order + --++---------++------+ + || -8...-2 || -1 | + --++---------++------+ + ... || s6...s0 || 0xFE | <- block's last byte + --++---------++------+ + +Layout at start of this block - see "Block first byte": FE. + +------------------------------------------------------------------------------ + +0x00...0xFD: Used (non free) block. + +============================================================================== + +Free lists table + +The free lists table content is stored in the standard layout of a used block. + +A table item is a 7 byte size field followed by a 7 byte atom address field +(both in network byte order), thus every item is 14 contiguous bytes. The +item's address field is pointing to a free block. The size field determines +the minimal size (in atoms) of free blocks on that list. + +The free list table is n above items, thus the content has 14n bytes. Note that +the largest block content is 61680 bytes and as there are 14 bytes per table +item, so the table is limited to at most 4405 entries. + +Items in the table do not have to be sorted according to their size field values. + +No two items can have the same value of the size field. + +When freeing blocks, the block MUST be linked into an item list with the +highest possible size field, which is less or equal to the number of atoms in +the new free block. + +When freeing a block, the block MUST be first merged with any adjacent free +blocks (thus possibly creating a bigger free block) using information derived +from the adjacent blocks first and last bytes. Such merged free blocks MUST be +removed from their original doubly linked lists. Afterwards the new bigger free +block is put to the free list table in the appropriate item. + +Items with address field == 0 are legal. Such item is a placeholder for a empty +list of free blocks of the item's size. + +Items with size field == 0 are legal. Such item is a placeholder, used e.g. to +avoid further reallocations/redirecting of the free lists table. + +The largest possible allocation request (for content length 61680 bytes) is +0xF10 (3856) atoms. All free blocks of this or bigger size are presumably put +into a single table item with the size 3856. It may be useful to additionally +have a free lists table item which links free blocks of some bigger size (say +1M+) and then use the OS sparse file support (if present) to save the physical +space used by such free blocks. + +Smaller (<3856 atoms) free blocks can be organized exactly (every distinct size +has its table item) or the sizes can run using other schema like e.g. "1, 2, +4, 8, ..." (powers of 2) or "1, 2, 3, 5, 8, 13, ..." (the Fibonacci sequence) +or they may be fine tuned to a specific usage pattern. + +============================================================================== + +Header + +The first block of a file (atom address == file offset == 0) is the file header. +The header block has the standard layout of a used short non escaped block. + +Special conditions apply: The header block and its content MUST be like this: + + +------+---------+---------+------+ + | 0 | 1...7 | 8...14 | 15 | + +------+---------+---------+------+ + | 0x0F | m6...m0 | f6...f0 | FLTT | + +------+---------+---------+------+ + +m6..m0 is a "magic" value 0xF1C1A1FE51B1E. + +f6...f0 is the atom address of the free lists table (discussed elsewhere). +If f6...f0 == 0x00 the there is no free lists table (yet). + +FLTT describes the type of the Free List Table. Currently defined values: + +------------------------------------------------------------------------------ + +FLTT == 0: Free List Table is fixed at atom address 2. It has a fixed size for 3856 entries +for free list of size 1..3855 atoms and the last is for the list of free block >= 3856 atoms. +*/ +package falloc + +const ( + INVALID_HANDLE = Handle(-1) +) diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/falloc/error.go b/Godeps/_workspace/src/github.com/cznic/fileutil/falloc/error.go new file mode 100644 index 0000000..dad3d29 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/falloc/error.go @@ -0,0 +1,130 @@ +// Copyright (c) 2011 CZ.NIC z.s.p.o. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// blame: jnml, labs.nic.cz + +package falloc + +import "fmt" + +// EBadRequest is an error produced for invalid operation, e.g. for data of more than maximum allowed. +type EBadRequest struct { + Name string + Size int +} + +func (e *EBadRequest) Error() string { + return fmt.Sprintf("%s: size %d", e.Name, e.Size) +} + +// EClose is a file/store close error. +type EClose struct { + Name string + Err error +} + +func (e *EClose) Error() string { + return fmt.Sprintf("%sx: %s", e.Name, e.Err) +} + +// ECorrupted is a file/store format error. +type ECorrupted struct { + Name string + Ofs int64 +} + +func (e *ECorrupted) Error() string { + return fmt.Sprintf("%s: corrupted data @%#x", e.Name, e.Ofs) +} + +// ECreate is a file/store create error. +type ECreate struct { + Name string + Err error +} + +func (e *ECreate) Error() string { + return fmt.Sprintf("%s: %s", e.Name, e.Err) +} + +// EFreeList is a file/store format error. +type EFreeList struct { + Name string + Size int64 + Block int64 +} + +func (e *EFreeList) Error() string { + return fmt.Sprintf("%s: invalid free list item, size %#x, block %#x", e.Name, e.Size, e.Block) +} + +// EHandle is an error type reported for invalid Handles. +type EHandle struct { + Name string + Handle Handle +} + +func (e EHandle) Error() string { + return fmt.Sprintf("%s: invalid handle %#x", e.Name, e.Handle) +} + +// EHeader is a file/store format error. +type EHeader struct { + Name string + Header []byte + Expected []byte +} + +func (e *EHeader) Error() string { + return fmt.Sprintf("%s: invalid header, got [% x], expected [% x]", e.Name, e.Header, e.Expected) +} + +// ENullHandle is a file/store access error via a null handle. +type ENullHandle string + +func (e ENullHandle) Error() string { + return fmt.Sprintf("%s: access via null handle", e) +} + +// EOpen is a file/store open error. +type EOpen struct { + Name string + Err error +} + +func (e *EOpen) Error() string { + return fmt.Sprintf("%s: %s", e.Name, e.Err) +} + +// ERead is a file/store read error. +type ERead struct { + Name string + Ofs int64 + Err error +} + +func (e *ERead) Error() string { + return fmt.Sprintf("%s, %#x: %s", e.Name, e.Ofs, e.Err) +} + +// ESize is a file/store size error. +type ESize struct { + Name string + Size int64 +} + +func (e *ESize) Error() string { + return fmt.Sprintf("%s: invalid size %#x(%d), size %%16 != 0", e.Name, e.Size, e.Size) +} + +// EWrite is a file/store write error. +type EWrite struct { + Name string + Ofs int64 + Err error +} + +func (e *EWrite) Error() string { + return fmt.Sprintf("%s, %#x: %s", e.Name, e.Ofs, e.Err) +} diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/falloc/falloc.go b/Godeps/_workspace/src/github.com/cznic/fileutil/falloc/falloc.go new file mode 100644 index 0000000..deb18eb --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/falloc/falloc.go @@ -0,0 +1,676 @@ +// Copyright (c) 2011 CZ.NIC z.s.p.o. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// blame: jnml, labs.nic.cz + +/* + +This is an mostly (WIP) conforming implementation of the "specs" in docs.go. + +The main incompletness is support for only one kind of FTL, though this table kind is still per "specs". + +*/ + +package falloc + +import ( + "bytes" + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/fileutil/storage" + "sync" +) + +// Handle is a reference to a block in a file/store. +// Handle is an uint56 wrapped in an in64, i.e. the most significant byte must be always zero. +type Handle int64 + +// Put puts the 7 least significant bytes of h into b. The MSB of h should be zero. +func (h Handle) Put(b []byte) { + for ofs := 6; ofs >= 0; ofs-- { + b[ofs] = byte(h) + h >>= 8 + } +} + +// Get gets the 7 least significant bytes of h from b. The MSB of h is zeroed. +func (h *Handle) Get(b []byte) { + var x Handle + for ofs := 0; ofs <= 6; ofs++ { + x = x<<8 | Handle(b[ofs]) + } + *h = x +} + +// File is a file/store with space allocation/deallocation support. +type File struct { + f storage.Accessor + atoms int64 // current file size in atom units + canfree int64 // only blocks >= canfree can be subject to Free() + freetab [3857]int64 // freetab[0] is unused, freetab[1] is size 1 ptr, freetab[2] is size 2 ptr, ... + rwm sync.RWMutex +} + +func (f *File) read(b []byte, off int64) { + if n, err := f.f.ReadAt(b, off); n != len(b) { + panic(&ERead{f.f.Name(), off, err}) + } +} + +func (f *File) write(b []byte, off int64) { + if n, err := f.f.WriteAt(b, off); n != len(b) { + panic(&EWrite{f.f.Name(), off, err}) + } +} + +var ( // R/O + hdr = []byte{0x0f, 0xf1, 0xc1, 0xa1, 0xfe, 0xa5, 0x1b, 0x1e, 0, 0, 0, 0, 0, 0, 2, 0} // free lists table @2 + empty = make([]byte, 16) + zero = []byte{0} + zero7 = make([]byte, 7) +) + +// New returns a new File backed by store or an error if any. +// Any existing data in store are discarded. +func New(store storage.Accessor) (f *File, err error) { + f = &File{f: store} + return f, storage.Mutate(store, func() (err error) { + if err = f.f.Truncate(0); err != nil { + return &ECreate{f.f.Name(), err} + } + + if _, err = f.Alloc(hdr[1:]); err != nil { //TODO internal panicking versions of the exported fns. + return + } + + if _, err = f.Alloc(nil); err != nil { // (empty) root @1 + return + } + + b := make([]byte, 3856*14) + for i := 1; i <= 3856; i++ { + Handle(i).Put(b[(i-1)*14:]) + } + if _, err = f.Alloc(b); err != nil { + return + } + + f.canfree = f.atoms + return + }) +} + +// Open returns a new File backed by store or an error if any. +// Store already has to be in a valid format. +func Open(store storage.Accessor) (f *File, err error) { + defer func() { + if e := recover(); e != nil { + f = nil + err = e.(error) + } + }() + + fi, err := store.Stat() + if err != nil { + panic(&EOpen{store.Name(), err}) + } + + fs := fi.Size() + if fs&0xf != 0 { + panic(&ESize{store.Name(), fi.Size()}) + } + + f = &File{f: store, atoms: fs >> 4} + b := make([]byte, len(hdr)) + f.read(b, 0) + if !bytes.Equal(b, hdr) { + panic(&EHeader{store.Name(), b, append([]byte{}, hdr...)}) + } + + var atoms int64 + b, atoms = f.readUsed(2) + f.canfree = atoms + 2 + ofs := 0 + var size, p Handle + for ofs < len(b) { + size.Get(b[ofs:]) + ofs += 7 + p.Get(b[ofs:]) + ofs += 7 + if sz, pp := int64(size), int64(p); size == 0 || size > 3856 || (pp != 0 && pp < f.canfree) || pp<<4 > fs-16 { + panic(&EFreeList{store.Name(), sz, pp}) + } + + f.freetab[size] = int64(p) + } + return +} + +// Accessor returns the File's underlying Accessor. +func (f *File) Accessor() storage.Accessor { + return f.f +} + +// Close closes f and returns an error if any. +func (f *File) Close() (err error) { + return storage.Mutate(f.Accessor(), func() (err error) { + if err = f.f.Close(); err != nil { + err = &EClose{f.f.Name(), err} + } + return + }) +} + +// Root returns the handle of the DB root (top level directory, ...). +func (f *File) Root() Handle { + return 1 +} + +func (f *File) readUsed(atom int64) (content []byte, atoms int64) { + b, redirected := make([]byte, 7), false +redir: + ofs := atom << 4 + f.read(b[:1], ofs) + switch pre := b[0]; { + default: + panic(&ECorrupted{f.f.Name(), ofs}) + case pre == 0x00: // Empty block + case pre >= 1 && pre <= 237: // Short + content = make([]byte, pre) + f.read(content, ofs+1) + case pre >= 0xee && pre <= 0xfb: // Short esc + content = make([]byte, 15+16*(pre-0xee)) + f.read(content, ofs+1) + content[len(content)-1] += 0xfe + case pre == 0xfc: // Long + f.read(b[:2], ofs+1) + n := int(b[0])<<8 + int(b[1]) + switch { + default: + panic(&ECorrupted{f.f.Name(), ofs + 1}) + case n >= 238 && n <= 61680: // Long non esc + content = make([]byte, n) + f.read(content, ofs+3) + case n >= 61681: // Long esc + content = make([]byte, 13+16*(n-0xf0f1)) + f.read(content, ofs+3) + content[len(content)-1] += 0xfe + } + case pre == 0xfd: // redir + if redirected { + panic(&ECorrupted{f.f.Name(), ofs}) + } + + f.read(b[:7], ofs+1) + (*Handle)(&atom).Get(b) + redirected = true + goto redir + } + return content, rq2Atoms(len(content)) +} + +func (f *File) writeUsed(b []byte, atom int64) { + n := len(b) + switch ofs, atoms, endmark := atom<<4, rq2Atoms(n), true; { + default: + panic("internal error") + case n == 0: + f.write(empty, ofs) + case n <= 237: + if (n+1)&0xf == 0 { // content end == atom end + if v := b[n-1]; v >= 0xfe { // escape + pre := []byte{byte((16*0xee + n - 15) >> 4)} + f.write(pre, ofs) + f.write(b[:n-1], ofs+1) + f.write([]byte{v - 0xfe}, ofs+atoms<<4-1) + return + } + endmark = false + } + // non esacpe + pre := []byte{byte(n)} + f.write(pre, ofs) + f.write(b, ofs+1) + if endmark { + f.write(zero, ofs+atoms<<4-1) // last block byte <- used block + } + case n > 237 && n <= 61680: + if (n+3)&0xf == 0 { // content end == atom end + if v := b[n-1]; v >= 0xfe { // escape + x := (16*0xf0f1 + n - 13) >> 4 + pre := []byte{0xFC, byte(x >> 8), byte(x)} + f.write(pre, ofs) + f.write(b[:n-1], ofs+3) + f.write([]byte{v - 0xfe}, ofs+atoms<<4-1) + return + } + endmark = false + } + // non esacpe + pre := []byte{0xfc, byte(n >> 8), byte(n)} + f.write(pre, ofs) + f.write(b, ofs+3) + if endmark { + f.write(zero, ofs+atoms<<4-1) // last block byte <- used block + } + } +} + +func rq2Atoms(rqbytes int) (rqatoms int64) { + if rqbytes > 237 { + rqbytes += 2 + } + return int64(rqbytes>>4 + 1) +} + +func (f *File) extend(b []byte) (handle int64) { + handle = f.atoms + f.writeUsed(b, handle) + f.atoms += rq2Atoms(len(b)) + return +} + +// Alloc stores b in a newly allocated space and returns its handle and an error if any. +func (f *File) Alloc(b []byte) (handle Handle, err error) { + err = storage.Mutate(f.Accessor(), func() (err error) { + rqAtoms := rq2Atoms(len(b)) + if rqAtoms > 3856 { + return &EBadRequest{f.f.Name(), len(b)} + } + + for foundsize, foundp := range f.freetab[rqAtoms:] { + if foundp != 0 { + // this works only for the current unique sizes list (except the last item!) + size := int64(foundsize) + rqAtoms + handle = Handle(foundp) + if size == 3856 { + buf := make([]byte, 7) + f.read(buf, int64(handle)<<4+15) + (*Handle)(&size).Get(buf) + } + f.delFree(int64(handle), size) + if rqAtoms < size { + f.addFree(int64(handle)+rqAtoms, size-rqAtoms) + } + f.writeUsed(b, int64(handle)) + return + } + } + + handle = Handle(f.extend(b)) + return + }) + return +} + +// checkLeft returns the atom size of a free bleck left adjacent to block @atom. +// If that block is not free the returned size is 0. +func (f *File) checkLeft(atom int64) (size int64) { + if atom <= f.canfree { + return + } + + b := make([]byte, 7) + fp := atom << 4 + f.read(b[:1], fp-1) + switch last := b[0]; { + case last <= 0xfd: + // used block + case last == 0xfe: + f.read(b, fp-8) + (*Handle)(&size).Get(b) + case last == 0xff: + size = 1 + } + return +} + +// getInfo returns the block @atom type and size. +func (f *File) getInfo(atom int64) (pref byte, size int64) { + b := make([]byte, 7) + fp := atom << 4 + f.read(b[:1], fp) + switch pref = b[0]; { + case pref == 0: // Empty used + size = 1 + case pref >= 1 && pref <= 237: // Short + size = rq2Atoms(int(pref)) + case pref >= 0xee && pref <= 0xfb: // Short esc + size = rq2Atoms(15 + 16*int(pref-0xee)) + case pref == 0xfc: // Long + f.read(b[:2], fp+1) + n := int(b[0])<<8 + int(b[1]) + switch { + default: + panic(&ECorrupted{f.f.Name(), fp + 1}) + case n >= 238 && n <= 61680: // Long non esc + size = rq2Atoms(n) + case n >= 61681: // Long esc + size = rq2Atoms(13 + 16*(n-0xf0f1)) + } + case pref == 0xfd: // reloc + size = 1 + case pref == 0xfe: + f.read(b, fp+15) + (*Handle)(&size).Get(b) + case pref == 0xff: + size = 1 + } + return +} + +// getSize returns the atom size of the block @atom and wheter it is free. +func (f *File) getSize(atom int64) (size int64, isFree bool) { + var typ byte + typ, size = f.getInfo(atom) + isFree = typ >= 0xfe + return +} + +// checkRight returns the atom size of a free bleck right adjacent to block @atom,atoms. +// If that block is not free the returned size is 0. +func (f *File) checkRight(atom, atoms int64) (size int64) { + if atom+atoms >= f.atoms { + return + } + + if sz, free := f.getSize(atom + atoms); free { + size = sz + } + return +} + +// delFree removes the atoms@atom free block from the free block list +func (f *File) delFree(atom, atoms int64) { + b := make([]byte, 15) + size := int(atoms) + if n := len(f.freetab); atoms >= int64(n) { + size = n - 1 + } + fp := atom << 4 + f.read(b[1:], fp+1) + var prev, next Handle + prev.Get(b[1:]) + next.Get(b[8:]) + + switch { + case prev == 0 && next != 0: + next.Put(b) + f.write(b[:7], int64(32+3+7+(size-1)*14)) + f.write(zero7, int64(next)<<4+1) + f.freetab[size] = int64(next) + case prev != 0 && next == 0: + f.write(zero7, int64(prev)<<4+8) + case prev != 0 && next != 0: + prev.Put(b) + f.write(b[:7], int64(next)<<4+1) + next.Put(b) + f.write(b[:7], int64(prev)<<4+8) + default: // prev == 0 && next == 0: + f.write(zero7, int64(32+3+7+(size-1)*14)) + f.freetab[size] = 0 + } +} + +// addFree adds atoms@atom to the free block lists and marks it free. +func (f *File) addFree(atom, atoms int64) { + b := make([]byte, 7) + size := int(atoms) + if n := len(f.freetab); atoms >= int64(n) { + size = n - 1 + } + head := f.freetab[size] + if head == 0 { // empty list + f.makeFree(0, atom, atoms, 0) + Handle(atom).Put(b) + f.write(b, int64(32+3+7+(size-1)*14)) + f.freetab[size] = atom + return + } + + Handle(atom).Put(b) + f.write(b, head<<4+1) // head.prev = atom + f.makeFree(0, atom, atoms, head) // atom.next = head + f.write(b, int64(32+3+7+(size-1)*14)) + f.freetab[size] = atom +} + +// makeFree sets up the content of a free block atoms@atom, fills the prev and next links. +func (f *File) makeFree(prev, atom, atoms, next int64) { + b := make([]byte, 23) + fp := atom << 4 + if atoms == 1 { + b[0] = 0xff + Handle(prev).Put(b[1:]) + Handle(next).Put(b[8:]) + b[15] = 0xff + f.write(b[:16], fp) + return + } + + b[0] = 0xfe + Handle(prev).Put(b[1:]) + Handle(next).Put(b[8:]) + Handle(atoms).Put(b[15:]) + f.write(b[:22], fp) + b[22] = 0xfe + f.write(b[15:], fp+atoms<<4-8) +} + +// Read reads and return the data associated with handle and an error if any. +// Passing an invalid handle to Read may return invalid data without error. +// It's like getting garbage via passing an invalid pointer to C.memcopy(). +func (f *File) Read(handle Handle) (b []byte, err error) { + defer func() { + if e := recover(); e != nil { + b = nil + err = e.(error) + } + }() + + switch handle { + case 0: + panic(ENullHandle(f.f.Name())) + case 2: + panic(&EHandle{f.f.Name(), handle}) + default: + b, _ = f.readUsed(int64(handle)) + } + return +} + +// Free frees space associated with handle and returns an error if any. Passing an invalid +// handle to Free or reusing handle afterwards will probably corrupt the database or provide +// invalid data on Read. It's like corrupting memory via passing an invalid pointer to C.free() +// or reusing that pointer. +func (f *File) Free(handle Handle) (err error) { + return storage.Mutate(f.Accessor(), func() (err error) { + atom := int64(handle) + atoms, isFree := f.getSize(atom) + if isFree || atom < f.canfree { + return &EHandle{f.f.Name(), handle} + } + + leftFree, rightFree := f.checkLeft(atom), f.checkRight(atom, atoms) + switch { + case leftFree != 0 && rightFree != 0: + f.delFree(atom-leftFree, leftFree) + f.delFree(atom+atoms, rightFree) + f.addFree(atom-leftFree, leftFree+atoms+rightFree) + case leftFree != 0 && rightFree == 0: + f.delFree(atom-leftFree, leftFree) + if atom+atoms == f.atoms { // the left free neighbour and this block together are an empy tail + f.atoms = atom - leftFree + f.f.Truncate(f.atoms << 4) + return + } + + f.addFree(atom-leftFree, leftFree+atoms) + case leftFree == 0 && rightFree != 0: + f.delFree(atom+atoms, rightFree) + f.addFree(atom, atoms+rightFree) + default: // leftFree == 0 && rightFree == 0 + if atom+atoms < f.atoms { // isolated inner block + f.addFree(atom, atoms) + return + } + + f.f.Truncate(atom << 4) // isolated tail block, shrink file + f.atoms = atom + } + return + }) +} + +// Realloc reallocates space associted with handle to acomodate b, returns the newhandle +// newly associated with b and an error if any. If keepHandle == true then Realloc guarantees +// newhandle == handle even if the new data are larger then the previous content associated +// with handle. If !keepHandle && newhandle != handle then reusing handle will probably corrupt +// the database. +// The above effects are like corrupting memory/data via passing an invalid pointer to C.realloc(). +func (f *File) Realloc(handle Handle, b []byte, keepHandle bool) (newhandle Handle, err error) { + err = storage.Mutate(f.Accessor(), func() (err error) { + switch handle { + case 0, 2: + return &EHandle{f.f.Name(), handle} + case 1: + keepHandle = true + } + newhandle = handle + atom, newatoms := int64(handle), rq2Atoms(len(b)) + if newatoms > 3856 { + return &EBadRequest{f.f.Name(), len(b)} + } + + typ, oldatoms := f.getInfo(atom) + switch { + default: + return &ECorrupted{f.f.Name(), atom << 4} + case typ <= 0xfc: // non relocated used block + switch { + case newatoms == oldatoms: // in place replace + f.writeUsed(b, atom) + case newatoms < oldatoms: // in place shrink + rightFree := f.checkRight(atom, oldatoms) + if rightFree > 0 { // right join + f.delFree(atom+oldatoms, rightFree) + } + f.addFree(atom+newatoms, oldatoms+rightFree-newatoms) + f.writeUsed(b, atom) + case newatoms > oldatoms: + if rightFree := f.checkRight(atom, oldatoms); rightFree > 0 && newatoms <= oldatoms+rightFree { + f.delFree(atom+oldatoms, rightFree) + if newatoms < oldatoms+rightFree { + f.addFree(atom+newatoms, oldatoms+rightFree-newatoms) + } + f.writeUsed(b, atom) + return + } + + if !keepHandle { + f.Free(Handle(atom)) + newhandle, err = f.Alloc(b) + return + } + + // reloc + newatom, e := f.Alloc(b) + if e != nil { + return e + } + + buf := make([]byte, 16) + buf[0] = 0xfd + Handle(newatom).Put(buf[1:]) + f.Realloc(Handle(atom), buf[1:], true) + f.write(buf[:1], atom<<4) + } + case typ == 0xfd: // reloc + var target Handle + buf := make([]byte, 7) + f.read(buf, atom<<4+1) + target.Get(buf) + switch { + case newatoms == 1: + f.writeUsed(b, atom) + f.Free(target) + default: + if rightFree := f.checkRight(atom, 1); rightFree > 0 && newatoms <= 1+rightFree { + f.delFree(atom+1, rightFree) + if newatoms < 1+rightFree { + f.addFree(atom+newatoms, 1+rightFree-newatoms) + } + f.writeUsed(b, atom) + f.Free(target) + return + } + + newtarget, e := f.Realloc(Handle(target), b, false) + if e != nil { + return e + } + + if newtarget != target { + Handle(newtarget).Put(buf) + f.write(buf, atom<<4+1) + } + } + } + return + }) + return +} + +// Lock locks f for writing. If the lock is already locked for reading or writing, +// Lock blocks until the lock is available. To ensure that the lock eventually becomes available, +// a blocked Lock call excludes new readers from acquiring the lock. +func (f *File) Lock() { + f.rwm.Lock() +} + +// RLock locks f for reading. If the lock is already locked for writing or there is a writer +// already waiting to release the lock, RLock blocks until the writer has released the lock. +func (f *File) RLock() { + f.rwm.RLock() +} + +// Unlock unlocks f for writing. It is a run-time error if f is not locked for writing on entry to Unlock. +// +// As with Mutexes, a locked RWMutex is not associated with a particular goroutine. +// One goroutine may RLock (Lock) f and then arrange for another goroutine to RUnlock (Unlock) it. +func (f *File) Unlock() { + f.rwm.Unlock() +} + +// RUnlock undoes a single RLock call; it does not affect other simultaneous readers. +// It is a run-time error if f is not locked for reading on entry to RUnlock. +func (f *File) RUnlock() { + f.rwm.RUnlock() +} + +// LockedAlloc wraps Alloc in a Lock/Unlock pair. +func (f *File) LockedAlloc(b []byte) (handle Handle, err error) { + f.Lock() + defer f.Unlock() + return f.Alloc(b) +} + +// LockedFree wraps Free in a Lock/Unlock pair. +func (f *File) LockedFree(handle Handle) (err error) { + f.Lock() + defer f.Unlock() + return f.Free(handle) +} + +// LockedRead wraps Read in a RLock/RUnlock pair. +func (f *File) LockedRead(handle Handle) (b []byte, err error) { + f.RLock() + defer f.RUnlock() + return f.Read(handle) +} + +// LockedRealloc wraps Realloc in a Lock/Unlock pair. +func (f *File) LockedRealloc(handle Handle, b []byte, keepHandle bool) (newhandle Handle, err error) { + f.Lock() + defer f.Unlock() + return f.Realloc(handle, b, keepHandle) +} diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/falloc/test_deps.go b/Godeps/_workspace/src/github.com/cznic/fileutil/falloc/test_deps.go new file mode 100644 index 0000000..bc797f9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/falloc/test_deps.go @@ -0,0 +1,16 @@ +// Copyright (c) 2011 CZ.NIC z.s.p.o. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// blame: jnml, labs.nic.cz + +package falloc + +// Pull test dependencies too. +// Enables easy 'go test X' after 'go get X' +import ( + _ "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/fileutil" + _ "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/fileutil/storage" + + _ "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/mathutil" +) diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/fileutil.go b/Godeps/_workspace/src/github.com/cznic/fileutil/fileutil.go new file mode 100644 index 0000000..2f0f7ab --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/fileutil.go @@ -0,0 +1,223 @@ +// Copyright (c) 2014 The fileutil 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 fileutil collects some file utility functions. +package fileutil + +import ( + "fmt" + "io" + "os" + "path/filepath" + "runtime" + "strconv" + "sync" + "time" +) + +// GoMFile is a concurrent access safe version of MFile. +type GoMFile struct { + mfile *MFile + mutex sync.Mutex +} + +// NewGoMFile return a newly created GoMFile. +func NewGoMFile(fname string, flag int, perm os.FileMode, delta_ns int64) (m *GoMFile, err error) { + m = &GoMFile{} + if m.mfile, err = NewMFile(fname, flag, perm, delta_ns); err != nil { + m = nil + } + return +} + +func (m *GoMFile) File() (file *os.File, err error) { + m.mutex.Lock() + defer m.mutex.Unlock() + return m.mfile.File() +} + +func (m *GoMFile) SetChanged() { + m.mutex.Lock() + defer m.mutex.Unlock() + m.mfile.SetChanged() +} + +func (m *GoMFile) SetHandler(h MFileHandler) { + m.mutex.Lock() + defer m.mutex.Unlock() + m.mfile.SetHandler(h) +} + +// MFileHandler resolves modifications of File. +// Possible File context is expected to be a part of the handler's closure. +type MFileHandler func(*os.File) error + +// MFile represents an os.File with a guard/handler on change/modification. +// Example use case is an app with a configuration file which can be modified at any time +// and have to be reloaded in such event prior to performing something configurable by that +// file. The checks are made only on access to the MFile file by +// File() and a time threshold/hysteresis value can be chosen on creating a new MFile. +type MFile struct { + file *os.File + handler MFileHandler + t0 int64 + delta int64 + ctime int64 +} + +// NewMFile returns a newly created MFile or Error if any. +// The fname, flag and perm parameters have the same meaning as in os.Open. +// For meaning of the delta_ns parameter please see the (m *MFile) File() docs. +func NewMFile(fname string, flag int, perm os.FileMode, delta_ns int64) (m *MFile, err error) { + m = &MFile{} + m.t0 = time.Now().UnixNano() + if m.file, err = os.OpenFile(fname, flag, perm); err != nil { + return + } + + var fi os.FileInfo + if fi, err = m.file.Stat(); err != nil { + return + } + + m.ctime = fi.ModTime().UnixNano() + m.delta = delta_ns + runtime.SetFinalizer(m, func(m *MFile) { + m.file.Close() + }) + return +} + +// SetChanged forces next File() to unconditionally handle modification of the wrapped os.File. +func (m *MFile) SetChanged() { + m.ctime = -1 +} + +// SetHandler sets a function to be invoked when modification of MFile is to be processed. +func (m *MFile) SetHandler(h MFileHandler) { + m.handler = h +} + +// File returns an os.File from MFile. If time elapsed between the last invocation of this function +// and now is at least delta_ns ns (a parameter of NewMFile) then the file is checked for +// change/modification. For delta_ns == 0 the modification is checked w/o getting os.Time(). +// If a change is detected a handler is invoked on the MFile file. +// Any of these steps can produce an Error. If that happens the function returns nil, Error. +func (m *MFile) File() (file *os.File, err error) { + var now int64 + + mustCheck := m.delta == 0 + if !mustCheck { + now = time.Now().UnixNano() + mustCheck = now-m.t0 > m.delta + } + + if mustCheck { // check interval reached + var fi os.FileInfo + if fi, err = m.file.Stat(); err != nil { + return + } + + if fi.ModTime().UnixNano() != m.ctime { // modification detected + if m.handler == nil { + return nil, fmt.Errorf("no handler set for modified file %q", m.file.Name()) + } + if err = m.handler(m.file); err != nil { + return + } + + m.ctime = fi.ModTime().UnixNano() + } + m.t0 = now + } + + return m.file, nil +} + +// Read reads buf from r. It will either fill the full buf or fail. +// It wraps the functionality of an io.Reader which may return less bytes than requested, +// but may block if not all data are ready for the io.Reader. +func Read(r io.Reader, buf []byte) (err error) { + have := 0 + remain := len(buf) + got := 0 + for remain > 0 { + if got, err = r.Read(buf[have:]); err != nil { + return + } + + remain -= got + have += got + } + return +} + +// "os" and/or "syscall" extensions + +// FadviseAdvice is used by Fadvise. +type FadviseAdvice int + +// FAdviseAdvice values. +const ( + // $ grep FADV /usr/include/bits/fcntl.h + POSIX_FADV_NORMAL FadviseAdvice = iota // No further special treatment. + POSIX_FADV_RANDOM // Expect random page references. + POSIX_FADV_SEQUENTIAL // Expect sequential page references. + POSIX_FADV_WILLNEED // Will need these pages. + POSIX_FADV_DONTNEED // Don't need these pages. + POSIX_FADV_NOREUSE // Data will be accessed once. +) + +// TempFile creates a new temporary file in the directory dir with a name +// ending with suffix, basename starting with prefix, opens the file for +// reading and writing, and returns the resulting *os.File. If dir is the +// empty string, TempFile uses the default directory for temporary files (see +// os.TempDir). Multiple programs calling TempFile simultaneously will not +// choose the same file. The caller can use f.Name() to find the pathname of +// the file. It is the caller's responsibility to remove the file when no +// longer needed. +// +// NOTE: This function differs from ioutil.TempFile. +func TempFile(dir, prefix, suffix string) (f *os.File, err error) { + if dir == "" { + dir = os.TempDir() + } + + nconflict := 0 + for i := 0; i < 10000; i++ { + name := filepath.Join(dir, prefix+nextInfix()+suffix) + f, err = os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600) + if os.IsExist(err) { + if nconflict++; nconflict > 10 { + rand = reseed() + } + continue + } + break + } + return +} + +// Random number state. +// We generate random temporary file names so that there's a good +// chance the file doesn't exist yet - keeps the number of tries in +// TempFile to a minimum. +var rand uint32 +var randmu sync.Mutex + +func reseed() uint32 { + return uint32(time.Now().UnixNano() + int64(os.Getpid())) +} + +func nextInfix() string { + randmu.Lock() + r := rand + if r == 0 { + r = reseed() + } + r = r*1664525 + 1013904223 // constants from Numerical Recipes + rand = r + randmu.Unlock() + return strconv.Itoa(int(1e9 + r%1e9))[1:] +} diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/fileutil_arm.go b/Godeps/_workspace/src/github.com/cznic/fileutil/fileutil_arm.go new file mode 100644 index 0000000..9410d1b --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/fileutil_arm.go @@ -0,0 +1,25 @@ +// Copyright (c) 2014 The fileutil 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 fileutil + +import ( + "io" + "os" +) + +// PunchHole deallocates space inside a file in the byte range starting at +// offset and continuing for len bytes. Not supported on ARM. +func PunchHole(f *os.File, off, len int64) error { + return nil +} + +// Fadvise predeclares an access pattern for file data. See also 'man 2 +// posix_fadvise'. Not supported on ARM. +func Fadvise(f *os.File, off, len int64, advice FadviseAdvice) error { + return nil +} + +// IsEOF reports whether err is an EOF condition. +func IsEOF(err error) bool { return err == io.EOF } diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/fileutil_darwin.go b/Godeps/_workspace/src/github.com/cznic/fileutil/fileutil_darwin.go new file mode 100644 index 0000000..a19723f --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/fileutil_darwin.go @@ -0,0 +1,25 @@ +// Copyright (c) 2014 The fileutil 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 fileutil + +import ( + "io" + "os" +) + +// PunchHole deallocates space inside a file in the byte range starting at +// offset and continuing for len bytes. Not supported on OSX. +func PunchHole(f *os.File, off, len int64) error { + return nil +} + +// Fadvise predeclares an access pattern for file data. See also 'man 2 +// posix_fadvise'. Not supported on OSX. +func Fadvise(f *os.File, off, len int64, advice FadviseAdvice) error { + return nil +} + +// IsEOF reports whether err is an EOF condition. +func IsEOF(err error) bool { return err == io.EOF } diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/fileutil_freebsd.go b/Godeps/_workspace/src/github.com/cznic/fileutil/fileutil_freebsd.go new file mode 100644 index 0000000..0865093 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/fileutil_freebsd.go @@ -0,0 +1,25 @@ +// Copyright (c) 2014 The fileutil 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 fileutil + +import ( + "io" + "os" +) + +// PunchHole deallocates space inside a file in the byte range starting at +// offset and continuing for len bytes. Unimplemented on FreeBSD. +func PunchHole(f *os.File, off, len int64) error { + return nil +} + +// Fadvise predeclares an access pattern for file data. See also 'man 2 +// posix_fadvise'. Unimplemented on FreeBSD. +func Fadvise(f *os.File, off, len int64, advice FadviseAdvice) error { + return nil +} + +// IsEOF reports whether err is an EOF condition. +func IsEOF(err error) bool { return err == io.EOF } diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/fileutil_linux.go b/Godeps/_workspace/src/github.com/cznic/fileutil/fileutil_linux.go new file mode 100644 index 0000000..8babfc5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/fileutil_linux.go @@ -0,0 +1,96 @@ +// Copyright (c) 2014 The fileutil Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !arm + +package fileutil + +import ( + "bytes" + "io" + "io/ioutil" + "os" + "strconv" + "syscall" +) + +func n(s []byte) byte { + for i, c := range s { + if c < '0' || c > '9' { + s = s[:i] + break + } + } + v, _ := strconv.Atoi(string(s)) + return byte(v) +} + +func init() { + b, err := ioutil.ReadFile("/proc/sys/kernel/osrelease") + if err != nil { + panic(err) + } + + tokens := bytes.Split(b, []byte(".")) + if len(tokens) > 3 { + tokens = tokens[:3] + } + switch len(tokens) { + case 3: + // Supported since kernel 2.6.38 + if bytes.Compare([]byte{n(tokens[0]), n(tokens[1]), n(tokens[2])}, []byte{2, 6, 38}) < 0 { + puncher = func(*os.File, int64, int64) error { return nil } + } + case 2: + if bytes.Compare([]byte{n(tokens[0]), n(tokens[1])}, []byte{2, 7}) < 0 { + puncher = func(*os.File, int64, int64) error { return nil } + } + default: + puncher = func(*os.File, int64, int64) error { return nil } + } +} + +var puncher = func(f *os.File, off, len int64) error { + const ( + /* + /usr/include/linux$ grep FL_ falloc.h + */ + _FALLOC_FL_KEEP_SIZE = 0x01 // default is extend size + _FALLOC_FL_PUNCH_HOLE = 0x02 // de-allocates range + ) + + _, _, errno := syscall.Syscall6( + syscall.SYS_FALLOCATE, + uintptr(f.Fd()), + uintptr(_FALLOC_FL_KEEP_SIZE|_FALLOC_FL_PUNCH_HOLE), + uintptr(off), + uintptr(len), + 0, 0) + if errno != 0 { + return os.NewSyscallError("SYS_FALLOCATE", errno) + } + return nil +} + +// PunchHole deallocates space inside a file in the byte range starting at +// offset and continuing for len bytes. No-op for kernels < 2.6.38 (or < 2.7). +func PunchHole(f *os.File, off, len int64) error { + return puncher(f, off, len) +} + +// Fadvise predeclares an access pattern for file data. See also 'man 2 +// posix_fadvise'. +func Fadvise(f *os.File, off, len int64, advice FadviseAdvice) error { + _, _, errno := syscall.Syscall6( + syscall.SYS_FADVISE64, + uintptr(f.Fd()), + uintptr(off), + uintptr(len), + uintptr(advice), + 0, 0) + return os.NewSyscallError("SYS_FADVISE64", errno) +} + +// IsEOF reports whether err is an EOF condition. +func IsEOF(err error) bool { return err == io.EOF } diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/fileutil_openbsd.go b/Godeps/_workspace/src/github.com/cznic/fileutil/fileutil_openbsd.go new file mode 100644 index 0000000..428171b --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/fileutil_openbsd.go @@ -0,0 +1,25 @@ +// Copyright (c) 2014 The fileutil 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 fileutil + +import ( + "io" + "os" +) + +// PunchHole deallocates space inside a file in the byte range starting at +// offset and continuing for len bytes. Similar to FreeBSD, this is +// unimplemented. +func PunchHole(f *os.File, off, len int64) error { + return nil +} + +// Unimplemented on OpenBSD. +func Fadvise(f *os.File, off, len int64, advice FadviseAdvice) error { + return nil +} + +// IsEOF reports whether err is an EOF condition. +func IsEOF(err error) bool { return err == io.EOF } diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/fileutil_plan9.go b/Godeps/_workspace/src/github.com/cznic/fileutil/fileutil_plan9.go new file mode 100644 index 0000000..a2db64e --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/fileutil_plan9.go @@ -0,0 +1,25 @@ +// Copyright (c) 2014 The fileutil 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 fileutil + +import ( + "io" + "os" +) + +// PunchHole deallocates space inside a file in the byte range starting at +// offset and continuing for len bytes. Unimplemented on Plan 9. +func PunchHole(f *os.File, off, len int64) error { + return nil +} + +// Fadvise predeclares an access pattern for file data. See also 'man 2 +// posix_fadvise'. Unimplemented on Plan 9. +func Fadvise(f *os.File, off, len int64, advice FadviseAdvice) error { + return nil +} + +// IsEOF reports whether err is an EOF condition. +func IsEOF(err error) bool { return err == io.EOF } diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/fileutil_solaris.go b/Godeps/_workspace/src/github.com/cznic/fileutil/fileutil_solaris.go new file mode 100644 index 0000000..61dfcde --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/fileutil_solaris.go @@ -0,0 +1,27 @@ +// Copyright (c) 2013 jnml. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build go1.3 + +package fileutil + +import ( + "io" + "os" +) + +// PunchHole deallocates space inside a file in the byte range starting at +// offset and continuing for len bytes. Not supported on Solaris. +func PunchHole(f *os.File, off, len int64) error { + return nil +} + +// Fadvise predeclares an access pattern for file data. See also 'man 2 +// posix_fadvise'. Not supported on Solaris. +func Fadvise(f *os.File, off, len int64, advice FadviseAdvice) error { + return nil +} + +// IsEOF reports whether err is an EOF condition. +func IsEOF(err error) bool { return err == io.EOF } diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/fileutil_windows.go b/Godeps/_workspace/src/github.com/cznic/fileutil/fileutil_windows.go new file mode 100644 index 0000000..3a81f2f --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/fileutil_windows.go @@ -0,0 +1,183 @@ +// Copyright (c) 2014 The fileutil 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 fileutil + +import ( + "io" + "os" + "sync" + "syscall" + "unsafe" +) + +// PunchHole deallocates space inside a file in the byte range starting at +// offset and continuing for len bytes. Not supported on Windows. +func PunchHole(f *os.File, off, len int64) error { + return puncher(f, off, len) +} + +// Fadvise predeclares an access pattern for file data. See also 'man 2 +// posix_fadvise'. Not supported on Windows. +func Fadvise(f *os.File, off, len int64, advice FadviseAdvice) error { + return nil +} + +// IsEOF reports whether err is an EOF condition. +func IsEOF(err error) bool { + if err == io.EOF { + return true + } + + // http://social.technet.microsoft.com/Forums/windowsserver/en-US/1a16311b-c625-46cf-830b-6a26af488435/how-to-solve-error-38-0x26-errorhandleeof-using-fsctlgetretrievalpointers + x, ok := err.(*os.PathError) + return ok && x.Op == "read" && x.Err.(syscall.Errno) == 0x26 +} + +var ( + modkernel32 = syscall.NewLazyDLL("kernel32.dll") + + procDeviceIOControl = modkernel32.NewProc("DeviceIoControl") + + sparseFilesMu sync.Mutex + sparseFiles map[uintptr]struct{} +) + +func init() { + // sparseFiles is an fd set for already "sparsed" files - according to + // msdn.microsoft.com/en-us/library/windows/desktop/aa364225(v=vs.85).aspx + // the file handles are unique per process. + sparseFiles = make(map[uintptr]struct{}) +} + +// puncHoleWindows punches a hole into the given file starting at offset, +// measuring "size" bytes +// (http://msdn.microsoft.com/en-us/library/windows/desktop/aa364597%28v=vs.85%29.aspx) +func puncher(file *os.File, offset, size int64) error { + if err := ensureFileSparse(file); err != nil { + return err + } + + // http://msdn.microsoft.com/en-us/library/windows/desktop/aa364411%28v=vs.85%29.aspx + // typedef struct _FILE_ZERO_DATA_INFORMATION { + // LARGE_INTEGER FileOffset; + // LARGE_INTEGER BeyondFinalZero; + //} FILE_ZERO_DATA_INFORMATION, *PFILE_ZERO_DATA_INFORMATION; + type fileZeroDataInformation struct { + FileOffset, BeyondFinalZero int64 + } + + lpInBuffer := fileZeroDataInformation{ + FileOffset: offset, + BeyondFinalZero: offset + size} + return deviceIOControl(false, file.Fd(), uintptr(unsafe.Pointer(&lpInBuffer)), 16) +} + +// // http://msdn.microsoft.com/en-us/library/windows/desktop/cc948908%28v=vs.85%29.aspx +// type fileSetSparseBuffer struct { +// SetSparse bool +// } + +func ensureFileSparse(file *os.File) (err error) { + fd := file.Fd() + sparseFilesMu.Lock() + if _, ok := sparseFiles[fd]; ok { + sparseFilesMu.Unlock() + return nil + } + + if err = deviceIOControl(true, fd, 0, 0); err == nil { + sparseFiles[fd] = struct{}{} + } + sparseFilesMu.Unlock() + return err +} + +func deviceIOControl(setSparse bool, fd, inBuf, inBufLen uintptr) (err error) { + const ( + //http://source.winehq.org/source/include/winnt.h#L4605 + file_read_data = 1 + file_write_data = 2 + + // METHOD_BUFFERED 0 + method_buffered = 0 + // FILE_ANY_ACCESS 0 + file_any_access = 0 + // FILE_DEVICE_FILE_SYSTEM 0x00000009 + file_device_file_system = 0x00000009 + // FILE_SPECIAL_ACCESS (FILE_ANY_ACCESS) + file_special_access = file_any_access + file_read_access = file_read_data + file_write_access = file_write_data + + // http://source.winehq.org/source/include/winioctl.h + // #define CTL_CODE ( DeviceType, + // Function, + // Method, + // Access ) + // ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) + + // FSCTL_SET_COMPRESSION CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 16, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA) + fsctl_set_compression = (file_device_file_system << 16) | ((file_read_access | file_write_access) << 14) | (16 << 2) | method_buffered + // FSCTL_SET_SPARSE CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 49, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) + fsctl_set_sparse = (file_device_file_system << 16) | (file_special_access << 14) | (49 << 2) | method_buffered + // FSCTL_SET_ZERO_DATA CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 50, METHOD_BUFFERED, FILE_WRITE_DATA) + fsctl_set_zero_data = (file_device_file_system << 16) | (file_write_data << 14) | (50 << 2) | method_buffered + ) + retPtr := uintptr(unsafe.Pointer(&(make([]byte, 8)[0]))) + var r1 uintptr + var e1 syscall.Errno + if setSparse { + // BOOL + // WINAPI + // DeviceIoControl( (HANDLE) hDevice, // handle to a file + // FSCTL_SET_SPARSE, // dwIoControlCode + // (PFILE_SET_SPARSE_BUFFER) lpInBuffer, // input buffer + // (DWORD) nInBufferSize, // size of input buffer + // NULL, // lpOutBuffer + // 0, // nOutBufferSize + // (LPDWORD) lpBytesReturned, // number of bytes returned + // (LPOVERLAPPED) lpOverlapped ); // OVERLAPPED structure + r1, _, e1 = syscall.Syscall9(procDeviceIOControl.Addr(), 8, + fd, + uintptr(fsctl_set_sparse), + // If the lpInBuffer parameter is NULL, the operation will behave the same as if the SetSparse member of the FILE_SET_SPARSE_BUFFER structure were TRUE. In other words, the operation sets the file to a sparse file. + 0, // uintptr(unsafe.Pointer(&lpInBuffer)), + 0, // 1, + 0, + 0, + retPtr, + 0, + 0) + } else { + // BOOL + // WINAPI + // DeviceIoControl( (HANDLE) hDevice, // handle to a file + // FSCTL_SET_ZERO_DATA, // dwIoControlCode + // (LPVOID) lpInBuffer, // input buffer + // (DWORD) nInBufferSize, // size of input buffer + // NULL, // lpOutBuffer + // 0, // nOutBufferSize + // (LPDWORD) lpBytesReturned, // number of bytes returned + // (LPOVERLAPPED) lpOverlapped ); // OVERLAPPED structure + r1, _, e1 = syscall.Syscall9(procDeviceIOControl.Addr(), 8, + fd, + uintptr(fsctl_set_zero_data), + inBuf, + inBufLen, + 0, + 0, + retPtr, + 0, + 0) + } + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return err +} diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/hdb/LICENSE b/Godeps/_workspace/src/github.com/cznic/fileutil/hdb/LICENSE new file mode 100644 index 0000000..1e92e33 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/hdb/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2011 CZ.NIC z.s.p.o. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of CZ.NIC nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/hdb/README b/Godeps/_workspace/src/github.com/cznic/fileutil/hdb/README new file mode 100644 index 0000000..05ce89f --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/hdb/README @@ -0,0 +1,5 @@ +This is a goinstall-able mirror of modified code already published at: +https://git.nic.cz/redmine/projects/gofileutil/repository/show/hdb + +Install: $go get github.com/cznic/fileutil/hdb +Godocs: http://gopkgdoc.appspot.com/pkg/github.com/cznic/fileutil/hdb diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/hdb/all_test.go b/Godeps/_workspace/src/github.com/cznic/fileutil/hdb/all_test.go new file mode 100644 index 0000000..a980587 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/hdb/all_test.go @@ -0,0 +1,15 @@ +// Copyright (c) 2011 CZ.NIC z.s.p.o. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// blame: jnml, labs.nic.cz + +package hdb + +import ( + "testing" +) + +func TestPlaceholder(t *testing.T) { + t.Log("TODO") //TODO +} diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/hdb/hdb.go b/Godeps/_workspace/src/github.com/cznic/fileutil/hdb/hdb.go new file mode 100644 index 0000000..af1e5ee --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/hdb/hdb.go @@ -0,0 +1,153 @@ +// Copyright (c) 2011 CZ.NIC z.s.p.o. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// blame: jnml, labs.nic.cz + +/* +WIP: Package hdb provides a "handle"/value DB like store, but actually it's +closer to the model of a process's virtual memory and its alloc, free and move +methods. + +The hdb package is a thin layer around falloc.File providing stable-only +handles and the basic synchronizing primitives. The central functionality of +hdb are the New, Set, Get and Delete methods of Store. + +Conceptual analogy: + New alloc(sizeof(content)), return new "memory" pointer (a handle). + + Get memmove() from "memory" "pointed to" by handle to the result content. + Note: Handle "knows" the size of its content. + + Set memmove() from content to "memory" pointed to by handle. + In contrast to real memory, the new content may have different + size than the previously stored one w/o additional handling + and the "pointer" handle remains the same. + + Delete free() the "memory" "pointed to" by handle. +*/ +package hdb + +import ( + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/fileutil/falloc" + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/fileutil/storage" +) + +type Store struct { + f *falloc.File +} + +// New returns a newly created Store backed by accessor, discarding its conents if any. +// If successful, methods on the returned Store can be used for I/O. +// It returns the Store and an error, if any. +func New(accessor storage.Accessor) (store *Store, err error) { + s := &Store{} + if s.f, err = falloc.New(accessor); err == nil { + store = s + } + return +} + +// Open opens the Store from accessor. +// If successful, methods on the returned Store can be used for data exchange. +// It returns the Store and an error, if any. +func Open(accessor storage.Accessor) (store *Store, err error) { + s := &Store{} + if s.f, err = falloc.Open(accessor); err == nil { + store = s + } + return +} + +// Close closes the store. Further access to the store has undefined behavior and may panic. +// It returns an error, if any. +func (s *Store) Close() (err error) { + defer func() { + s.f = nil + }() + + return s.f.Close() +} + +// Delete deletes the data associated with handle. +// It returns an error if any. +func (s *Store) Delete(handle falloc.Handle) (err error) { + return s.f.Free(handle) +} + +// Get gets the data associated with handle. +// It returns the data and an error, if any. +func (s *Store) Get(handle falloc.Handle) (b []byte, err error) { + return s.f.Read(handle) +} + +// New associates data with a new handle. +// It returns the handle and an error, if any. +func (s *Store) New(b []byte) (handle falloc.Handle, err error) { + return s.f.Alloc(b) +} + +// Set associates data with an existing handle. +// It returns an error, if any. +func (s *Store) Set(handle falloc.Handle, b []byte) (err error) { + _, err = s.f.Realloc(handle, b, true) + return +} + +// Root returns the handle of the DB root (top level directory, ...). +func (s *Store) Root() falloc.Handle { + return s.f.Root() +} + +// File returns the underlying falloc.File of 's'. +func (s *Store) File() *falloc.File { + return s.f +} + +// Lock locks 's' for writing. If the lock is already locked for reading or writing, +// Lock blocks until the lock is available. To ensure that the lock eventually becomes available, +// a blocked Lock call excludes new readers from acquiring the lock. +func (s *Store) Lock() { + s.f.Lock() +} + +// RLock locks 's' for reading. If the lock is already locked for writing or there is a writer +// already waiting to release the lock, RLock blocks until the writer has released the lock. +func (s *Store) RLock() { + s.f.RLock() +} + +// Unlock unlocks 's' for writing. It's a run-time error if 's' is not locked for writing on entry to Unlock. +// +// As with Mutexes, a locked RWMutex is not associated with a particular goroutine. +// One goroutine may RLock (Lock) 's' and then arrange for another goroutine to RUnlock (Unlock) it. +func (s *Store) Unlock() { + s.f.Unlock() +} + +// RUnlock undoes a single RLock call; it does not affect other simultaneous readers. +// It's a run-time error if 's' is not locked for reading on entry to RUnlock. +func (s *Store) RUnlock() { + s.f.RUnlock() +} + +// LockedNew wraps New in a Lock/Unlock pair. +func (s *Store) LockedNew(b []byte) (handle falloc.Handle, err error) { + return s.f.LockedAlloc(b) +} + +// LockedDelete wraps Delete in a Lock/Unlock pair. +func (s *Store) LockedDelete(handle falloc.Handle) (err error) { + return s.f.LockedFree(handle) +} + +// LockedGet wraps Get in a RLock/RUnlock pair. +func (s *Store) LockedGet(handle falloc.Handle) (b []byte, err error) { + return s.f.LockedRead(handle) +} + +// LockedSet wraps Set in a Lock/Unlock pair. +func (s *Store) LockedSet(handle falloc.Handle, b []byte) (err error) { + _, err = s.f.Realloc(handle, b, true) + return +} diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/hdb/test_deps.go b/Godeps/_workspace/src/github.com/cznic/fileutil/hdb/test_deps.go new file mode 100644 index 0000000..3164f63 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/hdb/test_deps.go @@ -0,0 +1,13 @@ +// Copyright (c) 2011 CZ.NIC z.s.p.o. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// blame: jnml, labs.nic.cz + +package hdb + +// Pull test dependencies too. +// Enables easy 'go test X' after 'go get X' +import ( +// nothing yet +) diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/punch_test.go b/Godeps/_workspace/src/github.com/cznic/fileutil/punch_test.go new file mode 100644 index 0000000..766f6f4 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/punch_test.go @@ -0,0 +1,55 @@ +// Copyright (c) 2014 The fileutil 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 fileutil + +import ( + "io/ioutil" + "os" + "testing" +) + +func TestPunch(t *testing.T) { + file, err := ioutil.TempFile("", "punchhole-") + if err != nil { + t.Error(err) + } + defer os.Remove(file.Name()) + defer file.Close() + buf := make([]byte, 10<<20) + for i := range buf { + buf[i] = byte(1 + (i+1)&0xfe) + } + if _, err = file.Write(buf); err != nil { + t.Errorf("error writing to the temp file: %v", err) + t.FailNow() + } + if err = file.Sync(); err != nil { + t.Logf("error syncing %q: %v", file.Name(), err) + } + for i, j := range []int{1, 31, 1 << 10} { + if err = PunchHole(file, int64(j), int64(j)); err != nil { + t.Errorf("%d. error punching at %d, size %d: %v", i, j, j, err) + continue + } + // read back, with 1-1 bytes overlaid + n, err := file.ReadAt(buf[:j+2], int64(j-1)) + if err != nil { + t.Errorf("%d. error reading file: %v", i, err) + continue + } + buf = buf[:n] + if buf[0] == 0 { + t.Errorf("%d. file at %d has been overwritten with 0!", i, j-1) + } + if buf[n-1] == 0 { + t.Errorf("%d. file at %d has been overwritten with 0!", i, j-1+n) + } + for k, v := range buf[1 : n-1] { + if v != 0 { + t.Errorf("%d. error reading file at %d got %d, want 0.", i, k, v) + } + } + } +} diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/storage/LICENSE b/Godeps/_workspace/src/github.com/cznic/fileutil/storage/LICENSE new file mode 100644 index 0000000..1e92e33 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/storage/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2011 CZ.NIC z.s.p.o. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of CZ.NIC nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/storage/README b/Godeps/_workspace/src/github.com/cznic/fileutil/storage/README new file mode 100644 index 0000000..2a400fc --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/storage/README @@ -0,0 +1,5 @@ +This is a goinstall-able mirror of modified code already published at: +https://git.nic.cz/redmine/projects/gofileutil/repository/show/storage + +Install: $go get github.com/cznic/fileutil/storage +Godocs: http://gopkgdoc.appspot.com/pkg/github.com/cznic/fileutil/storage diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/storage/all_test.go b/Godeps/_workspace/src/github.com/cznic/fileutil/storage/all_test.go new file mode 100644 index 0000000..8947a0a --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/storage/all_test.go @@ -0,0 +1,22 @@ +// Copyright (c) 2011 CZ.NIC z.s.p.o. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// blame: jnml, labs.nic.cz + +package storage + +import ( + "flag" + "runtime" +) + +var ( + devFlag = flag.Bool("dev", false, "enable dev tests") + goFlag = flag.Int("go", 1, "GOMAXPROCS") +) + +func init() { + flag.Parse() + runtime.GOMAXPROCS(*goFlag) +} diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/storage/cache.go b/Godeps/_workspace/src/github.com/cznic/fileutil/storage/cache.go new file mode 100644 index 0000000..3a6115a --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/storage/cache.go @@ -0,0 +1,322 @@ +// Copyright (c) 2011 CZ.NIC z.s.p.o. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// blame: jnml, labs.nic.cz + +package storage + +import ( + "container/list" + "io" + "math" + "os" + "sync" + "sync/atomic" +) + +type cachepage struct { + b [512]byte + dirty bool + lru *list.Element + pi int64 + valid int // page content is b[:valid] +} + +func (p *cachepage) wr(b []byte, off int) (wasDirty bool) { + copy(p.b[off:], b) + if n := off + len(b); n > p.valid { + p.valid = n + } + wasDirty = p.dirty + p.dirty = true + return +} + +func (c *Cache) rd(off int64, read bool) (p *cachepage, ok bool) { + c.Rq++ + pi := off >> 9 + if p, ok = c.m[pi]; ok { + c.lru.MoveToBack(p.lru) + return + } + + if !read { + return + } + + fp := off &^ 511 + if fp >= c.size { + return + } + + rq := 512 + if fp+512 > c.size { + rq = int(c.size - fp) + } + p = &cachepage{pi: pi, valid: rq} + p.lru = c.lru.PushBack(p) + if n, err := c.f.ReadAt(p.b[:p.valid], fp); n != rq { + panic(err) + } + + c.Load++ + if c.advise != nil { + c.advise(fp, 512, false) + } + c.m[pi], ok = p, true + return +} + +func (c *Cache) wr(off int64) (p *cachepage) { + var ok bool + if p, ok = c.rd(off, false); ok { + return + } + + pi := off >> 9 + p = &cachepage{pi: pi} + p.lru = c.lru.PushBack(p) + c.m[pi] = p + return +} + +// Cache provides caching support for another store Accessor. +type Cache struct { + advise func(int64, int, bool) + clean chan bool + cleaning int32 + close chan bool + f Accessor + fi *FileInfo + lock sync.Mutex + lru *list.List + m map[int64]*cachepage + maxpages int + size int64 + sync chan bool + wlist *list.List + write chan bool + writing int32 + Rq int64 // Pages requested from cache + Load int64 // Pages loaded (cache miss) + Purge int64 // Pages purged + Top int // "High water" pages +} + +// Implementation of Accessor. +func (c *Cache) BeginUpdate() error { return nil } + +// Implementation of Accessor. +func (c *Cache) EndUpdate() error { return nil } + +// NewCache creates a caching Accessor from store with total of maxcache bytes. +// NewCache returns the new Cache, implementing Accessor or an error if any. +// +// The LRU mechanism is used, so the cache tries to keep often accessed pages cached. +// +func NewCache(store Accessor, maxcache int64, advise func(int64, int, bool)) (c *Cache, err error) { + var fi os.FileInfo + if fi, err = store.Stat(); err != nil { + return + } + + x := maxcache >> 9 + if x > math.MaxInt32/2 { + x = math.MaxInt32 / 2 + } + c = &Cache{ + advise: advise, + clean: make(chan bool, 1), + close: make(chan bool), + f: store, + lru: list.New(), // front == oldest used, back == last recently used + m: make(map[int64]*cachepage), + maxpages: int(x), + size: fi.Size(), + sync: make(chan bool), + wlist: list.New(), + write: make(chan bool, 1), + } + c.fi = NewFileInfo(fi, c) + go c.writer() + go c.cleaner(int((int64(c.maxpages) * 95) / 100)) // hysteresis + return +} + +func (c *Cache) Accessor() Accessor { + return c.f +} + +func (c *Cache) Close() (err error) { + close(c.write) + <-c.close + close(c.clean) + <-c.close + return c.f.Close() +} + +func (c *Cache) Name() (s string) { + return c.f.Name() +} + +func (c *Cache) ReadAt(b []byte, off int64) (n int, err error) { + po := int(off) & 0x1ff + bp := 0 + rem := len(b) + m := 0 + for rem != 0 { + c.lock.Lock() // X1+ + p, ok := c.rd(off, true) + if !ok { + c.lock.Unlock() // X1- + return -1, io.EOF + } + + rq := rem + if po+rq > 512 { + rq = 512 - po + } + if n := copy(b[bp:bp+rq], p.b[po:p.valid]); n != rq { + c.lock.Unlock() // X1- + return -1, io.EOF + } + + m = len(c.m) + c.lock.Unlock() // X1- + po = 0 + bp += rq + off += int64(rq) + rem -= rq + n += rq + } + if m > c.maxpages && atomic.CompareAndSwapInt32(&c.cleaning, 0, 1) { + if m > c.Top { + c.Top = m + } + c.clean <- true + } + return +} + +func (c *Cache) Stat() (fi os.FileInfo, err error) { + c.lock.Lock() + defer c.lock.Unlock() + return c.fi, nil +} + +func (c *Cache) Sync() (err error) { + c.write <- false + <-c.sync + return +} + +func (c *Cache) Truncate(size int64) (err error) { + c.Sync() //TODO improve (discard pages, the writer goroutine should also be aware, ...) + c.lock.Lock() + defer c.lock.Unlock() + c.size = size + return c.f.Truncate(size) +} + +func (c *Cache) WriteAt(b []byte, off int64) (n int, err error) { + po := int(off) & 0x1ff + bp := 0 + rem := len(b) + m := 0 + for rem != 0 { + c.lock.Lock() // X+ + p := c.wr(off) + rq := rem + if po+rq > 512 { + rq = 512 - po + } + if wasDirty := p.wr(b[bp:bp+rq], po); !wasDirty { + c.wlist.PushBack(p) + } + m = len(c.m) + po = 0 + bp += rq + off += int64(rq) + if off > c.size { + c.size = off + } + c.lock.Unlock() // X- + rem -= rq + n += rq + } + if atomic.CompareAndSwapInt32(&c.writing, 0, 1) { + c.write <- true + } + if m > c.maxpages && atomic.CompareAndSwapInt32(&c.cleaning, 0, 1) { + if m > c.Top { + c.Top = m + } + c.clean <- true + } + return +} + +func (c *Cache) writer() { + for ok := true; ok; { + var wr bool + var off int64 + wr, ok = <-c.write + for { + c.lock.Lock() // X1+ + item := c.wlist.Front() + if item == nil { + c.lock.Unlock() // X1- + break + } + + p := item.Value.(*cachepage) + off = p.pi << 9 + if n, err := c.f.WriteAt(p.b[:p.valid], off); n != p.valid { + c.lock.Unlock() // X1- + panic("TODO Cache.writer errchan") //TODO +errchan + panic(err) + } + + p.dirty = false + c.wlist.Remove(item) + if c.advise != nil { + c.advise(off, 512, true) + } + c.lock.Unlock() // X1- + } + switch { + case wr: + atomic.AddInt32(&c.writing, -1) + case ok: + c.sync <- true + } + } + c.close <- true +} + +func (c *Cache) cleaner(limit int) { + for _ = range c.clean { + var item *list.Element + for { + c.lock.Lock() // X1+ + if len(c.m) < limit { + c.lock.Unlock() // X1- + break + } + + if item == nil { + item = c.lru.Front() + } + if p := item.Value.(*cachepage); !p.dirty { + delete(c.m, p.pi) + c.lru.Remove(item) + c.Purge++ + } + item = item.Next() + c.lock.Unlock() // X1- + } + atomic.AddInt32(&c.cleaning, -1) + } + c.close <- true +} diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/storage/cache_test.go b/Godeps/_workspace/src/github.com/cznic/fileutil/storage/cache_test.go new file mode 100644 index 0000000..8dbad08 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/storage/cache_test.go @@ -0,0 +1,83 @@ +// Copyright (c) 2011 CZ.NIC z.s.p.o. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// blame: jnml, labs.nic.cz + +package storage + +import ( + "io/ioutil" + "os" + "path/filepath" + "testing" +) + +func newfile(t *testing.T) (string, string, Accessor) { + dir, err := ioutil.TempDir("", "test-storage-") + if err != nil { + panic(err) + } + + name := filepath.Join(dir, "test.tmp") + f, err := NewFile(name, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0666) + if err != nil { + t.Fatal("newfile", err) + } + + return dir, name, f +} + +func readfile(t *testing.T, name string) (b []byte) { + var err error + if b, err = ioutil.ReadFile(name); err != nil { + t.Fatal("readfile") + } + + return +} + +func newcache(t *testing.T) (dir, name string, c *Cache) { + dir, name, f := newfile(t) + var err error + if c, err = NewCache(f, 1<<20, nil); err != nil { + t.Fatal("newCache", err) + } + + return +} + +func TestCache0(t *testing.T) { + dir, name, c := newcache(t) + defer os.RemoveAll(dir) + + if err := c.Close(); err != nil { + t.Fatal(10, err) + } + + if b := readfile(t, name); len(b) != 0 { + t.Fatal(20, len(b), 0) + } +} + +func TestCache1(t *testing.T) { + dir, name, c := newcache(t) + defer os.RemoveAll(dir) + + if n, err := c.WriteAt([]byte{0xa5}, 0); n != 1 { + t.Fatal(20, n, err) + } + + if err := c.Close(); err != nil { + t.Fatal(10, err) + } + + b := readfile(t, name) + if len(b) != 1 { + t.Fatal(30, len(b), 1) + } + + if b[0] != 0xa5 { + t.Fatal(40, b[0], 0xa5) + } +} diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/storage/dev_test.go b/Godeps/_workspace/src/github.com/cznic/fileutil/storage/dev_test.go new file mode 100644 index 0000000..7287a27 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/storage/dev_test.go @@ -0,0 +1,18 @@ +// Copyright (c) 2011 CZ.NIC z.s.p.o. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// blame: jnml, labs.nic.cz + +package storage + +import ( + "testing" +) + +func TestDevNothing(t *testing.T) { + if !*devFlag { + t.Log("not enabled") + return + } +} diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/storage/file.go b/Godeps/_workspace/src/github.com/cznic/fileutil/storage/file.go new file mode 100644 index 0000000..94feda5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/storage/file.go @@ -0,0 +1,50 @@ +// Copyright (c) 2011 CZ.NIC z.s.p.o. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// blame: jnml, labs.nic.cz + +package storage + +import ( + "os" +) + +// FileAccessor is the concrete type returned by NewFile and OpenFile. +type FileAccessor struct { + *os.File +} + +// Implementation of Accessor. +func (f *FileAccessor) BeginUpdate() error { return nil } + +// Implementation of Accessor. +func (f *FileAccessor) EndUpdate() error { return nil } + +// NewFile returns an Accessor backed by an os.File named name, It opens the +// named file with specified flag (os.O_RDWR etc.) and perm, (0666 etc.) if +// applicable. If successful, methods on the returned Accessor can be used for +// I/O. It returns the Accessor and an Error, if any. +// +// NOTE: The returned Accessor implements BeginUpdate and EndUpdate as a no op. +func NewFile(name string, flag int, perm os.FileMode) (store Accessor, err error) { + var f FileAccessor + if f.File, err = os.OpenFile(name, flag, perm); err == nil { + store = &f + } + return +} + +// OpenFile returns an Accessor backed by an existing os.File named name, It +// opens the named file with specified flag (os.O_RDWR etc.) and perm, (0666 +// etc.) if applicable. If successful, methods on the returned Accessor can be +// used for I/O. It returns the Accessor and an Error, if any. +// +// NOTE: The returned Accessor implements BeginUpdate and EndUpdate as a no op. +func OpenFile(name string, flag int, perm os.FileMode) (store Accessor, err error) { + var f FileAccessor + if f.File, err = os.OpenFile(name, flag, perm); err == nil { + store = &f + } + return +} diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/storage/mem.go b/Godeps/_workspace/src/github.com/cznic/fileutil/storage/mem.go new file mode 100644 index 0000000..7cda0b6 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/storage/mem.go @@ -0,0 +1,161 @@ +// Copyright (c) 2011 CZ.NIC z.s.p.o. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// blame: jnml, labs.nic.cz + +package storage + +import ( + "errors" + "fmt" + "io/ioutil" + "math" + "os" +) + +//TODO -> exported type w/ exported fields +type memaccessor struct { + f *os.File + fi *FileInfo + b []byte +} + +// Implementation of Accessor. +func (m *memaccessor) BeginUpdate() error { return nil } + +// Implementation of Accessor. +func (f *memaccessor) EndUpdate() error { return nil } + +// NewMem returns a new Accessor backed by an os.File. The returned Accessor +// keeps all of the store content in memory. The memory and file images are +// synced only by Sync and Close. Recomended for small amounts of data only +// and content which may be lost on process kill/crash. NewMem return the +// Accessor or an error of any. +// +// NOTE: The returned Accessor implements BeginUpdate and EndUpdate as a no op. +func NewMem(f *os.File) (store Accessor, err error) { + a := &memaccessor{f: f} + if err = f.Truncate(0); err != nil { + return + } + + var fi os.FileInfo + if fi, err = a.f.Stat(); err != nil { + return + } + + a.fi = NewFileInfo(fi, a) + store = a + return +} + +// OpenMem return a new Accessor backed by an os.File. The store content is +// loaded from f. The returned Accessor keeps all of the store content in +// memory. The memory and file images are synced only Sync and Close. +// Recomended for small amounts of data only and content which may be lost on +// process kill/crash. OpenMem return the Accessor or an error of any. +// +// NOTE: The returned Accessor implements BeginUpdate and EndUpdate as a no op. +func OpenMem(f *os.File) (store Accessor, err error) { + a := &memaccessor{f: f} + if a.b, err = ioutil.ReadAll(a.f); err != nil { + a.f.Close() + return + } + + var fi os.FileInfo + if fi, err = a.f.Stat(); err != nil { + a.f.Close() + return + } + + a.fi = NewFileInfo(fi, a) + store = a + return +} + +// Close implements Accessor. Specifically it synchronizes the memory and file images. +func (a *memaccessor) Close() (err error) { + defer func() { + a.b = nil + if a.f != nil { + if e := a.f.Close(); e != nil && err == nil { + err = e + } + } + a.f = nil + }() + + return a.Sync() +} + +func (a *memaccessor) Name() string { + return a.f.Name() +} + +func (a *memaccessor) ReadAt(b []byte, off int64) (n int, err error) { + if off < 0 || off > math.MaxInt32 { + return -1, fmt.Errorf("ReadAt: illegal offset %#x", off) + } + + rq, fp := len(b), int(off) + if fp+rq > len(a.b) { + return -1, fmt.Errorf("ReadAt: illegal rq %#x @ offset %#x, len %#x", rq, fp, len(a.b)) + } + + copy(b, a.b[fp:]) + return +} + +func (a *memaccessor) Stat() (fi os.FileInfo, err error) { + i := a.fi + i.FSize = int64(len(a.b)) + fi = i + return +} + +// Sync implements Accessor. Specifically it synchronizes the memory and file images. +func (a *memaccessor) Sync() (err error) { + var n int + if n, err = a.f.WriteAt(a.b, 0); n != len(a.b) { + return + } + + return a.f.Truncate(int64(len(a.b))) +} + +func (a *memaccessor) Truncate(size int64) (err error) { + defer func() { + if e := recover(); e != nil { + err = e.(error) + } + }() + + if size > math.MaxInt32 { + panic(errors.New("truncate: illegal size")) + } + + a.b = a.b[:int(size)] + return +} + +func (a *memaccessor) WriteAt(b []byte, off int64) (n int, err error) { + if off < 0 || off > math.MaxInt32 { + return -1, errors.New("WriteAt: illegal offset") + } + + rq, fp, size := len(b), int(off), len(a.b) + if need := rq + fp; need > size { + if need <= cap(a.b) { + a.b = a.b[:need] + } else { + nb := make([]byte, need, 2*need) + copy(nb, a.b) + a.b = nb + } + } + + copy(a.b[int(off):], b) + return +} diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/storage/mem_test.go b/Godeps/_workspace/src/github.com/cznic/fileutil/storage/mem_test.go new file mode 100644 index 0000000..921948c --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/storage/mem_test.go @@ -0,0 +1,15 @@ +// Copyright (c) 2011 CZ.NIC z.s.p.o. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// blame: jnml, labs.nic.cz + +package storage + +import ( + "testing" +) + +func Test(t *testing.T) { + t.Log("TODO placeholder") //TODO +} diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/storage/probe.go b/Godeps/_workspace/src/github.com/cznic/fileutil/storage/probe.go new file mode 100644 index 0000000..53b146a --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/storage/probe.go @@ -0,0 +1,74 @@ +// Copyright (c) 2011 CZ.NIC z.s.p.o. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// blame: jnml, labs.nic.cz + +package storage + +import "sync/atomic" + +// Probe collects usage statistics of the embeded Accessor. +// Probe itself IS an Accessor. +type Probe struct { + Accessor + Chain *Probe + OpsRd int64 + OpsWr int64 + BytesRd int64 + BytesWr int64 + SectorsRd int64 // Assuming 512 byte sector size + SectorsWr int64 +} + +// NewProbe returns a newly created probe which embedes the src Accessor. +// The retuned *Probe satisfies Accessor. if chain != nil then Reset() +// is cascaded down the chained Probes. +func NewProbe(src Accessor, chain *Probe) *Probe { + return &Probe{Accessor: src, Chain: chain} +} + +func reset(n *int64) { + atomic.AddInt64(n, -atomic.AddInt64(n, 0)) +} + +// Reset zeroes the collected statistics of p. +func (p *Probe) Reset() { + if p.Chain != nil { + p.Chain.Reset() + } + reset(&p.OpsRd) + reset(&p.OpsWr) + reset(&p.BytesRd) + reset(&p.BytesWr) + reset(&p.SectorsRd) + reset(&p.SectorsWr) +} + +func (p *Probe) ReadAt(b []byte, off int64) (n int, err error) { + n, err = p.Accessor.ReadAt(b, off) + atomic.AddInt64(&p.OpsRd, 1) + atomic.AddInt64(&p.BytesRd, int64(n)) + if n <= 0 { + return + } + + sectorFirst := off >> 9 + sectorLast := (off + int64(n) - 1) >> 9 + atomic.AddInt64(&p.SectorsRd, sectorLast-sectorFirst+1) + return +} + +func (p *Probe) WriteAt(b []byte, off int64) (n int, err error) { + n, err = p.Accessor.WriteAt(b, off) + atomic.AddInt64(&p.OpsWr, 1) + atomic.AddInt64(&p.BytesWr, int64(n)) + if n <= 0 { + return + } + + sectorFirst := off >> 9 + sectorLast := (off + int64(n) - 1) >> 9 + atomic.AddInt64(&p.SectorsWr, sectorLast-sectorFirst+1) + return +} diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/storage/probe_test.go b/Godeps/_workspace/src/github.com/cznic/fileutil/storage/probe_test.go new file mode 100644 index 0000000..00eca8e --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/storage/probe_test.go @@ -0,0 +1,86 @@ +// Copyright (c) 2011 CZ.NIC z.s.p.o. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// blame: jnml, labs.nic.cz + +package storage + +import ( + "os" + "testing" +) + +func (p *Probe) assert(t *testing.T, msg int, opsRd, opsWr, bytesRd, bytesWr, sectorsRd, sectorsWr int64) { + if n := p.OpsRd; n != opsRd { + t.Fatal(msg, n, opsRd) + } + + if n := p.OpsWr; n != opsWr { + t.Fatal(msg+1, n, opsWr) + } + + if n := p.BytesRd; n != bytesRd { + t.Fatal(msg+2, n, bytesRd) + } + + if n := p.BytesWr; n != bytesWr { + t.Fatal(msg+3, n, bytesWr) + } + + if n := p.SectorsRd; n != sectorsRd { + t.Fatal(msg+4, n, sectorsRd) + } + + if n := p.SectorsWr; n != sectorsWr { + t.Fatal(msg+5, n, sectorsWr) + } +} + +func TestProbe(t *testing.T) { + return //TODO disabled due to atomic.AddInt64 failing on W32 + const fn = "test.tmp" + + store, err := NewFile(fn, os.O_CREATE|os.O_RDWR|os.O_CREATE, 0666) + if err != nil { + t.Fatal(10, err) + } + + defer func() { + ec := store.Close() + er := os.Remove(fn) + if ec != nil { + t.Fatal(10000, ec) + } + if er != nil { + t.Fatal(10001, er) + } + }() + + probe := NewProbe(store, nil) + if n, err := probe.WriteAt([]byte{1}, 0); n != 1 { + t.Fatal(20, err) + } + + probe.assert(t, 30, 0, 1, 0, 1, 0, 1) + b := []byte{0} + if n, err := probe.ReadAt(b, 0); n != 1 { + t.Fatal(40, err) + } + + if n := b[0]; n != 1 { + t.Fatal(50, n, 1) + } + + probe.assert(t, 60, 1, 1, 1, 1, 1, 1) + if n, err := probe.WriteAt([]byte{2, 3}, 510); n != 2 { + t.Fatal(70, err) + } + + probe.assert(t, 80, 1, 2, 1, 3, 1, 2) + if n, err := probe.WriteAt([]byte{2, 3}, 511); n != 2 { + t.Fatal(90, err) + } + + probe.assert(t, 100, 1, 3, 1, 5, 1, 4) +} diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/storage/storage.go b/Godeps/_workspace/src/github.com/cznic/fileutil/storage/storage.go new file mode 100644 index 0000000..4956053 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/storage/storage.go @@ -0,0 +1,141 @@ +// Copyright (c) 2011 CZ.NIC z.s.p.o. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// blame: jnml, labs.nic.cz + +// WIP: Package storage defines and implements storage providers and store accessors. +package storage + +import ( + "os" + "sync" + "time" +) + +// FileInfo is a type implementing os.FileInfo which has setable fields, like +// the older os.FileInfo used to have. It is used wehere e.g. the Size is +// needed to be faked (encapsulated/memory only file, file cache, etc.). +type FileInfo struct { + FName string // base name of the file + FSize int64 // length in bytes + FMode os.FileMode // file mode bits + FModTime time.Time // modification time + FIsDir bool // abbreviation for Mode().IsDir() + sys interface{} // underlying data source (can be nil) +} + +// NewFileInfo creates FileInfo from os.FileInfo fi. +func NewFileInfo(fi os.FileInfo, sys interface{}) *FileInfo { + return &FileInfo{fi.Name(), fi.Size(), fi.Mode(), fi.ModTime(), fi.IsDir(), sys} +} + +// Implementation of os.FileInfo +func (fi *FileInfo) Name() string { + return fi.FName +} + +// Implementation of os.FileInfo +func (fi *FileInfo) Size() int64 { + return fi.FSize +} + +// Implementation of os.FileInfo +func (fi *FileInfo) Mode() os.FileMode { + return fi.FMode +} + +// Implementation of os.FileInfo +func (fi *FileInfo) ModTime() time.Time { + return fi.FModTime +} + +// Implementation of os.FileInfo +func (fi *FileInfo) IsDir() bool { + return fi.FIsDir +} + +func (fi *FileInfo) Sys() interface{} { + return fi.sys +} + +// Accessor provides I/O methods to access a store. +type Accessor interface { + + // Close closes the store, rendering it unusable for I/O. It returns an + // error, if any. + Close() error + + // Name returns the name of the file as presented to Open. + Name() string + + // ReadAt reads len(b) bytes from the store starting at byte offset off. + // It returns the number of bytes read and the error, if any. + // EOF is signaled by a zero count with err set to os.EOF. + // ReadAt always returns a non-nil Error when n != len(b). + ReadAt(b []byte, off int64) (n int, err error) + + // Stat returns the FileInfo structure describing the store. It returns + // the os.FileInfo and an error, if any. + Stat() (fi os.FileInfo, err error) + + // Sync commits the current contents of the store to stable storage. + // Typically, this means flushing the file system's in-memory copy of + // recently written data to disk. + Sync() (err error) + + // Truncate changes the size of the store. It does not change the I/O + // offset. + Truncate(size int64) error + + // WriteAt writes len(b) bytes to the store starting at byte offset off. + // It returns the number of bytes written and an error, if any. + // WriteAt returns a non-nil Error when n != len(b). + WriteAt(b []byte, off int64) (n int, err error) + + // Before every [structural] change of a store the BeginUpdate is to be + // called and paired with EndUpdate after the change makes the store's + // state consistent again. Invocations of BeginUpdate may nest. On + // invoking the last non nested EndUpdate an implicit "commit" should + // be performed by the store/provider. The concrete mechanism is + // unspecified. It could be for example a write-ahead log. Stores may + // implement BeginUpdate and EndUpdate as a (documented) no op. + BeginUpdate() error + EndUpdate() error +} + +// Mutate is a helper/wrapper for executing f in between a.BeginUpdate and +// a.EndUpdate. Any parameters and/or return values except an error should be +// captured by a function literal passed as f. The returned err is either nil +// or the first non nil error returned from the sequence of execution: +// BeginUpdate, [f,] EndUpdate. The pair BeginUpdate/EndUpdate *is* invoked +// always regardles of any possible errors produced. Mutate doesn't handle +// panic, it should be used only with a function [literal] which doesn't panic. +// Otherwise the pairing of BeginUpdate/EndUpdate is not guaranteed. +// +// NOTE: If BeginUpdate, which is invoked before f, returns a non-nil error, +// then f is not invoked at all (but EndUpdate still is). +func Mutate(a Accessor, f func() error) (err error) { + defer func() { + if e := a.EndUpdate(); e != nil && err == nil { + err = e + } + }() + + if err = a.BeginUpdate(); err != nil { + return + } + + return f() +} + +// LockedMutate wraps Mutate in yet another layer consisting of a +// l.Lock/l.Unlock pair. All other limitations apply as in Mutate, e.g. no +// panics are allowed to happen - otherwise no guarantees can be made about +// Unlock matching the Lock. +func LockedMutate(a Accessor, l sync.Locker, f func() error) (err error) { + l.Lock() + defer l.Unlock() + + return Mutate(a, f) +} diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/storage/test_deps.go b/Godeps/_workspace/src/github.com/cznic/fileutil/storage/test_deps.go new file mode 100644 index 0000000..92ac44a --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/storage/test_deps.go @@ -0,0 +1,13 @@ +// Copyright (c) 2011 CZ.NIC z.s.p.o. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// blame: jnml, labs.nic.cz + +package storage + +// Pull test dependencies too. +// Enables easy 'go test X' after 'go get X' +import ( +// nothing yet +) diff --git a/Godeps/_workspace/src/github.com/cznic/fileutil/test_deps.go b/Godeps/_workspace/src/github.com/cznic/fileutil/test_deps.go new file mode 100644 index 0000000..eec608a --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/fileutil/test_deps.go @@ -0,0 +1,13 @@ +// Copyright (c) 2014 The fileutil Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// blame: jnml, labs.nic.cz + +package fileutil + +// Pull test dependencies too. +// Enables easy 'go test X' after 'go get X' +import ( +// nothing yet +) diff --git a/Godeps/_workspace/src/github.com/cznic/mathutil/AUTHORS b/Godeps/_workspace/src/github.com/cznic/mathutil/AUTHORS new file mode 100644 index 0000000..d04c450 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/mathutil/AUTHORS @@ -0,0 +1,12 @@ +# This file lists authors for copyright purposes. This file is distinct from +# the CONTRIBUTORS files. See the latter for an explanation. +# +# Names should be added to this file as: +# Name or Organization +# +# The email address is not required for organizations. +# +# Please keep the list sorted. + +CZ.NIC z.s.p.o. +Jan Mercl <0xjnml@gmail.com> diff --git a/Godeps/_workspace/src/github.com/cznic/mathutil/CONTRIBUTORS b/Godeps/_workspace/src/github.com/cznic/mathutil/CONTRIBUTORS new file mode 100644 index 0000000..9c9a5dd --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/mathutil/CONTRIBUTORS @@ -0,0 +1,10 @@ +# This file lists people who contributed code to this repository. The AUTHORS +# file lists the copyright holders; this file lists people. +# +# Names should be added to this file like so: +# Name +# +# Please keep the list sorted. + +Gary Burd +Jan Mercl <0xjnml@gmail.com> diff --git a/Godeps/_workspace/src/github.com/cznic/mathutil/LICENSE b/Godeps/_workspace/src/github.com/cznic/mathutil/LICENSE new file mode 100644 index 0000000..128a1b6 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/mathutil/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2014 The mathutil Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the names of the authors nor the names of the +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Godeps/_workspace/src/github.com/cznic/mathutil/Makefile b/Godeps/_workspace/src/github.com/cznic/mathutil/Makefile new file mode 100644 index 0000000..b99ba9a --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/mathutil/Makefile @@ -0,0 +1,31 @@ +# Copyright (c) 2014 The mathutil Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +.PHONY: all todo clean nuke + +grep=--include=*.go --include=*.run --include=*.y + +all: editor + go build + go vet || true + golint . + go install + make todo + +clean: + go clean + +editor: + go fmt + go test -i + go test + +todo: + @grep -nr $(grep) ^[[:space:]]*_[[:space:]]*=[[:space:]][[:alpha:]][[:alnum:]]* * || true + @grep -nr $(grep) TODO * || true + @grep -nr $(grep) BUG * || true + @grep -nr $(grep) println * || true + +nuke: clean + go clean -i diff --git a/Godeps/_workspace/src/github.com/cznic/mathutil/README b/Godeps/_workspace/src/github.com/cznic/mathutil/README new file mode 100644 index 0000000..a9ee59c --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/mathutil/README @@ -0,0 +1,10 @@ +This is a goinstall-able mirror of modified code already published at: +http://git.nic.cz/redmine/projects/gornd/repository + +Packages in this repository: + +Install: $ go get github.com/cznic/mathutil +Godocs: http://godoc.org/github.com/cznic/mathutil + +Install: $ go get github.com/cznic/mathutil/mersenne +Godocs: http://godoc.org/github.com/cznic/mathutil/mersenne diff --git a/Godeps/_workspace/src/github.com/cznic/mathutil/all_test.go b/Godeps/_workspace/src/github.com/cznic/mathutil/all_test.go new file mode 100644 index 0000000..38427ad --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/mathutil/all_test.go @@ -0,0 +1,3530 @@ +// Copyright (c) 2014 The mathutil 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 mathutil + +import ( + "fmt" + "math" + "math/big" + "math/rand" + "os" + "path" + "runtime" + "sort" + "strings" + "sync" + "testing" +) + +func caller(s string, va ...interface{}) { + _, fn, fl, _ := runtime.Caller(2) + fmt.Fprintf(os.Stderr, "caller: %s:%d: ", path.Base(fn), fl) + fmt.Fprintf(os.Stderr, s, va...) + fmt.Fprintln(os.Stderr) + _, fn, fl, _ = runtime.Caller(1) + fmt.Fprintf(os.Stderr, "\tcallee: %s:%d: ", path.Base(fn), fl) + fmt.Fprintln(os.Stderr) +} + +func dbg(s string, va ...interface{}) { + if s == "" { + s = strings.Repeat("%v ", len(va)) + } + _, fn, fl, _ := runtime.Caller(1) + fmt.Fprintf(os.Stderr, "dbg %s:%d: ", path.Base(fn), fl) + fmt.Fprintf(os.Stderr, s, va...) + fmt.Fprintln(os.Stderr) +} + +func TODO(...interface{}) string { + _, fn, fl, _ := runtime.Caller(1) + return fmt.Sprintf("TODO: %s:%d:\n", path.Base(fn), fl) +} + +func use(...interface{}) {} + +// ============================================================================ + +func r32() *FC32 { + r, err := NewFC32(math.MinInt32, math.MaxInt32, true) + if err != nil { + panic(err) + } + + return r +} + +var ( + r64lo = big.NewInt(math.MinInt64) + r64hi = big.NewInt(math.MaxInt64) + _3 = big.NewInt(3) + MinIntM1 = MinInt + MaxIntP1 = MaxInt + MaxUintP1 uint = MaxUint +) + +func init() { + MinIntM1-- + MaxIntP1++ + MaxUintP1++ +} + +func r64() *FCBig { + r, err := NewFCBig(r64lo, r64hi, true) + if err != nil { + panic(err) + } + + return r +} + +func benchmark1eN(b *testing.B, r *FC32) { + b.StartTimer() + for i := 0; i < b.N; i++ { + r.Next() + } +} + +func BenchmarkFC1e3(b *testing.B) { + b.StopTimer() + r, _ := NewFC32(0, 1e3, false) + benchmark1eN(b, r) +} + +func BenchmarkFC1e6(b *testing.B) { + b.StopTimer() + r, _ := NewFC32(0, 1e6, false) + benchmark1eN(b, r) +} + +func BenchmarkFC1e9(b *testing.B) { + b.StopTimer() + r, _ := NewFC32(0, 1e9, false) + benchmark1eN(b, r) +} + +func Test0(t *testing.T) { + const N = 10000 + for n := 1; n < N; n++ { + lo, hi := 0, n-1 + period := int64(hi) - int64(lo) + 1 + r, err := NewFC32(lo, hi, false) + if err != nil { + t.Fatal(err) + } + if r.Cycle()-period > period { + t.Fatalf("Cycle exceeds 2 * period") + } + } + for n := 1; n < N; n++ { + lo, hi := 0, n-1 + period := int64(hi) - int64(lo) + 1 + r, err := NewFC32(lo, hi, true) + if err != nil { + t.Fatal(err) + } + if r.Cycle()-2*period > period { + t.Fatalf("Cycle exceeds 3 * period") + } + } +} + +func Test1(t *testing.T) { + const ( + N = 360 + S = 3 + ) + for hq := 0; hq <= 1; hq++ { + for n := 1; n < N; n++ { + for seed := 0; seed < S; seed++ { + lo, hi := -n, 2*n + period := int64(hi - lo + 1) + r, err := NewFC32(lo, hi, hq == 1) + if err != nil { + t.Fatal(err) + } + r.Seed(int64(seed)) + m := map[int]bool{} + v := make([]int, period, period) + p := make([]int64, period, period) + for i := lo; i <= hi; i++ { + x := r.Next() + p[i-lo] = r.Pos() + if x < lo || x > hi { + t.Fatal("t1.0") + } + if m[x] { + t.Fatal("t1.1") + } + m[x] = true + v[i-lo] = x + } + for i := lo; i <= hi; i++ { + x := r.Next() + if x < lo || x > hi { + t.Fatal("t1.2") + } + if !m[x] { + t.Fatal("t1.3") + } + if x != v[i-lo] { + t.Fatal("t1.4") + } + if r.Pos() != p[i-lo] { + t.Fatal("t1.5") + } + m[x] = false + } + for i := lo; i <= hi; i++ { + r.Seek(p[i-lo] + 1) + x := r.Prev() + if x < lo || x > hi { + t.Fatal("t1.6") + } + if x != v[i-lo] { + t.Fatal("t1.7") + } + } + } + } + } +} + +func Test2(t *testing.T) { + const ( + N = 370 + S = 3 + ) + for hq := 0; hq <= 1; hq++ { + for n := 1; n < N; n++ { + for seed := 0; seed < S; seed++ { + lo, hi := -n, 2*n + period := int64(hi - lo + 1) + r, err := NewFC32(lo, hi, hq == 1) + if err != nil { + t.Fatal(err) + } + r.Seed(int64(seed)) + m := map[int]bool{} + v := make([]int, period, period) + p := make([]int64, period, period) + for i := lo; i <= hi; i++ { + x := r.Prev() + p[i-lo] = r.Pos() + if x < lo || x > hi { + t.Fatal("t2.0") + } + if m[x] { + t.Fatal("t2.1") + } + m[x] = true + v[i-lo] = x + } + for i := lo; i <= hi; i++ { + x := r.Prev() + if x < lo || x > hi { + t.Fatal("t2.2") + } + if !m[x] { + t.Fatal("t2.3") + } + if x != v[i-lo] { + t.Fatal("t2.4") + } + if r.Pos() != p[i-lo] { + t.Fatal("t2.5") + } + m[x] = false + } + for i := lo; i <= hi; i++ { + s := p[i-lo] - 1 + if s < 0 { + s = r.Cycle() - 1 + } + r.Seek(s) + x := r.Next() + if x < lo || x > hi { + t.Fatal("t2.6") + } + if x != v[i-lo] { + t.Fatal("t2.7") + } + } + } + } + } +} + +func benchmarkBig1eN(b *testing.B, r *FCBig) { + b.StartTimer() + for i := 0; i < b.N; i++ { + r.Next() + } +} + +func BenchmarkFCBig1e3(b *testing.B) { + b.StopTimer() + hi := big.NewInt(0).SetInt64(1e3) + r, _ := NewFCBig(big0, hi, false) + benchmarkBig1eN(b, r) +} + +func BenchmarkFCBig1e6(b *testing.B) { + b.StopTimer() + hi := big.NewInt(0).SetInt64(1e6) + r, _ := NewFCBig(big0, hi, false) + benchmarkBig1eN(b, r) +} + +func BenchmarkFCBig1e9(b *testing.B) { + b.StopTimer() + hi := big.NewInt(0).SetInt64(1e9) + r, _ := NewFCBig(big0, hi, false) + benchmarkBig1eN(b, r) +} + +func BenchmarkFCBig1e12(b *testing.B) { + b.StopTimer() + hi := big.NewInt(0).SetInt64(1e12) + r, _ := NewFCBig(big0, hi, false) + benchmarkBig1eN(b, r) +} + +func BenchmarkFCBig1e15(b *testing.B) { + b.StopTimer() + hi := big.NewInt(0).SetInt64(1e15) + r, _ := NewFCBig(big0, hi, false) + benchmarkBig1eN(b, r) +} + +func BenchmarkFCBig1e18(b *testing.B) { + b.StopTimer() + hi := big.NewInt(0).SetInt64(1e18) + r, _ := NewFCBig(big0, hi, false) + benchmarkBig1eN(b, r) +} + +var ( + big0 = big.NewInt(0) +) + +func TestBig0(t *testing.T) { + const N = 7400 + lo := big.NewInt(0) + hi := big.NewInt(0) + period := big.NewInt(0) + c := big.NewInt(0) + for n := int64(1); n < N; n++ { + hi.SetInt64(n - 1) + period.Set(hi) + period.Sub(period, lo) + period.Add(period, _1) + r, err := NewFCBig(lo, hi, false) + if err != nil { + t.Fatal(err) + } + if r.cycle.Cmp(period) < 0 { + t.Fatalf("Period exceeds cycle") + } + c.Set(r.Cycle()) + c.Sub(c, period) + if c.Cmp(period) > 0 { + t.Fatalf("Cycle exceeds 2 * period") + } + } + for n := int64(1); n < N; n++ { + hi.SetInt64(n - 1) + period.Set(hi) + period.Sub(period, lo) + period.Add(period, _1) + r, err := NewFCBig(lo, hi, true) + if err != nil { + t.Fatal(err) + } + if r.cycle.Cmp(period) < 0 { + t.Fatalf("Period exceeds cycle") + } + c.Set(r.Cycle()) + c.Sub(c, period) + c.Sub(c, period) + if c.Cmp(period) > 0 { + t.Fatalf("Cycle exceeds 3 * period") + } + } +} + +func TestBig1(t *testing.T) { + const ( + N = 120 + S = 3 + ) + lo := big.NewInt(0) + hi := big.NewInt(0) + seek := big.NewInt(0) + for hq := 0; hq <= 1; hq++ { + for n := int64(1); n < N; n++ { + for seed := 0; seed < S; seed++ { + lo64 := -n + hi64 := 2 * n + lo.SetInt64(lo64) + hi.SetInt64(hi64) + period := hi64 - lo64 + 1 + r, err := NewFCBig(lo, hi, hq == 1) + if err != nil { + t.Fatal(err) + } + r.Seed(int64(seed)) + m := map[int64]bool{} + v := make([]int64, period, period) + p := make([]int64, period, period) + for i := lo64; i <= hi64; i++ { + x := r.Next().Int64() + p[i-lo64] = r.Pos().Int64() + if x < lo64 || x > hi64 { + t.Fatal("tb1.0") + } + if m[x] { + t.Fatal("tb1.1") + } + m[x] = true + v[i-lo64] = x + } + for i := lo64; i <= hi64; i++ { + x := r.Next().Int64() + if x < lo64 || x > hi64 { + t.Fatal("tb1.2") + } + if !m[x] { + t.Fatal("tb1.3") + } + if x != v[i-lo64] { + t.Fatal("tb1.4") + } + if r.Pos().Int64() != p[i-lo64] { + t.Fatal("tb1.5") + } + m[x] = false + } + for i := lo64; i <= hi64; i++ { + r.Seek(seek.SetInt64(p[i-lo64] + 1)) + x := r.Prev().Int64() + if x < lo64 || x > hi64 { + t.Fatal("tb1.6") + } + if x != v[i-lo64] { + t.Fatal("tb1.7") + } + } + } + } + } +} + +func TestBig2(t *testing.T) { + const ( + N = 120 + S = 3 + ) + lo := big.NewInt(0) + hi := big.NewInt(0) + seek := big.NewInt(0) + for hq := 0; hq <= 1; hq++ { + for n := int64(1); n < N; n++ { + for seed := 0; seed < S; seed++ { + lo64, hi64 := -n, 2*n + lo.SetInt64(lo64) + hi.SetInt64(hi64) + period := hi64 - lo64 + 1 + r, err := NewFCBig(lo, hi, hq == 1) + if err != nil { + t.Fatal(err) + } + r.Seed(int64(seed)) + m := map[int64]bool{} + v := make([]int64, period, period) + p := make([]int64, period, period) + for i := lo64; i <= hi64; i++ { + x := r.Prev().Int64() + p[i-lo64] = r.Pos().Int64() + if x < lo64 || x > hi64 { + t.Fatal("tb2.0") + } + if m[x] { + t.Fatal("tb2.1") + } + m[x] = true + v[i-lo64] = x + } + for i := lo64; i <= hi64; i++ { + x := r.Prev().Int64() + if x < lo64 || x > hi64 { + t.Fatal("tb2.2") + } + if !m[x] { + t.Fatal("tb2.3") + } + if x != v[i-lo64] { + t.Fatal("tb2.4") + } + if r.Pos().Int64() != p[i-lo64] { + t.Fatal("tb2.5") + } + m[x] = false + } + for i := lo64; i <= hi64; i++ { + s := p[i-lo64] - 1 + if s < 0 { + s = r.Cycle().Int64() - 1 + } + r.Seek(seek.SetInt64(s)) + x := r.Next().Int64() + if x < lo64 || x > hi64 { + t.Fatal("tb2.6") + } + if x != v[i-lo64] { + t.Fatal("tb2.7") + } + } + } + } + } +} + +func TestPermutations(t *testing.T) { + data := sort.IntSlice{3, 2, 1} + check := [][]int{ + {1, 2, 3}, + {1, 3, 2}, + {2, 1, 3}, + {2, 3, 1}, + {3, 1, 2}, + {3, 2, 1}, + } + i := 0 + for PermutationFirst(data); ; i++ { + if i >= len(check) { + t.Fatalf("too much permutations generated: %d > %d", i+1, len(check)) + } + + for j, v := range check[i] { + got := data[j] + if got != v { + t.Fatalf("permutation %d:\ndata: %v\ncheck: %v\nexpected data[%d] == %d, got %d", i, data, check[i], j, v, got) + } + } + + if !PermutationNext(data) { + if i != len(check)-1 { + t.Fatal("permutations generated", i, "expected", len(check)) + } + break + } + } +} + +func TestIsPrime(t *testing.T) { + const p4M = 283146 // # of primes < 4e6 + n := 0 + for i := uint32(0); i <= 4e6; i++ { + if IsPrime(i) { + n++ + } + } + t.Log(n) + if n != p4M { + t.Fatal(n) + } +} + +func BenchmarkIsPrime(b *testing.B) { + b.StopTimer() + n := make([]uint32, b.N) + rng := rand.New(rand.NewSource(1)) + for i := 0; i < b.N; i++ { + n[i] = rng.Uint32() + } + b.StartTimer() + for _, n := range n { + IsPrime(n) + } +} + +func BenchmarkNextPrime(b *testing.B) { + b.StopTimer() + n := make([]uint32, b.N) + rng := rand.New(rand.NewSource(1)) + for i := 0; i < b.N; i++ { + n[i] = rng.Uint32() + } + b.StartTimer() + for _, n := range n { + NextPrime(n) + } +} + +func BenchmarkIsPrimeUint64(b *testing.B) { + const N = 1 << 16 + b.StopTimer() + a := make([]uint64, N) + r := r64() + for i := range a { + a[i] = uint64(r.Next().Int64()) + } + runtime.GC() + b.StartTimer() + for i := 0; i < b.N; i++ { + IsPrimeUint64(a[i&(N-1)]) + } +} + +func BenchmarkNextPrimeUint64(b *testing.B) { + b.StopTimer() + n := make([]uint64, b.N) + rng := rand.New(rand.NewSource(1)) + for i := 0; i < b.N; i++ { + n[i] = uint64(rng.Int63()) + if i&1 == 0 { + n[i] ^= 1 << 63 + } + } + b.StartTimer() + for _, n := range n { + NextPrimeUint64(n) + } +} + +func TestNextPrime(t *testing.T) { + const p4M = 283146 // # of primes < 4e6 + n := 0 + var p uint32 + for { + p, _ = NextPrime(p) + if p >= 4e6 { + break + } + n++ + } + t.Log(n) + if n != p4M { + t.Fatal(n) + } +} + +func TestNextPrime2(t *testing.T) { + type data struct { + x uint32 + y uint32 + ok bool + } + tests := []data{ + {0, 2, true}, + {1, 2, true}, + {2, 3, true}, + {3, 5, true}, + {math.MaxUint32, 0, false}, + {math.MaxUint32 - 1, 0, false}, + {math.MaxUint32 - 2, 0, false}, + {math.MaxUint32 - 3, 0, false}, + {math.MaxUint32 - 4, 0, false}, + {math.MaxUint32 - 5, math.MaxUint32 - 4, true}, + } + + for _, test := range tests { + y, ok := NextPrime(test.x) + if ok != test.ok || ok && y != test.y { + t.Fatalf("x %d, got y %d ok %t, expected y %d ok %t", test.x, y, ok, test.y, test.ok) + } + } +} + +func TestNextPrimeUint64(t *testing.T) { + const ( + lo = 2000000000000000000 + hi = 2000000000000100000 + k = 2346 // PrimePi(hi)-PrimePi(lo) + ) + n := 0 + p := uint64(lo) - 1 + var ok bool + for { + p0 := p + p, ok = NextPrimeUint64(p) + if !ok { + t.Fatal(p0) + } + + if p > hi { + break + } + + n++ + } + if n != k { + t.Fatal(n, k) + } +} + +func TestISqrt(t *testing.T) { + for n := int64(0); n < 5e6; n++ { + x := int64(ISqrt(uint32(n))) + if x2 := x * x; x2 > n { + t.Fatalf("got ISqrt(%d) == %d, too big", n, x) + } + if x2 := x*x + 2*x + 1; x2 < n { + t.Fatalf("got ISqrt(%d) == %d, too low", n, x) + } + } + for n := int64(math.MaxUint32); n > math.MaxUint32-5e6; n-- { + x := int64(ISqrt(uint32(n))) + if x2 := x * x; x2 > n { + t.Fatalf("got ISqrt(%d) == %d, too big", n, x) + } + if x2 := x*x + 2*x + 1; x2 < n { + t.Fatalf("got ISqrt(%d) == %d, too low", n, x) + } + } + rng := rand.New(rand.NewSource(1)) + for i := 0; i < 5e6; i++ { + n := int64(rng.Uint32()) + x := int64(ISqrt(uint32(n))) + if x2 := x * x; x2 > n { + t.Fatalf("got ISqrt(%d) == %d, too big", n, x) + } + if x2 := x*x + 2*x + 1; x2 < n { + t.Fatalf("got ISqrt(%d) == %d, too low", n, x) + } + } +} + +func TestSqrtUint64(t *testing.T) { + for n := uint64(0); n < 2e6; n++ { + x := SqrtUint64(n) + if x > math.MaxUint32 { + t.Fatalf("got Sqrt(%d) == %d, too big", n, x) + } + if x2 := x * x; x2 > n { + t.Fatalf("got Sqrt(%d) == %d, too big", n, x) + } + if x2 := x*x + 2*x + 1; x2 < n { + t.Fatalf("got Sqrt(%d) == %d, too low", n, x) + } + } + const H = uint64(18446744056529682436) + for n := H; n > H-2e6; n-- { + x := SqrtUint64(n) + if x > math.MaxUint32 { + t.Fatalf("got Sqrt(%d) == %d, too big", n, x) + } + if x2 := x * x; x2 > n { + t.Fatalf("got Sqrt(%d) == %d, too big", n, x) + } + if x2 := x*x + 2*x + 1; x2 < n { + t.Fatalf("got Sqrt(%d) == %d, too low", n, x) + } + } + rng := rand.New(rand.NewSource(1)) + for i := 0; i < 2e6; i++ { + n := uint64(rng.Uint32())<<31 | uint64(rng.Uint32()) + x := SqrtUint64(n) + if x2 := x * x; x2 > n { + t.Fatalf("got Sqrt(%d) == %d, too big", n, x) + } + if x2 := x*x + 2*x + 1; x2 < n { + t.Fatalf("got Sqrt(%d) == %d, too low", n, x) + } + } +} + +func TestSqrtBig(t *testing.T) { + const N = 3e4 + var n, lim, x2 big.Int + lim.SetInt64(N) + for n.Cmp(&lim) != 0 { + x := SqrtBig(&n) + x2.Mul(x, x) + if x.Cmp(&n) > 0 { + t.Fatalf("got sqrt(%s) == %s, too big", &n, x) + } + x2.Add(&x2, x) + x2.Add(&x2, x) + x2.Add(&x2, _1) + if x2.Cmp(&n) < 0 { + t.Fatalf("got sqrt(%s) == %s, too low", &n, x) + } + n.Add(&n, _1) + } + rng := rand.New(rand.NewSource(1)) + var h big.Int + h.SetBit(&h, 1e3, 1) + for i := 0; i < N; i++ { + n.Rand(rng, &h) + x := SqrtBig(&n) + x2.Mul(x, x) + if x.Cmp(&n) > 0 { + t.Fatalf("got sqrt(%s) == %s, too big", &n, x) + } + x2.Add(&x2, x) + x2.Add(&x2, x) + x2.Add(&x2, _1) + if x2.Cmp(&n) < 0 { + t.Fatalf("got sqrt(%s) == %s, too low", &n, x) + } + } +} + +func TestFactorInt(t *testing.T) { + chk := func(n uint64, f []FactorTerm) bool { + if n < 2 { + return len(f) == 0 + } + + for i := 1; i < len(f); i++ { // verify ordering + if t, u := f[i-1], f[i]; t.Prime >= u.Prime { + return false + } + } + + x := uint64(1) + for _, v := range f { + if p := v.Prime; p < 0 || !IsPrime(uint32(v.Prime)) { + return false + } + + for i := uint32(0); i < v.Power; i++ { + x *= uint64(v.Prime) + if x > math.MaxUint32 { + return false + } + } + } + return x == n + } + + for n := uint64(0); n < 3e5; n++ { + f := FactorInt(uint32(n)) + if !chk(n, f) { + t.Fatalf("bad FactorInt(%d): %v", n, f) + } + } + for n := uint64(math.MaxUint32); n > math.MaxUint32-12e4; n-- { + f := FactorInt(uint32(n)) + if !chk(n, f) { + t.Fatalf("bad FactorInt(%d): %v", n, f) + } + } + rng := rand.New(rand.NewSource(1)) + for i := 0; i < 13e4; i++ { + n := rng.Uint32() + f := FactorInt(n) + if !chk(uint64(n), f) { + t.Fatalf("bad FactorInt(%d): %v", n, f) + } + } +} + +func TestFactorIntB(t *testing.T) { + const N = 3e5 // must be < math.MaxInt32 + factors := make([][]FactorTerm, N+1) + // set up the divisors + for prime := uint32(2); prime <= N; prime, _ = NextPrime(prime) { + for n := int(prime); n <= N; n += int(prime) { + factors[n] = append(factors[n], FactorTerm{prime, 0}) + } + } + // set up the powers + for n := 2; n <= N; n++ { + f := factors[n] + m := uint32(n) + for i, v := range f { + for m%v.Prime == 0 { + m /= v.Prime + v.Power++ + } + f[i] = v + } + factors[n] = f + } + // check equal + for n, e := range factors { + g := FactorInt(uint32(n)) + if len(e) != len(g) { + t.Fatal(n, "len", g, "!=", e) + } + + for i, ev := range e { + gv := g[i] + if ev.Prime != gv.Prime { + t.Fatal(n, "prime", gv, ev) + } + + if ev.Power != gv.Power { + t.Fatal(n, "power", gv, ev) + } + } + } +} + +func BenchmarkISqrt(b *testing.B) { + b.StopTimer() + n := make([]uint32, b.N) + rng := rand.New(rand.NewSource(1)) + for i := 0; i < b.N; i++ { + n[i] = rng.Uint32() + } + b.StartTimer() + for _, n := range n { + ISqrt(n) + } +} + +func BenchmarkSqrtUint64(b *testing.B) { + b.StopTimer() + n := make([]uint64, b.N) + rng := rand.New(rand.NewSource(1)) + for i := 0; i < b.N; i++ { + n[i] = uint64(rng.Uint32())<<32 | uint64(rng.Uint32()) + } + b.StartTimer() + for _, n := range n { + SqrtUint64(n) + } +} + +func benchmarkSqrtBig(b *testing.B, bits int) { + b.StopTimer() + n := make([]*big.Int, b.N) + rng := rand.New(rand.NewSource(1)) + var nn, h big.Int + h.SetBit(&h, bits, 1) + for i := 0; i < b.N; i++ { + n[i] = nn.Rand(rng, &h) + } + runtime.GC() + b.StartTimer() + for _, n := range n { + SqrtBig(n) + } +} + +func BenchmarkSqrtBig2e1e1(b *testing.B) { + benchmarkSqrtBig(b, 1e1) +} + +func BenchmarkSqrtBig2e1e2(b *testing.B) { + benchmarkSqrtBig(b, 1e2) +} + +func BenchmarkSqrtBig2e1e3(b *testing.B) { + benchmarkSqrtBig(b, 1e3) +} + +func BenchmarkSqrtBig2e1e4(b *testing.B) { + benchmarkSqrtBig(b, 1e4) +} + +func BenchmarkSqrtBig2e1e5(b *testing.B) { + benchmarkSqrtBig(b, 1e5) +} + +func BenchmarkFactorInt(b *testing.B) { + b.StopTimer() + n := make([]uint32, b.N) + rng := rand.New(rand.NewSource(1)) + for i := 0; i < b.N; i++ { + n[i] = rng.Uint32() + } + b.StartTimer() + for _, n := range n { + FactorInt(n) + } +} + +func TestIsPrimeUint16(t *testing.T) { + for n := 0; n <= math.MaxUint16; n++ { + if IsPrimeUint16(uint16(n)) != IsPrime(uint32(n)) { + t.Fatal(n) + } + } +} + +func BenchmarkIsPrimeUint16(b *testing.B) { + b.StopTimer() + n := make([]uint16, b.N) + rng := rand.New(rand.NewSource(1)) + for i := 0; i < b.N; i++ { + n[i] = uint16(rng.Uint32()) + } + b.StartTimer() + for _, n := range n { + IsPrimeUint16(n) + } +} + +func TestNextPrimeUint16(t *testing.T) { + for n := 0; n <= math.MaxUint16; n++ { + p, ok := NextPrimeUint16(uint16(n)) + p2, ok2 := NextPrime(uint32(n)) + switch { + case ok: + if !ok2 || uint32(p) != p2 { + t.Fatal(n, p, ok) + } + case !ok && ok2: + if p2 < 65536 { + t.Fatal(n, p, ok) + } + } + } +} + +func BenchmarkNextPrimeUint16(b *testing.B) { + b.StopTimer() + n := make([]uint16, b.N) + rng := rand.New(rand.NewSource(1)) + for i := 0; i < b.N; i++ { + n[i] = uint16(rng.Uint32()) + } + b.StartTimer() + for _, n := range n { + NextPrimeUint16(n) + } +} + +/* + +From: http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetKernighan + +Counting bits set, Brian Kernighan's way + +unsigned int v; // count the number of bits set in v +unsigned int c; // c accumulates the total bits set in v +for (c = 0; v; c++) +{ + v &= v - 1; // clear the least significant bit set +} + +Brian Kernighan's method goes through as many iterations as there are set bits. +So if we have a 32-bit word with only the high bit set, then it will only go +once through the loop. + +Published in 1988, the C Programming Language 2nd Ed. (by Brian W. Kernighan +and Dennis M. Ritchie) mentions this in exercise 2-9. On April 19, 2006 Don +Knuth pointed out to me that this method "was first published by Peter Wegner +in CACM 3 (1960), 322. (Also discovered independently by Derrick Lehmer and +published in 1964 in a book edited by Beckenbach.)" +*/ +func bcnt(v uint64) (c int) { + for ; v != 0; c++ { + v &= v - 1 + } + return +} + +func TestPopCount(t *testing.T) { + const N = 4e5 + maxUint64 := big.NewInt(0) + maxUint64.SetBit(maxUint64, 64, 1) + maxUint64.Sub(maxUint64, big.NewInt(1)) + rng := r64() + for i := 0; i < N; i++ { + n := uint64(rng.Next().Int64()) + if g, e := PopCountByte(byte(n)), bcnt(uint64(byte(n))); g != e { + t.Fatal(n, g, e) + } + + if g, e := PopCountUint16(uint16(n)), bcnt(uint64(uint16(n))); g != e { + t.Fatal(n, g, e) + } + + if g, e := PopCountUint32(uint32(n)), bcnt(uint64(uint32(n))); g != e { + t.Fatal(n, g, e) + } + + if g, e := PopCount(int(n)), bcnt(uint64(uint(n))); g != e { + t.Fatal(n, g, e) + } + + if g, e := PopCountUint(uint(n)), bcnt(uint64(uint(n))); g != e { + t.Fatal(n, g, e) + } + + if g, e := PopCountUint64(n), bcnt(n); g != e { + t.Fatal(n, g, e) + } + + if g, e := PopCountUintptr(uintptr(n)), bcnt(uint64(uintptr(n))); g != e { + t.Fatal(n, g, e) + } + } +} + +var gcds = []struct{ a, b, gcd uint64 }{ + {8, 12, 4}, + {12, 18, 6}, + {42, 56, 14}, + {54, 24, 6}, + {252, 105, 21}, + {1989, 867, 51}, + {1071, 462, 21}, + {2 * 3 * 5 * 7 * 11, 5 * 7 * 11 * 13 * 17, 5 * 7 * 11}, + {2 * 3 * 5 * 7 * 7 * 11, 5 * 7 * 7 * 11 * 13 * 17, 5 * 7 * 7 * 11}, + {2 * 3 * 5 * 7 * 7 * 11, 5 * 7 * 7 * 13 * 17, 5 * 7 * 7}, + {2 * 3 * 5 * 7 * 11, 13 * 17 * 19, 1}, +} + +func TestGCD(t *testing.T) { + for i, v := range gcds { + if v.a <= math.MaxUint16 && v.b <= math.MaxUint16 { + if g, e := uint64(GCDUint16(uint16(v.a), uint16(v.b))), v.gcd; g != e { + t.Errorf("%d: got gcd(%d, %d) %d, exp %d", i, v.a, v.b, g, e) + } + if g, e := uint64(GCDUint16(uint16(v.b), uint16(v.a))), v.gcd; g != e { + t.Errorf("%d: got gcd(%d, %d) %d, exp %d", i, v.b, v.a, g, e) + } + } + if v.a <= math.MaxUint32 && v.b <= math.MaxUint32 { + if g, e := uint64(GCDUint32(uint32(v.a), uint32(v.b))), v.gcd; g != e { + t.Errorf("%d: got gcd(%d, %d) %d, exp %d", i, v.a, v.b, g, e) + } + if g, e := uint64(GCDUint32(uint32(v.b), uint32(v.a))), v.gcd; g != e { + t.Errorf("%d: got gcd(%d, %d) %d, exp %d", i, v.b, v.a, g, e) + } + } + if g, e := GCDUint64(v.a, v.b), v.gcd; g != e { + t.Errorf("%d: got gcd(%d, %d) %d, exp %d", i, v.a, v.b, g, e) + } + if g, e := GCDUint64(v.b, v.a), v.gcd; g != e { + t.Errorf("%d: got gcd(%d, %d) %d, exp %d", i, v.b, v.a, g, e) + } + } +} + +func lg2(n uint64) (lg int) { + if n == 0 { + return -1 + } + + for n >>= 1; n != 0; n >>= 1 { + lg++ + } + return +} + +func TestLog2(t *testing.T) { + if g, e := Log2Byte(0), -1; g != e { + t.Error(g, e) + } + if g, e := Log2Uint16(0), -1; g != e { + t.Error(g, e) + } + if g, e := Log2Uint32(0), -1; g != e { + t.Error(g, e) + } + if g, e := Log2Uint64(0), -1; g != e { + t.Error(g, e) + } + const N = 1e6 + rng := r64() + for i := 0; i < N; i++ { + n := uint64(rng.Next().Int64()) + if g, e := Log2Uint64(n), lg2(n); g != e { + t.Fatalf("%b %d %d", n, g, e) + } + if g, e := Log2Uint32(uint32(n)), lg2(n&0xffffffff); g != e { + t.Fatalf("%b %d %d", n, g, e) + } + if g, e := Log2Uint16(uint16(n)), lg2(n&0xffff); g != e { + t.Fatalf("%b %d %d", n, g, e) + } + if g, e := Log2Byte(byte(n)), lg2(n&0xff); g != e { + t.Fatalf("%b %d %d", n, g, e) + } + } +} + +func TestBitLen(t *testing.T) { + if g, e := BitLenByte(0), 0; g != e { + t.Error(g, e) + } + if g, e := BitLenUint16(0), 0; g != e { + t.Error(g, e) + } + if g, e := BitLenUint32(0), 0; g != e { + t.Error(g, e) + } + if g, e := BitLenUint64(0), 0; g != e { + t.Error(g, e) + } + if g, e := BitLenUintptr(0), 0; g != e { + t.Error(g, e) + } + const N = 1e6 + rng := r64() + for i := 0; i < N; i++ { + n := uint64(rng.Next().Int64()) + if g, e := BitLenUintptr(uintptr(n)), lg2(uint64(uintptr(n)))+1; g != e { + t.Fatalf("%b %d %d", n, g, e) + } + if g, e := BitLenUint64(n), lg2(n)+1; g != e { + t.Fatalf("%b %d %d", n, g, e) + } + if g, e := BitLenUint32(uint32(n)), lg2(n&0xffffffff)+1; g != e { + t.Fatalf("%b %d %d", n, g, e) + } + if g, e := BitLen(int(n)), lg2(uint64(uint(n)))+1; g != e { + t.Fatalf("%b %d %d", n, g, e) + } + if g, e := BitLenUint(uint(n)), lg2(uint64(uint(n)))+1; g != e { + t.Fatalf("%b %d %d", n, g, e) + } + if g, e := BitLenUint16(uint16(n)), lg2(n&0xffff)+1; g != e { + t.Fatalf("%b %d %d", n, g, e) + } + if g, e := BitLenByte(byte(n)), lg2(n&0xff)+1; g != e { + t.Fatalf("%b %d %d", n, g, e) + } + } +} + +func BenchmarkGCDByte(b *testing.B) { + const N = 1 << 16 + type t byte + type u struct{ a, b t } + b.StopTimer() + rng := r32() + a := make([]u, N) + for i := range a { + a[i] = u{t(rng.Next()), t(rng.Next())} + } + b.StartTimer() + for i := 0; i < b.N; i++ { + v := a[i&(N-1)] + GCDByte(byte(v.a), byte(v.b)) + } +} + +func BenchmarkGCDUint16(b *testing.B) { + const N = 1 << 16 + type t uint16 + type u struct{ a, b t } + b.StopTimer() + rng := r32() + a := make([]u, N) + for i := range a { + a[i] = u{t(rng.Next()), t(rng.Next())} + } + b.StartTimer() + for i := 0; i < b.N; i++ { + v := a[i&(N-1)] + GCDUint16(uint16(v.a), uint16(v.b)) + } +} + +func BenchmarkGCDUint32(b *testing.B) { + const N = 1 << 16 + type t uint32 + type u struct{ a, b t } + b.StopTimer() + rng := r32() + a := make([]u, N) + for i := range a { + a[i] = u{t(rng.Next()), t(rng.Next())} + } + b.StartTimer() + for i := 0; i < b.N; i++ { + v := a[i&(N-1)] + GCDUint32(uint32(v.a), uint32(v.b)) + } +} + +func BenchmarkGCDUint64(b *testing.B) { + const N = 1 << 16 + type t uint64 + type u struct{ a, b t } + b.StopTimer() + rng := r64() + a := make([]u, N) + for i := range a { + a[i] = u{t(rng.Next().Int64()), t(rng.Next().Int64())} + } + b.StartTimer() + for i := 0; i < b.N; i++ { + v := a[i&(N-1)] + GCDUint64(uint64(v.a), uint64(v.b)) + } +} + +func BenchmarkLog2Byte(b *testing.B) { + const N = 1 << 16 + type t byte + b.StopTimer() + rng := r32() + a := make([]t, N) + for i := range a { + a[i] = t(rng.Next()) + } + b.StartTimer() + for i := 0; i < b.N; i++ { + Log2Byte(byte(a[i&(N-1)])) + } +} + +func BenchmarkLog2Uint16(b *testing.B) { + const N = 1 << 16 + type t uint16 + b.StopTimer() + rng := r32() + a := make([]t, N) + for i := range a { + a[i] = t(rng.Next()) + } + b.StartTimer() + for i := 0; i < b.N; i++ { + Log2Uint16(uint16(a[i&(N-1)])) + } +} + +func BenchmarkLog2Uint32(b *testing.B) { + const N = 1 << 16 + type t uint32 + b.StopTimer() + rng := r32() + a := make([]t, N) + for i := range a { + a[i] = t(rng.Next()) + } + b.StartTimer() + for i := 0; i < b.N; i++ { + Log2Uint32(uint32(a[i&(N-1)])) + } +} + +func BenchmarkLog2Uint64(b *testing.B) { + const N = 1 << 16 + type t uint64 + b.StopTimer() + rng := r64() + a := make([]t, N) + for i := range a { + a[i] = t(rng.Next().Int64()) + } + b.StartTimer() + for i := 0; i < b.N; i++ { + Log2Uint64(uint64(a[i&(N-1)])) + } +} +func BenchmarkBitLenByte(b *testing.B) { + const N = 1 << 16 + type t byte + b.StopTimer() + rng := r32() + a := make([]t, N) + for i := range a { + a[i] = t(rng.Next()) + } + b.StartTimer() + for i := 0; i < b.N; i++ { + BitLenByte(byte(a[i&(N-1)])) + } +} + +func BenchmarkBitLenUint16(b *testing.B) { + const N = 1 << 16 + type t uint16 + b.StopTimer() + rng := r32() + a := make([]t, N) + for i := range a { + a[i] = t(rng.Next()) + } + b.StartTimer() + for i := 0; i < b.N; i++ { + BitLenUint16(uint16(a[i&(N-1)])) + } +} + +func BenchmarkBitLenUint32(b *testing.B) { + const N = 1 << 16 + type t uint32 + b.StopTimer() + rng := r32() + a := make([]t, N) + for i := range a { + a[i] = t(rng.Next()) + } + b.StartTimer() + for i := 0; i < b.N; i++ { + BitLenUint32(uint32(a[i&(N-1)])) + } +} + +func BenchmarkBitLen(b *testing.B) { + const N = 1 << 16 + type t int + b.StopTimer() + rng := r64() + a := make([]t, N) + for i := range a { + a[i] = t(rng.Next().Int64()) + } + b.StartTimer() + for i := 0; i < b.N; i++ { + BitLen(int(a[i&(N-1)])) + } +} + +func BenchmarkBitLenUint(b *testing.B) { + const N = 1 << 16 + type t uint + b.StopTimer() + rng := r64() + a := make([]t, N) + for i := range a { + a[i] = t(rng.Next().Int64()) + } + b.StartTimer() + for i := 0; i < b.N; i++ { + BitLenUint(uint(a[i&(N-1)])) + } +} + +func BenchmarkBitLenUintptr(b *testing.B) { + const N = 1 << 16 + type t uintptr + b.StopTimer() + rng := r64() + a := make([]t, N) + for i := range a { + a[i] = t(rng.Next().Int64()) + } + b.StartTimer() + for i := 0; i < b.N; i++ { + BitLenUintptr(uintptr(a[i&(N-1)])) + } +} + +func BenchmarkBitLenUint64(b *testing.B) { + const N = 1 << 16 + type t uint64 + b.StopTimer() + rng := r64() + a := make([]t, N) + for i := range a { + a[i] = t(rng.Next().Int64()) + } + b.StartTimer() + for i := 0; i < b.N; i++ { + BitLenUint64(uint64(a[i&(N-1)])) + } +} + +func BenchmarkPopCountByte(b *testing.B) { + const N = 1 << 16 + type t byte + b.StopTimer() + rng := r32() + a := make([]t, N) + for i := range a { + a[i] = t(rng.Next()) + } + b.StartTimer() + for i := 0; i < b.N; i++ { + PopCountByte(byte(a[i&(N-1)])) + } +} + +func BenchmarkPopCountUint16(b *testing.B) { + const N = 1 << 16 + type t uint16 + b.StopTimer() + rng := r32() + a := make([]t, N) + for i := range a { + a[i] = t(rng.Next()) + } + b.StartTimer() + for i := 0; i < b.N; i++ { + PopCountUint16(uint16(a[i&(N-1)])) + } +} + +func BenchmarkPopCountUint32(b *testing.B) { + const N = 1 << 16 + type t uint32 + b.StopTimer() + rng := r32() + a := make([]t, N) + for i := range a { + a[i] = t(rng.Next()) + } + b.StartTimer() + for i := 0; i < b.N; i++ { + PopCountUint32(uint32(a[i&(N-1)])) + } +} + +func BenchmarkPopCount(b *testing.B) { + const N = 1 << 16 + type t int + b.StopTimer() + rng := r64() + a := make([]t, N) + for i := range a { + a[i] = t(rng.Next().Int64()) + } + b.StartTimer() + for i := 0; i < b.N; i++ { + PopCount(int(a[i&(N-1)])) + } +} + +func BenchmarkPopCountUint(b *testing.B) { + const N = 1 << 16 + type t uint + b.StopTimer() + rng := r64() + a := make([]t, N) + for i := range a { + a[i] = t(rng.Next().Int64()) + } + b.StartTimer() + for i := 0; i < b.N; i++ { + PopCountUint(uint(a[i&(N-1)])) + } +} + +func BenchmarkPopCountUintptr(b *testing.B) { + const N = 1 << 16 + type t uintptr + b.StopTimer() + rng := r64() + a := make([]t, N) + for i := range a { + a[i] = t(rng.Next().Int64()) + } + b.StartTimer() + for i := 0; i < b.N; i++ { + PopCountUintptr(uintptr(a[i&(N-1)])) + } +} + +func BenchmarkPopCountUint64(b *testing.B) { + const N = 1 << 16 + type t uint64 + b.StopTimer() + rng := r64() + a := make([]t, N) + for i := range a { + a[i] = t(rng.Next().Int64()) + } + b.StartTimer() + for i := 0; i < b.N; i++ { + PopCountUint64(uint64(a[i&(N-1)])) + } +} + +func TestUintptrBits(t *testing.T) { + switch g := UintptrBits(); g { + case 32, 64: + // ok + t.Log(g) + default: + t.Fatalf("got %d, expected 32 or 64", g) + } +} + +func BenchmarkUintptrBits(b *testing.B) { + for i := 0; i < b.N; i++ { + UintptrBits() + } +} + +func TestModPowByte(t *testing.T) { + data := []struct{ b, e, m, r byte }{ + {0, 1, 1, 0}, + {0, 2, 1, 0}, + {0, 3, 1, 0}, + + {1, 0, 1, 0}, + {1, 1, 1, 0}, + {1, 2, 1, 0}, + {1, 3, 1, 0}, + + {2, 0, 1, 0}, + {2, 1, 1, 0}, + {2, 2, 1, 0}, + {2, 3, 1, 0}, + + {2, 11, 23, 1}, // 23|M11 + {2, 11, 89, 1}, // 89|M11 + {2, 23, 47, 1}, // 47|M23 + {5, 3, 13, 8}, + } + + for _, v := range data { + if g, e := ModPowByte(v.b, v.e, v.m), v.r; g != e { + t.Errorf("b %d e %d m %d: got %d, exp %d", v.b, v.e, v.m, g, e) + } + } +} + +func TestModPowUint16(t *testing.T) { + data := []struct{ b, e, m, r uint16 }{ + {0, 1, 1, 0}, + {0, 2, 1, 0}, + {0, 3, 1, 0}, + + {1, 0, 1, 0}, + {1, 1, 1, 0}, + {1, 2, 1, 0}, + {1, 3, 1, 0}, + + {2, 0, 1, 0}, + {2, 1, 1, 0}, + {2, 2, 1, 0}, + {2, 3, 1, 0}, + + {2, 11, 23, 1}, // 23|M11 + {2, 11, 89, 1}, // 89|M11 + {2, 23, 47, 1}, // 47|M23 + {2, 929, 13007, 1}, // 13007|M929 + {4, 13, 497, 445}, + {5, 3, 13, 8}, + } + + for _, v := range data { + if g, e := ModPowUint16(v.b, v.e, v.m), v.r; g != e { + t.Errorf("b %d e %d m %d: got %d, exp %d", v.b, v.e, v.m, g, e) + } + } +} + +func TestModPowUint32(t *testing.T) { + data := []struct{ b, e, m, r uint32 }{ + {0, 1, 1, 0}, + {0, 2, 1, 0}, + {0, 3, 1, 0}, + + {1, 0, 1, 0}, + {1, 1, 1, 0}, + {1, 2, 1, 0}, + {1, 3, 1, 0}, + + {2, 0, 1, 0}, + {2, 1, 1, 0}, + {2, 2, 1, 0}, + {2, 3, 1, 0}, + + {2, 23, 47, 1}, // 47|M23 + {2, 67, 193707721, 1}, // 193707721|M67 + {2, 929, 13007, 1}, // 13007|M929 + {4, 13, 497, 445}, + {5, 3, 13, 8}, + {2, 500471, 264248689, 1}, + {2, 1000249, 112027889, 1}, + {2, 2000633, 252079759, 1}, + {2, 3000743, 222054983, 1}, + {2, 4000741, 1920355681, 1}, + {2, 5000551, 330036367, 1}, + {2, 6000479, 1020081431, 1}, + {2, 7000619, 840074281, 1}, + {2, 8000401, 624031279, 1}, + {2, 9000743, 378031207, 1}, + {2, 10000961, 380036519, 1}, + {2, 20000723, 40001447, 1}, + } + + for _, v := range data { + if g, e := ModPowUint32(v.b, v.e, v.m), v.r; g != e { + t.Errorf("b %d e %d m %d: got %d, exp %d", v.b, v.e, v.m, g, e) + } + } +} + +func TestModPowUint64(t *testing.T) { + data := []struct{ b, e, m, r uint64 }{ + {0, 1, 1, 0}, + {0, 2, 1, 0}, + {0, 3, 1, 0}, + + {1, 0, 1, 0}, + {1, 1, 1, 0}, + {1, 2, 1, 0}, + {1, 3, 1, 0}, + + {2, 0, 1, 0}, + {2, 1, 1, 0}, + {2, 2, 1, 0}, + {2, 3, 1, 0}, + + {2, 23, 47, 1}, // 47|M23 + {2, 67, 193707721, 1}, // 193707721|M67 + {2, 929, 13007, 1}, // 13007|M929 + {4, 13, 497, 445}, + {5, 3, 13, 8}, + {2, 500471, 264248689, 1}, // m|Me ... + {2, 1000249, 112027889, 1}, + {2, 2000633, 252079759, 1}, + {2, 3000743, 222054983, 1}, + {2, 4000741, 1920355681, 1}, + {2, 5000551, 330036367, 1}, + {2, 6000479, 1020081431, 1}, + {2, 7000619, 840074281, 1}, + {2, 8000401, 624031279, 1}, + {2, 9000743, 378031207, 1}, + {2, 10000961, 380036519, 1}, + {2, 20000723, 40001447, 1}, + {2, 1000099, 1872347344039, 1}, + + {9223372036854775919, 9223372036854776030, 9223372036854776141, 7865333882915297658}, + } + + for _, v := range data { + if g, e := ModPowUint64(v.b, v.e, v.m), v.r; g != e { + t.Errorf("b %d e %d m %d: got %d, exp %d", v.b, v.e, v.m, g, e) + } + } +} + +func TestModPowBigInt(t *testing.T) { + data := []struct { + b, e int64 + m interface{} + r int64 + }{ + {0, 1, 1, 0}, + {0, 2, 1, 0}, + {0, 3, 1, 0}, + + {1, 0, 1, 0}, + {1, 1, 1, 0}, + {1, 2, 1, 0}, + {1, 3, 1, 0}, + + {2, 0, 1, 0}, + {2, 1, 1, 0}, + {2, 2, 1, 0}, + {2, 3, 1, 0}, + + {2, 23, 47, 1}, // 47|M23 + {2, 67, 193707721, 1}, // 193707721|M67 + {2, 929, 13007, 1}, // 13007|M929 + {4, 13, 497, 445}, + {5, 3, 13, 8}, + {2, 500471, 264248689, 1}, // m|Me ... + {2, 1000249, 112027889, 1}, + {2, 2000633, 252079759, 1}, + {2, 3000743, 222054983, 1}, + {2, 4000741, 1920355681, 1}, + {2, 5000551, 330036367, 1}, + {2, 6000479, 1020081431, 1}, + {2, 7000619, 840074281, 1}, + {2, 8000401, 624031279, 1}, + {2, 9000743, 378031207, 1}, + {2, 10000961, 380036519, 1}, + {2, 20000723, 40001447, 1}, + {2, 100279, "11502865265922183403581252152383", 1}, + + {2, 7293457, "533975545077050000610542659519277030089249998649", 1}, + } + + for _, v := range data { + var m big.Int + switch x := v.m.(type) { + case int: + m.SetInt64(int64(x)) + case string: + m.SetString(x, 10) + } + b, e, r := big.NewInt(v.b), big.NewInt(v.e), big.NewInt(v.r) + if g, e := ModPowBigInt(b, e, &m), r; g.Cmp(e) != 0 { + t.Errorf("b %s e %s m %v: got %s, exp %s", b, e, m, g, e) + } + } + + s := func(n string) *big.Int { + i, ok := big.NewInt(0).SetString(n, 10) + if !ok { + t.Fatal(ok) + } + + return i + } + + if g, e := ModPowBigInt( + s("36893488147419103343"), s("36893488147419103454"), s("36893488147419103565")), s("34853007610367449339"); g.Cmp(e) != 0 { + t.Fatal(g, e) + } +} + +func BenchmarkModPowByte(b *testing.B) { + const N = 1 << 16 + b.StopTimer() + type t struct{ b, e, m byte } + a := make([]t, N) + r := r32() + for i := range a { + a[i] = t{ + byte(r.Next() | 2), + byte(r.Next() | 2), + byte(r.Next() | 2), + } + } + runtime.GC() + b.StartTimer() + for i := 0; i < b.N; i++ { + v := a[i&(N-1)] + ModPowByte(v.b, v.e, v.m) + } +} + +func BenchmarkModPowUint16(b *testing.B) { + const N = 1 << 16 + b.StopTimer() + type t struct{ b, e, m uint16 } + a := make([]t, N) + r := r32() + for i := range a { + a[i] = t{ + uint16(r.Next() | 2), + uint16(r.Next() | 2), + uint16(r.Next() | 2), + } + } + runtime.GC() + b.StartTimer() + for i := 0; i < b.N; i++ { + v := a[i&(N-1)] + ModPowUint16(v.b, v.e, v.m) + } +} + +func BenchmarkModPowUint32(b *testing.B) { + const N = 1 << 16 + b.StopTimer() + type t struct{ b, e, m uint32 } + a := make([]t, N) + r := r32() + for i := range a { + a[i] = t{ + uint32(r.Next() | 2), + uint32(r.Next() | 2), + uint32(r.Next() | 2), + } + } + runtime.GC() + b.StartTimer() + for i := 0; i < b.N; i++ { + v := a[i&(N-1)] + ModPowUint32(v.b, v.e, v.m) + } +} + +func BenchmarkModPowUint64(b *testing.B) { + const N = 1 << 16 + b.StopTimer() + type t struct{ b, e, m uint64 } + a := make([]t, N) + r := r64() + for i := range a { + a[i] = t{ + uint64(r.Next().Int64() | 2), + uint64(r.Next().Int64() | 2), + uint64(r.Next().Int64() | 2), + } + } + runtime.GC() + b.StartTimer() + for i := 0; i < b.N; i++ { + v := a[i&(N-1)] + ModPowUint64(v.b, v.e, v.m) + } +} + +func BenchmarkModPowBigInt(b *testing.B) { + const N = 1 << 16 + b.StopTimer() + type t struct{ b, e, m *big.Int } + a := make([]t, N) + mx := big.NewInt(math.MaxInt64) + mx.Mul(mx, mx) + r, err := NewFCBig(big.NewInt(2), mx, true) + if err != nil { + b.Fatal(err) + } + for i := range a { + a[i] = t{ + r.Next(), + r.Next(), + r.Next(), + } + } + runtime.GC() + b.StartTimer() + for i := 0; i < b.N; i++ { + v := a[i&(N-1)] + ModPowBigInt(v.b, v.e, v.m) + } +} + +func TestAdd128(t *testing.T) { + const N = 1e5 + r := r64() + var mm big.Int + for i := 0; i < N; i++ { + a, b := uint64(r.Next().Int64()), uint64(r.Next().Int64()) + aa, bb := big.NewInt(0).SetUint64(a), big.NewInt(0).SetUint64(b) + mhi, mlo := AddUint128_64(a, b) + m := big.NewInt(0).SetUint64(mhi) + m.Lsh(m, 64) + m.Add(m, big.NewInt(0).SetUint64(mlo)) + mm.Add(aa, bb) + if m.Cmp(&mm) != 0 { + t.Fatalf("%d\na %40d\nb %40d\ng %40s %032x\ne %40s %032x", i, a, b, m, m, &mm, &mm) + } + } +} + +func TestMul128(t *testing.T) { + const N = 1e5 + r := r64() + var mm big.Int + f := func(a, b uint64) { + aa, bb := big.NewInt(0).SetUint64(a), big.NewInt(0).SetUint64(b) + mhi, mlo := MulUint128_64(a, b) + m := big.NewInt(0).SetUint64(mhi) + m.Lsh(m, 64) + m.Add(m, big.NewInt(0).SetUint64(mlo)) + mm.Mul(aa, bb) + if m.Cmp(&mm) != 0 { + t.Fatalf("\na %40d\nb %40d\ng %40s %032x\ne %40s %032x", a, b, m, m, &mm, &mm) + } + } + for i := 0; i < N; i++ { + f(uint64(r.Next().Int64()), uint64(r.Next().Int64())) + } + for x := 0; x <= 1<<9; x++ { + for y := 0; y <= 1<<9; y++ { + f(math.MaxUint64-uint64(x), math.MaxUint64-uint64(y)) + } + } +} + +func BenchmarkMul128(b *testing.B) { + const N = 1 << 16 + b.StopTimer() + type t struct{ a, b uint64 } + a := make([]t, N) + r := r64() + for i := range a { + a[i] = t{ + uint64(r.Next().Int64()), + uint64(r.Next().Int64()), + } + } + runtime.GC() + b.StartTimer() + for i := 0; i < b.N; i++ { + v := a[i&(N-1)] + MulUint128_64(v.a, v.b) + } +} + +func BenchmarkMul128Big(b *testing.B) { + const N = 1 << 16 + b.StopTimer() + type t struct{ a, b *big.Int } + a := make([]t, N) + r := r64() + for i := range a { + a[i] = t{ + big.NewInt(r.Next().Int64()), + big.NewInt(r.Next().Int64()), + } + } + var x big.Int + runtime.GC() + b.StartTimer() + for i := 0; i < b.N; i++ { + v := a[i&(N-1)] + x.Mul(v.a, v.b) + } +} + +func TestIsPrimeUint64(t *testing.T) { + f := func(lo, hi uint64, exp int) { + got := 0 + for n := lo; n <= hi; { + if IsPrimeUint64(n) { + got++ + } + n0 := n + n++ + if n < n0 { + break + } + } + if got != exp { + t.Fatal(lo, hi, got, exp) + } + } + + // lo, hi, PrimePi(hi)-PrimePi(lo) + f(0, 1e4, 1229) + f(1e5, 1e5+1e4, 861) + f(1e6, 1e6+1e4, 753) + f(1e7, 1e7+1e4, 614) + f(1e8, 1e8+1e4, 551) + f(1e9, 1e9+1e4, 487) + f(1e10, 1e10+1e4, 406) + f(1e11, 1e11+1e4, 394) + f(1e12, 1e12+1e4, 335) + f(1e13, 1e13+1e4, 354) + f(1e14, 1e14+1e4, 304) + f(1e15, 1e15+1e4, 263) + f(1e16, 1e16+1e4, 270) + f(1e17, 1e17+1e4, 265) + f(1e18, 1e18+1e4, 241) + f(1e19, 1e19+1e4, 255) + f(1<<64-1e4, 1<<64-1, 218) +} + +func TestProbablyPrimeUint32(t *testing.T) { + f := func(n, firstFail uint32, primes []uint32) { + for ; n <= firstFail; n += 2 { + prp := true + for _, a := range primes { + if !ProbablyPrimeUint32(n, a) { + prp = false + break + } + } + if prp != IsPrime(n) && n != firstFail { + t.Fatal(n) + } + } + } + if !ProbablyPrimeUint32(5, 2) { + t.Fatal(false) + } + if !ProbablyPrimeUint32(7, 2) { + t.Fatal(false) + } + if ProbablyPrimeUint32(9, 2) { + t.Fatal(true) + } + if !ProbablyPrimeUint32(11, 2) { + t.Fatal(false) + } + // http://oeis.org/A014233 + f(5, 2047, []uint32{2}) + f(2047, 1373653, []uint32{2, 3}) + f(1373653, 25326001, []uint32{2, 3, 5}) +} + +func BenchmarkProbablyPrimeUint32(b *testing.B) { + const N = 1 << 16 + b.StopTimer() + type t struct{ n, a uint32 } + data := make([]t, N) + r := r32() + for i := range data { + n := uint32(r.Next()) | 1 + if n <= 3 { + n += 5 + } + a := uint32(r.Next()) + if a <= 1 { + a += 2 + } + data[i] = t{n, a} + } + runtime.GC() + b.StartTimer() + for i := 0; i < b.N; i++ { + v := data[i&(N-1)] + ProbablyPrimeUint32(v.n, v.a) + } +} + +func TestProbablyPrimeUint64_32(t *testing.T) { + f := func(n, firstFail uint64, primes []uint32) { + for ; n <= firstFail; n += 2 { + prp := true + for _, a := range primes { + if !ProbablyPrimeUint64_32(n, a) { + prp = false + break + } + } + if prp != IsPrimeUint64(n) && n != firstFail { + t.Fatal(n) + } + } + } + if !ProbablyPrimeUint64_32(5, 2) { + t.Fatal(false) + } + if !ProbablyPrimeUint64_32(7, 2) { + t.Fatal(false) + } + if ProbablyPrimeUint64_32(9, 2) { + t.Fatal(true) + } + if !ProbablyPrimeUint64_32(11, 2) { + t.Fatal(false) + } + // http://oeis.org/A014233 + f(5, 2047, []uint32{2}) + f(2047, 1373653, []uint32{2, 3}) +} + +func BenchmarkProbablyPrimeUint64_32(b *testing.B) { + const N = 1 << 16 + b.StopTimer() + type t struct { + n uint64 + a uint32 + } + data := make([]t, N) + r := r32() + r2 := r64() + for i := range data { + var n uint64 + for n <= 3 { + n = uint64(r2.Next().Int64()) | 1 + } + var a uint32 + for a <= 1 { + a = uint32(r.Next()) + } + data[i] = t{n, a} + } + runtime.GC() + b.StartTimer() + for i := 0; i < b.N; i++ { + v := data[i&(N-1)] + ProbablyPrimeUint64_32(v.n, v.a) + } +} + +func TestProbablyPrimeBigInt_32(t *testing.T) { + f := func(n0, firstFail0 uint64, primes []uint32) { + n, firstFail := big.NewInt(0).SetUint64(n0), big.NewInt(0).SetUint64(firstFail0) + for ; n.Cmp(firstFail) <= 0; n.Add(n, _2) { + prp := true + for _, a := range primes { + if !ProbablyPrimeBigInt_32(n, a) { + prp = false + break + } + } + if prp != IsPrimeUint64(n0) && n0 != firstFail0 { + t.Fatal(n) + } + n0 += 2 + } + } + if !ProbablyPrimeBigInt_32(big.NewInt(5), 2) { + t.Fatal(false) + } + if !ProbablyPrimeBigInt_32(big.NewInt(7), 2) { + t.Fatal(false) + } + if ProbablyPrimeBigInt_32(big.NewInt(9), 2) { + t.Fatal(true) + } + if !ProbablyPrimeBigInt_32(big.NewInt(11), 2) { + t.Fatal(false) + } + // http://oeis.org/A014233 + f(5, 2047, []uint32{2}) + f(2047, 1373653, []uint32{2, 3}) +} + +func BenchmarkProbablyPrimeBigInt_32(b *testing.B) { + const N = 1 << 16 + b.StopTimer() + type t struct { + n *big.Int + a uint32 + } + data := make([]t, N) + r := r32() + r2 := r64() + for i := range data { + var n uint64 + for n <= 3 { + n = uint64(r2.Next().Int64()) | 1 + } + var a uint32 + for a <= 1 { + a = uint32(r.Next()) + } + data[i] = t{big.NewInt(0).SetUint64(n), a} + } + runtime.GC() + b.StartTimer() + for i := 0; i < b.N; i++ { + v := data[i&(N-1)] + ProbablyPrimeBigInt_32(v.n, v.a) + } +} + +func TestProbablyPrimeBigInt(t *testing.T) { + f := func(n0, firstFail0 uint64, primes []uint32) { + n, firstFail := big.NewInt(0).SetUint64(n0), big.NewInt(0).SetUint64(firstFail0) + for ; n.Cmp(firstFail) <= 0; n.Add(n, _2) { + prp := true + var a big.Int + for _, a0 := range primes { + a.SetInt64(int64(a0)) + if !ProbablyPrimeBigInt(n, &a) { + prp = false + break + } + } + if prp != IsPrimeUint64(n0) && n0 != firstFail0 { + t.Fatal(n) + } + n0 += 2 + } + } + if !ProbablyPrimeBigInt(big.NewInt(5), _2) { + t.Fatal(false) + } + if !ProbablyPrimeBigInt(big.NewInt(7), _2) { + t.Fatal(false) + } + if ProbablyPrimeBigInt(big.NewInt(9), _2) { + t.Fatal(true) + } + if !ProbablyPrimeBigInt(big.NewInt(11), _2) { + t.Fatal(false) + } + // http://oeis.org/A014233 + f(5, 2047, []uint32{2}) + f(2047, 1373653, []uint32{2, 3}) +} + +var once2059 sync.Once + +func BenchmarkProbablyPrimeBigInt64(b *testing.B) { + const N = 1 << 16 + b.StopTimer() + once2059.Do(func() { b.Log("64 bit n, 64 bit a\n") }) + type t struct { + n, a *big.Int + } + data := make([]t, N) + r := r64() + for i := range data { + var n uint64 + for n <= 3 { + n = uint64(r.Next().Int64()) | 1 + } + var a uint64 + for a <= 1 { + a = uint64(r.Next().Int64()) + } + data[i] = t{big.NewInt(0).SetUint64(n), big.NewInt(0).SetUint64(uint64(a))} + } + runtime.GC() + b.StartTimer() + for i := 0; i < b.N; i++ { + v := data[i&(N-1)] + ProbablyPrimeBigInt(v.n, v.a) + } +} + +var once2090 sync.Once + +func BenchmarkProbablyPrimeBigInt128(b *testing.B) { + const N = 1 << 16 + b.StopTimer() + once2090.Do(func() { b.Log("128 bit n, 128 bit a\n") }) + type t struct { + n, a *big.Int + } + data := make([]t, N) + r := r64() + for i := range data { + n := big.NewInt(0).SetUint64(uint64(r.Next().Int64())) + n.Lsh(n, 64) + n.Add(n, big.NewInt(0).SetUint64(uint64(r.Next().Int64())|1)) + a := big.NewInt(0).SetUint64(uint64(r.Next().Int64())) + a.Lsh(a, 64) + a.Add(a, big.NewInt(0).SetUint64(uint64(r.Next().Int64()))) + data[i] = t{n, a} + } + runtime.GC() + b.StartTimer() + for i := 0; i < b.N; i++ { + v := data[i&(N-1)] + ProbablyPrimeBigInt(v.n, v.a) + } +} + +func TestQCmpUint32(t *testing.T) { + const N = 6e4 + r := r32() + var x, y big.Rat + for i := 0; i < N; i++ { + a, b, c, d := uint32(r.Next()), uint32(r.Next()), uint32(r.Next()), uint32(r.Next()) + x.SetFrac64(int64(a), int64(b)) + y.SetFrac64(int64(c), int64(d)) + if g, e := QCmpUint32(a, b, c, d), x.Cmp(&y); g != e { + t.Fatal(a, b, c, d, g, e) + } + } +} + +func TestQScaleUint32(t *testing.T) { + const N = 4e4 + r := r32() + var x, y big.Rat + var a uint64 + var b, c, d uint32 + for i := 0; i < N; i++ { + for { + b, c, d = uint32(r.Next()), uint32(r.Next()), uint32(r.Next()) + a = QScaleUint32(b, c, d) + if a <= math.MaxInt64 { + break + } + } + x.SetFrac64(int64(a), int64(b)) + y.SetFrac64(int64(c), int64(d)) + if g := x.Cmp(&y); g < 0 { + t.Fatal(a, b, c, d, g, "expexted 1 or 0") + } + + if a != 0 { + x.SetFrac64(int64(a-1), int64(b)) + if g := x.Cmp(&y); g > 0 { + t.Fatal(a, b, c, d, g, "expected -1 or 0") + } + } + } +} + +var smalls = []uint32{2, 3, 5, 7, 11, 13, 17, 19, 23, 29} + +func isPrimorialProduct(t FactorTerms, maxp uint32) bool { + if len(t) == 0 { + return false + } + + pmax := uint32(32) + for i, v := range t { + if v.Prime != smalls[i] || v.Power > pmax || v.Power > maxp { + return false + } + pmax = v.Power + } + return true +} + +func TestPrimorialProductsUint32(t *testing.T) { + r := PrimorialProductsUint32(2*3*5*7*11*13*17*19+1, math.MaxUint32, 1) + if len(r) != 1 { + t.Fatal(len(r)) + } + + if r[0] != 2*3*5*7*11*13*17*19*23 { + t.Fatal(r[0]) + } + + r = PrimorialProductsUint32(0, math.MaxUint32, math.MaxUint32) + if g, e := len(r), 1679; g != e { + t.Fatal(g, e) + } + + m := map[uint32]struct{}{} + for _, v := range r { + if _, ok := m[v]; ok { + t.Fatal(v) + } + + m[v] = struct{}{} + } + + for lo := uint32(0); lo < 5e4; lo += 1e3 { + hi := 1e2 * lo + for max := uint32(0); max <= 32; max++ { + m := map[uint32]struct{}{} + for i, v := range PrimorialProductsUint32(lo, hi, max) { + f := FactorInt(v) + if v < lo || v > hi { + t.Fatal(lo, hi, max, v) + } + + if _, ok := m[v]; ok { + t.Fatal(i, lo, hi, max, v, f) + } + + m[v] = struct{}{} + if !isPrimorialProduct(f, max) { + t.Fatal(i, v) + } + + for _, v := range f { + if v.Power > max { + t.Fatal(i, v, f) + } + } + } + } + } +} + +func BenchmarkPrimorialProductsUint32(b *testing.B) { + for i := 0; i < b.N; i++ { + PrimorialProductsUint32(0, math.MaxUint32, math.MaxUint32) + } +} + +func powerizeUint32BigInt(b uint32, n *big.Int) (e uint32, p *big.Int) { + p = big.NewInt(1) + bb := big.NewInt(int64(b)) + for p.Cmp(n) < 0 { + p.Mul(p, bb) + e++ + } + return +} + +func TestPowerizeUint32BigInt(t *testing.T) { + var data = []struct{ b, n, e, p int }{ + {0, 10, 0, -1}, + {1, 10, 0, -1}, + {2, -1, 0, -1}, + {2, 0, 0, 1}, + {2, 1, 0, 1}, + {2, 2, 1, 2}, + {2, 3, 2, 4}, + {3, 0, 0, 1}, + {3, 1, 0, 1}, + {3, 2, 1, 3}, + {3, 3, 1, 3}, + {3, 4, 2, 9}, + {3, 8, 2, 9}, + {3, 9, 2, 9}, + {3, 10, 3, 27}, + {3, 80, 4, 81}, + } + + var n big.Int + for _, v := range data { + b := v.b + n.SetInt64(int64(v.n)) + e, p := PowerizeUint32BigInt(uint32(b), &n) + if e != uint32(v.e) { + t.Fatal(b, &n, e, p, v.e, v.p) + } + + if v.p < 0 { + if p != nil { + t.Fatal(b, &n, e, p, v.e, v.p) + } + continue + } + + if p.Int64() != int64(v.p) { + t.Fatal(b, &n, e, p, v.e, v.p) + } + } + const N = 1e5 + var nn big.Int + for _, base := range []uint32{2, 3, 15, 17} { + for n := 0; n <= N; n++ { + nn.SetInt64(int64(n)) + ge, gp := PowerizeUint32BigInt(base, &nn) + ee, ep := powerizeUint32BigInt(base, &nn) + if ge != ee || gp.Cmp(ep) != 0 { + t.Fatal(base, n, ge, gp, ee, ep) + } + + gp.Div(gp, big.NewInt(int64(base))) + if gp.Sign() > 0 && gp.Cmp(&nn) >= 0 { + t.Fatal(gp.Sign(), gp.Cmp(&nn)) + } + } + } +} + +func benchmarkPowerizeUint32BigInt(b *testing.B, base uint32, exp int) { + b.StopTimer() + var n big.Int + n.SetBit(&n, exp, 1) + b.StartTimer() + for i := 0; i < b.N; i++ { + PowerizeUint32BigInt(base, &n) + } +} + +func BenchmarkPowerizeUint32BigInt_2_2e1e1(b *testing.B) { + benchmarkPowerizeUint32BigInt(b, 2, 1e1) +} + +func BenchmarkPowerizeUint32BigInt_2_2e1e2(b *testing.B) { + benchmarkPowerizeUint32BigInt(b, 2, 1e2) +} + +func BenchmarkPowerizeUint32BigInt_2_2e1e3(b *testing.B) { + benchmarkPowerizeUint32BigInt(b, 2, 1e3) +} + +func BenchmarkPowerizeUint32BigInt_2_2e1e4(b *testing.B) { + benchmarkPowerizeUint32BigInt(b, 2, 1e4) +} + +func BenchmarkPowerizeUint32BigInt_2_2e1e5(b *testing.B) { + benchmarkPowerizeUint32BigInt(b, 2, 1e5) +} + +func BenchmarkPowerizeUint32BigInt_2_2e1e6(b *testing.B) { + benchmarkPowerizeUint32BigInt(b, 2, 1e6) +} + +func BenchmarkPowerizeUint32BigInt_2_2e1e7(b *testing.B) { + benchmarkPowerizeUint32BigInt(b, 2, 1e7) +} + +func BenchmarkPowerizeUint32BigInt_3_2e1e1(b *testing.B) { + benchmarkPowerizeUint32BigInt(b, 3, 1e1) +} + +func BenchmarkPowerizeUint32BigInt_3_2e1e2(b *testing.B) { + benchmarkPowerizeUint32BigInt(b, 3, 1e2) +} + +func BenchmarkPowerizeUint32BigInt_3_2e1e3(b *testing.B) { + benchmarkPowerizeUint32BigInt(b, 3, 1e3) +} + +func BenchmarkPowerizeUint32BigInt_3_2e1e4(b *testing.B) { + benchmarkPowerizeUint32BigInt(b, 3, 1e4) +} + +func BenchmarkPowerizeUint32BigInt_3_2e1e5(b *testing.B) { + benchmarkPowerizeUint32BigInt(b, 3, 1e5) +} + +func BenchmarkPowerizeUint32BigInt_3_2e1e6(b *testing.B) { + benchmarkPowerizeUint32BigInt(b, 3, 1e6) +} + +func BenchmarkPowerizeUint32BigInt_15_2e1e1(b *testing.B) { + benchmarkPowerizeUint32BigInt(b, 15, 1e1) +} + +func BenchmarkPowerizeUint32BigInt_15_2e1e2(b *testing.B) { + benchmarkPowerizeUint32BigInt(b, 15, 1e2) +} + +func BenchmarkPowerizeUint32BigInt_15_2e1e3(b *testing.B) { + benchmarkPowerizeUint32BigInt(b, 15, 1e3) +} + +func BenchmarkPowerizeUint32BigInt_15_2e1e4(b *testing.B) { + benchmarkPowerizeUint32BigInt(b, 15, 1e4) +} + +func BenchmarkPowerizeUint32BigInt_15_2e1e5(b *testing.B) { + benchmarkPowerizeUint32BigInt(b, 15, 1e5) +} + +func BenchmarkPowerizeUint32BigInt_15_2e1e6(b *testing.B) { + benchmarkPowerizeUint32BigInt(b, 15, 1e6) +} + +func BenchmarkPowerizeUint32BigInt_17_2e1e1(b *testing.B) { + benchmarkPowerizeUint32BigInt(b, 17, 1e1) +} + +func BenchmarkPowerizeUint32BigInt_17_2e1e2(b *testing.B) { + benchmarkPowerizeUint32BigInt(b, 17, 1e2) +} + +func BenchmarkPowerizeUint32BigInt_17_2e1e3(b *testing.B) { + benchmarkPowerizeUint32BigInt(b, 17, 1e3) +} + +func BenchmarkPowerizeUint32BigInt_17_2e1e4(b *testing.B) { + benchmarkPowerizeUint32BigInt(b, 17, 1e4) +} + +func BenchmarkPowerizeUint32BigInt_17_2e1e5(b *testing.B) { + benchmarkPowerizeUint32BigInt(b, 17, 1e5) +} + +func BenchmarkPowerizeUint32BigInt_17_2e1e6(b *testing.B) { + benchmarkPowerizeUint32BigInt(b, 17, 1e6) +} + +func TestPowerizeBigInt(t *testing.T) { + var data = []struct{ b, n, e, p int }{ + {0, 10, 0, -1}, + {1, 10, 0, -1}, + {2, -1, 0, -1}, + {2, 0, 0, 1}, + {2, 1, 0, 1}, + {2, 2, 1, 2}, + {2, 3, 2, 4}, + {3, 0, 0, 1}, + {3, 1, 0, 1}, + {3, 2, 1, 3}, + {3, 3, 1, 3}, + {3, 4, 2, 9}, + {3, 8, 2, 9}, + {3, 9, 2, 9}, + {3, 10, 3, 27}, + {3, 80, 4, 81}, + } + + var b, n big.Int + for _, v := range data { + b.SetInt64(int64(v.b)) + n.SetInt64(int64(v.n)) + e, p := PowerizeBigInt(&b, &n) + if e != uint32(v.e) { + t.Fatal(&b, &n, e, p, v.e, v.p) + } + + if v.p < 0 { + if p != nil { + t.Fatal(&b, &n, e, p, v.e, v.p) + } + continue + } + + if p.Int64() != int64(v.p) { + t.Fatal(&b, &n, e, p, v.e, v.p) + } + } + const N = 1e5 + var nn big.Int + for _, base := range []uint32{2, 3, 15, 17} { + b.SetInt64(int64(base)) + for n := 0; n <= N; n++ { + nn.SetInt64(int64(n)) + ge, gp := PowerizeBigInt(&b, &nn) + ee, ep := powerizeUint32BigInt(base, &nn) + if ge != ee || gp.Cmp(ep) != 0 { + t.Fatal(base, n, ge, gp, ee, ep) + } + + gp.Div(gp, &b) + if gp.Sign() > 0 && gp.Cmp(&nn) >= 0 { + t.Fatal(gp.Sign(), gp.Cmp(&nn)) + } + } + } +} + +func benchmarkPowerizeBigInt(b *testing.B, base uint32, exp int) { + b.StopTimer() + var bb, n big.Int + n.SetBit(&n, exp, 1) + bb.SetInt64(int64(base)) + b.StartTimer() + for i := 0; i < b.N; i++ { + PowerizeBigInt(&bb, &n) + } +} + +func BenchmarkPowerizeBigInt_2_2e1e1(b *testing.B) { + benchmarkPowerizeBigInt(b, 2, 1e1) +} + +func BenchmarkPowerizeBigInt_2_2e1e2(b *testing.B) { + benchmarkPowerizeBigInt(b, 2, 1e2) +} + +func BenchmarkPowerizeBigInt_2_2e1e3(b *testing.B) { + benchmarkPowerizeBigInt(b, 2, 1e3) +} + +func BenchmarkPowerizeBigInt_2_2e1e4(b *testing.B) { + benchmarkPowerizeBigInt(b, 2, 1e4) +} + +func BenchmarkPowerizeBigInt_2_2e1e5(b *testing.B) { + benchmarkPowerizeBigInt(b, 2, 1e5) +} + +func BenchmarkPowerizeBigInt_2_2e1e6(b *testing.B) { + benchmarkPowerizeBigInt(b, 2, 1e6) +} + +func BenchmarkPowerizeBigInt_2_2e1e7(b *testing.B) { + benchmarkPowerizeBigInt(b, 2, 1e7) +} + +func BenchmarkPowerizeBigInt_3_2e1e1(b *testing.B) { + benchmarkPowerizeBigInt(b, 3, 1e1) +} + +func BenchmarkPowerizeBigInt_3_2e1e2(b *testing.B) { + benchmarkPowerizeBigInt(b, 3, 1e2) +} + +func BenchmarkPowerizeBigInt_3_2e1e3(b *testing.B) { + benchmarkPowerizeBigInt(b, 3, 1e3) +} + +func BenchmarkPowerizeBigInt_3_2e1e4(b *testing.B) { + benchmarkPowerizeBigInt(b, 3, 1e4) +} + +func BenchmarkPowerizeBigInt_3_2e1e5(b *testing.B) { + benchmarkPowerizeBigInt(b, 3, 1e5) +} + +func BenchmarkPowerizeBigInt_3_2e1e6(b *testing.B) { + benchmarkPowerizeBigInt(b, 3, 1e6) +} + +func BenchmarkPowerizeBigInt_15_2e1e1(b *testing.B) { + benchmarkPowerizeBigInt(b, 15, 1e1) +} + +func BenchmarkPowerizeBigInt_15_2e1e2(b *testing.B) { + benchmarkPowerizeBigInt(b, 15, 1e2) +} + +func BenchmarkPowerizeBigInt_15_2e1e3(b *testing.B) { + benchmarkPowerizeBigInt(b, 15, 1e3) +} + +func BenchmarkPowerizeBigInt_15_2e1e4(b *testing.B) { + benchmarkPowerizeBigInt(b, 15, 1e4) +} + +func BenchmarkPowerizeBigInt_15_2e1e5(b *testing.B) { + benchmarkPowerizeBigInt(b, 15, 1e5) +} + +func BenchmarkPowerizeBigInt_15_2e1e6(b *testing.B) { + benchmarkPowerizeBigInt(b, 15, 1e6) +} + +func BenchmarkPowerizeBigInt_17_2e1e1(b *testing.B) { + benchmarkPowerizeBigInt(b, 17, 1e1) +} + +func BenchmarkPowerizeBigInt_17_2e1e2(b *testing.B) { + benchmarkPowerizeBigInt(b, 17, 1e2) +} + +func BenchmarkPowerizeBigInt_17_2e1e3(b *testing.B) { + benchmarkPowerizeBigInt(b, 17, 1e3) +} + +func BenchmarkPowerizeBigInt_17_2e1e4(b *testing.B) { + benchmarkPowerizeBigInt(b, 17, 1e4) +} + +func BenchmarkPowerizeBigInt_17_2e1e5(b *testing.B) { + benchmarkPowerizeBigInt(b, 17, 1e5) +} + +func BenchmarkPowerizeBigInt_17_2e1e6(b *testing.B) { + benchmarkPowerizeBigInt(b, 17, 1e6) +} + +func TestEnvelope(t *testing.T) { + const prec = 1e-3 + type check struct { + approx Approximation + x, y float64 + } + data := []struct { + points []float64 + checks []check + }{ + { + []float64{0, 1}, + []check{ + {Linear, 0, 0}, + {Linear, 0.25, 0.25}, + {Linear, 0.5, 0.5}, + {Linear, 0.75, 0.75}, + {Linear, 0.9999, 1}, + }, + }, + { + []float64{-1, 0}, + []check{ + {Linear, 0, -1}, + {Linear, 0.25, -0.75}, + {Linear, 0.5, -0.5}, + {Linear, 0.75, -0.25}, + {Linear, 0.9999, 0}, + }, + }, + { + []float64{-1, 1}, + []check{ + {Linear, 0, -1}, + {Linear, 0.25, -0.5}, + {Linear, 0.5, 0}, + {Linear, 0.75, 0.5}, + {Linear, 0.9999, 1}, + }, + }, + { + []float64{-1, 1, -2}, + []check{ + {Linear, 0, -1}, + {Linear, 0.25, 0}, + {Linear, 0.5, 1}, + {Linear, 0.75, -0.5}, + {Linear, 0.9, -1.4}, + {Linear, 0.9999, -2}, + }, + }, + { + []float64{-1, 1}, + []check{ + {Sinusoidal, 0, -1}, + {Sinusoidal, 0.25, -math.Sqrt2 / 2}, + {Sinusoidal, 0.5, 0}, + {Sinusoidal, 0.75, math.Sqrt2 / 2}, + {Sinusoidal, 0.9999, 1}, + }, + }, + { + []float64{-1, 1, -2}, + []check{ + {Sinusoidal, 0, -1}, + {Sinusoidal, 1. / 8, -math.Sqrt2 / 2}, + {Sinusoidal, 2. / 8, 0}, + {Sinusoidal, 3. / 8, math.Sqrt2 / 2}, + {Sinusoidal, 4. / 8, 1}, + {Sinusoidal, 5. / 8, (3*math.Sqrt2 - 2) / 4}, + {Sinusoidal, 6. / 8, -0.5}, + {Sinusoidal, 7. / 8, (-3*math.Sqrt2 - 2) / 4}, + {Sinusoidal, 0.9999, -2}, + }, + }, + } + for i, suite := range data { + for j, test := range suite.checks { + e, g := test.y, Envelope(test.x, suite.points, test.approx) + d := math.Abs(e - g) + if d > prec { + t.Errorf( + "i %d, j %d, x %v, e %v, g %v, d %v, prec %v", + i, j, test.x, e, g, d, prec, + ) + } + } + } +} + +func TestMaxInt(t *testing.T) { + n := int64(MaxInt) + if n != math.MaxInt32 && n != math.MaxInt64 { + t.Error(n) + } + + t.Logf("64 bit ints: %t, MaxInt: %d", n == math.MaxInt64, n) +} + +func TestMinInt(t *testing.T) { + n := int64(MinInt) + if n != math.MinInt32 && n != math.MinInt64 { + t.Error(n) + } + + t.Logf("64 bit ints: %t. MinInt: %d", n == math.MinInt64, n) +} + +func TestMaxUint(t *testing.T) { + n := uint64(MaxUint) + if n != math.MaxUint32 && n != math.MaxUint64 { + t.Error(n) + } + + t.Logf("64 bit uints: %t. MaxUint: %d", n == math.MaxUint64, n) +} + +func TestMax(t *testing.T) { + tests := []struct{ a, b, e int }{ + {MinInt, MinIntM1, MaxInt}, + {MinIntM1, MinInt, MaxInt}, + {MinIntM1, MinIntM1, MaxInt}, + + {MinInt, MinInt, MinInt}, + {MinInt + 1, MinInt, MinInt + 1}, + {MinInt, MinInt + 1, MinInt + 1}, + + {-1, -1, -1}, + {-1, 0, 0}, + {-1, 1, 1}, + + {0, -1, 0}, + {0, 0, 0}, + {0, 1, 1}, + + {1, -1, 1}, + {1, 0, 1}, + {1, 1, 1}, + + {MaxInt, MaxInt, MaxInt}, + {MaxInt - 1, MaxInt, MaxInt}, + {MaxInt, MaxInt - 1, MaxInt}, + + {MaxIntP1, MaxInt, MaxInt}, + {MaxInt, MaxIntP1, MaxInt}, + {MaxIntP1, MaxIntP1, MinInt}, + } + + for _, test := range tests { + if g, e := Max(test.a, test.b), test.e; g != e { + t.Fatal(test.a, test.b, g, e) + } + } +} + +func TestMin(t *testing.T) { + tests := []struct{ a, b, e int }{ + {MinIntM1, MinInt, MinInt}, + {MinInt, MinIntM1, MinInt}, + {MinIntM1, MinIntM1, MaxInt}, + + {MinInt, MinInt, MinInt}, + {MinInt + 1, MinInt, MinInt}, + {MinInt, MinInt + 1, MinInt}, + + {-1, -1, -1}, + {-1, 0, -1}, + {-1, 1, -1}, + + {0, -1, -1}, + {0, 0, 0}, + {0, 1, 0}, + + {1, -1, -1}, + {1, 0, 0}, + {1, 1, 1}, + + {MaxInt, MaxInt, MaxInt}, + {MaxInt - 1, MaxInt, MaxInt - 1}, + {MaxInt, MaxInt - 1, MaxInt - 1}, + + {MaxIntP1, MaxInt, MinInt}, + {MaxInt, MaxIntP1, MinInt}, + {MaxIntP1, MaxIntP1, MinInt}, + } + + for _, test := range tests { + if g, e := Min(test.a, test.b), test.e; g != e { + t.Fatal(test.a, test.b, g, e) + } + } +} + +func TestUMax(t *testing.T) { + tests := []struct{ a, b, e uint }{ + {0, 0, 0}, + {0, 1, 1}, + {1, 0, 1}, + + {10, 10, 10}, + {10, 11, 11}, + {11, 10, 11}, + {11, 11, 11}, + + {MaxUint, MaxUint, MaxUint}, + {MaxUint, MaxUint - 1, MaxUint}, + {MaxUint - 1, MaxUint, MaxUint}, + {MaxUint - 1, MaxUint - 1, MaxUint - 1}, + + {MaxUint, MaxUintP1, MaxUint}, + {MaxUintP1, MaxUint, MaxUint}, + {MaxUintP1, MaxUintP1, 0}, + } + + for _, test := range tests { + if g, e := UMax(test.a, test.b), test.e; g != e { + t.Fatal(test.a, test.b, g, e) + } + } +} + +func TestUMin(t *testing.T) { + tests := []struct{ a, b, e uint }{ + {0, 0, 0}, + {0, 1, 0}, + {1, 0, 0}, + + {10, 10, 10}, + {10, 11, 10}, + {11, 10, 10}, + {11, 11, 11}, + + {MaxUint, MaxUint, MaxUint}, + {MaxUint, MaxUint - 1, MaxUint - 1}, + {MaxUint - 1, MaxUint, MaxUint - 1}, + {MaxUint - 1, MaxUint - 1, MaxUint - 1}, + + {MaxUint, MaxUintP1, 0}, + {MaxUintP1, MaxUint, 0}, + {MaxUintP1, MaxUintP1, 0}, + } + + for _, test := range tests { + if g, e := UMin(test.a, test.b), test.e; g != e { + t.Fatal(test.a, test.b, g, e) + } + } +} + +func TestMaxByte(t *testing.T) { + tests := []struct{ a, b, e byte }{ + {0, 0, 0}, + {0, 1, 1}, + {1, 0, 1}, + + {10, 10, 10}, + {10, 11, 11}, + {11, 10, 11}, + {11, 11, 11}, + + {math.MaxUint8, math.MaxUint8, math.MaxUint8}, + {math.MaxUint8, math.MaxUint8 - 1, math.MaxUint8}, + {math.MaxUint8 - 1, math.MaxUint8, math.MaxUint8}, + {math.MaxUint8 - 1, math.MaxUint8 - 1, math.MaxUint8 - 1}, + } + + for _, test := range tests { + if g, e := MaxByte(test.a, test.b), test.e; g != e { + t.Fatal(test.a, test.b, g, e) + } + } +} + +func TestMinByte(t *testing.T) { + tests := []struct{ a, b, e byte }{ + {0, 0, 0}, + {0, 1, 0}, + {1, 0, 0}, + + {10, 10, 10}, + {10, 11, 10}, + {11, 10, 10}, + {11, 11, 11}, + + {math.MaxUint8, math.MaxUint8, math.MaxUint8}, + {math.MaxUint8, math.MaxUint8 - 1, math.MaxUint8 - 1}, + {math.MaxUint8 - 1, math.MaxUint8, math.MaxUint8 - 1}, + {math.MaxUint8 - 1, math.MaxUint8 - 1, math.MaxUint8 - 1}, + } + + for _, test := range tests { + if g, e := MinByte(test.a, test.b), test.e; g != e { + t.Fatal(test.a, test.b, g, e) + } + } +} + +func TestMaxUint16(t *testing.T) { + tests := []struct{ a, b, e uint16 }{ + {0, 0, 0}, + {0, 1, 1}, + {1, 0, 1}, + + {10, 10, 10}, + {10, 11, 11}, + {11, 10, 11}, + {11, 11, 11}, + + {math.MaxUint16, math.MaxUint16, math.MaxUint16}, + {math.MaxUint16, math.MaxUint16 - 1, math.MaxUint16}, + {math.MaxUint16 - 1, math.MaxUint16, math.MaxUint16}, + {math.MaxUint16 - 1, math.MaxUint16 - 1, math.MaxUint16 - 1}, + } + + for _, test := range tests { + if g, e := MaxUint16(test.a, test.b), test.e; g != e { + t.Fatal(test.a, test.b, g, e) + } + } +} + +func TestMinUint16(t *testing.T) { + tests := []struct{ a, b, e uint16 }{ + {0, 0, 0}, + {0, 1, 0}, + {1, 0, 0}, + + {10, 10, 10}, + {10, 11, 10}, + {11, 10, 10}, + {11, 11, 11}, + + {math.MaxUint16, math.MaxUint16, math.MaxUint16}, + {math.MaxUint16, math.MaxUint16 - 1, math.MaxUint16 - 1}, + {math.MaxUint16 - 1, math.MaxUint16, math.MaxUint16 - 1}, + {math.MaxUint16 - 1, math.MaxUint16 - 1, math.MaxUint16 - 1}, + } + + for _, test := range tests { + if g, e := MinUint16(test.a, test.b), test.e; g != e { + t.Fatal(test.a, test.b, g, e) + } + } +} + +func TestMaxUint32(t *testing.T) { + tests := []struct{ a, b, e uint32 }{ + {0, 0, 0}, + {0, 1, 1}, + {1, 0, 1}, + + {10, 10, 10}, + {10, 11, 11}, + {11, 10, 11}, + {11, 11, 11}, + + {math.MaxUint32, math.MaxUint32, math.MaxUint32}, + {math.MaxUint32, math.MaxUint32 - 1, math.MaxUint32}, + {math.MaxUint32 - 1, math.MaxUint32, math.MaxUint32}, + {math.MaxUint32 - 1, math.MaxUint32 - 1, math.MaxUint32 - 1}, + } + + for _, test := range tests { + if g, e := MaxUint32(test.a, test.b), test.e; g != e { + t.Fatal(test.a, test.b, g, e) + } + } +} + +func TestMinUint32(t *testing.T) { + tests := []struct{ a, b, e uint32 }{ + {0, 0, 0}, + {0, 1, 0}, + {1, 0, 0}, + + {10, 10, 10}, + {10, 11, 10}, + {11, 10, 10}, + {11, 11, 11}, + + {math.MaxUint32, math.MaxUint32, math.MaxUint32}, + {math.MaxUint32, math.MaxUint32 - 1, math.MaxUint32 - 1}, + {math.MaxUint32 - 1, math.MaxUint32, math.MaxUint32 - 1}, + {math.MaxUint32 - 1, math.MaxUint32 - 1, math.MaxUint32 - 1}, + } + + for _, test := range tests { + if g, e := MinUint32(test.a, test.b), test.e; g != e { + t.Fatal(test.a, test.b, g, e) + } + } +} + +func TestMaxUint64(t *testing.T) { + tests := []struct{ a, b, e uint64 }{ + {0, 0, 0}, + {0, 1, 1}, + {1, 0, 1}, + + {10, 10, 10}, + {10, 11, 11}, + {11, 10, 11}, + {11, 11, 11}, + + {math.MaxUint64, math.MaxUint64, math.MaxUint64}, + {math.MaxUint64, math.MaxUint64 - 1, math.MaxUint64}, + {math.MaxUint64 - 1, math.MaxUint64, math.MaxUint64}, + {math.MaxUint64 - 1, math.MaxUint64 - 1, math.MaxUint64 - 1}, + } + + for _, test := range tests { + if g, e := MaxUint64(test.a, test.b), test.e; g != e { + t.Fatal(test.a, test.b, g, e) + } + } +} + +func TestMinUint64(t *testing.T) { + tests := []struct{ a, b, e uint64 }{ + {0, 0, 0}, + {0, 1, 0}, + {1, 0, 0}, + + {10, 10, 10}, + {10, 11, 10}, + {11, 10, 10}, + {11, 11, 11}, + + {math.MaxUint64, math.MaxUint64, math.MaxUint64}, + {math.MaxUint64, math.MaxUint64 - 1, math.MaxUint64 - 1}, + {math.MaxUint64 - 1, math.MaxUint64, math.MaxUint64 - 1}, + {math.MaxUint64 - 1, math.MaxUint64 - 1, math.MaxUint64 - 1}, + } + + for _, test := range tests { + if g, e := MinUint64(test.a, test.b), test.e; g != e { + t.Fatal(test.a, test.b, g, e) + } + } +} + +func TestMaxInt8(t *testing.T) { + tests := []struct{ a, b, e int8 }{ + {math.MinInt8, math.MinInt8, math.MinInt8}, + {math.MinInt8 + 1, math.MinInt8, math.MinInt8 + 1}, + {math.MinInt8, math.MinInt8 + 1, math.MinInt8 + 1}, + + {-1, -1, -1}, + {-1, 0, 0}, + {-1, 1, 1}, + + {0, -1, 0}, + {0, 0, 0}, + {0, 1, 1}, + + {1, -1, 1}, + {1, 0, 1}, + {1, 1, 1}, + + {math.MaxInt8, math.MaxInt8, math.MaxInt8}, + {math.MaxInt8 - 1, math.MaxInt8, math.MaxInt8}, + {math.MaxInt8, math.MaxInt8 - 1, math.MaxInt8}, + } + + for _, test := range tests { + if g, e := MaxInt8(test.a, test.b), test.e; g != e { + t.Fatal(test.a, test.b, g, e) + } + } +} + +func TestMinInt8(t *testing.T) { + tests := []struct{ a, b, e int8 }{ + {math.MinInt8, math.MinInt8, math.MinInt8}, + {math.MinInt8 + 1, math.MinInt8, math.MinInt8}, + {math.MinInt8, math.MinInt8 + 1, math.MinInt8}, + + {-1, -1, -1}, + {-1, 0, -1}, + {-1, 1, -1}, + + {0, -1, -1}, + {0, 0, 0}, + {0, 1, 0}, + + {1, -1, -1}, + {1, 0, 0}, + {1, 1, 1}, + + {math.MaxInt8, math.MaxInt8, math.MaxInt8}, + {math.MaxInt8 - 1, math.MaxInt8, math.MaxInt8 - 1}, + {math.MaxInt8, math.MaxInt8 - 1, math.MaxInt8 - 1}, + } + + for _, test := range tests { + if g, e := MinInt8(test.a, test.b), test.e; g != e { + t.Fatal(test.a, test.b, g, e) + } + } +} + +func TestMaxInt16(t *testing.T) { + tests := []struct{ a, b, e int16 }{ + {math.MinInt16, math.MinInt16, math.MinInt16}, + {math.MinInt16 + 1, math.MinInt16, math.MinInt16 + 1}, + {math.MinInt16, math.MinInt16 + 1, math.MinInt16 + 1}, + + {-1, -1, -1}, + {-1, 0, 0}, + {-1, 1, 1}, + + {0, -1, 0}, + {0, 0, 0}, + {0, 1, 1}, + + {1, -1, 1}, + {1, 0, 1}, + {1, 1, 1}, + + {math.MaxInt16, math.MaxInt16, math.MaxInt16}, + {math.MaxInt16 - 1, math.MaxInt16, math.MaxInt16}, + {math.MaxInt16, math.MaxInt16 - 1, math.MaxInt16}, + } + + for _, test := range tests { + if g, e := MaxInt16(test.a, test.b), test.e; g != e { + t.Fatal(test.a, test.b, g, e) + } + } +} + +func TestMinInt16(t *testing.T) { + tests := []struct{ a, b, e int16 }{ + {math.MinInt16, math.MinInt16, math.MinInt16}, + {math.MinInt16 + 1, math.MinInt16, math.MinInt16}, + {math.MinInt16, math.MinInt16 + 1, math.MinInt16}, + + {-1, -1, -1}, + {-1, 0, -1}, + {-1, 1, -1}, + + {0, -1, -1}, + {0, 0, 0}, + {0, 1, 0}, + + {1, -1, -1}, + {1, 0, 0}, + {1, 1, 1}, + + {math.MaxInt16, math.MaxInt16, math.MaxInt16}, + {math.MaxInt16 - 1, math.MaxInt16, math.MaxInt16 - 1}, + {math.MaxInt16, math.MaxInt16 - 1, math.MaxInt16 - 1}, + } + + for _, test := range tests { + if g, e := MinInt16(test.a, test.b), test.e; g != e { + t.Fatal(test.a, test.b, g, e) + } + } +} + +func TestMaxInt32(t *testing.T) { + tests := []struct{ a, b, e int32 }{ + {math.MinInt32, math.MinInt32, math.MinInt32}, + {math.MinInt32 + 1, math.MinInt32, math.MinInt32 + 1}, + {math.MinInt32, math.MinInt32 + 1, math.MinInt32 + 1}, + + {-1, -1, -1}, + {-1, 0, 0}, + {-1, 1, 1}, + + {0, -1, 0}, + {0, 0, 0}, + {0, 1, 1}, + + {1, -1, 1}, + {1, 0, 1}, + {1, 1, 1}, + + {math.MaxInt32, math.MaxInt32, math.MaxInt32}, + {math.MaxInt32 - 1, math.MaxInt32, math.MaxInt32}, + {math.MaxInt32, math.MaxInt32 - 1, math.MaxInt32}, + } + + for _, test := range tests { + if g, e := MaxInt32(test.a, test.b), test.e; g != e { + t.Fatal(test.a, test.b, g, e) + } + } +} + +func TestMinInt32(t *testing.T) { + tests := []struct{ a, b, e int32 }{ + {math.MinInt32, math.MinInt32, math.MinInt32}, + {math.MinInt32 + 1, math.MinInt32, math.MinInt32}, + {math.MinInt32, math.MinInt32 + 1, math.MinInt32}, + + {-1, -1, -1}, + {-1, 0, -1}, + {-1, 1, -1}, + + {0, -1, -1}, + {0, 0, 0}, + {0, 1, 0}, + + {1, -1, -1}, + {1, 0, 0}, + {1, 1, 1}, + + {math.MaxInt32, math.MaxInt32, math.MaxInt32}, + {math.MaxInt32 - 1, math.MaxInt32, math.MaxInt32 - 1}, + {math.MaxInt32, math.MaxInt32 - 1, math.MaxInt32 - 1}, + } + + for _, test := range tests { + if g, e := MinInt32(test.a, test.b), test.e; g != e { + t.Fatal(test.a, test.b, g, e) + } + } +} + +func TestMaxInt64(t *testing.T) { + tests := []struct{ a, b, e int64 }{ + {math.MinInt64, math.MinInt64, math.MinInt64}, + {math.MinInt64 + 1, math.MinInt64, math.MinInt64 + 1}, + {math.MinInt64, math.MinInt64 + 1, math.MinInt64 + 1}, + + {-1, -1, -1}, + {-1, 0, 0}, + {-1, 1, 1}, + + {0, -1, 0}, + {0, 0, 0}, + {0, 1, 1}, + + {1, -1, 1}, + {1, 0, 1}, + {1, 1, 1}, + + {math.MaxInt64, math.MaxInt64, math.MaxInt64}, + {math.MaxInt64 - 1, math.MaxInt64, math.MaxInt64}, + {math.MaxInt64, math.MaxInt64 - 1, math.MaxInt64}, + } + + for _, test := range tests { + if g, e := MaxInt64(test.a, test.b), test.e; g != e { + t.Fatal(test.a, test.b, g, e) + } + } +} + +func TestMinInt64(t *testing.T) { + tests := []struct{ a, b, e int64 }{ + {math.MinInt64, math.MinInt64, math.MinInt64}, + {math.MinInt64 + 1, math.MinInt64, math.MinInt64}, + {math.MinInt64, math.MinInt64 + 1, math.MinInt64}, + + {-1, -1, -1}, + {-1, 0, -1}, + {-1, 1, -1}, + + {0, -1, -1}, + {0, 0, 0}, + {0, 1, 0}, + + {1, -1, -1}, + {1, 0, 0}, + {1, 1, 1}, + + {math.MaxInt64, math.MaxInt64, math.MaxInt64}, + {math.MaxInt64 - 1, math.MaxInt64, math.MaxInt64 - 1}, + {math.MaxInt64, math.MaxInt64 - 1, math.MaxInt64 - 1}, + } + + for _, test := range tests { + if g, e := MinInt64(test.a, test.b), test.e; g != e { + t.Fatal(test.a, test.b, g, e) + } + } +} + +func TestPopCountBigInt(t *testing.T) { + const N = 1e4 + rng := rand.New(rand.NewSource(42)) + lim := big.NewInt(0) + lim.SetBit(lim, 1e3, 1) + z := big.NewInt(0) + m1 := big.NewInt(-1) + for i := 0; i < N; i++ { + z.Rand(rng, lim) + g := PopCountBigInt(z) + e := 0 + for bit := 0; bit < z.BitLen(); bit++ { + if z.Bit(bit) != 0 { + e++ + } + } + if g != e { + t.Fatal(g, e) + } + + z.Mul(z, m1) + if g := PopCountBigInt(z); g != e { + t.Fatal(g, e) + } + } +} + +func benchmarkPopCountBigInt(b *testing.B, bits int) { + lim := big.NewInt(0) + lim.SetBit(lim, bits, 1) + z := big.NewInt(0) + z.Rand(rand.New(rand.NewSource(42)), lim) + b.ResetTimer() + for i := 0; i < b.N; i++ { + PopCountBigInt(z) + } +} + +func BenchmarkPopCountBigInt1e1(b *testing.B) { + benchmarkPopCountBigInt(b, 1e1) +} + +func BenchmarkPopCountBigInt1e2(b *testing.B) { + benchmarkPopCountBigInt(b, 1e2) +} + +func BenchmarkPopCountBigInt1e3(b *testing.B) { + benchmarkPopCountBigInt(b, 1e3) +} + +func BenchmarkPopCountBigIbnt1e4(b *testing.B) { + benchmarkPopCountBigInt(b, 1e4) +} + +func BenchmarkPopCountBigInt1e5(b *testing.B) { + benchmarkPopCountBigInt(b, 1e5) +} + +func BenchmarkPopCountBigInt1e6(b *testing.B) { + benchmarkPopCountBigInt(b, 1e6) +} + +func TestToBase(t *testing.T) { + x := ToBase(big.NewInt(0), 42) + e := []int{0} + if g, e := len(x), len(e); g != e { + t.Fatal(g, e) + } + + for i, g := range x { + if e := e[i]; g != e { + t.Fatal(i, g, e) + } + } + + x = ToBase(big.NewInt(2047), 22) + e = []int{1, 5, 4} + if g, e := len(x), len(e); g != e { + t.Fatal(g, e) + } + + for i, g := range x { + if e := e[i]; g != e { + t.Fatal(i, g, e) + } + } + + x = ToBase(big.NewInt(-2047), 22) + e = []int{-1, -5, -4} + if g, e := len(x), len(e); g != e { + t.Fatal(g, e) + } + + for i, g := range x { + if e := e[i]; g != e { + t.Fatal(i, g, e) + } + } +} + +func TestBug(t *testing.T) { + if BitLenUint(MaxUint) != 64 { + t.Logf("Bug reproducible only on 64 bit architecture") + return + } + + _, err := NewFC32(MinInt, MaxInt, true) + if err == nil { + t.Fatal("Expected non nil err") + } +} diff --git a/Godeps/_workspace/src/github.com/cznic/mathutil/bits.go b/Godeps/_workspace/src/github.com/cznic/mathutil/bits.go new file mode 100644 index 0000000..6eaa4e3 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/mathutil/bits.go @@ -0,0 +1,207 @@ +// Copyright (c) 2014 The mathutil 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 mathutil + +import ( + "math/big" +) + +// BitLenByte returns the bit width of the non zero part of n. +func BitLenByte(n byte) int { + return log2[n] + 1 +} + +// BitLenUint16 returns the bit width of the non zero part of n. +func BitLenUint16(n uint16) int { + if b := n >> 8; b != 0 { + return log2[b] + 8 + 1 + } + + return log2[n] + 1 +} + +// BitLenUint32 returns the bit width of the non zero part of n. +func BitLenUint32(n uint32) int { + if b := n >> 24; b != 0 { + return log2[b] + 24 + 1 + } + + if b := n >> 16; b != 0 { + return log2[b] + 16 + 1 + } + + if b := n >> 8; b != 0 { + return log2[b] + 8 + 1 + } + + return log2[n] + 1 +} + +// BitLen returns the bit width of the non zero part of n. +func BitLen(n int) int { // Should handle correctly [future] 64 bit Go ints + if IntBits == 64 { + return BitLenUint64(uint64(n)) + } + + if b := byte(n >> 24); b != 0 { + return log2[b] + 24 + 1 + } + + if b := byte(n >> 16); b != 0 { + return log2[b] + 16 + 1 + } + + if b := byte(n >> 8); b != 0 { + return log2[b] + 8 + 1 + } + + return log2[byte(n)] + 1 +} + +// BitLenUint returns the bit width of the non zero part of n. +func BitLenUint(n uint) int { // Should handle correctly [future] 64 bit Go uints + if IntBits == 64 { + return BitLenUint64(uint64(n)) + } + + if b := n >> 24; b != 0 { + return log2[b] + 24 + 1 + } + + if b := n >> 16; b != 0 { + return log2[b] + 16 + 1 + } + + if b := n >> 8; b != 0 { + return log2[b] + 8 + 1 + } + + return log2[n] + 1 +} + +// BitLenUint64 returns the bit width of the non zero part of n. +func BitLenUint64(n uint64) int { + if b := n >> 56; b != 0 { + return log2[b] + 56 + 1 + } + + if b := n >> 48; b != 0 { + return log2[b] + 48 + 1 + } + + if b := n >> 40; b != 0 { + return log2[b] + 40 + 1 + } + + if b := n >> 32; b != 0 { + return log2[b] + 32 + 1 + } + + if b := n >> 24; b != 0 { + return log2[b] + 24 + 1 + } + + if b := n >> 16; b != 0 { + return log2[b] + 16 + 1 + } + + if b := n >> 8; b != 0 { + return log2[b] + 8 + 1 + } + + return log2[n] + 1 +} + +// BitLenUintptr returns the bit width of the non zero part of n. +func BitLenUintptr(n uintptr) int { + if b := n >> 56; b != 0 { + return log2[b] + 56 + 1 + } + + if b := n >> 48; b != 0 { + return log2[b] + 48 + 1 + } + + if b := n >> 40; b != 0 { + return log2[b] + 40 + 1 + } + + if b := n >> 32; b != 0 { + return log2[b] + 32 + 1 + } + + if b := n >> 24; b != 0 { + return log2[b] + 24 + 1 + } + + if b := n >> 16; b != 0 { + return log2[b] + 16 + 1 + } + + if b := n >> 8; b != 0 { + return log2[b] + 8 + 1 + } + + return log2[n] + 1 +} + +// PopCountByte returns population count of n (number of bits set in n). +func PopCountByte(n byte) int { + return int(popcnt[byte(n)]) +} + +// PopCountUint16 returns population count of n (number of bits set in n). +func PopCountUint16(n uint16) int { + return int(popcnt[byte(n>>8)]) + int(popcnt[byte(n)]) +} + +// PopCountUint32 returns population count of n (number of bits set in n). +func PopCountUint32(n uint32) int { + return int(popcnt[byte(n>>24)]) + int(popcnt[byte(n>>16)]) + + int(popcnt[byte(n>>8)]) + int(popcnt[byte(n)]) +} + +// PopCount returns population count of n (number of bits set in n). +func PopCount(n int) int { // Should handle correctly [future] 64 bit Go ints + if IntBits == 64 { + return PopCountUint64(uint64(n)) + } + + return PopCountUint32(uint32(n)) +} + +// PopCountUint returns population count of n (number of bits set in n). +func PopCountUint(n uint) int { // Should handle correctly [future] 64 bit Go uints + if IntBits == 64 { + return PopCountUint64(uint64(n)) + } + + return PopCountUint32(uint32(n)) +} + +// PopCountUintptr returns population count of n (number of bits set in n). +func PopCountUintptr(n uintptr) int { + if UintPtrBits == 64 { + return PopCountUint64(uint64(n)) + } + + return PopCountUint32(uint32(n)) +} + +// PopCountUint64 returns population count of n (number of bits set in n). +func PopCountUint64(n uint64) int { + return int(popcnt[byte(n>>56)]) + int(popcnt[byte(n>>48)]) + + int(popcnt[byte(n>>40)]) + int(popcnt[byte(n>>32)]) + + int(popcnt[byte(n>>24)]) + int(popcnt[byte(n>>16)]) + + int(popcnt[byte(n>>8)]) + int(popcnt[byte(n)]) +} + +// PopCountBigInt returns population count of |n| (number of bits set in |n|). +func PopCountBigInt(n *big.Int) (r int) { + for _, v := range n.Bits() { + r += PopCountUintptr(uintptr(v)) + } + return +} diff --git a/Godeps/_workspace/src/github.com/cznic/mathutil/envelope.go b/Godeps/_workspace/src/github.com/cznic/mathutil/envelope.go new file mode 100644 index 0000000..ff8e601 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/mathutil/envelope.go @@ -0,0 +1,46 @@ +// Copyright (c) 2014 The mathutil 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 mathutil + +import ( + "math" +) + +// Approximation type determines approximation methods used by e.g. Envelope. +type Approximation int + +// Specific approximation method tags +const ( + _ Approximation = iota + Linear // As named + Sinusoidal // Smooth for all derivations +) + +// Envelope is an utility for defining simple curves using a small (usually) +// set of data points. Envelope returns a value defined by x, points and +// approximation. The value of x must be in [0,1) otherwise the result is +// undefined or the function may panic. Points are interpreted as dividing the +// [0,1) interval in len(points)-1 sections, so len(points) must be > 1 or the +// function may panic. According to the left and right points closing/adjacent +// to the section the resulting value is interpolated using the chosen +// approximation method. Unsupported values of approximation are silently +// interpreted as 'Linear'. +func Envelope(x float64, points []float64, approximation Approximation) float64 { + step := 1 / float64(len(points)-1) + fslot := math.Floor(x / step) + mod := x - fslot*step + slot := int(fslot) + l, r := points[slot], points[slot+1] + rmod := mod / step + switch approximation { + case Sinusoidal: + k := (math.Sin(math.Pi*(rmod-0.5)) + 1) / 2 + return l + (r-l)*k + case Linear: + fallthrough + default: + return l + (r-l)*rmod + } +} diff --git a/Godeps/_workspace/src/github.com/cznic/mathutil/example/.gitignore b/Godeps/_workspace/src/github.com/cznic/mathutil/example/.gitignore new file mode 100644 index 0000000..ae251f3 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/mathutil/example/.gitignore @@ -0,0 +1,2 @@ +example +Makefile diff --git a/Godeps/_workspace/src/github.com/cznic/mathutil/example/example.go b/Godeps/_workspace/src/github.com/cznic/mathutil/example/example.go new file mode 100644 index 0000000..b34aabb --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/mathutil/example/example.go @@ -0,0 +1,48 @@ +// Copyright (c) 2011 CZ.NIC z.s.p.o. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// blame: jnml, labs.nic.cz + +// +build ignore + +package main + +import ( + "bufio" + "flag" + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/mathutil" + "log" + "math" + "os" +) + +/* + +$ # Usage e.g.: +$ go run example.go -max 1024 > mathutil.dat # generate 1kB of "random" data + +*/ +func main() { + r, err := mathutil.NewFC32(math.MinInt32, math.MaxInt32, true) + if err != nil { + log.Fatal(err) + } + + var mflag uint64 + flag.Uint64Var(&mflag, "max", 0, "limit output to max bytes") + flag.Parse() + stdout := bufio.NewWriter(os.Stdout) + if mflag != 0 { + for i := uint64(0); i < mflag; i++ { + if err := stdout.WriteByte(byte(r.Next())); err != nil { + log.Fatal(err) + } + } + stdout.Flush() + return + } + + for stdout.WriteByte(byte(r.Next())) == nil { + } +} diff --git a/Godeps/_workspace/src/github.com/cznic/mathutil/example2/.gitignore b/Godeps/_workspace/src/github.com/cznic/mathutil/example2/.gitignore new file mode 100644 index 0000000..85c3999 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/mathutil/example2/.gitignore @@ -0,0 +1,2 @@ +example2 +Makefile diff --git a/Godeps/_workspace/src/github.com/cznic/mathutil/example2/example2.go b/Godeps/_workspace/src/github.com/cznic/mathutil/example2/example2.go new file mode 100644 index 0000000..86a0420 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/mathutil/example2/example2.go @@ -0,0 +1,66 @@ +// Copyright (c) 2011 CZ.NIC z.s.p.o. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// blame: jnml, labs.nic.cz + +// +build ignore + +package main + +import ( + "bytes" + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/mathutil" + "image" + "image/png" + "io/ioutil" + "log" + "math" + "math/rand" +) + +// $ go run example2.go # view rand.png and rnd.png by your favorite pic viewer +// +// see http://www.boallen.com/random-numbers.html +func main() { + sqr := image.Rect(0, 0, 511, 511) + r, err := mathutil.NewFC32(math.MinInt32, math.MaxInt32, true) + if err != nil { + log.Fatal("NewFC32", err) + } + + img := image.NewGray(sqr) + for y := 0; y < 512; y++ { + for x := 0; x < 512; x++ { + if r.Next()&1 != 0 { + img.Set(x, y, image.White) + } + } + } + buf := bytes.NewBuffer(nil) + if err := png.Encode(buf, img); err != nil { + log.Fatal("Encode rnd.png ", err) + } + + if err := ioutil.WriteFile("rnd.png", buf.Bytes(), 0666); err != nil { + log.Fatal("ioutil.WriteFile/rnd.png ", err) + } + + r2 := rand.New(rand.NewSource(0)) + img = image.NewGray(sqr) + for y := 0; y < 512; y++ { + for x := 0; x < 512; x++ { + if r2.Int()&1 != 0 { + img.Set(x, y, image.White) + } + } + } + buf = bytes.NewBuffer(nil) + if err := png.Encode(buf, img); err != nil { + log.Fatal("Encode rand.png ", err) + } + + if err := ioutil.WriteFile("rand.png", buf.Bytes(), 0666); err != nil { + log.Fatal("ioutil.WriteFile/rand.png ", err) + } +} diff --git a/Godeps/_workspace/src/github.com/cznic/mathutil/example3/.gitignore b/Godeps/_workspace/src/github.com/cznic/mathutil/example3/.gitignore new file mode 100644 index 0000000..474f23a --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/mathutil/example3/.gitignore @@ -0,0 +1,2 @@ +example3 +Makefile diff --git a/Godeps/_workspace/src/github.com/cznic/mathutil/example3/example3.go b/Godeps/_workspace/src/github.com/cznic/mathutil/example3/example3.go new file mode 100644 index 0000000..572d108 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/mathutil/example3/example3.go @@ -0,0 +1,43 @@ +// Copyright (c) 2011 CZ.NIC z.s.p.o. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// blame: jnml, labs.nic.cz + +// +build ignore + +package main + +import ( + "bufio" + "flag" + "log" + "math/rand" + "os" +) + +/* + +$ # Usage e.g.: +$ go run example3.go -max 1024 > rand.dat # generate 1kB of "random" data + +*/ +func main() { + r := rand.New(rand.NewSource(1)) + var mflag uint64 + flag.Uint64Var(&mflag, "max", 0, "limit output to max bytes") + flag.Parse() + stdout := bufio.NewWriter(os.Stdout) + if mflag != 0 { + for i := uint64(0); i < mflag; i++ { + if err := stdout.WriteByte(byte(r.Int())); err != nil { + log.Fatal(err) + } + } + stdout.Flush() + return + } + + for stdout.WriteByte(byte(r.Int())) == nil { + } +} diff --git a/Godeps/_workspace/src/github.com/cznic/mathutil/example4/main.go b/Godeps/_workspace/src/github.com/cznic/mathutil/example4/main.go new file mode 100644 index 0000000..8157211 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/mathutil/example4/main.go @@ -0,0 +1,90 @@ +// Copyright (c) 2011 jnml. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +// Let QRN be the number of quadratic residues of N. Let Q be QRN/N. From a +// sorted list of primorial products < 2^32 find "record breakers". "Record +// breaker" is N with new lowest Q. +// +// There are only 49 "record breakers" < 2^32. +// +// To run the example $ go run main.go +package main + +import ( + "fmt" + "math" + "sort" + "time" + + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/mathutil" + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/sortutil" +) + +func main() { + pp := mathutil.PrimorialProductsUint32(0, math.MaxUint32, 32) + sort.Sort(sortutil.Uint32Slice(pp)) + var bestN, bestD uint32 = 1, 1 + order, checks := 0, 0 + var ixDirty uint32 + m := make([]byte, math.MaxUint32>>3) + for _, n := range pp { + for i := range m[:ixDirty+1] { + m[i] = 0 + } + ixDirty = 0 + checks++ + limit0 := mathutil.QScaleUint32(n, bestN, bestD) + if limit0 > math.MaxUint32 { + panic(0) + } + limit := uint32(limit0) + n64 := uint64(n) + hi := n64 >> 1 + hits := uint32(0) + check := true + fmt.Printf("\r%10d %d/%d", n, checks, len(pp)) + t0 := time.Now() + for i := uint64(0); i < hi; i++ { + sq := uint32(i * i % n64) + ix := sq >> 3 + msk := byte(1 << (sq & 7)) + if m[ix]&msk == 0 { + hits++ + if hits >= limit { + check = false + break + } + } + m[ix] |= msk + if ix > ixDirty { + ixDirty = ix + } + } + + adjPrime := ".." // Composite before + if mathutil.IsPrime(n - 1) { + adjPrime = "P." // Prime before + } + switch mathutil.IsPrime(n + 1) { + case true: + adjPrime += "P" // Prime after + case false: + adjPrime += "." // Composite after + } + + if check && mathutil.QCmpUint32(hits, n, bestN, bestD) < 0 { + order++ + d := time.Since(t0) + bestN, bestD = hits, n + q := float64(hits) / float64(n) + fmt.Printf( + "\r%2s #%03d %d %d %.2f %.2E %s %s %v\n", + adjPrime, order, n, hits, + 1/q, q, d, time.Now().Format("15:04:05"), mathutil.FactorInt(n), + ) + } + } +} diff --git a/Godeps/_workspace/src/github.com/cznic/mathutil/example4/results b/Godeps/_workspace/src/github.com/cznic/mathutil/example4/results new file mode 100644 index 0000000..1642c9d --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/mathutil/example4/results @@ -0,0 +1,55 @@ +$ time go run main.go +..P #001 2 1 2.00 5.00E-01 3us 11:13:37 +P.. #002 8 3 2.67 3.75E-01 1us 11:13:37 +P.P #003 12 4 3.00 3.33E-01 1us 11:13:37 +..P #004 16 4 4.00 2.50E-01 1us 11:13:37 +P.. #005 32 7 4.57 2.19E-01 1us 11:13:37 +P.. #006 48 8 6.00 1.67E-01 1us 11:13:37 +..P #007 96 14 6.86 1.46E-01 2us 11:13:37 +... #008 144 16 9.00 1.11E-01 2us 11:13:37 +P.P #009 240 24 10.00 1.00E-01 3us 11:13:37 +... #010 288 28 10.29 9.72E-02 4us 11:13:37 +P.. #011 480 42 11.43 8.75E-02 6us 11:13:37 +..P #012 576 48 12.00 8.33E-02 7us 11:13:37 +P.. #013 720 48 15.00 6.67E-02 8us 11:13:37 +P.. #014 1440 84 17.14 5.83E-02 15us 11:13:37 +... #015 1680 96 17.50 5.71E-02 17us 11:13:37 +P.. #016 2880 144 20.00 5.00E-02 28us 11:13:37 +... #017 3600 176 20.45 4.89E-02 35us 11:13:37 +P.. #018 5040 192 26.25 3.81E-02 50us 11:13:37 +P.. #019 10080 336 30.00 3.33E-02 96us 11:13:37 +..P #020 18480 576 32.08 3.12E-02 174us 11:13:37 +..P #021 20160 576 35.00 2.86E-02 190us 11:13:37 +... #022 25200 704 35.80 2.79E-02 237us 11:13:37 +... #023 36960 1008 36.67 2.73E-02 348us 11:13:37 +... #024 50400 1232 40.91 2.44E-02 473us 11:13:37 +P.P #025 55440 1152 48.12 2.08E-02 518us 11:13:37 +P.P #026 110880 2016 55.00 1.82E-02 1.039ms 11:13:37 +... #027 221760 3456 64.17 1.56E-02 2.056ms 11:13:37 +... #028 277200 4224 65.62 1.52E-02 2.82ms 11:13:37 +... #029 443520 6624 66.96 1.49E-02 4.179ms 11:13:37 +... #030 480480 7056 68.10 1.47E-02 4.536ms 11:13:37 +... #031 554400 7392 75.00 1.33E-02 5.217ms 11:13:37 +... #032 720720 8064 89.38 1.12E-02 6.919ms 11:13:37 +P.. #033 1441440 14112 102.14 9.79E-03 14.767ms 11:13:38 +... #034 2882880 24192 119.17 8.39E-03 28.661ms 11:13:38 +... #035 3603600 29568 121.88 8.21E-03 35.55ms 11:13:38 +... #036 5765760 46368 124.35 8.04E-03 57.798ms 11:13:38 +... #037 7207200 51744 139.29 7.18E-03 75.157ms 11:13:38 +... #038 12252240 72576 168.82 5.92E-03 147.179ms 11:13:38 +P.. #039 24504480 127008 192.94 5.18E-03 507.174ms 11:13:40 +... #040 49008960 217728 225.09 4.44E-03 1.334847s 11:13:43 +P.. #041 61261200 266112 230.21 4.34E-03 1.739597s 11:13:45 +... #042 98017920 417312 234.88 4.26E-03 2.971988s 11:13:51 +... #043 122522400 465696 263.10 3.80E-03 3.767685s 11:13:57 +P.P #044 232792560 725760 320.76 3.12E-03 7.425308s 11:14:15 +P.. #045 465585120 1270080 366.58 2.73E-03 15.18066s 11:14:50 +P.. #046 931170240 2177280 427.68 2.34E-03 34.22548s 11:16:06 +..P #047 1163962800 2661120 437.40 2.29E-03 45.038331s 11:17:10 +..P #048 1862340480 4173120 446.27 2.24E-03 1m10.288676s 11:19:26 +... #049 2327925600 4656960 499.88 2.00E-03 1m31.882756s 11:21:44 +4257792000 1679/1679 +real 11m36.548s +user 11m30.530s +sys 0m1.700s +$ diff --git a/Godeps/_workspace/src/github.com/cznic/mathutil/ff/main.go b/Godeps/_workspace/src/github.com/cznic/mathutil/ff/main.go new file mode 100644 index 0000000..c5690c1 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/mathutil/ff/main.go @@ -0,0 +1,83 @@ +// Copyright (c) jnml. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build ignore + +// Factor Finder - searches for Mersenne number factors of one specific special +// form. +package main + +import ( + "flag" + "fmt" + "math/big" + "runtime" + "time" + + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/mathutil" +) + +const ( + pp = 1 + pp2 = 10 +) + +var ( + _1 = big.NewInt(1) + _2 = big.NewInt(2) +) + +func main() { + runtime.GOMAXPROCS(2) + oClass := flag.Uint64("c", 2, `factor "class" number`) + oDuration := flag.Duration("d", time.Second, "duration to spend on one class") + flag.Parse() + class := *oClass + for class&1 != 0 { + class >>= 1 + } + class = mathutil.MaxUint64(class, 2) + + for { + c := time.After(*oDuration) + factor := big.NewInt(0) + factor.SetUint64(class) + exp := big.NewInt(0) + oneClass: + for { + select { + case <-c: + break oneClass + default: + } + + exp.Set(factor) + factor.Lsh(factor, 1) + factor.Add(factor, _1) + if !factor.ProbablyPrime(pp) { + continue + } + + if !exp.ProbablyPrime(pp) { + continue + } + + if mathutil.ModPowBigInt(_2, exp, factor).Cmp(_1) != 0 { + continue + } + + if !factor.ProbablyPrime(pp2) { + continue + } + + if !exp.ProbablyPrime(pp2) { + continue + } + + fmt.Printf("%d: %s | M%s (%d bits)\n", class, factor, exp, factor.BitLen()) + } + + class += 2 + } +} diff --git a/Godeps/_workspace/src/github.com/cznic/mathutil/mathutil.go b/Godeps/_workspace/src/github.com/cznic/mathutil/mathutil.go new file mode 100644 index 0000000..e8f3f56 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/mathutil/mathutil.go @@ -0,0 +1,829 @@ +// Copyright (c) 2014 The mathutil 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 mathutil provides utilities supplementing the standard 'math' and +// 'math/rand' packages. +// +// Compatibility issues +// +// 2013-12-13: The following functions have been REMOVED +// +// func Uint64ToBigInt(n uint64) *big.Int +// func Uint64FromBigInt(n *big.Int) (uint64, bool) +// +// 2013-05-13: The following functions are now DEPRECATED +// +// func Uint64ToBigInt(n uint64) *big.Int +// func Uint64FromBigInt(n *big.Int) (uint64, bool) +// +// These functions will be REMOVED with Go release 1.1+1. +// +// 2013-01-21: The following functions have been REMOVED +// +// func MaxInt() int +// func MinInt() int +// func MaxUint() uint +// func UintPtrBits() int +// +// They are now replaced by untyped constants +// +// MaxInt +// MinInt +// MaxUint +// UintPtrBits +// +// Additionally one more untyped constant was added +// +// IntBits +// +// This change breaks any existing code depending on the above removed +// functions. They should have not been published in the first place, that was +// unfortunate. Instead, defining such architecture and/or implementation +// specific integer limits and bit widths as untyped constants improves +// performance and allows for static dead code elimination if it depends on +// these values. Thanks to minux for pointing it out in the mail list +// (https://groups.google.com/d/msg/golang-nuts/tlPpLW6aJw8/NT3mpToH-a4J). +// +// 2012-12-12: The following functions will be DEPRECATED with Go release +// 1.0.3+1 and REMOVED with Go release 1.0.3+2, b/c of +// http://code.google.com/p/go/source/detail?r=954a79ee3ea8 +// +// func Uint64ToBigInt(n uint64) *big.Int +// func Uint64FromBigInt(n *big.Int) (uint64, bool) +package mathutil + +import ( + "math" + "math/big" +) + +// Architecture and/or implementation specific integer limits and bit widths. +const ( + MaxInt = 1<<(IntBits-1) - 1 + MinInt = -MaxInt - 1 + MaxUint = 1<>32&1 + ^uint(0)>>16&1 + ^uint(0)>>8&1 + 3) + UintPtrBits = 1 << (^uintptr(0)>>32&1 + ^uintptr(0)>>16&1 + ^uintptr(0)>>8&1 + 3) +) + +var ( + _1 = big.NewInt(1) + _2 = big.NewInt(2) +) + +// GCDByte returns the greatest common divisor of a and b. Based on: +// http://en.wikipedia.org/wiki/Euclidean_algorithm#Implementations +func GCDByte(a, b byte) byte { + for b != 0 { + a, b = b, a%b + } + return a +} + +// GCDUint16 returns the greatest common divisor of a and b. +func GCDUint16(a, b uint16) uint16 { + for b != 0 { + a, b = b, a%b + } + return a +} + +// GCD returns the greatest common divisor of a and b. +func GCDUint32(a, b uint32) uint32 { + for b != 0 { + a, b = b, a%b + } + return a +} + +// GCD64 returns the greatest common divisor of a and b. +func GCDUint64(a, b uint64) uint64 { + for b != 0 { + a, b = b, a%b + } + return a +} + +// ISqrt returns floor(sqrt(n)). Typical run time is few hundreds of ns. +func ISqrt(n uint32) (x uint32) { + if n == 0 { + return + } + + if n >= math.MaxUint16*math.MaxUint16 { + return math.MaxUint16 + } + + var px, nx uint32 + for x = n; ; px, x = x, nx { + nx = (x + n/x) / 2 + if nx == x || nx == px { + break + } + } + return +} + +// SqrtUint64 returns floor(sqrt(n)). Typical run time is about 0.5 µs. +func SqrtUint64(n uint64) (x uint64) { + if n == 0 { + return + } + + if n >= math.MaxUint32*math.MaxUint32 { + return math.MaxUint32 + } + + var px, nx uint64 + for x = n; ; px, x = x, nx { + nx = (x + n/x) / 2 + if nx == x || nx == px { + break + } + } + return +} + +// SqrtBig returns floor(sqrt(n)). It panics on n < 0. +func SqrtBig(n *big.Int) (x *big.Int) { + switch n.Sign() { + case -1: + panic(-1) + case 0: + return big.NewInt(0) + } + + var px, nx big.Int + x = big.NewInt(0) + x.SetBit(x, n.BitLen()/2+1, 1) + for { + nx.Rsh(nx.Add(x, nx.Div(n, x)), 1) + if nx.Cmp(x) == 0 || nx.Cmp(&px) == 0 { + break + } + px.Set(x) + x.Set(&nx) + } + return +} + +// Log2Byte returns log base 2 of n. It's the same as index of the highest +// bit set in n. For n == 0 -1 is returned. +func Log2Byte(n byte) int { + return log2[n] +} + +// Log2Uint16 returns log base 2 of n. It's the same as index of the highest +// bit set in n. For n == 0 -1 is returned. +func Log2Uint16(n uint16) int { + if b := n >> 8; b != 0 { + return log2[b] + 8 + } + + return log2[n] +} + +// Log2Uint32 returns log base 2 of n. It's the same as index of the highest +// bit set in n. For n == 0 -1 is returned. +func Log2Uint32(n uint32) int { + if b := n >> 24; b != 0 { + return log2[b] + 24 + } + + if b := n >> 16; b != 0 { + return log2[b] + 16 + } + + if b := n >> 8; b != 0 { + return log2[b] + 8 + } + + return log2[n] +} + +// Log2Uint64 returns log base 2 of n. It's the same as index of the highest +// bit set in n. For n == 0 -1 is returned. +func Log2Uint64(n uint64) int { + if b := n >> 56; b != 0 { + return log2[b] + 56 + } + + if b := n >> 48; b != 0 { + return log2[b] + 48 + } + + if b := n >> 40; b != 0 { + return log2[b] + 40 + } + + if b := n >> 32; b != 0 { + return log2[b] + 32 + } + + if b := n >> 24; b != 0 { + return log2[b] + 24 + } + + if b := n >> 16; b != 0 { + return log2[b] + 16 + } + + if b := n >> 8; b != 0 { + return log2[b] + 8 + } + + return log2[n] +} + +// ModPowByte computes (b^e)%m. It panics for m == 0 || b == e == 0. +// +// See also: http://en.wikipedia.org/wiki/Modular_exponentiation#Right-to-left_binary_method +func ModPowByte(b, e, m byte) byte { + if b == 0 && e == 0 { + panic(0) + } + + if m == 1 { + return 0 + } + + r := uint16(1) + for b, m := uint16(b), uint16(m); e > 0; b, e = b*b%m, e>>1 { + if e&1 == 1 { + r = r * b % m + } + } + return byte(r) +} + +// ModPowByte computes (b^e)%m. It panics for m == 0 || b == e == 0. +func ModPowUint16(b, e, m uint16) uint16 { + if b == 0 && e == 0 { + panic(0) + } + + if m == 1 { + return 0 + } + + r := uint32(1) + for b, m := uint32(b), uint32(m); e > 0; b, e = b*b%m, e>>1 { + if e&1 == 1 { + r = r * b % m + } + } + return uint16(r) +} + +// ModPowUint32 computes (b^e)%m. It panics for m == 0 || b == e == 0. +func ModPowUint32(b, e, m uint32) uint32 { + if b == 0 && e == 0 { + panic(0) + } + + if m == 1 { + return 0 + } + + r := uint64(1) + for b, m := uint64(b), uint64(m); e > 0; b, e = b*b%m, e>>1 { + if e&1 == 1 { + r = r * b % m + } + } + return uint32(r) +} + +// ModPowUint64 computes (b^e)%m. It panics for m == 0 || b == e == 0. +func ModPowUint64(b, e, m uint64) (r uint64) { + if b == 0 && e == 0 { + panic(0) + } + + if m == 1 { + return 0 + } + + return modPowBigInt(big.NewInt(0).SetUint64(b), big.NewInt(0).SetUint64(e), big.NewInt(0).SetUint64(m)).Uint64() +} + +func modPowBigInt(b, e, m *big.Int) (r *big.Int) { + r = big.NewInt(1) + for i, n := 0, e.BitLen(); i < n; i++ { + if e.Bit(i) != 0 { + r.Mod(r.Mul(r, b), m) + } + b.Mod(b.Mul(b, b), m) + } + return +} + +// ModPowBigInt computes (b^e)%m. Returns nil for e < 0. It panics for m == 0 || b == e == 0. +func ModPowBigInt(b, e, m *big.Int) (r *big.Int) { + if b.Sign() == 0 && e.Sign() == 0 { + panic(0) + } + + if m.Cmp(_1) == 0 { + return big.NewInt(0) + } + + if e.Sign() < 0 { + return + } + + return modPowBigInt(big.NewInt(0).Set(b), big.NewInt(0).Set(e), m) +} + +var uint64ToBigIntDelta big.Int + +func init() { + uint64ToBigIntDelta.SetBit(&uint64ToBigIntDelta, 63, 1) +} + +var uintptrBits int + +func init() { + x := uint64(math.MaxUint64) + uintptrBits = BitLenUintptr(uintptr(x)) +} + +// UintptrBits returns the bit width of an uintptr at the executing machine. +func UintptrBits() int { + return uintptrBits +} + +// AddUint128_64 returns the uint128 sum of uint64 a and b. +func AddUint128_64(a, b uint64) (hi uint64, lo uint64) { + lo = a + b + if lo < a { + hi = 1 + } + return +} + +// MulUint128_64 returns the uint128 bit product of uint64 a and b. +func MulUint128_64(a, b uint64) (hi, lo uint64) { + /* + 2^(2 W) ahi bhi + 2^W alo bhi + 2^W ahi blo + alo blo + + FEDCBA98 76543210 FEDCBA98 76543210 + ---- alo*blo ---- + ---- alo*bhi ---- + ---- ahi*blo ---- + ---- ahi*bhi ---- + */ + const w = 32 + const m = 1<>w, b>>w, a&m, b&m + lo = alo * blo + mid1 := alo * bhi + mid2 := ahi * blo + c1, lo := AddUint128_64(lo, mid1<>w+mid2>>w+uint64(c1+c2)) + return +} + +// PowerizeBigInt returns (e, p) such that e is the smallest number for which p +// == b^e is greater or equal n. For n < 0 or b < 2 (0, nil) is returned. +// +// NOTE: Run time for large values of n (above about 2^1e6 ~= 1e300000) can be +// significant and/or unacceptabe. For any smaller values of n the function +// typically performs in sub second time. For "small" values of n (cca bellow +// 2^1e3 ~= 1e300) the same can be easily below 10 µs. +// +// A special (and trivial) case of b == 2 is handled separately and performs +// much faster. +func PowerizeBigInt(b, n *big.Int) (e uint32, p *big.Int) { + switch { + case b.Cmp(_2) < 0 || n.Sign() < 0: + return + case n.Sign() == 0 || n.Cmp(_1) == 0: + return 0, big.NewInt(1) + case b.Cmp(_2) == 0: + p = big.NewInt(0) + e = uint32(n.BitLen() - 1) + p.SetBit(p, int(e), 1) + if p.Cmp(n) < 0 { + p.Mul(p, _2) + e++ + } + return + } + + bw := b.BitLen() + nw := n.BitLen() + p = big.NewInt(1) + var bb, r big.Int + for { + switch p.Cmp(n) { + case -1: + x := uint32((nw - p.BitLen()) / bw) + if x == 0 { + x = 1 + } + e += x + switch x { + case 1: + p.Mul(p, b) + default: + r.Set(_1) + bb.Set(b) + e := x + for { + if e&1 != 0 { + r.Mul(&r, &bb) + } + if e >>= 1; e == 0 { + break + } + + bb.Mul(&bb, &bb) + } + p.Mul(p, &r) + } + case 0, 1: + return + } + } +} + +// PowerizeUint32BigInt returns (e, p) such that e is the smallest number for +// which p == b^e is greater or equal n. For n < 0 or b < 2 (0, nil) is +// returned. +// +// More info: see PowerizeBigInt. +func PowerizeUint32BigInt(b uint32, n *big.Int) (e uint32, p *big.Int) { + switch { + case b < 2 || n.Sign() < 0: + return + case n.Sign() == 0 || n.Cmp(_1) == 0: + return 0, big.NewInt(1) + case b == 2: + p = big.NewInt(0) + e = uint32(n.BitLen() - 1) + p.SetBit(p, int(e), 1) + if p.Cmp(n) < 0 { + p.Mul(p, _2) + e++ + } + return + } + + var bb big.Int + bb.SetInt64(int64(b)) + return PowerizeBigInt(&bb, n) +} + +/* +ProbablyPrimeUint32 returns true if n is prime or n is a pseudoprime to base a. +It implements the Miller-Rabin primality test for one specific value of 'a' and +k == 1. + +Wrt pseudocode shown at +http://en.wikipedia.org/wiki/Miller-Rabin_primality_test#Algorithm_and_running_time + + Input: n > 3, an odd integer to be tested for primality; + Input: k, a parameter that determines the accuracy of the test + Output: composite if n is composite, otherwise probably prime + write n − 1 as 2^s·d with d odd by factoring powers of 2 from n − 1 + LOOP: repeat k times: + pick a random integer a in the range [2, n − 2] + x ← a^d mod n + if x = 1 or x = n − 1 then do next LOOP + for r = 1 .. s − 1 + x ← x^2 mod n + if x = 1 then return composite + if x = n − 1 then do next LOOP + return composite + return probably prime + +... this function behaves like passing 1 for 'k' and additionaly a +fixed/non-random 'a'. Otherwise it's the same algorithm. + +See also: http://mathworld.wolfram.com/Rabin-MillerStrongPseudoprimeTest.html +*/ +func ProbablyPrimeUint32(n, a uint32) bool { + d, s := n-1, 0 + for ; d&1 == 0; d, s = d>>1, s+1 { + } + x := uint64(ModPowUint32(a, d, n)) + if x == 1 || uint32(x) == n-1 { + return true + } + + for ; s > 1; s-- { + if x = x * x % uint64(n); x == 1 { + return false + } + + if uint32(x) == n-1 { + return true + } + } + return false +} + +// ProbablyPrimeUint64_32 returns true if n is prime or n is a pseudoprime to +// base a. It implements the Miller-Rabin primality test for one specific value +// of 'a' and k == 1. See also ProbablyPrimeUint32. +func ProbablyPrimeUint64_32(n uint64, a uint32) bool { + d, s := n-1, 0 + for ; d&1 == 0; d, s = d>>1, s+1 { + } + x := ModPowUint64(uint64(a), d, n) + if x == 1 || x == n-1 { + return true + } + + bx, bn := big.NewInt(0).SetUint64(x), big.NewInt(0).SetUint64(n) + for ; s > 1; s-- { + if x = bx.Mod(bx.Mul(bx, bx), bn).Uint64(); x == 1 { + return false + } + + if x == n-1 { + return true + } + } + return false +} + +// ProbablyPrimeBigInt_32 returns true if n is prime or n is a pseudoprime to +// base a. It implements the Miller-Rabin primality test for one specific value +// of 'a' and k == 1. See also ProbablyPrimeUint32. +func ProbablyPrimeBigInt_32(n *big.Int, a uint32) bool { + var d big.Int + d.Set(n) + d.Sub(&d, _1) // d <- n-1 + s := 0 + for ; d.Bit(s) == 0; s++ { + } + nMinus1 := big.NewInt(0).Set(&d) + d.Rsh(&d, uint(s)) + + x := ModPowBigInt(big.NewInt(int64(a)), &d, n) + if x.Cmp(_1) == 0 || x.Cmp(nMinus1) == 0 { + return true + } + + for ; s > 1; s-- { + if x = x.Mod(x.Mul(x, x), n); x.Cmp(_1) == 0 { + return false + } + + if x.Cmp(nMinus1) == 0 { + return true + } + } + return false +} + +// ProbablyPrimeBigInt returns true if n is prime or n is a pseudoprime to base +// a. It implements the Miller-Rabin primality test for one specific value of +// 'a' and k == 1. See also ProbablyPrimeUint32. +func ProbablyPrimeBigInt(n, a *big.Int) bool { + var d big.Int + d.Set(n) + d.Sub(&d, _1) // d <- n-1 + s := 0 + for ; d.Bit(s) == 0; s++ { + } + nMinus1 := big.NewInt(0).Set(&d) + d.Rsh(&d, uint(s)) + + x := ModPowBigInt(a, &d, n) + if x.Cmp(_1) == 0 || x.Cmp(nMinus1) == 0 { + return true + } + + for ; s > 1; s-- { + if x = x.Mod(x.Mul(x, x), n); x.Cmp(_1) == 0 { + return false + } + + if x.Cmp(nMinus1) == 0 { + return true + } + } + return false +} + +// Max returns the larger of a and b. +func Max(a, b int) int { + if a > b { + return a + } + + return b +} + +// Min returns the smaller of a and b. +func Min(a, b int) int { + if a < b { + return a + } + + return b +} + +// UMax returns the larger of a and b. +func UMax(a, b uint) uint { + if a > b { + return a + } + + return b +} + +// UMin returns the smaller of a and b. +func UMin(a, b uint) uint { + if a < b { + return a + } + + return b +} + +// MaxByte returns the larger of a and b. +func MaxByte(a, b byte) byte { + if a > b { + return a + } + + return b +} + +// MinByte returns the smaller of a and b. +func MinByte(a, b byte) byte { + if a < b { + return a + } + + return b +} + +// MaxInt8 returns the larger of a and b. +func MaxInt8(a, b int8) int8 { + if a > b { + return a + } + + return b +} + +// MinInt8 returns the smaller of a and b. +func MinInt8(a, b int8) int8 { + if a < b { + return a + } + + return b +} + +// MaxUint16 returns the larger of a and b. +func MaxUint16(a, b uint16) uint16 { + if a > b { + return a + } + + return b +} + +// MinUint16 returns the smaller of a and b. +func MinUint16(a, b uint16) uint16 { + if a < b { + return a + } + + return b +} + +// MaxInt16 returns the larger of a and b. +func MaxInt16(a, b int16) int16 { + if a > b { + return a + } + + return b +} + +// MinInt16 returns the smaller of a and b. +func MinInt16(a, b int16) int16 { + if a < b { + return a + } + + return b +} + +// MaxUint32 returns the larger of a and b. +func MaxUint32(a, b uint32) uint32 { + if a > b { + return a + } + + return b +} + +// MinUint32 returns the smaller of a and b. +func MinUint32(a, b uint32) uint32 { + if a < b { + return a + } + + return b +} + +// MaxInt32 returns the larger of a and b. +func MaxInt32(a, b int32) int32 { + if a > b { + return a + } + + return b +} + +// MinInt32 returns the smaller of a and b. +func MinInt32(a, b int32) int32 { + if a < b { + return a + } + + return b +} + +// MaxUint64 returns the larger of a and b. +func MaxUint64(a, b uint64) uint64 { + if a > b { + return a + } + + return b +} + +// MinUint64 returns the smaller of a and b. +func MinUint64(a, b uint64) uint64 { + if a < b { + return a + } + + return b +} + +// MaxInt64 returns the larger of a and b. +func MaxInt64(a, b int64) int64 { + if a > b { + return a + } + + return b +} + +// MinInt64 returns the smaller of a and b. +func MinInt64(a, b int64) int64 { + if a < b { + return a + } + + return b +} + +// ToBase produces n in base b. For example +// +// ToBase(2047, 22) -> [1, 5, 4] +// +// 1 * 22^0 1 +// 5 * 22^1 110 +// 4 * 22^2 1936 +// ---- +// 2047 +// +// ToBase panics for bases < 2. +func ToBase(n *big.Int, b int) []int { + var nn big.Int + nn.Set(n) + if b < 2 { + panic("invalid base") + } + + k := 1 + switch nn.Sign() { + case -1: + nn.Neg(&nn) + k = -1 + case 0: + return []int{0} + } + + bb := big.NewInt(int64(b)) + var r []int + rem := big.NewInt(0) + for nn.Sign() != 0 { + nn.QuoRem(&nn, bb, rem) + r = append(r, k*int(rem.Int64())) + } + return r +} diff --git a/Godeps/_workspace/src/github.com/cznic/mathutil/mersenne/AUTHORS b/Godeps/_workspace/src/github.com/cznic/mathutil/mersenne/AUTHORS new file mode 100644 index 0000000..0078f5f --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/mathutil/mersenne/AUTHORS @@ -0,0 +1,11 @@ +# This file lists authors for copyright purposes. This file is distinct from +# the CONTRIBUTORS files. See the latter for an explanation. +# +# Names should be added to this file as: +# Name or Organization +# +# The email address is not required for organizations. +# +# Please keep the list sorted. + +Jan Mercl <0xjnml@gmail.com> diff --git a/Godeps/_workspace/src/github.com/cznic/mathutil/mersenne/CONTRIBUTORS b/Godeps/_workspace/src/github.com/cznic/mathutil/mersenne/CONTRIBUTORS new file mode 100644 index 0000000..5e86f06 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/mathutil/mersenne/CONTRIBUTORS @@ -0,0 +1,9 @@ +# This file lists people who contributed code to this repository. The AUTHORS +# file lists the copyright holders; this file lists people. +# +# Names should be added to this file like so: +# Name +# +# Please keep the list sorted. + +Jan Mercl <0xjnml@gmail.com> diff --git a/Godeps/_workspace/src/github.com/cznic/mathutil/mersenne/LICENSE b/Godeps/_workspace/src/github.com/cznic/mathutil/mersenne/LICENSE new file mode 100644 index 0000000..4fa2a1f --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/mathutil/mersenne/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2014 The mersenne Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the names of the authors nor the names of the +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Godeps/_workspace/src/github.com/cznic/mathutil/mersenne/Makefile b/Godeps/_workspace/src/github.com/cznic/mathutil/mersenne/Makefile new file mode 100644 index 0000000..a12fc57 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/mathutil/mersenne/Makefile @@ -0,0 +1,24 @@ +# Copyright (c) 2014 The mersenne Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +all: editor + go build + go vet + golint . + go install + make todo + +editor: + go fmt + go test -i + go test + +todo: + @grep -n ^[[:space:]]*_[[:space:]]*=[[:space:]][[:alnum:]] *.go || true + @grep -n TODO *.go || true + @grep -n FIXME *.go || true + @grep -n BUG *.go || true + +clean: + rm -f *~ diff --git a/Godeps/_workspace/src/github.com/cznic/mathutil/mersenne/README b/Godeps/_workspace/src/github.com/cznic/mathutil/mersenne/README new file mode 100644 index 0000000..afa401c --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/mathutil/mersenne/README @@ -0,0 +1,2 @@ +Install: $ go get github.com/cznic/mathutil/mersenne +Godocs: http://gopkgdoc.appspot.com/pkg/github.com/cznic/mathutil/mersenne diff --git a/Godeps/_workspace/src/github.com/cznic/mathutil/mersenne/all_test.go b/Godeps/_workspace/src/github.com/cznic/mathutil/mersenne/all_test.go new file mode 100644 index 0000000..832d8dc --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/mathutil/mersenne/all_test.go @@ -0,0 +1,943 @@ +// Copyright (c) 2014 The mersenne 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 mersenne + +import ( + "math" + "math/big" + "math/rand" + "runtime" + "sync" + "testing" + + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/mathutil" +) + +func r32() *mathutil.FC32 { + r, err := mathutil.NewFC32(math.MinInt32, math.MaxInt32, true) + if err != nil { + panic(err) + } + + return r +} + +var ( + r64lo = big.NewInt(math.MinInt64) + r64hi = big.NewInt(math.MaxInt64) +) + +func r64() *mathutil.FCBig { + r, err := mathutil.NewFCBig(r64lo, r64hi, true) + if err != nil { + panic(err) + } + + return r +} + +func TestNew(t *testing.T) { + const N = 1e4 + data := []struct{ n, m uint32 }{ + {0, 0}, + {1, 1}, + {2, 3}, + {3, 7}, + {4, 15}, + {5, 31}, + {6, 63}, + {7, 127}, + {8, 255}, + {9, 511}, + {10, 1023}, + {11, 2047}, + {12, 4095}, + {13, 8191}, + {14, 16383}, + {15, 32767}, + {16, 65535}, + {17, 131071}, + } + + e := big.NewInt(0) + for _, v := range data { + g := New(v.n) + e.SetInt64(int64(v.m)) + if g.Cmp(e) != 0 { + t.Errorf("%d: got %s, exp %s", v.n, g, e) + } + } + + r := r32() + for i := 0; i < N; i++ { + exp := uint32(r.Next()) % 1e6 + g := New(exp) + b0 := g.BitLen() + g.Add(g, _1) + b1 := g.BitLen() + if b1-b0 != 1 { + t.Fatal(i, exp, b1, b0) + } + } +} + +func benchmarkNew(b *testing.B, max uint32) { + const N = 1 << 16 + b.StopTimer() + a := make([]uint32, N) + r := r32() + for i := range a { + a[i] = uint32(r.Next()) % max + } + runtime.GC() + b.StartTimer() + for i := 0; i < b.N; i++ { + New(a[i&(N-1)]) + } +} + +func BenchmarkNew_1e1(b *testing.B) { + benchmarkNew(b, 1e1) +} + +func BenchmarkNew_1e2(b *testing.B) { + benchmarkNew(b, 1e2) +} + +func BenchmarkNew_1e3(b *testing.B) { + benchmarkNew(b, 1e3) +} + +func BenchmarkNew_1e4(b *testing.B) { + benchmarkNew(b, 1e4) +} + +func BenchmarkNew_1e5(b *testing.B) { + benchmarkNew(b, 1e5) +} + +func BenchmarkNew_1e6(b *testing.B) { + benchmarkNew(b, 1e6) +} + +func BenchmarkNew_1e7(b *testing.B) { + benchmarkNew(b, 1e7) +} + +func BenchmarkNew_1e8(b *testing.B) { + benchmarkNew(b, 1e8) +} + +func TestHasFactorUint32(t *testing.T) { + data := []struct { + d, e uint32 + r bool + }{ + {0, 42, false}, + {1, 24, true}, + {2, 22, false}, + {3, 2, true}, + {3, 3, false}, + {3, 4, true}, + {3, 5, false}, + {3, 6, true}, + {5, 4, true}, + {5, 5, false}, + {5, 6, false}, + {5, 7, false}, + {5, 8, true}, + {5, 9, false}, + {5, 10, false}, + {5, 11, false}, + {5, 12, true}, + {7, 3, true}, + {7, 6, true}, + {7, 9, true}, + {9, 6, true}, + {9, 12, true}, + {9, 18, true}, + {11, 10, true}, + {23, 11, true}, + {89, 11, true}, + {47, 23, true}, + {193707721, 67, true}, + {13007, 929, true}, + {264248689, 500471, true}, + {112027889, 1000249, true}, + {252079759, 2000633, true}, + {222054983, 3000743, true}, + {1920355681, 4000741, true}, + {330036367, 5000551, true}, + {1020081431, 6000479, true}, + {840074281, 7000619, true}, + {624031279, 8000401, true}, + {378031207, 9000743, true}, + {380036519, 10000961, true}, + {40001447, 20000723, true}, + } + + for _, v := range data { + if g, e := HasFactorUint32(v.d, v.e), v.r; g != e { + t.Errorf("d %d e %d: got %t, exp %t", v.d, v.e, g, e) + } + } +} + +func TestHasFactorUint64(t *testing.T) { + data := []struct { + d uint64 + e uint32 + r bool + }{ + {0, 42, false}, + {1, 24, true}, + {2, 22, false}, + {3, 2, true}, + {3, 3, false}, + {3, 4, true}, + {3, 5, false}, + {3, 6, true}, + {5, 4, true}, + {5, 5, false}, + {5, 6, false}, + {5, 7, false}, + {5, 8, true}, + {5, 9, false}, + {5, 10, false}, + {5, 11, false}, + {5, 12, true}, + {7, 3, true}, + {7, 6, true}, + {7, 9, true}, + {9, 6, true}, + {9, 12, true}, + {9, 18, true}, + {11, 10, true}, + {23, 11, true}, + {89, 11, true}, + {47, 23, true}, + {193707721, 67, true}, + {13007, 929, true}, + {264248689, 500471, true}, + {112027889, 1000249, true}, + {252079759, 2000633, true}, + {222054983, 3000743, true}, + {1920355681, 4000741, true}, + {330036367, 5000551, true}, + {1020081431, 6000479, true}, + {840074281, 7000619, true}, + {624031279, 8000401, true}, + {378031207, 9000743, true}, + {380036519, 10000961, true}, + {40001447, 20000723, true}, + {1872347344039, 1000099, true}, + } + + for _, v := range data { + if g, e := HasFactorUint64(v.d, v.e), v.r; g != e { + t.Errorf("d %d e %d: got %t, exp %t", v.d, v.e, g, e) + } + } +} + +func TestHasFactorBigInt(t *testing.T) { + data := []struct { + d interface{} + e uint32 + r bool + }{ + {0, 42, false}, + {1, 24, true}, + {2, 22, false}, + {3, 2, true}, + {3, 3, false}, + {3, 4, true}, + {3, 5, false}, + {3, 6, true}, + {5, 4, true}, + {5, 5, false}, + {5, 6, false}, + {5, 7, false}, + {5, 8, true}, + {5, 9, false}, + {5, 10, false}, + {5, 11, false}, + {5, 12, true}, + {7, 3, true}, + {7, 6, true}, + {7, 9, true}, + {9, 6, true}, + {9, 12, true}, + {9, 18, true}, + {11, 10, true}, + {23, 11, true}, + {89, 11, true}, + {47, 23, true}, + {193707721, 67, true}, + {13007, 929, true}, + {264248689, 500471, true}, + {112027889, 1000249, true}, + {252079759, 2000633, true}, + {222054983, 3000743, true}, + {1920355681, 4000741, true}, + {330036367, 5000551, true}, + {1020081431, 6000479, true}, + {840074281, 7000619, true}, + {624031279, 8000401, true}, + {378031207, 9000743, true}, + {380036519, 10000961, true}, + {40001447, 20000723, true}, + {"1872347344039", 1000099, true}, + {"11502865265922183403581252152383", 100279, true}, + {"533975545077050000610542659519277030089249998649", 7293457, true}, + } + + var d big.Int + for _, v := range data { + bigInt(&d, v.d) + if g, e := HasFactorBigInt(&d, v.e), v.r; g != e { + t.Errorf("d %s e %d: got %t, exp %t", &d, v.e, g, e) + } + + if g, e := HasFactorBigInt2(&d, big.NewInt(int64(v.e))), v.r; g != e { + t.Errorf("d %s e %d: got %t, exp %t", &d, v.e, g, e) + } + } +} + +var once309 sync.Once + +func BenchmarkHasFactorUint32Rnd(b *testing.B) { + const N = 1 << 16 + b.StopTimer() + type t struct{ d, e uint32 } + a := make([]t, N) + r := r32() + for i := range a { + a[i] = t{ + uint32(r.Next()) | 1, + uint32(r.Next()), + } + } + once309.Do(func() { b.Log("Random 32 bit factor, random 32 bit exponent\n") }) + runtime.GC() + b.StartTimer() + for i := 0; i < b.N; i++ { + v := a[i&(N-1)] + HasFactorUint32(v.d, v.e) + } +} + +var once332 sync.Once + +func BenchmarkHasFactorUint64Rnd(b *testing.B) { + const N = 1 << 16 + b.StopTimer() + type t struct { + d uint64 + e uint32 + } + a := make([]t, N) + r := r64() + for i := range a { + a[i] = t{ + uint64(r.Next().Int64()) | 1, + uint32(r.Next().Int64()), + } + } + once332.Do(func() { b.Log("Random 64 bit factor, random 32 bit exponent\n") }) + runtime.GC() + b.StartTimer() + for i := 0; i < b.N; i++ { + v := a[i&(N-1)] + HasFactorUint64(v.d, v.e) + } +} + +var once358 sync.Once + +func BenchmarkHasFactorBigIntRnd_128b(b *testing.B) { + const N = 1 << 16 + b.StopTimer() + type t struct { + d *big.Int + e uint32 + } + a := make([]t, N) + r, err := mathutil.NewFCBig(_1, New(128), true) + if err != nil { + b.Fatal(err) + } + r2 := r32() + for i := range a { + dd := r.Next() + a[i] = t{ + dd.SetBit(dd, 0, 1), + uint32(r2.Next()), + } + } + once358.Do(func() { b.Log("Random 128 bit factor, random 32 bit exponent\n") }) + runtime.GC() + b.StartTimer() + for i := 0; i < b.N; i++ { + v := a[i&(N-1)] + HasFactorBigInt(v.d, v.e) + } +} + +var ( + f104b, _ = big.NewInt(0).SetString( // 104 bit factor of M100279 + "11502865265922183403581252152383", + 10, + ) + f137b, _ = big.NewInt(0).SetString( // 137 bit factor of M7293457 + "533975545077050000610542659519277030089249998649", + 10, + ) +) + +var once396 sync.Once + +func BenchmarkHasFactorBigInt_104b(b *testing.B) { + b.StopTimer() + once396.Do(func() { b.Log("Verify a 104 bit factor of M100279 (16.6 bit exponent)\n") }) + runtime.GC() + var r bool + b.StartTimer() + for i := 0; i < b.N; i++ { + r = HasFactorBigInt(f104b, 100279) + } + if !r { + b.Fatal(r) + } +} + +var once412 sync.Once + +func BenchmarkHasFactorBigIntMod104b(b *testing.B) { + b.StopTimer() + once412.Do(func() { b.Log("Verify a 104 bit factor of M100279 (16.6 bit exponent) using big.Int.Mod\n") }) + runtime.GC() + m := New(100279) + var x big.Int + b.StartTimer() + for i := 0; i < b.N; i++ { + x.Mod(m, f104b) + } + if x.Cmp(_0) != 0 { + b.Fatal(x) + } +} + +var once429 sync.Once + +func BenchmarkHasFactorBigInt_137b(b *testing.B) { + b.StopTimer() + once429.Do(func() { b.Log("Verify a 137 bit factor of M7293457 (22.8 bit exponent)\n") }) + runtime.GC() + var r bool + b.StartTimer() + for i := 0; i < b.N; i++ { + r = HasFactorBigInt(f137b, 7293457) + } + if !r { + b.Fatal(r) + } +} + +var once445 sync.Once + +func BenchmarkHasFactorBigIntMod137b(b *testing.B) { + b.StopTimer() + once445.Do(func() { b.Log("Verify a 137 bit factor of M7293457 (22.8 bit exponent) using big.Int.Mod\n") }) + runtime.GC() + m := New(7293457) + var x big.Int + b.StartTimer() + for i := 0; i < b.N; i++ { + x.Mod(m, f137b) + } + if x.Cmp(_0) != 0 { + b.Fatal(x) + } +} + +func bigInt(b *big.Int, v interface{}) { + switch v := v.(type) { + case int: + b.SetInt64(int64(v)) + case string: + if _, ok := b.SetString(v, 10); !ok { + panic("bigInt: bad decimal string") + } + default: + panic("bigInt: bad v.(type)") + } +} + +func TestFromFactorBigInt(t *testing.T) { + data := []struct { + d interface{} + n uint32 + }{ + {0, 0}, + {1, 1}, + {2, 0}, + {3, 2}, + {4, 0}, + {5, 4}, + {7, 3}, + {9, 6}, + {11, 10}, + {23, 11}, + {89, 11}, + {"7432339208719", 101}, + {"198582684439", 1009}, + {"20649907789079", 1009}, + {"21624641697047", 1009}, + {"30850253615723594284324529", 1009}, + {"1134327302421596486779379019599", 1009}, + {35311753, 10009}, + {"104272300687", 10009}, + {"10409374085465521", 10009}, + {"890928517778601397463", 10009}, + {6400193, 100003}, + } + + f := func(d *big.Int, max, e uint32) { + if g := FromFactorBigInt(d, max); g != e { + t.Fatalf("%s %d %d %d", d, max, g, e) + } + } + + var d big.Int + for _, v := range data { + bigInt(&d, v.d) + switch { + case v.n > 0: + f(&d, v.n-1, 0) + default: // v.n == 0 + f(&d, 100, 0) + } + f(&d, v.n, v.n) + } +} + +var f20b = big.NewInt(200000447) // 20 bit factor of M100000223 + +func benchmarkFromFactorBigInt(b *testing.B, f *big.Int, max uint32) { + var n uint32 + for i := 0; i < b.N; i++ { + n = FromFactorBigInt(f, max) + } + if n != 0 { + b.Fatal(n) + } +} + +func BenchmarkFromFactorBigInt20b_1e1(b *testing.B) { + benchmarkFromFactorBigInt(b, f20b, 1e1) +} + +func BenchmarkFromFactorBigInt20b_1e2(b *testing.B) { + benchmarkFromFactorBigInt(b, f20b, 1e2) +} + +func BenchmarkFromFactorBigInt20b_1e3(b *testing.B) { + benchmarkFromFactorBigInt(b, f20b, 1e3) +} + +func BenchmarkFromFactorBigInt20b_1e4(b *testing.B) { + benchmarkFromFactorBigInt(b, f20b, 1e4) +} + +func BenchmarkFromFactorBigInt20b_1e5(b *testing.B) { + benchmarkFromFactorBigInt(b, f20b, 1e5) +} + +func BenchmarkFromFactorBigInt20b_1e6(b *testing.B) { + benchmarkFromFactorBigInt(b, f20b, 1e6) +} + +func BenchmarkFromFactorBigInt137b_1e1(b *testing.B) { + benchmarkFromFactorBigInt(b, f137b, 1e1) +} + +func BenchmarkFromFactorBigInt137b_1e2(b *testing.B) { + benchmarkFromFactorBigInt(b, f137b, 1e2) +} + +func BenchmarkFromFactorBigInt137b_1e3(b *testing.B) { + benchmarkFromFactorBigInt(b, f137b, 1e3) +} + +func BenchmarkFromFactorBigInt137b_1e4(b *testing.B) { + benchmarkFromFactorBigInt(b, f137b, 1e4) +} + +func BenchmarkFromFactorBigInt137b_1e5(b *testing.B) { + benchmarkFromFactorBigInt(b, f137b, 1e5) +} + +func BenchmarkFromFactorBigInt137b_1e6(b *testing.B) { + benchmarkFromFactorBigInt(b, f137b, 1e6) +} +func TestMod(t *testing.T) { + const N = 1e4 + data := []struct { + mod, n int64 + exp uint32 + }{ + {0, 0x00, 3}, + {1, 0x01, 3}, + {3, 0x03, 3}, + {0, 0x07, 3}, + {1, 0x0f, 3}, + {3, 0x1f, 3}, + {0, 0x3f, 3}, + {1, 0x7f, 3}, + {3, 0xff, 3}, + {0, 0x1ff, 3}, + } + + var mod, n big.Int + for _, v := range data { + n.SetInt64(v.n) + p := Mod(&mod, &n, v.exp) + if p != &mod { + t.Fatal(p) + } + + if g, e := mod.Int64(), v.mod; g != e { + t.Fatal(v.n, v.exp, g, e) + } + } + + f := func(in int64, exp uint32) { + n.SetInt64(in) + mod.Mod(&n, New(exp)) + e := mod.Int64() + Mod(&mod, &n, exp) + g := mod.Int64() + if g != e { + t.Fatal(in, exp, g, e) + } + } + + r32, _ := mathutil.NewFC32(1, 1e6, true) + r64, _ := mathutil.NewFCBig(_0, big.NewInt(math.MaxInt64), true) + for i := 0; i < N; i++ { + f(r64.Next().Int64(), uint32(r32.Next())) + } +} + +func benchmarkMod(b *testing.B, w, exp uint32) { + b.StopTimer() + var n, mod big.Int + n.Rand(rand.New(rand.NewSource(1)), New(w)) + n.SetBit(&n, int(w), 1) + runtime.GC() + b.StartTimer() + for i := 0; i < b.N; i++ { + Mod(&mod, &n, exp) + } +} + +func benchmarkModBig(b *testing.B, w, exp uint32) { + b.StopTimer() + var n, mod big.Int + n.Rand(rand.New(rand.NewSource(1)), New(w)) + n.SetBit(&n, int(w), 1) + runtime.GC() + runtime.GC() + b.StartTimer() + for i := 0; i < b.N; i++ { + mod.Mod(&n, New(exp)) + } +} + +func BenchmarkMod_1e2(b *testing.B) { + benchmarkMod(b, 1e2+2, 1e2) +} + +func BenchmarkModBig_1e2(b *testing.B) { + benchmarkModBig(b, 1e2+2, 1e2) +} + +func BenchmarkMod_1e3(b *testing.B) { + benchmarkMod(b, 1e3+2, 1e3) +} + +func BenchmarkModBig_1e3(b *testing.B) { + benchmarkModBig(b, 1e3+2, 1e3) +} + +func BenchmarkMod_1e4(b *testing.B) { + benchmarkMod(b, 1e4+2, 1e4) +} + +func BenchmarkModBig_1e4(b *testing.B) { + benchmarkModBig(b, 1e4+2, 1e4) +} + +func BenchmarkMod_1e5(b *testing.B) { + benchmarkMod(b, 1e5+2, 1e5) +} + +func BenchmarkModBig_1e5(b *testing.B) { + benchmarkModBig(b, 1e5+2, 1e5) +} + +func BenchmarkMod_1e6(b *testing.B) { + benchmarkMod(b, 1e6+2, 1e6) +} + +func BenchmarkModBig_1e6(b *testing.B) { + benchmarkModBig(b, 1e6+2, 1e6) +} + +func BenchmarkMod_1e7(b *testing.B) { + benchmarkMod(b, 1e7+2, 1e7) +} + +func BenchmarkModBig_1e7(b *testing.B) { + benchmarkModBig(b, 1e7+2, 1e7) +} + +func BenchmarkMod_1e8(b *testing.B) { + benchmarkMod(b, 1e8+2, 1e8) +} + +func BenchmarkModBig_1e8(b *testing.B) { + benchmarkModBig(b, 1e8+2, 1e8) +} + +func BenchmarkMod_5e8(b *testing.B) { + benchmarkMod(b, 5e8+2, 5e8) +} + +func BenchmarkModBig_5e8(b *testing.B) { + benchmarkModBig(b, 5e8+2, 5e8) +} + +func TestModPow(t *testing.T) { + const N = 2e2 + data := []struct{ b, e, m, r uint32 }{ + {0, 1, 1, 0}, + {0, 2, 1, 0}, + {0, 3, 1, 0}, + + {1, 0, 1, 0}, + {1, 1, 1, 0}, + {1, 2, 1, 0}, + {1, 3, 1, 0}, + + {2, 0, 1, 0}, + {2, 1, 1, 0}, + {2, 2, 1, 0}, + {2, 3, 1, 0}, + + {2, 3, 4, 8}, + {2, 3, 5, 4}, + {2, 4, 3, 1}, + {3, 3, 3, 3}, + {3, 4, 5, 30}, + } + + f := func(b, e, m uint32, expect *big.Int) { + got := ModPow(b, e, m) + if got.Cmp(expect) != 0 { + t.Fatal(b, e, m, got, expect) + } + } + + var r big.Int + for _, v := range data { + r.SetInt64(int64(v.r)) + f(v.b, v.e, v.m, &r) + } + + rg, _ := mathutil.NewFC32(2, 1<<10, true) + var bb big.Int + for i := 0; i < N; i++ { + b, e, m := uint32(rg.Next()), uint32(rg.Next()), uint32(rg.Next()) + bb.SetInt64(int64(b)) + f(b, e, m, mathutil.ModPowBigInt(&bb, New(e), New(m))) + } +} + +func benchmarkModPow2(b *testing.B, e, m uint32) { + b.StopTimer() + runtime.GC() + b.StartTimer() + for i := 0; i < b.N; i++ { + ModPow2(e, m) + } +} + +func benchmarkModPow(b *testing.B, base, e, m uint32) { + b.StopTimer() + runtime.GC() + b.StartTimer() + for i := 0; i < b.N; i++ { + ModPow(base, e, m) + } +} + +func benchmarkModPowBig(b *testing.B, base, e, m uint32) { + b.StopTimer() + bb := big.NewInt(int64(base)) + ee := New(e) + mm := New(m) + runtime.GC() + b.StartTimer() + for i := 0; i < b.N; i++ { + mathutil.ModPowBigInt(bb, ee, mm) + } +} + +func BenchmarkModPow2_1e2(b *testing.B) { + benchmarkModPow2(b, 1e2, 1e2+1) +} + +func BenchmarkModPow_2_1e2(b *testing.B) { + benchmarkModPow(b, 2, 1e2, 1e2+1) +} + +func BenchmarkModPowB_2_1e2(b *testing.B) { + benchmarkModPowBig(b, 2, 1e2, 1e2+1) +} + +func BenchmarkModPow_3_1e2(b *testing.B) { + benchmarkModPow(b, 3, 1e2, 1e2+1) +} + +func BenchmarkModPowB_3_1e2(b *testing.B) { + benchmarkModPowBig(b, 3, 1e2, 1e2+1) +} + +// ---- + +func BenchmarkModPow2_1e3(b *testing.B) { + benchmarkModPow2(b, 1e3, 1e3+1) +} + +func BenchmarkModPow_2_1e3(b *testing.B) { + benchmarkModPow(b, 2, 1e3, 1e3+1) +} + +func BenchmarkModPowB_2_1e3(b *testing.B) { + benchmarkModPowBig(b, 2, 1e3, 1e3+1) +} + +func BenchmarkModPow_3_1e3(b *testing.B) { + benchmarkModPow(b, 3, 1e3, 1e3+1) +} + +func BenchmarkModPowB_3_1e3(b *testing.B) { + benchmarkModPowBig(b, 3, 1e3, 1e3+1) +} + +// ---- + +func BenchmarkModPow2_1e4(b *testing.B) { + benchmarkModPow2(b, 1e4, 1e4+1) +} + +func BenchmarkModPow_2_1e4(b *testing.B) { + benchmarkModPow(b, 2, 1e4, 1e4+1) +} + +func BenchmarkModPowB_2_1e4(b *testing.B) { + benchmarkModPowBig(b, 2, 1e4, 1e4+1) +} + +func BenchmarkModPow_3_1e4(b *testing.B) { + benchmarkModPow(b, 3, 1e4, 1e4+1) +} + +func BenchmarkModPowB_3_1e4(b *testing.B) { + benchmarkModPowBig(b, 3, 1e4, 1e4+1) +} + +// ---- + +func BenchmarkModPow2_1e5(b *testing.B) { + benchmarkModPow2(b, 1e5, 1e5+1) +} + +func BenchmarkModPow2_1e6(b *testing.B) { + benchmarkModPow2(b, 1e6, 1e6+1) +} + +func BenchmarkModPow2_1e7(b *testing.B) { + benchmarkModPow2(b, 1e7, 1e7+1) +} + +func BenchmarkModPow2_1e8(b *testing.B) { + benchmarkModPow2(b, 1e8, 1e8+1) +} + +func BenchmarkModPow2_1e9(b *testing.B) { + benchmarkModPow2(b, 1e9, 1e9+1) +} + +func TestModPow2(t *testing.T) { + const N = 1e3 + data := []struct{ e, m uint32 }{ + // e == 0 -> x == 0 + {0, 2}, + {0, 3}, + {0, 4}, + + {1, 2}, + {1, 3}, + {1, 4}, + {1, 5}, + + {2, 2}, + {2, 3}, + {2, 4}, + {2, 5}, + + {3, 2}, + {3, 3}, + {3, 4}, + {3, 5}, + {3, 6}, + {3, 7}, + {3, 8}, + {3, 9}, + + {4, 2}, + {4, 3}, + {4, 4}, + {4, 5}, + {4, 6}, + {4, 7}, + {4, 8}, + {4, 9}, + } + + var got big.Int + f := func(e, m uint32) { + x := ModPow2(e, m) + exp := ModPow(2, e, m) + got.SetInt64(0) + got.SetBit(&got, int(x), 1) + if got.Cmp(exp) != 0 { + t.Fatalf("\ne %d, m %d\ng: %s\ne: %s", e, m, &got, exp) + } + } + + for _, v := range data { + f(v.e, v.m) + } + + rg, _ := mathutil.NewFC32(2, 1<<10, true) + for i := 0; i < N; i++ { + f(uint32(rg.Next()), uint32(rg.Next())) + } +} diff --git a/Godeps/_workspace/src/github.com/cznic/mathutil/mersenne/mersenne.go b/Godeps/_workspace/src/github.com/cznic/mathutil/mersenne/mersenne.go new file mode 100644 index 0000000..6020296 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/mathutil/mersenne/mersenne.go @@ -0,0 +1,296 @@ +// Copyright (c) 2014 The mersenne 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 mersenne collects utilities related to Mersenne numbers[1] and/or some +of their properties. + +Exponent + +In this documentation the term 'exponent' refers to 'n' of a Mersenne number Mn +equal to 2^n-1. This package supports only uint32 sized exponents. New() +currently supports exponents only up to math.MaxInt32 (31 bits, up to 256 MB +required to represent such Mn in memory as a big.Int). + +Links + +Referenced from above: + [1] http://en.wikipedia.org/wiki/Mersenne_number +*/ +package mersenne + +import ( + "math" + "math/big" + + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/mathutil" + "github.com/remyoudompheng/bigfft" +) + +var ( + _0 = big.NewInt(0) + _1 = big.NewInt(1) + _2 = big.NewInt(2) +) + +// Knowns list the exponent of currently (March 2012) known Mersenne primes +// exponents in order. See also: http://oeis.org/A000043 for a partial list. +var Knowns = []uint32{ + 2, // #1 + 3, // #2 + 5, // #3 + 7, // #4 + 13, // #5 + 17, // #6 + 19, // #7 + 31, // #8 + 61, // #9 + 89, // #10 + + 107, // #11 + 127, // #12 + 521, // #13 + 607, // #14 + 1279, // #15 + 2203, // #16 + 2281, // #17 + 3217, // #18 + 4253, // #19 + 4423, // #20 + + 9689, // #21 + 9941, // #22 + 11213, // #23 + 19937, // #24 + 21701, // #25 + 23209, // #26 + 44497, // #27 + 86243, // #28 + 110503, // #29 + 132049, // #30 + + 216091, // #31 + 756839, // #32 + 859433, // #33 + 1257787, // #34 + 1398269, // #35 + 2976221, // #36 + 3021377, // #37 + 6972593, // #38 + 13466917, // #39 + 20996011, // #40 + + 24036583, // #41 + 25964951, // #42 + 30402457, // #43 + 32582657, // #44 + 37156667, // #45 + 42643801, // #46 + 43112609, // #47 + 57885161, // #48 +} + +// Known maps the exponent of known Mersenne primes its ordinal number/rank. +// Ranks > 41 are currently provisional. +var Known map[uint32]int + +func init() { + Known = map[uint32]int{} + for i, v := range Knowns { + Known[v] = i + 1 + } +} + +// New returns Mn == 2^n-1 for n <= math.MaxInt32 or nil otherwise. +func New(n uint32) (m *big.Int) { + if n > math.MaxInt32 { + return + } + + m = big.NewInt(0) + return m.Sub(m.SetBit(m, int(n), 1), _1) +} + +// HasFactorUint32 returns true if d | Mn. Typical run time for a 32 bit factor +// and a 32 bit exponent is < 1 µs. +func HasFactorUint32(d, n uint32) bool { + return d == 1 || d&1 != 0 && mathutil.ModPowUint32(2, n, d) == 1 +} + +// HasFactorUint64 returns true if d | Mn. Typical run time for a 64 bit factor +// and a 32 bit exponent is < 30 µs. +func HasFactorUint64(d uint64, n uint32) bool { + return d == 1 || d&1 != 0 && mathutil.ModPowUint64(2, uint64(n), d) == 1 +} + +// HasFactorBigInt returns true if d | Mn, d > 0. Typical run time for a 128 +// bit factor and a 32 bit exponent is < 75 µs. +func HasFactorBigInt(d *big.Int, n uint32) bool { + return d.Cmp(_1) == 0 || d.Sign() > 0 && d.Bit(0) == 1 && + mathutil.ModPowBigInt(_2, big.NewInt(int64(n)), d).Cmp(_1) == 0 +} + +// HasFactorBigInt2 returns true if d | Mn, d > 0 +func HasFactorBigInt2(d, n *big.Int) bool { + return d.Cmp(_1) == 0 || d.Sign() > 0 && d.Bit(0) == 1 && + mathutil.ModPowBigInt(_2, n, d).Cmp(_1) == 0 +} + +/* +FromFactorBigInt returns n such that d | Mn if n <= max and d is odd. In other +cases zero is returned. + +It is conjectured that every odd d ∊ N divides infinitely many Mersenne numbers. +The returned n should be the exponent of smallest such Mn. + +NOTE: The computation of n from a given d performs roughly in O(n). It is +thus highly recomended to use the 'max' argument to limit the "searched" +exponent upper bound as appropriate. Otherwise the computation can take a long +time as a large factor can be a divisor of a Mn with exponent above the uint32 +limits. + +The FromFactorBigInt function is a modification of the original Will +Edgington's "reverse method", discussed here: +http://tech.groups.yahoo.com/group/primenumbers/message/15061 +*/ +func FromFactorBigInt(d *big.Int, max uint32) (n uint32) { + if d.Bit(0) == 0 { + return + } + + var m big.Int + for n < max { + m.Add(&m, d) + i := 0 + for ; m.Bit(i) == 1; i++ { + if n == math.MaxUint32 { + return 0 + } + + n++ + } + m.Rsh(&m, uint(i)) + if m.Sign() == 0 { + if n > max { + n = 0 + } + return + } + } + return 0 +} + +// Mod sets mod to n % Mexp and returns mod. It panics for exp == 0 || exp >= +// math.MaxInt32 || n < 0. +func Mod(mod, n *big.Int, exp uint32) *big.Int { + if exp == 0 || exp >= math.MaxInt32 || n.Sign() < 0 { + panic(0) + } + + m := New(exp) + mod.Set(n) + var x big.Int + for mod.BitLen() > int(exp) { + x.Set(mod) + x.Rsh(&x, uint(exp)) + mod.And(mod, m) + mod.Add(mod, &x) + } + if mod.BitLen() == int(exp) && mod.Cmp(m) == 0 { + mod.SetInt64(0) + } + return mod +} + +// ModPow2 returns x such that 2^Me % Mm == 2^x. It panics for m < 2. Typical +// run time is < 1 µs. Use instead of ModPow(2, e, m) wherever possible. +func ModPow2(e, m uint32) (x uint32) { + /* + m < 2 -> panic + e == 0 -> x == 0 + e == 1 -> x == 1 + + 2^M1 % M2 == 2^1 % 3 == 2^1 10 // 2^1, 3, 5, 7 ... +2k + 2^M1 % M3 == 2^1 % 7 == 2^1 010 // 2^1, 4, 7, ... +3k + 2^M1 % M4 == 2^1 % 15 == 2^1 0010 // 2^1, 5, 9, 13... +4k + 2^M1 % M5 == 2^1 % 31 == 2^1 00010 // 2^1, 6, 11, 16... +5k + + 2^M2 % M2 == 2^3 % 3 == 2^1 10.. // 2^3, 5, 7, 9, 11, ... +2k + 2^M2 % M3 == 2^3 % 7 == 2^0 001... // 2^3, 6, 9, 12, 15, ... +3k + 2^M2 % M4 == 2^3 % 15 == 2^3 1000 // 2^3, 7, 11, 15, 19, ... +4k + 2^M2 % M5 == 2^3 % 31 == 2^3 01000 // 2^3, 8, 13, 18, 23, ... +5k + + 2^M3 % M2 == 2^7 % 3 == 2^1 10..--.. // 2^3, 5, 7... +2k + 2^M3 % M3 == 2^7 % 7 == 2^1 010...--- // 2^1, 4, 7... +3k + 2^M3 % M4 == 2^7 % 15 == 2^3 1000.... // +4k + 2^M3 % M5 == 2^7 % 31 == 2^2 00100..... // +5k + 2^M3 % M6 == 2^7 % 63 == 2^1 000010...... // +6k + 2^M3 % M7 == 2^7 % 127 == 2^0 0000001....... + 2^M3 % M8 == 2^7 % 255 == 2^7 10000000 + 2^M3 % M9 == 2^7 % 511 == 2^7 010000000 + + 2^M4 % M2 == 2^15 % 3 == 2^1 10..--..--..--.. + 2^M4 % M3 == 2^15 % 7 == 2^0 1...---...---... + 2^M4 % M4 == 2^15 % 15 == 2^3 1000....----.... + 2^M4 % M5 == 2^15 % 31 == 2^0 1.....-----..... + 2^M4 % M6 == 2^15 % 63 == 2^3 1000......------ + 2^M4 % M7 == 2^15 % 127 == 2^1 10.......------- + 2^M4 % M8 == 2^15 % 255 == 2^7 10000000........ + 2^M4 % M9 == 2^15 % 511 == 2^6 1000000......... + */ + switch { + case m < 2: + panic(0) + case e < 2: + return e + } + + if x = mathutil.ModPowUint32(2, e, m); x == 0 { + return m - 1 + } + + return x - 1 +} + +// ModPow returns b^Me % Mm. Run time grows quickly with 'e' and/or 'm' when b +// != 2 (then ModPow2 is used). +func ModPow(b, e, m uint32) (r *big.Int) { + if m == 1 { + return big.NewInt(0) + } + + if b == 2 { + x := ModPow2(e, m) + r = big.NewInt(0) + r.SetBit(r, int(x), 1) + return + } + + bb := big.NewInt(int64(b)) + r = big.NewInt(1) + for ; e != 0; e-- { + r = bigfft.Mul(r, bb) + Mod(r, r, m) + bb = bigfft.Mul(bb, bb) + Mod(bb, bb, m) + } + return +} + +// ProbablyPrime returns true if Mn is prime or is a pseudoprime to base a. +// Note: Every Mp, prime p, is a prime or is a pseudoprime to base 2, actually +// to every base 2^i, i ∊ [1, p). In contrast - it is conjectured (w/o any +// known counterexamples) that no composite Mp, prime p, is a pseudoprime to +// base 3. +func ProbablyPrime(n, a uint32) bool { + //TODO +test, +bench + if a == 2 { + return ModPow2(n-1, n) == 0 + } + + nMinus1 := New(n) + nMinus1.Sub(nMinus1, _1) + x := ModPow(a, n-1, n) + return x.Cmp(_1) == 0 || x.Cmp(nMinus1) == 0 +} diff --git a/Godeps/_workspace/src/github.com/cznic/mathutil/nist-sts-2-1-1-report b/Godeps/_workspace/src/github.com/cznic/mathutil/nist-sts-2-1-1-report new file mode 100644 index 0000000..20e686c --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/mathutil/nist-sts-2-1-1-report @@ -0,0 +1,267 @@ +$ ./example -max 100000000 > rnd.dat +$ ./assess 1000000 + G E N E R A T O R S E L E C T I O N + ______________________________________ + + [0] Input File [1] Linear Congruential + [2] Quadratic Congruential I [3] Quadratic Congruential II + [4] Cubic Congruential [5] XOR + [6] Modular Exponentiation [7] Blum-Blum-Shub + [8] Micali-Schnorr [9] G Using SHA-1 + + Enter Choice: 0 + + + User Prescribed Input File: rnd.dat + + S T A T I S T I C A L T E S T S + _________________________________ + + [01] Frequency [02] Block Frequency + [03] Cumulative Sums [04] Runs + [05] Longest Run of Ones [06] Rank + [07] Discrete Fourier Transform [08] Nonperiodic Template Matchings + [09] Overlapping Template Matchings [10] Universal Statistical + [11] Approximate Entropy [12] Random Excursions + [13] Random Excursions Variant [14] Serial + [15] Linear Complexity + + INSTRUCTIONS + Enter 0 if you DO NOT want to apply all of the + statistical tests to each sequence and 1 if you DO. + + Enter Choice: 1 + + P a r a m e t e r A d j u s t m e n t s + ----------------------------------------- + [1] Block Frequency Test - block length(M): 128 + [2] NonOverlapping Template Test - block length(m): 9 + [3] Overlapping Template Test - block length(m): 9 + [4] Approximate Entropy Test - block length(m): 10 + [5] Serial Test - block length(m): 16 + [6] Linear Complexity Test - block length(M): 500 + + Select Test (0 to continue): 0 + + How many bitstreams? 200 + + Input File Format: + [0] ASCII - A sequence of ASCII 0's and 1's + [1] Binary - Each byte in data file contains 8 bits of data + + Select input mode: 1 + + Statistical Testing In Progress......... + + Statistical Testing Complete!!!!!!!!!!!! + +$ cat experiments/AlgorithmTesting/finalAnalysisReport.txt +------------------------------------------------------------------------------ +RESULTS FOR THE UNIFORMITY OF P-VALUES AND THE PROPORTION OF PASSING SEQUENCES +------------------------------------------------------------------------------ + generator is +------------------------------------------------------------------------------ + C1 C2 C3 C4 C5 C6 C7 C8 C9 C10 P-VALUE PROPORTION STATISTICAL TEST +------------------------------------------------------------------------------ + 28 22 17 19 15 8 24 23 19 25 0.093720 198/200 Frequency + 20 18 24 14 18 17 16 28 21 24 0.504219 199/200 BlockFrequency + 25 22 17 24 19 21 22 15 16 19 0.825505 197/200 CumulativeSums + 27 17 16 22 14 26 14 25 19 20 0.304126 199/200 CumulativeSums + 22 19 14 23 22 22 13 28 13 24 0.224821 199/200 Runs + 20 24 18 21 15 13 22 23 24 20 0.719747 197/200 LongestRun + 22 26 18 22 26 15 17 22 20 12 0.410055 199/200 Rank + 25 22 26 22 20 16 20 20 16 13 0.585209 195/200 FFT + 22 11 15 26 33 24 21 13 14 21 0.013102 197/200 NonOverlappingTemplate + 17 11 16 27 19 24 19 20 28 19 0.219006 200/200 NonOverlappingTemplate + 23 27 24 15 21 11 18 27 15 19 0.162606 197/200 NonOverlappingTemplate + 21 18 13 20 19 23 20 17 26 23 0.749884 197/200 NonOverlappingTemplate + 24 22 24 24 24 21 13 15 17 16 0.494392 196/200 NonOverlappingTemplate + 24 16 23 15 23 18 25 16 18 22 0.699313 199/200 NonOverlappingTemplate + 19 23 21 16 27 18 17 20 18 21 0.859637 198/200 NonOverlappingTemplate + 12 20 16 19 26 14 30 20 24 19 0.141256 198/200 NonOverlappingTemplate + 18 21 17 21 20 14 25 19 24 21 0.859637 198/200 NonOverlappingTemplate + 24 25 21 18 23 15 23 17 16 18 0.749884 199/200 NonOverlappingTemplate + 20 22 22 18 16 22 28 16 14 22 0.574903 198/200 NonOverlappingTemplate + 18 23 22 17 24 25 19 16 23 13 0.626709 199/200 NonOverlappingTemplate + 17 22 14 19 21 21 18 19 24 25 0.842937 198/200 NonOverlappingTemplate + 18 17 26 21 22 15 22 18 21 20 0.883171 197/200 NonOverlappingTemplate + 19 25 16 32 15 19 20 18 16 20 0.236810 199/200 NonOverlappingTemplate + 19 18 15 21 24 22 18 21 20 22 0.964295 200/200 NonOverlappingTemplate + 21 14 17 23 26 19 20 22 20 18 0.834308 196/200 NonOverlappingTemplate + 15 21 17 27 26 23 21 17 24 9 0.129620 198/200 NonOverlappingTemplate + 25 17 19 19 18 22 21 22 21 16 0.951205 196/200 NonOverlappingTemplate + 20 19 24 21 19 24 16 18 17 22 0.946308 197/200 NonOverlappingTemplate + 27 16 19 18 23 19 22 17 22 17 0.807412 197/200 NonOverlappingTemplate + 14 18 21 23 23 20 14 22 20 25 0.719747 198/200 NonOverlappingTemplate + 18 22 19 12 24 25 25 22 18 15 0.474986 198/200 NonOverlappingTemplate + 21 18 23 17 19 18 28 19 20 17 0.825505 198/200 NonOverlappingTemplate + 20 19 15 16 27 20 26 17 20 20 0.657933 198/200 NonOverlappingTemplate + 17 25 21 21 11 19 22 16 27 21 0.401199 198/200 NonOverlappingTemplate + 19 16 15 18 24 19 25 25 19 20 0.769527 199/200 NonOverlappingTemplate + 18 20 20 26 20 12 24 25 19 16 0.524101 198/200 NonOverlappingTemplate + 14 16 18 23 21 21 19 19 28 21 0.668321 197/200 NonOverlappingTemplate + 21 20 23 25 21 22 19 17 14 18 0.875539 197/200 NonOverlappingTemplate + 14 16 29 22 23 13 20 29 17 17 0.099513 197/200 NonOverlappingTemplate + 14 19 27 19 17 23 18 24 20 19 0.709558 199/200 NonOverlappingTemplate + 18 15 21 19 27 22 21 23 17 17 0.779188 198/200 NonOverlappingTemplate + 13 23 13 22 22 23 22 21 21 20 0.689019 199/200 NonOverlappingTemplate + 17 14 26 26 16 21 30 15 21 14 0.096578 199/200 NonOverlappingTemplate + 18 21 24 23 21 13 23 23 19 15 0.719747 197/200 NonOverlappingTemplate + 19 21 14 32 20 15 16 18 24 21 0.202268 199/200 NonOverlappingTemplate + 27 22 20 21 21 14 15 22 14 24 0.474986 196/200 NonOverlappingTemplate + 31 12 25 11 21 18 19 16 24 23 0.050305 197/200 NonOverlappingTemplate + 17 26 20 22 15 27 22 19 12 20 0.383827 199/200 NonOverlappingTemplate + 15 22 14 14 31 15 27 18 23 21 0.078086 194/200 NonOverlappingTemplate + 19 19 14 15 24 21 25 21 20 22 0.788728 197/200 NonOverlappingTemplate + 20 21 19 22 25 18 13 24 28 10 0.153763 195/200 NonOverlappingTemplate + 23 17 21 25 21 20 13 30 14 16 0.196920 196/200 NonOverlappingTemplate + 17 31 17 22 16 15 28 23 11 20 0.050305 197/200 NonOverlappingTemplate + 15 21 26 27 15 18 19 21 18 20 0.605916 198/200 NonOverlappingTemplate + 23 18 15 14 20 21 20 20 20 29 0.554420 200/200 NonOverlappingTemplate + 22 19 19 18 19 17 22 21 31 12 0.311542 199/200 NonOverlappingTemplate + 16 22 23 21 19 19 18 24 21 17 0.960198 197/200 NonOverlappingTemplate + 21 21 17 20 16 23 25 22 18 17 0.917870 200/200 NonOverlappingTemplate + 27 17 17 16 21 20 22 18 21 21 0.859637 197/200 NonOverlappingTemplate + 18 24 15 27 18 21 18 16 24 19 0.657933 199/200 NonOverlappingTemplate + 13 16 21 21 15 25 18 22 29 20 0.326749 198/200 NonOverlappingTemplate + 18 17 23 23 15 19 26 30 11 18 0.125927 198/200 NonOverlappingTemplate + 30 21 18 22 17 21 15 17 21 18 0.544254 195/200 NonOverlappingTemplate + 12 18 19 24 16 24 18 24 28 17 0.311542 199/200 NonOverlappingTemplate + 20 15 23 15 18 30 23 18 17 21 0.410055 196/200 NonOverlappingTemplate + 15 18 23 16 29 21 22 16 19 21 0.544254 200/200 NonOverlappingTemplate + 18 16 27 13 21 22 22 21 16 24 0.534146 199/200 NonOverlappingTemplate + 20 25 18 21 16 21 17 28 21 13 0.484646 200/200 NonOverlappingTemplate + 23 22 13 22 14 20 26 18 19 23 0.574903 197/200 NonOverlappingTemplate + 21 24 25 13 19 22 18 13 24 21 0.504219 199/200 NonOverlappingTemplate + 19 13 18 25 22 15 23 28 19 18 0.410055 195/200 NonOverlappingTemplate + 20 15 27 22 26 26 14 13 21 16 0.181557 198/200 NonOverlappingTemplate + 18 18 19 23 18 20 19 21 24 20 0.991468 200/200 NonOverlappingTemplate + 18 23 17 14 20 25 22 22 22 17 0.816537 198/200 NonOverlappingTemplate + 26 15 15 11 23 21 21 16 36 16 0.005557 196/200 NonOverlappingTemplate + 27 13 21 23 21 16 19 20 16 24 0.544254 198/200 NonOverlappingTemplate + 16 15 32 17 20 23 22 19 20 16 0.262249 200/200 NonOverlappingTemplate + 26 19 24 13 24 16 18 18 13 29 0.137282 199/200 NonOverlappingTemplate + 15 18 14 27 32 21 15 20 19 19 0.112047 198/200 NonOverlappingTemplate + 22 23 22 18 20 23 19 22 16 15 0.924076 196/200 NonOverlappingTemplate + 18 17 21 22 14 17 22 24 20 25 0.798139 199/200 NonOverlappingTemplate + 15 17 19 24 21 23 17 25 23 16 0.739918 196/200 NonOverlappingTemplate + 22 11 15 26 32 25 21 13 14 21 0.017305 197/200 NonOverlappingTemplate + 22 16 19 23 22 21 21 19 17 20 0.985788 200/200 NonOverlappingTemplate + 22 28 18 24 14 20 23 21 20 10 0.230755 198/200 NonOverlappingTemplate + 14 13 22 28 14 28 17 22 23 19 0.129620 197/200 NonOverlappingTemplate + 22 16 22 20 21 21 16 19 18 25 0.935716 198/200 NonOverlappingTemplate + 15 20 23 17 19 22 21 23 18 22 0.951205 200/200 NonOverlappingTemplate + 20 24 21 19 17 19 19 24 15 22 0.930026 198/200 NonOverlappingTemplate + 18 21 15 21 17 28 24 22 20 14 0.534146 200/200 NonOverlappingTemplate + 19 15 19 19 20 20 15 25 23 25 0.779188 198/200 NonOverlappingTemplate + 17 24 25 16 15 21 18 19 23 22 0.788728 198/200 NonOverlappingTemplate + 15 20 18 25 24 15 21 31 18 13 0.141256 200/200 NonOverlappingTemplate + 24 17 19 20 18 21 15 22 24 20 0.924076 196/200 NonOverlappingTemplate + 23 18 17 21 17 28 23 21 18 14 0.605916 197/200 NonOverlappingTemplate + 21 19 22 23 16 17 20 21 22 19 0.985788 200/200 NonOverlappingTemplate + 27 17 21 27 24 15 15 17 15 22 0.304126 199/200 NonOverlappingTemplate + 25 28 20 24 13 14 16 22 19 19 0.304126 197/200 NonOverlappingTemplate + 27 16 14 24 22 18 24 20 18 17 0.564639 196/200 NonOverlappingTemplate + 18 18 24 19 19 19 26 11 27 19 0.375313 195/200 NonOverlappingTemplate + 20 15 29 19 26 16 21 11 18 25 0.141256 197/200 NonOverlappingTemplate + 19 14 21 25 11 23 22 25 26 14 0.176657 199/200 NonOverlappingTemplate + 18 23 20 17 19 18 29 22 26 8 0.102526 199/200 NonOverlappingTemplate + 22 17 18 16 18 20 19 19 25 26 0.834308 198/200 NonOverlappingTemplate + 25 18 14 16 16 24 18 18 30 21 0.268917 198/200 NonOverlappingTemplate + 24 21 23 13 12 22 20 23 20 22 0.554420 196/200 NonOverlappingTemplate + 18 21 21 30 22 17 19 14 18 20 0.534146 197/200 NonOverlappingTemplate + 25 20 22 21 15 18 17 20 17 25 0.825505 199/200 NonOverlappingTemplate + 18 21 22 21 18 20 26 16 20 18 0.941144 197/200 NonOverlappingTemplate + 23 18 22 25 12 16 17 19 26 22 0.474986 198/200 NonOverlappingTemplate + 22 18 29 23 19 23 17 17 15 17 0.534146 198/200 NonOverlappingTemplate + 19 21 17 26 18 15 22 26 15 21 0.626709 197/200 NonOverlappingTemplate + 16 20 20 23 18 21 18 18 25 21 0.955835 199/200 NonOverlappingTemplate + 23 21 20 21 22 10 15 27 15 26 0.186566 198/200 NonOverlappingTemplate + 18 26 20 26 26 18 17 17 20 12 0.358641 198/200 NonOverlappingTemplate + 24 20 21 18 24 12 19 27 14 21 0.401199 195/200 NonOverlappingTemplate + 16 25 15 21 24 18 18 25 22 16 0.657933 199/200 NonOverlappingTemplate + 24 14 17 26 15 17 17 25 21 24 0.428095 200/200 NonOverlappingTemplate + 22 24 11 20 22 24 19 18 12 28 0.176657 196/200 NonOverlappingTemplate + 27 16 27 18 27 14 13 16 21 21 0.141256 197/200 NonOverlappingTemplate + 23 25 20 18 23 17 15 23 19 17 0.834308 196/200 NonOverlappingTemplate + 19 21 20 27 16 16 18 25 16 22 0.678686 199/200 NonOverlappingTemplate + 25 22 21 19 15 19 22 19 25 13 0.657933 197/200 NonOverlappingTemplate + 19 28 21 25 20 12 18 13 29 15 0.073417 198/200 NonOverlappingTemplate + 20 24 21 19 21 15 17 24 20 19 0.941144 198/200 NonOverlappingTemplate + 18 29 23 17 24 19 17 18 16 19 0.585209 200/200 NonOverlappingTemplate + 18 28 18 16 25 21 18 20 14 22 0.544254 198/200 NonOverlappingTemplate + 22 19 23 22 22 21 21 26 12 12 0.401199 199/200 NonOverlappingTemplate + 22 15 25 16 21 27 14 22 21 17 0.484646 199/200 NonOverlappingTemplate + 18 25 20 23 30 17 13 22 18 14 0.213309 200/200 NonOverlappingTemplate + 20 23 21 21 23 29 16 13 16 18 0.410055 199/200 NonOverlappingTemplate + 21 19 16 22 31 18 20 17 18 18 0.514124 198/200 NonOverlappingTemplate + 26 22 12 14 23 17 21 24 21 20 0.455937 197/200 NonOverlappingTemplate + 21 17 18 17 14 32 21 26 18 16 0.162606 197/200 NonOverlappingTemplate + 22 24 22 23 11 15 17 18 29 19 0.230755 198/200 NonOverlappingTemplate + 19 27 20 19 23 15 24 15 21 17 0.657933 198/200 NonOverlappingTemplate + 20 25 16 10 24 13 23 21 21 27 0.149495 200/200 NonOverlappingTemplate + 19 21 21 27 17 17 19 21 21 17 0.904708 200/200 NonOverlappingTemplate + 18 23 15 19 24 21 23 21 13 23 0.719747 198/200 NonOverlappingTemplate + 26 16 28 19 19 18 17 17 16 24 0.474986 199/200 NonOverlappingTemplate + 24 32 17 18 20 13 18 18 19 21 0.236810 195/200 NonOverlappingTemplate + 26 25 18 17 12 19 20 23 21 19 0.585209 196/200 NonOverlappingTemplate + 18 26 25 12 18 16 24 19 18 24 0.410055 199/200 NonOverlappingTemplate + 27 21 22 27 21 14 18 14 23 13 0.219006 197/200 NonOverlappingTemplate + 18 23 24 16 19 21 16 26 20 17 0.798139 199/200 NonOverlappingTemplate + 19 30 15 27 14 19 24 11 22 19 0.073417 198/200 NonOverlappingTemplate + 20 23 22 20 22 15 22 21 18 17 0.964295 198/200 NonOverlappingTemplate + 22 31 16 26 13 19 17 22 24 10 0.037566 197/200 NonOverlappingTemplate + 18 24 22 14 23 19 16 18 19 27 0.637119 197/200 NonOverlappingTemplate + 19 20 21 22 21 18 19 22 20 18 0.999438 198/200 NonOverlappingTemplate + 27 15 21 18 28 18 15 23 18 17 0.375313 195/200 NonOverlappingTemplate + 26 23 20 20 23 19 20 23 14 12 0.514124 199/200 NonOverlappingTemplate + 18 19 11 15 21 24 20 26 23 23 0.428095 198/200 NonOverlappingTemplate + 19 16 21 25 19 21 15 24 24 16 0.749884 197/200 NonOverlappingTemplate + 17 26 23 18 20 26 23 14 18 15 0.494392 198/200 NonOverlappingTemplate + 15 17 19 24 21 23 17 25 23 16 0.739918 196/200 NonOverlappingTemplate + 26 19 20 20 24 22 22 13 14 20 0.605916 198/200 OverlappingTemplate + 29 24 17 21 18 13 18 21 17 22 0.446556 196/200 Universal + 22 18 22 20 20 21 22 21 18 16 0.992952 198/200 ApproximateEntropy + 14 8 13 9 11 13 13 8 7 10 0.719747 106/106 RandomExcursions + 13 18 9 7 12 12 9 6 12 8 0.236810 104/106 RandomExcursions + 11 15 10 7 11 14 9 6 12 11 0.595549 106/106 RandomExcursions + 15 7 12 12 9 11 16 8 10 6 0.350485 106/106 RandomExcursions + 10 10 12 16 10 12 10 7 13 6 0.554420 106/106 RandomExcursions + 8 7 12 10 11 16 11 13 10 8 0.657933 106/106 RandomExcursions + 9 6 12 12 14 9 11 13 10 10 0.816537 104/106 RandomExcursions + 10 10 7 12 11 9 10 13 14 10 0.911413 105/106 RandomExcursions + 8 8 12 9 10 5 13 12 17 12 0.319084 104/106 RandomExcursionsVariant + 5 11 10 11 7 11 10 15 11 15 0.455937 104/106 RandomExcursionsVariant + 6 12 11 8 12 12 12 13 13 7 0.699313 104/106 RandomExcursionsVariant + 14 10 11 6 12 9 8 12 11 13 0.779188 104/106 RandomExcursionsVariant + 12 12 10 7 17 6 6 12 13 11 0.262249 103/106 RandomExcursionsVariant + 13 8 14 13 7 6 6 13 15 11 0.249284 102/106 RandomExcursionsVariant + 12 12 12 13 7 9 6 13 12 10 0.739918 105/106 RandomExcursionsVariant + 13 15 12 8 9 10 6 9 14 10 0.574903 106/106 RandomExcursionsVariant + 10 15 9 12 14 10 8 11 7 10 0.739918 105/106 RandomExcursionsVariant + 13 12 8 11 12 11 9 10 11 9 0.978072 103/106 RandomExcursionsVariant + 10 13 12 12 8 13 8 9 14 7 0.739918 104/106 RandomExcursionsVariant + 12 10 10 14 7 8 7 13 14 11 0.657933 106/106 RandomExcursionsVariant + 10 13 10 10 13 10 12 6 10 12 0.897763 106/106 RandomExcursionsVariant + 9 12 15 8 13 8 12 8 11 10 0.779188 106/106 RandomExcursionsVariant + 9 13 15 10 10 10 8 14 6 11 0.616305 106/106 RandomExcursionsVariant + 7 17 9 12 9 11 10 16 4 11 0.129620 106/106 RandomExcursionsVariant + 10 9 10 15 7 12 7 8 12 16 0.419021 106/106 RandomExcursionsVariant + 9 12 11 8 8 9 15 12 9 13 0.798139 106/106 RandomExcursionsVariant + 17 34 11 22 22 17 19 20 13 25 0.026057 199/200 Serial + 22 20 16 22 20 18 20 18 23 21 0.989786 199/200 Serial + 12 33 25 29 21 11 21 15 14 19 0.003996 199/200 LinearComplexity + + +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +The minimum pass rate for each statistical test with the exception of the +random excursion (variant) test is approximately = 193 for a +sample size = 200 binary sequences. + +The minimum pass rate for the random excursion (variant) test +is approximately = 101 for a sample size = 106 binary sequences. + +For further guidelines construct a probability table using the MAPLE program +provided in the addendum section of the documentation. +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +$ diff --git a/Godeps/_workspace/src/github.com/cznic/mathutil/permute.go b/Godeps/_workspace/src/github.com/cznic/mathutil/permute.go new file mode 100644 index 0000000..bf828b6 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/mathutil/permute.go @@ -0,0 +1,39 @@ +// Copyright (c) 2014 The mathutil 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 mathutil + +import ( + "sort" +) + +// Generate the first permutation of data. +func PermutationFirst(data sort.Interface) { + sort.Sort(data) +} + +// Generate the next permutation of data if possible and return true. +// Return false if there is no more permutation left. +// Based on the algorithm described here: +// http://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order +func PermutationNext(data sort.Interface) bool { + var k, l int + for k = data.Len() - 2; ; k-- { // 1. + if k < 0 { + return false + } + + if data.Less(k, k+1) { + break + } + } + for l = data.Len() - 1; !data.Less(k, l); l-- { // 2. + } + data.Swap(k, l) // 3. + for i, j := k+1, data.Len()-1; i < j; i++ { // 4. + data.Swap(i, j) + j-- + } + return true +} diff --git a/Godeps/_workspace/src/github.com/cznic/mathutil/primes.go b/Godeps/_workspace/src/github.com/cznic/mathutil/primes.go new file mode 100644 index 0000000..2c82eb0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/mathutil/primes.go @@ -0,0 +1,342 @@ +// Copyright (c) 2014 The mathutil 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 mathutil + +import ( + "math" +) + +// IsPrimeUint16 returns true if n is prime. Typical run time is few ns. +func IsPrimeUint16(n uint16) bool { + return n > 0 && primes16[n-1] == 1 +} + +// NextPrimeUint16 returns first prime > n and true if successful or an +// undefined value and false if there is no next prime in the uint16 limits. +// Typical run time is few ns. +func NextPrimeUint16(n uint16) (p uint16, ok bool) { + return n + uint16(primes16[n]), n < 65521 +} + +// IsPrime returns true if n is prime. Typical run time is about 100 ns. +// +//TODO rename to IsPrimeUint32 +func IsPrime(n uint32) bool { + switch { + case n&1 == 0: + return n == 2 + case n%3 == 0: + return n == 3 + case n%5 == 0: + return n == 5 + case n%7 == 0: + return n == 7 + case n%11 == 0: + return n == 11 + case n%13 == 0: + return n == 13 + case n%17 == 0: + return n == 17 + case n%19 == 0: + return n == 19 + case n%23 == 0: + return n == 23 + case n%29 == 0: + return n == 29 + case n%31 == 0: + return n == 31 + case n%37 == 0: + return n == 37 + case n%41 == 0: + return n == 41 + case n%43 == 0: + return n == 43 + case n%47 == 0: + return n == 47 + case n%53 == 0: + return n == 53 // Benchmarked optimum + case n < 65536: + // use table data + return IsPrimeUint16(uint16(n)) + default: + mod := ModPowUint32(2, (n+1)/2, n) + if mod != 2 && mod != n-2 { + return false + } + blk := &lohi[n>>24] + lo, hi := blk.lo, blk.hi + for lo <= hi { + index := (lo + hi) >> 1 + liar := liars[index] + switch { + case n > liar: + lo = index + 1 + case n < liar: + hi = index - 1 + default: + return false + } + } + return true + } +} + +// IsPrimeUint64 returns true if n is prime. Typical run time is few tens of µs. +// +// SPRP bases: http://miller-rabin.appspot.com +func IsPrimeUint64(n uint64) bool { + switch { + case n%2 == 0: + return n == 2 + case n%3 == 0: + return n == 3 + case n%5 == 0: + return n == 5 + case n%7 == 0: + return n == 7 + case n%11 == 0: + return n == 11 + case n%13 == 0: + return n == 13 + case n%17 == 0: + return n == 17 + case n%19 == 0: + return n == 19 + case n%23 == 0: + return n == 23 + case n%29 == 0: + return n == 29 + case n%31 == 0: + return n == 31 + case n%37 == 0: + return n == 37 + case n%41 == 0: + return n == 41 + case n%43 == 0: + return n == 43 + case n%47 == 0: + return n == 47 + case n%53 == 0: + return n == 53 + case n%59 == 0: + return n == 59 + case n%61 == 0: + return n == 61 + case n%67 == 0: + return n == 67 + case n%71 == 0: + return n == 71 + case n%73 == 0: + return n == 73 + case n%79 == 0: + return n == 79 + case n%83 == 0: + return n == 83 + case n%89 == 0: + return n == 89 // Benchmarked optimum + case n <= math.MaxUint16: + return IsPrimeUint16(uint16(n)) + case n <= math.MaxUint32: + return ProbablyPrimeUint32(uint32(n), 11000544) && + ProbablyPrimeUint32(uint32(n), 31481107) + case n < 105936894253: + return ProbablyPrimeUint64_32(n, 2) && + ProbablyPrimeUint64_32(n, 1005905886) && + ProbablyPrimeUint64_32(n, 1340600841) + case n < 31858317218647: + return ProbablyPrimeUint64_32(n, 2) && + ProbablyPrimeUint64_32(n, 642735) && + ProbablyPrimeUint64_32(n, 553174392) && + ProbablyPrimeUint64_32(n, 3046413974) + case n < 3071837692357849: + return ProbablyPrimeUint64_32(n, 2) && + ProbablyPrimeUint64_32(n, 75088) && + ProbablyPrimeUint64_32(n, 642735) && + ProbablyPrimeUint64_32(n, 203659041) && + ProbablyPrimeUint64_32(n, 3613982119) + default: + return ProbablyPrimeUint64_32(n, 2) && + ProbablyPrimeUint64_32(n, 325) && + ProbablyPrimeUint64_32(n, 9375) && + ProbablyPrimeUint64_32(n, 28178) && + ProbablyPrimeUint64_32(n, 450775) && + ProbablyPrimeUint64_32(n, 9780504) && + ProbablyPrimeUint64_32(n, 1795265022) + } +} + +// NextPrime returns first prime > n and true if successful or an undefined value and false if there +// is no next prime in the uint32 limits. Typical run time is about 2 µs. +// +//TODO rename to NextPrimeUint32 +func NextPrime(n uint32) (p uint32, ok bool) { + switch { + case n < 65521: + p16, _ := NextPrimeUint16(uint16(n)) + return uint32(p16), true + case n >= math.MaxUint32-4: + return + } + + n++ + var d0, d uint32 + switch mod := n % 6; mod { + case 0: + d0, d = 1, 4 + case 1: + d = 4 + case 2, 3, 4: + d0, d = 5-mod, 2 + case 5: + d = 2 + } + + p = n + d0 + if p < n { // overflow + return + } + + for { + if IsPrime(p) { + return p, true + } + + p0 := p + p += d + if p < p0 { // overflow + break + } + + d ^= 6 + } + return +} + +// NextPrimeUint64 returns first prime > n and true if successful or an undefined value and false if there +// is no next prime in the uint64 limits. Typical run time is in hundreds of µs. +func NextPrimeUint64(n uint64) (p uint64, ok bool) { + switch { + case n < 65521: + p16, _ := NextPrimeUint16(uint16(n)) + return uint64(p16), true + case n >= 18446744073709551557: // last uint64 prime + return + } + + n++ + var d0, d uint64 + switch mod := n % 6; mod { + case 0: + d0, d = 1, 4 + case 1: + d = 4 + case 2, 3, 4: + d0, d = 5-mod, 2 + case 5: + d = 2 + } + + p = n + d0 + if p < n { // overflow + return + } + + for { + if ok = IsPrimeUint64(p); ok { + break + } + + p0 := p + p += d + if p < p0 { // overflow + break + } + + d ^= 6 + } + return +} + +// FactorTerm is one term of an integer factorization. +type FactorTerm struct { + Prime uint32 // The divisor + Power uint32 // Term == Prime^Power +} + +// FactorTerms represent a factorization of an integer +type FactorTerms []FactorTerm + +// FactorInt returns prime factorization of n > 1 or nil otherwise. +// Resulting factors are ordered by Prime. Typical run time is few µs. +func FactorInt(n uint32) (f FactorTerms) { + switch { + case n < 2: + return + case IsPrime(n): + return []FactorTerm{{n, 1}} + } + + f, w := make([]FactorTerm, 9), 0 + prime16 := uint16(0) + for { + var ok bool + if prime16, ok = NextPrimeUint16(prime16); !ok { + break + } + + prime := uint32(prime16) + if prime*prime > n { + break + } + + power := uint32(0) + for n%prime == 0 { + n /= prime + power++ + } + if power != 0 { + f[w] = FactorTerm{prime, power} + w++ + } + if n == 1 { + break + } + } + if n != 1 { + f[w] = FactorTerm{n, 1} + w++ + } + return f[:w] +} + +// PrimorialProductsUint32 returns a slice of numbers in [lo, hi] which are a +// product of max 'max' primorials. The slice is not sorted. +// +// See also: http://en.wikipedia.org/wiki/Primorial +func PrimorialProductsUint32(lo, hi, max uint32) (r []uint32) { + lo64, hi64 := int64(lo), int64(hi) + if max > 31 { // N/A + max = 31 + } + + var f func(int64, int64, uint32) + f = func(n, p int64, emax uint32) { + e := uint32(1) + for n <= hi64 && e <= emax { + n *= p + if n >= lo64 && n <= hi64 { + r = append(r, uint32(n)) + } + if n < hi64 { + p, _ := NextPrime(uint32(p)) + f(n, int64(p), e) + } + e++ + } + } + + f(1, 2, max) + return +} diff --git a/Godeps/_workspace/src/github.com/cznic/mathutil/rat.go b/Godeps/_workspace/src/github.com/cznic/mathutil/rat.go new file mode 100644 index 0000000..91b1c6f --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/mathutil/rat.go @@ -0,0 +1,27 @@ +// Copyright (c) 2014 The mathutil 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 mathutil + +// QCmpUint32 compares a/b and c/d and returns: +// +// -1 if a/b < c/d +// 0 if a/b == c/d +// +1 if a/b > c/d +// +func QCmpUint32(a, b, c, d uint32) int { + switch x, y := uint64(a)*uint64(d), uint64(b)*uint64(c); { + case x < y: + return -1 + case x == y: + return 0 + default: // x > y + return 1 + } +} + +// QScaleUint32 returns a such that a/b >= c/d. +func QScaleUint32(b, c, d uint32) (a uint64) { + return 1 + (uint64(b)*uint64(c))/uint64(d) +} diff --git a/Godeps/_workspace/src/github.com/cznic/mathutil/rnd.go b/Godeps/_workspace/src/github.com/cznic/mathutil/rnd.go new file mode 100644 index 0000000..9132dc0 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/mathutil/rnd.go @@ -0,0 +1,383 @@ +// Copyright (c) 2014 The mathutil 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 mathutil + +import ( + "fmt" + "math" + "math/big" +) + +// FC32 is a full cycle PRNG covering the 32 bit signed integer range. +// In contrast to full cycle generators shown at e.g. http://en.wikipedia.org/wiki/Full_cycle, +// this code doesn't produce values at constant delta (mod cycle length). +// The 32 bit limit is per this implementation, the algorithm used has no intrinsic limit on the cycle size. +// Properties include: +// - Adjustable limits on creation (hi, lo). +// - Positionable/randomly accessible (Pos, Seek). +// - Repeatable (deterministic). +// - Can run forward or backward (Next, Prev). +// - For a billion numbers cycle the Next/Prev PRN can be produced in cca 100-150ns. +// That's like 5-10 times slower compared to PRNs generated using the (non FC) rand package. +type FC32 struct { + cycle int64 // On average: 3 * delta / 2, (HQ: 2 * delta) + delta int64 // hi - lo + factors [][]int64 // This trades some space for hopefully a bit of speed (multiple adding vs multiplying). + lo int + mods []int // pos % set + pos int64 // Within cycle. + primes []int64 // Ordered. ∏ primes == cycle. + set []int64 // Reordered primes (magnitude order bases) according to seed. +} + +// NewFC32 returns a newly created FC32 adjusted for the closed interval [lo, hi] or an Error if any. +// If hq == true then trade some generation time for improved (pseudo)randomness. +func NewFC32(lo, hi int, hq bool) (r *FC32, err error) { + if lo > hi { + return nil, fmt.Errorf("invalid range %d > %d", lo, hi) + } + + if uint64(hi)-uint64(lo) > math.MaxUint32 { + return nil, fmt.Errorf("range out of int32 limits %d, %d", lo, hi) + } + + delta := int64(hi) - int64(lo) + // Find the primorial covering whole delta + n, set, p := int64(1), []int64{}, uint32(2) + if hq { + p++ + } + for { + set = append(set, int64(p)) + n *= int64(p) + if n > delta { + break + } + p, _ = NextPrime(p) + } + + // Adjust the set so n ∊ [delta, 2 * delta] (HQ: [delta, 3 * delta]) + // while keeping the cardinality of the set (correlates with the statistic "randomness quality") + // at max, i.e. discard atmost one member. + i := -1 // no candidate prime + if n > 2*(delta+1) { + for j, p := range set { + q := n / p + if q < delta+1 { + break + } + + i = j // mark the highest candidate prime set index + } + } + if i >= 0 { // shrink the inner cycle + n = n / set[i] + set = delete(set, i) + } + r = &FC32{ + cycle: n, + delta: delta, + factors: make([][]int64, len(set)), + lo: lo, + mods: make([]int, len(set)), + primes: set, + } + r.Seed(1) // the default seed should be always non zero + return +} + +// Cycle reports the length of the inner FCPRNG cycle. +// Cycle is atmost the double (HQ: triple) of the generator period (hi - lo + 1). +func (r *FC32) Cycle() int64 { + return r.cycle +} + +// Next returns the first PRN after Pos. +func (r *FC32) Next() int { + return r.step(1) +} + +// Pos reports the current position within the inner cycle. +func (r *FC32) Pos() int64 { + return r.pos +} + +// Prev return the first PRN before Pos. +func (r *FC32) Prev() int { + return r.step(-1) +} + +// Seed uses the provided seed value to initialize the generator to a deterministic state. +// A zero seed produces a "canonical" generator with worse randomness than for most non zero seeds. +// Still, the FC property holds for any seed value. +func (r *FC32) Seed(seed int64) { + u := uint64(seed) + r.set = mix(r.primes, &u) + n := int64(1) + for i, p := range r.set { + k := make([]int64, p) + v := int64(0) + for j := range k { + k[j] = v + v += n + } + n *= p + r.factors[i] = mix(k, &u) + } +} + +// Seek sets Pos to |pos| % Cycle. +func (r *FC32) Seek(pos int64) { //vet:ignore + if pos < 0 { + pos = -pos + } + pos %= r.cycle + r.pos = pos + for i, p := range r.set { + r.mods[i] = int(pos % p) + } +} + +func (r *FC32) step(dir int) int { + for { // avg loops per step: 3/2 (HQ: 2) + y := int64(0) + pos := r.pos + pos += int64(dir) + switch { + case pos < 0: + pos = r.cycle - 1 + case pos >= r.cycle: + pos = 0 + } + r.pos = pos + for i, mod := range r.mods { + mod += dir + p := int(r.set[i]) + switch { + case mod < 0: + mod = p - 1 + case mod >= p: + mod = 0 + } + r.mods[i] = mod + y += r.factors[i][mod] + } + if y <= r.delta { + return int(y) + r.lo + } + } +} + +func delete(set []int64, i int) (y []int64) { + for j, v := range set { + if j != i { + y = append(y, v) + } + } + return +} + +func mix(set []int64, seed *uint64) (y []int64) { + for len(set) != 0 { + *seed = rol(*seed) + i := int(*seed % uint64(len(set))) + y = append(y, set[i]) + set = delete(set, i) + } + return +} + +func rol(u uint64) (y uint64) { + y = u << 1 + if int64(u) < 0 { + y |= 1 + } + return +} + +// FCBig is a full cycle PRNG covering ranges outside of the int32 limits. +// For more info see the FC32 docs. +// Next/Prev PRN on a 1e15 cycle can be produced in about 2 µsec. +type FCBig struct { + cycle *big.Int // On average: 3 * delta / 2, (HQ: 2 * delta) + delta *big.Int // hi - lo + factors [][]*big.Int // This trades some space for hopefully a bit of speed (multiple adding vs multiplying). + lo *big.Int + mods []int // pos % set + pos *big.Int // Within cycle. + primes []int64 // Ordered. ∏ primes == cycle. + set []int64 // Reordered primes (magnitude order bases) according to seed. +} + +// NewFCBig returns a newly created FCBig adjusted for the closed interval [lo, hi] or an Error if any. +// If hq == true then trade some generation time for improved (pseudo)randomness. +func NewFCBig(lo, hi *big.Int, hq bool) (r *FCBig, err error) { + if lo.Cmp(hi) > 0 { + return nil, fmt.Errorf("invalid range %d > %d", lo, hi) + } + + delta := big.NewInt(0) + delta.Add(delta, hi).Sub(delta, lo) + + // Find the primorial covering whole delta + n, set, pp, p := big.NewInt(1), []int64{}, big.NewInt(0), uint32(2) + if hq { + p++ + } + for { + set = append(set, int64(p)) + pp.SetInt64(int64(p)) + n.Mul(n, pp) + if n.Cmp(delta) > 0 { + break + } + p, _ = NextPrime(p) + } + + // Adjust the set so n ∊ [delta, 2 * delta] (HQ: [delta, 3 * delta]) + // while keeping the cardinality of the set (correlates with the statistic "randomness quality") + // at max, i.e. discard atmost one member. + dd1 := big.NewInt(1) + dd1.Add(dd1, delta) + dd2 := big.NewInt(0) + dd2.Lsh(dd1, 1) + i := -1 // no candidate prime + if n.Cmp(dd2) > 0 { + q := big.NewInt(0) + for j, p := range set { + pp.SetInt64(p) + q.Set(n) + q.Div(q, pp) + if q.Cmp(dd1) < 0 { + break + } + + i = j // mark the highest candidate prime set index + } + } + if i >= 0 { // shrink the inner cycle + pp.SetInt64(set[i]) + n.Div(n, pp) + set = delete(set, i) + } + r = &FCBig{ + cycle: n, + delta: delta, + factors: make([][]*big.Int, len(set)), + lo: lo, + mods: make([]int, len(set)), + pos: big.NewInt(0), + primes: set, + } + r.Seed(1) // the default seed should be always non zero + return +} + +// Cycle reports the length of the inner FCPRNG cycle. +// Cycle is atmost the double (HQ: triple) of the generator period (hi - lo + 1). +func (r *FCBig) Cycle() *big.Int { + return r.cycle +} + +// Next returns the first PRN after Pos. +func (r *FCBig) Next() *big.Int { + return r.step(1) +} + +// Pos reports the current position within the inner cycle. +func (r *FCBig) Pos() *big.Int { + return r.pos +} + +// Prev return the first PRN before Pos. +func (r *FCBig) Prev() *big.Int { + return r.step(-1) +} + +// Seed uses the provided seed value to initialize the generator to a deterministic state. +// A zero seed produces a "canonical" generator with worse randomness than for most non zero seeds. +// Still, the FC property holds for any seed value. +func (r *FCBig) Seed(seed int64) { + u := uint64(seed) + r.set = mix(r.primes, &u) + n := big.NewInt(1) + v := big.NewInt(0) + pp := big.NewInt(0) + for i, p := range r.set { + k := make([]*big.Int, p) + v.SetInt64(0) + for j := range k { + k[j] = big.NewInt(0) + k[j].Set(v) + v.Add(v, n) + } + pp.SetInt64(p) + n.Mul(n, pp) + r.factors[i] = mixBig(k, &u) + } +} + +// Seek sets Pos to |pos| % Cycle. +func (r *FCBig) Seek(pos *big.Int) { + r.pos.Set(pos) + r.pos.Abs(r.pos) + r.pos.Mod(r.pos, r.cycle) + mod := big.NewInt(0) + pp := big.NewInt(0) + for i, p := range r.set { + pp.SetInt64(p) + r.mods[i] = int(mod.Mod(r.pos, pp).Int64()) + } +} + +func (r *FCBig) step(dir int) (y *big.Int) { + y = big.NewInt(0) + d := big.NewInt(int64(dir)) + for { // avg loops per step: 3/2 (HQ: 2) + r.pos.Add(r.pos, d) + switch { + case r.pos.Sign() < 0: + r.pos.Add(r.pos, r.cycle) + case r.pos.Cmp(r.cycle) >= 0: + r.pos.SetInt64(0) + } + for i, mod := range r.mods { + mod += dir + p := int(r.set[i]) + switch { + case mod < 0: + mod = p - 1 + case mod >= p: + mod = 0 + } + r.mods[i] = mod + y.Add(y, r.factors[i][mod]) + } + if y.Cmp(r.delta) <= 0 { + y.Add(y, r.lo) + return + } + y.SetInt64(0) + } +} + +func deleteBig(set []*big.Int, i int) (y []*big.Int) { + for j, v := range set { + if j != i { + y = append(y, v) + } + } + return +} + +func mixBig(set []*big.Int, seed *uint64) (y []*big.Int) { + for len(set) != 0 { + *seed = rol(*seed) + i := int(*seed % uint64(len(set))) + y = append(y, set[i]) + set = deleteBig(set, i) + } + return +} diff --git a/Godeps/_workspace/src/github.com/cznic/mathutil/tables.go b/Godeps/_workspace/src/github.com/cznic/mathutil/tables.go new file mode 100644 index 0000000..f32952c --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/mathutil/tables.go @@ -0,0 +1,6995 @@ +// Copyright (c) 2014 The mathutil Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// "Static" data + +package mathutil + +var ( + // Set bits count in a byte + popcnt = [256]byte{ + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, // 0 + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, // 1 + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, // 2 + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, // 3 + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, // 4 + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, // 5 + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, // 6 + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, // 7 + 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, // 8 + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, // 9 + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, // 10 + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, // 11 + 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, // 12 + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, // 13 + 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, // 14 + 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, // 15 + } + + // Highest set bit index in a byte + log2 = [256]int{ + -1, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, // 0 + + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 1 + + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 2 + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, // 3 + + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, // 4 + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, // 5 + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, // 6 + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, // 7 + + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 8 + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 9 + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 10 + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 11 + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 12 + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 13 + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 14 + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // 15 + } + + // "Predivisors": 2-53 + liars = [3660]uint32{ + 31621, 42799, 49141, 49981, 65077, 65281, 80581, 83333, 88357, 90751, + 104653, 130561, 164737, 188057, 194221, 196093, 215749, 219781, 220729, 253241, + 256999, 271951, 280601, 282133, 357761, 390937, 458989, 486737, 489997, 514447, + 580337, 587861, 611701, 647089, 653333, 657901, 665281, 665333, 688213, 710533, + 721801, 722261, 738541, 741751, 742813, 745889, 769757, 818201, 838861, 873181, + 877099, 916327, 976873, 983401, 1016801, 1018921, 1053761, 1064053, 1073021, 1082401, + 1109461, 1132657, 1145257, 1168513, 1194649, 1207361, 1251949, 1252697, 1302451, 1325843, + 1357441, 1373653, 1397419, 1441091, 1493857, 1507963, 1509709, 1530787, 1584133, 1678541, + 1690501, 1730977, 1735841, 1811573, 1876393, 1969417, 1987021, 2004403, 2081713, 2163001, + 2181961, 2205967, 2261953, 2264369, 2269093, 2284453, 2304167, 2387797, 2487941, 2510569, + 2670361, 2746477, 2748023, 2757241, 2811271, 2909197, 2944261, 2976487, 3048841, 3090091, + 3116107, 3125281, 3225601, 3363121, 3375041, 3400013, 3413533, 3429037, 3539101, 3542533, + 3567481, 3568661, 3605429, 3656449, 3763801, 3828001, 3898129, 3911197, 3985921, 4072729, + 4181921, 4188889, 4209661, 4360621, 4469471, 4480477, 4513841, 4835209, 4863127, 4869313, + 4877641, 4922413, 5016191, 5044033, 5095177, 5173169, 5173601, 5176153, 5256091, 5271841, + 5284333, 5351537, 5489641, 5590621, 5672041, 5919187, 6027193, 6118141, 6140161, 6159301, + 6189121, 6226193, 6233977, 6236257, 6278533, 6334351, 6368689, 6386993, 6631549, 6658669, + 6779137, 6787327, 6836233, 6952037, 6955541, 6998881, 7017193, 7232321, 7306261, 7306561, + 7429117, 7462001, 7674967, 7725901, 7759937, 7820201, 7883731, 8036033, 8095447, 8239477, + 8384513, 8534233, 8725753, 8727391, 8902741, 9006401, 9056501, 9073513, 9131401, 9345541, + 9371251, 9439201, 9480461, 9533701, 9564169, 9567673, 9588151, 9591661, 9729301, 9774181, + 9863461, 10024561, 10084177, 10323769, 10331141, 10386241, 10425511, 10610063, 10700761, 10712857, + 10763653, 10974881, 11081459, 11115037, 11335501, 11541307, 11585293, 11592397, 11777599, 12032021, + 12096613, 12263131, 12322133, 12327121, 12599233, 12854437, 13057787, 13338371, 13446253, 13500313, + 13635289, 13694761, 13747361, 13773061, 14026897, 14154337, 14179537, 14324473, 14469841, 14671801, + 14676481, 14709241, 14794081, 14796289, 14865121, 15101893, 15139199, 15162941, 15188557, 15220951, + 15247621, 15479777, 15525241, 15603391, 15621409, 15700301, 15802681, 15976747, 15978007, 16070429, + 16132321, 16149169, 16153633, 16324001, 16349477, 16360381, 16705021, 16773121, 16822081, 16843009, + 16853077, 16879501, 16973393, 17098369, 17116837, 17134043, 17208601, 17236801, 17327773, 17375249, + 17405537, 17585969, 17870561, 18067501, 18073817, 18366937, 18443701, 18454921, 18535177, 18653353, + 18740971, 19328653, 19384289, 19404139, 19471033, 19607561, 20261251, 20417311, 20647621, 20968501, + 21042001, 21303343, 21306157, 21359521, 21397381, 21400481, 21623659, 21654533, 22075579, 22087477, + 22369621, 22591301, 22669501, 22711873, 22849481, 22953673, 23247901, 23382529, 23464033, 23577497, + 23634181, 23734901, 23828017, 23872213, 23963869, 24214051, 24356377, 25080101, 25150501, 25276421, + 25326001, 25457833, 25629913, 25696133, 25768261, 25909453, 26280073, 26377921, 26821601, 26840269, + 26877421, 26886817, 27108397, 27118601, 27219697, 27271151, 27279409, 27331921, 27380831, 27392041, + 27409541, 27491237, 27509653, 27664033, 27798461, 27808463, 28325881, 28527049, 28572961, 29111881, + 29214541, 29581501, 30022129, 30090817, 30185569, 30219757, 30295141, 30338593, 30388753, 30418957, + 30576151, 30662497, 30740417, 30881551, 30894307, 31040833, 31166803, 31436123, 31735621, 31759121, + 32091781, 32095057, 32168117, 32285041, 32497921, 32676481, 33146717, 33298337, 33600533, 33627301, + 33704101, 33872593, 34003061, 34043101, 34124641, 34540801, 34856167, 34944001, 35576599, 35703361, + 35820937, 35851037, 36291193, 36307981, 36861901, 36919681, 36974341, 37109467, 37376509, 37439201, + 37964809, 37988497, 38010307, 38046817, 38118763, 38210323, 39465091, 39512773, 39655153, 39684157, + 40165093, 40238797, 40315441, 40361197, 40629601, 40782589, 40827473, 40987201, 41121433, 41568101, + 41604109, 41642681, 41662297, 41840809, 42009217, 42485119, 42623017, 42984589, 43224397, 43363601, + 43661257, 44070841, 44314129, 44465221, 44482901, 45100177, 45175201, 45219329, 45414433, 45819541, + 45879941, 46094401, 46325029, 46386589, 46469809, 46517857, 46679761, 46860001, 47220367, 47903701, + 47918581, 48064021, 48191653, 48269761, 48316969, 48400753, 48448661, 48551161, 48563089, 49075417, + 49303801, 49411801, 49459801, 50155733, 50201089, 50443201, 50523661, 51030601, 51129781, 51302353, + 51500521, 52072021, 52119289, 52204237, 53283169, 53399449, 53656021, 53675623, 53695721, 53711113, + 54029741, 54449431, 55109401, 55176097, 55318957, 55729957, 56052361, 56420033, 56479897, 56810137, + 57762433, 58003213, 58422409, 58449847, 58509977, 58679941, 58755877, 59631211, 59840537, 59913157, + 59953741, 60155201, 60352921, 60547831, 60566431, 60581401, 60696661, 60738257, 60957361, 61201009, + 61219789, 61377109, 61832377, 62756641, 63001801, 63002501, 63065281, 63167743, 63318169, 63328469, + 63346999, 63388033, 64148717, 64605041, 64735897, 65144501, 65254393, 65301013, 65350801, 65359477, + 66096253, 67194401, 67642513, 67928221, 68102641, 68154001, 68165761, 68512867, 68621701, 68839597, + 69030901, 69128641, 69176647, 69228967, 69231061, 69485281, 69612061, 69885649, 70149631, 70463489, + 70593931, 70728121, 71079661, 71734417, 72498253, 72543547, 73562833, 73645001, 74411131, 74927161, + 75140137, 75565873, 76725091, 76745101, 77533123, 77648941, 77812153, 77817979, 78939089, 79398901, + 79411201, 79417801, 79464533, 79786523, 80142761, 80146909, 80375707, 80556337, 80687881, 80891009, + 81433591, 81954133, 82273201, 82506439, 82870517, 82929001, 83083001, 83103329, 83204801, 84164033, + 84350561, 84421081, 84487457, 84998503, 85328717, 85519337, 85823401, 86027329, 86438857, 86530621, + 86999837, 87499651, 87694261, 88256449, 88368853, 88661861, 89308771, 89784581, 90270613, 90278161, + 90341197, 90665789, 90698401, 91433281, 91659283, 92438581, 92625121, 93431521, 93541537, 93571633, + 93643201, 93677761, 93926197, 94316401, 94502701, 95451361, 95452781, 96135601, 96618397, 96791881, + 96888641, 96895441, 96904081, 96925921, 97255801, 97496449, 97796953, 97863529, 97924217, 99036001, + 99115297, 99486889, 99789673, 99898801, 100463443, 100618933, 100943201, 101152133, 101218921, 101270251, + 101276579, 101649241, 102004421, 102678031, 102690677, 102690901, 103301633, 104078857, 104524421, 104988673, + 105305443, 105919633, 106485121, 106622353, 106743073, 107360641, 107543333, 108596953, 109231229, 109437751, + 109541461, 109879837, 110135821, 110139499, 110312773, 110413333, 110717861, 111370141, 111654401, 112032001, + 112402981, 112828801, 113589601, 113605201, 113730481, 113892589, 114305441, 114329881, 114701341, 114842677, + 114910489, 115039081, 115174681, 115497901, 115804501, 115873801, 116090081, 116321617, 116617289, 116682721, + 116696161, 116998669, 117987841, 118466401, 118901521, 119092801, 119204809, 119261113, 119327041, 119558011, + 119743537, 119940853, 120296677, 120517021, 120838609, 121062001, 121374241, 121472359, 121609489, 122166307, + 122396737, 122941981, 123481777, 123671671, 123877081, 123987793, 124145473, 124630273, 124818601, 125284141, + 125686241, 125848577, 126132553, 127050067, 128079409, 128124151, 128396921, 128468957, 128665319, 128987429, + 129205781, 129256273, 129357061, 129461617, 129524669, 130556329, 130693393, 130944133, 131023201, 131567929, + 131938561, 132332201, 132338881, 132440521, 132575071, 133216381, 133302781, 133467517, 133800661, 134696801, + 134767153, 134868029, 135263269, 135296053, 135308881, 135945853, 135969401, 136043641, 136661201, 136722433, + 137415821, 137763037, 138030721, 138403981, 138828821, 139295701, 139487041, 140197051, 142525333, 142922413, + 143106133, 143168581, 145348529, 146156617, 146272901, 146659801, 146843929, 146884393, 147028001, 147287141, + 148109473, 148171769, 148910653, 149389633, 150379693, 150960239, 150988753, 151533377, 151589881, 152716537, + 152922001, 152991841, 153369061, 153589801, 153754873, 153928133, 154287451, 154513633, 154944533, 155203361, + 156114061, 156532799, 157069189, 157368661, 157405249, 157725829, 158068153, 158192317, 158397247, 158496911, + 158544401, 158895281, 160348189, 160378861, 160491329, 160587841, 160672201, 160730389, 161184013, 161216021, + 161289649, 161304001, 161423377, 162026869, 162067441, 162690481, 162771337, 162776041, 163442551, 163954561, + 164111281, 165061909, 165224321, 165938653, 166082309, 166339057, 166406561, 166827943, 167579497, 167582377, + 167692141, 167881121, 168566501, 169655641, 170640961, 170782921, 170856533, 171454321, 172116181, 172436713, + 172947529, 173401621, 174479729, 176030977, 176597821, 176609441, 176977921, 177167233, 177254533, 177693521, + 177927641, 177951973, 178837201, 178956971, 179083601, 179285137, 179820257, 180115489, 180497633, 180703451, + 181285001, 181285537, 181542601, 181647497, 182383111, 183677341, 184411567, 185653333, 186183469, 186393481, + 186983521, 187050529, 187667969, 187761241, 188516329, 188985961, 189714193, 189738361, 189941761, 190212181, + 190382161, 190913297, 191233813, 191648161, 191981609, 192346153, 192857761, 193330237, 193638337, 193949641, + 194556451, 196035001, 196049701, 196231393, 198982759, 199674721, 200143351, 200753281, 201261061, 202130197, + 202156813, 202538857, 203505697, 204280501, 204582457, 204766381, 205057561, 206304961, 206453509, 206504033, + 206529737, 207008569, 207030541, 207132481, 207477001, 207618781, 208051201, 208969223, 209246701, 209404369, + 209990881, 210592873, 210842113, 213035761, 214038533, 214110541, 214852609, 214858717, 215436241, 216821881, + 217123069, 217875571, 218603617, 218642029, 218947121, 219621781, 220531501, 220883521, 221368153, 221415781, + 221884001, 222010721, 222630193, 223449463, 223625851, 223782263, 224074369, 224136013, 224769241, 224957893, + 225853633, 226359547, 226450297, 227132641, 227444101, 227475481, 228652201, 228842209, 228988033, 229589413, + 230357761, 231383461, 231405701, 231927781, 232114433, 232460821, 232771501, 233110081, 234869009, 235426913, + 235928071, 237791143, 238001653, 238833421, 240068041, 240371713, 240694513, 240785047, 241505377, 242067841, + 242650717, 242860069, 243583201, 243955141, 244883981, 245006623, 245950561, 246099317, 246282511, 246434761, + 246658441, 247318957, 247321301, 247416101, 249582481, 250436033, 250958401, 250988173, 251528401, 251663837, + 251855893, 252853921, 253610281, 253893397, 255416897, 256831433, 257590661, 258020473, 258043229, 258234401, + 258944401, 259763093, 259765747, 260156101, 260518801, 260736341, 260963389, 261186001, 261703417, 262979501, + 263428181, 264269449, 264384469, 265020001, 265584133, 265735969, 265836161, 266790481, 266925601, 270525737, + 271272569, 271763467, 271826629, 271950829, 273361789, 273480637, 274701913, 274810241, 274919401, 275283401, + 275619961, 276018913, 276131137, 276542401, 276638321, 277787141, 278943061, 279377281, 280885153, 282253141, + 282471853, 282769771, 283900961, 284166877, 284301751, 284736091, 284834299, 285820501, 286316801, 287160301, + 287449091, 287715121, 288099001, 288117721, 288735277, 290643601, 290706781, 290953921, 291088513, 291461633, + 292153681, 292290181, 292433321, 292902481, 293346637, 293847721, 293938261, 295419097, 295743017, 297624961, + 297798961, 298212601, 299367877, 299736181, 301413001, 302635351, 304080001, 307629401, 307694323, 307972801, + 308483209, 309666361, 310474249, 310978027, 311177213, 311411629, 311655829, 311671361, 312408113, 312614021, + 314184487, 315034513, 315351521, 317137969, 317365933, 317641171, 317796119, 319053281, 319374577, 319440769, + 319726177, 320326003, 321324589, 321850849, 322469701, 322941881, 324477697, 325028089, 325352101, 325546873, + 326266051, 326405713, 326469137, 326628721, 326694301, 326695141, 327073601, 327093409, 327398009, 328302901, + 329153653, 329769721, 330198331, 330759617, 331658081, 331934989, 337135501, 337420679, 337665901, 337783981, + 338125537, 338458807, 338914369, 339195097, 339492169, 339794641, 341958121, 341994131, 343017529, 343052833, + 344201441, 344255551, 344776301, 346080391, 348989101, 349752913, 350031973, 350244577, 351058753, 351177769, + 352802803, 352932337, 353815801, 353932801, 354062809, 356604421, 356836819, 357348601, 357872971, 358416577, + 359394751, 359727073, 360145633, 360375181, 360787771, 361307521, 361312337, 362569201, 363170837, 363430637, + 364550761, 365077373, 365231401, 366487201, 366532321, 366652201, 367559501, 367632301, 368016949, 368476501, + 369667561, 371011801, 371611153, 372167101, 373012777, 373533617, 373669453, 373906513, 374346361, 374988661, + 376957153, 377192353, 377334497, 377458849, 377806687, 377869031, 378792649, 379732501, 380137633, 382304161, + 384100001, 385175113, 385319089, 387072661, 388695301, 390609941, 390612221, 391014937, 392679737, 393611653, + 394723177, 396864469, 399156661, 399302581, 399647221, 400385701, 400557109, 401100881, 403095967, 403293313, + 405739681, 405782623, 407737201, 407889161, 409302001, 409458241, 410613809, 410680357, 411618241, 411851389, + 412836689, 413138881, 413429801, 413778817, 414216461, 414368641, 415200361, 415204501, 415476343, 416964241, + 417767201, 417779909, 418044563, 418226581, 418616161, 418617281, 418667401, 419184481, 420607441, 421942951, + 422429041, 422928101, 423384001, 423465001, 424175761, 424411501, 424431541, 425967301, 426174101, 426219649, + 426770437, 426783811, 427294141, 428180191, 428758201, 429135841, 429509837, 430046857, 430381921, 430646401, + 430733701, 432227449, 434042801, 435016187, 435358657, 435993301, 436465501, 437247841, 437462101, 437597101, + 437866087, 439309261, 441354497, 441650591, 441758461, 442050577, 442181291, 442543553, 444660421, 445429693, + 446414621, 446619617, 449501761, 450807481, 450866021, 450872573, 452990401, 453366029, 453967739, 454745773, + 455198563, 457274161, 457320533, 459785089, 460251733, 460585861, 461151121, 461272267, 461329601, 462587329, + 462639409, 462701513, 464012033, 464955857, 465505633, 466290949, 466758181, 467100937, 468410113, 468950021, + 470120257, 470268137, 470644021, 471535373, 471664513, 472814413, 473581057, 474892741, 474970501, 474983881, + 475723849, 478614067, 479962009, 480668347, 481153501, 481239361, 482488393, 482824669, 482921297, 483006889, + 483029821, 483945601, 484200289, 486063001, 486902929, 487896601, 488104681, 488169289, 488585521, 488656981, + 489994201, 490950461, 491738801, 493108481, 494288677, 495909871, 496109729, 496560349, 497148599, 497285713, + 498662561, 498706651, 498905189, 500747293, 501172241, 501472333, 502686713, 504870241, 505473263, 505532773, + 505798213, 506349421, 507142567, 507323521, 508606771, 509302873, 509551201, 510925609, 511098521, 511215521, + 511611673, 512330281, 514738981, 516045197, 516259657, 516764063, 517662001, 518216201, 518548801, 521501473, + 522390109, 522758233, 523756711, 526067821, 526359289, 526686889, 528013333, 528043753, 528220117, 530630701, + 531095029, 531681281, 532126801, 532758241, 532800133, 533429881, 534782293, 535252867, 535428577, 535517581, + 536003333, 536114197, 536342419, 536870911, 540207097, 540621181, 540654409, 540680141, 542497201, 542536457, + 544861633, 545550433, 545622401, 546102481, 546117301, 546322201, 548080513, 548989561, 549308761, 550132741, + 550230409, 550635373, 550853137, 551313001, 552573793, 553027201, 554487121, 554599051, 554964001, 555321007, + 555465601, 556001377, 556069849, 556095433, 556114609, 557165209, 558235109, 558900821, 558977761, 561448487, + 562367821, 563298061, 563947141, 564298489, 564689381, 565664761, 565707061, 567358513, 567596401, 568902001, + 568967221, 569332177, 569495809, 570941881, 572123521, 572228929, 572430769, 572567353, 572936869, 573817861, + 573862021, 574998841, 575326033, 576724219, 577210181, 577352641, 577613261, 579606301, 579956653, 581618143, + 582389641, 582799951, 585261637, 586706821, 587343541, 588049001, 591242653, 591822001, 592467451, 592468777, + 593682169, 593728489, 595405201, 595590841, 597537361, 597717121, 599135767, 599945293, 600893921, 601606487, + 602379181, 604584221, 605454917, 605961049, 606872449, 607148653, 607750681, 608421637, 608917753, 609361567, + 609813781, 611097401, 611374453, 611770513, 611812321, 611817421, 612006253, 613849601, 614742241, 615361183, + 615760133, 615895897, 616280897, 617087701, 619239457, 619365121, 619480601, 620169409, 620544961, 620755537, + 621769669, 622137601, 623735953, 624303241, 624732421, 625060801, 625482001, 626717471, 627886657, 628868467, + 629134081, 630496621, 630622753, 630811513, 631767943, 631974613, 633289807, 635155291, 635291077, 635319361, + 636287653, 636337073, 636936697, 638502913, 638837761, 639305921, 639807781, 640650931, 640977373, 643036321, + 643316461, 643552909, 644004817, 644453633, 644457551, 644731357, 644900257, 645556481, 648056449, 648328801, + 651011329, 651064681, 651151801, 651514753, 652469641, 653235841, 653260633, 655264369, 657732349, 659526601, + 659846021, 660095641, 660754117, 661122881, 661207177, 662134201, 663760681, 665462081, 668498321, 670976641, + 670987021, 671716921, 672103001, 672108193, 673778827, 675260477, 676359391, 678481693, 680983817, 681019921, + 681124207, 681303241, 682528687, 683316001, 683362681, 684350833, 686059921, 687741401, 689537441, 690035713, + 690562601, 691131349, 692535637, 693456521, 694116893, 696042901, 696321949, 696998251, 697821857, 698192041, + 698819711, 702683101, 705303457, 705351583, 706728377, 707691601, 709409993, 710382401, 710617861, 710721001, + 714490481, 717096641, 717653129, 717831211, 720767521, 722955773, 724160251, 724969087, 725508241, 731276521, + 732805681, 734166217, 736668013, 739444021, 739576801, 740988151, 741182401, 741214237, 742017181, 742550401, + 744500641, 745493761, 745745461, 746331041, 747406801, 748638001, 749172821, 749640161, 750632137, 751226401, + 751705597, 752186593, 753233717, 753574537, 753594001, 754020361, 754874257, 756205633, 756271909, 756980137, + 758581651, 758687581, 758901701, 759252367, 759266621, 759638881, 762699649, 763907741, 764033999, 764240611, + 765378241, 766303693, 766823797, 770201221, 770909107, 770937931, 771043201, 771337891, 772495777, 773131927, + 773807401, 775368901, 775896181, 776443769, 777218989, 781471001, 782823281, 784450393, 784777393, 784783477, + 784966297, 787085857, 787209277, 788046901, 788931361, 789082001, 790453049, 791118043, 792144161, 792145729, + 794201333, 794399041, 794937601, 795064909, 796072003, 796200901, 796560703, 797418997, 797834017, 799162561, + 799630753, 799898833, 799916101, 801093011, 801227269, 801866647, 804978721, 805505957, 805771501, 807115753, + 807218413, 808214161, 809790881, 810023881, 810455101, 811110301, 811478533, 811607777, 811730923, 815430533, + 815796413, 816024161, 816215401, 816549121, 817832329, 818401321, 819466201, 819743233, 822018961, 822531841, + 824389441, 826004467, 829512001, 830664451, 831933901, 832048447, 832127489, 832169857, 833610751, 837766217, + 839268139, 839280691, 839908217, 840749761, 841217653, 841660961, 842785841, 842824981, 842960981, 843161887, + 844545271, 845376533, 846961321, 848090377, 848755969, 849548671, 852432769, 854094781, 854868257, 855734401, + 857100421, 857902861, 858687103, 859096477, 860334301, 862082677, 862678081, 863196181, 863609113, 863984881, + 865242841, 867022747, 867110501, 867638201, 868088341, 868111597, 868691401, 870985223, 871157233, 871195561, + 871908481, 876850801, 877542481, 878492941, 878940833, 879995689, 880870513, 880922657, 883276549, 884304037, + 884952001, 886180429, 887795221, 888868441, 892740853, 893692819, 894264337, 896901461, 897087361, 897283213, + 899019353, 900736411, 901848301, 902566501, 903108821, 903390643, 905040953, 907378669, 907670501, 907711561, + 908005249, 910202509, 910867481, 911484421, 914348737, 914906539, 920375821, 920696653, 921858631, 922845241, + 923437213, 926756881, 927106561, 927877001, 929159941, 930530701, 932148253, 933729421, 935794081, 936421141, + 937675393, 938376181, 939947009, 940123801, 941056273, 941734657, 943271569, 944832533, 946034057, 946787377, + 947878081, 949317217, 949697233, 952893881, 954924013, 957600541, 957631249, 958131157, 958735681, 960269377, + 960946321, 962442001, 962489557, 962523169, 964412837, 965501857, 967266451, 967287751, 967790401, 968283247, + 968413217, 968751241, 969528337, 970586713, 971975071, 974113601, 974471243, 974774401, 975576281, 976396961, + 977483449, 979363153, 980056507, 980725201, 981484561, 983456377, 984133441, 984252001, 985052881, 985075681, + 987842101, 994133479, 995586373, 995650921, 997836841, 998489017, 998590601, 998596741, 998724481, 999828727, + 1002261781, 1003062061, 1005402133, 1005833971, 1006800829, 1008777001, 1008839999, 1009025263, 1009140161, 1011319501, + 1011333061, 1011570457, 1011909271, 1012438391, 1013833153, 1015339441, 1015626151, 1017748057, 1020515761, 1021281301, + 1022336611, 1024041853, 1024123501, 1024605121, 1025035129, 1026738161, 1027744453, 1028494429, 1034252929, 1034958601, + 1040234231, 1049584313, 1050102901, 1050535501, 1054999441, 1055009117, 1056121453, 1057426651, 1063212481, 1065508321, + 1065602281, 1066972301, 1069388497, 1070639389, 1070941987, 1071512749, 1071643249, 1072898711, 1073159281, 1073288581, + 1073484823, 1075100041, 1077133397, 1078467589, 1081798061, 1082472553, 1084241341, 1084444481, 1090858081, 1093150081, + 1093352833, 1093526353, 1094042321, 1097416321, 1098743563, 1100624857, 1101623381, 1101673501, 1102573501, 1102750013, + 1104194521, 1105038871, 1106529761, 1106580817, 1106595493, 1107138961, 1108135381, 1109304913, 1110582947, 1111205873, + 1111939201, 1112671603, 1114277221, 1116379301, 1117202557, 1117785881, 1117828001, 1117890019, 1119412321, 1120076281, + 1120981021, 1121176981, 1123406047, 1123625501, 1123727617, 1124396521, 1125038377, 1127040769, 1130933429, 1134367777, + 1138289041, 1138607233, 1139137057, 1140573601, 1142466151, 1147434289, 1148578201, 1150229761, 1151670001, 1153164097, + 1153440289, 1154343961, 1154691409, 1154987209, 1155939709, 1156761911, 1156993373, 1157839381, 1159421509, 1160844821, + 1163098249, 1163227759, 1164218641, 1165717129, 1166475601, 1166598217, 1168221121, 1168256953, 1168492417, 1173229201, + 1173545533, 1174300093, 1180970407, 1181566219, 1183338241, 1184554801, 1186325981, 1187235193, 1191153937, 1191216133, + 1192314817, 1192412033, 1192903531, 1193229577, 1193557093, 1195524181, 1196852273, 1198650961, 1198880261, 1200456577, + 1200778753, 1202142061, 1204205449, 1205606533, 1205772499, 1209998077, 1210393801, 1210562701, 1210653541, 1213619761, + 1217181061, 1217823517, 1217924159, 1219816261, 1219858921, 1220114377, 1221127013, 1222861271, 1223531677, 1223941657, + 1225128829, 1226230297, 1226855293, 1227220801, 1229491063, 1229751667, 1230446653, 1231362793, 1232445677, 1234125721, + 1234646533, 1235188597, 1235864033, 1236313501, 1236442421, 1238825569, 1242171349, 1242858317, 1249166881, 1249785941, + 1250656621, 1252236421, 1254277909, 1255665613, 1257102001, 1258903981, 1260332137, 1263293281, 1264145401, 1265477791, + 1266003461, 1266273793, 1266425101, 1267345081, 1269295201, 1269835201, 1270193401, 1270489621, 1270667353, 1272558739, + 1272866167, 1282447477, 1282568741, 1285636801, 1286298133, 1286298263, 1296613501, 1297443913, 1299072721, 1299784141, + 1299963601, 1301509249, 1301926081, 1302745481, 1306836001, 1307004641, 1307520469, 1307823661, 1308758533, 1308998741, + 1309723213, 1309983901, 1310329567, 1311255661, 1311616153, 1312332001, 1312573123, 1313396221, 1315858381, 1316169541, + 1318126321, 1318717531, 1319978701, 1319992181, 1320793813, 1321058213, 1323668917, 1325172421, 1325329297, 1328256247, + 1329174601, 1329431689, 1331973329, 1341010577, 1341926401, 1343575381, 1344597577, 1344975721, 1345514101, 1345523401, + 1347387361, 1348964401, 1350685001, 1351126261, 1352453257, 1353051517, 1356241321, 1356328121, 1357459183, 1362463807, + 1362515701, 1362742561, 1365662917, 1366587661, 1366608377, 1368769681, 1371908137, 1372681861, 1375322101, 1376799577, + 1378646179, 1379464633, 1382453333, 1383283129, 1385656829, 1386705433, 1388972353, 1389353941, 1389975149, 1391890033, + 1393851553, 1394640941, 1394746081, 1394942473, 1397357851, 1398883201, 1400859847, 1401840833, 1404008369, 1404253369, + 1406826241, 1406851249, 1409372779, 1413803197, 1414154827, 1414529533, 1415969101, 1417986901, 1421475031, 1424503849, + 1425860101, 1426319563, 1426534201, 1427771089, 1428966001, 1432354901, 1435091377, 1438648993, 1440231941, 1440922891, + 1441139641, 1441678411, 1442945689, 1443388481, 1443742273, 1446298309, 1446434677, 1446818651, 1448921633, 1451635201, + 1454282449, 1454445413, 1456527461, 1457378449, 1461307717, 1463065501, 1463178817, 1463992661, 1464568381, 1465908193, + 1465945417, 1468540477, 1468824787, 1469059481, 1469960377, 1470080501, 1470650851, 1471628401, 1472221921, 1473580001, + 1477289941, 1481626513, 1482274513, 1482876673, 1483873861, 1483918801, 1485061471, 1486564301, 1493114149, 1495190699, + 1497221281, 1497965713, 1499971457, 1499989177, 1500142001, 1501165097, 1502171117, 1502403121, 1503240559, 1503705601, + 1504139521, 1504832033, 1507746241, 1509156013, 1510870241, 1511558533, 1515175087, 1515785041, 1517039371, 1518014689, + 1518290707, 1520190341, 1521221473, 1522302121, 1526732803, 1529648231, 1529819971, 1530495289, 1532419099, 1532569681, + 1532755369, 1533343261, 1534063081, 1535020133, 1536112001, 1536251047, 1536883357, 1537433899, 1537641691, 1538012449, + 1539583921, 1539804001, 1540454761, 1540550413, 1541047813, 1541849761, 1541955409, 1544145121, 1545019813, 1545177581, + 1546106773, 1546340401, 1546508057, 1547140841, 1547543161, 1547712601, 1550924873, 1554270481, 1557118081, 1560312001, + 1560620041, 1561800833, 1565893201, 1566594551, 1567830241, 1568916311, 1574362441, 1574601601, 1577983489, 1578009401, + 1580449201, 1581576641, 1581714481, 1582783777, 1583230241, 1583658649, 1586436193, 1587650401, 1590394313, 1593706201, + 1595647351, 1595887921, 1598197201, 1602517949, 1603765021, 1603810561, 1603994701, 1609916491, 1609935913, 1612121473, + 1614508267, 1617795181, 1617921667, 1619447741, 1620646177, 1627103521, 1627898401, 1628692201, 1630062253, 1630307617, + 1631314609, 1632286673, 1632513601, 1633044241, 1636185601, 1637434657, 1637436457, 1637930893, 1638294661, 1639351981, + 1639846391, 1641971701, 1642814653, 1644637051, 1645413001, 1647225529, 1648076041, 1649430889, 1650265549, 1650682153, + 1654940509, 1655660761, 1656229921, 1656280033, 1656917377, 1659009601, 1661202113, 1668037621, 1668926629, 1669893661, + 1671603667, 1671714241, 1672125131, 1674091141, 1674658133, 1675978193, 1678274581, 1679130641, 1680901381, 1683174533, + 1685433413, 1686001861, 1687248001, 1691745821, 1692605041, 1694128129, 1695158921, 1696893101, 1698707377, 1699279441, + 1700250049, 1709909293, 1710753001, 1712392321, 1714322377, 1716160321, 1716714793, 1716774481, 1718013133, 1718088301, + 1719197621, 1721061497, 1721986313, 1722007169, 1722685777, 1725675451, 1726372441, 1731048937, 1731995497, 1732924001, + 1734059291, 1734285601, 1735071913, 1736481601, 1738687469, 1740214841, 1742288881, 1742815621, 1743166441, 1744605097, + 1746692641, 1746721681, 1749124829, 1750412161, 1754818561, 1757148121, 1760014561, 1766984389, 1767234613, 1769091241, + 1769267761, 1770236893, 1771303801, 1772267281, 1773582977, 1776439261, 1776820033, 1779649381, 1779892577, 1784306273, + 1784638309, 1785843547, 1786005521, 1787934881, 1790023861, 1791426787, 1792442737, 1792588813, 1794814103, 1801558201, + 1801774081, 1802510669, 1803768091, 1804906517, 1805947313, 1809888967, 1816408273, 1817067169, 1819829749, 1820306953, + 1821514633, 1828682101, 1828887061, 1831258601, 1835114401, 1837156049, 1837599769, 1839568981, 1841034961, 1841099261, + 1841479501, 1844028961, 1846171781, 1847811673, 1849964117, 1850233897, 1850598961, 1852496761, 1853926777, 1854084649, + 1854940231, 1856689453, 1857221281, 1858098497, 1858197961, 1860373241, 1861026133, 1861880689, 1862880401, 1866409861, + 1867906721, 1868682241, 1871987041, 1872937057, 1873177693, 1874634721, 1874849929, 1878691753, 1879111697, 1879623157, + 1879775501, 1883509633, 1883785681, 1885915841, 1894909141, 1894955311, 1897700113, 1899081757, 1899525601, 1900687381, + 1903447841, 1904658913, 1905958891, 1908088001, 1909566073, 1910134309, 1911197947, 1912950241, 1914303841, 1915391521, + 1916987593, 1917397637, 1920301951, 1921309633, 1922092567, 1922687293, 1923224689, 1923311317, 1923845801, 1924201501, + 1925042737, 1928903971, 1929862849, 1930403333, 1930447501, 1930534453, 1930915169, 1934350351, 1938264241, 1940048881, + 1943951041, 1944125633, 1945042181, 1950987193, 1952513369, 1952968753, 1957705177, 1959659857, 1960708261, 1963149553, + 1965007601, 1968002149, 1970065681, 1974474049, 1977257441, 1982123893, 1982826961, 1988071801, 1988713189, 1988835713, + 1988965861, 1989192277, 1991063449, 1995784961, 1995830761, 1996231189, 1996339649, 1997844157, 1998780001, 1999053601, + 1999111801, 1999743661, 2004299641, 2007646961, 2013554869, 2013834961, 2016481477, 2017021333, 2017509601, 2019564769, + 2021392369, 2021884343, 2027675701, 2028279793, 2028631361, 2028812399, 2029830409, 2030600833, 2036224321, 2043173273, + 2049293401, 2050617713, 2052149221, 2054711381, 2055634561, 2057267941, 2057835781, 2058072041, 2059739221, 2062612033, + 2068867841, 2070739441, 2072624761, 2076192007, 2081039297, 2081551753, 2082146617, 2083034113, 2083997441, 2085453649, + 2085882661, 2086645009, 2093300401, 2095627153, 2096046457, 2097317377, 2100292841, 2101470541, 2101744837, 2104994449, + 2106147457, 2107148761, 2114643217, 2115769633, 2115986557, 2116483027, 2116541221, 2117031263, 2117555641, 2118621097, + 2120096161, 2123601751, 2124078653, 2124691213, 2127197489, 2128104001, 2129304997, 2130134533, 2131004737, 2131811501, + 2140699681, 2140771609, 2141340833, 2144961253, 2147418113, 2147429509, 2152627801, 2154446641, 2155416251, 2156151313, + 2164282177, 2168431201, 2170282969, 2172155819, 2173499329, 2173540951, 2173579801, 2175126601, 2175406201, 2175646177, + 2177374321, 2177645557, 2178082901, 2178939221, 2180221201, 2182281601, 2182802689, 2185362233, 2187717761, 2193980881, + 2199617701, 2200115713, 2201924341, 2202101761, 2202205897, 2203649197, 2203856497, 2206095589, 2210578759, 2213431729, + 2216960929, 2217879901, 2219072017, 2224252801, 2229468697, 2231332357, 2233031701, 2240507821, 2241880033, 2241982009, + 2244932281, 2245519981, 2246762899, 2248354153, 2251732033, 2254314241, 2254757077, 2256197761, 2256748777, 2256751837, + 2262861901, 2269307587, 2274584089, 2283289681, 2284416181, 2289251669, 2289624793, 2290316377, 2290910257, 2291205461, + 2292068143, 2295209281, 2296995121, 2299190401, 2300628601, 2300795353, 2301745249, 2304120001, 2308966661, 2309241601, + 2309405617, 2311558021, 2311575001, 2315137261, 2320527613, 2323147201, 2324867399, 2329584217, 2330569541, 2331181621, + 2335341601, 2338157597, 2338728001, 2340460487, 2345907961, 2347597981, 2352371251, 2354453561, 2355230749, 2355320101, + 2355622721, 2355649921, 2355735089, 2358534361, 2360261989, 2370771181, 2370928337, 2371350101, 2372976563, 2374232977, + 2375415841, 2377166401, 2378309041, 2381782597, 2382678101, 2383164577, 2385574201, 2389072321, 2389544977, 2393708761, + 2394311233, 2398393661, 2404912501, 2411128441, 2412172153, 2412675721, 2413973071, 2422296241, 2423401681, 2425249601, + 2428648967, 2428870753, 2428986913, 2429407961, 2430697513, 2431136401, 2431144801, 2432761633, 2432860273, 2433791593, + 2434964321, 2434974433, 2435091221, 2436691321, 2437907779, 2438778413, 2442050353, 2442454561, 2443708961, 2444950561, + 2448039497, 2448374689, 2453473049, 2454285751, 2456536681, 2457846161, 2463713281, 2471205361, 2473120961, 2473189441, + 2473823353, 2474308069, 2474676949, 2476283239, 2477814193, 2478643907, 2480147521, 2480343553, 2482435981, 2482682131, + 2484408301, 2486017249, 2488420801, 2488591117, 2492480233, 2494660033, 2494984321, 2495834329, 2499327041, 2501012599, + 2501771329, 2502525637, 2504008609, 2506529257, 2506733189, 2507121037, 2508178843, 2513230891, 2516684801, 2519297089, + 2525070241, 2526566041, 2528291341, 2529410281, 2529827821, 2529854713, 2530351561, 2532630787, 2533465661, 2533797017, + 2535516173, 2537105761, 2539406281, 2539736257, 2540469901, 2541660367, 2542479481, 2544590161, 2545934077, 2548051801, + 2550139253, 2550780277, 2551365769, 2552418761, 2553272929, 2555391481, 2561945401, 2564536201, 2565186137, 2570087521, + 2571180247, 2575060949, 2575737361, 2577345541, 2582092189, 2582246701, 2582952769, 2583322381, 2584460701, 2588054401, + 2588582089, 2590663681, 2593065721, 2595276353, 2597289241, 2597294701, 2598933481, 2600611861, 2602343521, 2602378721, + 2604465013, 2604803701, 2611122229, 2611461529, 2613382201, 2614688801, 2616180821, 2617563031, 2621080741, 2621977627, + 2622993661, 2624549929, 2625903601, 2626783921, 2627284987, 2630643401, 2632605049, 2634284801, 2634804481, 2634820813, + 2638067881, 2639099233, 2642159809, 2642582251, 2646751249, 2646790033, 2648662777, 2649907201, 2650820329, 2651507713, + 2654716321, 2656494271, 2658630913, 2658696301, 2659265701, 2668095181, 2668469431, 2670972949, 2672605657, 2672651521, + 2676053333, 2677147201, 2677821121, 2678785621, 2681041843, 2682823681, 2683742491, 2684284441, 2687655169, 2688124001, + 2689427281, 2690408533, 2690867401, 2693739751, 2695115473, 2700818017, 2700891839, 2701878941, 2704957909, 2706863833, + 2707661501, 2716157989, 2716275007, 2717428033, 2719319513, 2721666817, 2721721939, 2723859001, 2725357249, 2733156029, + 2736316301, 2738184697, 2740336561, 2744329909, 2746021741, 2753333227, 2753538001, 2759392633, 2765323397, 2766006253, + 2767672189, 2769080161, 2769602333, 2774295577, 2777887297, 2778304273, 2779477741, 2781117721, 2781226477, 2786028337, + 2787998641, 2789218909, 2800352011, 2805762961, 2809635901, 2812672981, 2814748201, 2823570433, 2824256377, 2824804693, + 2824854913, 2828205397, 2832384133, 2832743713, 2837697773, 2837917633, 2840634109, 2840871041, 2841190381, 2847894377, + 2848466281, 2848722131, 2855046421, 2855071801, 2855512909, 2862066481, 2865483601, 2866005139, 2866527841, 2870377309, + 2871536561, 2872527733, 2872948321, 2874382853, 2877769501, 2881429741, 2882370481, 2885594497, 2887955533, 2890316801, + 2890414873, 2892426029, 2894667781, 2895004927, 2899294889, 2903776129, 2915953633, 2916247819, 2918295451, 2920691161, + 2923042141, 2924158001, 2929062533, 2929106753, 2930831641, 2931708097, 2932327549, 2936227603, 2936958181, 2941174897, + 2941343633, 2944555681, 2944677961, 2945208001, 2945549881, 2951136343, 2956724317, 2957320351, 2965700233, 2967053953, + 2968206601, 2974506841, 2975377429, 2976930001, 2978766341, 2980689601, 2986025677, 2987414977, 2990152901, 2993462713, + 2993495041, 2994098281, 2994415201, 2998202353, 2998919873, 3000688381, 3001561441, 3002647829, 3004443679, 3009628301, + 3011421841, 3014101261, 3015502181, 3016957381, 3017444761, 3018147217, 3018576689, 3019916461, 3025350343, 3026575553, + 3028586471, 3030393901, 3033332641, 3034402681, 3034817209, 3035375047, 3036079729, 3037295801, 3037781251, 3038880473, + 3039681457, 3041984353, 3042630533, 3048159841, 3050190163, 3056100623, 3056160929, 3057886591, 3058670677, 3059397793, + 3063685633, 3065998717, 3076505209, 3077122133, 3079496551, 3082054697, 3082068013, 3083053387, 3083537689, 3083884651, + 3088408429, 3089013313, 3091019777, 3094763851, 3099670657, 3103800701, 3112974481, 3114125071, 3115667521, 3120445697, + 3122287981, 3129914881, 3133899409, 3135040133, 3143282221, 3145410761, 3150972917, 3156599161, 3156643141, 3157579861, + 3163106953, 3166504273, 3167442721, 3170262409, 3172658653, 3175204531, 3175255717, 3178375201, 3181356263, 3181391641, + 3182606857, 3182655361, 3182891401, 3185472001, 3187035113, 3187421077, 3187939921, 3196397821, 3196431829, 3197565001, + 3197632441, 3197911001, 3197911741, 3199164901, 3205663921, 3207297773, 3208902491, 3212465437, 3215031751, 3217412881, + 3219808411, 3221580281, 3222693421, 3224143441, 3225081473, 3227082823, 3227209057, 3229131137, 3233558021, 3237992101, + 3242533897, 3248236309, 3250348417, 3250700737, 3252148621, 3257334541, 3258647809, 3258892801, 3261114601, 3263097641, + 3263568901, 3263626957, 3264820001, 3265122451, 3267417677, 3268506541, 3268841941, 3270933121, 3271999249, 3272030401, + 3272702497, 3274264033, 3275671969, 3276075709, 3277047649, 3278640289, 3280067129, 3282974857, 3287174129, 3288757249, + 3295362727, 3296403601, 3299246833, 3302322241, 3304307341, 3305829073, 3306686659, 3306957593, 3310858777, 3312489577, + 3312536569, 3313196881, 3315139717, 3320669437, 3323308501, 3323590463, 3323829169, 3328354801, 3332800021, 3334350781, + 3340214413, 3342005633, 3344191241, 3346172189, 3347908801, 3349218881, 3350993969, 3352091557, 3355382857, 3355953001, + 3357417181, 3359737921, 3360511981, 3369139201, 3371024521, 3371452921, 3371693063, 3372667121, 3373086601, 3381052177, + 3381901921, 3385842877, 3386603221, 3387014401, 3387487351, 3389030261, 3395091311, 3399205591, 3399890413, 3402234749, + 3407609221, 3407772817, 3407952169, 3408135121, 3409339393, 3411250081, 3411574801, 3411829693, 3412575097, 3415379701, + 3415832137, 3417522841, 3420143941, 3421845001, 3423222757, 3423580481, 3427050673, 3428133103, 3429457921, 3429982081, + 3430804297, 3432695921, 3432997537, 3433458073, 3434575327, 3435973837, 3440195713, 3443704261, 3449768513, 3450717901, + 3453900913, 3458257741, 3461861761, 3463907761, 3464236901, 3466158361, 3470716657, 3474335437, 3480174001, 3482161261, + 3485747521, 3489958697, 3491763493, 3492178873, 3492883081, 3493262761, 3497607433, 3504132113, 3512030497, 3512291021, + 3512369857, 3513604657, 3516565057, 3519318721, 3524086333, 3525088961, 3529119361, 3529864391, 3532687201, 3533662129, + 3533856913, 3538213381, 3542303047, 3543203333, 3548378341, 3549286001, 3549988261, 3552158521, 3553567057, 3557646401, + 3562963973, 3563340457, 3566428301, 3574891757, 3582711841, 3583249921, 3583604161, 3584800801, 3586833253, 3587553971, + 3589937261, 3590409439, 3593276353, 3594110081, 3596491907, 3596815169, 3598772761, 3602006101, 3605151241, 3611571121, + 3612298321, 3612825221, 3614770573, 3616574081, 3620631169, 3628526287, 3630596257, 3631828481, 3632452741, 3635993089, + 3649116277, 3649965281, 3650158849, 3651572609, 3656355841, 3658730893, 3662387977, 3662503093, 3663084541, 3668926801, + 3669587533, 3672754633, 3677180797, 3679657997, 3682471321, 3685647701, 3685775741, 3692307161, 3695628133, 3697278427, + 3700801861, 3705582073, 3705623281, 3708123301, 3708905341, 3709626961, 3712887289, 3713287801, 3713448769, 3718226401, + 3721486081, 3723410161, 3723699373, 3725016749, 3727828501, 3729097633, 3733761739, 3736293461, 3745192001, 3746101189, + 3749383681, 3751554581, 3751782737, 3754680403, 3756668401, 3759781369, 3760622689, 3760896133, 3762110881, 3767640601, + 3773061337, 3774337201, 3784123501, 3787491457, 3798040471, 3798626833, 3799111681, 3800084401, 3805699501, 3807112123, + 3807308269, 3807749821, 3809018947, 3813919453, 3817561777, 3817706621, 3821233121, 3827035237, 3832807681, 3833208961, + 3842941741, 3846174151, 3846532801, 3847106803, 3850058689, 3852800033, 3863326897, 3865604023, 3867183937, 3874471147, + 3874523017, 3875096893, 3875965417, 3886515361, 3886643801, 3887423437, 3887635753, 3891892421, 3891919417, 3894053311, + 3896079281, 3897241129, 3897869201, 3898906129, 3900327241, 3903711841, 3905533721, 3905876501, 3907577521, 3907752241, + 3912174421, 3914880337, 3914923211, 3915467341, 3915604421, 3915921241, 3918227437, 3922321561, 3926912669, 3929293061, + 3934940833, 3935864017, 3936123601, 3945165841, 3947233201, 3947383201, 3953408801, 3953949421, 3955572001, 3958597301, + 3958930441, 3959578801, 3960728641, 3962037061, 3966350203, 3967343161, 3971095301, 3973556837, 3979485931, 3982017601, + 3987528793, 3987960913, 3991124341, 3992697997, 3997536427, 4005660961, 4007365741, 4011996871, 4015548769, 4017684529, + 4018283501, 4020144133, 4026822577, 4027012021, 4027518961, 4028465873, 4028771849, 4031223841, 4034969401, 4034993269, + 4035498409, 4036395581, 4042538497, 4044601751, 4044884689, 4048493983, 4053267217, 4054039841, 4057195309, 4058433931, + 4059776533, 4060942381, 4061009971, 4064633821, 4067039461, 4067887501, 4068671881, 4071644893, 4075241633, 4075721921, + 4076009857, 4079665633, 4079682361, 4083376067, 4085074909, 4088147617, 4088838913, 4092929149, 4098258707, 4099180801, + 4100934241, 4103745689, 4105691393, 4108970251, 4109461709, 4109711581, 4110320663, 4113013141, 4115891893, 4117058221, + 4117447441, 4121286907, 4127050621, 4129914673, 4133928761, 4135847101, 4136916001, 4137262541, 4138838401, 4139015987, + 4150174393, 4155375349, 4157008813, 4162880401, 4166032873, 4183664101, 4185636781, 4186561633, 4187360341, 4191864013, + 4192060699, 4195843037, 4196323561, 4204344601, 4206006229, 4206295433, 4212105409, 4215885697, 4218900001, 4220122321, + 4232966251, 4234224601, 4237212061, 4243744201, 4244022301, 4244663651, 4247990917, 4250920459, 4251904273, 4255695013, + 4257003353, 4261352869, 4271267333, 4275011401, 4277526901, 4278305651, 4282867213, 4285148981, 4293088801, 4294901761, + } + + primes16 = [65536]byte{ + 2, 1, 1, 2, 1, 2, 1, 4, 3, 2, // 0-9 + 1, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 10-19 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 20-29 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 30-39 + 1, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 40-49 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 50-59 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 60-69 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 70-79 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 80-89 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 90-99 + 1, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 100-109 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 110-119 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 120-129 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 130-139 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 140-149 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 150-159 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 160-169 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 170-179 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 180-189 + 1, 2, 1, 4, 3, 2, 1, 2, 1, 12, // 190-199 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 200-209 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 210-219 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 220-229 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 230-239 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 240-249 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 250-259 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 260-269 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 270-279 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 280-289 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 290-299 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 300-309 + 1, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 310-319 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 320-329 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 330-339 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 340-349 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 350-359 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 360-369 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 370-379 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 380-389 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 390-399 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 400-409 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 410-419 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 420-429 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 430-439 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 440-449 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 450-459 + 1, 2, 1, 4, 3, 2, 1, 12, 11, 10, // 460-469 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 470-479 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 480-489 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 490-499 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 500-509 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 510-519 + 1, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 520-529 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 530-539 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 540-549 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 550-559 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 560-569 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 570-579 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 580-589 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 590-599 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 600-609 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 12, // 610-619 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 620-629 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 630-639 + 1, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 640-649 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 650-659 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 660-669 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 670-679 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 680-689 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 690-699 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 700-709 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 710-719 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 720-729 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 730-739 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 740-749 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 750-759 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 760-769 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 770-779 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 780-789 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 790-799 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 800-809 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 810-819 + 1, 2, 1, 4, 3, 2, 1, 2, 1, 10, // 820-829 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 830-839 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 840-849 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 850-859 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 860-869 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 870-879 + 1, 2, 1, 4, 3, 2, 1, 20, 19, 18, // 880-889 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 890-899 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 900-909 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 910-919 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 920-929 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 930-939 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 940-949 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 950-959 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 960-969 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 970-979 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 980-989 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 990-999 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 1000-1009 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 1010-1019 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 1020-1029 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 1030-1039 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 1040-1049 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 1050-1059 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 18, // 1060-1069 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 1070-1079 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 1080-1089 + 1, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 1090-1099 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 1100-1109 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 1110-1119 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 22, // 1120-1129 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 1130-1139 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 1140-1149 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 1150-1159 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 1160-1169 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 1170-1179 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 1180-1189 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 1190-1199 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 1200-1209 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 1210-1219 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 1220-1229 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 1230-1239 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 1240-1249 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 1250-1259 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 1260-1269 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 1270-1279 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 1280-1289 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 1290-1299 + 1, 2, 1, 4, 3, 2, 1, 12, 11, 10, // 1300-1309 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 1310-1319 + 1, 6, 5, 4, 3, 2, 1, 34, 33, 32, // 1320-1329 + 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 1330-1339 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 1340-1349 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 1350-1359 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 1360-1369 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 1370-1379 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 1380-1389 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 1390-1399 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 1400-1409 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 1410-1419 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 1420-1429 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 1430-1439 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 1440-1449 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 1450-1459 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 1460-1469 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 1470-1479 + 1, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 1480-1489 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 1490-1499 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 1500-1509 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 1510-1519 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 1520-1529 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 1530-1539 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 1540-1549 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 1550-1559 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 1560-1569 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 1570-1579 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 1580-1589 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 1590-1599 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 1600-1609 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 1610-1619 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 1620-1629 + 7, 6, 5, 4, 3, 2, 1, 20, 19, 18, // 1630-1639 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 1640-1649 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 1650-1659 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 24, // 1660-1669 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 1670-1679 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 1680-1689 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 10, // 1690-1699 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 1700-1709 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 1710-1719 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 1720-1729 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 1730-1739 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 1740-1749 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 18, // 1750-1759 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 1760-1769 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 1770-1779 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 12, // 1780-1789 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 1790-1799 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 1800-1809 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 1810-1819 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 1820-1829 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 1830-1839 + 7, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 1840-1849 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 1850-1859 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 1860-1869 + 1, 2, 1, 4, 3, 2, 1, 2, 1, 10, // 1870-1879 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 1880-1889 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 1890-1899 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 1900-1909 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 1910-1919 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 1920-1929 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 1930-1939 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 1940-1949 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 1950-1959 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 1960-1969 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 1970-1979 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 1980-1989 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 1990-1999 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 2000-2009 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 2010-2019 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 2020-2029 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 2030-2039 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 2040-2049 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 2050-2059 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 2060-2069 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 2070-2079 + 1, 2, 1, 4, 3, 2, 1, 2, 1, 10, // 2080-2089 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 2090-2099 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 2100-2109 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 2110-2119 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 2120-2129 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 2130-2139 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 2140-2149 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 2150-2159 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 2160-2169 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 24, // 2170-2179 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 2180-2189 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 2190-2199 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 2200-2209 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 2210-2219 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 2220-2229 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 2230-2239 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 2240-2249 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 2250-2259 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 2260-2269 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 2270-2279 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 2280-2289 + 3, 2, 1, 4, 3, 2, 1, 12, 11, 10, // 2290-2299 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 2300-2309 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 2310-2319 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 2320-2329 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 2330-2339 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 2340-2349 + 1, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 2350-2359 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 2360-2369 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 2370-2379 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 2380-2389 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 2390-2399 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 2400-2409 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 2410-2419 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 2420-2429 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 2430-2439 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 2440-2449 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 2450-2459 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 2460-2469 + 3, 2, 1, 4, 3, 2, 1, 26, 25, 24, // 2470-2479 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 2480-2489 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 2490-2499 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 2500-2509 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 2510-2519 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 2520-2529 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 2530-2539 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 2540-2549 + 1, 6, 5, 4, 3, 2, 1, 22, 21, 20, // 2550-2559 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 2560-2569 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 2570-2579 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 2580-2589 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 2590-2599 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 2600-2609 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 2610-2619 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 2620-2629 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 2630-2639 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 2640-2649 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 2650-2659 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 2660-2669 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 2670-2679 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 2680-2689 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 2690-2699 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 2700-2709 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 2710-2719 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 2720-2729 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 2730-2739 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 2740-2749 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 2750-2759 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 2760-2769 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 2770-2779 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 2780-2789 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 2790-2799 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 2800-2809 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 2810-2819 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 2820-2829 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 2830-2839 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 2840-2849 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 2850-2859 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 2860-2869 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 2870-2879 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 2880-2889 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 2890-2899 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 2900-2909 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 2910-2919 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 2920-2929 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 2930-2939 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 2940-2949 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 2950-2959 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 2960-2969 + 1, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 2970-2979 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 2980-2989 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 2990-2999 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 3000-3009 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 3010-3019 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 3020-3029 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 3030-3039 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 3040-3049 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 3050-3059 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 3060-3069 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 3070-3079 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 20, // 3080-3089 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 3090-3099 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 3100-3109 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 3110-3119 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 3120-3129 + 7, 6, 5, 4, 3, 2, 1, 26, 25, 24, // 3130-3139 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 3140-3149 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 3150-3159 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 12, // 3160-3169 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 3170-3179 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 3180-3189 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 3190-3199 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 3200-3209 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 3210-3219 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 22, // 3220-3229 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 3230-3239 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 3240-3249 + 1, 2, 1, 4, 3, 2, 1, 2, 1, 12, // 3250-3259 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 3260-3269 + 1, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 3270-3279 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 3280-3289 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 3290-3299 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 3300-3309 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 3310-3319 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 3320-3329 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 3330-3339 + 3, 2, 1, 4, 3, 2, 1, 12, 11, 10, // 3340-3349 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 3350-3359 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 3360-3369 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 3370-3379 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 3380-3389 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 3390-3399 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 3400-3409 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 3410-3419 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 3420-3429 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 3430-3439 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 3440-3449 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 3450-3459 + 1, 2, 1, 4, 3, 2, 1, 2, 1, 22, // 3460-3469 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 3470-3479 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 3480-3489 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 3490-3499 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 3500-3509 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 3510-3519 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 3520-3529 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 3530-3539 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 3540-3549 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 3550-3559 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 3560-3569 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 3570-3579 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 3580-3589 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 3590-3599 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 3600-3609 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 3610-3619 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 3620-3629 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 3630-3639 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 3640-3649 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 3650-3659 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 3660-3669 + 1, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 3670-3679 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 3680-3689 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 3690-3699 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 3700-3709 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 3710-3719 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 3720-3729 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 22, // 3730-3739 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 3740-3749 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 3750-3759 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 3760-3769 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 3770-3779 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 3780-3789 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 3790-3799 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 3800-3809 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 3810-3819 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 3820-3829 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 3830-3839 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 3840-3849 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 3850-3859 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 3860-3869 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 3870-3879 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 3880-3889 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 3890-3899 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 3900-3909 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 3910-3919 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 3920-3929 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 3930-3939 + 3, 2, 1, 4, 3, 2, 1, 20, 19, 18, // 3940-3949 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 3950-3959 + 7, 6, 5, 4, 3, 2, 1, 22, 21, 20, // 3960-3969 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 3970-3979 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 3980-3989 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 3990-3999 + 1, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 4000-4009 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 4010-4019 + 1, 6, 5, 4, 3, 2, 1, 22, 21, 20, // 4020-4029 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 4030-4039 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 4040-4049 + 1, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 4050-4059 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 4060-4069 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 4070-4079 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 4080-4089 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 4090-4099 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 4100-4109 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 4110-4119 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 4120-4129 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 14, // 4130-4139 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 4140-4149 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 18, // 4150-4159 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 4160-4169 + 7, 6, 5, 4, 3, 2, 1, 24, 23, 22, // 4170-4179 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 4180-4189 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 4190-4199 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 4200-4209 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 4210-4219 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 4220-4229 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 4230-4239 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 4240-4249 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 4250-4259 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 4260-4269 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 4270-4279 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 4280-4289 + 7, 6, 5, 4, 3, 2, 1, 30, 29, 28, // 4290-4299 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 4300-4309 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 4310-4319 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 4320-4329 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 4330-4339 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 4340-4349 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 4350-4359 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 4360-4369 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 4370-4379 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 4380-4389 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 4390-4399 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 4400-4409 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 4410-4419 + 1, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 4420-4429 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 4430-4439 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 4440-4449 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 4450-4459 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 4460-4469 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 4470-4479 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 4480-4489 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 4490-4499 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 4500-4509 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 4510-4519 + 3, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 4520-4529 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 4530-4539 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 4540-4549 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 4550-4559 + 1, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 4560-4569 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 4570-4579 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 4580-4589 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 4590-4599 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 4600-4609 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 4610-4619 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 4620-4629 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 4630-4639 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 4640-4649 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 4650-4659 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 4660-4669 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 4670-4679 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 4680-4689 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 4690-4699 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 4700-4709 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 4710-4719 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 4720-4729 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 4730-4739 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 4740-4749 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 24, // 4750-4759 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 4760-4769 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 4770-4779 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 4780-4789 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 4790-4799 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 4800-4809 + 3, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 4810-4819 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 4820-4829 + 1, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 4830-4839 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 4840-4849 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 4850-4859 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 4860-4869 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 4870-4879 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 4880-4889 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 4890-4899 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 4900-4909 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 4910-4919 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 4920-4929 + 1, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 4930-4939 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 4940-4949 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 4950-4959 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 4960-4969 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 4970-4979 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 4980-4989 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 4990-4999 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 5000-5009 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 5010-5019 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 5020-5029 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 5030-5039 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 5040-5049 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 5050-5059 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 5060-5069 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 5070-5079 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 5080-5089 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 5090-5099 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 5100-5109 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 28, // 5110-5119 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 5120-5129 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 5130-5139 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 5140-5149 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 5150-5159 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 5160-5169 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 5170-5179 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 5180-5189 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 5190-5199 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 5200-5209 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 5210-5219 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 5220-5229 + 1, 2, 1, 4, 3, 2, 1, 24, 23, 22, // 5230-5239 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 5240-5249 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 5250-5259 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 5260-5269 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 5270-5279 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 5280-5289 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 5290-5299 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 14, // 5300-5309 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 5310-5319 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 5320-5329 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 5330-5339 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 5340-5349 + 1, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 5350-5359 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 5360-5369 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 5370-5379 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 5380-5389 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 5390-5399 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 5400-5409 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 12, // 5410-5419 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 5420-5429 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 5430-5439 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 22, // 5440-5449 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 5450-5459 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 5460-5469 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 5470-5479 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 5480-5489 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 5490-5499 + 1, 2, 1, 4, 3, 2, 1, 12, 11, 10, // 5500-5509 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 5510-5519 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 5520-5529 + 1, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 5530-5539 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 5540-5549 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 5550-5559 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 5560-5569 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 5570-5579 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 5580-5589 + 1, 32, 31, 30, 29, 28, 27, 26, 25, 24, // 5590-5599 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 5600-5609 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 5610-5619 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 5620-5629 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 5630-5639 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 5640-5649 + 1, 2, 1, 4, 3, 2, 1, 2, 1, 10, // 5650-5659 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 5660-5669 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 5670-5679 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 5680-5689 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 5690-5699 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 5700-5709 + 1, 6, 5, 4, 3, 2, 1, 20, 19, 18, // 5710-5719 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 5720-5729 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 5730-5739 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 30, // 5740-5749 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 5750-5759 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 5760-5769 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 5770-5779 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 5780-5789 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 5790-5799 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 5800-5809 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 5810-5819 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 5820-5829 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 5830-5839 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 5840-5849 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 5850-5859 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 5860-5869 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 5870-5879 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 5880-5889 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 5890-5899 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 5900-5909 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 5910-5919 + 3, 2, 1, 4, 3, 2, 1, 12, 11, 10, // 5920-5929 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 5930-5939 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 5940-5949 + 3, 2, 1, 28, 27, 26, 25, 24, 23, 22, // 5950-5959 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 5960-5969 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 5970-5979 + 1, 6, 5, 4, 3, 2, 1, 20, 19, 18, // 5980-5989 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 5990-5999 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 6000-6009 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 6010-6019 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 6020-6029 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 6030-6039 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 6040-6049 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 6050-6059 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 6060-6069 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 6070-6079 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 6080-6089 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 6090-6099 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 6100-6109 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 6110-6119 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 6120-6129 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 6130-6139 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 6140-6149 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 6150-6159 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 6160-6169 + 3, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 6170-6179 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 6180-6189 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 6190-6199 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 6200-6209 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 6210-6219 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 6220-6229 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 6230-6239 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 6240-6249 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 6250-6259 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 6260-6269 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 6270-6279 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 6280-6289 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 6290-6299 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 6300-6309 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 6310-6319 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 6320-6329 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 6330-6339 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 6340-6349 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 6350-6359 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 6360-6369 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 6370-6379 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 6380-6389 + 7, 6, 5, 4, 3, 2, 1, 24, 23, 22, // 6390-6399 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 6400-6409 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 6410-6419 + 1, 6, 5, 4, 3, 2, 1, 22, 21, 20, // 6420-6429 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 6430-6439 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 6440-6449 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 6450-6459 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 6460-6469 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 6470-6479 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 6480-6489 + 1, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 6490-6499 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 6500-6509 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 6510-6519 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 6520-6529 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 6530-6539 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 6540-6549 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 6550-6559 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 6560-6569 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 6570-6579 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 6580-6589 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 6590-6599 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 6600-6609 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 6610-6619 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 6620-6629 + 7, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 6630-6639 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 6640-6649 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 6650-6659 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 6660-6669 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 6670-6679 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 6680-6689 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 6690-6699 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 6700-6709 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 6710-6719 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 6720-6729 + 3, 2, 1, 4, 3, 2, 1, 24, 23, 22, // 6730-6739 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 6740-6749 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 6750-6759 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 6760-6769 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 6770-6779 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 6780-6789 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 6790-6799 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 6800-6809 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 6810-6819 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 6820-6829 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 6830-6839 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 6840-6849 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 6850-6859 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 6860-6869 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 6870-6879 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 6880-6889 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 6890-6899 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 6900-6909 + 1, 6, 5, 4, 3, 2, 1, 30, 29, 28, // 6910-6919 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 6920-6929 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 6930-6939 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 6940-6949 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 6950-6959 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 6960-6969 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 6970-6979 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 6980-6989 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 6990-6999 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 7000-7009 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 7010-7019 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 7020-7029 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 7030-7039 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 7040-7049 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 7050-7059 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 7060-7069 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 24, // 7070-7079 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 7080-7089 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 7090-7099 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 7100-7109 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 7110-7119 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 22, // 7120-7129 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 7130-7139 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 7140-7149 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 7150-7159 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 7160-7169 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 7170-7179 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 7180-7189 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 7190-7199 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 7200-7209 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 7210-7219 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 7220-7229 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 7230-7239 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 7240-7249 + 3, 2, 1, 30, 29, 28, 27, 26, 25, 24, // 7250-7259 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 7260-7269 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 7270-7279 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 7280-7289 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 7290-7299 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 7300-7309 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 7310-7319 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 7320-7329 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 7330-7339 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 7340-7349 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 7350-7359 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 24, // 7360-7369 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 7370-7379 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 7380-7389 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 7390-7399 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 7400-7409 + 1, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 7410-7419 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 7420-7429 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 7430-7439 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 7440-7449 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 18, // 7450-7459 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 7460-7469 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 7470-7479 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 7480-7489 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 7490-7499 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 7500-7509 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 7510-7519 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 7520-7529 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 7530-7539 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 7540-7549 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 7550-7559 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 7560-7569 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 7570-7579 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 7580-7589 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 7590-7599 + 3, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 7600-7609 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 7610-7619 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 7620-7629 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 7630-7639 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 20, // 7640-7649 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 7650-7659 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 7660-7669 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 7670-7679 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 7680-7689 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 7690-7699 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 7700-7709 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 7710-7719 + 3, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 7720-7729 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 7730-7739 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 7740-7749 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 30, // 7750-7759 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 7760-7769 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 7770-7779 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 7780-7789 + 3, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 7790-7799 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 7800-7809 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 7810-7819 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 7820-7829 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 7830-7839 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 7840-7849 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 7850-7859 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 7860-7869 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 7870-7879 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 7880-7889 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 7890-7899 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 7900-7909 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 7910-7919 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 7920-7929 + 3, 2, 1, 4, 3, 2, 1, 12, 11, 10, // 7930-7939 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 7940-7949 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 7950-7959 + 3, 2, 1, 30, 29, 28, 27, 26, 25, 24, // 7960-7969 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 7970-7979 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 7980-7989 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 7990-7999 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 8000-8009 + 1, 6, 5, 4, 3, 2, 1, 22, 21, 20, // 8010-8019 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 8020-8029 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 8030-8039 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 8040-8049 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 8050-8059 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 8060-8069 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 8070-8079 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 8080-8089 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 8090-8099 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 8100-8109 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 8110-8119 + 3, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 8120-8129 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 8130-8139 + 7, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 8140-8149 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 8150-8159 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 8160-8169 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 8170-8179 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 8180-8189 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 8190-8199 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 8200-8209 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 8210-8219 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 8220-8229 + 1, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 8230-8239 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 8240-8249 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 8250-8259 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 8260-8269 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 8270-8279 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 8280-8289 + 1, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 8290-8299 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 8300-8309 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 8310-8319 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 24, // 8320-8329 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 8330-8339 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 8340-8349 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 8350-8359 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 8360-8369 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 8370-8379 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 30, // 8380-8389 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 8390-8399 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 8400-8409 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 8410-8419 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 8420-8429 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 8430-8439 + 3, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 8440-8449 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 8450-8459 + 1, 6, 5, 4, 3, 2, 1, 34, 33, 32, // 8460-8469 + 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 8470-8479 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 8480-8489 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 8490-8499 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 8500-8509 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 8510-8519 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 8520-8529 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 8530-8539 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 8540-8549 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 8550-8559 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 8560-8569 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 8570-8579 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 8580-8589 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 8590-8599 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 8600-8609 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 8610-8619 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 12, // 8620-8629 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 8630-8639 + 1, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 8640-8649 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 8650-8659 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 8660-8669 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 8670-8679 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 8680-8689 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 8690-8699 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 8700-8709 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 8710-8719 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 8720-8729 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 8730-8739 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 8740-8749 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 8750-8759 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 8760-8769 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 8770-8779 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 8780-8789 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 8790-8799 + 3, 2, 1, 4, 3, 2, 1, 12, 11, 10, // 8800-8809 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 8810-8819 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 8820-8829 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 8830-8839 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 8840-8849 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 8850-8859 + 1, 2, 1, 4, 3, 2, 1, 20, 19, 18, // 8860-8869 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 8870-8879 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 8880-8889 + 3, 2, 1, 30, 29, 28, 27, 26, 25, 24, // 8890-8899 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 8900-8909 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 8910-8919 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 8920-8929 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 8930-8939 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 8940-8949 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 8950-8959 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 8960-8969 + 1, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 8970-8979 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 8980-8989 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 8990-8999 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 9000-9009 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 9010-9019 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 9020-9029 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 9030-9039 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 9040-9049 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 9050-9059 + 7, 6, 5, 4, 3, 2, 1, 24, 23, 22, // 9060-9069 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 9070-9079 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 9080-9089 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 9090-9099 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 18, // 9100-9109 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 9110-9119 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 9120-9129 + 3, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 9130-9139 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 9140-9149 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 9150-9159 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 9160-9169 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 9170-9179 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 9180-9189 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 9190-9199 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 9200-9209 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 9210-9219 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 9220-9229 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 9230-9239 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 9240-9249 + 7, 6, 5, 4, 3, 2, 1, 20, 19, 18, // 9250-9259 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 9260-9269 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 9270-9279 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 9280-9289 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 9290-9299 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 9300-9309 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 9310-9319 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 9320-9329 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 9330-9339 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 22, // 9340-9349 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 9350-9359 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 9360-9369 + 1, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 9370-9379 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 9380-9389 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 9390-9399 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 9400-9409 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 9410-9419 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 9420-9429 + 1, 2, 1, 4, 3, 2, 1, 2, 1, 22, // 9430-9439 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 9440-9449 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 9450-9459 + 1, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 9460-9469 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 9470-9479 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 9480-9489 + 1, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 9490-9499 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 9500-9509 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 9510-9519 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 9520-9529 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 9530-9539 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 9540-9549 + 1, 36, 35, 34, 33, 32, 31, 30, 29, 28, // 9550-9559 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 9560-9569 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 9570-9579 + 7, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 9580-9589 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 9590-9599 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 9600-9609 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 9610-9619 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 9620-9629 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 9630-9639 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 9640-9649 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 9650-9659 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 9660-9669 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 9670-9679 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 9680-9689 + 7, 6, 5, 4, 3, 2, 1, 22, 21, 20, // 9690-9699 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 9700-9709 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 9710-9719 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 9720-9729 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 9730-9739 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 18, // 9740-9749 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 9750-9759 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 9760-9769 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 9770-9779 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 9780-9789 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 9790-9799 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 9800-9809 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 9810-9819 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 9820-9829 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 9830-9839 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 9840-9849 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 9850-9859 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 9860-9869 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 9870-9879 + 3, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 9880-9889 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 9890-9899 + 1, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 9900-9909 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 9910-9919 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 9920-9929 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 9930-9939 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 9940-9949 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 9950-9959 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 9960-9969 + 3, 2, 1, 34, 33, 32, 31, 30, 29, 28, // 9970-9979 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 9980-9989 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 9990-9999 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 28, // 10000-10009 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 10010-10019 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 10020-10029 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 22, // 10030-10039 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 10040-10049 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 10050-10059 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 10060-10069 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 10070-10079 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 10080-10089 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 10090-10099 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 10100-10109 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 10110-10119 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 10120-10129 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 10130-10139 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 10140-10149 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 10150-10159 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 10160-10169 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 10170-10179 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 10180-10189 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 10190-10199 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 10200-10209 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 10210-10219 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 10220-10229 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 10230-10239 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 10240-10249 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 10250-10259 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 10260-10269 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 10270-10279 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 10280-10289 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 10290-10299 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 10300-10309 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 10310-10319 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 10320-10329 + 1, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 10330-10339 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 10340-10349 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 10350-10359 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 22, // 10360-10369 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 10370-10379 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 10380-10389 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 28, // 10390-10399 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 10400-10409 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 10410-10419 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 10420-10429 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 10430-10439 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 10440-10449 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 10450-10459 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 10460-10469 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 10470-10479 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 10480-10489 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 10490-10499 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 10500-10509 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 10510-10519 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 10520-10529 + 1, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 10530-10539 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 10540-10549 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 10550-10559 + 7, 6, 5, 4, 3, 2, 1, 22, 21, 20, // 10560-10569 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 10570-10579 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 10580-10589 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 10590-10599 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 10600-10609 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 10610-10619 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 10620-10629 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 10630-10639 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 10640-10649 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 10650-10659 + 3, 2, 1, 4, 3, 2, 1, 20, 19, 18, // 10660-10669 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 10670-10679 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 10680-10689 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 10690-10699 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 10700-10709 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 10710-10719 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 10720-10729 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 14, // 10730-10739 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 10740-10749 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 10750-10759 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 10760-10769 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 10770-10779 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 10780-10789 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 32, // 10790-10799 + 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 10800-10809 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 10810-10819 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 10820-10829 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 10830-10839 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 10840-10849 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 10850-10859 + 1, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 10860-10869 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 10870-10879 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 10880-10889 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 10890-10899 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 28, // 10900-10909 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 10910-10919 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 10920-10929 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 10930-10939 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 10940-10949 + 7, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 10950-10959 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 10960-10969 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 10970-10979 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 10980-10989 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 10990-10999 + 3, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 11000-11009 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 11010-11019 + 7, 6, 5, 4, 3, 2, 1, 20, 19, 18, // 11020-11029 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 11030-11039 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 11040-11049 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 11050-11059 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 11060-11069 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 11070-11079 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 11080-11089 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 11090-11099 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 11100-11109 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 12, // 11110-11119 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 11120-11129 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 11130-11139 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 11140-11149 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 11150-11159 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 11160-11169 + 1, 2, 1, 4, 3, 2, 1, 20, 19, 18, // 11170-11179 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 11180-11189 + 7, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 11190-11199 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 11200-11209 + 3, 2, 1, 26, 25, 24, 23, 22, 21, 20, // 11210-11219 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 11220-11229 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 11230-11239 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 11240-11249 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 11250-11259 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 11260-11269 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 11270-11279 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 11280-11289 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 11290-11299 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 11300-11309 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 11310-11319 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 22, // 11320-11329 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 11330-11339 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 11340-11349 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 11350-11359 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 11360-11369 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 11370-11379 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 11380-11389 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 11390-11399 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 11400-11409 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 11410-11419 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 11420-11429 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 11430-11439 + 3, 2, 1, 4, 3, 2, 1, 20, 19, 18, // 11440-11449 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 11450-11459 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 11460-11469 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 11470-11479 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 11480-11489 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 11490-11499 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 11500-11509 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 11510-11519 + 7, 6, 5, 4, 3, 2, 1, 22, 21, 20, // 11520-11529 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 11530-11539 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 11540-11549 + 1, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 11550-11559 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 11560-11569 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 11570-11579 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 11580-11589 + 3, 2, 1, 4, 3, 2, 1, 20, 19, 18, // 11590-11599 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 11600-11609 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 11610-11619 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 11620-11629 + 3, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 11630-11639 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 11640-11649 + 7, 6, 5, 4, 3, 2, 1, 20, 19, 18, // 11650-11659 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 11660-11669 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 11670-11679 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 11680-11689 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 11690-11699 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 11700-11709 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 11710-11719 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 11720-11729 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 11730-11739 + 3, 2, 1, 34, 33, 32, 31, 30, 29, 28, // 11740-11749 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 11750-11759 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 11760-11769 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 11770-11779 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 11780-11789 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 11790-11799 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 11800-11809 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 11810-11819 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 11820-11829 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 24, // 11830-11839 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 11840-11849 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 11850-11859 + 3, 2, 1, 4, 3, 2, 1, 20, 19, 18, // 11860-11869 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 11870-11879 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 11880-11889 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 11890-11899 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 14, // 11900-11909 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 11910-11919 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 11920-11929 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 11930-11939 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 11940-11949 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 11950-11959 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 11960-11969 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 11970-11979 + 1, 6, 5, 4, 3, 2, 1, 20, 19, 18, // 11980-11989 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 11990-11999 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 12000-12009 + 1, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 12010-12019 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 12020-12029 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 12030-12039 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 22, // 12040-12049 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 12050-12059 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 12060-12069 + 1, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 12070-12079 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 12080-12089 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 12090-12099 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 12100-12109 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 24, // 12110-12119 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 12120-12129 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 12130-12139 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 12140-12149 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 12150-12159 + 1, 2, 1, 34, 33, 32, 31, 30, 29, 28, // 12160-12169 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 12170-12179 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 12180-12189 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 12190-12199 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 12200-12209 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 12210-12219 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 12220-12229 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 12230-12239 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 12240-12249 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 12250-12259 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 12260-12269 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 12270-12279 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 12280-12289 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 12290-12299 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 12300-12309 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 12310-12319 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 14, // 12320-12329 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 12330-12339 + 3, 2, 1, 4, 3, 2, 1, 26, 25, 24, // 12340-12349 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 12350-12359 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 12360-12369 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 12, // 12370-12379 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 12380-12389 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 12390-12399 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 12400-12409 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 12410-12419 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 12420-12429 + 3, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 12430-12439 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 12440-12449 + 1, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 12450-12459 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 12460-12469 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 12470-12479 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 12480-12489 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 12490-12499 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 12500-12509 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 12510-12519 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 12520-12529 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 12530-12539 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 12540-12549 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 12550-12559 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 12560-12569 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 12570-12579 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 12580-12589 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 12590-12599 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 12600-12609 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 18, // 12610-12619 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 12620-12629 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 12630-12639 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 12640-12649 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 12650-12659 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 12660-12669 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 12670-12679 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 12680-12689 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 12690-12699 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 12700-12709 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 12710-12719 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 12720-12729 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 12730-12739 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 12740-12749 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 12750-12759 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 12760-12769 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 12770-12779 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 12780-12789 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 12790-12799 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 12800-12809 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 12810-12819 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 12820-12829 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 12830-12839 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 12840-12849 + 3, 2, 1, 36, 35, 34, 33, 32, 31, 30, // 12850-12859 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 12860-12869 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 12870-12879 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 12880-12889 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 12890-12899 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 12900-12909 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 12910-12919 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 12920-12929 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 12930-12939 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 12940-12949 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 12950-12959 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 12960-12969 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 12970-12979 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 12980-12989 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 12990-12999 + 1, 2, 1, 4, 3, 2, 1, 2, 1, 24, // 13000-13009 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 13010-13019 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 13020-13029 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 13030-13039 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 14, // 13040-13049 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 13050-13059 + 3, 2, 1, 30, 29, 28, 27, 26, 25, 24, // 13060-13069 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 13070-13079 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 13080-13089 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 13090-13099 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 13100-13109 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 13110-13119 + 1, 6, 5, 4, 3, 2, 1, 20, 19, 18, // 13120-13129 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 13130-13139 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 13140-13149 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 13150-13159 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 13160-13169 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 13170-13179 + 3, 2, 1, 4, 3, 2, 1, 30, 29, 28, // 13180-13189 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 13190-13199 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 13200-13209 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 13210-13219 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 13220-13229 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 13230-13239 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 13240-13249 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 13250-13259 + 7, 6, 5, 4, 3, 2, 1, 24, 23, 22, // 13260-13269 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 13270-13279 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 13280-13289 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 13290-13299 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 13300-13309 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 13310-13319 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 13320-13329 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 28, // 13330-13339 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 13340-13349 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 13350-13359 + 7, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 13360-13369 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 13370-13379 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 13380-13389 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 13390-13399 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 13400-13409 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 13410-13419 + 1, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 13420-13429 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 13430-13439 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 13440-13449 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 13450-13459 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 13460-13469 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 13470-13479 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 13480-13489 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 13490-13499 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 13500-13509 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 13510-13519 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 13520-13529 + 7, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 13530-13539 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 13540-13549 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 13550-13559 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 13560-13569 + 7, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 13570-13579 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 13580-13589 + 1, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 13590-13599 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 13600-13609 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 13610-13619 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 13620-13629 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 13630-13639 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 20, // 13640-13649 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 13650-13659 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 13660-13669 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 13670-13679 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 13680-13689 + 1, 2, 1, 4, 3, 2, 1, 12, 11, 10, // 13690-13699 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 13700-13709 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 13710-13719 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 22, // 13720-13729 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 13730-13739 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 13740-13749 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 13750-13759 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 13760-13769 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 13770-13779 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 13780-13789 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 13790-13799 + 7, 6, 5, 4, 3, 2, 1, 22, 21, 20, // 13800-13809 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 13810-13819 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 13820-13829 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 13830-13839 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 13840-13849 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 13850-13859 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 13860-13869 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 13870-13879 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 13880-13889 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 13890-13899 + 1, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 13900-13909 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 13910-13919 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 13920-13929 + 1, 2, 1, 30, 29, 28, 27, 26, 25, 24, // 13930-13939 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 13940-13949 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 13950-13959 + 3, 2, 1, 4, 3, 2, 1, 30, 29, 28, // 13960-13969 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 13970-13979 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 13980-13989 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 13990-13999 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 14000-14009 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 14010-14019 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 14020-14029 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 14030-14039 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 14040-14049 + 1, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 14050-14059 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 14060-14069 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 14070-14079 + 1, 2, 1, 4, 3, 2, 1, 20, 19, 18, // 14080-14089 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 14090-14099 + 7, 6, 5, 4, 3, 2, 1, 36, 35, 34, // 14100-14109 + 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, // 14110-14119 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 14120-14129 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 14130-14139 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 14140-14149 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 14, // 14150-14159 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 14160-14169 + 3, 2, 1, 4, 3, 2, 1, 20, 19, 18, // 14170-14179 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 14180-14189 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 14190-14199 + 7, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 14200-14209 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 14210-14219 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 14220-14229 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 14230-14239 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 14240-14249 + 1, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 14250-14259 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 14260-14269 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 14270-14279 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 14280-14289 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 14290-14299 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 14300-14309 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 14310-14319 + 1, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 14320-14329 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 14330-14339 + 1, 6, 5, 4, 3, 2, 1, 22, 21, 20, // 14340-14349 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 14350-14359 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 14360-14369 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 14370-14379 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 14380-14389 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 14390-14399 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 14400-14409 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 14410-14419 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 14420-14429 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 14430-14439 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 14440-14449 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 14450-14459 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 14460-14469 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 14470-14479 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 14480-14489 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 14490-14499 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 14500-14509 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 14510-14519 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 14520-14529 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 14530-14539 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 14540-14549 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 14550-14559 + 1, 2, 1, 28, 27, 26, 25, 24, 23, 22, // 14560-14569 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 14570-14579 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 14580-14589 + 1, 2, 1, 28, 27, 26, 25, 24, 23, 22, // 14590-14599 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 14600-14609 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 14610-14619 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 14620-14629 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 14, // 14630-14639 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 14640-14649 + 3, 2, 1, 4, 3, 2, 1, 12, 11, 10, // 14650-14659 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 14660-14669 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 14670-14679 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 14680-14689 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 14690-14699 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 14700-14709 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 14710-14719 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 14720-14729 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 14730-14739 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 14740-14749 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 14750-14759 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 14760-14769 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 14770-14779 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 14780-14789 + 7, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 14790-14799 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 14800-14809 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 14810-14819 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 14820-14829 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 14830-14839 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 14840-14849 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 14850-14859 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 14860-14869 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 14870-14879 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 14880-14889 + 1, 6, 5, 4, 3, 2, 1, 26, 25, 24, // 14890-14899 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 14900-14909 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 14910-14919 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 14920-14929 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 14930-14939 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 14940-14949 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 14950-14959 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 14960-14969 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 14970-14979 + 3, 2, 1, 30, 29, 28, 27, 26, 25, 24, // 14980-14989 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 14990-14999 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 15000-15009 + 3, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 15010-15019 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 15020-15029 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 15030-15039 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 15040-15049 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 15050-15059 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 15060-15069 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 15070-15079 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 15080-15089 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 15090-15099 + 1, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 15100-15109 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 15110-15119 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 15120-15129 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 15130-15139 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 15140-15149 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 15150-15159 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 15160-15169 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 15170-15179 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 15180-15189 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 18, // 15190-15199 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 15200-15209 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 15210-15219 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 15220-15229 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 15230-15239 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 15240-15249 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 15250-15259 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 15260-15269 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 15270-15279 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 15280-15289 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 15290-15299 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 15300-15309 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 15310-15319 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 15320-15329 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 15330-15339 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 15340-15349 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 15350-15359 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 15360-15369 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 15370-15379 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 15380-15389 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 15390-15399 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 15400-15409 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 15410-15419 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 15420-15429 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 15430-15439 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 15440-15449 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 15450-15459 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 15460-15469 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 15470-15479 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 15480-15489 + 3, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 15490-15499 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 15500-15509 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 15510-15519 + 7, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 15520-15529 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 15530-15539 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 15540-15549 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 15550-15559 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 15560-15569 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 15570-15579 + 1, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 15580-15589 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 15590-15599 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 15600-15609 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 15610-15619 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 15620-15629 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 15630-15639 + 1, 2, 1, 4, 3, 2, 1, 2, 1, 12, // 15640-15649 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 15650-15659 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 15660-15669 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 15670-15679 + 3, 2, 1, 44, 43, 42, 41, 40, 39, 38, // 15680-15689 + 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, // 15690-15699 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 15700-15709 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 15710-15719 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 15720-15729 + 1, 2, 1, 4, 3, 2, 1, 2, 1, 10, // 15730-15739 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 15740-15749 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 15750-15759 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 15760-15769 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 15770-15779 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 15780-15789 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 15790-15799 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 15800-15809 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 15810-15819 + 3, 2, 1, 36, 35, 34, 33, 32, 31, 30, // 15820-15829 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 15830-15839 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 15840-15849 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 15850-15859 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 15860-15869 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 15870-15879 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 15880-15889 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 15890-15899 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 15900-15909 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 15910-15919 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 15920-15929 + 7, 6, 5, 4, 3, 2, 1, 22, 21, 20, // 15930-15939 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 15940-15949 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 15950-15959 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 15960-15969 + 1, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 15970-15979 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 15980-15989 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 15990-15999 + 1, 6, 5, 4, 3, 2, 1, 26, 25, 24, // 16000-16009 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 16010-16019 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 16020-16029 + 3, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 16030-16039 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 16040-16049 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 16050-16059 + 1, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 16060-16069 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 16070-16079 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 16080-16089 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 16090-16099 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 16100-16109 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 16110-16119 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 16120-16129 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 16130-16139 + 1, 42, 41, 40, 39, 38, 37, 36, 35, 34, // 16140-16149 + 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, // 16150-16159 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 16160-16169 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 16170-16179 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 16180-16189 + 3, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 16190-16199 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 16200-16209 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 16210-16219 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 16220-16229 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 16230-16239 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 16240-16249 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 16250-16259 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 16260-16269 + 3, 2, 1, 28, 27, 26, 25, 24, 23, 22, // 16270-16279 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 16280-16289 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 16290-16299 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 16300-16309 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 16310-16319 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 16320-16329 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 16330-16339 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 16340-16349 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 16350-16359 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 16360-16369 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 16370-16379 + 1, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 16380-16389 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 16390-16399 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 16400-16409 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 16410-16419 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 16420-16429 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 16430-16439 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 16440-16449 + 1, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 16450-16459 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 16460-16469 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 16470-16479 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 16480-16489 + 3, 2, 1, 26, 25, 24, 23, 22, 21, 20, // 16490-16499 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 16500-16509 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 16510-16519 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 16520-16529 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 16530-16539 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 16540-16549 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 16550-16559 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 16560-16569 + 3, 2, 1, 30, 29, 28, 27, 26, 25, 24, // 16570-16579 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 16580-16589 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 16590-16599 + 3, 2, 1, 4, 3, 2, 1, 12, 11, 10, // 16600-16609 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 16610-16619 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 16620-16629 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 16630-16639 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 16640-16649 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 16650-16659 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 16660-16669 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 16670-16679 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 16680-16689 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 16690-16699 + 3, 2, 1, 26, 25, 24, 23, 22, 21, 20, // 16700-16709 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 16710-16719 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 16720-16729 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 16730-16739 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 16740-16749 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 16750-16759 + 3, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 16760-16769 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 16770-16779 + 7, 6, 5, 4, 3, 2, 1, 24, 23, 22, // 16780-16789 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 16790-16799 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 16800-16809 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 16810-16819 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 16820-16829 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 16830-16839 + 3, 2, 1, 28, 27, 26, 25, 24, 23, 22, // 16840-16849 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 16850-16859 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 16860-16869 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 16870-16879 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 16880-16889 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 16890-16899 + 1, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 16900-16909 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 16910-16919 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 16920-16929 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 16930-16939 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 16940-16949 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 16950-16959 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 16960-16969 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 16970-16979 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 16980-16989 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 16990-16999 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 17000-17009 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 17010-17019 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 17020-17029 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 17030-17039 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 17040-17049 + 3, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 17050-17059 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 17060-17069 + 7, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 17070-17079 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 17080-17089 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 17090-17099 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 17100-17109 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 17110-17119 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 17120-17129 + 7, 6, 5, 4, 3, 2, 1, 22, 21, 20, // 17130-17139 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 17140-17149 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 17150-17159 + 7, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 17160-17169 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 17170-17179 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 17180-17189 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 17190-17199 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 22, // 17200-17209 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 17210-17219 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 17220-17229 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 17230-17239 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 17240-17249 + 7, 6, 5, 4, 3, 2, 1, 34, 33, 32, // 17250-17259 + 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 17260-17269 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 17270-17279 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 17280-17289 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 18, // 17290-17299 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 17300-17309 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 17310-17319 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 17320-17329 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 17330-17339 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 17340-17349 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 17350-17359 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 17360-17369 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 17370-17379 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 17380-17389 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 17390-17399 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 17400-17409 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 17410-17419 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 17420-17429 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 17430-17439 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 18, // 17440-17449 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 17450-17459 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 17460-17469 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 17470-17479 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 17480-17489 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 17490-17499 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 17500-17509 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 20, // 17510-17519 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 17520-17529 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 17530-17539 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 17540-17549 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 17550-17559 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 17560-17569 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 17570-17579 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 17580-17589 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 17590-17599 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 17600-17609 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 17610-17619 + 3, 2, 1, 4, 3, 2, 1, 30, 29, 28, // 17620-17629 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 17630-17639 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 17640-17649 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 17650-17659 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 17660-17669 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 17670-17679 + 1, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 17680-17689 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 17690-17699 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 17700-17709 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 17710-17719 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 17720-17729 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 17730-17739 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 17740-17749 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 17750-17759 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 17760-17769 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 17770-17779 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 17780-17789 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 17790-17799 + 7, 6, 5, 4, 3, 2, 1, 20, 19, 18, // 17800-17809 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 17810-17819 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 17820-17829 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 17830-17839 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 17840-17849 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 17850-17859 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 17860-17869 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 17870-17879 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 17880-17889 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 17890-17899 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 17900-17909 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 17910-17919 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 17920-17929 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 17930-17939 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 17940-17949 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 17950-17959 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 17960-17969 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 17970-17979 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 24, // 17980-17989 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 17990-17999 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 18000-18009 + 3, 2, 1, 28, 27, 26, 25, 24, 23, 22, // 18010-18019 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 18020-18029 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 18030-18039 + 1, 2, 1, 4, 3, 2, 1, 2, 1, 10, // 18040-18049 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 18050-18059 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 18060-18069 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 18070-18079 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 18080-18089 + 7, 6, 5, 4, 3, 2, 1, 22, 21, 20, // 18090-18099 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 18100-18109 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 18110-18119 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 18120-18129 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 18130-18139 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 20, // 18140-18149 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 18150-18159 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 18160-18169 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 18170-18179 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 18180-18189 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 18190-18199 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 18200-18209 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 18210-18219 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 18220-18229 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 18230-18239 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 18240-18249 + 1, 2, 1, 4, 3, 2, 1, 12, 11, 10, // 18250-18259 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 18260-18269 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 18270-18279 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 18280-18289 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 18290-18299 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 18300-18309 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 18310-18319 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 18320-18329 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 18330-18339 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 18340-18349 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 18350-18359 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 18360-18369 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 18370-18379 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 18380-18389 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 18390-18399 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 18400-18409 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 18410-18419 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 18420-18429 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 18430-18439 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 18440-18449 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 18450-18459 + 1, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 18460-18469 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 18470-18479 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 18480-18489 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 18490-18499 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 18500-18509 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 18510-18519 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 18520-18529 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 18530-18539 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 18540-18549 + 3, 2, 1, 30, 29, 28, 27, 26, 25, 24, // 18550-18559 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 18560-18569 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 18570-18579 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 18580-18589 + 3, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 18590-18599 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 18600-18609 + 7, 6, 5, 4, 3, 2, 1, 20, 19, 18, // 18610-18619 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 18620-18629 + 7, 6, 5, 4, 3, 2, 1, 24, 23, 22, // 18630-18639 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 18640-18649 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 18650-18659 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 18660-18669 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 18670-18679 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 18680-18689 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 18690-18699 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 18700-18709 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 18710-18719 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 18720-18729 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 18730-18739 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 18740-18749 + 7, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 18750-18759 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 18760-18769 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 18770-18779 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 18780-18789 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 18790-18799 + 3, 2, 1, 36, 35, 34, 33, 32, 31, 30, // 18800-18809 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 18810-18819 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 18820-18829 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 20, // 18830-18839 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 18840-18849 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 18850-18859 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 30, // 18860-18869 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 18870-18879 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 18880-18889 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 18890-18899 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 18900-18909 + 1, 2, 1, 4, 3, 2, 1, 2, 1, 28, // 18910-18919 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 18920-18929 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 18930-18939 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 18940-18949 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 18950-18959 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 18960-18969 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 22, // 18970-18979 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 18980-18989 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 18990-18999 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 19000-19009 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 19010-19019 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 19020-19029 + 1, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 19030-19039 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 19040-19049 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 19050-19059 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 19060-19069 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 19070-19079 + 1, 6, 5, 4, 3, 2, 1, 34, 33, 32, // 19080-19089 + 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 19090-19099 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 19100-19109 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 19110-19119 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 19120-19129 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 19130-19139 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 19140-19149 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 19150-19159 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 19160-19169 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 19170-19179 + 1, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 19180-19189 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 19190-19199 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 19200-19209 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 19210-19219 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 19220-19229 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 19230-19239 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 19240-19249 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 19250-19259 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 19260-19269 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 19270-19279 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 19280-19289 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 19290-19299 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 19300-19309 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 19310-19319 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 19320-19329 + 3, 2, 1, 40, 39, 38, 37, 36, 35, 34, // 19330-19339 + 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, // 19340-19349 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 19350-19359 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 19360-19369 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 19370-19379 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 19380-19389 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 19390-19399 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 19400-19409 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 19410-19419 + 1, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 19420-19429 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 19430-19439 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 19440-19449 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 19450-19459 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 19460-19469 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 19470-19479 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 19480-19489 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 19490-19499 + 1, 6, 5, 4, 3, 2, 1, 24, 23, 22, // 19500-19509 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 19510-19519 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 19520-19529 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 19530-19539 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 19540-19549 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 19550-19559 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 19560-19569 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 19570-19579 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 19580-19589 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 19590-19599 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 52, // 19600-19609 + 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, // 19610-19619 + 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, // 19620-19629 + 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 19630-19639 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 19640-19649 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 19650-19659 + 1, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 19660-19669 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 19670-19679 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 19680-19689 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 19690-19699 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 19700-19709 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 19710-19719 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 19720-19729 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 19730-19739 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 19740-19749 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 19750-19759 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 19760-19769 + 7, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 19770-19779 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 19780-19789 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 19790-19799 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 19800-19809 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 22, // 19810-19819 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 19820-19829 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 19830-19839 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 19840-19849 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 19850-19859 + 1, 6, 5, 4, 3, 2, 1, 22, 21, 20, // 19860-19869 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 19870-19879 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 19880-19889 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 19890-19899 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 19900-19909 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 19910-19919 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 19920-19929 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 19930-19939 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 19940-19949 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 19950-19959 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 19960-19969 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 19970-19979 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 19980-19989 + 1, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 19990-19999 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 20000-20009 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 20010-20019 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 18, // 20020-20029 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 20030-20039 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 20040-20049 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 20050-20059 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 20060-20069 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 20070-20079 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 20080-20089 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 20090-20099 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 20100-20109 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 20110-20119 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 14, // 20120-20129 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 20130-20139 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 12, // 20140-20149 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 20150-20159 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 20160-20169 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 20170-20179 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 20180-20189 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 20190-20199 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 20200-20209 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 20210-20219 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 20220-20229 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 20230-20239 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 20240-20249 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 20250-20259 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 20260-20269 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 20270-20279 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 20280-20289 + 7, 6, 5, 4, 3, 2, 1, 26, 25, 24, // 20290-20299 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 20300-20309 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 20310-20319 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 20320-20329 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 20330-20339 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 20340-20349 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 10, // 20350-20359 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 20, // 20360-20369 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 20370-20379 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 20380-20389 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 20390-20399 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 20400-20409 + 1, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 20410-20419 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 20420-20429 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 20430-20439 + 1, 2, 1, 34, 33, 32, 31, 30, 29, 28, // 20440-20449 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 20450-20459 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 20460-20469 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 20470-20479 + 3, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 20480-20489 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 20490-20499 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 20500-20509 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 20510-20519 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 20520-20529 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 20530-20539 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 20540-20549 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 20550-20559 + 3, 2, 1, 30, 29, 28, 27, 26, 25, 24, // 20560-20569 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 20570-20579 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 20580-20589 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 20590-20599 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 20600-20609 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 20610-20619 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 20620-20629 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 20630-20639 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 20640-20649 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 20650-20659 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 20660-20669 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 20670-20679 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 20680-20689 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 20690-20699 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 20700-20709 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 20710-20719 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 20720-20729 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 20730-20739 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 20740-20749 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 20750-20759 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 20760-20769 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 20770-20779 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 20780-20789 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 20790-20799 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 40, // 20800-20809 + 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, // 20810-20819 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 20820-20829 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 20830-20839 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 20840-20849 + 7, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 20850-20859 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 20860-20869 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 20870-20879 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 20880-20889 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 20890-20899 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 20900-20909 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 20910-20919 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 20920-20929 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 20930-20939 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 20940-20949 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 20950-20959 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 20960-20969 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 20970-20979 + 1, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 20980-20989 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 20990-20999 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 21000-21009 + 1, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 21010-21019 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 21020-21029 + 1, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 21030-21039 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 21040-21049 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 21050-21059 + 1, 6, 5, 4, 3, 2, 1, 22, 21, 20, // 21060-21069 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 21070-21079 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 21080-21089 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 21090-21099 + 1, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 21100-21109 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 21110-21119 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 21120-21129 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 21130-21139 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 21140-21149 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 21150-21159 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 21160-21169 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 21170-21179 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 21180-21189 + 1, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 21190-21199 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 21200-21209 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 21210-21219 + 1, 6, 5, 4, 3, 2, 1, 20, 19, 18, // 21220-21229 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 21230-21239 + 7, 6, 5, 4, 3, 2, 1, 22, 21, 20, // 21240-21249 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 21250-21259 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 21260-21269 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 21270-21279 + 3, 2, 1, 30, 29, 28, 27, 26, 25, 24, // 21280-21289 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 21290-21299 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 21300-21309 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 21310-21319 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 21320-21329 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 21330-21339 + 1, 6, 5, 4, 3, 2, 1, 30, 29, 28, // 21340-21349 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 21350-21359 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 21360-21369 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 21370-21379 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 21380-21389 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 21390-21399 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 21400-21409 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 21410-21419 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 21420-21429 + 3, 2, 1, 34, 33, 32, 31, 30, 29, 28, // 21430-21439 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 21440-21449 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 21450-21459 + 7, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 21460-21469 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 21470-21479 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 21480-21489 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 21490-21499 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 21500-21509 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 21510-21519 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 28, // 21520-21529 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 21530-21539 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 21540-21549 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 21550-21559 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 21560-21569 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 21570-21579 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 21580-21589 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 21590-21599 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 21600-21609 + 1, 2, 1, 4, 3, 2, 1, 30, 29, 28, // 21610-21619 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 21620-21629 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 21630-21639 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 21640-21649 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 21650-21659 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 21660-21669 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 21670-21679 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 21680-21689 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 21690-21699 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 21700-21709 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 21710-21719 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 21720-21729 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 21730-21739 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 21740-21749 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 21750-21759 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 21760-21769 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 21770-21779 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 21780-21789 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 21790-21799 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 21800-21809 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 21810-21819 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 21820-21829 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 21830-21839 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 21840-21849 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 21850-21859 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 21860-21869 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 21870-21879 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 21880-21889 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 21890-21899 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 21900-21909 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 21910-21919 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 21920-21929 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 21930-21939 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 21940-21949 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 21950-21959 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 21960-21969 + 7, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 21970-21979 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 21980-21989 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 21990-21999 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 22000-22009 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 22010-22019 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 22020-22029 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 22030-22039 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 22040-22049 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 22050-22059 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 22060-22069 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 22070-22079 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 22080-22089 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 22090-22099 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 22100-22109 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 22110-22119 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 22120-22129 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 22130-22139 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 22140-22149 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 12, // 22150-22159 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 22160-22169 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 22170-22179 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 22180-22189 + 3, 2, 1, 36, 35, 34, 33, 32, 31, 30, // 22190-22199 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 22200-22209 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 22210-22219 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 22220-22229 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 22230-22239 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 22240-22249 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 22250-22259 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 22260-22269 + 1, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 22270-22279 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 22280-22289 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 22290-22299 + 3, 2, 1, 4, 3, 2, 1, 36, 35, 34, // 22300-22309 + 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, // 22310-22319 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 22320-22329 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 22330-22339 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 18, // 22340-22349 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 22350-22359 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 22360-22369 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 22370-22379 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 22380-22389 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 22390-22399 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 24, // 22400-22409 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 22410-22419 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 22420-22429 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 22430-22439 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 22440-22449 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 22450-22459 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 22460-22469 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 22470-22479 + 1, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 22480-22489 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 22490-22499 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 22500-22509 + 1, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 22510-22519 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 22520-22529 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 22530-22539 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 18, // 22540-22549 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 22550-22559 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 22560-22569 + 1, 2, 1, 40, 39, 38, 37, 36, 35, 34, // 22570-22579 + 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, // 22580-22589 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 22590-22599 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 22600-22609 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 22610-22619 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 22620-22629 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 22630-22639 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 22640-22649 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 22650-22659 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 22660-22669 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 22670-22679 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 22680-22689 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 22690-22699 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 22700-22709 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 22710-22719 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 22720-22729 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 22730-22739 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 22740-22749 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 22750-22759 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 22760-22769 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 22770-22779 + 3, 2, 1, 4, 3, 2, 1, 20, 19, 18, // 22780-22789 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 22790-22799 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 22800-22809 + 1, 6, 5, 4, 3, 2, 1, 36, 35, 34, // 22810-22819 + 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, // 22820-22829 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 22830-22839 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 22840-22849 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 22850-22859 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 22860-22869 + 1, 6, 5, 4, 3, 2, 1, 24, 23, 22, // 22870-22879 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 22880-22889 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 22890-22899 + 1, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 22900-22909 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 22910-22919 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 22920-22929 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 22930-22939 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 22940-22949 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 22950-22959 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 22960-22969 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 22970-22979 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 22980-22989 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 22990-22999 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 23000-23009 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 23010-23019 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 23020-23029 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 23030-23039 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 23040-23049 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 23050-23059 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 23060-23069 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 23070-23079 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 23080-23089 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 23090-23099 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 23100-23109 + 7, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 23110-23119 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 23120-23129 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 23130-23139 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 23140-23149 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 23150-23159 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 23160-23169 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 23170-23179 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 23180-23189 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 23190-23199 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 18, // 23200-23209 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 23210-23219 + 7, 6, 5, 4, 3, 2, 1, 24, 23, 22, // 23220-23229 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 23230-23239 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 23240-23249 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 23250-23259 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 23260-23269 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 23270-23279 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 23280-23289 + 1, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 23290-23299 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 23300-23309 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 23310-23319 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 23320-23329 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 18, // 23330-23339 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 23340-23349 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 23350-23359 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 23360-23369 + 1, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 23370-23379 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 23380-23389 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 23390-23399 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 23400-23409 + 7, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 23410-23419 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 23420-23429 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 23430-23439 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 23440-23449 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 23450-23459 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 23460-23469 + 3, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 23470-23479 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 23480-23489 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 23490-23499 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 22, // 23500-23509 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 23510-23519 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 23520-23529 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 23530-23539 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 23540-23549 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 23550-23559 + 1, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 23560-23569 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 23570-23579 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 23580-23589 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 23590-23599 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 14, // 23600-23609 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 23610-23619 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 23620-23629 + 3, 2, 1, 30, 29, 28, 27, 26, 25, 24, // 23630-23639 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 23640-23649 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 23650-23659 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 23660-23669 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 23670-23679 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 30, // 23680-23689 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 23690-23699 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 23700-23709 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 22, // 23710-23719 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 23720-23729 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 23730-23739 + 1, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 23740-23749 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 23750-23759 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 23760-23769 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 23770-23779 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 23780-23789 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 23790-23799 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 23800-23809 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 23810-23819 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 23820-23829 + 1, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 23830-23839 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 23840-23849 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 23850-23859 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 23860-23869 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 23870-23879 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 23880-23889 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 23890-23899 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 23900-23909 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 23910-23919 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 28, // 23920-23929 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 23930-23939 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 23940-23949 + 7, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 23950-23959 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 23960-23969 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 23970-23979 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 23980-23989 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 23990-23999 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 24000-24009 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 24010-24019 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 14, // 24020-24029 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 24030-24039 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 24040-24049 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 24050-24059 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 24060-24069 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 24070-24079 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 24080-24089 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 24090-24099 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 24100-24109 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 24110-24119 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 24120-24129 + 3, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 24130-24139 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 24140-24149 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 24150-24159 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 24160-24169 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 24170-24179 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 24180-24189 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 24190-24199 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 24200-24209 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 24210-24219 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 24220-24229 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 24230-24239 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 24240-24249 + 1, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 24250-24259 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 24260-24269 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 24270-24279 + 1, 36, 35, 34, 33, 32, 31, 30, 29, 28, // 24280-24289 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 24290-24299 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 24300-24309 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 24310-24319 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 24320-24329 + 7, 6, 5, 4, 3, 2, 1, 22, 21, 20, // 24330-24339 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 24340-24349 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 24350-24359 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 24360-24369 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 24370-24379 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 24380-24389 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 24390-24399 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 24400-24409 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 24410-24419 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 24420-24429 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 24430-24439 + 3, 2, 1, 26, 25, 24, 23, 22, 21, 20, // 24440-24449 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 24450-24459 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 24460-24469 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 24470-24479 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 24480-24489 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 24490-24499 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 24500-24509 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 24510-24519 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 24520-24529 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 24530-24539 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 24540-24549 + 1, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 24550-24559 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 24560-24569 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 24570-24579 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 24580-24589 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 24590-24599 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 24600-24609 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 24610-24619 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 24620-24629 + 1, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 24630-24639 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 24640-24649 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 24650-24659 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 24660-24669 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 24670-24679 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 24680-24689 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 24690-24699 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 24, // 24700-24709 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 24710-24719 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 24720-24729 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 24730-24739 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 24740-24749 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 24750-24759 + 3, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 24760-24769 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 24770-24779 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 24780-24789 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 24790-24799 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 24800-24809 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 24810-24819 + 1, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 24820-24829 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 24830-24839 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 24840-24849 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 24850-24859 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 24860-24869 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 24870-24879 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 24880-24889 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 24890-24899 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 24900-24909 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 24910-24919 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 24920-24929 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 24930-24939 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 24940-24949 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 24950-24959 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 24960-24969 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 24970-24979 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 24, // 24980-24989 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 24990-24999 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 25000-25009 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 25010-25019 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 25020-25029 + 1, 2, 1, 4, 3, 2, 1, 20, 19, 18, // 25030-25039 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 25040-25049 + 7, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 25050-25059 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 25060-25069 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 25070-25079 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 25080-25089 + 7, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 25090-25099 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 25100-25109 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 25110-25119 + 1, 6, 5, 4, 3, 2, 1, 20, 19, 18, // 25120-25129 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 25130-25139 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 25140-25149 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 25150-25159 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 25160-25169 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 25170-25179 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 30, // 25180-25189 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 25190-25199 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 25200-25209 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 25210-25219 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 25220-25229 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 25230-25239 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 25240-25249 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 25250-25259 + 1, 40, 39, 38, 37, 36, 35, 34, 33, 32, // 25260-25269 + 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 25270-25279 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 25280-25289 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 25290-25299 + 1, 2, 1, 4, 3, 2, 1, 2, 1, 12, // 25300-25309 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 25310-25319 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 25320-25329 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 25330-25339 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 25340-25349 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 25350-25359 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 25360-25369 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 25370-25379 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 25380-25389 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 25390-25399 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 25400-25409 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 25410-25419 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 25420-25429 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 25430-25439 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 25440-25449 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 25450-25459 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 25460-25469 + 1, 52, 51, 50, 49, 48, 47, 46, 45, 44, // 25470-25479 + 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, // 25480-25489 + 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, // 25490-25499 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 25500-25509 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 25510-25519 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 25520-25529 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 25530-25539 + 1, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 25540-25549 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 25550-25559 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 25560-25569 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 25570-25579 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 25580-25589 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 25590-25599 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 25600-25609 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 25610-25619 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 25620-25629 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 25630-25639 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 25640-25649 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 25650-25659 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 25660-25669 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 14, // 25670-25679 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 25680-25689 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 25690-25699 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 25700-25709 + 7, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 25710-25719 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 25720-25729 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 25730-25739 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 25740-25749 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 25750-25759 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 25760-25769 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 25770-25779 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 25780-25789 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 25790-25799 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 25800-25809 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 22, // 25810-25819 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 25820-25829 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 25830-25839 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 18, // 25840-25849 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 25850-25859 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 25860-25869 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 25870-25879 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 25880-25889 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 25890-25899 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 25900-25909 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 25910-25919 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 25920-25929 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 25930-25939 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 25940-25949 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 25950-25959 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 25960-25969 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 25970-25979 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 25980-25989 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 25990-25999 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 26000-26009 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 26010-26019 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 26020-26029 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 26030-26039 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 26040-26049 + 3, 2, 1, 30, 29, 28, 27, 26, 25, 24, // 26050-26059 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 26060-26069 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 26070-26079 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 26080-26089 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 26090-26099 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 26100-26109 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 22, // 26110-26119 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 26120-26129 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 26130-26139 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 26140-26149 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 26150-26159 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 26160-26169 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 26170-26179 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 14, // 26180-26189 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 26190-26199 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 18, // 26200-26209 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 26210-26219 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 26220-26229 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 26230-26239 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 26240-26249 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 26250-26259 + 1, 2, 1, 4, 3, 2, 1, 26, 25, 24, // 26260-26269 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 26270-26279 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 26280-26289 + 3, 2, 1, 4, 3, 2, 1, 12, 11, 10, // 26290-26299 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 26300-26309 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 26310-26319 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 26320-26329 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 26330-26339 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 26340-26349 + 7, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 26350-26359 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 26360-26369 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 26370-26379 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 26380-26389 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 26390-26399 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 26400-26409 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 26410-26419 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 26420-26429 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 26430-26439 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 26440-26449 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 20, // 26450-26459 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 26460-26469 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 26470-26479 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 26480-26489 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 26490-26499 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 26500-26509 + 3, 2, 1, 26, 25, 24, 23, 22, 21, 20, // 26510-26519 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 26520-26529 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 26530-26539 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 26540-26549 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 26550-26559 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 26560-26569 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 26570-26579 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 26580-26589 + 1, 6, 5, 4, 3, 2, 1, 30, 29, 28, // 26590-26599 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 26600-26609 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 26610-26619 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 26620-26629 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 26630-26639 + 1, 6, 5, 4, 3, 2, 1, 22, 21, 20, // 26640-26649 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 26650-26659 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 26660-26669 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 26670-26679 + 1, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 26680-26689 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 26690-26699 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 26700-26709 + 1, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 26710-26719 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 26720-26729 + 1, 6, 5, 4, 3, 2, 1, 22, 21, 20, // 26730-26739 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 26740-26749 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 26750-26759 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 26760-26769 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 26770-26779 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 26780-26789 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 26790-26799 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 26800-26809 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 26810-26819 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 26820-26829 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 26830-26839 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 26840-26849 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 26850-26859 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 26860-26869 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 26870-26879 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 26880-26889 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 26890-26899 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 26900-26909 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 26910-26919 + 1, 6, 5, 4, 3, 2, 1, 20, 19, 18, // 26920-26929 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 26930-26939 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 26940-26949 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 22, // 26950-26959 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 26960-26969 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 26970-26979 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 26980-26989 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 26990-26999 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 27000-27009 + 1, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 27010-27019 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 27020-27029 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 27030-27039 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 27040-27049 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 27050-27059 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 27060-27069 + 3, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 27070-27079 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 27080-27089 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 27090-27099 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 18, // 27100-27109 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 27110-27119 + 7, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 27120-27129 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 27130-27139 + 3, 2, 1, 36, 35, 34, 33, 32, 31, 30, // 27140-27149 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 27150-27159 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 27160-27169 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 27170-27179 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 27180-27189 + 1, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 27190-27199 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 27200-27209 + 1, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 27210-27219 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 27220-27229 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 27230-27239 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 27240-27249 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 27250-27259 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 27260-27269 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 27270-27279 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 27280-27289 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 30, // 27290-27299 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 27300-27309 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 27310-27319 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 27320-27329 + 7, 6, 5, 4, 3, 2, 1, 24, 23, 22, // 27330-27339 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 27340-27349 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 27350-27359 + 1, 6, 5, 4, 3, 2, 1, 30, 29, 28, // 27360-27369 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 27370-27379 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 27380-27389 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 27390-27399 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 18, // 27400-27409 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 27410-27419 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 27420-27429 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 27430-27439 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 27440-27449 + 7, 6, 5, 4, 3, 2, 1, 22, 21, 20, // 27450-27459 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 27460-27469 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 27470-27479 + 1, 6, 5, 4, 3, 2, 1, 22, 21, 20, // 27480-27489 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 27490-27499 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 27500-27509 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 27510-27519 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 27520-27529 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 27530-27539 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 27540-27549 + 1, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 27550-27559 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 27560-27569 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 27570-27579 + 1, 2, 1, 28, 27, 26, 25, 24, 23, 22, // 27580-27589 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 27590-27599 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 27600-27609 + 1, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 27610-27619 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 27620-27629 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 27630-27639 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 27640-27649 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 27650-27659 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 27660-27669 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 27670-27679 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 27680-27689 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 27690-27699 + 1, 32, 31, 30, 29, 28, 27, 26, 25, 24, // 27700-27709 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 27710-27719 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 27720-27729 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 27730-27739 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 27740-27749 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 27750-27759 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 27760-27769 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 27770-27779 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 27780-27789 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 27790-27799 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 27800-27809 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 27810-27819 + 3, 2, 1, 4, 3, 2, 1, 20, 19, 18, // 27820-27829 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 27830-27839 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 27840-27849 + 1, 32, 31, 30, 29, 28, 27, 26, 25, 24, // 27850-27859 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 27860-27869 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 27870-27879 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 27880-27889 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 27890-27899 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 27900-27909 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 22, // 27910-27919 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 27920-27929 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 27930-27939 + 1, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 27940-27949 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 27950-27959 + 1, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 27960-27969 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 27970-27979 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 27980-27989 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 27990-27999 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 28000-28009 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 28010-28019 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 28020-28029 + 1, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 28030-28039 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 28040-28049 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 28050-28059 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 28060-28069 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 28070-28079 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 28080-28089 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 28090-28099 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 28100-28109 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 28110-28119 + 3, 2, 1, 28, 27, 26, 25, 24, 23, 22, // 28120-28129 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 28130-28139 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 28140-28149 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 28150-28159 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 28160-28169 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 28170-28179 + 1, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 28180-28189 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 28190-28199 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 28200-28209 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 28210-28219 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 48, // 28220-28229 + 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, // 28230-28239 + 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, // 28240-28249 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 28250-28259 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 28260-28269 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 28270-28279 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 28280-28289 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 28290-28299 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 28300-28309 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 30, // 28310-28319 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 28320-28329 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 28330-28339 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 28340-28349 + 1, 36, 35, 34, 33, 32, 31, 30, 29, 28, // 28350-28359 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 28360-28369 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 28370-28379 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 28380-28389 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 28390-28399 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 28400-28409 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 28410-28419 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 28420-28429 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 28430-28439 + 7, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 28440-28449 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 28450-28459 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 28460-28469 + 7, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 28470-28479 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 28480-28489 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 14, // 28490-28499 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 28500-28509 + 3, 2, 1, 4, 3, 2, 1, 20, 19, 18, // 28510-28519 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 28520-28529 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 28530-28539 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 28540-28549 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 28550-28559 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 28560-28569 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 28570-28579 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 28580-28589 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 28590-28599 + 3, 2, 1, 4, 3, 2, 1, 12, 11, 10, // 28600-28609 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 28610-28619 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 28620-28629 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 28630-28639 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 28640-28649 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 28650-28659 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 18, // 28660-28669 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 28670-28679 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 28680-28689 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 28690-28699 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 28700-28709 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 28710-28719 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 22, // 28720-28729 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 28730-28739 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 28740-28749 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 28750-28759 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 28760-28769 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 28770-28779 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 28780-28789 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 28790-28799 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 28800-28809 + 3, 2, 1, 4, 3, 2, 1, 20, 19, 18, // 28810-28819 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 28820-28829 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 28830-28839 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 28840-28849 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 28850-28859 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 28860-28869 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 22, // 28870-28879 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 28880-28889 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 28890-28899 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 28900-28909 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 28910-28919 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 28920-28929 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 28930-28939 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 28940-28949 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 28950-28959 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 28960-28969 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 30, // 28970-28979 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 28980-28989 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 28990-28999 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 29000-29009 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 29010-29019 + 1, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 29020-29029 + 3, 2, 1, 26, 25, 24, 23, 22, 21, 20, // 29030-29039 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 29040-29049 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 29050-29059 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 29060-29069 + 7, 6, 5, 4, 3, 2, 1, 24, 23, 22, // 29070-29079 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 29080-29089 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 29090-29099 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 29100-29109 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 29110-29119 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 29120-29129 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 29130-29139 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 29140-29149 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 29150-29159 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 29160-29169 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 29170-29179 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 29180-29189 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 29190-29199 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 29200-29209 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 29210-29219 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 29220-29229 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 29230-29239 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 29240-29249 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 29250-29259 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 29260-29269 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 29270-29279 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 29280-29289 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 29290-29299 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 29300-29309 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 29310-29319 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 29320-29329 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 29330-29339 + 7, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 29340-29349 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 29350-29359 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 29360-29369 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 29370-29379 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 10, // 29380-29389 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 29390-29399 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 29400-29409 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 29410-29419 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 29420-29429 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 29430-29439 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 29440-29449 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 29450-29459 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 29460-29469 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 29470-29479 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 29480-29489 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 29490-29499 + 1, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 29500-29509 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 29510-29519 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 29520-29529 + 1, 6, 5, 4, 3, 2, 1, 30, 29, 28, // 29530-29539 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 29540-29549 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 29550-29559 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 29560-29569 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 29570-29579 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 29580-29589 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 29590-29599 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 29600-29609 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 29610-29619 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 29620-29629 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 29630-29639 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 29640-29649 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 29650-29659 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 29660-29669 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 29670-29679 + 3, 2, 1, 34, 33, 32, 31, 30, 29, 28, // 29680-29689 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 29690-29699 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 29700-29709 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 29710-29719 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 29720-29729 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 29730-29739 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 29740-29749 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 29750-29759 + 1, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 29760-29769 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 29770-29779 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 29780-29789 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 29790-29799 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 29800-29809 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 29810-29819 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 29820-29829 + 3, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 29830-29839 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 29840-29849 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 29850-29859 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 29860-29869 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 29870-29879 + 1, 36, 35, 34, 33, 32, 31, 30, 29, 28, // 29880-29889 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 29890-29899 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 29900-29909 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 29910-29919 + 1, 6, 5, 4, 3, 2, 1, 20, 19, 18, // 29920-29929 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 29930-29939 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 29940-29949 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 24, // 29950-29959 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 29960-29969 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 29970-29979 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 22, // 29980-29989 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 29990-29999 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 30000-30009 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 30010-30019 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 30020-30029 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 30030-30039 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 30040-30049 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 30050-30059 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 30060-30069 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 30070-30079 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 30080-30089 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 30090-30099 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 30100-30109 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 14, // 30110-30119 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 30120-30129 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 22, // 30130-30139 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 30140-30149 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 30150-30159 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 30160-30169 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 30170-30179 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 30180-30189 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 30190-30199 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 30200-30209 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 30210-30219 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 30220-30229 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 30230-30239 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 30240-30249 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 30250-30259 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 30260-30269 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 30270-30279 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 30280-30289 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 30290-30299 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 30300-30309 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 30310-30319 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 30320-30329 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 30330-30339 + 1, 6, 5, 4, 3, 2, 1, 20, 19, 18, // 30340-30349 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 30350-30359 + 7, 6, 5, 4, 3, 2, 1, 22, 21, 20, // 30360-30369 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 30370-30379 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 30380-30389 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 30390-30399 + 3, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 30400-30409 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 30410-30419 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 30420-30429 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 30430-30439 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 30440-30449 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 30450-30459 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 22, // 30460-30469 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 30470-30479 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 30480-30489 + 1, 2, 1, 4, 3, 2, 1, 12, 11, 10, // 30490-30499 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 30500-30509 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 30510-30519 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 30520-30529 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 30530-30539 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 30540-30549 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 18, // 30550-30559 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 30560-30569 + 7, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 30570-30579 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 30580-30589 + 3, 2, 1, 38, 37, 36, 35, 34, 33, 32, // 30590-30599 + 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 30600-30609 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 30610-30619 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 30620-30629 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 30630-30639 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 30640-30649 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 30650-30659 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 30660-30669 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 30670-30679 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 30680-30689 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 30690-30699 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 30700-30709 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 30710-30719 + 7, 6, 5, 4, 3, 2, 1, 30, 29, 28, // 30720-30729 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 30730-30739 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 30740-30749 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 30750-30759 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 30760-30769 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 30770-30779 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 30780-30789 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 30790-30799 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 30800-30809 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 30810-30819 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 30820-30829 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 30830-30839 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 30840-30849 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 30850-30859 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 30860-30869 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 30870-30879 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 30880-30889 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 30890-30899 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 30900-30909 + 1, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 30910-30919 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 30920-30929 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 30930-30939 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 22, // 30940-30949 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 30950-30959 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 30960-30969 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 30970-30979 + 3, 2, 1, 30, 29, 28, 27, 26, 25, 24, // 30980-30989 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 30990-30999 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 31000-31009 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 14, // 31010-31019 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 31020-31029 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 31030-31039 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 31040-31049 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 31050-31059 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 31060-31069 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 31070-31079 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 31080-31089 + 1, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 31090-31099 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 31100-31109 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 31110-31119 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 31120-31129 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 31130-31139 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 31140-31149 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 18, // 31150-31159 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 31160-31169 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 31170-31179 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 31180-31189 + 3, 2, 1, 26, 25, 24, 23, 22, 21, 20, // 31190-31199 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 31200-31209 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 31210-31219 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 31220-31229 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 31230-31239 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 31240-31249 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 31250-31259 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 31260-31269 + 1, 6, 5, 4, 3, 2, 1, 30, 29, 28, // 31270-31279 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 31280-31289 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 31290-31299 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 31300-31309 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 31310-31319 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 31320-31329 + 3, 2, 1, 4, 3, 2, 1, 20, 19, 18, // 31330-31339 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 31340-31349 + 7, 6, 5, 4, 3, 2, 1, 22, 21, 20, // 31350-31359 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 31360-31369 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 31370-31379 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 31380-31389 + 1, 2, 1, 4, 3, 2, 1, 72, 71, 70, // 31390-31399 + 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, // 31400-31409 + 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, // 31410-31419 + 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, // 31420-31429 + 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, // 31430-31439 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 31440-31449 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 31450-31459 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 31460-31469 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 31470-31479 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 22, // 31480-31489 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 31490-31499 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 31500-31509 + 1, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 31510-31519 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 31520-31529 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 31530-31539 + 1, 2, 1, 4, 3, 2, 1, 20, 19, 18, // 31540-31549 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 31550-31559 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 31560-31569 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 31570-31579 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 31580-31589 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 31590-31599 + 1, 6, 5, 4, 3, 2, 1, 20, 19, 18, // 31600-31609 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 31610-31619 + 7, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 31620-31629 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 31630-31639 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 31640-31649 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 31650-31659 + 3, 2, 1, 4, 3, 2, 1, 20, 19, 18, // 31660-31669 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 31670-31679 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 31680-31689 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 22, // 31690-31699 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 31700-31709 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 31710-31719 + 1, 2, 1, 4, 3, 2, 1, 2, 1, 12, // 31720-31729 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 31730-31739 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 31740-31749 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 31750-31759 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 31760-31769 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 31770-31779 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 31780-31789 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 18, // 31790-31799 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 31800-31809 + 7, 6, 5, 4, 3, 2, 1, 30, 29, 28, // 31810-31819 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 31820-31829 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 31830-31839 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 31840-31849 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 31850-31859 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 31860-31869 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 31870-31879 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 31880-31889 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 31890-31899 + 7, 6, 5, 4, 3, 2, 1, 50, 49, 48, // 31900-31909 + 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, // 31910-31919 + 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, // 31920-31929 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 31930-31939 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 31940-31949 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 31950-31959 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 31960-31969 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 31970-31979 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 31980-31989 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 31990-31999 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 18, // 32000-32009 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 32010-32019 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 22, // 32020-32029 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 32030-32039 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 32040-32049 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 32050-32059 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 32060-32069 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 32070-32079 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 32080-32089 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 32090-32099 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 32100-32109 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 22, // 32110-32119 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 32120-32129 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 32130-32139 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 32140-32149 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 32150-32159 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 32160-32169 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 32170-32179 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 32180-32189 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 32190-32199 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 32200-32209 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 32210-32219 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 32220-32229 + 3, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 32230-32239 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 32240-32249 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 32250-32259 + 1, 36, 35, 34, 33, 32, 31, 30, 29, 28, // 32260-32269 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 32270-32279 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 32280-32289 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 32290-32299 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 32300-32309 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 32310-32319 + 1, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 32320-32329 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 32330-32339 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 32340-32349 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 32350-32359 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 32360-32369 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 32370-32379 + 1, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 32380-32389 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 32390-32399 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 32400-32409 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 32410-32419 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 32420-32429 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 32430-32439 + 1, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 32440-32449 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 32450-32459 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 32460-32469 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 32470-32479 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 32480-32489 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 32490-32499 + 3, 2, 1, 4, 3, 2, 1, 24, 23, 22, // 32500-32509 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 32510-32519 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 32520-32529 + 1, 2, 1, 4, 3, 2, 1, 24, 23, 22, // 32530-32539 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 32540-32549 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 32550-32559 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 32560-32569 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 32570-32579 + 7, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 32580-32589 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 32590-32599 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 32600-32609 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 32610-32619 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 32620-32629 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 32630-32639 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 32640-32649 + 3, 2, 1, 34, 33, 32, 31, 30, 29, 28, // 32650-32659 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 32660-32669 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 32670-32679 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 32680-32689 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 32690-32699 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 32700-32709 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 30, // 32710-32719 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 32720-32729 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 32730-32739 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 22, // 32740-32749 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 32750-32759 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 32760-32769 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 32770-32779 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 32780-32789 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 32790-32799 + 1, 2, 1, 28, 27, 26, 25, 24, 23, 22, // 32800-32809 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 32810-32819 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 32820-32829 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 32830-32839 + 3, 2, 1, 26, 25, 24, 23, 22, 21, 20, // 32840-32849 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 32850-32859 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 32860-32869 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 32870-32879 + 7, 6, 5, 4, 3, 2, 1, 22, 21, 20, // 32880-32889 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 32890-32899 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 32900-32909 + 1, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 32910-32919 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 32920-32929 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 32930-32939 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 32940-32949 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 32950-32959 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 32960-32969 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 32970-32979 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 32980-32989 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 14, // 32990-32999 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 33000-33009 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 33010-33019 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 33020-33029 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 33030-33039 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 33040-33049 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 33050-33059 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 33060-33069 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 33070-33079 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 33080-33089 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 33090-33099 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 33100-33109 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 30, // 33110-33119 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 33120-33129 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 33130-33139 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 33140-33149 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 33150-33159 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 33160-33169 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 33170-33179 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 33180-33189 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 33190-33199 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 33200-33209 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 33210-33219 + 3, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 33220-33229 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 33230-33239 + 7, 6, 5, 4, 3, 2, 1, 40, 39, 38, // 33240-33249 + 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, // 33250-33259 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 33260-33269 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 33270-33279 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 33280-33289 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 33290-33299 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 33300-33309 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 33310-33319 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 33320-33329 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 33330-33339 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 33340-33349 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 18, // 33350-33359 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 33360-33369 + 7, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 33370-33379 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 33380-33389 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 33390-33399 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 33400-33409 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 33410-33419 + 7, 6, 5, 4, 3, 2, 1, 30, 29, 28, // 33420-33429 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 33430-33439 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 33440-33449 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 33450-33459 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 33460-33469 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 33470-33479 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 33480-33489 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 33490-33499 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 33500-33509 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 33510-33519 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 33520-33529 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 33530-33539 + 7, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 33540-33549 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 33550-33559 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 33560-33569 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 33570-33579 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 33580-33589 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 33590-33599 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 33600-33609 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 33610-33619 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 33620-33629 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 33630-33639 + 1, 6, 5, 4, 3, 2, 1, 32, 31, 30, // 33640-33649 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 33650-33659 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 33660-33669 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 24, // 33670-33679 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 33680-33689 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 33690-33699 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 33700-33709 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 33710-33719 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 33720-33729 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 33730-33739 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 33740-33749 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 33750-33759 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 33760-33769 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 33770-33779 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 33780-33789 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 33790-33799 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 33800-33809 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 33810-33819 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 22, // 33820-33829 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 33830-33839 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 33840-33849 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 33850-33859 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 33860-33869 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 33870-33879 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 33880-33889 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 33890-33899 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 33900-33909 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 33910-33919 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 33920-33929 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 33930-33939 + 1, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 33940-33949 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 33950-33959 + 1, 6, 5, 4, 3, 2, 1, 30, 29, 28, // 33960-33969 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 33970-33979 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 33980-33989 + 7, 6, 5, 4, 3, 2, 1, 22, 21, 20, // 33990-33999 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 34000-34009 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 34010-34019 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 34020-34029 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 18, // 34030-34039 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 34040-34049 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 34050-34059 + 1, 62, 61, 60, 59, 58, 57, 56, 55, 54, // 34060-34069 + 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, // 34070-34079 + 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, // 34080-34089 + 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, // 34090-34099 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 34100-34109 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 34110-34119 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 12, // 34120-34129 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 34130-34139 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 34140-34149 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 34150-34159 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 34160-34169 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 34170-34179 + 3, 2, 1, 28, 27, 26, 25, 24, 23, 22, // 34180-34189 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 34190-34199 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 34200-34209 + 1, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 34210-34219 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 34220-34229 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 34230-34239 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 34240-34249 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 34250-34259 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 34260-34269 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 34270-34279 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 34280-34289 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 34290-34299 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 34300-34309 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 34310-34319 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 34320-34329 + 7, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 34330-34339 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 34340-34349 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 34350-34359 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 34360-34369 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 34370-34379 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 34380-34389 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 34390-34399 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 34400-34409 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 34410-34419 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 34420-34429 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 34430-34439 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 34440-34449 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 34450-34459 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 34460-34469 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 34470-34479 + 3, 2, 1, 4, 3, 2, 1, 12, 11, 10, // 34480-34489 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 34490-34499 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 34500-34509 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 18, // 34510-34519 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 34520-34529 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 34530-34539 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 34, // 34540-34549 + 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, // 34550-34559 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 34560-34569 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 34570-34579 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 34580-34589 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 34590-34599 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 34600-34609 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 34610-34619 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 34620-34629 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 34630-34639 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 34640-34649 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 34650-34659 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 34660-34669 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 34670-34679 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 34680-34689 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 34690-34699 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 34700-34709 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 34710-34719 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 34720-34729 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 34730-34739 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 34740-34749 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 34750-34759 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 34760-34769 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 34770-34779 + 1, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 34780-34789 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 34790-34799 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 34800-34809 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 22, // 34810-34819 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 34820-34829 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 34830-34839 + 1, 2, 1, 4, 3, 2, 1, 2, 1, 22, // 34840-34849 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 34850-34859 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 34860-34869 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 34870-34879 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 34880-34889 + 7, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 34890-34899 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 34900-34909 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 20, // 34910-34919 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 34920-34929 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 34930-34939 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 34940-34949 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 34950-34959 + 1, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 34960-34969 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 34970-34979 + 1, 42, 41, 40, 39, 38, 37, 36, 35, 34, // 34980-34989 + 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, // 34990-34999 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 35000-35009 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 35010-35019 + 3, 2, 1, 4, 3, 2, 1, 24, 23, 22, // 35020-35029 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 35030-35039 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 35040-35049 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 35050-35059 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 35060-35069 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 35070-35079 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 35080-35089 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 35090-35099 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 35100-35109 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 35110-35119 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 35120-35129 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 35130-35139 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 35140-35149 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 35150-35159 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 35160-35169 + 1, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 35170-35179 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 35180-35189 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 35190-35199 + 1, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 35200-35209 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 35210-35219 + 1, 6, 5, 4, 3, 2, 1, 24, 23, 22, // 35220-35229 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 35230-35239 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 35240-35249 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 35250-35259 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 35260-35269 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 35270-35279 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 35280-35289 + 1, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 35290-35299 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 35300-35309 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 35310-35319 + 3, 2, 1, 4, 3, 2, 1, 12, 11, 10, // 35320-35329 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 35330-35339 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 35340-35349 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 35350-35359 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 35360-35369 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 35370-35379 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 35380-35389 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 35390-35399 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 35400-35409 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 35410-35419 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 35420-35429 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 35430-35439 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 35440-35449 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 35450-35459 + 1, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 35460-35469 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 35470-35479 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 35480-35489 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 35490-35499 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 35500-35509 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 35510-35519 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 35520-35529 + 1, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 35530-35539 + 3, 2, 1, 26, 25, 24, 23, 22, 21, 20, // 35540-35549 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 35550-35559 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 35560-35569 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 35570-35579 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 35580-35589 + 1, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 35590-35599 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 35600-35609 + 7, 6, 5, 4, 3, 2, 1, 54, 53, 52, // 35610-35619 + 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, // 35620-35629 + 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, // 35630-35639 + 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 35640-35649 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 35650-35659 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 35660-35669 + 1, 6, 5, 4, 3, 2, 1, 52, 51, 50, // 35670-35679 + 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, // 35680-35689 + 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, // 35690-35699 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 35700-35709 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 35710-35719 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 35720-35729 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 35730-35739 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 35740-35749 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 35750-35759 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 35760-35769 + 1, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 35770-35779 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 35780-35789 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 35790-35799 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 22, // 35800-35809 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 35810-35819 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 35820-35829 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 35830-35839 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 35840-35849 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 35850-35859 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 35860-35869 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 35870-35879 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 35880-35889 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 35890-35899 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 35900-35909 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 35910-35919 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 35920-35929 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 35930-35939 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 35940-35949 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 35950-35959 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 35960-35969 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 35970-35979 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 35980-35989 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 35990-35999 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 36000-36009 + 1, 2, 1, 4, 3, 2, 1, 20, 19, 18, // 36010-36019 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 36020-36029 + 7, 6, 5, 4, 3, 2, 1, 24, 23, 22, // 36030-36039 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 36040-36049 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 36050-36059 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 36060-36069 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 36070-36079 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 36080-36089 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 36090-36099 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 22, // 36100-36109 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 36110-36119 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 36120-36129 + 1, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 36130-36139 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 36140-36149 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 36150-36159 + 1, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 36160-36169 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 36170-36179 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 36180-36189 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 36190-36199 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 36200-36209 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 36210-36219 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 36220-36229 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 36230-36239 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 36240-36249 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 36250-36259 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 36260-36269 + 7, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 36270-36279 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 36280-36289 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 36290-36299 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 36300-36309 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 22, // 36310-36319 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 36320-36329 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 36330-36339 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 36340-36349 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 36350-36359 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 36360-36369 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 36370-36379 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 44, // 36380-36389 + 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, // 36390-36399 + 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, // 36400-36409 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 36410-36419 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 36420-36429 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 36430-36439 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 36440-36449 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 36450-36459 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 36460-36469 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 14, // 36470-36479 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 36480-36489 + 3, 2, 1, 4, 3, 2, 1, 26, 25, 24, // 36490-36499 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 36500-36509 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 36510-36519 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 12, // 36520-36529 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 36530-36539 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 36540-36549 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 36550-36559 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 36560-36569 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 36570-36579 + 3, 2, 1, 4, 3, 2, 1, 12, 11, 10, // 36580-36589 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 36590-36599 + 7, 6, 5, 4, 3, 2, 1, 22, 21, 20, // 36600-36609 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 36610-36619 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 36620-36629 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 36630-36639 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 36640-36649 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 36650-36659 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 36660-36669 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 36670-36679 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 36680-36689 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 36690-36699 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 36700-36709 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 36710-36719 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 36720-36729 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 36730-36739 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 36740-36749 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 36750-36759 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 36760-36769 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 36770-36779 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 36780-36789 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 36790-36799 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 36800-36809 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 36810-36819 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 36820-36829 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 36830-36839 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 36840-36849 + 7, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 36850-36859 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 36860-36869 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 36870-36879 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 36880-36889 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 36890-36899 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 36900-36909 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 36910-36919 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 36920-36929 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 36930-36939 + 3, 2, 1, 4, 3, 2, 1, 26, 25, 24, // 36940-36949 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 36950-36959 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 36960-36969 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 18, // 36970-36979 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 36980-36989 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 36990-36999 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 37000-37009 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 37010-37019 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 37020-37029 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 37030-37039 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 37040-37049 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 37050-37059 + 1, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 37060-37069 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 37070-37079 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 37080-37089 + 7, 6, 5, 4, 3, 2, 1, 20, 19, 18, // 37090-37099 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 37100-37109 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 37110-37119 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 37120-37129 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 20, // 37130-37139 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 37140-37149 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 37150-37159 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 37160-37169 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 37170-37179 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 37180-37189 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 37190-37199 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 37200-37209 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 37210-37219 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 37220-37229 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 37230-37239 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 37240-37249 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 37250-37259 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 37260-37269 + 3, 2, 1, 4, 3, 2, 1, 30, 29, 28, // 37270-37279 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 37280-37289 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 37290-37299 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 37300-37309 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 37310-37319 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 37320-37329 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 18, // 37330-37339 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 37340-37349 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 37350-37359 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 37360-37369 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 37370-37379 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 37380-37389 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 37390-37399 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 37400-37409 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 37410-37419 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 37420-37429 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 37430-37439 + 1, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 37440-37449 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 37450-37459 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 37460-37469 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 37470-37479 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 37480-37489 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 37490-37499 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 37500-37509 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 37510-37519 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 37520-37529 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 37530-37539 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 37540-37549 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 37550-37559 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 37560-37569 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 37570-37579 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 37580-37589 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 37590-37599 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 37600-37609 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 37610-37619 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 37620-37629 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 37630-37639 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 37640-37649 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 37650-37659 + 3, 2, 1, 28, 27, 26, 25, 24, 23, 22, // 37660-37669 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 37670-37679 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 37680-37689 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 18, // 37690-37699 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 37700-37709 + 7, 6, 5, 4, 3, 2, 1, 30, 29, 28, // 37710-37719 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 37720-37729 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 37730-37739 + 7, 6, 5, 4, 3, 2, 1, 34, 33, 32, // 37740-37749 + 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 37750-37759 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 37760-37769 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 37770-37779 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 37780-37789 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 37790-37799 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 37800-37809 + 1, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 37810-37819 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 37820-37829 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 37830-37839 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 37840-37849 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 37850-37859 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 37860-37869 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 37870-37879 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 37880-37889 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 37890-37899 + 7, 6, 5, 4, 3, 2, 1, 44, 43, 42, // 37900-37909 + 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, // 37910-37919 + 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 37920-37929 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 37930-37939 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 37940-37949 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 37950-37959 + 3, 2, 1, 4, 3, 2, 1, 20, 19, 18, // 37960-37969 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 37970-37979 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 37980-37989 + 1, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 37990-37999 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 38000-38009 + 1, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 38010-38019 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 38020-38029 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 38030-38039 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 38040-38049 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 38050-38059 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 38060-38069 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 38070-38079 + 3, 2, 1, 30, 29, 28, 27, 26, 25, 24, // 38080-38089 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 38090-38099 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 38100-38109 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 30, // 38110-38119 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 38120-38129 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 38130-38139 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 38140-38149 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 38150-38159 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 38160-38169 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 38170-38179 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 38180-38189 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 38190-38199 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 38200-38209 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 38210-38219 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 38220-38229 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 22, // 38230-38239 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 38240-38249 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 38250-38259 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 38260-38269 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 38270-38279 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 38280-38289 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 38290-38299 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 38300-38309 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 38310-38319 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 38320-38329 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 38330-38339 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 38340-38349 + 1, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 38350-38359 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 38360-38369 + 1, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 38370-38379 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 38380-38389 + 3, 2, 1, 38, 37, 36, 35, 34, 33, 32, // 38390-38399 + 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 38400-38409 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 38410-38419 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 38420-38429 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 38430-38439 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 38440-38449 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 38450-38459 + 1, 40, 39, 38, 37, 36, 35, 34, 33, 32, // 38460-38469 + 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 38470-38479 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 38480-38489 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 38490-38499 + 1, 42, 41, 40, 39, 38, 37, 36, 35, 34, // 38500-38509 + 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, // 38510-38519 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 38520-38529 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 38530-38539 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 38540-38549 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 38550-38559 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 24, // 38560-38569 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 38570-38579 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 38580-38589 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 38590-38599 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 38600-38609 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 38610-38619 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 38620-38629 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 38630-38639 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 38640-38649 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 38650-38659 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 38660-38669 + 1, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 38670-38679 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 38680-38689 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 38690-38699 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 38700-38709 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 38710-38719 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 38720-38729 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 38730-38739 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 18, // 38740-38749 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 38750-38759 + 7, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 38760-38769 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 38770-38779 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 38780-38789 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 38790-38799 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 38800-38809 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 38810-38819 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 38820-38829 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 38830-38839 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 38840-38849 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 38850-38859 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 38860-38869 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 38870-38879 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 38880-38889 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 38890-38899 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 38900-38909 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 38910-38919 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 38920-38929 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 38930-38939 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 38940-38949 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 38950-38959 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 38960-38969 + 1, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 38970-38979 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 38980-38989 + 3, 2, 1, 26, 25, 24, 23, 22, 21, 20, // 38990-38999 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 39000-39009 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 39010-39019 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 39020-39029 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 39030-39039 + 1, 2, 1, 4, 3, 2, 1, 32, 31, 30, // 39040-39049 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 39050-39059 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 39060-39069 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 39070-39079 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 39080-39089 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 39090-39099 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 39100-39109 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 14, // 39110-39119 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 39120-39129 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 18, // 39130-39139 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 39140-39149 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 39150-39159 + 1, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 39160-39169 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 39170-39179 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 39180-39189 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 39190-39199 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 39200-39209 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 39210-39219 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 39220-39229 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 39230-39239 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 39240-39249 + 1, 42, 41, 40, 39, 38, 37, 36, 35, 34, // 39250-39259 + 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, // 39260-39269 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 39270-39279 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 39280-39289 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 39290-39299 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 39300-39309 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 39310-39319 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 39320-39329 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 39330-39339 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 39340-39349 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 39350-39359 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 39360-39369 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 39370-39379 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 39380-39389 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 39390-39399 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 39400-39409 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 20, // 39410-39419 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 39420-39429 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 39430-39439 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 39440-39449 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 39450-39459 + 1, 38, 37, 36, 35, 34, 33, 32, 31, 30, // 39460-39469 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 39470-39479 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 39480-39489 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 39490-39499 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 39500-39509 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 39510-39519 + 1, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 39520-39529 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 39530-39539 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 39540-39549 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 39550-39559 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 39560-39569 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 39570-39579 + 1, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 39580-39589 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 39590-39599 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 39600-39609 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 39610-39619 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 39620-39629 + 1, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 39630-39639 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 39640-39649 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 39650-39659 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 39660-39669 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 24, // 39670-39679 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 39680-39689 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 39690-39699 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 39700-39709 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 39710-39719 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 39720-39729 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 39730-39739 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 39740-39749 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 39750-39759 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 39760-39769 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 39770-39779 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 39780-39789 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 22, // 39790-39799 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 39800-39809 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 39810-39819 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 39820-39829 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 39830-39839 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 39840-39849 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 39850-39859 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 39860-39869 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 39870-39879 + 3, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 39880-39889 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 39890-39899 + 1, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 39900-39909 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 39910-39919 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 39920-39929 + 7, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 39930-39939 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 39940-39949 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 39950-39959 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 39960-39969 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 39970-39979 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 20, // 39980-39989 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 39990-39999 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 40000-40009 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 40010-40019 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 40020-40029 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 24, // 40030-40039 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 40040-40049 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 40050-40059 + 3, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 40060-40069 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 40070-40079 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 40080-40089 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 40090-40099 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 40100-40109 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 40110-40119 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 22, // 40120-40129 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 40130-40139 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 40140-40149 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 40150-40159 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 40160-40169 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 40170-40179 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 40180-40189 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 40190-40199 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 40200-40209 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 40210-40219 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 40220-40229 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 40230-40239 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 40240-40249 + 3, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 40250-40259 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 40260-40269 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 40270-40279 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 54, // 40280-40289 + 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, // 40290-40299 + 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, // 40300-40309 + 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, // 40310-40319 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 40320-40329 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 40330-40339 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 40340-40349 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 40350-40359 + 1, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 40360-40369 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 40370-40379 + 7, 6, 5, 4, 3, 2, 1, 36, 35, 34, // 40380-40389 + 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, // 40390-40399 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 40400-40409 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 40410-40419 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 40420-40429 + 3, 2, 1, 26, 25, 24, 23, 22, 21, 20, // 40430-40439 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 40440-40449 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 40450-40459 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 40460-40469 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 40470-40479 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 40480-40489 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 40490-40499 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 40500-40509 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 40510-40519 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 40520-40529 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 40530-40539 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 40540-40549 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 40550-40559 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 40560-40569 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 40570-40579 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 40580-40589 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 40590-40599 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 40600-40609 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 40610-40619 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 40620-40629 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 54, // 40630-40639 + 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, // 40640-40649 + 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, // 40650-40659 + 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, // 40660-40669 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 40670-40679 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 40680-40689 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 10, // 40690-40699 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 30, // 40700-40709 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 40710-40719 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 40720-40729 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 40730-40739 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 40740-40749 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 40750-40759 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 40760-40769 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 40770-40779 + 7, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 40780-40789 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 40790-40799 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 40800-40809 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 40810-40819 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 40820-40829 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 40830-40839 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 40840-40849 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 40850-40859 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 40860-40869 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 40870-40879 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 40880-40889 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 40890-40899 + 3, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 40900-40909 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 40910-40919 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 40920-40929 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 40930-40939 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 40940-40949 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 40950-40959 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 40960-40969 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 40970-40979 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 40980-40989 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 40990-40999 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 41000-41009 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 41010-41019 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 41020-41029 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 41030-41039 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 41040-41049 + 1, 6, 5, 4, 3, 2, 1, 20, 19, 18, // 41050-41059 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 41060-41069 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 41070-41079 + 1, 32, 31, 30, 29, 28, 27, 26, 25, 24, // 41080-41089 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 41090-41099 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 41100-41109 + 3, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 41110-41119 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 41120-41129 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 41130-41139 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 41140-41149 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 41150-41159 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 41160-41169 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 41170-41179 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 41180-41189 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 41190-41199 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 41200-41209 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 41210-41219 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 41220-41229 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 41230-41239 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 41240-41249 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 41250-41259 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 41260-41269 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 41270-41279 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 41280-41289 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 34, // 41290-41299 + 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, // 41300-41309 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 41310-41319 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 41320-41329 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 41330-41339 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 41340-41349 + 1, 6, 5, 4, 3, 2, 1, 24, 23, 22, // 41350-41359 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 41360-41369 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 41370-41379 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 41380-41389 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 41390-41399 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 41400-41409 + 1, 2, 1, 30, 29, 28, 27, 26, 25, 24, // 41410-41419 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 41420-41429 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 41430-41439 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 41440-41449 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 41450-41459 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 41460-41469 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 41470-41479 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 41480-41489 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 41490-41499 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 41500-41509 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 41510-41519 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 41520-41529 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 41530-41539 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 30, // 41540-41549 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 41550-41559 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 41560-41569 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 41570-41579 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 41580-41589 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 41590-41599 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 41600-41609 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 41610-41619 + 1, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 41620-41629 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 41630-41639 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 41640-41649 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 41650-41659 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 41660-41669 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 41670-41679 + 1, 6, 5, 4, 3, 2, 1, 32, 31, 30, // 41680-41689 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 41690-41699 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 41700-41709 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 41710-41719 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 41720-41729 + 7, 6, 5, 4, 3, 2, 1, 22, 21, 20, // 41730-41739 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 41740-41749 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 41750-41759 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 41760-41769 + 1, 6, 5, 4, 3, 2, 1, 24, 23, 22, // 41770-41779 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 41780-41789 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 41790-41799 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 41800-41809 + 3, 2, 1, 30, 29, 28, 27, 26, 25, 24, // 41810-41819 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 41820-41829 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 41830-41839 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 41840-41849 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 41850-41859 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 41860-41869 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 41870-41879 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 41880-41889 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 41890-41899 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 41900-41909 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 41910-41919 + 7, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 41920-41929 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 41930-41939 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 41940-41949 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 10, // 41950-41959 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 41960-41969 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 41970-41979 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 41980-41989 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 41990-41999 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 42000-42009 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 42010-42019 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 42020-42029 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 42030-42039 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 42040-42049 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 42050-42059 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 42060-42069 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 42070-42079 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 42080-42089 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 42090-42099 + 1, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 42100-42109 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 42110-42119 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 42120-42129 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 42130-42139 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 42140-42149 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 42150-42159 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 42160-42169 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 42170-42179 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 42180-42189 + 3, 2, 1, 4, 3, 2, 1, 12, 11, 10, // 42190-42199 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 42200-42209 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 42210-42219 + 1, 2, 1, 4, 3, 2, 1, 12, 11, 10, // 42220-42229 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 42230-42239 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 42240-42249 + 7, 6, 5, 4, 3, 2, 1, 24, 23, 22, // 42250-42259 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 42260-42269 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 42270-42279 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 42280-42289 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 42290-42299 + 7, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 42300-42309 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 42310-42319 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 42320-42329 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 42330-42339 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 42340-42349 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 42350-42359 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 42360-42369 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 42370-42379 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 42380-42389 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 42390-42399 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 24, // 42400-42409 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 42410-42419 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 42420-42429 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 42430-42439 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 42440-42449 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 42450-42459 + 1, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 42460-42469 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 42470-42479 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 42480-42489 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 42490-42499 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 24, // 42500-42509 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 42510-42519 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 42520-42529 + 3, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 42530-42539 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 42540-42549 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 42550-42559 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 42560-42569 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 42570-42579 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 22, // 42580-42589 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 42590-42599 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 42600-42609 + 1, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 42610-42619 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 42620-42629 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 42630-42639 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 18, // 42640-42649 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 42650-42659 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 42660-42669 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 42670-42679 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 42680-42689 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 42690-42699 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 42700-42709 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 42710-42719 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 42720-42729 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 42730-42739 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 42740-42749 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 42750-42759 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 42760-42769 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 42770-42779 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 42780-42789 + 3, 2, 1, 4, 3, 2, 1, 24, 23, 22, // 42790-42799 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 42800-42809 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 42810-42819 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 42820-42829 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 42830-42839 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 42840-42849 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 42850-42859 + 3, 2, 1, 36, 35, 34, 33, 32, 31, 30, // 42860-42869 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 42870-42879 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 42880-42889 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 42890-42899 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 42900-42909 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 42910-42919 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 42920-42929 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 42930-42939 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 42940-42949 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 42950-42959 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 42960-42969 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 42970-42979 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 42980-42989 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 42990-42999 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 43000-43009 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 18, // 43010-43019 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 43020-43029 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 43030-43039 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 43040-43049 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 43050-43059 + 3, 2, 1, 4, 3, 2, 1, 26, 25, 24, // 43060-43069 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 43070-43079 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 43080-43089 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 43090-43099 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 43100-43109 + 7, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 43110-43119 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 43120-43129 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 43130-43139 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 43140-43149 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 43150-43159 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 43160-43169 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 43170-43179 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 43180-43189 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 43190-43199 + 1, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 43200-43209 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 43210-43219 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 43220-43229 + 7, 6, 5, 4, 3, 2, 1, 24, 23, 22, // 43230-43239 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 43240-43249 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 43250-43259 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 43260-43269 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 43270-43279 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 43280-43289 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 43290-43299 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 43300-43309 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 43310-43319 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 43320-43329 + 1, 60, 59, 58, 57, 56, 55, 54, 53, 52, // 43330-43339 + 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, // 43340-43349 + 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, // 43350-43359 + 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 43360-43369 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 43370-43379 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 43380-43389 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 43390-43399 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 43400-43409 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 43410-43419 + 7, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 43420-43429 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 43430-43439 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 43440-43449 + 1, 6, 5, 4, 3, 2, 1, 24, 23, 22, // 43450-43459 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 43460-43469 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 43470-43479 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 43480-43489 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 43490-43499 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 43500-43509 + 7, 6, 5, 4, 3, 2, 1, 24, 23, 22, // 43510-43519 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 43520-43529 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 43530-43539 + 1, 2, 1, 30, 29, 28, 27, 26, 25, 24, // 43540-43549 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 43550-43559 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 43560-43569 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 12, // 43570-43579 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 43580-43589 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 43590-43599 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 43600-43609 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 43610-43619 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 43620-43629 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 43630-43639 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 43640-43649 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 43650-43659 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 22, // 43660-43669 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 43670-43679 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 43680-43689 + 1, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 43690-43699 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 43700-43709 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 43710-43719 + 1, 32, 31, 30, 29, 28, 27, 26, 25, 24, // 43720-43729 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 43730-43739 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 43740-43749 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 18, // 43750-43759 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 43760-43769 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 43770-43779 + 1, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 43780-43789 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 43790-43799 + 1, 52, 51, 50, 49, 48, 47, 46, 45, 44, // 43800-43809 + 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, // 43810-43819 + 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, // 43820-43829 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 43830-43839 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 43840-43849 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 43850-43859 + 7, 6, 5, 4, 3, 2, 1, 22, 21, 20, // 43860-43869 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 43870-43879 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 43880-43889 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 43890-43899 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 43900-43909 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 43910-43919 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 43920-43929 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 43930-43939 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 43940-43949 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 43950-43959 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 43960-43969 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 43970-43979 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 43980-43989 + 1, 6, 5, 4, 3, 2, 1, 20, 19, 18, // 43990-43999 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 44000-44009 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 44010-44019 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 44020-44029 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 44030-44039 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 44040-44049 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 44050-44059 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 44060-44069 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 44070-44079 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 44080-44089 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 44090-44099 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 44100-44109 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 44110-44119 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 44120-44129 + 1, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 44130-44139 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 44140-44149 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 44150-44159 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 44160-44169 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 44170-44179 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 44180-44189 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 44190-44199 + 1, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 44200-44209 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 44210-44219 + 1, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 44220-44229 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 44230-44239 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 44240-44249 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 44250-44259 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 44260-44269 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 44270-44279 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 44280-44289 + 3, 2, 1, 58, 57, 56, 55, 54, 53, 52, // 44290-44299 + 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, // 44300-44309 + 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, // 44310-44319 + 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 44320-44329 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 44330-44339 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 44340-44349 + 1, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 44350-44359 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 44360-44369 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 44370-44379 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 28, // 44380-44389 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 44390-44399 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 44400-44409 + 7, 6, 5, 4, 3, 2, 1, 32, 31, 30, // 44410-44419 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 44420-44429 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 44430-44439 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 44440-44449 + 3, 2, 1, 30, 29, 28, 27, 26, 25, 24, // 44450-44459 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 44460-44469 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 44470-44479 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 44480-44489 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 44490-44499 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 44500-44509 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 44510-44519 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 44520-44529 + 1, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 44530-44539 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 14, // 44540-44549 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 44550-44559 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 44560-44569 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 44570-44579 + 7, 6, 5, 4, 3, 2, 1, 30, 29, 28, // 44580-44589 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 44590-44599 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 44600-44609 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 44610-44619 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 44620-44629 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 44630-44639 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 44640-44649 + 1, 6, 5, 4, 3, 2, 1, 26, 25, 24, // 44650-44659 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 44660-44669 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 44670-44679 + 3, 2, 1, 4, 3, 2, 1, 12, 11, 10, // 44680-44689 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 44690-44699 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 44700-44709 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 44710-44719 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 44720-44729 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 44730-44739 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 44740-44749 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 44750-44759 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 44760-44769 + 1, 2, 1, 4, 3, 2, 1, 12, 11, 10, // 44770-44779 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 44780-44789 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 44790-44799 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 44800-44809 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 20, // 44810-44819 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 44820-44829 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 44830-44839 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 44840-44849 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 44850-44859 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 44860-44869 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 44870-44879 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 44880-44889 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 44890-44899 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 44900-44909 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 44910-44919 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 44920-44929 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 44930-44939 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 44940-44949 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 44950-44959 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 44960-44969 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 44970-44979 + 3, 2, 1, 4, 3, 2, 1, 20, 19, 18, // 44980-44989 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 44990-44999 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 45000-45009 + 3, 2, 1, 40, 39, 38, 37, 36, 35, 34, // 45010-45019 + 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, // 45020-45029 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 45030-45039 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 45040-45049 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 45050-45059 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 45060-45069 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 45070-45079 + 3, 2, 1, 36, 35, 34, 33, 32, 31, 30, // 45080-45089 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 45090-45099 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 45100-45109 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 45110-45119 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 45120-45129 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 22, // 45130-45139 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 45140-45149 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 45150-45159 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 45160-45169 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 45170-45179 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 45180-45189 + 1, 6, 5, 4, 3, 2, 1, 36, 35, 34, // 45190-45199 + 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, // 45200-45209 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 45210-45219 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 45220-45229 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 45230-45239 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 45240-45249 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 45250-45259 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 45260-45269 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 45270-45279 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 45280-45289 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 45290-45299 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 45300-45309 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 45310-45319 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 45320-45329 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 45330-45339 + 1, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 45340-45349 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 45350-45359 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 45360-45369 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 45370-45379 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 45380-45389 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 45390-45399 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 45400-45409 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 45410-45419 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 45420-45429 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 42, // 45430-45439 + 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, // 45440-45449 + 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 45450-45459 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 45460-45469 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 45470-45479 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 45480-45489 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 45490-45499 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 45500-45509 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 45510-45519 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 45520-45529 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 45530-45539 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 45540-45549 + 3, 2, 1, 4, 3, 2, 1, 12, 11, 10, // 45550-45559 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 45560-45569 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 45570-45579 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 45580-45589 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 45590-45599 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 45600-45609 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 45610-45619 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 45620-45629 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 45630-45639 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 45640-45649 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 45650-45659 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 45660-45669 + 3, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 45670-45679 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 45680-45689 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 45690-45699 + 7, 6, 5, 4, 3, 2, 1, 30, 29, 28, // 45700-45709 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 45710-45719 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 45720-45729 + 7, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 45730-45739 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 45740-45749 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 45750-45759 + 3, 2, 1, 4, 3, 2, 1, 12, 11, 10, // 45760-45769 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 38, // 45770-45779 + 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, // 45780-45789 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 45790-45799 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 45800-45809 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 45810-45819 + 1, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 45820-45829 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 45830-45839 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 45840-45849 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 45850-45859 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 18, // 45860-45869 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 45870-45879 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 45880-45889 + 3, 2, 1, 50, 49, 48, 47, 46, 45, 44, // 45890-45899 + 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, // 45900-45909 + 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, // 45910-45919 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 45920-45929 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 45930-45939 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 45940-45949 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 45950-45959 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 45960-45969 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 45970-45979 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 32, // 45980-45989 + 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 45990-45999 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 46000-46009 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 46010-46019 + 1, 6, 5, 4, 3, 2, 1, 22, 21, 20, // 46020-46029 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 46030-46039 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 46040-46049 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 46050-46059 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 46060-46069 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 46070-46079 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 46080-46089 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 46090-46099 + 3, 2, 1, 30, 29, 28, 27, 26, 25, 24, // 46100-46109 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 46110-46119 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 46120-46129 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 46130-46139 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 46140-46149 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 46150-46159 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 46160-46169 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 46170-46179 + 1, 2, 1, 4, 3, 2, 1, 12, 11, 10, // 46180-46189 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 20, // 46190-46199 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 46200-46209 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 46210-46219 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 46220-46229 + 7, 6, 5, 4, 3, 2, 1, 24, 23, 22, // 46230-46239 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 46240-46249 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 46250-46259 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 46260-46269 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 22, // 46270-46279 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 46280-46289 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 46290-46299 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 18, // 46300-46309 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 46310-46319 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 46320-46329 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 46330-46339 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 46340-46349 + 1, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 46350-46359 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 46360-46369 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 46370-46379 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 46380-46389 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 46390-46399 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 46400-46409 + 1, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 46410-46419 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 46420-46429 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 46430-46439 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 46440-46449 + 1, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 46450-46459 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 46460-46469 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 46470-46479 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 46480-46489 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 46490-46499 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 46500-46509 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 46510-46519 + 3, 2, 1, 26, 25, 24, 23, 22, 21, 20, // 46520-46529 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 46530-46539 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 46540-46549 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 46550-46559 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 46560-46569 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 46570-46579 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 46580-46589 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 46590-46599 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 46600-46609 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 46610-46619 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 46620-46629 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 46630-46639 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 14, // 46640-46649 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 46650-46659 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 46660-46669 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 46670-46679 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 46680-46689 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 46690-46699 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 46700-46709 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 46710-46719 + 3, 2, 1, 4, 3, 2, 1, 20, 19, 18, // 46720-46729 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 46730-46739 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 46740-46749 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 46750-46759 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 46760-46769 + 1, 36, 35, 34, 33, 32, 31, 30, 29, 28, // 46770-46779 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 46780-46789 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 46790-46799 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 46800-46809 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 46810-46819 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 46820-46829 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 46830-46839 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 46840-46849 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 46850-46859 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 46860-46869 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 46870-46879 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 46880-46889 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 46890-46899 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 46900-46909 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 46910-46919 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 46920-46929 + 3, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 46930-46939 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 46940-46949 + 7, 6, 5, 4, 3, 2, 1, 36, 35, 34, // 46950-46959 + 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, // 46960-46969 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 46970-46979 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 46980-46989 + 3, 2, 1, 4, 3, 2, 1, 20, 19, 18, // 46990-46999 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 47000-47009 + 7, 6, 5, 4, 3, 2, 1, 24, 23, 22, // 47010-47019 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 47020-47029 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 47030-47039 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 47040-47049 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 28, // 47050-47059 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 47060-47069 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 47070-47079 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 47080-47089 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 47090-47099 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 47100-47109 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 47110-47119 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 47120-47129 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 47130-47139 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 12, // 47140-47149 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 47150-47159 + 1, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 47160-47169 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 47170-47179 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 47180-47189 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 47190-47199 + 7, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 47200-47209 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 47210-47219 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 47220-47229 + 7, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 47230-47239 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 47240-47249 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 47250-47259 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 47260-47269 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 47270-47279 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 47280-47289 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 47290-47299 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 47300-47309 + 7, 6, 5, 4, 3, 2, 1, 22, 21, 20, // 47310-47319 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 47320-47329 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 47330-47339 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 47340-47349 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 47350-47359 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 47360-47369 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 47370-47379 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 18, // 47380-47389 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 47390-47399 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 47400-47409 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 47410-47419 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 47420-47429 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 47430-47439 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 47440-47449 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 32, // 47450-47459 + 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 47460-47469 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 47470-47479 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 47480-47489 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 47490-47499 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 47500-47509 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 47510-47519 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 47520-47529 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 47530-47539 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 47540-47549 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 47550-47559 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 47560-47569 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 47570-47579 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 47580-47589 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 47590-47599 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 47600-47609 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 47610-47619 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 47620-47629 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 47630-47639 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 47640-47649 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 22, // 47650-47659 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 47660-47669 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 47670-47679 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 47680-47689 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 47690-47699 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 47700-47709 + 1, 2, 1, 4, 3, 2, 1, 20, 19, 18, // 47710-47719 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 47720-47729 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 47730-47739 + 1, 2, 1, 34, 33, 32, 31, 30, 29, 28, // 47740-47749 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 47750-47759 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 47760-47769 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 47770-47779 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 47780-47789 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 47790-47799 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 47800-47809 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 47810-47819 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 47820-47829 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 47830-47839 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 47840-47849 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 47850-47859 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 47860-47869 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 47870-47879 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 47880-47889 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 47890-47899 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 47900-47909 + 1, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 47910-47919 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 47920-47929 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 47930-47939 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 47940-47949 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 47950-47959 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 47960-47969 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 47970-47979 + 1, 36, 35, 34, 33, 32, 31, 30, 29, 28, // 47980-47989 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 47990-47999 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 48000-48009 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 48010-48019 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 20, // 48020-48029 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 48030-48039 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 24, // 48040-48049 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 48050-48059 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 48060-48069 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 48070-48079 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 48080-48089 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 48090-48099 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 48100-48109 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 48110-48119 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 48120-48129 + 1, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 48130-48139 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 48140-48149 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 48150-48159 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 48160-48169 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 48170-48179 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 48180-48189 + 3, 2, 1, 4, 3, 2, 1, 24, 23, 22, // 48190-48199 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 48200-48209 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 48210-48219 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 48220-48229 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 48230-48239 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 48240-48249 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 48250-48259 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 48260-48269 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 48270-48279 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 48280-48289 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 48290-48299 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 48300-48309 + 1, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 48310-48319 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 48320-48329 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 48330-48339 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 48340-48349 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 48350-48359 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 48360-48369 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 48370-48379 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 48380-48389 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 48390-48399 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 48400-48409 + 3, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 48410-48419 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 48420-48429 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 48430-48439 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 48440-48449 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 48450-48459 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 48460-48469 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 48470-48479 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 48480-48489 + 1, 6, 5, 4, 3, 2, 1, 26, 25, 24, // 48490-48499 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 48500-48509 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 48510-48519 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 48520-48529 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 48530-48539 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 48540-48549 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 48550-48559 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 48560-48569 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 48570-48579 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 48580-48589 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 48590-48599 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 48600-48609 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 48610-48619 + 3, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 48620-48629 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 48630-48639 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 48640-48649 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 48650-48659 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 48660-48669 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 52, // 48670-48679 + 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, // 48680-48689 + 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, // 48690-48699 + 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 48700-48709 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 48710-48719 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 48720-48729 + 1, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 48730-48739 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 48740-48749 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 48750-48759 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 48760-48769 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 48770-48779 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 48780-48789 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 48790-48799 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 48800-48809 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 48810-48819 + 1, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 48820-48829 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 48830-48839 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 48840-48849 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 48850-48859 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 48860-48869 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 48870-48879 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 18, // 48880-48889 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 48890-48899 + 7, 6, 5, 4, 3, 2, 1, 40, 39, 38, // 48900-48909 + 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, // 48910-48919 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 48920-48929 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 48930-48939 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 48940-48949 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 48950-48959 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 48960-48969 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 48970-48979 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 48980-48989 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 48990-48999 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 49000-49009 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 49010-49019 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 49020-49029 + 1, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 49030-49039 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 49040-49049 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 49050-49059 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 49060-49069 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 49070-49079 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 49080-49089 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 49090-49099 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 49100-49109 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 49110-49119 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 49120-49129 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 49130-49139 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 49140-49149 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 49150-49159 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 49160-49169 + 1, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 49170-49179 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 49180-49189 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 49190-49199 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 49200-49209 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 49210-49219 + 3, 2, 1, 30, 29, 28, 27, 26, 25, 24, // 49220-49229 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 49230-49239 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 49240-49249 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 49250-49259 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 49260-49269 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 18, // 49270-49279 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 49280-49289 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 49290-49299 + 7, 6, 5, 4, 3, 2, 1, 24, 23, 22, // 49300-49309 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 49310-49319 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 49320-49329 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 24, // 49330-49339 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 49340-49349 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 49350-49359 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 22, // 49360-49369 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 49370-49379 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 49380-49389 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 49390-49399 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 49400-49409 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 49410-49419 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 49420-49429 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 49430-49439 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 49440-49449 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 49450-49459 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 49460-49469 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 49470-49479 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 49480-49489 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 24, // 49490-49499 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 49500-49509 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 49510-49519 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 49520-49529 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 49530-49539 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 49540-49549 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 38, // 49550-49559 + 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, // 49560-49569 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 49570-49579 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 49580-49589 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 49590-49599 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 49600-49609 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 49610-49619 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 49620-49629 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 24, // 49630-49639 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 49640-49649 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 49650-49659 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 12, // 49660-49669 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 49670-49679 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 49680-49689 + 7, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 49690-49699 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 49700-49709 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 49710-49719 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 49720-49729 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 49730-49739 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 49740-49749 + 7, 6, 5, 4, 3, 2, 1, 26, 25, 24, // 49750-49759 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 49760-49769 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 49770-49779 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 12, // 49780-49789 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 49790-49799 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 49800-49809 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 49810-49819 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 49820-49829 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 49830-49839 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 49840-49849 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 49850-49859 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 49860-49869 + 1, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 49870-49879 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 49880-49889 + 1, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 49890-49899 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 49900-49909 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 49910-49919 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 49920-49929 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 49930-49939 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 49940-49949 + 7, 6, 5, 4, 3, 2, 1, 34, 33, 32, // 49950-49959 + 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 49960-49969 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 49970-49979 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 49980-49989 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 22, // 49990-49999 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 50000-50009 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 50010-50019 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 50020-50029 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 50030-50039 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 50040-50049 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 50050-50059 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 50060-50069 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 50070-50079 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 50080-50089 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 50090-50099 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 50100-50109 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 50110-50119 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 50120-50129 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 50130-50139 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 50140-50149 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 18, // 50150-50159 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 50160-50169 + 7, 6, 5, 4, 3, 2, 1, 30, 29, 28, // 50170-50179 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 50180-50189 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 50190-50199 + 7, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 50200-50209 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 50210-50219 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 50220-50229 + 1, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 50230-50239 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 50240-50249 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 50250-50259 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 50260-50269 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 50270-50279 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 50280-50289 + 1, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 50290-50299 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 50300-50309 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 50310-50319 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 50320-50329 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 50330-50339 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 50340-50349 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 50350-50359 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 50360-50369 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 50370-50379 + 3, 2, 1, 4, 3, 2, 1, 24, 23, 22, // 50380-50389 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 50390-50399 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 50400-50409 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 50410-50419 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 50420-50429 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 50430-50439 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 50440-50449 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 50450-50459 + 1, 36, 35, 34, 33, 32, 31, 30, 29, 28, // 50460-50469 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 50470-50479 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 50480-50489 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 50490-50499 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 50500-50509 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 50510-50519 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 50520-50529 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 50530-50539 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 50540-50549 + 1, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 50550-50559 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 50560-50569 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 50570-50579 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 50580-50589 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 28, // 50590-50599 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 50600-50609 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 50610-50619 + 7, 6, 5, 4, 3, 2, 1, 20, 19, 18, // 50620-50629 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 50630-50639 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 50640-50649 + 1, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 50650-50659 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 50660-50669 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 50670-50679 + 3, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 50680-50689 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 50690-50699 + 7, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 50700-50709 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 50710-50719 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 50720-50729 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 50730-50739 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 50740-50749 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 50750-50759 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 50760-50769 + 3, 2, 1, 4, 3, 2, 1, 12, 11, 10, // 50770-50779 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 32, // 50780-50789 + 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 50790-50799 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 50800-50809 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 50810-50819 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 50820-50829 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 50830-50839 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 50840-50849 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 50850-50859 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 50860-50869 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 50870-50879 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 50880-50889 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 50890-50899 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 50900-50909 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 50910-50919 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 22, // 50920-50929 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 50930-50939 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 50940-50949 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 50950-50959 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 50960-50969 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 50970-50979 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 50980-50989 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 50990-50999 + 1, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 51000-51009 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 51010-51019 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 51020-51029 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 51030-51039 + 3, 2, 1, 4, 3, 2, 1, 12, 11, 10, // 51040-51049 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 51050-51059 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 51060-51069 + 1, 38, 37, 36, 35, 34, 33, 32, 31, 30, // 51070-51079 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 51080-51089 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 51090-51099 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 22, // 51100-51109 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 51110-51119 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 51120-51129 + 1, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 51130-51139 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 51140-51149 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 51150-51159 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 24, // 51160-51169 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 51170-51179 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 51180-51189 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 51190-51199 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 51200-51209 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 51210-51219 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 51220-51229 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 51230-51239 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 51240-51249 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 51250-51259 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 51260-51269 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 51270-51279 + 3, 2, 1, 4, 3, 2, 1, 20, 19, 18, // 51280-51289 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 51290-51299 + 7, 6, 5, 4, 3, 2, 1, 22, 21, 20, // 51300-51309 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 51310-51319 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 51320-51329 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 51330-51339 + 1, 2, 1, 4, 3, 2, 1, 2, 1, 12, // 51340-51349 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 51350-51359 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 51360-51369 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 51370-51379 + 3, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 51380-51389 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 51390-51399 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 51400-51409 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 51410-51419 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 51420-51429 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 51430-51439 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 51440-51449 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 51450-51459 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 51460-51469 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 51470-51479 + 1, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 51480-51489 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 51490-51499 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 51500-51509 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 51510-51519 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 51520-51529 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 51530-51539 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 51540-51549 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 51550-51559 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 51560-51569 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 51570-51579 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 51580-51589 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 51590-51599 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 51600-51609 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 51610-51619 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 51620-51629 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 51630-51639 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 51640-51649 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 51650-51659 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 51660-51669 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 51670-51679 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 51680-51689 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 51690-51699 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 51700-51709 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 51710-51719 + 1, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 51720-51729 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 51730-51739 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 51740-51749 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 51750-51759 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 18, // 51760-51769 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 51770-51779 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 51780-51789 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 51790-51799 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 51800-51809 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 51810-51819 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 51820-51829 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 51830-51839 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 51840-51849 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 51850-51859 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 51860-51869 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 51870-51879 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 51880-51889 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 51890-51899 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 51900-51909 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 51910-51919 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 51920-51929 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 51930-51939 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 22, // 51940-51949 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 51950-51959 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 51960-51969 + 1, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 51970-51979 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 51980-51989 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 51990-51999 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 52000-52009 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 52010-52019 + 1, 6, 5, 4, 3, 2, 1, 24, 23, 22, // 52020-52029 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 52030-52039 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 52040-52049 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 52050-52059 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 52060-52069 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 52070-52079 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 52080-52089 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 52090-52099 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 52100-52109 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 52110-52119 + 1, 6, 5, 4, 3, 2, 1, 20, 19, 18, // 52120-52129 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 52130-52139 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 52140-52149 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 52150-52159 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 52160-52169 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 52170-52179 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 52180-52189 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 52190-52199 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 52200-52209 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 52210-52219 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 52220-52229 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 52230-52239 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 52240-52249 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 52250-52259 + 7, 6, 5, 4, 3, 2, 1, 22, 21, 20, // 52260-52269 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 52270-52279 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 52280-52289 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 52290-52299 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 52300-52309 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 52310-52319 + 1, 40, 39, 38, 37, 36, 35, 34, 33, 32, // 52320-52329 + 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 52330-52339 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 52340-52349 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 52350-52359 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 52360-52369 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 52370-52379 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 52380-52389 + 1, 42, 41, 40, 39, 38, 37, 36, 35, 34, // 52390-52399 + 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, // 52400-52409 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 52410-52419 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 52420-52429 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 52430-52439 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 52440-52449 + 3, 2, 1, 4, 3, 2, 1, 32, 31, 30, // 52450-52459 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 52460-52469 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 52470-52479 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 52480-52489 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 52490-52499 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 52500-52509 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 52510-52519 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 52520-52529 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 52530-52539 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 52540-52549 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 52550-52559 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 52560-52569 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 52570-52579 + 3, 2, 1, 26, 25, 24, 23, 22, 21, 20, // 52580-52589 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 52590-52599 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 52600-52609 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 52610-52619 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 52620-52629 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 28, // 52630-52639 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 52640-52649 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 52650-52659 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 52660-52669 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 52670-52679 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 52680-52689 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 52690-52699 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 52700-52709 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 52710-52719 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 52720-52729 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 52730-52739 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 52740-52749 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 52750-52759 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 52760-52769 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 52770-52779 + 3, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 52780-52789 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 52790-52799 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 52800-52809 + 3, 2, 1, 4, 3, 2, 1, 20, 19, 18, // 52810-52819 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 52820-52829 + 7, 6, 5, 4, 3, 2, 1, 22, 21, 20, // 52830-52839 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 52840-52849 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 52850-52859 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 52860-52869 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 52870-52879 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 52880-52889 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 52890-52899 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 52900-52909 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 52910-52919 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 52920-52929 + 7, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 52930-52939 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 52940-52949 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 52950-52959 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 52960-52969 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 52970-52979 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 52980-52989 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 52990-52999 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 53000-53009 + 7, 6, 5, 4, 3, 2, 1, 30, 29, 28, // 53010-53019 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 53020-53029 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 53030-53039 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 53040-53049 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 53050-53059 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 53060-53069 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 53070-53079 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 53080-53089 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 53090-53099 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 53100-53109 + 3, 2, 1, 4, 3, 2, 1, 12, 11, 10, // 53110-53119 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 53120-53129 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 53130-53139 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 53140-53149 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 53150-53159 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 53160-53169 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 53170-53179 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 53180-53189 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 53190-53199 + 1, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 53200-53209 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 53210-53219 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 53220-53229 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 28, // 53230-53239 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 53240-53249 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 53250-53259 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 53260-53269 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 53270-53279 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 53280-53289 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 53290-53299 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 53300-53309 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 53310-53319 + 3, 2, 1, 4, 3, 2, 1, 26, 25, 24, // 53320-53329 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 53330-53339 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 53340-53349 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 18, // 53350-53359 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 53360-53369 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 53370-53379 + 1, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 53380-53389 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 53390-53399 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 53400-53409 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 53410-53419 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 53420-53429 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 53430-53439 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 53440-53449 + 3, 2, 1, 26, 25, 24, 23, 22, 21, 20, // 53450-53459 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 53460-53469 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 24, // 53470-53479 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 53480-53489 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 53490-53499 + 3, 2, 1, 4, 3, 2, 1, 20, 19, 18, // 53500-53509 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 53510-53519 + 7, 6, 5, 4, 3, 2, 1, 22, 21, 20, // 53520-53529 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 53530-53539 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 53540-53549 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 53550-53559 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 22, // 53560-53569 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 53570-53579 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 53580-53589 + 1, 2, 1, 4, 3, 2, 1, 12, 11, 10, // 53590-53599 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 53600-53609 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 53610-53619 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 53620-53629 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 14, // 53630-53639 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 53640-53649 + 3, 2, 1, 4, 3, 2, 1, 24, 23, 22, // 53650-53659 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 53660-53669 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 53670-53679 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 53680-53689 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 18, // 53690-53699 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 53700-53709 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 53710-53719 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 53720-53729 + 1, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 53730-53739 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 53740-53749 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 53750-53759 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 53760-53769 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 53770-53779 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 53780-53789 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 53790-53799 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 53800-53809 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 53810-53819 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 53820-53829 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 53830-53839 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 53840-53849 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 53850-53859 + 1, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 53860-53869 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 53870-53879 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 53880-53889 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 18, // 53890-53899 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 53900-53909 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 53910-53919 + 3, 2, 1, 4, 3, 2, 1, 12, 11, 10, // 53920-53929 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 53930-53939 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 53940-53949 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 28, // 53950-53959 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 53960-53969 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 53970-53979 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 53980-53989 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 53990-53999 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 54000-54009 + 1, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 54010-54019 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 54020-54029 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 54030-54039 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 54040-54049 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 24, // 54050-54059 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 54060-54069 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 54070-54079 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 54080-54089 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 54090-54099 + 1, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 54100-54109 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 54110-54119 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 54120-54129 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 54130-54139 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 54140-54149 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 54150-54159 + 3, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 54160-54169 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 54170-54179 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 54180-54189 + 3, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 54190-54199 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 54200-54209 + 7, 6, 5, 4, 3, 2, 1, 34, 33, 32, // 54210-54219 + 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 54220-54229 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 54230-54239 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 54240-54249 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 54250-54259 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 54260-54269 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 54270-54279 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 54280-54289 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 54290-54299 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 54300-54309 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 54310-54319 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 54320-54329 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 54330-54339 + 7, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 54340-54349 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 54350-54359 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 54360-54369 + 1, 6, 5, 4, 3, 2, 1, 24, 23, 22, // 54370-54379 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 54380-54389 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 54390-54399 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 54400-54409 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 54410-54419 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 54420-54429 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 54430-54439 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 20, // 54440-54449 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 54450-54459 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 24, // 54460-54469 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 54470-54479 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 54480-54489 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 54490-54499 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 54500-54509 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 54510-54519 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 54520-54529 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 54530-54539 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 54540-54549 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 54550-54559 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 54560-54569 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 54570-54579 + 1, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 54580-54589 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 54590-54599 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 54600-54609 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 54610-54619 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 54620-54629 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 54630-54639 + 7, 6, 5, 4, 3, 2, 1, 20, 19, 18, // 54640-54649 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 54650-54659 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 54660-54669 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 30, // 54670-54679 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 54680-54689 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 54690-54699 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 54700-54709 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 54710-54719 + 1, 6, 5, 4, 3, 2, 1, 24, 23, 22, // 54720-54729 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 54730-54739 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 54740-54749 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 54750-54759 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 54760-54769 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 54770-54779 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 54780-54789 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 30, // 54790-54799 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 54800-54809 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 54810-54819 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 54820-54829 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 54830-54839 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 54840-54849 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 54850-54859 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 54860-54869 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 54870-54879 + 1, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 54880-54889 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 54890-54899 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 54900-54909 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 22, // 54910-54919 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 54920-54929 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 54930-54939 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 54940-54949 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 54950-54959 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 54960-54969 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 54970-54979 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 54980-54989 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 54990-54999 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 55000-55009 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 55010-55019 + 1, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 55020-55029 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 55030-55039 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 55040-55049 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 55050-55059 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 55060-55069 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 24, // 55070-55079 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 55080-55089 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 55090-55099 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 55100-55109 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 55110-55119 + 7, 6, 5, 4, 3, 2, 1, 20, 19, 18, // 55120-55129 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 55130-55139 + 7, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 55140-55149 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 55150-55159 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 55160-55169 + 1, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 55170-55179 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 55180-55189 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 55190-55199 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 55200-55209 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 10, // 55210-55219 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 55220-55229 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 55230-55239 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 55240-55249 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 32, // 55250-55259 + 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 55260-55269 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 55270-55279 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 55280-55289 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 55290-55299 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 55300-55309 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 55310-55319 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 55320-55329 + 1, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 55330-55339 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 55340-55349 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 55350-55359 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 55360-55369 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 55370-55379 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 55380-55389 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 55390-55399 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 55400-55409 + 1, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 55410-55419 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 55420-55429 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 55430-55439 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 55440-55449 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 55450-55459 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 55460-55469 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 55470-55479 + 7, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 55480-55489 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 55490-55499 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 55500-55509 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 55510-55519 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 55520-55529 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 55530-55539 + 1, 6, 5, 4, 3, 2, 1, 32, 31, 30, // 55540-55549 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 55550-55559 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 55560-55569 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 55570-55579 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 55580-55589 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 55590-55599 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 55600-55609 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 55610-55619 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 55620-55629 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 22, // 55630-55639 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 55640-55649 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 55650-55659 + 1, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 55660-55669 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 55670-55679 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 55680-55689 + 1, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 55690-55699 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 55700-55709 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 55710-55719 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 55720-55729 + 3, 2, 1, 30, 29, 28, 27, 26, 25, 24, // 55730-55739 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 55740-55749 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 55750-55759 + 3, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 55760-55769 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 55770-55779 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 55780-55789 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 55790-55799 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 55800-55809 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 55810-55819 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 55820-55829 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 55830-55839 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 22, // 55840-55849 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 55850-55859 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 55860-55869 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 55870-55879 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 55880-55889 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 55890-55899 + 1, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 55900-55909 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 55910-55919 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 55920-55929 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 55930-55939 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 55940-55949 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 55950-55959 + 7, 6, 5, 4, 3, 2, 1, 20, 19, 18, // 55960-55969 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 55970-55979 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 55980-55989 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 55990-55999 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 30, // 56000-56009 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 56010-56019 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 56020-56029 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 56030-56039 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 56040-56049 + 3, 2, 1, 28, 27, 26, 25, 24, 23, 22, // 56050-56059 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 56060-56069 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 56070-56079 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 56080-56089 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 56090-56099 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 56100-56109 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 56110-56119 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 56120-56129 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 56130-56139 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 56140-56149 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 56150-56159 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 56160-56169 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 56170-56179 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 56180-56189 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 56190-56199 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 28, // 56200-56209 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 56210-56219 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 56220-56229 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 56230-56239 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 56240-56249 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 56250-56259 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 30, // 56260-56269 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 56270-56279 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 56280-56289 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 56290-56299 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 56300-56309 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 56310-56319 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 56320-56329 + 3, 2, 1, 26, 25, 24, 23, 22, 21, 20, // 56330-56339 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 56340-56349 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 56350-56359 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 56360-56369 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 56370-56379 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 56380-56389 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 56390-56399 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 56400-56409 + 7, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 56410-56419 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 56420-56429 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 56430-56439 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 56440-56449 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 56450-56459 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 56460-56469 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 10, // 56470-56479 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 56480-56489 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 56490-56499 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 56500-56509 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 56510-56519 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 56520-56529 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 56530-56539 + 3, 2, 1, 26, 25, 24, 23, 22, 21, 20, // 56540-56549 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 56550-56559 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 22, // 56560-56569 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 56570-56579 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 56580-56589 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 56590-56599 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 56600-56609 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 56610-56619 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 56620-56629 + 3, 2, 1, 26, 25, 24, 23, 22, 21, 20, // 56630-56639 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 56640-56649 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 56650-56659 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 56660-56669 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 56670-56679 + 1, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 56680-56689 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 56690-56699 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 56700-56709 + 1, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 56710-56719 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 56720-56729 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 56730-56739 + 7, 6, 5, 4, 3, 2, 1, 20, 19, 18, // 56740-56749 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 56750-56759 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 56760-56769 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 56770-56779 + 3, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 56780-56789 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 56790-56799 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 56800-56809 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 56810-56819 + 1, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 56820-56829 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 56830-56839 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 56840-56849 + 7, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 56850-56859 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 56860-56869 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 56870-56879 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 56880-56889 + 1, 2, 1, 4, 3, 2, 1, 12, 11, 10, // 56890-56899 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 56900-56909 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 56910-56919 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 56920-56929 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 56930-56939 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 56940-56949 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 56950-56959 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 56960-56969 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 56970-56979 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 56980-56989 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 38, // 56990-56999 + 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, // 57000-57009 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 57010-57019 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 57020-57029 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 57030-57039 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 57040-57049 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 57050-57059 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 57060-57069 + 3, 2, 1, 4, 3, 2, 1, 12, 11, 10, // 57070-57079 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 57080-57089 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 57090-57099 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 57100-57109 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 57110-57119 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 57120-57129 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 57130-57139 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 14, // 57140-57149 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 57150-57159 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 57160-57169 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 57170-57179 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 57180-57189 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 57190-57199 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 57200-57209 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 57210-57219 + 1, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 57220-57229 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 57230-57239 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 57240-57249 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 57250-57259 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 57260-57269 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 57270-57279 + 3, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 57280-57289 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 57290-57299 + 1, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 57300-57309 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 57310-57319 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 57320-57329 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 57330-57339 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 18, // 57340-57349 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 57350-57359 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 57360-57369 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 57370-57379 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 57380-57389 + 7, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 57390-57399 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 57400-57409 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 57410-57419 + 7, 6, 5, 4, 3, 2, 1, 30, 29, 28, // 57420-57429 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 57430-57439 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 57440-57449 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 57450-57459 + 7, 6, 5, 4, 3, 2, 1, 20, 19, 18, // 57460-57469 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 57470-57479 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 57480-57489 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 57490-57499 + 3, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 57500-57509 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 57510-57519 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 28, // 57520-57529 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 57530-57539 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 57540-57549 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 57550-57559 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 57560-57569 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 57570-57579 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 57580-57589 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 57590-57599 + 1, 36, 35, 34, 33, 32, 31, 30, 29, 28, // 57600-57609 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 57610-57619 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 57620-57629 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 57630-57639 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 57640-57649 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 57650-57659 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 57660-57669 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 57670-57679 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 57680-57689 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 57690-57699 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 57700-57709 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 57710-57719 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 57720-57729 + 1, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 57730-57739 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 57740-57749 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 57750-57759 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 57760-57769 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 57770-57779 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 57780-57789 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 57790-57799 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 20, // 57800-57809 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 57810-57819 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 57820-57829 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 57830-57839 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 57840-57849 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 22, // 57850-57859 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 57860-57869 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 57870-57879 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 57880-57889 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 57890-57899 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 57900-57909 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 57910-57919 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 57920-57929 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 57930-57939 + 3, 2, 1, 4, 3, 2, 1, 26, 25, 24, // 57940-57949 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 57950-57959 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 57960-57969 + 3, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 57970-57979 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 57980-57989 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 57990-57999 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 58000-58009 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 58010-58019 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 58020-58029 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 58030-58039 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 58040-58049 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 58050-58059 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 58060-58069 + 3, 2, 1, 26, 25, 24, 23, 22, 21, 20, // 58070-58079 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 58080-58089 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 58090-58099 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 58100-58109 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 58110-58119 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 58120-58129 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 58130-58139 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 58140-58149 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 58150-58159 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 58160-58169 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 58170-58179 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 58180-58189 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 58190-58199 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 58200-58209 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 58210-58219 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 58220-58229 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 58230-58239 + 3, 2, 1, 28, 27, 26, 25, 24, 23, 22, // 58240-58249 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 58250-58259 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 58260-58269 + 1, 38, 37, 36, 35, 34, 33, 32, 31, 30, // 58270-58279 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 58280-58289 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 58290-58299 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 58300-58309 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 58310-58319 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 58320-58329 + 7, 6, 5, 4, 3, 2, 1, 26, 25, 24, // 58330-58339 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 58340-58349 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 58350-58359 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 10, // 58360-58369 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 58370-58379 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 58380-58389 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 58390-58399 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 58400-58409 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 58410-58419 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 58420-58429 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 58430-58439 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 58440-58449 + 1, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 58450-58459 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 58460-58469 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 58470-58479 + 1, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 58480-58489 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 58490-58499 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 58500-58509 + 1, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 58510-58519 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 58520-58529 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 58530-58539 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 18, // 58540-58549 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 58550-58559 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 58560-58569 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 22, // 58570-58579 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 58580-58589 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 58590-58599 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 58600-58609 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 58610-58619 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 58620-58629 + 1, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 58630-58639 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 58640-58649 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 58650-58659 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 58660-58669 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 58670-58679 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 58680-58689 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 58690-58699 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 58700-58709 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 58710-58719 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 58720-58729 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 58730-58739 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 58740-58749 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 58750-58759 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 58760-58769 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 58770-58779 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 42, // 58780-58789 + 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, // 58790-58799 + 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 58800-58809 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 58810-58819 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 58820-58829 + 1, 58, 57, 56, 55, 54, 53, 52, 51, 50, // 58830-58839 + 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, // 58840-58849 + 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, // 58850-58859 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 58860-58869 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 58870-58879 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 58880-58889 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 58890-58899 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 58900-58909 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 58910-58919 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 58920-58929 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 58930-58939 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 58940-58949 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 58950-58959 + 3, 2, 1, 4, 3, 2, 1, 12, 11, 10, // 58960-58969 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 58970-58979 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 58980-58989 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 58990-58999 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 59000-59009 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 59010-59019 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 22, // 59020-59029 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 59030-59039 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 59040-59049 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 59050-59059 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 59060-59069 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 59070-59079 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 59080-59089 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 59090-59099 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 59100-59109 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 59110-59119 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 59120-59129 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 59130-59139 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 59140-59149 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 59150-59159 + 7, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 59160-59169 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 59170-59179 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 59180-59189 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 59190-59199 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 59200-59209 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 59210-59219 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 59220-59229 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 59230-59239 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 59240-59249 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 59250-59259 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 59260-59269 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 59270-59279 + 1, 52, 51, 50, 49, 48, 47, 46, 45, 44, // 59280-59289 + 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, // 59290-59299 + 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, // 59300-59309 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 59310-59319 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 59320-59329 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 59330-59339 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 59340-59349 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 59350-59359 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 59360-59369 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 59370-59379 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 59380-59389 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 59390-59399 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 59400-59409 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 22, // 59410-59419 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 59420-59429 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 59430-59439 + 1, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 59440-59449 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 59450-59459 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 59460-59469 + 1, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 59470-59479 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 59480-59489 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 59490-59499 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 59500-59509 + 3, 2, 1, 26, 25, 24, 23, 22, 21, 20, // 59510-59519 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 59520-59529 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 59530-59539 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 59540-59549 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 59550-59559 + 1, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 59560-59569 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 59570-59579 + 1, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 59580-59589 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 59590-59599 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 59600-59609 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 59610-59619 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 22, // 59620-59629 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 59630-59639 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 59640-59649 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 59650-59659 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 59660-59669 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 59670-59679 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 59680-59689 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 59690-59699 + 7, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 59700-59709 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 59710-59719 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 14, // 59720-59729 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 59730-59739 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 59740-59749 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 59750-59759 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 59760-59769 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 59770-59779 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 59780-59789 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 59790-59799 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 24, // 59800-59809 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 59810-59819 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 59820-59829 + 3, 2, 1, 30, 29, 28, 27, 26, 25, 24, // 59830-59839 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 59840-59849 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 59850-59859 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 59860-59869 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 59870-59879 + 7, 6, 5, 4, 3, 2, 1, 34, 33, 32, // 59880-59889 + 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 59890-59899 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 59900-59909 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 59910-59919 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 22, // 59920-59929 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 59930-59939 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 59940-59949 + 1, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 59950-59959 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 59960-59969 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 59970-59979 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 59980-59989 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 59990-59999 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 60000-60009 + 3, 2, 1, 4, 3, 2, 1, 12, 11, 10, // 60010-60019 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 60020-60029 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 60030-60039 + 1, 36, 35, 34, 33, 32, 31, 30, 29, 28, // 60040-60049 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 60050-60059 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 60060-60069 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 60070-60079 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 60080-60089 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 60090-60099 + 1, 2, 1, 4, 3, 2, 1, 20, 19, 18, // 60100-60109 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 60110-60119 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 60120-60129 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 60130-60139 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 60140-60149 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 60150-60159 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 40, // 60160-60169 + 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, // 60170-60179 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 60180-60189 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 60190-60199 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 60200-60209 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 60210-60219 + 3, 2, 1, 28, 27, 26, 25, 24, 23, 22, // 60220-60229 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 60230-60239 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 60240-60249 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 60250-60259 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 60260-60269 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 60270-60279 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 60280-60289 + 3, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 60290-60299 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 60300-60309 + 7, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 60310-60319 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 60320-60329 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 60330-60339 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 60340-60349 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 60350-60359 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 60360-60369 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 60370-60379 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 60380-60389 + 7, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 60390-60399 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 60400-60409 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 60410-60419 + 7, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 60420-60429 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 60430-60439 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 60440-60449 + 7, 6, 5, 4, 3, 2, 1, 36, 35, 34, // 60450-60459 + 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, // 60460-60469 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 60470-60479 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 60480-60489 + 3, 2, 1, 4, 3, 2, 1, 12, 11, 10, // 60490-60499 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 60500-60509 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 60510-60519 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 60520-60529 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 50, // 60530-60539 + 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, // 60540-60549 + 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, // 60550-60559 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 60560-60569 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 60570-60579 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 60580-60589 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 60590-60599 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 60600-60609 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 60610-60619 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 60620-60629 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 60630-60639 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 60640-60649 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 60650-60659 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 60660-60669 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 60670-60679 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 60680-60689 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 60690-60699 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 60700-60709 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 60710-60719 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 60720-60729 + 3, 2, 1, 4, 3, 2, 1, 20, 19, 18, // 60730-60739 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 60740-60749 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 60750-60759 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 60760-60769 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 14, // 60770-60779 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 60780-60789 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 60790-60799 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 60800-60809 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 60810-60819 + 1, 38, 37, 36, 35, 34, 33, 32, 31, 30, // 60820-60829 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 60830-60839 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 60840-60849 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 60850-60859 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 60860-60869 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 60870-60879 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 60880-60889 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 60890-60899 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 60900-60909 + 3, 2, 1, 4, 3, 2, 1, 2, 1, 4, // 60910-60919 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 60920-60929 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 60930-60939 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 60940-60949 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 60950-60959 + 1, 40, 39, 38, 37, 36, 35, 34, 33, 32, // 60960-60969 + 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 60970-60979 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 60980-60989 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 60990-60999 + 1, 6, 5, 4, 3, 2, 1, 20, 19, 18, // 61000-61009 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 61010-61019 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 61020-61029 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 61030-61039 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 61040-61049 + 1, 6, 5, 4, 3, 2, 1, 34, 33, 32, // 61050-61059 + 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 61060-61069 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 61070-61079 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 61080-61089 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 22, // 61090-61099 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 61100-61109 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 61110-61119 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 61120-61129 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 61130-61139 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 61140-61149 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 61150-61159 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 42, // 61160-61169 + 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, // 61170-61179 + 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 61180-61189 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 61190-61199 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 61200-61209 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 61210-61219 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 61220-61229 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 61230-61239 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 61240-61249 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 61250-61259 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 61260-61269 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 61270-61279 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 61280-61289 + 1, 6, 5, 4, 3, 2, 1, 34, 33, 32, // 61290-61299 + 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 61300-61309 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 61310-61319 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 61320-61329 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 61330-61339 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 61340-61349 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 61350-61359 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 61360-61369 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 61370-61379 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 61380-61389 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 61390-61399 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 8, // 61400-61409 + 7, 6, 5, 4, 3, 2, 1, 24, 23, 22, // 61410-61419 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 61420-61429 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 61430-61439 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 61440-61449 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 61450-61459 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 61460-61469 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 61470-61479 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 61480-61489 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 61490-61499 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 61500-61509 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 24, // 61510-61519 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 61520-61529 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 61530-61539 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 61540-61549 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 2, // 61550-61559 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 61560-61569 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 61570-61579 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 61580-61589 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 61590-61599 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 61600-61609 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 61610-61619 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 61620-61629 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 61630-61639 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 61640-61649 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 61650-61659 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 61660-61669 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 61670-61679 + 1, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 61680-61689 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 61690-61699 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 61700-61709 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 61710-61719 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 22, // 61720-61729 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 61730-61739 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 61740-61749 + 1, 6, 5, 4, 3, 2, 1, 24, 23, 22, // 61750-61759 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 61760-61769 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 61770-61779 + 1, 32, 31, 30, 29, 28, 27, 26, 25, 24, // 61780-61789 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 61790-61799 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 61800-61809 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 18, // 61810-61819 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 61820-61829 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 61830-61839 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 61840-61849 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 61850-61859 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 61860-61869 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 30, // 61870-61879 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 61880-61889 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 61890-61899 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 61900-61909 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 61910-61919 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 61920-61929 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 61930-61939 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 61940-61949 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 61950-61959 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 61960-61969 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 61970-61979 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 61980-61989 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 61990-61999 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 62000-62009 + 1, 6, 5, 4, 3, 2, 1, 22, 21, 20, // 62010-62019 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 62020-62029 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 62030-62039 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 62040-62049 + 3, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 62050-62059 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 62060-62069 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 62070-62079 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 62080-62089 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 20, // 62090-62099 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 62100-62109 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 62110-62119 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 62120-62129 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 62130-62139 + 1, 2, 1, 28, 27, 26, 25, 24, 23, 22, // 62140-62149 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 62150-62159 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 62160-62169 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 62170-62179 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 62180-62189 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 62190-62199 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 62200-62209 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 14, // 62210-62219 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 62220-62229 + 3, 2, 1, 40, 39, 38, 37, 36, 35, 34, // 62230-62239 + 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, // 62240-62249 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 62250-62259 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 62260-62269 + 3, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 62270-62279 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 62280-62289 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 62290-62299 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 62300-62309 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 62310-62319 + 3, 2, 1, 4, 3, 2, 1, 20, 19, 18, // 62320-62329 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 62330-62339 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 62340-62349 + 1, 32, 31, 30, 29, 28, 27, 26, 25, 24, // 62350-62359 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 62360-62369 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 62370-62379 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 62380-62389 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 62390-62399 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 62400-62409 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 62410-62419 + 3, 2, 1, 36, 35, 34, 33, 32, 31, 30, // 62420-62429 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 62430-62439 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 62440-62449 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 62450-62459 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 62460-62469 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 62470-62479 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 62480-62489 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 62490-62499 + 1, 6, 5, 4, 3, 2, 1, 26, 25, 24, // 62500-62509 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 62510-62519 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 62520-62529 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 62530-62539 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 62540-62549 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 62550-62559 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 62560-62569 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 62570-62579 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 62580-62589 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 62590-62599 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 62600-62609 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 62610-62619 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 62620-62629 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 14, // 62630-62639 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 62640-62649 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 24, // 62650-62659 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 62660-62669 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 62670-62679 + 3, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 62680-62689 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 62690-62699 + 1, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 62700-62709 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 62710-62719 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 62720-62729 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 62730-62739 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 62740-62749 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 62750-62759 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 62760-62769 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 62770-62779 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 62780-62789 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 62790-62799 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 62800-62809 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 62810-62819 + 7, 6, 5, 4, 3, 2, 1, 24, 23, 22, // 62820-62829 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 62830-62839 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 62840-62849 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 62850-62859 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 62860-62869 + 3, 2, 1, 24, 23, 22, 21, 20, 19, 18, // 62870-62879 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 62880-62889 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 62890-62899 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 62900-62909 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 62910-62919 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 62920-62929 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 30, // 62930-62939 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 62940-62949 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 62950-62959 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 62960-62969 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 62970-62979 + 1, 2, 1, 4, 3, 2, 1, 2, 1, 40, // 62980-62989 + 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, // 62990-62999 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 63000-63009 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 63010-63019 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 63020-63029 + 1, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 63030-63039 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 63040-63049 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 63050-63059 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 63060-63069 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 18, // 63070-63079 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 63080-63089 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 63090-63099 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 63100-63109 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 63110-63119 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 63120-63129 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 63130-63139 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 30, // 63140-63149 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 63150-63159 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 63160-63169 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 63170-63179 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 63180-63189 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 63190-63199 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 63200-63209 + 1, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 63210-63219 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 63220-63229 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 63230-63239 + 1, 6, 5, 4, 3, 2, 1, 30, 29, 28, // 63240-63249 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 63250-63259 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 63260-63269 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 63270-63279 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 63280-63289 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 12, // 63290-63299 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 63300-63309 + 1, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 63310-63319 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 63320-63329 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 63330-63339 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 63340-63349 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 63350-63359 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 63360-63369 + 7, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 63370-63379 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 63380-63389 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 63390-63399 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 63400-63409 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 63410-63419 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 63420-63429 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 63430-63439 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 63440-63449 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 63450-63459 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 63460-63469 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 63470-63479 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 63480-63489 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 22, // 63490-63499 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 63500-63509 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 63510-63519 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 63520-63529 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 63530-63539 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 63540-63549 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 63550-63559 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 63560-63569 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 63570-63579 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 63580-63589 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 63590-63599 + 1, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 63600-63609 + 1, 6, 5, 4, 3, 2, 1, 12, 11, 10, // 63610-63619 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 63620-63629 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 63630-63639 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 10, // 63640-63649 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 63650-63659 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 63660-63669 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 63670-63679 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 63680-63689 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 63690-63699 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 63700-63709 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 63710-63719 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 63720-63729 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 63730-63739 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 63740-63749 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 63750-63759 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 63760-63769 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 63770-63779 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 63780-63789 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 63790-63799 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 14, // 63800-63809 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 63810-63819 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 63820-63829 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 63830-63839 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 63840-63849 + 3, 2, 1, 4, 3, 2, 1, 6, 5, 4, // 63850-63859 + 3, 2, 1, 38, 37, 36, 35, 34, 33, 32, // 63860-63869 + 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 63870-63879 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 63880-63889 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 63890-63899 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 63900-63909 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 63910-63919 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 20, // 63920-63929 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 63930-63939 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 28, // 63940-63949 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 63950-63959 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 63960-63969 + 7, 6, 5, 4, 3, 2, 1, 20, 19, 18, // 63970-63979 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 63980-63989 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 63990-63999 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 64000-64009 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 14, // 64010-64019 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 64020-64029 + 3, 2, 1, 4, 3, 2, 1, 26, 25, 24, // 64030-64039 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 64040-64049 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 64050-64059 + 3, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 64060-64069 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 64070-64079 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 64080-64089 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 64090-64099 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 64100-64109 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 64110-64119 + 3, 2, 1, 28, 27, 26, 25, 24, 23, 22, // 64120-64129 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 64130-64139 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 64140-64149 + 1, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 64150-64159 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 64160-64169 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 64170-64179 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 28, // 64180-64189 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 64190-64199 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 64200-64209 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 64210-64219 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 64220-64229 + 1, 6, 5, 4, 3, 2, 1, 34, 33, 32, // 64230-64239 + 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, // 64240-64249 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 64250-64259 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 64260-64269 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 64270-64279 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 64280-64289 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 64290-64299 + 1, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 64300-64309 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 64310-64319 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 64320-64329 + 3, 2, 1, 40, 39, 38, 37, 36, 35, 34, // 64330-64339 + 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, // 64340-64349 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 64350-64359 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 64360-64369 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 64370-64379 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 64380-64389 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 64390-64399 + 3, 2, 1, 30, 29, 28, 27, 26, 25, 24, // 64400-64409 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 64410-64419 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 64420-64429 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 64430-64439 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 64440-64449 + 1, 2, 1, 30, 29, 28, 27, 26, 25, 24, // 64450-64459 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 64460-64469 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 64470-64479 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 10, // 64480-64489 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 64490-64499 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 64500-64509 + 3, 2, 1, 40, 39, 38, 37, 36, 35, 34, // 64510-64519 + 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, // 64520-64529 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 64530-64539 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 64540-64549 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 64550-64559 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 64560-64569 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 64570-64579 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 64580-64589 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 64590-64599 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 64600-64609 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 64610-64619 + 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 64620-64629 + 3, 2, 1, 28, 27, 26, 25, 24, 23, 22, // 64630-64639 + 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, // 64640-64649 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 64650-64659 + 1, 2, 1, 4, 3, 2, 1, 12, 11, 10, // 64660-64669 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 64670-64679 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 64680-64689 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 64690-64699 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 8, // 64700-64709 + 7, 6, 5, 4, 3, 2, 1, 30, 29, 28, // 64710-64719 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 64720-64729 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 64730-64739 + 7, 6, 5, 4, 3, 2, 1, 16, 15, 14, // 64740-64749 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 64750-64759 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 64760-64769 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 64770-64779 + 1, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 64780-64789 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 64790-64799 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 64800-64809 + 1, 6, 5, 4, 3, 2, 1, 32, 31, 30, // 64810-64819 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 64820-64829 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 64830-64839 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 64840-64849 + 3, 2, 1, 18, 17, 16, 15, 14, 13, 12, // 64850-64859 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 64860-64869 + 1, 6, 5, 4, 3, 2, 1, 2, 1, 12, // 64870-64879 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 64880-64889 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 64890-64899 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 64900-64909 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 64910-64919 + 1, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 64920-64929 + 7, 6, 5, 4, 3, 2, 1, 14, 13, 12, // 64930-64939 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 64940-64949 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 64950-64959 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 28, // 64960-64969 + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, // 64970-64979 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 64980-64989 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 64990-64999 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 65000-65009 + 1, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 65010-65019 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 4, // 65020-65029 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 65030-65039 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 65040-65049 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 65050-65059 + 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, // 65060-65069 + 1, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 65070-65079 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 10, // 65080-65089 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 65090-65099 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 65100-65109 + 1, 8, 7, 6, 5, 4, 3, 2, 1, 4, // 65110-65119 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 12, // 65120-65129 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 65130-65139 + 1, 6, 5, 4, 3, 2, 1, 20, 19, 18, // 65140-65149 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 65150-65159 + 7, 6, 5, 4, 3, 2, 1, 4, 3, 2, // 65160-65169 + 1, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 65170-65179 + 3, 2, 1, 20, 19, 18, 17, 16, 15, 14, // 65180-65189 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 65190-65199 + 3, 2, 1, 10, 9, 8, 7, 6, 5, 4, // 65200-65209 + 3, 2, 1, 26, 25, 24, 23, 22, 21, 20, // 65210-65219 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 65220-65229 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 65230-65239 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 65240-65249 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 65250-65259 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 18, // 65260-65269 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 65270-65279 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 65280-65289 + 3, 2, 1, 16, 15, 14, 13, 12, 11, 10, // 65290-65299 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 14, // 65300-65309 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 65310-65319 + 3, 2, 1, 4, 3, 2, 1, 26, 25, 24, // 65320-65329 + 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, // 65330-65339 + 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 65340-65349 + 3, 2, 1, 4, 3, 2, 1, 14, 13, 12, // 65350-65359 + 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 65360-65369 + 1, 10, 9, 8, 7, 6, 5, 4, 3, 2, // 65370-65379 + 1, 12, 11, 10, 9, 8, 7, 6, 5, 4, // 65380-65389 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 65390-65399 + 7, 6, 5, 4, 3, 2, 1, 6, 5, 4, // 65400-65409 + 3, 2, 1, 6, 5, 4, 3, 2, 1, 4, // 65410-65419 + 3, 2, 1, 14, 13, 12, 11, 10, 9, 8, // 65420-65429 + 7, 6, 5, 4, 3, 2, 1, 10, 9, 8, // 65430-65439 + 7, 6, 5, 4, 3, 2, 1, 2, 1, 30, // 65440-65449 + 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, // 65450-65459 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 65460-65469 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 18, // 65470-65479 + 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, // 65480-65489 + 7, 6, 5, 4, 3, 2, 1, 22, 21, 20, // 65490-65499 + 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, // 65500-65509 + 9, 8, 7, 6, 5, 4, 3, 2, 1, 2, // 65510-65519 + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 65520-65529 + 0, 0, 0, 0, 0, 0, + } + + lohi [256]struct{ lo, hi int } +) + +func init() { + for i, v := range liars { + blk := v >> 24 + x := &lohi[blk] + if x.lo == 0 || i < x.lo { + x.lo = i + } + if i > x.hi { + x.hi = i + } + } +} diff --git a/Godeps/_workspace/src/github.com/cznic/mathutil/test_deps.go b/Godeps/_workspace/src/github.com/cznic/mathutil/test_deps.go new file mode 100644 index 0000000..40054dc --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/mathutil/test_deps.go @@ -0,0 +1,11 @@ +// Copyright (c) 2014 The mathutil 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 mathutil + +// Pull test dependencies too. +// Enables easy 'go test X' after 'go get X' +import ( +// nothing yet +) diff --git a/Godeps/_workspace/src/github.com/cznic/ql/AUTHORS b/Godeps/_workspace/src/github.com/cznic/ql/AUTHORS new file mode 100644 index 0000000..0078f5f --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/ql/AUTHORS @@ -0,0 +1,11 @@ +# This file lists authors for copyright purposes. This file is distinct from +# the CONTRIBUTORS files. See the latter for an explanation. +# +# Names should be added to this file as: +# Name or Organization +# +# The email address is not required for organizations. +# +# Please keep the list sorted. + +Jan Mercl <0xjnml@gmail.com> diff --git a/Godeps/_workspace/src/github.com/cznic/ql/CONTRIBUTORS b/Godeps/_workspace/src/github.com/cznic/ql/CONTRIBUTORS new file mode 100644 index 0000000..a96130f --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/ql/CONTRIBUTORS @@ -0,0 +1,11 @@ +# This file lists people who contributed code to this repository. The AUTHORS +# file lists the copyright holders; this file lists people. +# +# Names should be added to this file like so: +# Name +# +# Please keep the list sorted. + +Dan Kortschak +Jan Mercl <0xjnml@gmail.com> +OpenNota diff --git a/Godeps/_workspace/src/github.com/cznic/ql/LICENSE b/Godeps/_workspace/src/github.com/cznic/ql/LICENSE new file mode 100644 index 0000000..0d10c02 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/ql/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2014 The ql Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the names of the authors nor the names of the +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Godeps/_workspace/src/github.com/cznic/ql/Makefile b/Godeps/_workspace/src/github.com/cznic/ql/Makefile new file mode 100644 index 0000000..d4db8a7 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/ql/Makefile @@ -0,0 +1,74 @@ +# Copyright (c) 2014 The ql Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +.PHONY: all clean nuke + +all: editor scanner.go parser.go + go build + go vet || true + golint + go install ./... + make todo + +bench: all + go test -run NONE -bench . + +check: ql.y + goyacc -v /dev/null -o /dev/null $< + +clean: + go clean + rm -f *~ y.go y.tab.c *.out ql.test + +coerce.go: helper.go + if [ -f coerce.go ] ; then rm coerce.go ; fi + go run helper.go | gofmt > $@ + +cover: + t=$(shell tempfile) ; go test -coverprofile $$t && go tool cover -html $$t && unlink $$t + +cpu: ql.test + go test -c + ./$< -test.bench . -test.cpuprofile cpu.out + go tool pprof --lines $< cpu.out + +editor: check scanner.go parser.go coerce.go + go fmt + go test -i + go test + go install + +internalError: + egrep -ho '"internal error.*"' *.go | sort | cat -n + +mem: ql.test + go test -c + ./$< -test.bench . -test.memprofile mem.out + go tool pprof --lines --web --alloc_space $< mem.out + +nuke: + go clean -i + +parser.go: parser.y + goyacc -o $@ $< + sed -i -e 's|//line.*||' -e 's/yyEofCode/yyEOFCode/' $@ + +ql.test: all + +ql.y: doc.go + sed -n '1,/^package/ s/^\/\/ //p' < $< \ + | ebnf2y -o $@ -oe $*.ebnf -start StatementList -pkg $* -p _ + +scanner.go: scanner.l parser.go + golex -o $@ $< + +todo: + @grep -n ^[[:space:]]*_[[:space:]]*=[[:space:]][[:alpha:]][[:alnum:]]* *.go *.l parser.y || true + @grep -n TODO *.go *.l parser.y testdata.ql || true + @grep -n BUG *.go *.l parser.y || true + @grep -n println *.go *.l parser.y || true + +later: + @grep -n LATER *.go *.l parser.y || true + @grep -n MAYBE *.go *.l parser.y || true diff --git a/Godeps/_workspace/src/github.com/cznic/ql/README.md b/Godeps/_workspace/src/github.com/cznic/ql/README.md new file mode 100644 index 0000000..c7a453a --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/ql/README.md @@ -0,0 +1,21 @@ +ql +== + +Package ql is a pure Go embedded (S)QL database. + +Installation + + $ go get github.com/cznic/ql + +Documentation: [godoc.org/github.com/cznic/ql](http://godoc.org/github.com/cznic/ql) + +---- + +Accompanying tool to play with a DB + +Installation + + $ go get github.com/cznic/ql/ql + +Documentation: [godoc.org/github.com/cznic/ql/ql](http://godoc.org/github.com/cznic/ql/ql) + diff --git a/Godeps/_workspace/src/github.com/cznic/ql/all_test.go b/Godeps/_workspace/src/github.com/cznic/ql/all_test.go new file mode 100644 index 0000000..fae3f45 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/ql/all_test.go @@ -0,0 +1,2720 @@ +// Copyright 2014 The ql 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 ql + +import ( + "bytes" + "crypto/md5" + "database/sql" + "fmt" + "io" + "io/ioutil" + "log" + "math/big" + "math/rand" + "os" + "path" + "path/filepath" + "runtime" + "runtime/debug" + "sort" + "strings" + "sync" + "testing" + "time" + + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/strutil" +) + +// Note: All benchmarks report MB/s equal to record/s. +const benchScale = 1e6 + +func init() { + log.SetFlags(log.Flags() | log.Lshortfile) + isTesting = true +} + +func dbg(s string, va ...interface{}) { + if s == "" { + s = strings.Repeat("%v ", len(va)) + } + _, fn, fl, _ := runtime.Caller(1) + fmt.Printf("dbg %s:%d: ", path.Base(fn), fl) + fmt.Printf(s, va...) + fmt.Println() +} + +func caller(s string, va ...interface{}) { + _, fn, fl, _ := runtime.Caller(2) + fmt.Printf("caller: %s:%d: ", path.Base(fn), fl) + fmt.Printf(s, va...) + fmt.Println() + _, fn, fl, _ = runtime.Caller(1) + fmt.Printf("\tcallee: %s:%d: ", path.Base(fn), fl) + fmt.Println() +} + +func use(...interface{}) {} + +func dumpTables3(r *root) { + fmt.Printf("---- r.head %d, r.thead %p\n", r.head, r.thead) + for k, v := range r.tables { + fmt.Printf("%p: %s->%+v\n", v, k, v) + } + fmt.Println("") +} + +func dumpTables2(s storage) { + fmt.Println("****") + h := int64(1) + for h != 0 { + d, err := s.Read(nil, h) + if err != nil { + log.Fatal(err) + } + + fmt.Printf("%d: %v\n", h, d) + h = d[0].(int64) + } + fmt.Println("") +} + +func (db *DB) dumpTables() string { + var buf bytes.Buffer + for k, v := range db.root.tables { + buf.WriteString(fmt.Sprintf("%s->%v, %v\n", k, v.h, v.next)) + } + return buf.String() +} + +func fldsString(f []*fld) string { + a := []string{} + for _, v := range f { + a = append(a, v.name) + } + return strings.Join(a, " ") +} + +type testDB interface { + setup() (db *DB, err error) + mark() (err error) + teardown() (err error) +} + +var ( + _ testDB = (*fileTestDB)(nil) + _ testDB = (*memTestDB)(nil) +) + +type memTestDB struct { + db *DB + m0 int64 +} + +func (m *memTestDB) setup() (db *DB, err error) { + if m.db, err = OpenMem(); err != nil { + return + } + + return m.db, nil +} + +func (m *memTestDB) mark() (err error) { + m.m0, err = m.db.store.Verify() + if err != nil { + m.m0 = -1 + } + return +} + +func (m *memTestDB) teardown() (err error) { + if m.m0 < 0 { + return + } + + n, err := m.db.store.Verify() + if err != nil { + return + } + + if g, e := n, m.m0; g != e { + return fmt.Errorf("STORAGE LEAK: allocs: got %d, exp %d", g, e) + } + + return +} + +type fileTestDB struct { + db *DB + gmp0 int + m0 int64 +} + +func (m *fileTestDB) setup() (db *DB, err error) { + m.gmp0 = runtime.GOMAXPROCS(0) + f, err := ioutil.TempFile("", "ql-test-") + if err != nil { + return + } + + if m.db, err = OpenFile(f.Name(), &Options{}); err != nil { + return + } + + return m.db, nil +} + +func (m *fileTestDB) mark() (err error) { + m.m0, err = m.db.store.Verify() + if err != nil { + m.m0 = -1 + } + return +} + +func (m *fileTestDB) teardown() (err error) { + runtime.GOMAXPROCS(m.gmp0) + defer func() { + f := m.db.store.(*file) + errSet(&err, m.db.Close()) + os.Remove(f.f0.Name()) + if f.wal != nil { + os.Remove(f.wal.Name()) + } + }() + + if m.m0 < 0 { + return + } + + n, err := m.db.store.Verify() + if err != nil { + return + } + + if g, e := n, m.m0; g != e { + return fmt.Errorf("STORAGE LEAK: allocs: got %d, exp %d", g, e) + } + return +} + +type osFileTestDB struct { + db *DB + gmp0 int + m0 int64 +} + +func (m *osFileTestDB) setup() (db *DB, err error) { + m.gmp0 = runtime.GOMAXPROCS(0) + f, err := ioutil.TempFile("", "ql-test-osfile") + if err != nil { + return + } + + if m.db, err = OpenFile("", &Options{OSFile: f}); err != nil { + return + } + + return m.db, nil +} + +func (m *osFileTestDB) mark() (err error) { + m.m0, err = m.db.store.Verify() + if err != nil { + m.m0 = -1 + } + return +} + +func (m *osFileTestDB) teardown() (err error) { + runtime.GOMAXPROCS(m.gmp0) + defer func() { + f := m.db.store.(*file) + errSet(&err, m.db.Close()) + os.Remove(f.f0.Name()) + if f.wal != nil { + os.Remove(f.wal.Name()) + } + }() + + if m.m0 < 0 { + return + } + + n, err := m.db.store.Verify() + if err != nil { + return + } + + if g, e := n, m.m0; g != e { + return fmt.Errorf("STORAGE LEAK: allocs: got %d, exp %d", g, e) + } + return +} + +func TestMemStorage(t *testing.T) { + test(t, &memTestDB{}) +} + +func TestFileStorage(t *testing.T) { + test(t, &fileTestDB{}) +} + +func TestOSFileStorage(t *testing.T) { + test(t, &osFileTestDB{}) +} + +var ( + compiledCommit = MustCompile("COMMIT;") + compiledCreate = MustCompile("BEGIN TRANSACTION; CREATE TABLE t (i16 int16, s16 string, s string);") + compiledCreate2 = MustCompile("BEGIN TRANSACTION; CREATE TABLE t (i16 int16, s16 string, s string); COMMIT;") + compiledIns = MustCompile("INSERT INTO t VALUES($1, $2, $3);") + compiledSelect = MustCompile("SELECT * FROM t;") + compiledSelectOrderBy = MustCompile("SELECT * FROM t ORDER BY i16, s16;") + compiledTrunc = MustCompile("BEGIN TRANSACTION; TRUNCATE TABLE t; COMMIT;") +) + +func rnds16(rng *rand.Rand, n int) string { + a := make([]string, n) + for i := range a { + a[i] = fmt.Sprintf("%016x", rng.Int63()) + } + return strings.Join(a, "") +} + +var ( + benchmarkScaleOnce sync.Once + benchmarkSelectOnce = map[string]sync.Once{} +) + +func benchProlog(b *testing.B) { + benchmarkScaleOnce.Do(func() { + b.Logf(` +============================================================= +NOTE: All benchmarks report records/s as %d bytes/s. +=============================================================`, int64(benchScale)) + }) +} + +func benchmarkSelect(b *testing.B, n int, sel List, ts testDB) { + if testing.Verbose() { + benchProlog(b) + id := fmt.Sprintf("%T|%d", ts, n) + once := benchmarkSelectOnce[id] + once.Do(func() { + b.Logf(`Having a table of %d records, each of size 1kB, measure the performance of +%s +`, n, sel) + }) + benchmarkSelectOnce[id] = once + } + + db, err := ts.setup() + if err != nil { + b.Error(err) + return + } + + defer ts.teardown() + + ctx := NewRWCtx() + if _, i, err := db.Execute(ctx, compiledCreate); err != nil { + b.Error(i, err) + return + } + + rng := rand.New(rand.NewSource(42)) + for i := 0; i < n; i++ { + if _, _, err := db.Execute(ctx, compiledIns, int16(rng.Int()), rnds16(rng, 1), rnds16(rng, 63)); err != nil { + b.Error(err) + return + } + } + + if _, i, err := db.Execute(ctx, compiledCommit); err != nil { + b.Error(i, err) + return + } + + b.SetBytes(int64(n) * benchScale) + runtime.GC() + b.ResetTimer() + for i := 0; i < b.N; i++ { + rs, index, err := db.Execute(nil, sel) + if err != nil { + b.Error(index, err) + return + } + + if err = rs[0].Do(false, func(record []interface{}) (bool, error) { return true, nil }); err != nil { + b.Errorf("%v %T(%#v)", err, err, err) + return + } + } + b.StopTimer() + +} + +func BenchmarkSelectMem1kBx1e2(b *testing.B) { + benchmarkSelect(b, 1e2, compiledSelect, &memTestDB{}) +} + +func BenchmarkSelectMem1kBx1e3(b *testing.B) { + benchmarkSelect(b, 1e3, compiledSelect, &memTestDB{}) +} + +func BenchmarkSelectMem1kBx1e4(b *testing.B) { + benchmarkSelect(b, 1e4, compiledSelect, &memTestDB{}) +} + +func BenchmarkSelectMem1kBx1e5(b *testing.B) { + benchmarkSelect(b, 1e5, compiledSelect, &memTestDB{}) +} + +func BenchmarkSelectFile1kBx1e2(b *testing.B) { + benchmarkSelect(b, 1e2, compiledSelect, &fileTestDB{}) +} + +func BenchmarkSelectFile1kBx1e3(b *testing.B) { + benchmarkSelect(b, 1e3, compiledSelect, &fileTestDB{}) +} + +func BenchmarkSelectFile1kBx1e4(b *testing.B) { + benchmarkSelect(b, 1e4, compiledSelect, &fileTestDB{}) +} + +func BenchmarkSelectFile1kBx1e5(b *testing.B) { + benchmarkSelect(b, 1e5, compiledSelect, &fileTestDB{}) +} + +func BenchmarkSelectOrderedMem1kBx1e2(b *testing.B) { + benchmarkSelect(b, 1e2, compiledSelectOrderBy, &memTestDB{}) +} + +func BenchmarkSelectOrderedMem1kBx1e3(b *testing.B) { + benchmarkSelect(b, 1e3, compiledSelectOrderBy, &memTestDB{}) +} + +func BenchmarkSelectOrderedMem1kBx1e4(b *testing.B) { + benchmarkSelect(b, 1e4, compiledSelectOrderBy, &memTestDB{}) +} + +func BenchmarkSelectOrderedFile1kBx1e2(b *testing.B) { + benchmarkSelect(b, 1e2, compiledSelectOrderBy, &fileTestDB{}) +} + +func BenchmarkSelectOrderedFile1kBx1e3(b *testing.B) { + benchmarkSelect(b, 1e3, compiledSelectOrderBy, &fileTestDB{}) +} + +func BenchmarkSelectOrderedFile1kBx1e4(b *testing.B) { + benchmarkSelect(b, 1e4, compiledSelectOrderBy, &fileTestDB{}) +} + +func TestString(t *testing.T) { + for _, v := range testdata { + a := strings.Split(v, "\n|") + v = a[0] + v = strings.Replace(v, "∨", "|", -1) + v = strings.Replace(v, "⩖", "||", -1) + l, err := Compile(v) + if err != nil { + continue + } + + if s := l.String(); len(s) == 0 { + t.Fatal("List.String() returned empty string") + } + } +} + +var benchmarkInsertOnce = map[string]sync.Once{} + +func benchmarkInsert(b *testing.B, batch, total int, ts testDB) { + if testing.Verbose() { + benchProlog(b) + id := fmt.Sprintf("%T|%d|%d", ts, batch, total) + once := benchmarkInsertOnce[id] + once.Do(func() { + b.Logf(`In batches of %d record(s), insert a total of %d records, each of size 1kB, into a table. + +`, batch, total) + }) + benchmarkInsertOnce[id] = once + } + + if total%batch != 0 { + b.Fatal("internal error 001") + } + + db, err := ts.setup() + if err != nil { + b.Error(err) + return + } + + defer ts.teardown() + + ctx := NewRWCtx() + if _, i, err := db.Execute(ctx, compiledCreate2); err != nil { + b.Error(i, err) + return + } + + s := fmt.Sprintf(`(0, "0123456789abcdef", "%s"),`, rnds16(rand.New(rand.NewSource(42)), 63)) + var buf bytes.Buffer + buf.WriteString("BEGIN TRANSACTION; INSERT INTO t VALUES\n") + for i := 0; i < batch; i++ { + buf.WriteString(s) + } + buf.WriteString("; COMMIT;") + ins, err := Compile(buf.String()) + if err != nil { + b.Error(err) + return + } + + b.SetBytes(int64(total) * benchScale) + runtime.GC() + b.ResetTimer() + for i := 0; i < b.N; i++ { + for n := 0; n != total; n += batch { + if _, _, err = db.Execute(ctx, ins); err != nil { + b.Error(err) + return + } + } + b.StopTimer() + if _, _, err = db.Execute(ctx, compiledTrunc); err != nil { + b.Error(err) + } + b.StartTimer() + } + b.StopTimer() +} + +func BenchmarkInsertMem1kBn1e0t1e2(b *testing.B) { + benchmarkInsert(b, 1e0, 1e2, &memTestDB{}) +} + +func BenchmarkInsertFile1kBn1e0t1e2(b *testing.B) { + benchmarkInsert(b, 1e0, 1e2, &fileTestDB{}) +} + +//============================================================================= + +func BenchmarkInsertMem1kBn1e1t1e2(b *testing.B) { + benchmarkInsert(b, 1e1, 1e2, &memTestDB{}) +} + +func BenchmarkInsertFile1kBn1e1t1e2(b *testing.B) { + benchmarkInsert(b, 1e1, 1e2, &fileTestDB{}) +} + +func BenchmarkInsertMem1kBn1e1t1e3(b *testing.B) { + benchmarkInsert(b, 1e1, 1e3, &memTestDB{}) +} + +func BenchmarkInsertFile1kBn1e1t1e3(b *testing.B) { + benchmarkInsert(b, 1e1, 1e3, &fileTestDB{}) +} + +//============================================================================= + +func BenchmarkInsertMem1kBn1e2t1e2(b *testing.B) { + benchmarkInsert(b, 1e2, 1e2, &memTestDB{}) +} + +func BenchmarkInsertFile1kBn1e2t1e2(b *testing.B) { + benchmarkInsert(b, 1e2, 1e2, &fileTestDB{}) +} + +func BenchmarkInsertMem1kBn1e2t1e3(b *testing.B) { + benchmarkInsert(b, 1e2, 1e3, &memTestDB{}) +} + +func BenchmarkInsertFile1kBn1e2t1e3(b *testing.B) { + benchmarkInsert(b, 1e2, 1e3, &fileTestDB{}) +} + +func BenchmarkInsertMem1kBn1e2t1e4(b *testing.B) { + benchmarkInsert(b, 1e2, 1e4, &memTestDB{}) +} + +func BenchmarkInsertFile1kBn1e2t1e4(b *testing.B) { + benchmarkInsert(b, 1e2, 1e4, &fileTestDB{}) +} + +//============================================================================= + +func BenchmarkInsertMem1kBn1e3t1e3(b *testing.B) { + benchmarkInsert(b, 1e3, 1e3, &memTestDB{}) +} + +func BenchmarkInsertFile1kBn1e3t1e3(b *testing.B) { + benchmarkInsert(b, 1e3, 1e3, &fileTestDB{}) +} + +func BenchmarkInsertMem1kBn1e3t1e4(b *testing.B) { + benchmarkInsert(b, 1e3, 1e4, &memTestDB{}) +} + +func BenchmarkInsertFile1kBn1e3t1e4(b *testing.B) { + benchmarkInsert(b, 1e3, 1e4, &fileTestDB{}) +} + +func BenchmarkInsertMem1kBn1e3t1e5(b *testing.B) { + benchmarkInsert(b, 1e3, 1e5, &memTestDB{}) +} + +func BenchmarkInsertFile1kBn1e3t1e5(b *testing.B) { + benchmarkInsert(b, 1e3, 1e5, &fileTestDB{}) +} + +func TestReopen(t *testing.T) { + f, err := ioutil.TempFile("", "ql-test-") + if err != nil { + t.Fatal(err) + } + + nm := f.Name() + if err = f.Close(); err != nil { + t.Fatal(err) + } + + defer func() { + if nm != "" { + os.Remove(nm) + } + }() + + db, err := OpenFile(nm, &Options{}) + if err != nil { + t.Error(err) + return + } + + for _, tn := range "abc" { + ql := fmt.Sprintf(` +BEGIN TRANSACTION; + CREATE TABLE %c (i int, s string); + INSERT INTO %c VALUES (%d, "<%c>"); +COMMIT; + `, tn, tn, tn-'a'+42, tn) + _, i, err := db.Run(NewRWCtx(), ql) + if err != nil { + db.Close() + t.Error(i, err) + return + } + } + + if err = db.Close(); err != nil { + t.Error(err) + return + } + + db, err = OpenFile(nm, &Options{}) + if err != nil { + t.Error(err) + return + } + + defer func() { + if err = db.Close(); err != nil { + t.Error(err) + } + }() + + if _, _, err = db.Run(NewRWCtx(), "BEGIN TRANSACTION; DROP TABLE b; COMMIT;"); err != nil { + t.Error(err) + return + } + + for _, tn := range "ac" { + ql := fmt.Sprintf("SELECT * FROM %c;", tn) + rs, i, err := db.Run(NewRWCtx(), ql) + if err != nil { + t.Error(i, err) + return + } + + if rs == nil { + t.Error(rs) + return + } + + rid := 0 + if err = rs[0].Do(false, func(r []interface{}) (bool, error) { + rid++ + if rid != 1 { + return false, fmt.Errorf("rid %d", rid) + } + + if g, e := recStr(r), fmt.Sprintf(`%d, "<%c>"`, tn-'a'+42, tn); g != e { + return false, fmt.Errorf("g `%s`, e `%s`", g, e) + } + + return true, nil + }); err != nil { + t.Error(err) + return + } + } +} + +func recStr(data []interface{}) string { + a := make([]string, len(data)) + for i, v := range data { + switch x := v.(type) { + case string: + a[i] = fmt.Sprintf("%q", x) + default: + a[i] = fmt.Sprint(x) + } + } + return strings.Join(a, ", ") +} + +//TODO +test long blob types with multiple inner chunks. + +func TestLastInsertID(t *testing.T) { + table := []struct { + ql string + id int + }{ + // 0 + {`BEGIN TRANSACTION; CREATE TABLE t (c int); COMMIT`, 0}, + {`BEGIN TRANSACTION; INSERT INTO t VALUES (41); COMMIT`, 1}, + {`BEGIN TRANSACTION; INSERT INTO t VALUES (42);`, 2}, + {`INSERT INTO t VALUES (43)`, 3}, + {`ROLLBACK; BEGIN TRANSACTION; INSERT INTO t VALUES (44); COMMIT`, 4}, + + //5 + {`BEGIN TRANSACTION; INSERT INTO t VALUES (45); COMMIT`, 5}, + {` + BEGIN TRANSACTION; + INSERT INTO t VALUES (46); // 6 + BEGIN TRANSACTION; + INSERT INTO t VALUES (47); // 7 + INSERT INTO t VALUES (48); // 8 + ROLLBACK; + INSERT INTO t VALUES (49); // 9 + COMMIT`, 9}, + {` + BEGIN TRANSACTION; + INSERT INTO t VALUES (50); // 10 + BEGIN TRANSACTION; + INSERT INTO t VALUES (51); // 11 + INSERT INTO t VALUES (52); // 12 + ROLLBACK; + COMMIT;`, 10}, + {`BEGIN TRANSACTION; INSERT INTO t VALUES (53); ROLLBACK`, 10}, + {`BEGIN TRANSACTION; INSERT INTO t VALUES (54); COMMIT`, 14}, + // 10 + {`BEGIN TRANSACTION; CREATE TABLE u (c int); COMMIT`, 14}, + {` + BEGIN TRANSACTION; + INSERT INTO t SELECT * FROM u; + COMMIT;`, 14}, + {`BEGIN TRANSACTION; INSERT INTO u VALUES (150); COMMIT`, 15}, + {` + BEGIN TRANSACTION; + INSERT INTO t SELECT * FROM u; + COMMIT;`, 16}, + } + + db, err := OpenMem() + if err != nil { + t.Fatal(err) + } + + ctx := NewRWCtx() + for i, test := range table { + l, err := Compile(test.ql) + if err != nil { + t.Fatal(i, err) + } + + if _, _, err = db.Execute(ctx, l); err != nil { + t.Fatal(i, err) + } + + if g, e := ctx.LastInsertID, int64(test.id); g != e { + t.Fatal(i, g, e) + } + } +} + +func ExampleTCtx_lastInsertID() { + ins := MustCompile("BEGIN TRANSACTION; INSERT INTO t VALUES ($1); COMMIT;") + + db, err := OpenMem() + if err != nil { + panic(err) + } + + ctx := NewRWCtx() + if _, _, err = db.Run(ctx, ` + BEGIN TRANSACTION; + CREATE TABLE t (c int); + INSERT INTO t VALUES (1), (2), (3); + COMMIT; + `); err != nil { + panic(err) + } + + if _, _, err = db.Execute(ctx, ins, int64(42)); err != nil { + panic(err) + } + + id := ctx.LastInsertID + rs, _, err := db.Run(ctx, `SELECT * FROM t WHERE id() == $1`, id) + if err != nil { + panic(err) + } + + if err = rs[0].Do(false, func(data []interface{}) (more bool, err error) { + fmt.Println(data) + return true, nil + }); err != nil { + panic(err) + } + // Output: + // [42] +} + +func Example_recordsetFields() { + // See RecordSet.Fields documentation + + db, err := OpenMem() + if err != nil { + panic(err) + } + + ctx := NewRWCtx() + rs, _, err := db.Run(ctx, ` + BEGIN TRANSACTION; + CREATE TABLE t (s string, i int); + CREATE TABLE u (s string, i int); + INSERT INTO t VALUES + ("a", 1), + ("a", 2), + ("b", 3), + ("b", 4), + ; + INSERT INTO u VALUES + ("A", 10), + ("A", 20), + ("B", 30), + ("B", 40), + ; + COMMIT; + + // [0]: Fields are not computable. + SELECT * FROM noTable; + + // [1]: Fields are computable even when Do will fail (table noTable does not exist). + SELECT X AS Y FROM noTable; + + // [2]: Both Fields and Do are okay. + SELECT t.s+u.s as a, t.i+u.i as b, "noName", "name" as Named FROM t, u; + + // [3]: Filds are computable even when Do will fail (uknown column a). + SELECT DISTINCT s as S, sum(i) as I FROM ( + SELECT t.s+u.s as s, t.i+u.i, 3 as i FROM t, u; + ) + GROUP BY a + ORDER BY d; + + // [4]: Fields are computable even when Do will fail on missing $1. + SELECT DISTINCT * FROM ( + SELECT t.s+u.s as S, t.i+u.i, 3 as I FROM t, u; + ) + WHERE I < $1 + ORDER BY S; + ` /* , 42 */) // <-- $1 missing + if err != nil { + panic(err) + } + + for i, v := range rs { + fields, err := v.Fields() + switch { + case err != nil: + fmt.Printf("Fields[%d]: error: %s\n", i, err) + default: + fmt.Printf("Fields[%d]: %#v\n", i, fields) + } + if err = v.Do( + true, + func(data []interface{}) (more bool, err error) { + fmt.Printf(" Do[%d]: %#v\n", i, data) + return false, nil + }, + ); err != nil { + fmt.Printf(" Do[%d]: error: %s\n", i, err) + } + } + // Output: + // Fields[0]: error: table noTable does not exist + // Do[0]: error: table noTable does not exist + // Fields[1]: []string{"Y"} + // Do[1]: error: table noTable does not exist + // Fields[2]: []string{"a", "b", "", "Named"} + // Do[2]: []interface {}{"a", "b", "", "Named"} + // Fields[3]: []string{"S", "I"} + // Do[3]: error: unknown column a + // Fields[4]: []string{"S", "", "I"} + // Do[4]: error: missing $1 +} + +func TestRowsAffected(t *testing.T) { + db, err := OpenMem() + if err != nil { + t.Fatal(err) + } + + ctx := NewRWCtx() + ctx.LastInsertID, ctx.RowsAffected = -1, -1 + if _, _, err = db.Run(ctx, ` + BEGIN TRANSACTION; + CREATE TABLE t (i int); + COMMIT; + `); err != nil { + t.Fatal(err) + } + + if g, e := ctx.LastInsertID, int64(0); g != e { + t.Fatal(g, e) + } + + if g, e := ctx.RowsAffected, int64(0); g != e { + t.Fatal(g, e) + } + + if _, _, err = db.Run(ctx, ` + BEGIN TRANSACTION; + INSERT INTO t VALUES (1), (2), (3); + COMMIT; + `); err != nil { + t.Fatal(err) + } + + if g, e := ctx.LastInsertID, int64(3); g != e { + t.Fatal(g, e) + } + + if g, e := ctx.RowsAffected, int64(3); g != e { + t.Fatal(g, e) + } + + if _, _, err = db.Run(ctx, ` + BEGIN TRANSACTION; + INSERT INTO t + SELECT * FROM t WHERE i == 2; + COMMIT; + `); err != nil { + t.Fatal(err) + } + + if g, e := ctx.LastInsertID, int64(4); g != e { + t.Fatal(g, e) + } + + if g, e := ctx.RowsAffected, int64(1); g != e { + t.Fatal(g, e) + } + + if _, _, err = db.Run(ctx, ` + BEGIN TRANSACTION; + DELETE FROM t WHERE i == 2; + COMMIT; + `); err != nil { + t.Fatal(err) + } + + if g, e := ctx.LastInsertID, int64(4); g != e { + t.Fatal(g, e) + } + + if g, e := ctx.RowsAffected, int64(2); g != e { + t.Fatal(g, e) + } + + if _, _, err = db.Run(ctx, ` + BEGIN TRANSACTION; + UPDATE t i = 42 WHERE i == 3; + COMMIT; + `); err != nil { + t.Fatal(err) + } + + if g, e := ctx.LastInsertID, int64(4); g != e { + t.Fatal(g, e) + } + + if g, e := ctx.RowsAffected, int64(1); g != e { + t.Fatal(g, e) + } +} + +func dumpDB(db *DB, tag string) (string, error) { + var buf bytes.Buffer + f := strutil.IndentFormatter(&buf, "\t") + f.Format("---- %s%i\n", tag) + for nm, tab := range db.root.tables { + h := tab.head + f.Format("%u%q: head %d, scols0 %q, scols %q%i\n", nm, h, cols2meta(tab.cols0), cols2meta(tab.cols)) + for h != 0 { + rec, err := db.store.Read(nil, h, tab.cols...) + if err != nil { + return "", err + } + + f.Format("record @%d: %v\n", h, rec) + h = rec[0].(int64) + } + f.Format("%u") + for i, v := range tab.indices { + if v == nil { + continue + } + + xname := v.name + cname := "id()" + if i != 0 { + cname = tab.cols0[i-1].name + } + f.Format("index %s on %s%i\n", xname, cname) + it, _, err := v.x.Seek(nil) + if err != nil { + return "", err + } + + for { + k, v, err := it.Next() + if err != nil { + if err == io.EOF { + break + } + + return "", err + } + + f.Format("%v: %v\n", k, v) + } + f.Format("%u") + } + } + + return buf.String(), nil +} + +func testIndices(db *DB, t *testing.T) { + ctx := NewRWCtx() + var err error + e := func(q string) { + if _, _, err = db.Run(ctx, q); err != nil { + t.Fatal(err) + } + + s, err := dumpDB(db, "post\n\t"+q) + if err != nil { + t.Fatal(err) + } + + t.Logf("%s\n\n", s) + if db.isMem { + return + } + + nm := db.Name() + if err = db.Close(); err != nil { + t.Fatal(err) + } + + if db, err = OpenFile(nm, &Options{}); err != nil { + t.Fatal(err) + } + + if s, err = dumpDB(db, "reopened"); err != nil { + t.Fatal(err) + } + + t.Logf("%s\n\n", s) + } + + e(` BEGIN TRANSACTION; + CREATE TABLE t (i int); + COMMIT;`) + e(` BEGIN TRANSACTION; + CREATE INDEX x ON t (id()); + COMMIT;`) + e(` BEGIN TRANSACTION; + INSERT INTO t VALUES(42); + COMMIT;`) + e(` BEGIN TRANSACTION; + INSERT INTO t VALUES(24); + COMMIT;`) + e(` BEGIN TRANSACTION; + CREATE INDEX xi ON t (i); + COMMIT;`) + e(` BEGIN TRANSACTION; + INSERT INTO t VALUES(1); + COMMIT;`) + e(` BEGIN TRANSACTION; + INSERT INTO t VALUES(999); + COMMIT;`) + e(` BEGIN TRANSACTION; + UPDATE t i = 240 WHERE i == 24; + COMMIT;`) + e(` BEGIN TRANSACTION; + DELETE FROM t WHERE i == 240; + COMMIT;`) + e(` BEGIN TRANSACTION; + TRUNCATE TABLE t; + COMMIT;`) + e(` BEGIN TRANSACTION; + DROP TABLE IF EXISTS t; + CREATE TABLE t (i int, s string); + CREATE INDEX xi ON t (i); + INSERT INTO t VALUES (42, "foo"); + COMMIT;`) + e(` BEGIN TRANSACTION; + ALTER TABLE t DROP COLUMN i; + COMMIT;`) + + e(` BEGIN TRANSACTION; + DROP TABLE IF EXISTS t; + CREATE TABLE t (i int); + CREATE INDEX x ON t (i); + INSERT INTO t VALUES (42); + INSERT INTO t SELECT 10*i FROM t; + COMMIT;`) + e(` BEGIN TRANSACTION; + DROP TABLE IF EXISTS t; + CREATE TABLE t (i int); + CREATE INDEX x ON t (i); + INSERT INTO t VALUES (42); + COMMIT; + BEGIN TRANSACTION; + INSERT INTO t SELECT 10*i FROM t; + COMMIT;`) + e(` BEGIN TRANSACTION; + DROP TABLE IF EXISTS t; + CREATE TABLE t (i int); + CREATE INDEX x ON t (i); + INSERT INTO t VALUES (42); + DROP INDEX x; + COMMIT;`) + e(` BEGIN TRANSACTION; + DROP TABLE IF EXISTS t; + CREATE TABLE t (i int); + CREATE INDEX x ON t (i); + INSERT INTO t VALUES (42); + COMMIT; + BEGIN TRANSACTION; + DROP INDEX x; + COMMIT;`) + e(` BEGIN TRANSACTION; + DROP TABLE IF EXISTS t; + CREATE TABLE t (i int); + CREATE INDEX x ON t (i); + INSERT INTO t VALUES (42); + COMMIT;`) + e(` + BEGIN TRANSACTION; + DROP INDEX x; + COMMIT;`) + e(` BEGIN TRANSACTION; + DROP TABLE IF EXISTS t; + CREATE TABLE t (i int); + CREATE INDEX x ON t (i); + ALTER TABLE t ADD s string; + COMMIT;`) + e(` BEGIN TRANSACTION; + DROP TABLE IF EXISTS t; + CREATE TABLE t (i int); + CREATE INDEX x ON t (i); + COMMIT;`) + e(` BEGIN TRANSACTION; + ALTER TABLE t ADD s string; + COMMIT;`) + e(` BEGIN TRANSACTION; + DROP TABLE IF EXISTS t; + CREATE TABLE t (i bigint); + CREATE INDEX x ON t (i); + INSERT INTO t VALUES(42); + COMMIT;`) + + if err = db.Close(); err != nil { + t.Fatal(err) + } +} + +func TestIndices(t *testing.T) { + db, err := OpenMem() + if err != nil { + t.Fatal(err) + } + + testIndices(db, t) + dir, err := ioutil.TempDir("", "ql-test") + + if err != nil { + t.Fatal(err) + } + + defer os.RemoveAll(dir) + + nm := filepath.Join(dir, "ql.db") + db, err = OpenFile(nm, &Options{CanCreate: true}) + if err != nil { + t.Fatal(err) + } + + testIndices(db, t) +} + +var benchmarkInsertBoolOnce = map[string]sync.Once{} + +func benchmarkInsertBool(b *testing.B, db *DB, size int, selectivity float64, index bool, teardown func()) { + if testing.Verbose() { + benchProlog(b) + id := fmt.Sprintf("%t|%d|%g|%t", db.isMem, size, selectivity, index) + once := benchmarkInsertBoolOnce[id] + once.Do(func() { + s := "INDEXED" + if !index { + s = "NON " + s + } + b.Logf(`Insert %d records into a table having a single bool %s column. Batch size: 1 record. + +`, size, s) + }) + benchmarkInsertBoolOnce[id] = once + } + + if teardown != nil { + defer teardown() + } + + ctx := NewRWCtx() + if _, _, err := db.Run(ctx, ` + BEGIN TRANSACTION; + CREATE TABLE t (b bool); + `); err != nil { + b.Fatal(err) + } + + if index { + if _, _, err := db.Run(ctx, ` + CREATE INDEX x ON t (b); + `); err != nil { + b.Fatal(err) + } + } + + ins, err := Compile("INSERT INTO t VALUES($1);") + if err != nil { + b.Fatal(err) + } + + trunc, err := Compile("TRUNCATE TABLE t;") + if err != nil { + b.Fatal(err) + } + + begin, err := Compile("BEGIN TRANSACTION;") + if err != nil { + b.Fatal(err) + } + + commit, err := Compile("COMMIT;") + if err != nil { + b.Fatal(err) + } + + rng := rand.New(rand.NewSource(42)) + debug.FreeOSMemory() + b.ResetTimer() + for i := 0; i < b.N; i++ { + b.StopTimer() + if i != 0 { + if _, _, err = db.Execute(ctx, begin); err != nil { + b.Fatal(err) + } + } + + if _, _, err = db.Execute(ctx, trunc); err != nil { + b.Fatal(err) + } + + b.StartTimer() + for j := 0; j < size; j++ { + if _, _, err = db.Execute(ctx, ins, rng.Float64() < selectivity); err != nil { + b.Fatal(err) + } + } + if _, _, err = db.Execute(ctx, commit); err != nil { + b.Fatal(err) + } + } + b.StopTimer() + b.SetBytes(int64(size) * benchScale) +} + +func benchmarkInsertBoolMem(b *testing.B, size int, sel float64, index bool) { + db, err := OpenMem() + if err != nil { + b.Fatal(err) + } + + benchmarkInsertBool(b, db, size, sel, index, nil) +} + +func BenchmarkInsertBoolMemNoX1e1(b *testing.B) { + benchmarkInsertBoolMem(b, 1e1, 0.5, false) +} + +func BenchmarkInsertBoolMemX1e1(b *testing.B) { + benchmarkInsertBoolMem(b, 1e1, 0.5, true) +} + +func BenchmarkInsertBoolMemNoX1e2(b *testing.B) { + benchmarkInsertBoolMem(b, 1e2, 0.5, false) +} + +func BenchmarkInsertBoolMemX1e2(b *testing.B) { + benchmarkInsertBoolMem(b, 1e2, 0.5, true) +} + +func BenchmarkInsertBoolMemNoX1e3(b *testing.B) { + benchmarkInsertBoolMem(b, 1e3, 0.5, false) +} + +func BenchmarkInsertBoolMemX1e3(b *testing.B) { + benchmarkInsertBoolMem(b, 1e3, 0.5, true) +} + +func BenchmarkInsertBoolMemNoX1e4(b *testing.B) { + benchmarkInsertBoolMem(b, 1e4, 0.5, false) +} + +func BenchmarkInsertBoolMemX1e4(b *testing.B) { + benchmarkInsertBoolMem(b, 1e4, 0.5, true) +} + +func BenchmarkInsertBoolMemNoX1e5(b *testing.B) { + benchmarkInsertBoolMem(b, 1e5, 0.5, false) +} + +func BenchmarkInsertBoolMemX1e5(b *testing.B) { + benchmarkInsertBoolMem(b, 1e5, 0.5, true) +} + +func benchmarkInsertBoolFile(b *testing.B, size int, sel float64, index bool) { + dir, err := ioutil.TempDir("", "ql-bench-") + if err != nil { + b.Fatal(err) + } + + n := runtime.GOMAXPROCS(0) + db, err := OpenFile(filepath.Join(dir, "ql.db"), &Options{CanCreate: true}) + if err != nil { + b.Fatal(err) + } + + benchmarkInsertBool(b, db, size, sel, index, func() { + runtime.GOMAXPROCS(n) + db.Close() + os.RemoveAll(dir) + }) +} + +func BenchmarkInsertBoolFileNoX1e1(b *testing.B) { + benchmarkInsertBoolFile(b, 1e1, 0.5, false) +} + +func BenchmarkInsertBoolFileX1e1(b *testing.B) { + benchmarkInsertBoolFile(b, 1e1, 0.5, true) +} + +func BenchmarkInsertBoolFileNoX1e2(b *testing.B) { + benchmarkInsertBoolFile(b, 1e2, 0.5, false) +} + +func BenchmarkInsertBoolFileX1e2(b *testing.B) { + benchmarkInsertBoolFile(b, 1e2, 0.5, true) +} + +func BenchmarkInsertBoolFileNoX1e3(b *testing.B) { + benchmarkInsertBoolFile(b, 1e3, 0.5, false) +} + +func BenchmarkInsertBoolFileX1e3(b *testing.B) { + benchmarkInsertBoolFile(b, 1e3, 0.5, true) +} + +var benchmarkSelectBoolOnce = map[string]sync.Once{} + +func benchmarkSelectBool(b *testing.B, db *DB, size int, selectivity float64, index bool, teardown func()) { + sel, err := Compile("SELECT * FROM t WHERE b;") + if err != nil { + b.Fatal(err) + } + + if testing.Verbose() { + benchProlog(b) + id := fmt.Sprintf("%t|%d|%g|%t", db.isMem, size, selectivity, index) + once := benchmarkSelectBoolOnce[id] + once.Do(func() { + s := "INDEXED" + if !index { + s = "NON " + s + } + b.Logf(`A table has a single %s bool column b. Insert %d records with a random bool value, +%.0f%% of them are true. Measure the performance of +%s +`, s, size, 100*selectivity, sel) + }) + benchmarkSelectBoolOnce[id] = once + } + + if teardown != nil { + defer teardown() + } + + ctx := NewRWCtx() + if _, _, err := db.Run(ctx, ` + BEGIN TRANSACTION; + CREATE TABLE t (b bool); + `); err != nil { + b.Fatal(err) + } + + if index { + if _, _, err := db.Run(ctx, ` + CREATE INDEX x ON t (b); + `); err != nil { + b.Fatal(err) + } + } + + ins, err := Compile("INSERT INTO t VALUES($1);") + if err != nil { + b.Fatal(err) + } + + var n int64 + rng := rand.New(rand.NewSource(42)) + for j := 0; j < size; j++ { + v := rng.Float64() < selectivity + if v { + n++ + } + if _, _, err = db.Execute(ctx, ins, v); err != nil { + b.Fatal(err) + } + } + + if _, _, err := db.Run(ctx, "COMMIT;"); err != nil { + b.Fatal(err) + } + + debug.FreeOSMemory() + b.ResetTimer() + for i := 0; i < b.N; i++ { + var m int64 + rss, _, err := db.Execute(nil, sel) + if err != nil { + b.Fatal(err) + } + + if err = rss[0].Do(false, func([]interface{}) (bool, error) { + m++ + return true, nil + }); err != nil { + b.Fatal(err) + } + if g, e := n, m; g != e { + b.Fatal(g, e) + } + } + b.StopTimer() + b.SetBytes(n * benchScale) +} + +func benchmarkSelectBoolMem(b *testing.B, size int, sel float64, index bool) { + db, err := OpenMem() + if err != nil { + b.Fatal(err) + } + + benchmarkSelectBool(b, db, size, sel, index, nil) +} + +// ---- + +func BenchmarkSelectBoolMemNoX1e1Perc50(b *testing.B) { + benchmarkSelectBoolMem(b, 1e1, 0.5, false) +} + +func BenchmarkSelectBoolMemX1e1Perc50(b *testing.B) { + benchmarkSelectBoolMem(b, 1e1, 0.5, true) +} + +func BenchmarkSelectBoolMemNoX1e2Perc50(b *testing.B) { + benchmarkSelectBoolMem(b, 1e2, 0.5, false) +} + +func BenchmarkSelectBoolMemX1e2Perc50(b *testing.B) { + benchmarkSelectBoolMem(b, 1e2, 0.5, true) +} + +func BenchmarkSelectBoolMemNoX1e3Perc50(b *testing.B) { + benchmarkSelectBoolMem(b, 1e3, 0.5, false) +} + +func BenchmarkSelectBoolMemX1e3Perc50(b *testing.B) { + benchmarkSelectBoolMem(b, 1e3, 0.5, true) +} + +func BenchmarkSelectBoolMemNoX1e4Perc50(b *testing.B) { + benchmarkSelectBoolMem(b, 1e4, 0.5, false) +} + +func BenchmarkSelectBoolMemX1e4Perc50(b *testing.B) { + benchmarkSelectBoolMem(b, 1e4, 0.5, true) +} + +func BenchmarkSelectBoolMemNoX1e5Perc50(b *testing.B) { + benchmarkSelectBoolMem(b, 1e5, 0.5, false) +} + +func BenchmarkSelectBoolMemX1e5Perc50(b *testing.B) { + benchmarkSelectBoolMem(b, 1e5, 0.5, true) +} + +// ---- + +func BenchmarkSelectBoolMemNoX1e1Perc5(b *testing.B) { + benchmarkSelectBoolMem(b, 1e1, 0.05, false) +} + +func BenchmarkSelectBoolMemX1e1Perc5(b *testing.B) { + benchmarkSelectBoolMem(b, 1e1, 0.05, true) +} + +func BenchmarkSelectBoolMemNoX1e2Perc5(b *testing.B) { + benchmarkSelectBoolMem(b, 1e2, 0.05, false) +} + +func BenchmarkSelectBoolMemX1e2Perc5(b *testing.B) { + benchmarkSelectBoolMem(b, 1e2, 0.05, true) +} + +func BenchmarkSelectBoolMemNoX1e3Perc5(b *testing.B) { + benchmarkSelectBoolMem(b, 1e3, 0.05, false) +} + +func BenchmarkSelectBoolMemX1e3Perc5(b *testing.B) { + benchmarkSelectBoolMem(b, 1e3, 0.05, true) +} + +func BenchmarkSelectBoolMemNoX1e4Perc5(b *testing.B) { + benchmarkSelectBoolMem(b, 1e4, 0.05, false) +} + +func BenchmarkSelectBoolMemX1e4Perc5(b *testing.B) { + benchmarkSelectBoolMem(b, 1e4, 0.05, true) +} + +func BenchmarkSelectBoolMemNoX1e5Perc5(b *testing.B) { + benchmarkSelectBoolMem(b, 1e5, 0.05, false) +} + +func BenchmarkSelectBoolMemX1e5Perc5(b *testing.B) { + benchmarkSelectBoolMem(b, 1e5, 0.05, true) +} + +func benchmarkSelectBoolFile(b *testing.B, size int, sel float64, index bool) { + dir, err := ioutil.TempDir("", "ql-bench-") + if err != nil { + b.Fatal(err) + } + + n := runtime.GOMAXPROCS(0) + db, err := OpenFile(filepath.Join(dir, "ql.db"), &Options{CanCreate: true}) + if err != nil { + b.Fatal(err) + } + + benchmarkSelectBool(b, db, size, sel, index, func() { + runtime.GOMAXPROCS(n) + db.Close() + os.RemoveAll(dir) + }) +} + +// ---- + +func BenchmarkSelectBoolFileNoX1e1Perc50(b *testing.B) { + benchmarkSelectBoolFile(b, 1e1, 0.5, false) +} + +func BenchmarkSelectBoolFileX1e1Perc50(b *testing.B) { + benchmarkSelectBoolFile(b, 1e1, 0.5, true) +} + +func BenchmarkSelectBoolFileNoX1e2Perc50(b *testing.B) { + benchmarkSelectBoolFile(b, 1e2, 0.5, false) +} + +func BenchmarkSelectBoolFileX1e2Perc50(b *testing.B) { + benchmarkSelectBoolFile(b, 1e2, 0.5, true) +} + +func BenchmarkSelectBoolFileNoX1e3Perc50(b *testing.B) { + benchmarkSelectBoolFile(b, 1e3, 0.5, false) +} + +func BenchmarkSelectBoolFileX1e3Perc50(b *testing.B) { + benchmarkSelectBoolFile(b, 1e3, 0.5, true) +} + +func BenchmarkSelectBoolFileNoX1e4Perc50(b *testing.B) { + benchmarkSelectBoolFile(b, 1e4, 0.5, false) +} + +func BenchmarkSelectBoolFileX1e4Perc50(b *testing.B) { + benchmarkSelectBoolFile(b, 1e4, 0.5, true) +} + +// ---- + +func BenchmarkSelectBoolFileNoX1e1Perc5(b *testing.B) { + benchmarkSelectBoolFile(b, 1e1, 0.05, false) +} + +func BenchmarkSelectBoolFileX1e1Perc5(b *testing.B) { + benchmarkSelectBoolFile(b, 1e1, 0.05, true) +} + +func BenchmarkSelectBoolFileNoX1e2Perc5(b *testing.B) { + benchmarkSelectBoolFile(b, 1e2, 0.05, false) +} + +func BenchmarkSelectBoolFileX1e2Perc5(b *testing.B) { + benchmarkSelectBoolFile(b, 1e2, 0.05, true) +} + +func BenchmarkSelectBoolFileNoX1e3Perc5(b *testing.B) { + benchmarkSelectBoolFile(b, 1e3, 0.05, false) +} + +func BenchmarkSelectBoolFileX1e3Perc5(b *testing.B) { + benchmarkSelectBoolFile(b, 1e3, 0.05, true) +} + +func BenchmarkSelectBoolFileNoX1e4Perc5(b *testing.B) { + benchmarkSelectBoolFile(b, 1e4, 0.05, false) +} + +func BenchmarkSelectBoolFileX1e4Perc5(b *testing.B) { + benchmarkSelectBoolFile(b, 1e4, 0.05, true) +} + +func TestIndex(t *testing.T) { + db, err := OpenMem() + if err != nil { + t.Fatal(err) + } + + ctx := NewRWCtx() + if _, _, err := db.Run(ctx, ` + BEGIN TRANSACTION; + CREATE TABLE t (b bool); + `); err != nil { + t.Fatal(err) + } + + if _, _, err := db.Run(ctx, ` + CREATE INDEX x ON t (b); + `); err != nil { + t.Fatal(err) + } + + ins, err := Compile("INSERT INTO t VALUES($1);") + if err != nil { + t.Fatal(err) + } + + size, selectivity := int(1e1), 0.5 + rng := rand.New(rand.NewSource(42)) + var n int64 + for j := 0; j < size; j++ { + v := rng.Float64() < selectivity + if v { + n++ + t.Logf("id %d <- true", j+1) + } + if _, _, err = db.Execute(ctx, ins, v); err != nil { + t.Fatal(err) + } + } + + if _, _, err := db.Run(ctx, "COMMIT;"); err != nil { + t.Fatal(err) + } + + s, err := dumpDB(db, "") + if err != nil { + t.Fatal(err) + } + + t.Logf("n: %d\n%s", n, s) + sel, err := Compile("SELECT id(), b FROM t WHERE b;") + if err != nil { + t.Fatal(err) + } + + var m int64 + rss, _, err := db.Execute(nil, sel) + if err != nil { + t.Fatal(err) + } + + if err = rss[0].Do(false, func(rec []interface{}) (bool, error) { + t.Logf("%v", rec) + m++ + return true, nil + }); err != nil { + t.Fatal(err) + } + + if g, e := n, m; g != e { + t.Fatal(g, e) + } +} + +var benchmarkCrossJoinOnce = map[string]sync.Once{} + +func benchmarkCrossJoin(b *testing.B, db *DB, create, sel List, size1, size2 int, index bool, teardown func()) { + if testing.Verbose() { + benchProlog(b) + id := fmt.Sprintf("%t|%d|%d|%t", db.isMem, size1, size2, index) + once := benchmarkCrossJoinOnce[id] + once.Do(func() { + s := "INDEXED " + if !index { + s = "NON " + s + } + b.Logf(`Fill two %stables with %d and %d records of random numbers [0, 1). Measure the performance of +%s +`, s, size1, size2, sel) + }) + benchmarkCrossJoinOnce[id] = once + } + + if teardown != nil { + defer teardown() + } + + ctx := NewRWCtx() + if _, _, err := db.Execute(ctx, create); err != nil { + b.Fatal(err) + } + + if index { + if _, _, err := db.Execute(ctx, xjoinX); err != nil { + b.Fatal(err) + } + } + + rng := rand.New(rand.NewSource(42)) + for i := 0; i < size1; i++ { + if _, _, err := db.Execute(ctx, xjoinT, rng.Float64()); err != nil { + b.Fatal(err) + } + } + for i := 0; i < size2; i++ { + if _, _, err := db.Execute(ctx, xjoinU, rng.Float64()); err != nil { + b.Fatal(err) + } + } + + if _, _, err := db.Run(ctx, "COMMIT"); err != nil { + b.Fatal(err) + } + + rs, _, err := db.Execute(nil, sel) + if err != nil { + b.Fatal(err) + } + + var n int + debug.FreeOSMemory() + b.ResetTimer() + for i := 0; i < b.N; i++ { + n = 0 + if err := rs[0].Do(false, func(rec []interface{}) (bool, error) { + n++ + return true, nil + }); err != nil { + b.Fatal(err) + } + } + b.StopTimer() + b.SetBytes(int64(n) * benchScale) +} + +var ( + xjoinCreate = MustCompile(`BEGIN TRANSACTION; + CREATE TABLE t (f float); + CREATE TABLE u (f float);`) + xjoinSel = MustCompile(`SELECT * FROM (SELECT f FROM t WHERE f < 0.1), (SELECT f FROM u where f < 0.1);`) + xjoinT = MustCompile("INSERT INTO t VALUES($1);") + xjoinU = MustCompile("INSERT INTO u VALUES($1);") + xjoinX = MustCompile(`CREATE INDEX x ON t (f); CREATE INDEX y ON u (f);`) +) + +func benchmarkCrossJoinMem(b *testing.B, size1, size2 int, index bool) { + db, err := OpenMem() + if err != nil { + b.Fatal(err) + } + + benchmarkCrossJoin(b, db, xjoinCreate, xjoinSel, size1, size2, index, nil) +} + +func benchmarkCrossJoinFile(b *testing.B, size1, size2 int, index bool) { + dir, err := ioutil.TempDir("", "ql-bench-") + if err != nil { + b.Fatal(err) + } + + n := runtime.GOMAXPROCS(0) + db, err := OpenFile(filepath.Join(dir, "ql.db"), &Options{CanCreate: true}) + if err != nil { + b.Fatal(err) + } + + benchmarkCrossJoin(b, db, xjoinCreate, xjoinSel, size1, size2, index, func() { + runtime.GOMAXPROCS(n) + db.Close() + os.RemoveAll(dir) + }) +} + +func BenchmarkCrossJoinMem1e1NoX1e2(b *testing.B) { + benchmarkCrossJoinMem(b, 1e1, 1e2, false) +} + +func BenchmarkCrossJoinMem1e1X1e2(b *testing.B) { + benchmarkCrossJoinMem(b, 1e1, 1e2, true) +} + +func BenchmarkCrossJoinMem1e2NoX1e3(b *testing.B) { + benchmarkCrossJoinMem(b, 1e2, 1e3, false) +} + +func BenchmarkCrossJoinMem1e2X1e3(b *testing.B) { + benchmarkCrossJoinMem(b, 1e2, 1e3, true) +} + +func BenchmarkCrossJoinMem1e3NoX1e4(b *testing.B) { + benchmarkCrossJoinMem(b, 1e3, 1e4, false) +} + +func BenchmarkCrossJoinMem1e3X1e4(b *testing.B) { + benchmarkCrossJoinMem(b, 1e3, 1e4, true) +} + +func BenchmarkCrossJoinMem1e2NoX1e1(b *testing.B) { + benchmarkCrossJoinMem(b, 1e2, 1e1, false) +} + +func BenchmarkCrossJoinMem1e2X1e1(b *testing.B) { + benchmarkCrossJoinMem(b, 1e2, 1e1, true) +} + +func BenchmarkCrossJoinMem1e3NoX1e2(b *testing.B) { + benchmarkCrossJoinMem(b, 1e3, 1e2, false) +} + +func BenchmarkCrossJoinMem1e3X1e2(b *testing.B) { + benchmarkCrossJoinMem(b, 1e3, 1e2, true) +} + +func BenchmarkCrossJoinMem1e4NoX1e3(b *testing.B) { + benchmarkCrossJoinMem(b, 1e4, 1e3, false) +} + +func BenchmarkCrossJoinMem1e4X1e3(b *testing.B) { + benchmarkCrossJoinMem(b, 1e4, 1e3, true) +} + +// ---- + +func BenchmarkCrossJoinFile1e1NoX1e2(b *testing.B) { + benchmarkCrossJoinFile(b, 1e1, 1e2, false) +} + +func BenchmarkCrossJoinFile1e1X1e2(b *testing.B) { + benchmarkCrossJoinFile(b, 1e1, 1e2, true) +} + +func BenchmarkCrossJoinFile1e2NoX1e3(b *testing.B) { + benchmarkCrossJoinFile(b, 1e2, 1e3, false) +} + +func BenchmarkCrossJoinFile1e2X1e3(b *testing.B) { + benchmarkCrossJoinFile(b, 1e2, 1e3, true) +} + +func BenchmarkCrossJoinFile1e3NoX1e4(b *testing.B) { + benchmarkCrossJoinFile(b, 1e3, 1e4, false) +} + +func BenchmarkCrossJoinFile1e3X1e4(b *testing.B) { + benchmarkCrossJoinFile(b, 1e3, 1e4, true) +} + +func BenchmarkCrossJoinFile1e2NoX1e1(b *testing.B) { + benchmarkCrossJoinFile(b, 1e2, 1e1, false) +} + +func BenchmarkCrossJoinFile1e2X1e1(b *testing.B) { + benchmarkCrossJoinFile(b, 1e2, 1e1, true) +} + +func BenchmarkCrossJoinFile1e3NoX1e2(b *testing.B) { + benchmarkCrossJoinFile(b, 1e3, 1e2, false) +} + +func BenchmarkCrossJoinFile1e3X1e2(b *testing.B) { + benchmarkCrossJoinFile(b, 1e3, 1e2, true) +} + +func BenchmarkCrossJoinFile1e4NoX1e3(b *testing.B) { + benchmarkCrossJoinFile(b, 1e4, 1e3, false) +} + +func BenchmarkCrossJoinFile1e4X1e3(b *testing.B) { + benchmarkCrossJoinFile(b, 1e4, 1e3, true) +} + +func TestIssue35(t *testing.T) { + var bigInt big.Int + var bigRat big.Rat + bigInt.SetInt64(42) + bigRat.SetInt64(24) + db, err := OpenMem() + if err != nil { + t.Fatal(err) + } + + ctx := NewRWCtx() + _, _, err = db.Run(ctx, ` + BEGIN TRANSACTION; + CREATE TABLE t (i bigint, r bigrat); + INSERT INTO t VALUES ($1, $2); + COMMIT; + `, bigInt, bigRat) + if err != nil { + t.Fatal(err) + } + + bigInt.SetInt64(420) + bigRat.SetInt64(240) + + rs, _, err := db.Run(nil, "SELECT * FROM t;") + if err != nil { + t.Fatal(err) + } + + n := 0 + if err := rs[0].Do(false, func(rec []interface{}) (bool, error) { + switch n { + case 0: + n++ + if g, e := fmt.Sprint(rec), "[42 24/1]"; g != e { + t.Fatal(g, e) + } + + return true, nil + default: + t.Fatal(n) + panic("unreachable") + } + }); err != nil { + t.Fatal(err) + } +} + +func TestIssue28(t *testing.T) { + RegisterDriver() + dir, err := ioutil.TempDir("", "ql-test-") + if err != nil { + t.Fatal(err) + } + + defer os.RemoveAll(dir) + pth := filepath.Join(dir, "ql.db") + sdb, err := sql.Open("ql", "file://"+pth) + if err != nil { + t.Fatal(err) + } + + defer sdb.Close() + tx, err := sdb.Begin() + if err != nil { + t.Fatal(err) + } + + if _, err = tx.Exec("CREATE TABLE t (i int);"); err != nil { + t.Fatal(err) + } + + if err = tx.Commit(); err != nil { + t.Fatal(err) + } + + if _, err = os.Stat(pth); err != nil { + t.Fatal(err) + } + + pth = filepath.Join(dir, "mem.db") + mdb, err := sql.Open("ql", "memory://"+pth) + if err != nil { + t.Fatal(err) + } + + defer mdb.Close() + if tx, err = mdb.Begin(); err != nil { + t.Fatal(err) + } + + if _, err = tx.Exec("CREATE TABLE t (i int);"); err != nil { + t.Fatal(err) + } + + if err = tx.Commit(); err != nil { + t.Fatal(err) + } + + if _, err = os.Stat(pth); err == nil { + t.Fatal(err) + } +} + +func TestIsPossiblyRewriteableCrossJoinWhereExpression(t *testing.T) { + db, err := OpenMem() + if err != nil { + t.Fatal(err) + } + + table := []struct { + q string + e bool + slist string + }{ + // 0 + {"SELECT * FROM t WHERE !c", false, ""}, + {"SELECT * FROM t WHERE !t.c && 4 < !u.c", true, "!c|4 3", false, ""}, + // 10 + {"SELECT * FROM t WHERE c", false, ""}, + {"SELECT * FROM t WHERE false == !t.c", true, "false==!c"}, //TODO(indices) support !c relOp fixedValue (rewrite false==!c -> !c, true==c -> c, true != c -> !c, etc.) + {"SELECT * FROM t WHERE false == ^t.c", false, ""}, + {"SELECT * FROM t WHERE false == t.c", true, "false==c"}, + {"SELECT * FROM t WHERE t.c && 4 < u.c", true, "c|4 0", true, "c|c|c>0"}, + {"SELECT * FROM t WHERE t.c && u.c && v.c", true, "c|c|c"}, + {"SELECT * FROM t WHERE t.c && u.c > 0 && v.c > 0", true, "c|c>0|c>0"}, + {"SELECT * FROM t WHERE t.c && u.c", true, "c|c"}, + // 20 + {"SELECT * FROM t WHERE t.c < 3 && u.c > 2 && v.c != 42", true, "c<3|c>2|c!=42"}, + {"SELECT * FROM t WHERE t.c > 0 && u.c && v.c", true, "c>0|c|c"}, + {"SELECT * FROM t WHERE t.c > 0 && u.c > 0 && v.c > 0", true, "c>0|c>0|c>0"}, + {"SELECT * FROM t WHERE t.c > 3 && 4 < u.c", true, "c>3|4 3 && u.c", true, "c>3|c"}, + // 25 + {"SELECT * FROM t WHERE t.c > 3", true, "c>3"}, + {"SELECT * FROM t WHERE t.c", true, "c"}, + {"SELECT * FROM t WHERE u.c == !t.c", false, ""}, + {"SELECT * FROM t WHERE u.c == 42", true, "c==42"}, + {"SELECT * FROM t WHERE u.c == ^t.c", false, ""}, + } + + for i, test := range table { + q, e, list := test.q, test.e, strings.Split(test.slist, "|") + sort.Strings(list) + l, err := Compile(q) + if err != nil { + t.Fatalf("%s\n%v", q, err) + } + + rs, _, err := db.Execute(nil, l) + if err != nil { + t.Fatalf("%s\n%v", q, err) + } + + r := rs[0].(recordset) + sel := r.rset.(*selectRset) + where := sel.src.(*whereRset) + g, glist := isPossiblyRewriteableCrossJoinWhereExpression(where.expr) + if g != e { + t.Fatalf("%d: %sg: %v e: %v", i, l, g, e) + } + + if !g { + continue + } + + a := []string{} + for _, v := range glist { + a = append(a, v.expr.String()) + } + sort.Strings(a) + if g, e := len(glist), len(list); g != e { + t.Fatalf("%d: g: %v, e: %v", i, glist, list) + } + + for j, g := range a { + if e := list[j]; g != e { + t.Fatalf("%d[%d]: g: %v e: %v", i, j, g, e) + } + } + } +} + +func dumpFields(f []*fld) string { + a := []string{} + for _, v := range f { + a = append(a, fmt.Sprintf("%p: %q", v, v.name)) + } + return strings.Join(a, ", ") +} + +func rndBytes(n int, seed int64) []byte { + rng := rand.New(rand.NewSource(seed)) + b := make([]byte, n) + for i := range b { + b[i] = byte(rng.Int()) + } + return b +} + +func TestIssue50(t *testing.T) { // https://github.com/cznic/ql/issues/50 + const dbFileName = "scans.qldb" + + type Scan struct { + ID int + Jobname string + Timestamp time.Time + Data []byte + + X, Y, Z float64 + Alpha, Beta, Gamma float64 + } + + // querys + const dbCreateTables = ` +CREATE TABLE IF NOT EXISTS Scans ( + X float, + Y float, + Z float, + Alpha float, + Beta float, + Gamma float, + Timestamp time, + Jobname string, + Data blob +); +CREATE INDEX IF NOT EXISTS ScansId on Scans (id()); +` + + const dbInsertScan = ` +INSERT INTO Scans (Timestamp,Jobname,X,Y,Z,Alpha,Beta,Gamma,Data) VALUES( +$1, +$2, +$3,$4,$5, +$6,$7,$8, +$9 +); +` + + const dbSelectOverview = `SELECT id() as ID, Jobname, Timestamp, Data, Y,Z, Gamma From Scans;` + + dir, err := ioutil.TempDir("", "ql-test-") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + // create db + t.Log("Opening db.") + RegisterDriver() + db, err := sql.Open("ql", filepath.Join(dir, dbFileName)) + if err != nil { + t.Fatal(err) + } + defer db.Close() + + tx, err := db.Begin() + if err != nil { + return + } + _, err = tx.Exec(dbCreateTables) + if err != nil { + t.Fatal("could not create Table.", err) + } + + err = tx.Commit() + if err != nil { + t.Fatal("could not commit transaction.", err) + } + + // insert some data + tx, err = db.Begin() + if err != nil { + t.Fatalf("db.Begin() Error - %v", err) + } + + stmt, err := tx.Prepare(dbInsertScan) + if err != nil { + t.Fatalf("tx.Prepare(dbInsertScan) Error - %v", err) + } + defer stmt.Close() + + scanFnames := []string{"1.xyz", "2.xyz", "3.xyz"} + for _, fname := range scanFnames { + scanData, err := ioutil.ReadFile(filepath.Join("_testdata", fname)) + if err != nil { + t.Fatalf("ioutil.ReadFile(%s) Error - %v", fname, err) + } + + // hash before insert + h := md5.New() + h.Write(scanData) + + t.Logf("md5 of %s: %x", fname, h.Sum(nil)) + + _, err = stmt.Exec(time.Now(), "Job-0815", 1.0, 2.0, 3.0, 0.1, 0.2, 0.3, scanData) + if err != nil { + t.Fatalf("stmt.Exec() Error - %v", err) + return + } + } + + err = tx.Commit() + if err != nil { + t.Fatalf("tx.Commit() Error - %v", err) + } + + // select the inserted data + rows, err := db.Query(dbSelectOverview) + if err != nil { + t.Fatalf("db.Query(dbSelectOverview) Error - %v", err) + } + defer rows.Close() + + var scans []Scan + for rows.Next() { + var s Scan + var data []byte + + err = rows.Scan(&s.ID, &s.Jobname, &s.Timestamp, &data, &s.Y, &s.Z, &s.Gamma) + if err != nil { + t.Fatalf("rows.Scan(&s..) Error - %v", err) + } + scans = append(scans, s) + + // hash after select + h := md5.New() + h.Write(data) + + t.Logf("md5 of %d: %x", s.ID, h.Sum(nil)) + } + + err = rows.Err() + if err != nil { + t.Fatalf("rows.Err() Error - %v", err) + } + + t.Log("Done:", scans) +} + +func TestIssue56(t *testing.T) { + var schema = ` +CREATE TABLE IF NOT EXISTS Test ( + A string, + B string, + Suppressed bool, +); +CREATE INDEX IF NOT EXISTS aIdx ON Test (A); +CREATE INDEX IF NOT EXISTS bIdx ON Test (B); +` + + RegisterDriver() + dir, err := ioutil.TempDir("", "ql-test-") + if err != nil { + t.Fatal(err) + } + + defer os.RemoveAll(dir) + pth := filepath.Join(dir, "test.db") + db, err := sql.Open("ql", "file://"+pth) + if err != nil { + t.Fatal(err) + } + + defer db.Close() + + tx, err := db.Begin() + if err != nil { + t.Fatal(err) + } + + _, err = tx.Exec(schema) + if err != nil { + t.Fatal(err) + } + + err = tx.Commit() + if err != nil { + t.Fatal(err) + } + + // Open a new transaction and do a SELECT + + tx, err = db.Begin() + if err != nil { + t.Fatal(err) + } + + var id int64 + row := tx.QueryRow("SELECT * FROM Test") + err = row.Scan(&id) // <-- Blocks here + + switch err { + case sql.ErrNoRows: + break + case nil: + break + default: + t.Fatal(err) + } + + tx.Rollback() + return +} + +func TestRecordSetRows(t *testing.T) { + db, err := OpenMem() + if err != nil { + t.Fatal(err) + } + + rss, _, err := db.Run(NewRWCtx(), ` + BEGIN TRANSACTION; + CREATE TABLE t (i int); + INSERT INTO t VALUES (1), (2), (3), (4), (5); + COMMIT; + SELECT * FROM t ORDER BY i; + `) + if err != nil { + t.Fatal(err) + } + + tab := []struct { + limit, offset int + result []int64 + }{ + // 0 + {-1, 0, []int64{1, 2, 3, 4, 5}}, + {0, 0, nil}, + {1, 0, []int64{1}}, + {2, 0, []int64{1, 2}}, + {3, 0, []int64{1, 2, 3}}, + // 5 + {4, 0, []int64{1, 2, 3, 4}}, + {5, 0, []int64{1, 2, 3, 4, 5}}, + {6, 0, []int64{1, 2, 3, 4, 5}}, + {-1, 0, []int64{1, 2, 3, 4, 5}}, + {-1, 1, []int64{2, 3, 4, 5}}, + // 10 + {-1, 2, []int64{3, 4, 5}}, + {-1, 3, []int64{4, 5}}, + {-1, 4, []int64{5}}, + {-1, 5, nil}, + {3, 0, []int64{1, 2, 3}}, + // 15 + {3, 1, []int64{2, 3, 4}}, + {3, 2, []int64{3, 4, 5}}, + {3, 3, []int64{4, 5}}, + {3, 4, []int64{5}}, + {3, 5, nil}, + // 20 + {-1, 2, []int64{3, 4, 5}}, + {0, 2, nil}, + {1, 2, []int64{3}}, + {2, 2, []int64{3, 4}}, + {3, 2, []int64{3, 4, 5}}, + // 25 + {4, 2, []int64{3, 4, 5}}, + } + + rs := rss[0] + for iTest, test := range tab { + t.Log(iTest) + rows, err := rs.Rows(test.limit, test.offset) + if err != nil { + t.Fatal(err) + } + + if g, e := len(rows), len(test.result); g != e { + t.Log(rows, test.result) + t.Fatal(g, e) + } + + for i, row := range rows { + if g, e := len(row), 1; g != e { + t.Fatal(i, g, i) + } + + if g, e := row[0], test.result[i]; g != e { + t.Fatal(i, g, e) + } + } + } +} + +func TestRecordFirst(t *testing.T) { + q := MustCompile("SELECT * FROM t WHERE i > $1 ORDER BY i;") + db, err := OpenMem() + if err != nil { + t.Fatal(err) + } + + if _, _, err = db.Run(NewRWCtx(), ` + BEGIN TRANSACTION; + CREATE TABLE t (i int); + INSERT INTO t VALUES (1), (2), (3), (4), (5); + COMMIT; + `); err != nil { + t.Fatal(err) + } + + tab := []struct { + par int64 + result int64 + }{ + {-1, 1}, + {0, 1}, + {1, 2}, + {2, 3}, + {3, 4}, + {4, 5}, + {5, -1}, + } + + for iTest, test := range tab { + t.Log(iTest) + rss, _, err := db.Execute(nil, q, test.par) + if err != nil { + t.Fatal(err) + } + + row, err := rss[0].FirstRow() + if err != nil { + t.Fatal(err) + } + + switch { + case test.result < 0: + if row != nil { + t.Fatal(row) + } + default: + if row == nil { + t.Fatal(row) + } + + if g, e := len(row), 1; g != e { + t.Fatal(g, e) + } + + if g, e := row[0], test.result; g != e { + t.Fatal(g, e) + } + } + } +} + +var issue63 = MustCompile(` +BEGIN TRANSACTION; + CREATE TABLE Forecast (WeatherProvider string, Timestamp time, MinTemp int32, MaxTemp int32); + INSERT INTO Forecast VALUES ("dwd.de", now(), 20, 22); +COMMIT; +SELECT * FROM Forecast WHERE Timestamp > 0;`) + +func TestIssue63(t *testing.T) { + db, err := OpenMem() + if err != nil { + t.Fatal(err) + } + + rs, _, err := db.Execute(NewRWCtx(), issue63) + if err != nil { + t.Fatal(err) + } + + if _, err = rs[0].Rows(-1, 0); err == nil { + t.Fatal(err) + } + + t.Log(err) + if g, e := strings.Contains(err.Error(), "invalid operation"), true; g != e { + t.Fatal(g, e) + } + + if g, e := strings.Contains(err.Error(), "mismatched types time.Time and int64"), true; g != e { + t.Fatal(g, e) + } +} + +const issue66Src = ` +BEGIN TRANSACTION; + CREATE TABLE t (i int); + CREATE UNIQUE INDEX x ON t (i); + INSERT INTO t VALUES (1), (1); +COMMIT;` + +var issue66 = MustCompile(issue66Src) + +func TestIssue66Mem(t *testing.T) { + db, err := OpenMem() + if err != nil { + t.Fatal(err) + } + + _, _, err = db.Execute(NewRWCtx(), issue66) + if err == nil { + t.Fatal(err) + } + + t.Log(err) +} + +func TestIssue66File(t *testing.T) { + dir, err := ioutil.TempDir("", "ql-test-") + if err != nil { + t.Fatal(err) + } + + defer os.RemoveAll(dir) + + db, err := OpenFile(filepath.Join(dir, "test.db"), &Options{CanCreate: true}) + if err != nil { + t.Fatal(err) + } + + defer db.Close() + + _, _, err = db.Execute(NewRWCtx(), issue66) + if err == nil { + t.Fatal(err) + } + + t.Log(err) +} + +func TestIssue66MemDriver(t *testing.T) { + RegisterMemDriver() + db, err := sql.Open("ql-mem", "TestIssue66MemDriver-"+fmt.Sprintf("%d", time.Now().UnixNano())) + if err != nil { + t.Fatal(err) + } + + defer db.Close() + + tx, err := db.Begin() + if err != nil { + t.Fatal(err) + } + + if _, err = tx.Exec(issue66Src); err == nil { + t.Fatal(err) + } + + t.Log(err) +} + +func TestIssue66FileDriver(t *testing.T) { + RegisterDriver() + dir, err := ioutil.TempDir("", "ql-test-") + if err != nil { + t.Fatal(err) + } + + defer os.RemoveAll(dir) + + db, err := sql.Open("ql", filepath.Join(dir, "TestIssue66MemDriver")) + if err != nil { + t.Fatal(err) + } + + defer db.Close() + + tx, err := db.Begin() + if err != nil { + t.Fatal(err) + } + + if _, err = tx.Exec(issue66Src); err == nil { + t.Fatal(err) + } + + t.Log(err) +} + +func Example_lIKE() { + db, err := OpenMem() + if err != nil { + panic(err) + } + + rss, _, err := db.Run(NewRWCtx(), ` + BEGIN TRANSACTION; + CREATE TABLE t (i int, s string); + INSERT INTO t VALUES + (1, "seafood"), + (2, "A fool on the hill"), + (3, NULL), + (4, "barbaz"), + (5, "foobar"), + ; + COMMIT; + + SELECT * FROM t WHERE s LIKE "foo" ORDER BY i; + SELECT * FROM t WHERE s LIKE "^bar" ORDER BY i; + SELECT * FROM t WHERE s LIKE "bar$" ORDER BY i; + SELECT * FROM t WHERE !(s LIKE "foo") ORDER BY i;`, + ) + if err != nil { + panic(err) + } + + for _, rs := range rss { + if err := rs.Do(false, func(data []interface{}) (bool, error) { + fmt.Println(data) + return true, nil + }); err != nil { + panic(err) + } + fmt.Println("----") + } + // Output: + // [1 seafood] + // [2 A fool on the hill] + // [5 foobar] + // ---- + // [4 barbaz] + // ---- + // [5 foobar] + // ---- + // [4 barbaz] + // ---- +} + +func TestIssue73(t *testing.T) { + RegisterDriver() + dir, err := ioutil.TempDir("", "ql-test-") + if err != nil { + t.Fatal(err) + } + + defer os.RemoveAll(dir) + pth := filepath.Join(dir, "test.db") + + for i := 0; i < 10; i++ { + var db *sql.DB + var tx *sql.Tx + var err error + var row *sql.Row + var name string + + if db, err = sql.Open("ql", pth); err != nil { + t.Fatal("sql.Open: ", err) + } + + t.Log("Call to db.Begin()") + if tx, err = db.Begin(); err != nil { + t.Fatal("db.Begin: ", err) + } + + t.Log("Call to tx.QueryRow()") + row = tx.QueryRow(`SELECT Name FROM __Table`) + t.Log("Call to tx.Commit()") + if err = tx.Commit(); err != nil { + t.Fatal("tx.Commit: ", err) + } + + row.Scan(&name) + t.Log("name: ", name) + } +} + +func Example_id() { + db, err := OpenMem() + if err != nil { + panic(err) + } + + rss, _, err := db.Run(NewRWCtx(), ` + BEGIN TRANSACTION; + CREATE TABLE foo (i int); + INSERT INTO foo VALUES (10), (20); + CREATE TABLE bar (fooID int, s string); + INSERT INTO bar SELECT id(), "ten" FROM foo WHERE i == 10; + INSERT INTO bar SELECT id(), "twenty" FROM foo WHERE i == 20; + COMMIT; + SELECT * + FROM foo, bar + WHERE bar.fooID == id(foo) + ORDER BY id(foo);`, + ) + if err != nil { + panic(err) + } + + for _, rs := range rss { + if err := rs.Do(false, func(data []interface{}) (bool, error) { + fmt.Println(data) + return true, nil + }); err != nil { + panic(err) + } + fmt.Println("----") + } + // Output: + // [10 1 ten] + // [20 2 twenty] + // ---- +} diff --git a/Godeps/_workspace/src/github.com/cznic/ql/benchcmp b/Godeps/_workspace/src/github.com/cznic/ql/benchcmp new file mode 100644 index 0000000..a0f7a50 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/ql/benchcmp @@ -0,0 +1 @@ +go test -test.run NONE -test.bench . -test.benchmem -timeout 1h | tee $1 diff --git a/Godeps/_workspace/src/github.com/cznic/ql/blob.go b/Godeps/_workspace/src/github.com/cznic/ql/blob.go new file mode 100644 index 0000000..0aec6a9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/ql/blob.go @@ -0,0 +1,140 @@ +// Copyright 2014 The ql 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 ql + +import ( + "bytes" + "encoding/gob" + "log" + "math/big" + "sync" + "time" +) + +const shortBlob = 256 // bytes + +var ( + gobInitDuration = time.Duration(278) + gobInitInt = big.NewInt(42) + gobInitRat = big.NewRat(355, 113) + gobInitTime time.Time +) + +func init() { + var err error + if gobInitTime, err = time.ParseInLocation( + "Jan 2, 2006 at 3:04pm (MST)", + "Jul 9, 2012 at 5:02am (CEST)", + time.FixedZone("XYZ", 1234), + ); err != nil { + log.Panic(err) + } + newGobCoder() +} + +type gobCoder struct { + buf bytes.Buffer + dec *gob.Decoder + enc *gob.Encoder + mu sync.Mutex +} + +func newGobCoder() (g *gobCoder) { + g = &gobCoder{} + g.enc = gob.NewEncoder(&g.buf) + if err := g.enc.Encode(gobInitInt); err != nil { + log.Panic(err) + } + + if err := g.enc.Encode(gobInitRat); err != nil { + log.Panic(err) + } + + if err := g.enc.Encode(gobInitTime); err != nil { + log.Panic(err) + } + + if err := g.enc.Encode(gobInitDuration); err != nil { + log.Panic(err) + } + + g.dec = gob.NewDecoder(&g.buf) + i := big.NewInt(0) + if err := g.dec.Decode(i); err != nil { + log.Panic(err) + } + + r := big.NewRat(3, 5) + if err := g.dec.Decode(r); err != nil { + log.Panic(err) + } + + t := time.Now() + if err := g.dec.Decode(&t); err != nil { + log.Panic(err) + } + + var d time.Duration + if err := g.dec.Decode(&d); err != nil { + log.Panic(err) + } + + return +} + +func (g *gobCoder) encode(v interface{}) (b []byte, err error) { + g.mu.Lock() + defer g.mu.Unlock() + + g.buf.Reset() + switch x := v.(type) { + case []byte: + return x, nil + case *big.Int: + err = g.enc.Encode(x) + case *big.Rat: + err = g.enc.Encode(x) + case time.Time: + err = g.enc.Encode(x) + case time.Duration: + err = g.enc.Encode(int64(x)) + default: + //dbg("%T(%v)", v, v) + log.Panic("internal error 002") + } + b = g.buf.Bytes() + return +} + +func (g *gobCoder) decode(b []byte, typ int) (v interface{}, err error) { + g.mu.Lock() + defer g.mu.Unlock() + + g.buf.Reset() + g.buf.Write(b) + switch typ { + case qBlob: + return b, nil + case qBigInt: + x := big.NewInt(0) + err = g.dec.Decode(&x) + v = x + case qBigRat: + x := big.NewRat(1, 1) + err = g.dec.Decode(&x) + v = x + case qTime: + var x time.Time + err = g.dec.Decode(&x) + v = x + case qDuration: + var x int64 + err = g.dec.Decode(&x) + v = time.Duration(x) + default: + log.Panic("internal error 003") + } + return +} diff --git a/Godeps/_workspace/src/github.com/cznic/ql/btree.go b/Godeps/_workspace/src/github.com/cznic/ql/btree.go new file mode 100644 index 0000000..4f64239 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/ql/btree.go @@ -0,0 +1,725 @@ +// Copyright 2014 The ql 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 ql + +import ( + "io" +) + +const ( + kx = 128 //DONE benchmark tune this number if using custom key/value type(s). + kd = 64 //DONE benchmark tune this number if using custom key/value type(s). +) + +type ( + // cmp compares a and b. Return value is: + // + // < 0 if a < b + // 0 if a == b + // > 0 if a > b + // + cmp func(a, b []interface{}) int + + d struct { // data page + c int + d [2*kd + 1]de + n *d + p *d + } + + de struct { // d element + k []interface{} + v []interface{} + } + + enumerator struct { + err error + hit bool + i int + k []interface{} + q *d + t *tree + ver int64 + } + + // tree is a B+tree. + tree struct { + c int + cmp cmp + first *d + last *d + r interface{} + ver int64 + } + + xe struct { // x element + ch interface{} + sep *d + } + + x struct { // index page + c int + x [2*kx + 2]xe + } +) + +var ( // R/O zero values + zd d + zde de + zx x + zxe xe +) + +func clr(q interface{}) { + switch x := q.(type) { + case *x: + for i := 0; i <= x.c; i++ { // Ch0 Sep0 ... Chn-1 Sepn-1 Chn + clr(x.x[i].ch) + } + *x = zx // GC + case *d: + *x = zd // GC + } +} + +// -------------------------------------------------------------------------- x + +func newX(ch0 interface{}) *x { + r := &x{} + r.x[0].ch = ch0 + return r +} + +func (q *x) extract(i int) { + q.c-- + if i < q.c { + copy(q.x[i:], q.x[i+1:q.c+1]) + q.x[q.c].ch = q.x[q.c+1].ch + q.x[q.c].sep = nil // GC + q.x[q.c+1] = zxe // GC + } +} + +func (q *x) insert(i int, d *d, ch interface{}) *x { + c := q.c + if i < c { + q.x[c+1].ch = q.x[c].ch + copy(q.x[i+2:], q.x[i+1:c]) + q.x[i+1].sep = q.x[i].sep + } + c++ + q.c = c + q.x[i].sep = d + q.x[i+1].ch = ch + return q +} + +func (q *x) siblings(i int) (l, r *d) { + if i >= 0 { + if i > 0 { + l = q.x[i-1].ch.(*d) + } + if i < q.c { + r = q.x[i+1].ch.(*d) + } + } + return +} + +// -------------------------------------------------------------------------- d + +func (l *d) mvL(r *d, c int) { + copy(l.d[l.c:], r.d[:c]) + copy(r.d[:], r.d[c:r.c]) + l.c += c + r.c -= c +} + +func (l *d) mvR(r *d, c int) { + copy(r.d[c:], r.d[:r.c]) + copy(r.d[:c], l.d[l.c-c:]) + r.c += c + l.c -= c +} + +// ----------------------------------------------------------------------- tree + +// treeNew returns a newly created, empty tree. The compare function is used +// for key collation. +func treeNew(cmp cmp) *tree { + return &tree{cmp: cmp} +} + +// Clear removes all K/V pairs from the tree. +func (t *tree) Clear() { + if t.r == nil { + return + } + + clr(t.r) + t.c, t.first, t.last, t.r = 0, nil, nil, nil + t.ver++ +} + +func (t *tree) cat(p *x, q, r *d, pi int) { + t.ver++ + q.mvL(r, r.c) + if r.n != nil { + r.n.p = q + } else { + t.last = q + } + q.n = r.n + if p.c > 1 { + p.extract(pi) + p.x[pi].ch = q + } else { + t.r = q + } +} + +func (t *tree) catX(p, q, r *x, pi int) { + t.ver++ + q.x[q.c].sep = p.x[pi].sep + copy(q.x[q.c+1:], r.x[:r.c]) + q.c += r.c + 1 + q.x[q.c].ch = r.x[r.c].ch + if p.c > 1 { + p.c-- + pc := p.c + if pi < pc { + p.x[pi].sep = p.x[pi+1].sep + copy(p.x[pi+1:], p.x[pi+2:pc+1]) + p.x[pc].ch = p.x[pc+1].ch + p.x[pc].sep = nil // GC + p.x[pc+1].ch = nil // GC + } + return + } + + t.r = q +} + +//Delete removes the k's KV pair, if it exists, in which case Delete returns +//true. +func (t *tree) Delete(k []interface{}) (ok bool) { + pi := -1 + var p *x + q := t.r + if q == nil { + return + } + + for { + var i int + i, ok = t.find(q, k) + if ok { + switch x := q.(type) { + case *x: + dp := x.x[i].sep + switch { + case dp.c > kd: + t.extract(dp, 0) + default: + if x.c < kx && q != t.r { + t.underflowX(p, &x, pi, &i) + } + pi = i + 1 + p = x + q = x.x[pi].ch + ok = false + continue + } + case *d: + t.extract(x, i) + if x.c >= kd { + return + } + + if q != t.r { + t.underflow(p, x, pi) + } else if t.c == 0 { + t.Clear() + } + } + return + } + + switch x := q.(type) { + case *x: + if x.c < kx && q != t.r { + t.underflowX(p, &x, pi, &i) + } + pi = i + p = x + q = x.x[i].ch + case *d: + return + } + } +} + +func (t *tree) extract(q *d, i int) { // (r []interface{}) { + t.ver++ + //r = q.d[i].v // prepared for Extract + q.c-- + if i < q.c { + copy(q.d[i:], q.d[i+1:q.c+1]) + } + q.d[q.c] = zde // GC + t.c-- + return +} + +func (t *tree) find(q interface{}, k []interface{}) (i int, ok bool) { + var mk []interface{} + l := 0 + switch x := q.(type) { + case *x: + h := x.c - 1 + for l <= h { + m := (l + h) >> 1 + mk = x.x[m].sep.d[0].k + switch cmp := t.cmp(k, mk); { + case cmp > 0: + l = m + 1 + case cmp == 0: + return m, true + default: + h = m - 1 + } + } + case *d: + h := x.c - 1 + for l <= h { + m := (l + h) >> 1 + mk = x.d[m].k + switch cmp := t.cmp(k, mk); { + case cmp > 0: + l = m + 1 + case cmp == 0: + return m, true + default: + h = m - 1 + } + } + } + return l, false +} + +// First returns the first item of the tree in the key collating order, or +// (nil, nil) if the tree is empty. +func (t *tree) First() (k []interface{}, v []interface{}) { + if q := t.first; q != nil { + q := &q.d[0] + k, v = q.k, q.v + } + return +} + +// Get returns the value associated with k and true if it exists. Otherwise Get +// returns (nil, false). +func (t *tree) Get(k []interface{}) (v []interface{}, ok bool) { + q := t.r + if q == nil { + return + } + + for { + var i int + if i, ok = t.find(q, k); ok { + switch x := q.(type) { + case *x: + return x.x[i].sep.d[0].v, true + case *d: + return x.d[i].v, true + } + } + switch x := q.(type) { + case *x: + q = x.x[i].ch + default: + return + } + } +} + +func (t *tree) insert(q *d, i int, k []interface{}, v []interface{}) *d { + t.ver++ + c := q.c + if i < c { + copy(q.d[i+1:], q.d[i:c]) + } + c++ + q.c = c + q.d[i].k, q.d[i].v = k, v + t.c++ + return q +} + +// Last returns the last item of the tree in the key collating order, or (nil, +// nil) if the tree is empty. +func (t *tree) Last() (k []interface{}, v []interface{}) { + if q := t.last; q != nil { + q := &q.d[q.c-1] + k, v = q.k, q.v + } + return +} + +// Len returns the number of items in the tree. +func (t *tree) Len() int { + return t.c +} + +func (t *tree) overflow(p *x, q *d, pi, i int, k []interface{}, v []interface{}) { + t.ver++ + l, r := p.siblings(pi) + + if l != nil && l.c < 2*kd { + l.mvL(q, 1) + t.insert(q, i-1, k, v) + return + } + + if r != nil && r.c < 2*kd { + if i < 2*kd { + q.mvR(r, 1) + t.insert(q, i, k, v) + } else { + t.insert(r, 0, k, v) + } + return + } + + t.split(p, q, pi, i, k, v) +} + +// Seek returns an enumerator positioned on a an item such that k >= item's +// key. ok reports if k == item.key The enumerator's position is possibly +// after the last item in the tree. +func (t *tree) Seek(k []interface{}) (e *enumerator, ok bool) { + q := t.r + if q == nil { + e = &enumerator{nil, false, 0, k, nil, t, t.ver} + return + } + + for { + var i int + if i, ok = t.find(q, k); ok { + switch x := q.(type) { + case *x: + e = &enumerator{nil, ok, 0, k, x.x[i].sep, t, t.ver} + return + case *d: + e = &enumerator{nil, ok, i, k, x, t, t.ver} + return + } + } + switch x := q.(type) { + case *x: + q = x.x[i].ch + case *d: + e = &enumerator{nil, ok, i, k, x, t, t.ver} + return + } + } +} + +// SeekFirst returns an enumerator positioned on the first KV pair in the tree, +// if any. For an empty tree, err == io.EOF is returned and e will be nil. +func (t *tree) SeekFirst() (e *enumerator, err error) { + q := t.first + if q == nil { + return nil, io.EOF + } + + return &enumerator{nil, true, 0, q.d[0].k, q, t, t.ver}, nil +} + +// SeekLast returns an enumerator positioned on the last KV pair in the tree, +// if any. For an empty tree, err == io.EOF is returned and e will be nil. +func (t *tree) SeekLast() (e *enumerator, err error) { + q := t.last + if q == nil { + return nil, io.EOF + } + + return &enumerator{nil, true, q.c - 1, q.d[q.c-1].k, q, t, t.ver}, nil +} + +// Set sets the value associated with k. +func (t *tree) Set(k []interface{}, v []interface{}) { + pi := -1 + var p *x + q := t.r + if q != nil { + for { + i, ok := t.find(q, k) + if ok { + switch x := q.(type) { + case *x: + x.x[i].sep.d[0].v = v + case *d: + x.d[i].v = v + } + return + } + + switch x := q.(type) { + case *x: + if x.c > 2*kx { + t.splitX(p, &x, pi, &i) + } + pi = i + p = x + q = x.x[i].ch + case *d: + switch { + case x.c < 2*kd: + t.insert(x, i, k, v) + default: + t.overflow(p, x, pi, i, k, v) + } + return + } + } + } + + z := t.insert(&d{}, 0, k, v) + t.r, t.first, t.last = z, z, z + return +} + +func (t *tree) split(p *x, q *d, pi, i int, k []interface{}, v []interface{}) { + t.ver++ + r := &d{} + if q.n != nil { + r.n = q.n + r.n.p = r + } else { + t.last = r + } + q.n = r + r.p = q + + copy(r.d[:], q.d[kd:2*kd]) + for i := range q.d[kd:] { + q.d[kd+i] = zde + } + q.c = kd + r.c = kd + if pi >= 0 { + p.insert(pi, r, r) + } else { + t.r = newX(q).insert(0, r, r) + } + if i > kd { + t.insert(r, i-kd, k, v) + return + } + + t.insert(q, i, k, v) +} + +func (t *tree) splitX(p *x, pp **x, pi int, i *int) { + t.ver++ + q := *pp + r := &x{} + copy(r.x[:], q.x[kx+1:]) + q.c = kx + r.c = kx + if pi >= 0 { + p.insert(pi, q.x[kx].sep, r) + } else { + t.r = newX(q).insert(0, q.x[kx].sep, r) + } + q.x[kx].sep = nil + for i := range q.x[kx+1:] { + q.x[kx+i+1] = zxe + } + if *i > kx { + *pp = r + *i -= kx + 1 + } +} + +func (t *tree) underflow(p *x, q *d, pi int) { + t.ver++ + l, r := p.siblings(pi) + + if l != nil && l.c+q.c >= 2*kd { + l.mvR(q, 1) + } else if r != nil && q.c+r.c >= 2*kd { + q.mvL(r, 1) + r.d[r.c] = zde // GC + } else if l != nil { + t.cat(p, l, q, pi-1) + } else { + t.cat(p, q, r, pi) + } +} + +func (t *tree) underflowX(p *x, pp **x, pi int, i *int) { + t.ver++ + var l, r *x + q := *pp + + if pi >= 0 { + if pi > 0 { + l = p.x[pi-1].ch.(*x) + } + if pi < p.c { + r = p.x[pi+1].ch.(*x) + } + } + + if l != nil && l.c > kx { + q.x[q.c+1].ch = q.x[q.c].ch + copy(q.x[1:], q.x[:q.c]) + q.x[0].ch = l.x[l.c].ch + q.x[0].sep = p.x[pi-1].sep + q.c++ + *i++ + l.c-- + p.x[pi-1].sep = l.x[l.c].sep + return + } + + if r != nil && r.c > kx { + q.x[q.c].sep = p.x[pi].sep + q.c++ + q.x[q.c].ch = r.x[0].ch + p.x[pi].sep = r.x[0].sep + copy(r.x[:], r.x[1:r.c]) + r.c-- + rc := r.c + r.x[rc].ch = r.x[rc+1].ch + r.x[rc].sep = nil + r.x[rc+1].ch = nil + return + } + + if l != nil { + *i += l.c + 1 + t.catX(p, l, q, pi-1) + *pp = l + return + } + + t.catX(p, q, r, pi) +} + +// ----------------------------------------------------------------- enumerator + +// Next returns the currently enumerated item, if it exists and moves to the +// next item in the key collation order. If there is no item to return, err == +// io.EOF is returned. +func (e *enumerator) Next() (k []interface{}, v []interface{}, err error) { + if err = e.err; err != nil { + return + } + + if e.ver != e.t.ver { + f, hit := e.t.Seek(e.k) + if !e.hit && hit { + if err = f.next(); err != nil { + return + } + } + + *e = *f + } + if e.q == nil { + e.err, err = io.EOF, io.EOF + return + } + + if e.i >= e.q.c { + if err = e.next(); err != nil { + return + } + } + + i := e.q.d[e.i] + k, v = i.k, i.v + e.k, e.hit = k, false + e.next() + return +} + +func (e *enumerator) next() error { + if e.q == nil { + e.err = io.EOF + return io.EOF + } + + switch { + case e.i < e.q.c-1: + e.i++ + default: + if e.q, e.i = e.q.n, 0; e.q == nil { + e.err = io.EOF + } + } + return e.err +} + +// Prev returns the currently enumerated item, if it exists and moves to the +// previous item in the key collation order. If there is no item to return, err +// == io.EOF is returned. +func (e *enumerator) Prev() (k []interface{}, v []interface{}, err error) { + if err = e.err; err != nil { + return + } + + if e.ver != e.t.ver { + f, hit := e.t.Seek(e.k) + if !e.hit && hit { + if err = f.prev(); err != nil { + return + } + } + + *e = *f + } + if e.q == nil { + e.err, err = io.EOF, io.EOF + return + } + + if e.i >= e.q.c { + if err = e.next(); err != nil { + return + } + } + + i := e.q.d[e.i] + k, v = i.k, i.v + e.k, e.hit = k, false + e.prev() + return +} + +func (e *enumerator) prev() error { + if e.q == nil { + e.err = io.EOF + return io.EOF + } + + switch { + case e.i > 0: + e.i-- + default: + if e.q = e.q.p; e.q == nil { + e.err = io.EOF + break + } + + e.i = e.q.c - 1 + } + return e.err +} diff --git a/Godeps/_workspace/src/github.com/cznic/ql/builtin.go b/Godeps/_workspace/src/github.com/cznic/ql/builtin.go new file mode 100644 index 0000000..4508193 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/ql/builtin.go @@ -0,0 +1,878 @@ +// Copyright 2014 The ql 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 ql + +import ( + "fmt" + "log" + "math/rand" + "reflect" + "strings" + "time" +) + +//TODO agg bigint, bigrat, time, duration + +var builtin = map[string]struct { + f func([]interface{}, map[interface{}]interface{}) (interface{}, error) + minArgs int + maxArgs int + isStatic bool + isAggregate bool +}{ + "__testBlob": {builtinTestBlob, 1, 1, true, false}, + "__testString": {builtinTestString, 1, 1, true, false}, + "avg": {builtinAvg, 1, 1, false, true}, + "complex": {builtinComplex, 2, 2, true, false}, + "contains": {builtinContains, 2, 2, true, false}, + "count": {builtinCount, 0, 1, false, true}, + "date": {builtinDate, 8, 8, true, false}, + "day": {builtinDay, 1, 1, true, false}, + "formatTime": {builtinFormatTime, 2, 2, true, false}, + "hasPrefix": {builtinHasPrefix, 2, 2, true, false}, + "hasSuffix": {builtinHasSuffix, 2, 2, true, false}, + "hour": {builtinHour, 1, 1, true, false}, + "hours": {builtinHours, 1, 1, true, false}, + "id": {builtinID, 0, 1, false, false}, + "imag": {builtinImag, 1, 1, true, false}, + "len": {builtinLen, 1, 1, true, false}, + "max": {builtinMax, 1, 1, false, true}, + "min": {builtinMin, 1, 1, false, true}, + "minute": {builtinMinute, 1, 1, true, false}, + "minutes": {builtinMinutes, 1, 1, true, false}, + "month": {builtinMonth, 1, 1, true, false}, + "nanosecond": {builtinNanosecond, 1, 1, true, false}, + "nanoseconds": {builtinNanoseconds, 1, 1, true, false}, + "now": {builtinNow, 0, 0, false, false}, + "parseTime": {builtinParseTime, 2, 2, true, false}, + "real": {builtinReal, 1, 1, true, false}, + "second": {builtinSecond, 1, 1, true, false}, + "seconds": {builtinSeconds, 1, 1, true, false}, + "since": {builtinSince, 1, 1, false, false}, + "sum": {builtinSum, 1, 1, false, true}, + "timeIn": {builtinTimeIn, 2, 2, true, false}, + "weekday": {builtinWeekday, 1, 1, true, false}, + "year": {builtinYear, 1, 1, true, false}, + "yearDay": {builtinYearday, 1, 1, true, false}, +} + +func badNArgs(min int, s string, arg []interface{}) error { + a := []string{} + for _, v := range arg { + a = append(a, fmt.Sprintf("%v", v)) + } + switch len(arg) < min { + case true: + return fmt.Errorf("missing argument to %s(%s)", s, strings.Join(a, ", ")) + default: //case false: + return fmt.Errorf("too many arguments to %s(%s)", s, strings.Join(a, ", ")) + } +} + +func invArg(arg interface{}, s string) error { + return fmt.Errorf("invalid argument %v (type %T) for %s", arg, arg, s) +} + +func builtinTestBlob(arg []interface{}, ctx map[interface{}]interface{}) (v interface{}, err error) { + n, err := intExpr(arg[0]) + if err != nil { + return nil, err + } + + rng := rand.New(rand.NewSource(n)) + b := make([]byte, n) + for i := range b { + b[i] = byte(rng.Int()) + } + return b, nil +} + +func builtinTestString(arg []interface{}, ctx map[interface{}]interface{}) (v interface{}, err error) { + n, err := intExpr(arg[0]) + if err != nil { + return nil, err + } + + rng := rand.New(rand.NewSource(n)) + b := make([]byte, n) + for i := range b { + b[i] = byte(rng.Int()) + } + return string(b), nil +} + +func builtinAvg(arg []interface{}, ctx map[interface{}]interface{}) (v interface{}, err error) { + type avg struct { + sum interface{} + n uint64 + } + + if _, ok := ctx["$agg0"]; ok { + return + } + + fn := ctx["$fn"] + if _, ok := ctx["$agg"]; ok { + data, ok := ctx[fn].(avg) + if !ok { + return + } + + switch x := data.sum.(type) { + case complex64: + return complex64(complex128(x) / complex(float64(data.n), 0)), nil + case complex128: + return complex64(complex128(x) / complex(float64(data.n), 0)), nil + case float32: + return float32(float64(x) / float64(data.n)), nil + case float64: + return float64(x) / float64(data.n), nil + case int8: + return int8(int64(x) / int64(data.n)), nil + case int16: + return int16(int64(x) / int64(data.n)), nil + case int32: + return int32(int64(x) / int64(data.n)), nil + case int64: + return int64(int64(x) / int64(data.n)), nil + case uint8: + return uint8(uint64(x) / data.n), nil + case uint16: + return uint16(uint64(x) / data.n), nil + case uint32: + return uint32(uint64(x) / data.n), nil + case uint64: + return uint64(uint64(x) / data.n), nil + } + + } + + data, _ := ctx[fn].(avg) + y := arg[0] + if y == nil { + return + } + + switch x := data.sum.(type) { + case nil: + switch y := y.(type) { + case float32, float64, int8, int16, int32, int64, uint8, uint16, uint32, uint64: + data = avg{y, 0} + default: + return nil, fmt.Errorf("avg: cannot accept %v (value if type %T)", y, y) + } + case complex64: + data.sum = x + y.(complex64) + case complex128: + data.sum = x + y.(complex128) + case float32: + data.sum = x + y.(float32) + case float64: + data.sum = x + y.(float64) + case int8: + data.sum = x + y.(int8) + case int16: + data.sum = x + y.(int16) + case int32: + data.sum = x + y.(int32) + case int64: + data.sum = x + y.(int64) + case uint8: + data.sum = x + y.(uint8) + case uint16: + data.sum = x + y.(uint16) + case uint32: + data.sum = x + y.(uint32) + case uint64: + data.sum = x + y.(uint64) + } + data.n++ + ctx[fn] = data + return +} + +func builtinComplex(arg []interface{}, _ map[interface{}]interface{}) (v interface{}, err error) { + re, im := arg[0], arg[1] + if re == nil || im == nil { + return nil, nil + } + + re, im = coerce(re, im) + if reflect.TypeOf(re) != reflect.TypeOf(im) { + return nil, fmt.Errorf("complex(%T(%#v), %T(%#v)): invalid types", re, re, im, im) + } + + switch re := re.(type) { + case idealFloat: + return idealComplex(complex(float64(re), float64(im.(idealFloat)))), nil + case idealInt: + return idealComplex(complex(float64(re), float64(im.(idealInt)))), nil + case idealRune: + return idealComplex(complex(float64(re), float64(im.(idealRune)))), nil + case idealUint: + return idealComplex(complex(float64(re), float64(im.(idealUint)))), nil + case float32: + return complex(float32(re), im.(float32)), nil + case float64: + return complex(float64(re), im.(float64)), nil + case int8: + return complex(float64(re), float64(im.(int8))), nil + case int16: + return complex(float64(re), float64(im.(int16))), nil + case int32: + return complex(float64(re), float64(im.(int32))), nil + case int64: + return complex(float64(re), float64(im.(int64))), nil + case uint8: + return complex(float64(re), float64(im.(uint8))), nil + case uint16: + return complex(float64(re), float64(im.(uint16))), nil + case uint32: + return complex(float64(re), float64(im.(uint32))), nil + case uint64: + return complex(float64(re), float64(im.(uint64))), nil + default: + return nil, invArg(re, "complex") + } +} + +func builtinContains(arg []interface{}, _ map[interface{}]interface{}) (v interface{}, err error) { + switch s := arg[0].(type) { + case nil: + return nil, nil + case string: + switch chars := arg[1].(type) { + case nil: + return nil, nil + case string: + return strings.Contains(s, chars), nil + default: + return nil, invArg(chars, "string") + } + default: + return nil, invArg(s, "string") + } +} + +func builtinCount(arg []interface{}, ctx map[interface{}]interface{}) (v interface{}, err error) { + if _, ok := ctx["$agg0"]; ok { + return int64(0), nil + } + + fn := ctx["$fn"] + if _, ok := ctx["$agg"]; ok { + return ctx[fn].(int64), nil + } + + n, _ := ctx[fn].(int64) + switch len(arg) { + case 0: + n++ + case 1: + if arg[0] != nil { + n++ + } + default: + log.Panic("internal error 067") + } + ctx[fn] = n + return +} + +func builtinDate(arg []interface{}, _ map[interface{}]interface{}) (v interface{}, err error) { + for i, v := range arg { + switch i { + case 7: + switch x := v.(type) { + case string: + default: + return nil, invArg(x, "date") + } + default: + switch x := v.(type) { + case int64: + case idealInt: + arg[i] = int64(x) + default: + return nil, invArg(x, "date") + } + } + } + + sloc := arg[7].(string) + loc := time.Local + switch sloc { + case "local": + default: + loc, err = time.LoadLocation(sloc) + if err != nil { + return + } + } + + return time.Date( + int(arg[0].(int64)), + time.Month(arg[1].(int64)), + int(arg[2].(int64)), + int(arg[3].(int64)), + int(arg[4].(int64)), + int(arg[5].(int64)), + int(arg[6].(int64)), + loc, + ), nil +} + +func builtinLen(arg []interface{}, _ map[interface{}]interface{}) (v interface{}, err error) { + switch x := arg[0].(type) { + case nil: + return nil, nil + case string: + return int64(len(x)), nil + default: + return nil, invArg(x, "len") + } +} + +func builtinDay(arg []interface{}, ctx map[interface{}]interface{}) (v interface{}, err error) { + switch x := arg[0].(type) { + case nil: + return nil, nil + case time.Time: + return int64(x.Day()), nil + default: + return nil, invArg(x, "day") + } +} + +func builtinFormatTime(arg []interface{}, ctx map[interface{}]interface{}) (v interface{}, err error) { + switch x := arg[0].(type) { + case nil: + return nil, nil + case time.Time: + switch y := arg[1].(type) { + case nil: + return nil, nil + case string: + return x.Format(y), nil + default: + return nil, invArg(y, "formatTime") + } + default: + return nil, invArg(x, "formatTime") + } +} + +func builtinHasPrefix(arg []interface{}, _ map[interface{}]interface{}) (v interface{}, err error) { + switch s := arg[0].(type) { + case nil: + return nil, nil + case string: + switch prefix := arg[1].(type) { + case nil: + return nil, nil + case string: + return strings.HasPrefix(s, prefix), nil + default: + return nil, invArg(prefix, "string") + } + default: + return nil, invArg(s, "string") + } +} + +func builtinHasSuffix(arg []interface{}, _ map[interface{}]interface{}) (v interface{}, err error) { + switch s := arg[0].(type) { + case nil: + return nil, nil + case string: + switch suffix := arg[1].(type) { + case nil: + return nil, nil + case string: + return strings.HasSuffix(s, suffix), nil + default: + return nil, invArg(suffix, "string") + } + default: + return nil, invArg(s, "string") + } +} + +func builtinHour(arg []interface{}, ctx map[interface{}]interface{}) (v interface{}, err error) { + switch x := arg[0].(type) { + case nil: + return nil, nil + case time.Time: + return int64(x.Hour()), nil + default: + return nil, invArg(x, "hour") + } +} + +func builtinHours(arg []interface{}, ctx map[interface{}]interface{}) (v interface{}, err error) { + switch x := arg[0].(type) { + case nil: + return nil, nil + case time.Duration: + return x.Hours(), nil + default: + return nil, invArg(x, "hours") + } +} + +func builtinID(arg []interface{}, ctx map[interface{}]interface{}) (v interface{}, err error) { + switch x := ctx["$id"].(type) { + case map[string]interface{}: + if len(arg) == 0 { + return nil, nil + } + + tab := arg[0].(*ident) + id, ok := x[tab.s] + if !ok { + return nil, fmt.Errorf("value not available: id(%s)", tab) + } + + if _, ok := id.(int64); ok { + return id, nil + } + + return nil, fmt.Errorf("value not available: id(%s)", tab) + case int64: + return x, nil + default: + panic("internal error 072") + } +} + +func builtinImag(arg []interface{}, _ map[interface{}]interface{}) (v interface{}, err error) { + switch x := arg[0].(type) { + case nil: + return nil, nil + case idealComplex: + return imag(x), nil + case complex64: + return imag(x), nil + case complex128: + return imag(x), nil + default: + return nil, invArg(x, "imag") + } +} + +func builtinMax(arg []interface{}, ctx map[interface{}]interface{}) (v interface{}, err error) { + if _, ok := ctx["$agg0"]; ok { + return + } + + fn := ctx["$fn"] + if _, ok := ctx["$agg"]; ok { + if v, ok = ctx[fn]; ok { + return + } + + return nil, nil + } + + max := ctx[fn] + y := arg[0] + if y == nil { + return + } + switch x := max.(type) { + case nil: + switch y := y.(type) { + case float32, float64, string, int8, int16, int32, int64, uint8, uint16, uint32, uint64, time.Time: + max = y + default: + return nil, fmt.Errorf("max: cannot accept %v (value if type %T)", y, y) + } + case float32: + if y := y.(float32); y > x { + max = y + } + case float64: + if y := y.(float64); y > x { + max = y + } + case string: + if y := y.(string); y > x { + max = y + } + case int8: + if y := y.(int8); y > x { + max = y + } + case int16: + if y := y.(int16); y > x { + max = y + } + case int32: + if y := y.(int32); y > x { + max = y + } + case int64: + if y := y.(int64); y > x { + max = y + } + case uint8: + if y := y.(uint8); y > x { + max = y + } + case uint16: + if y := y.(uint16); y > x { + max = y + } + case uint32: + if y := y.(uint32); y > x { + max = y + } + case uint64: + if y := y.(uint64); y > x { + max = y + } + case time.Time: + if y := y.(time.Time); y.After(x) { + max = y + } + } + ctx[fn] = max + return +} + +func builtinMin(arg []interface{}, ctx map[interface{}]interface{}) (v interface{}, err error) { + if _, ok := ctx["$agg0"]; ok { + return + } + + fn := ctx["$fn"] + if _, ok := ctx["$agg"]; ok { + if v, ok = ctx[fn]; ok { + return + } + + return nil, nil + } + + min := ctx[fn] + y := arg[0] + if y == nil { + return + } + switch x := min.(type) { + case nil: + switch y := y.(type) { + case float32, float64, string, int8, int16, int32, int64, uint8, uint16, uint32, uint64, time.Time: + min = y + default: + return nil, fmt.Errorf("min: cannot accept %v (value if type %T)", y, y) + } + case float32: + if y := y.(float32); y < x { + min = y + } + case float64: + if y := y.(float64); y < x { + min = y + } + case string: + if y := y.(string); y < x { + min = y + } + case int8: + if y := y.(int8); y < x { + min = y + } + case int16: + if y := y.(int16); y < x { + min = y + } + case int32: + if y := y.(int32); y < x { + min = y + } + case int64: + if y := y.(int64); y < x { + min = y + } + case uint8: + if y := y.(uint8); y < x { + min = y + } + case uint16: + if y := y.(uint16); y < x { + min = y + } + case uint32: + if y := y.(uint32); y < x { + min = y + } + case uint64: + if y := y.(uint64); y < x { + min = y + } + case time.Time: + if y := y.(time.Time); y.Before(x) { + min = y + } + } + ctx[fn] = min + return +} + +func builtinMinute(arg []interface{}, ctx map[interface{}]interface{}) (v interface{}, err error) { + switch x := arg[0].(type) { + case nil: + return nil, nil + case time.Time: + return int64(x.Minute()), nil + default: + return nil, invArg(x, "minute") + } +} + +func builtinMinutes(arg []interface{}, ctx map[interface{}]interface{}) (v interface{}, err error) { + switch x := arg[0].(type) { + case nil: + return nil, nil + case time.Duration: + return x.Minutes(), nil + default: + return nil, invArg(x, "minutes") + } +} + +func builtinMonth(arg []interface{}, ctx map[interface{}]interface{}) (v interface{}, err error) { + switch x := arg[0].(type) { + case nil: + return nil, nil + case time.Time: + return int64(x.Month()), nil + default: + return nil, invArg(x, "month") + } +} + +func builtinNanosecond(arg []interface{}, ctx map[interface{}]interface{}) (v interface{}, err error) { + switch x := arg[0].(type) { + case nil: + return nil, nil + case time.Time: + return int64(x.Nanosecond()), nil + default: + return nil, invArg(x, "nanosecond") + } +} + +func builtinNanoseconds(arg []interface{}, ctx map[interface{}]interface{}) (v interface{}, err error) { + switch x := arg[0].(type) { + case nil: + return nil, nil + case time.Duration: + return x.Nanoseconds(), nil + default: + return nil, invArg(x, "nanoseconds") + } +} + +func builtinNow(arg []interface{}, ctx map[interface{}]interface{}) (v interface{}, err error) { + return time.Now(), nil +} + +func builtinParseTime(arg []interface{}, ctx map[interface{}]interface{}) (v interface{}, err error) { + var a [2]string + for i, v := range arg { + switch x := v.(type) { + case nil: + return nil, nil + case string: + a[i] = x + default: + return nil, invArg(x, "parseTime") + } + } + + t, err := time.Parse(a[0], a[1]) + if err != nil { + return nil, err + } + + ls := t.Location().String() + if ls == "UTC" { + return t, nil + } + + l, err := time.LoadLocation(ls) + if err != nil { + return t, nil + } + + return time.ParseInLocation(a[0], a[1], l) +} + +func builtinReal(arg []interface{}, _ map[interface{}]interface{}) (v interface{}, err error) { + switch x := arg[0].(type) { + case nil: + return nil, nil + case idealComplex: + return real(x), nil + case complex64: + return real(x), nil + case complex128: + return real(x), nil + default: + return nil, invArg(x, "real") + } +} + +func builtinSecond(arg []interface{}, ctx map[interface{}]interface{}) (v interface{}, err error) { + switch x := arg[0].(type) { + case nil: + return nil, nil + case time.Time: + return int64(x.Second()), nil + default: + return nil, invArg(x, "second") + } +} + +func builtinSeconds(arg []interface{}, ctx map[interface{}]interface{}) (v interface{}, err error) { + switch x := arg[0].(type) { + case nil: + return nil, nil + case time.Duration: + return x.Seconds(), nil + default: + return nil, invArg(x, "seconds") + } +} + +func builtinSince(arg []interface{}, ctx map[interface{}]interface{}) (v interface{}, err error) { + switch x := arg[0].(type) { + case nil: + return nil, nil + case time.Time: + return time.Since(x), nil + default: + return nil, invArg(x, "since") + } +} + +func builtinSum(arg []interface{}, ctx map[interface{}]interface{}) (v interface{}, err error) { + if _, ok := ctx["$agg0"]; ok { + return + } + + fn := ctx["$fn"] + if _, ok := ctx["$agg"]; ok { + if v, ok = ctx[fn]; ok { + return + } + + return nil, nil + } + + sum := ctx[fn] + y := arg[0] + if y == nil { + return + } + switch x := sum.(type) { + case nil: + switch y := y.(type) { + case complex64, complex128, float32, float64, int8, int16, int32, int64, uint8, uint16, uint32, uint64: + sum = y + default: + return nil, fmt.Errorf("sum: cannot accept %v (value if type %T)", y, y) + } + case complex64: + sum = x + y.(complex64) + case complex128: + sum = x + y.(complex128) + case float32: + sum = x + y.(float32) + case float64: + sum = x + y.(float64) + case int8: + sum = x + y.(int8) + case int16: + sum = x + y.(int16) + case int32: + sum = x + y.(int32) + case int64: + sum = x + y.(int64) + case uint8: + sum = x + y.(uint8) + case uint16: + sum = x + y.(uint16) + case uint32: + sum = x + y.(uint32) + case uint64: + sum = x + y.(uint64) + } + ctx[fn] = sum + return +} + +func builtinTimeIn(arg []interface{}, ctx map[interface{}]interface{}) (v interface{}, err error) { + switch x := arg[0].(type) { + case nil: + return nil, nil + case time.Time: + switch y := arg[1].(type) { + case nil: + return nil, nil + case string: + loc := time.Local + switch y { + case "local": + default: + loc, err = time.LoadLocation(y) + if err != nil { + return + } + } + + return x.In(loc), nil + default: + return nil, invArg(x, "timeIn") + } + default: + return nil, invArg(x, "timeIn") + } +} + +func builtinWeekday(arg []interface{}, ctx map[interface{}]interface{}) (v interface{}, err error) { + switch x := arg[0].(type) { + case nil: + return nil, nil + case time.Time: + return int64(x.Weekday()), nil + default: + return nil, invArg(x, "weekday") + } +} + +func builtinYear(arg []interface{}, ctx map[interface{}]interface{}) (v interface{}, err error) { + switch x := arg[0].(type) { + case nil: + return nil, nil + case time.Time: + return int64(x.Year()), nil + default: + return nil, invArg(x, "year") + } +} + +func builtinYearday(arg []interface{}, ctx map[interface{}]interface{}) (v interface{}, err error) { + switch x := arg[0].(type) { + case nil: + return nil, nil + case time.Time: + return int64(x.YearDay()), nil + default: + return nil, invArg(x, "yearDay") + } +} diff --git a/Godeps/_workspace/src/github.com/cznic/ql/coerce.go b/Godeps/_workspace/src/github.com/cznic/ql/coerce.go new file mode 100644 index 0000000..368d5b3 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/ql/coerce.go @@ -0,0 +1,290 @@ +// Copyright 2013 The ql Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// CAUTION: This file was generated automatically by +// +// $ go run helper -o coerce.go +// +// DO NOT EDIT! + +package ql + +import ( + "math" + "math/big" + "reflect" + "time" +) + +func coerce(a, b interface{}) (x, y interface{}) { + if reflect.TypeOf(a) == reflect.TypeOf(b) { + return a, b + } + + switch a.(type) { + case idealComplex, idealFloat, idealInt, idealRune, idealUint: + switch b.(type) { + case idealComplex, idealFloat, idealInt, idealRune, idealUint: + x, y = coerce1(a, b), b + if reflect.TypeOf(x) == reflect.TypeOf(y) { + return + } + + return a, coerce1(b, a) + default: + return coerce1(a, b), b + } + default: + switch b.(type) { + case idealComplex, idealFloat, idealInt, idealRune, idealUint: + return a, coerce1(b, a) + default: + return a, b + } + } +} + +func coerce1(inVal, otherVal interface{}) (coercedInVal interface{}) { + coercedInVal = inVal + if otherVal == nil { + return + } + + switch x := inVal.(type) { + case nil: + return + case idealComplex: + switch otherVal.(type) { + //case idealComplex: + //case idealFloat: + //case idealInt: + //case idealRune: + //case idealUint: + //case bool: + case complex64: + return complex64(x) + case complex128: + return complex128(x) + //case float32: + //case float64: + //case int8: + //case int16: + //case int32: + //case int64: + //case string: + //case uint8: + //case uint16: + //case uint32: + //case uint64: + //case *big.Int: + //case *big.Rat: + //case time.Time: + //case time.Duration: + } + case idealFloat: + switch otherVal.(type) { + case idealComplex: + return idealComplex(complex(float64(x), 0)) + case idealFloat: + return idealFloat(float64(x)) + //case idealInt: + //case idealRune: + //case idealUint: + //case bool: + case complex64: + return complex64(complex(float32(x), 0)) + case complex128: + return complex128(complex(float64(x), 0)) + case float32: + return float32(float64(x)) + case float64: + return float64(float64(x)) + //case int8: + //case int16: + //case int32: + //case int64: + //case string: + //case uint8: + //case uint16: + //case uint32: + //case uint64: + //case *big.Int: + case *big.Rat: + return big.NewRat(1, 1).SetFloat64(float64(x)) + //case time.Time: + //case time.Duration: + } + case idealInt: + switch otherVal.(type) { + case idealComplex: + return idealComplex(complex(float64(x), 0)) + case idealFloat: + return idealFloat(int64(x)) + case idealInt: + return idealInt(int64(x)) + //case idealRune: + case idealUint: + if x >= 0 { + return idealUint(int64(x)) + } + //case bool: + case complex64: + return complex64(complex(float32(x), 0)) + case complex128: + return complex128(complex(float64(x), 0)) + case float32: + return float32(int64(x)) + case float64: + return float64(int64(x)) + case int8: + if x >= math.MinInt8 && x <= math.MaxInt8 { + return int8(int64(x)) + } + case int16: + if x >= math.MinInt16 && x <= math.MaxInt16 { + return int16(int64(x)) + } + case int32: + if x >= math.MinInt32 && x <= math.MaxInt32 { + return int32(int64(x)) + } + case int64: + return int64(int64(x)) + //case string: + case uint8: + if x >= 0 && x <= math.MaxUint8 { + return uint8(int64(x)) + } + case uint16: + if x >= 0 && x <= math.MaxUint16 { + return uint16(int64(x)) + } + case uint32: + if x >= 0 && x <= math.MaxUint32 { + return uint32(int64(x)) + } + case uint64: + if x >= 0 { + return uint64(int64(x)) + } + case *big.Int: + return big.NewInt(int64(x)) + case *big.Rat: + return big.NewRat(1, 1).SetInt64(int64(x)) + //case time.Time: + case time.Duration: + return time.Duration(int64(x)) + } + case idealRune: + switch otherVal.(type) { + case idealComplex: + return idealComplex(complex(float64(x), 0)) + case idealFloat: + return idealFloat(int64(x)) + case idealInt: + return idealInt(int64(x)) + case idealRune: + return idealRune(int64(x)) + case idealUint: + return idealUint(int64(x)) + //case bool: + case complex64: + return complex64(complex(float32(x), 0)) + case complex128: + return complex128(complex(float64(x), 0)) + case float32: + return float32(int64(x)) + case float64: + return float64(int64(x)) + case int8: + return int8(int64(x)) + case int16: + return int16(int64(x)) + case int32: + return int32(int64(x)) + case int64: + return int64(int64(x)) + //case string: + case uint8: + return uint8(int64(x)) + case uint16: + return uint16(int64(x)) + case uint32: + return uint32(int64(x)) + case uint64: + return uint64(int64(x)) + case *big.Int: + return big.NewInt(int64(x)) + case *big.Rat: + return big.NewRat(1, 1).SetInt64(int64(x)) + //case time.Time: + case time.Duration: + return time.Duration(int64(x)) + } + case idealUint: + switch otherVal.(type) { + case idealComplex: + return idealComplex(complex(float64(x), 0)) + case idealFloat: + return idealFloat(uint64(x)) + case idealInt: + if x <= math.MaxInt64 { + return idealInt(int64(x)) + } + //case idealRune: + case idealUint: + return idealUint(uint64(x)) + //case bool: + case complex64: + return complex64(complex(float32(x), 0)) + case complex128: + return complex128(complex(float64(x), 0)) + case float32: + return float32(uint64(x)) + case float64: + return float64(uint64(x)) + case int8: + if x <= math.MaxInt8 { + return int8(int64(x)) + } + case int16: + if x <= math.MaxInt16 { + return int16(int64(x)) + } + case int32: + if x <= math.MaxInt32 { + return int32(int64(x)) + } + case int64: + if x <= math.MaxInt64 { + return int64(int64(x)) + } + //case string: + case uint8: + if x >= 0 && x <= math.MaxUint8 { + return uint8(int64(x)) + } + case uint16: + if x >= 0 && x <= math.MaxUint16 { + return uint16(int64(x)) + } + case uint32: + if x >= 0 && x <= math.MaxUint32 { + return uint32(int64(x)) + } + case uint64: + return uint64(uint64(x)) + case *big.Int: + return big.NewInt(0).SetUint64(uint64(x)) + case *big.Rat: + return big.NewRat(1, 1).SetInt(big.NewInt(0).SetUint64(uint64(x))) + //case time.Time: + case time.Duration: + if x <= math.MaxInt64 { + return time.Duration(int64(x)) + } + } + } + return +} diff --git a/Godeps/_workspace/src/github.com/cznic/ql/design/doc.go b/Godeps/_workspace/src/github.com/cznic/ql/design/doc.go new file mode 100644 index 0000000..6e94c6c --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/ql/design/doc.go @@ -0,0 +1,298 @@ +// Copyright 2014 The ql 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 design describes some of the data structures used in QL. + +Handles + +A handle is a 7 byte "pointer" to a block in the DB[0]. + +Scalar encoding + +Encoding of so called "scalars" provided by [1]. Unless specified otherwise, +all values discussed below are scalars, encoded scalars or encoding of scalar +arrays. + +Database root + +DB root is a 1-scalar found at a fixed handle (#1). + + +---+------+--------+-----------------------+ + | # | Name | Type | Description | + +---+------+--------+-----------------------+ + | 0 | head | handle | First table meta data | + +---+------+--------+-----------------------+ + +Head is the head of a single linked list of table of meta data. It's zero if +there are no tables in the DB. + +Table meta data + +Table meta data are a 6-scalar. + + +---+---------+--------+--------------------------+ + | # | Name | Type | Description | + +---+---------+--------+--------------------------+ + | 0 | next | handle | Next table meta data. | + | 1 | scols | string | Column defintitions | + | 2 | hhead | handle | -> head -> first record | + | 3 | name | string | Table name | + | 4 | indices | string | Index definitions | + | 5 | hxroots | handle | Index B+Trees roots list | + +---+---------+--------+--------------------------+ + +Fields #4 and #5 are optional for backward compatibility with existing +databases. OTOH, forward compatibility will not work. Once any indices are +created using a newer QL version the older versions of QL, expecting only 4 +fields of meta data will not be able to use the DB. That's the intended +behavior because the older versions of QL cannot update the indexes, which can +break queries runned by the newer QL version which expect indices to be always +actualized on any table-with-indices mutation. + +The handle of the next table meta data is in the field #0 (next). If there is +no next table meta data, the field is zero. Names and types of table columns +are stored in field #1 (scols). A single field is described by concatenating a +type tag and the column name. The type tags are + + bool 'b' + complex64 'c' + complex128 'd' + float32 'f' + float64 'g', alias float + int8 'i' + int16 'j' + int32 'k' + int64 'l', alias int + string 's' + uint8 'u', alias byte + uint16 'v' + uint32 'w' + uint64 'x', alias uint + bigInt 'I' + bigRat 'R' + blob 'B' + duration 'D' + time 'T' + +The scols value is the above described encoded fields joined using "|". For +example + + CREATE TABLE t (Foo bool, Bar string, Baz float); + +This statement adds a table meta data with scols + + "bFool|sBar|gBaz" + +Columns can be dropped from a table + + ALTER TABLE t DROP COLUMN Bar; + +This "erases" the field info in scols, so the value becomes + + "bFool||gBaz" + +Colums can be added to a table + + ALTER TABLE t ADD Count uint; + +New fields are always added to the end of scols + + "bFool||gBaz|xCount" + +Index of a field in strings.Split(scols, "|") is the index of the field in a +table record. The above discussed rules for column dropping and column adding +allow for schema evolution without a need to reshape any existing table data. +Dropped columns are left where they are and new records insert nil in their +place. The encoded nil is one byte. Added columns, when not present in +preexisting records are returned as nil values. If the overhead of dropped +columns becomes an issue and there's time/space and memory enough to move the +records of a table around: + + BEGIN TRANSACTION; + CREATE TABLE new (column definitions); + INSERT INTO new SELECT * FROM old; + DROP TABLE old; + CREATE TABLE old (column definitions); + INSERT INTO old SELECT * FROM new; + DROP TABLE new; + END TRANSACTION; + +This is not very time/space effective and for Big Data it can cause an OOM +because transactions are limited by memory resources available to the process. +Perhaps a method and/or QL statement to do this in-place should be added +(MAYBE consider adopting MySQL's OPTIMIZE TABLE syntax). + +Field #2 (hhead) is a handle to a head of table records, i.e. not a handle to +the first record in the table. It is thus always non zero even for a table +having no records. The reason for this "double pointer" schema is to enable +adding (linking) a new record by updating a single value of the (hhead pointing +to) head. + + tableMeta.hhead -> head -> firstTableRecord + +The table name is stored in field #3 (name). + +Indices + +Consider an index named N, indexing column named C. The encoding of this +particular index is a string "N". is a string "n" for non unique +indices and "u" for unique indices. There is this index information for the +index possibly indexing the record id() and for all other columns of scols. +Where the column is not indexed, the index info is an empty string. Infos for +all indexes are joined with "|". For example + + BEGIN TRANSACTION; + CREATE TABLE t (Foo int, Bar bool, Baz string); + CREATE INDEX X ON t (Baz); + CREATE UNIQUE INDEX Y ON t (Foo); + COMMIT; + +The values of fields #1 and #4 for the above are + + scols: "lFoo|bBar|sBaz" + indices: "|uY||nX" + +Aligning properly the "|" split parts + + id col #0 col#1 col#2 + +----------+----+--------+--------+--------+ + | scols: | | "lFoo" | "bBar" | "sBaz" | + +----------+----+--------+--------+--------+ + | indices: | "" | "uY" | "" | "nX" | + +----------+----+--------+--------+--------+ + +shows that the record id() is not indexed for this table while the columns Foo +and Baz are. + +Note that there cannot be two differently named indexes for the same column and +it's intended. The indices are B+Trees[2]. The list of handles to their roots +is pointed to by hxroots with zeros for non indexed columns. For the previous +example + + tableMeta.hxroots -> {0, y, 0, x} + +where x is the root of the B+Tree for the X index and y is the root of the +B+Tree for the Y index. If there would be an index for id(), its B+Tree root +will be present where the first zero is. Similarly to hhead, hxroots is never +zero, even when there are no indices for a table. + +Table record + +A table record is an N-scalar. + + +-----+------------+--------+-------------------------------+ + | # | Name | Type | Description | + +-----+------------+--------+-------------------------------+ + | 0 | next | handle | Next record or zero. | + | 1 | id | int64 | Automatically assigned unique | + | | | | value obtainable by id(). | + | 2 | field #0 | scalar | First field of the record. | + | 3 | field #1 | scalar | Second field of the record. | + ... + | N-1 | field #N-2 | scalar | Last field of the record. | + +-----+------------+--------+-------------------------------+ + +The linked "ordering" of table records has no semantics and it doesn't have to +correlate to the order of how the records were added to the table. In fact, an +efficient way of the linking leads to "ordering" which is actually reversed wrt +the insertion order. + +Non unique index + +The composite key of the B+Tree is {indexed value, record handle}. The B+Tree +value is not used. + + B+Tree key B+Tree value + +---------------+---------------+ +--------------+ + | Indexed Value | Record Handle | -> | not used | + +---------------+---------------+ +--------------+ + +Unique index + +If the indexed value is NULL then the composite B+Tree key is {nil, record +handle} and the B+Tree value is not used. + + B+Tree key B+Tree value + +------+-----------------+ +--------------+ + | NULL | Record Handle | -> | not used | + +------+-----------------+ +--------------+ + +If the indexed value is not NULL then key of the B+Tree key is the indexed +value and the B+Tree value is the record handle. + + B+Tree key B+Tree value + +------------------------+ +---------------+ + | Non NULL Indexed Value | -> | Record Handle | + +------------------------+ +---------------+ + +Non scalar types + +Scalar types of [1] are bool, complex*, float*, int*, uint*, string and []byte +types. All other types are "blob-like". + + QL type Go type + ----------------------------- + blob []byte + bigint big.Int + bigrat big.Rat + time time.Time + duration time.Duration + +Memory back-end stores the Go type directly. File back-end must resort to +encode all of the above as (tagged) []byte due to the lack of more types +supported natively by lldb. NULL values of blob-like types are encoded as nil +(gbNull in lldb/gb.go), exactly the same as the already existing QL types are. + +Blob encoding + +The values of the blob-like types are first encoded into a []byte slice: + + +-----------------------+-------------------+ + | blob | raw | + | bigint, bigrat, time | gob encoded | + | duration | gob encoded int64 | + +-----------------------+-------------------+ + +The gob encoding is "differential" wrt an initial encoding of all of the +blob-like type. IOW, the initial type descriptors which gob encoding must write +out are stripped off and "resupplied" on decoding transparently. See also +blob.go. If the length of the resulting slice is <= shortBlob, the first and +only chunk is the scalar encoding of + + + []interface{}{typeTag, slice}. // initial (and last) chunk + +The length of slice can be zero (for blob("")). If the resulting slice is long +(> shortBlob), the first chunk comes from encoding + + []interface{}{typeTag, nextHandle, firstPart}. // initial, but not final chunk + +In this case len(firstPart) <= shortBlob. Second and other chunks: If the chunk +is the last one, src is + + []interface{lastPart}. // overflow chunk (last) + +In this case len(lastPart) <= 64kB. If the chunk is not the last one, src is + + []interface{}{nextHandle, part}. // overflow chunk (not last) + +In this case len(part) == 64kB. + +Links + +Referenced from above: + + [0]: http://godoc.org/github.com/cznic/exp/lldb#hdr-Block_handles + [1]: http://godoc.org/github.com/cznic/exp/lldb#EncodeScalars + [2]: http://godoc.org/github.com/cznic/exp/lldb#BTree + +Rationale + +While these notes might be useful to anyone looking at QL sources, the +specifically intended reader is my future self. + +*/ +package design diff --git a/Godeps/_workspace/src/github.com/cznic/ql/doc.go b/Godeps/_workspace/src/github.com/cznic/ql/doc.go new file mode 100644 index 0000000..e8e8389 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/ql/doc.go @@ -0,0 +1,2295 @@ +// Copyright 2014 The ql Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//MAYBE set operations +//MAYBE IN ( SELECT ... ) +//MAYBE +=, -=, ... + +//TODO verify there's a graceful failure for a 2G+ blob on a 32 bit machine. + +// Package ql is a pure Go embedded (S)QL database. +// +// QL is a SQL-like language. It is less complex and less powerful than SQL +// (whichever specification SQL is considered to be). +// +// Change list +// +// 2015-02-16: IN predicate now accepts a SELECT statement. See the updated +// "Predicates" section. +// +// 2015-01-17: Logical operators || and && have now alternative spellings: OR +// and AND (case insensitive). AND was a keyword before, but OR is a new one. +// This can possibly break existing queries. For the record, it's a good idea +// to not use any name appearing in, for example, [7] in your queries as the +// list of QL's keywords may expand for gaining better compatibility with +// existing SQL "standards". +// +// 2015-01-12: ACID guarantees were tightened at the cost of performance in +// some cases. The write collecting window mechanism, a formerly used +// implementation detail, was removed. Inserting rows one by one in a +// transaction is now slow. I mean very slow. Try to avoid inserting single +// rows in a transaction. Instead, whenever possible, perform batch updates of +// tens to, say thousands of rows in a single transaction. See also: +// http://www.sqlite.org/faq.html#q19, the discussed synchronization principles +// involved are the same as for QL, modulo minor details. +// +// Note: A side effect is that closing a DB before exiting an application, both +// for the Go API and through database/sql driver, is no more required, +// strictly speaking. Beware that exiting an application while there is an open +// (uncommitted) transaction in progress means losing the transaction data. +// However, the DB will not become corrupted because of not closing it. Nor +// that was the case before, but formerly failing to close a DB could have +// resulted in losing the data of the last transaction. +// +// 2014-09-21: id() now optionally accepts a single argument - a table name. +// +// 2014-09-01: Added the DB.Flush() method and the LIKE pattern matching +// predicate. +// +// 2014-08-08: The built in functions max and min now accept also time values. +// Thanks opennota! (https://github.com/opennota) +// +// 2014-06-05: RecordSet interface extended by new methods FirstRow and Rows. +// +// 2014-06-02: Indices on id() are now used by SELECT statements. +// +// 2014-05-07: Introduction of Marshal, Schema, Unmarshal. +// +// 2014-04-15: +// +// Added optional IF NOT EXISTS clause to CREATE INDEX and optional IF EXISTS +// clause to DROP INDEX. +// +// 2014-04-12: +// +// The column Unique in the virtual table __Index was renamed to IsUnique +// because the old name is a keyword. Unfortunately, this is a breaking change, +// sorry. +// +// 2014-04-11: Introduction of LIMIT, OFFSET. +// +// 2014-04-10: Introduction of query rewriting. +// +// 2014-04-07: Introduction of indices. +// +// Notation +// +// The syntax is specified using Extended Backus-Naur Form (EBNF) +// +// Production = production_name "=" [ Expression ] "." . +// Expression = Alternative { "|" Alternative } . +// Alternative = Term { Term } . +// Term = production_name | token [ "…" token ] | Group | Option | Repetition . +// Group = "(" Expression ")" . +// Option = "[" Expression "]" . +// Repetition = "{" Expression "}" . +// Productions are expressions constructed from terms and the following operators, in increasing precedence +// +// | alternation +// () grouping +// [] option (0 or 1 times) +// {} repetition (0 to n times) +// +// Lower-case production names are used to identify lexical tokens. +// Non-terminals are in CamelCase. Lexical tokens are enclosed in double quotes +// "" or back quotes ``. +// +// The form a … b represents the set of characters from a through b as +// alternatives. The horizontal ellipsis … is also used elsewhere in the spec +// to informally denote various enumerations or code snippets that are not +// further specified. +// +// QL source code representation +// +// QL source code is Unicode text encoded in UTF-8. The text is not +// canonicalized, so a single accented code point is distinct from the same +// character constructed from combining an accent and a letter; those are +// treated as two code points. For simplicity, this document will use the +// unqualified term character to refer to a Unicode code point in the source +// text. +// +// Each code point is distinct; for instance, upper and lower case letters are +// different characters. +// +// Implementation restriction: For compatibility with other tools, the parser +// may disallow the NUL character (U+0000) in the statement. +// +// Implementation restriction: A byte order mark is disallowed anywhere in QL +// statements. +// +// Characters +// +// The following terms are used to denote specific character classes +// +// newline = . // the Unicode code point U+000A +// unicode_char = . // an arbitrary Unicode code point except newline +// ascii_letter = "a" … "z" | "A" … "Z" . +// +// Letters and digits +// +// The underscore character _ (U+005F) is considered a letter. +// +// letter = ascii_letter | "_" . +// decimal_digit = "0" … "9" . +// octal_digit = "0" … "7" . +// hex_digit = "0" … "9" | "A" … "F" | "a" … "f" . +// +// Lexical elements +// +// Lexical elements are comments, tokens, identifiers, keywords, operators and +// delimiters, integer, floating-point, imaginary, rune and string literals and +// QL parameters. +// +// Comments +// +// There are three forms of comments +// +// Line comments start with the character sequence // or -- and stop at the end +// of the line. A line comment acts like a space. +// +// General comments start with the character sequence /* and continue through +// the character sequence */. A general comment acts like a space. +// +// Comments do not nest. +// +// Tokens +// +// Tokens form the vocabulary of QL. There are four classes: identifiers, +// keywords, operators and delimiters, and literals. White space, formed from +// spaces (U+0020), horizontal tabs (U+0009), carriage returns (U+000D), and +// newlines (U+000A), is ignored except as it separates tokens that would +// otherwise combine into a single token. +// +// Semicolons +// +// The formal grammar uses semicolons ";" as separators of QL statements. A +// single QL statement or the last QL statement in a list of statements can +// have an optional semicolon terminator. (Actually a separator from the +// following empty statement.) +// +// Identifiers +// +// Identifiers name entities such as tables or record set columns. An +// identifier is a sequence of one or more letters and digits. The first +// character in an identifier must be a letter. +// +// identifier = letter { letter | decimal_digit } . +// +// For example +// +// price +// _tmp42 +// Sales +// +// No identifiers are predeclared, however note that no keyword can be used as +// an identifier. Identifiers starting with two underscores are used for meta +// data virtual tables names. For forward compatibility, users should generally +// avoid using any identifiers starting with two underscores. For example +// +// __Column +// __Index +// __Table +// +// Keywords +// +// The following keywords are reserved and may not be used as identifiers. +// +// ADD BY duration INDEX NULL TRUNCATE +// ALTER byte EXISTS INSERT OFFSET uint +// AND COLUMN false int ON uint16 +// AS complex128 float int16 ORDER uint32 +// ASC complex64 float32 int32 SELECT uint64 +// BETWEEN CREATE float64 int64 SET uint8 +// bigint DELETE FROM int8 string UNIQUE +// bigrat DESC GROUP INTO TABLE UPDATE +// blob DISTINCT IF LIMIT time VALUES +// bool DROP IN LIKE true WHERE +// NOT OR +// +// Keywords are not case sensitive. +// +// Operators and Delimiters +// +// The following character sequences represent operators, delimiters, and other +// special tokens +// +// + & && == != ( ) +// - | || < <= [ ] +// * ^ > >= , ; +// / << = . +// % >> ! +// &^ +// +// Operators consisting of more than one character are referred to by names in +// the rest of the documentation +// +// andand = "&&" . +// andnot = "&^" . +// lsh = "<<" . +// le = "<=" . +// eq = "==" . +// ge = ">=" . +// neq = "!=" . +// oror = "||" . +// rsh = ">>" . +// +// Integer literals +// +// An integer literal is a sequence of digits representing an integer constant. +// An optional prefix sets a non-decimal base: 0 for octal, 0x or 0X for +// hexadecimal. In hexadecimal literals, letters a-f and A-F represent values +// 10 through 15. +// +// int_lit = decimal_lit | octal_lit | hex_lit . +// decimal_lit = ( "1" … "9" ) { decimal_digit } . +// octal_lit = "0" { octal_digit } . +// hex_lit = "0" ( "x" | "X" ) hex_digit { hex_digit } . +// +// For example +// +// 42 +// 0600 +// 0xBadFace +// 1701411834604692 +// +// Floating-point literals +// +// A floating-point literal is a decimal representation of a floating-point +// constant. It has an integer part, a decimal point, a fractional part, and an +// exponent part. The integer and fractional part comprise decimal digits; the +// exponent part is an e or E followed by an optionally signed decimal +// exponent. One of the integer part or the fractional part may be elided; one +// of the decimal point or the exponent may be elided. +// +// float_lit = decimals "." [ decimals ] [ exponent ] | +// decimals exponent | +// "." decimals [ exponent ] . +// decimals = decimal_digit { decimal_digit } . +// exponent = ( "e" | "E" ) [ "+" | "-" ] decimals . +// +// For example +// +// 0. +// 72.40 +// 072.40 // == 72.40 +// 2.71828 +// 1.e+0 +// 6.67428e-11 +// 1E6 +// .25 +// .12345E+5 +// +// Imaginary literals +// +// An imaginary literal is a decimal representation of the imaginary part of a +// complex constant. It consists of a floating-point literal or decimal integer +// followed by the lower-case letter i. +// +// imaginary_lit = (decimals | float_lit) "i" . +// +// For example +// +// 0i +// 011i // == 11i +// 0.i +// 2.71828i +// 1.e+0i +// 6.67428e-11i +// 1E6i +// .25i +// .12345E+5i +// +// Rune literals +// +// A rune literal represents a rune constant, an integer value identifying a +// Unicode code point. A rune literal is expressed as one or more characters +// enclosed in single quotes. Within the quotes, any character may appear +// except single quote and newline. A single quoted character represents the +// Unicode value of the character itself, while multi-character sequences +// beginning with a backslash encode values in various formats. +// +// The simplest form represents the single character within the quotes; since +// QL statements are Unicode characters encoded in UTF-8, multiple +// UTF-8-encoded bytes may represent a single integer value. For instance, the +// literal 'a' holds a single byte representing a literal a, Unicode U+0061, +// value 0x61, while 'ä' holds two bytes (0xc3 0xa4) representing a literal +// a-dieresis, U+00E4, value 0xe4. +// +// Several backslash escapes allow arbitrary values to be encoded as ASCII +// text. There are four ways to represent the integer value as a numeric +// constant: \x followed by exactly two hexadecimal digits; \u followed by +// exactly four hexadecimal digits; \U followed by exactly eight hexadecimal +// digits, and a plain backslash \ followed by exactly three octal digits. In +// each case the value of the literal is the value represented by the digits in +// the corresponding base. +// +// Although these representations all result in an integer, they have different +// valid ranges. Octal escapes must represent a value between 0 and 255 +// inclusive. Hexadecimal escapes satisfy this condition by construction. The +// escapes \u and \U represent Unicode code points so within them some values +// are illegal, in particular those above 0x10FFFF and surrogate halves. +// +// After a backslash, certain single-character escapes represent special +// values +// +// \a U+0007 alert or bell +// \b U+0008 backspace +// \f U+000C form feed +// \n U+000A line feed or newline +// \r U+000D carriage return +// \t U+0009 horizontal tab +// \v U+000b vertical tab +// \\ U+005c backslash +// \' U+0027 single quote (valid escape only within rune literals) +// \" U+0022 double quote (valid escape only within string literals) +// +// All other sequences starting with a backslash are illegal inside rune +// literals. +// +// rune_lit = "'" ( unicode_value | byte_value ) "'" . +// unicode_value = unicode_char | little_u_value | big_u_value | escaped_char . +// byte_value = octal_byte_value | hex_byte_value . +// octal_byte_value = `\` octal_digit octal_digit octal_digit . +// hex_byte_value = `\` "x" hex_digit hex_digit . +// little_u_value = `\` "u" hex_digit hex_digit hex_digit hex_digit . +// big_u_value = `\` "U" hex_digit hex_digit hex_digit hex_digit +// hex_digit hex_digit hex_digit hex_digit . +// escaped_char = `\` ( "a" | "b" | "f" | "n" | "r" | "t" | "v" | `\` | "'" | `"` ) . +// +// For example +// +// 'a' +// 'ä' +// '本' +// '\t' +// '\000' +// '\007' +// '\377' +// '\x07' +// '\xff' +// '\u12e4' +// '\U00101234' +// 'aa' // illegal: too many characters +// '\xa' // illegal: too few hexadecimal digits +// '\0' // illegal: too few octal digits +// '\uDFFF' // illegal: surrogate half +// '\U00110000' // illegal: invalid Unicode code point +// +// String literals +// +// A string literal represents a string constant obtained from concatenating a +// sequence of characters. There are two forms: raw string literals and +// interpreted string literals. +// +// Raw string literals are character sequences between back quotes ``. Within +// the quotes, any character is legal except back quote. The value of a raw +// string literal is the string composed of the uninterpreted (implicitly +// UTF-8-encoded) characters between the quotes; in particular, backslashes +// have no special meaning and the string may contain newlines. Carriage +// returns inside raw string literals are discarded from the raw string value. +// +// Interpreted string literals are character sequences between double quotes +// "". The text between the quotes, which may not contain newlines, forms the +// value of the literal, with backslash escapes interpreted as they are in rune +// literals (except that \' is illegal and \" is legal), with the same +// restrictions. The three-digit octal (\nnn) and two-digit hexadecimal (\xnn) +// escapes represent individual bytes of the resulting string; all other +// escapes represent the (possibly multi-byte) UTF-8 encoding of individual +// characters. Thus inside a string literal \377 and \xFF represent a single +// byte of value 0xFF=255, while ÿ, \u00FF, \U000000FF and \xc3\xbf represent +// the two bytes 0xc3 0xbf of the UTF-8 encoding of character U+00FF. +// +// string_lit = raw_string_lit | interpreted_string_lit . +// raw_string_lit = "`" { unicode_char | newline } "`" . +// interpreted_string_lit = `"` { unicode_value | byte_value } `"` . +// +// For example +// +// `abc` // same as "abc" +// `\n +// \n` // same as "\\n\n\\n" +// "\n" +// "" +// "Hello, world!\n" +// "日本語" +// "\u65e5本\U00008a9e" +// "\xff\u00FF" +// "\uD800" // illegal: surrogate half +// "\U00110000" // illegal: invalid Unicode code point +// +// These examples all represent the same string +// +// "日本語" // UTF-8 input text +// `日本語` // UTF-8 input text as a raw literal +// "\u65e5\u672c\u8a9e" // the explicit Unicode code points +// "\U000065e5\U0000672c\U00008a9e" // the explicit Unicode code points +// "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e" // the explicit UTF-8 bytes +// +// If the statement source represents a character as two code points, such as a +// combining form involving an accent and a letter, the result will be an error +// if placed in a rune literal (it is not a single code point), and will appear +// as two code points if placed in a string literal. +// +// QL parameters +// +// Literals are assigned their values from the respective text representation +// at "compile" (parse) time. QL parameters provide the same functionality as +// literals, but their value is assigned at execution time from an expression +// list passed to DB.Run or DB.Execute. Using '?' or '$' is completely +// equivalent. +// +// ql_parameter = ( "?" | "$" ) "1" … "9" { "0" … "9" } . +// +// For example +// +// SELECT DepartmentID +// FROM department +// WHERE DepartmentID == ?1 +// ORDER BY DepartmentName; +// +// SELECT employee.LastName +// FROM department, employee +// WHERE department.DepartmentID == $1 && employee.LastName > $2 +// ORDER BY DepartmentID; +// +// Constants +// +// Keywords 'false' and 'true' (not case sensitive) represent the two possible +// constant values of type bool (also not case sensitive). +// +// Keyword 'NULL' (not case sensitive) represents an untyped constant which is +// assignable to any type. NULL is distinct from any other value of any type. +// +// Types +// +// A type determines the set of values and operations specific to values of +// that type. A type is specified by a type name. +// +// Type = "bigint" // http://golang.org/pkg/math/big/#Int +// | "bigrat" // http://golang.org/pkg/math/big/#Rat +// | "blob" // []byte +// | "bool" +// | "byte" // alias for uint8 +// | "complex128" +// | "complex64" +// | "duration" // http://golang.org/pkg/time/#Duration +// | "float" // alias for float64 +// | "float32" +// | "float64" +// | "int" // alias for int64 +// | "int16" +// | "int32" +// | "int64" +// | "int8" +// | "rune" // alias for int32 +// | "string" +// | "time" // http://golang.org/pkg/time/#Time +// | "uint" // alias for uint64 +// | "uint16" +// | "uint32" +// | "uint64" +// | "uint8" . +// +// Named instances of the boolean, numeric, and string types are keywords. The +// names are not case sensitive. +// +// Note: The blob type is exchanged between the back end and the API as []byte. +// On 32 bit platforms this limits the size which the implementation can handle +// to 2G. +// +// Boolean types +// +// A boolean type represents the set of Boolean truth values denoted by the +// predeclared constants true and false. The predeclared boolean type is bool. +// +// Duration type +// +// A duration type represents the elapsed time between two instants as an int64 +// nanosecond count. The representation limits the largest representable +// duration to approximately 290 years. +// +// Numeric types +// +// A numeric type represents sets of integer or floating-point values. The +// predeclared architecture-independent numeric types are +// +// uint8 the set of all unsigned 8-bit integers (0 to 255) +// uint16 the set of all unsigned 16-bit integers (0 to 65535) +// uint32 the set of all unsigned 32-bit integers (0 to 4294967295) +// uint64 the set of all unsigned 64-bit integers (0 to 18446744073709551615) +// +// int8 the set of all signed 8-bit integers (-128 to 127) +// int16 the set of all signed 16-bit integers (-32768 to 32767) +// int32 the set of all signed 32-bit integers (-2147483648 to 2147483647) +// int64 the set of all signed 64-bit integers (-9223372036854775808 to 9223372036854775807) +// duration the set of all signed 64-bit integers (-9223372036854775808 to 9223372036854775807) +// bigint the set of all integers +// +// bigrat the set of all rational numbers +// +// float32 the set of all IEEE-754 32-bit floating-point numbers +// float64 the set of all IEEE-754 64-bit floating-point numbers +// +// complex64 the set of all complex numbers with float32 real and imaginary parts +// complex128 the set of all complex numbers with float64 real and imaginary parts +// +// byte alias for uint8 +// float alias for float64 +// int alias for int64 +// rune alias for int32 +// uint alias for uint64 +// +// The value of an n-bit integer is n bits wide and represented using two's +// complement arithmetic. +// +// Conversions are required when different numeric types are mixed in an +// expression or assignment. +// +// String types +// +// A string type represents the set of string values. A string value is a +// (possibly empty) sequence of bytes. The case insensitive keyword for the +// string type is 'string'. +// +// The length of a string (its size in bytes) can be discovered using the +// built-in function len. +// +// Time types +// +// A time type represents an instant in time with nanosecond precision. Each +// time has associated with it a location, consulted when computing the +// presentation form of the time. +// +// Predeclared functions +// +// The following functions are implicitly declared +// +// avg complex contains count date +// day formatTime hasPrefix hasSuffix hour +// hours id imag len max +// min minute minutes month nanosecond +// nanoseconds now parseTime real second +// seconds since sum timeIn weekday +// year yearDay +// +// Expressions +// +// An expression specifies the computation of a value by applying operators and +// functions to operands. +// +// Operands +// +// Operands denote the elementary values in an expression. An operand may be a +// literal, a (possibly qualified) identifier denoting a constant or a function +// or a table/record set column, or a parenthesized expression. +// +// Operand = Literal | QualifiedIdent | "(" Expression ")" . +// Literal = "FALSE" | "NULL" | "TRUE" +// | float_lit | imaginary_lit | int_lit | rune_lit | string_lit +// | ql_parameter . +// +// Qualified identifiers +// +// A qualified identifier is an identifier qualified with a table/record set +// name prefix. +// +// QualifiedIdent = identifier [ "." identifier ] . +// +// For example +// +// invoice.Num // might denote column 'Num' from table 'invoice' +// +// Primary expressions +// +// Primary expression are the operands for unary and binary expressions. +// +// PrimaryExpression = Operand +// | Conversion +// | PrimaryExpression Index +// | PrimaryExpression Slice +// | PrimaryExpression Call . +// +// Call = "(" [ ExpressionList ] ")" . +// Index = "[" Expression "]" . +// Slice = "[" [ Expression ] ":" [ Expression ] "]" . +// +// For example +// +// x +// 2 +// (s + ".txt") +// f(3.1415, true) +// s[i : j + 1] +// +// Index expressions +// +// A primary expression of the form +// +// s[x] +// +// denotes the element of a string indexed by x. Its type is byte. The value x +// is called the index. The following rules apply +// +// - The index x must be of integer type except bigint or duration; it is in +// range if 0 <= x < len(s), otherwise it is out of range. +// +// - A constant index must be non-negative and representable by a value of type +// int. +// +// - A constant index must be in range if the string a is a literal. +// +// - If x is out of range at run time, a run-time error occurs. +// +// - s[x] is the byte at index x and the type of s[x] is byte. +// +// If s is NULL or x is NULL then the result is NULL. +// +// Otherwise s[x] is illegal. +// +// Slices +// +// For a string, the primary expression +// +// s[low : high] +// +// constructs a substring. The indices low and high select which elements +// appear in the result. The result has indices starting at 0 and length equal +// to high - low. +// +// For convenience, any of the indices may be omitted. A missing low index +// defaults to zero; a missing high index defaults to the length of the sliced +// operand +// +// s[2:] // same s[2 : len(s)] +// s[:3] // same as s[0 : 3] +// s[:] // same as s[0 : len(s)] +// +// The indices low and high are in range if 0 <= low <= high <= len(a), +// otherwise they are out of range. A constant index must be non-negative and +// representable by a value of type int. If both indices are constant, they +// must satisfy low <= high. If the indices are out of range at run time, a +// run-time error occurs. +// +// Integer values of type bigint or duration cannot be used as indices. +// +// If s is NULL the result is NULL. If low or high is not omitted and is NULL +// then the result is NULL. +// +// Calls +// +// Given an identifier f denoting a predeclared function, +// +// f(a1, a2, … an) +// +// calls f with arguments a1, a2, … an. Arguments are evaluated before the +// function is called. The type of the expression is the result type of f. +// +// complex(x, y) +// len(name) +// +// In a function call, the function value and arguments are evaluated in the +// usual order. After they are evaluated, the parameters of the call are passed +// by value to the function and the called function begins execution. The +// return value of the function is passed by value when the function returns. +// +// Calling an undefined function causes a compile-time error. +// +// Operators +// +// Operators combine operands into expressions. +// +// Expression = Term { ( oror | "OR" ) Term } . +// +// ExpressionList = Expression { "," Expression } [ "," ]. +// Factor = PrimaryFactor { ( ge | ">" | le | "<" | neq | eq | "LIKE" ) PrimaryFactor } [ Predicate ] . +// PrimaryFactor = PrimaryTerm { ( "^" | "|" | "-" | "+" ) PrimaryTerm } . +// PrimaryTerm = UnaryExpr { ( andnot | "&" | lsh | rsh | "%" | "/" | "*" ) UnaryExpr } . +// Term = Factor { ( andand | "AND" ) Factor } . +// UnaryExpr = [ "^" | "!" | "-" | "+" ] PrimaryExpression . +// +// Comparisons are discussed elsewhere. For other binary operators, the operand +// types must be identical unless the operation involves shifts or untyped +// constants. For operations involving constants only, see the section on +// constant expressions. +// +// Except for shift operations, if one operand is an untyped constant and the +// other operand is not, the constant is converted to the type of the other +// operand. +// +// The right operand in a shift expression must have unsigned integer type or +// be an untyped constant that can be converted to unsigned integer type. If +// the left operand of a non-constant shift expression is an untyped constant, +// the type of the constant is what it would be if the shift expression were +// replaced by its left operand alone. +// +// Pattern matching +// +// Expressions of the form +// +// expr1 LIKE expr2 +// +// yeild a boolean value true if expr2, a regular expression, matches expr1 +// (see also [6]). Both expression must be of type string. If any one of the +// expressions is NULL the result is NULL. +// +// Predicates +// +// Predicates are special form expressions having a boolean result type. +// +// Expressions of the form +// +// expr IN ( expr1, expr2, expr3, ... ) // case A +// +// expr NOT IN ( expr1, expr2, expr3, ... ) // case B +// +// are equivalent, including NULL handling, to +// +// expr == expr1 || expr == expr2 || expr == expr3 || ... // case A +// +// expr != expr1 && expr != expr2 && expr != expr3 && ... // case B +// +// The types of involved expressions must be comparable as defined in +// "Comparison operators". +// +// Another form of the IN predicate creates the expression list from a result +// of a SelectStmt. +// +// DELETE FROM t WHERE id() IN (SELECT id_t FROM u WHERE inactive_days > 365) +// +// The SelectStmt must select only one column. The produced expression list is +// resource limited by the memory available to the process. NULL values +// produced by the SelectStmt are ignored, but if all records of the SelectStmt +// are NULL the predicate yields NULL. The select statement is evaluated only +// once. If the type of expr is not the same as the type of the field returned +// by the SelectStmt then the set operation yields false. The type of the +// column returned by the SelectStmt must be one of the simple (non blob-like) +// types: +// +// bool +// byte // alias uint8 +// complex128 +// complex64 +// float // alias float64 +// float32 +// float64 +// int // alias int64 +// int16 +// int32 +// int64 +// int8 +// rune // alias int32 +// string +// uint // alias uint64 +// uint16 +// uint32 +// uint64 +// uint8 +// +// Expressions of the form +// +// expr BETWEEN low AND high // case A +// +// expr NOT BETWEEN low AND high // case B +// +// are equivalent, including NULL handling, to +// +// expr >= low && expr <= high // case A +// +// expr < low || expr > high // case B +// +// The types of involved expressions must be ordered as defined in "Comparison +// operators". +// +// Predicate = ( +// [ "NOT" ] ( +// "IN" "(" ExpressionList ")" +// | "IN" "(" SelectStmt ")" +// | "BETWEEN" PrimaryFactor "AND" PrimaryFactor +// ) +// | "IS" [ "NOT" ] "NULL" +// ). +// +// Expressions of the form +// +// expr IS NULL // case A +// +// expr IS NOT NULL // case B +// +// yeild a boolean value true if expr does not have a specific type (case A) or +// if expr has a specific type (case B). In other cases the result is a boolean +// value false. +// +// Operator precedence +// +// Unary operators have the highest precedence. +// +// There are five precedence levels for binary operators. Multiplication +// operators bind strongest, followed by addition operators, comparison +// operators, && (logical AND), and finally || (logical OR) +// +// Precedence Operator +// 5 * / % << >> & &^ +// 4 + - | ^ +// 3 == != < <= > >= +// 2 && +// 1 || +// +// Binary operators of the same precedence associate from left to right. For +// instance, x / y * z is the same as (x / y) * z. +// +// +x +// 23 + 3*x[i] +// x <= f() +// ^a >> b +// f() || g() +// x == y+1 && z > 0 +// +// Note that the operator precedence is reflected explicitly by the grammar. +// +// Arithmetic operators +// +// Arithmetic operators apply to numeric values and yield a result of the same +// type as the first operand. The four standard arithmetic operators (+, -, *, +// /) apply to integer, rational, floating-point, and complex types; + also +// applies to strings; +,- also applies to times. All other arithmetic +// operators apply to integers only. +// +// + sum integers, rationals, floats, complex values, strings +// - difference integers, rationals, floats, complex values, times +// * product integers, rationals, floats, complex values +// / quotient integers, rationals, floats, complex values +// % remainder integers +// +// & bitwise AND integers +// | bitwise OR integers +// ^ bitwise XOR integers +// &^ bit clear (AND NOT) integers +// +// << left shift integer << unsigned integer +// >> right shift integer >> unsigned integer +// +// Strings can be concatenated using the + operator +// +// "hi" + string(c) + " and good bye" +// +// String addition creates a new string by concatenating the operands. +// +// A value of type duration can be added to or subtracted from a value of type time. +// +// now() + duration("1h") // time after 1 hour from now +// duration("1h") + now() // time after 1 hour from now +// now() - duration("1h") // time before 1 hour from now +// duration("1h") - now() // illegal, negative times do not exist +// +// Times can subtracted from each other producing a value of type duration. +// +// now() - t0 // elapsed time since t0 +// now() + now() // illegal, operator + not defined for times +// +// For two integer values x and y, the integer quotient q = x / y and remainder +// r = x % y satisfy the following relationships +// +// x = q*y + r and |r| < |y| +// +// with x / y truncated towards zero ("truncated division"). +// +// x y x / y x % y +// 5 3 1 2 +// -5 3 -1 -2 +// 5 -3 -1 2 +// -5 -3 1 -2 +// +// As an exception to this rule, if the dividend x is the most negative value +// for the int type of x, the quotient q = x / -1 is equal to x (and r = 0). +// +// x, q +// int8 -128 +// int16 -32768 +// int32 -2147483648 +// int64 -9223372036854775808 +// +// If the divisor is a constant expression, it must not be zero. If the divisor +// is zero at run time, a run-time error occurs. If the dividend is +// non-negative and the divisor is a constant power of 2, the division may be +// replaced by a right shift, and computing the remainder may be replaced by a +// bitwise AND operation +// +// x x / 4 x % 4 x >> 2 x & 3 +// 11 2 3 2 3 +// -11 -2 -3 -3 1 +// +// The shift operators shift the left operand by the shift count specified by +// the right operand. They implement arithmetic shifts if the left operand is a +// signed integer and logical shifts if it is an unsigned integer. There is no +// upper limit on the shift count. Shifts behave as if the left operand is +// shifted n times by 1 for a shift count of n. As a result, x << 1 is the same +// as x*2 and x >> 1 is the same as x/2 but truncated towards negative +// infinity. +// +// For integer operands, the unary operators +, -, and ^ are defined as follows +// +// +x is 0 + x +// -x negation is 0 - x +// ^x bitwise complement is m ^ x with m = "all bits set to 1" for unsigned x +// and m = -1 for signed x +// +// For floating-point and complex numbers, +x is the same as x, while -x is the +// negation of x. The result of a floating-point or complex division by zero is +// not specified beyond the IEEE-754 standard; whether a run-time error occurs +// is implementation-specific. +// +// Whenever any operand of any arithmetic operation, unary or binary, is NULL, +// as well as in the case of the string concatenating operation, the result is +// NULL. +// +// 42*NULL // the result is NULL +// NULL/x // the result is NULL +// "foo"+NULL // the result is NULL +// +// Integer overflow +// +// For unsigned integer values, the operations +, -, *, and << are computed +// modulo 2n, where n is the bit width of the unsigned integer's type. Loosely +// speaking, these unsigned integer operations discard high bits upon overflow, +// and expressions may rely on ``wrap around''. +// +// For signed integers with a finite bit width, the operations +, -, *, and << +// may legally overflow and the resulting value exists and is deterministically +// defined by the signed integer representation, the operation, and its +// operands. No exception is raised as a result of overflow. An evaluator may +// not optimize an expression under the assumption that overflow does not +// occur. For instance, it may not assume that x < x + 1 is always true. +// +// Integers of type bigint and rationals do not overflow but their handling is +// limited by the memory resources available to the program. +// +// Comparison operators +// +// Comparison operators compare two operands and yield a boolean value. +// +// == equal +// != not equal +// < less +// <= less or equal +// > greater +// >= greater or equal +// +// In any comparison, the first operand must be of same type as is the second +// operand, or vice versa. +// +// The equality operators == and != apply to operands that are comparable. The +// ordering operators <, <=, >, and >= apply to operands that are ordered. +// These terms and the result of the comparisons are defined as follows +// +// - Boolean values are comparable. Two boolean values are equal if they are +// either both true or both false. +// +// - Complex values are comparable. Two complex values u and v are equal if +// both real(u) == real(v) and imag(u) == imag(v). +// +// - Integer values are comparable and ordered, in the usual way. Note that +// durations are integers. +// +// - Floating point values are comparable and ordered, as defined by the +// IEEE-754 standard. +// +// - Rational values are comparable and ordered, in the usual way. +// +// - String values are comparable and ordered, lexically byte-wise. +// +// - Time values are comparable and ordered. +// +// Whenever any operand of any comparison operation is NULL, the result is +// NULL. +// +// Note that slices are always of type string. +// +// Logical operators +// +// Logical operators apply to boolean values and yield a boolean result. The +// right operand is evaluated conditionally. +// +// && conditional AND p && q is "if p then q else false" +// || conditional OR p || q is "if p then true else q" +// ! NOT !p is "not p" +// +// The truth tables for logical operations with NULL values +// +// +-------+-------+---------+---------+ +// | p | q | p || q | p && q | +// +-------+-------+---------+---------+ +// | true | true | *true | true | +// | true | false | *true | false | +// | true | NULL | *true | NULL | +// | false | true | true | *false | +// | false | false | false | *false | +// | false | NULL | NULL | *false | +// | NULL | true | true | NULL | +// | NULL | false | NULL | false | +// | NULL | NULL | NULL | NULL | +// +-------+-------+---------+---------+ +// * indicates q is not evaluated. +// +// +-------+-------+ +// | p | !p | +// +-------+-------+ +// | true | false | +// | false | true | +// | NULL | NULL | +// +-------+-------+ +// +// Conversions +// +// Conversions are expressions of the form T(x) where T is a type and x is an +// expression that can be converted to type T. +// +// Conversion = Type "(" Expression ")" . +// +// A constant value x can be converted to type T in any of these cases: +// +// - x is representable by a value of type T. +// +// - x is a floating-point constant, T is a floating-point type, and x is +// representable by a value of type T after rounding using IEEE 754 +// round-to-even rules. The constant T(x) is the rounded value. +// +// - x is an integer constant and T is a string type. The same rule as for +// non-constant x applies in this case. +// +// Converting a constant yields a typed constant as result. +// +// float32(2.718281828) // 2.718281828 of type float32 +// complex128(1) // 1.0 + 0.0i of type complex128 +// float32(0.49999999) // 0.5 of type float32 +// string('x') // "x" of type string +// string(0x266c) // "♬" of type string +// "foo" + "bar" // "foobar" +// int(1.2) // illegal: 1.2 cannot be represented as an int +// string(65.0) // illegal: 65.0 is not an integer constant +// +// A non-constant value x can be converted to type T in any of these cases: +// +// - x has type T. +// +// - x's type and T are both integer or floating point types. +// +// - x's type and T are both complex types. +// +// - x is an integer, except bigint or duration, and T is a string type. +// +// Specific rules apply to (non-constant) conversions between numeric types or +// to and from a string type. These conversions may change the representation +// of x and incur a run-time cost. All other conversions only change the type +// but not the representation of x. +// +// A conversion of NULL to any type yields NULL. +// +// Conversions between numeric types +// +// For the conversion of non-constant numeric values, the following rules +// apply +// +// 1. When converting between integer types, if the value is a signed integer, +// it is sign extended to implicit infinite precision; otherwise it is zero +// extended. It is then truncated to fit in the result type's size. For +// example, if v == uint16(0x10F0), then uint32(int8(v)) == 0xFFFFFFF0. The +// conversion always yields a valid value; there is no indication of overflow. +// +// 2. When converting a floating-point number to an integer, the fraction is +// discarded (truncation towards zero). +// +// 3. When converting an integer or floating-point number to a floating-point +// type, or a complex number to another complex type, the result value is +// rounded to the precision specified by the destination type. For instance, +// the value of a variable x of type float32 may be stored using additional +// precision beyond that of an IEEE-754 32-bit number, but float32(x) +// represents the result of rounding x's value to 32-bit precision. Similarly, +// x + 0.1 may use more than 32 bits of precision, but float32(x + 0.1) does +// not. +// +// In all non-constant conversions involving floating-point or complex values, +// if the result type cannot represent the value the conversion succeeds but +// the result value is implementation-dependent. +// +// Conversions to and from a string type +// +// 1. Converting a signed or unsigned integer value to a string type yields a +// string containing the UTF-8 representation of the integer. Values outside +// the range of valid Unicode code points are converted to "\uFFFD". +// +// string('a') // "a" +// string(-1) // "\ufffd" == "\xef\xbf\xbd" +// string(0xf8) // "\u00f8" == "ø" == "\xc3\xb8" +// string(0x65e5) // "\u65e5" == "日" == "\xe6\x97\xa5" +// +// 2. Converting a blob to a string type yields a string whose successive bytes +// are the elements of the blob. +// +// string(b /* []byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'} */) // "hellø" +// string(b /* []byte{} */) // "" +// string(b /* []byte(nil) */) // "" +// +// 3. Converting a value of a string type to a blob yields a blob whose +// successive elements are the bytes of the string. +// +// blob("hellø") // []byte{'h', 'e', 'l', 'l', '\xc3', '\xb8'} +// blob("") // []byte{} +// +// 4. Converting a value of a bigint type to a string yields a string +// containing the decimal decimal representation of the integer. +// +// string(M9) // "2305843009213693951" +// +// 5. Converting a value of a string type to a bigint yields a bigint value +// containing the integer represented by the string value. A prefix of “0x” or +// “0X” selects base 16; the “0” prefix selects base 8, and a “0b” or “0B” +// prefix selects base 2. Otherwise the value is interpreted in base 10. An +// error occurs if the string value is not in any valid format. +// +// bigint("2305843009213693951") // M9 +// bigint("0x1ffffffffffffffffffffff") // M10 == 2^89-1 +// +// 6. Converting a value of a rational type to a string yields a string +// containing the decimal decimal representation of the rational in the form +// "a/b" (even if b == 1). +// +// string(bigrat(355)/bigrat(113)) // "355/113" +// +// 7. Converting a value of a string type to a bigrat yields a bigrat value +// containing the rational represented by the string value. The string can be +// given as a fraction "a/b" or as a floating-point number optionally followed +// by an exponent. An error occurs if the string value is not in any valid +// format. +// +// bigrat("1.2e-34") +// bigrat("355/113") +// +// 8. Converting a value of a duration type to a string returns a string +// representing the duration in the form "72h3m0.5s". Leading zero units are +// omitted. As a special case, durations less than one second format using a +// smaller unit (milli-, micro-, or nanoseconds) to ensure that the leading +// digit is non-zero. The zero duration formats as 0, with no unit. +// +// string(elapsed) // "1h", for example +// +// 9. Converting a string value to a duration yields a duration represented by +// the string. A duration string is a possibly signed sequence of decimal +// numbers, each with optional fraction and a unit suffix, such as "300ms", +// "-1.5h" or "2h45m". Valid time units are "ns", "us" (or "µs"), "ms", "s", +// "m", "h". +// +// duration("1m") // http://golang.org/pkg/time/#Minute +// +// 10. Converting a time value to a string returns the time formatted using the +// format string +// +// "2006-01-02 15:04:05.999999999 -0700 MST" +// +// Order of evaluation +// +// When evaluating the operands of an expression or of function calls, +// operations are evaluated in lexical left-to-right order. +// +// For example, in the evaluation of +// +// g(h(), i()+x[j()], c) +// +// the function calls and evaluation of c happen in the order h(), i(), j(), c. +// +// Floating-point operations within a single expression are evaluated according +// to the associativity of the operators. Explicit parentheses affect the +// evaluation by overriding the default associativity. In the expression x + (y +// + z) the addition y + z is performed before adding x. +// +// Statements +// +// Statements control execution. +// +// Statement = EmptyStmt | AlterTableStmt | BeginTransactionStmt | CommitStmt +// | CreateIndexStmt | CreateTableStmt | DeleteFromStmt | DropIndexStmt +// | DropTableStmt | InsertIntoStmt | RollbackStmt | SelectStmt +// | TruncateTableStmt | UpdateStmt . +// +// StatementList = Statement { ";" Statement } . +// +// Empty statements +// +// The empty statement does nothing. +// +// EmptyStmt = . +// +// ALTER TABLE +// +// Alter table statements modify existing tables. With the ADD clause it adds +// a new column to the table. The column must not exist. With the DROP clause +// it removes an existing column from a table. The column must exist and it +// must be not the only (last) column of the table. IOW, there cannot be a +// table with no columns. +// +// AlterTableStmt = "ALTER" "TABLE" TableName ( "ADD" ColumnDef | "DROP" "COLUMN" ColumnName ) . +// +// For example +// +// BEGIN TRANSACTION; +// ALTER TABLE Stock ADD Qty int; +// ALTER TABLE Income DROP COLUMN Taxes; +// COMMIT; +// +// BEGIN TRANSACTION +// +// Begin transactions statements introduce a new transaction level. Every +// transaction level must be eventually balanced by exactly one of COMMIT or +// ROLLBACK statements. Note that when a transaction is roll-backed because of +// a statement failure then no explicit balancing of the respective BEGIN +// TRANSACTION is statement is required nor permitted. +// +// Failure to properly balance any opened transaction level may cause dead +// locks and/or lose of data updated in the uppermost opened but never properly +// closed transaction level. +// +// BeginTransactionStmt = "BEGIN" "TRANSACTION" . +// +// For example +// +// BEGIN TRANSACTION; +// INSERT INTO foo VALUES (42, 3.14); +// INSERT INTO foo VALUES (-1, 2.78); +// COMMIT; +// +// Mandatory transactions +// +// A database cannot be updated (mutated) outside of a transaction. Statements +// requiring a transaction +// +// ALTER TABLE +// COMMIT +// CREATE INDEX +// CREATE TABLE +// DELETE FROM +// DROP INDEX +// DROP TABLE +// INSERT INTO +// ROLLBACK +// TRUNCATE TABLE +// UPDATE +// +// A database is effectively read only outside of a transaction. Statements not +// requiring a transaction +// +// BEGIN TRANSACTION +// SELECT FROM +// +// COMMIT +// +// The commit statement closes the innermost transaction nesting level. If +// that's the outermost level then the updates to the DB made by the +// transaction are atomically made persistent. +// +// CommitStmt = "COMMIT" . +// +// For example +// +// BEGIN TRANSACTION; +// INSERT INTO AccountA (Amount) VALUES ($1); +// INSERT INTO AccountB (Amount) VALUES (-$1); +// COMMIT; +// +// CREATE INDEX +// +// Create index statements create new indices. Index is a named projection of +// ordered values of a table column to the respective records. As a special +// case the id() of the record can be indexed. Index name must not be the same +// as any of the existing tables and it also cannot be the same as of any +// column name of the table the index is on. +// +// CreateIndexStmt = "CREATE" [ "UNIQUE" ] "INDEX" [ "IF" "NOT" "EXISTS" ] +// IndexName "ON" TableName "(" ( ColumnName | "id" Call ) ")" . +// +// For example +// +// BEGIN TRANSACTION; +// CREATE TABLE Orders (CustomerID int, Date time); +// CREATE INDEX OrdersID ON Orders (id()); +// CREATE INDEX OrdersDate ON Orders (Date); +// CREATE TABLE Items (OrderID int, ProductID int, Qty int); +// CREATE INDEX ItemsOrderID ON Items (OrderID); +// COMMIT; +// +// Now certain SELECT statements may use the indices to speed up joins and/or +// to speed up record set filtering when the WHERE clause is used; or the +// indices might be used to improve the performance when the ORDER BY clause is +// present. +// +// The UNIQUE modifier requires the indexed values to be unique or NULL. +// +// The optional IF NOT EXISTS clause makes the statement a no operation if the +// index already exists. +// +// CREATE TABLE +// +// Create table statements create new tables. A column definition declares the +// column name and type. Table names and column names are case sensitive. +// Neither a table or an index of the same name may exist in the DB. +// +// CreateTableStmt = "CREATE" "TABLE" [ "IF" "NOT" "EXISTS" ] TableName +// "(" ColumnDef { "," ColumnDef } [ "," ] ")" . +// +// ColumnDef = ColumnName Type . +// ColumnName = identifier . +// TableName = identifier . +// +// For example +// +// BEGIN TRANSACTION; +// CREATE TABLE department ( +// DepartmentID int, +// DepartmentName string, +// ); +// CREATE TABLE employee ( +// LastName string, +// DepartmentID int, +// ); +// COMMIT; +// +// The optional IF NOT EXISTS clause makes the statement a no operation if the +// table already exists. +// +// DELETE FROM +// +// Delete from statements remove rows from a table, which must exist. +// +// DeleteFromStmt = "DELETE" "FROM" TableName [ WhereClause ] . +// +// For example +// +// BEGIN TRANSACTION; +// DELETE FROM DepartmentID +// WHERE DepartmentName == "Ponies"; +// COMMIT; +// +// If the WHERE clause is not present then all rows are removed and the +// statement is equivalent to the TRUNCATE TABLE statement. +// +// DROP INDEX +// +// Drop index statements remove indices from the DB. The index must exist. +// +// DropIndexStmt = "DROP" "INDEX" [ "IF" "EXISTS" ] IndexName . +// IndexName = identifier . +// +// For example +// +// BEGIN TRANSACTION; +// DROP INDEX ItemsOrderID; +// COMMIT; +// +// The optional IF EXISTS clause makes the statement a no operation if the +// index does not exist. +// +// DROP TABLE +// +// Drop table statements remove tables from the DB. The table must exist. +// +// DropTableStmt = "DROP" "TABLE" [ "IF" "EXISTS" ] TableName . +// +// For example +// +// BEGIN TRANSACTION; +// DROP TABLE Inventory; +// COMMIT; +// +// The optional IF EXISTS clause makes the statement a no operation if the +// table does not exist. +// +// INSERT INTO +// +// Insert into statements insert new rows into tables. New rows come from +// literal data, if using the VALUES clause, or are a result of select +// statement. In the later case the select statement is fully evaluated before +// the insertion of any rows is performed, allowing to insert values calculated +// from the same table rows are to be inserted into. If the ColumnNameList part +// is omitted then the number of values inserted in the row must be the same as +// are columns in the table. If the ColumnNameList part is present then the +// number of values per row must be same as the same number of column names. +// All other columns of the record are set to NULL. The type of the value +// assigned to a column must be the same as is the column's type or the value +// must be NULL. +// +// InsertIntoStmt = "INSERT" "INTO" TableName [ "(" ColumnNameList ")" ] ( Values | SelectStmt ) . +// +// ColumnNameList = ColumnName { "," ColumnName } [ "," ] . +// Values = "VALUES" "(" ExpressionList ")" { "," "(" ExpressionList ")" } [ "," ] . +// +// For example +// +// BEGIN TRANSACTION; +// INSERT INTO department (DepartmentID) VALUES (42); +// +// INSERT INTO department ( +// DepartmentName, +// DepartmentID, +// ) +// VALUES ( +// "R&D", +// 42, +// ); +// +// INSERT INTO department VALUES +// (42, "R&D"), +// (17, "Sales"), +// ; +// COMMIT; +// +// BEGIN TRANSACTION; +// INSERT INTO department (DepartmentName, DepartmentID) +// SELECT DepartmentName+"/headquarters", DepartmentID+1000 +// FROM department; +// COMMIT; +// +// ROLLBACK +// +// The rollback statement closes the innermost transaction nesting level +// discarding any updates to the DB made by it. If that's the outermost level +// then the effects on the DB are as if the transaction never happened. +// +// RollbackStmt = "ROLLBACK" . +// +// For example +// +// // First statement list +// BEGIN TRANSACTION +// SELECT * INTO tmp FROM foo; +// INSERT INTO tmp SELECT * from bar; +// SELECT * from tmp; +// +// The (temporary) record set from the last statement is returned and can be +// processed by the client. +// +// // Second statement list +// ROLLBACK; +// +// In this case the rollback is the same as 'DROP TABLE tmp;' but it can be a +// more complex operation. +// +// SELECT FROM +// +// Select from statements produce recordsets. The optional DISTINCT modifier +// ensures all rows in the result recordset are unique. Either all of the +// resulting fields are returned ('*') or only those named in FieldList. +// +// RecordSetList is a list of table names or parenthesized select statements, +// optionally (re)named using the AS clause. +// +// The result can be filtered using a WhereClause and orderd by the OrderBy +// clause. +// +// SelectStmt = "SELECT" [ "DISTINCT" ] ( "*" | FieldList ) "FROM" RecordSetList +// [ WhereClause ] [ GroupByClause ] [ OrderBy ] [ Limit ] [ Offset ]. +// +// RecordSet = ( TableName | "(" SelectStmt [ ";" ] ")" ) [ "AS" identifier ] . +// RecordSetList = RecordSet { "," RecordSet } [ "," ] . +// +// For example +// +// SELECT * FROM Stock; +// +// SELECT DepartmentID +// FROM department +// WHERE DepartmentID == 42 +// ORDER BY DepartmentName; +// +// SELECT employee.LastName +// FROM department, employee +// WHERE department.DepartmentID == employee.DepartmentID +// ORDER BY DepartmentID; +// +// If Recordset is a nested, parenthesized SelectStmt then it must be given a +// name using the AS clause if its field are to be accessible in expressions. +// +// SELECT a.b, c.d +// FROM +// x AS a, +// ( +// SELECT * FROM y; +// ) AS c +// WHERE a.e > c.e; +// +// Fields naming rules +// +// A field is an named expression. Identifiers, not used as a type in +// conversion or a function name in the Call clause, denote names of (other) +// fields, values of which should be used in the expression. +// +// Field = Expression [ "AS" identifier ] . +// +// The expression can be named using the AS clause. If the AS clause is not +// present and the expression consists solely of a field name, then that field +// name is used as the name of the resulting field. Otherwise the field is +// unnamed. +// +// For example +// +// SELECT 314, 42 as AUQLUE, DepartmentID, DepartmentID+1000, LastName as Name from employee; +// // Fields are []string{"", "AUQLUE", "DepartmentID", "", "Name"} +// +// The SELECT statement can optionally enumerate the desired/resulting fields +// in a list. +// +// FieldList = Field { "," Field } [ "," ] . +// +// No two identical field names can appear in the list. +// +// SELECT DepartmentID, LastName, DepartmentID from employee; +// // duplicate field name "DepartmentID" +// +// SELECT DepartmentID, LastName, DepartmentID as ID2 from employee; +// // works +// +// When more than one record set is used in the FROM clause record set list, +// the result record set field names are rewritten to be qualified using +// the record set names. +// +// SELECT * FROM employee, department; +// // Fields are []string{"employee.LastName", "employee.DepartmentID", "department.DepartmentID", "department.DepartmentName" +// +// If a particular record set doesn't have a name, its respective fields became +// unnamed. +// +// SELECT * FROM employee as e, ( SELECT * FROM department); +// // Fields are []string{"e.LastName", "e.DepartmentID", "", "" +// +// SELECT * FROM employee AS e, ( SELECT * FROM department) AS d; +// // Fields are []string{"e.LastName", "e.DepartmentID", "d.DepartmentID", "d.DepartmentName" +// +// Recordset ordering +// +// Resultins rows of a SELECT statement can be optionally ordered by the ORDER +// BY clause. Collating proceeds by considering the expressions in the +// expression list left to right until a collating order is determined. Any +// possibly remaining expressions are not evaluated. +// +// OrderBy = "ORDER" "BY" ExpressionList [ "ASC" | "DESC" ] . +// +// All of the expression values must yield an ordered type or NULL. Ordered +// types are defined in "Comparison operators". Collating of elements having a +// NULL value is different compared to what the comparison operators yield in +// expression evaluation (NULL result instead of a boolean value). +// +// Below, T denotes a non NULL value of any QL type. +// +// NULL < T +// +// NULL collates before any non NULL value (is considered smaller than T). +// +// NULL == NULL +// +// Two NULLs have no collating order (are considered equal). +// +// Recordset filtering +// +// The WHERE clause restricts records considered by some statements, like +// SELECT FROM, DELETE FROM, or UPDATE. +// +// expression value consider the record +// ---------------- ------------------- +// true yes +// false or NULL no +// +// It is an error if the expression evaluates to a non null value of non bool +// type. +// +// WhereClause = "WHERE" Expression . +// +// Recordset grouping +// +// The GROUP BY clause is used to project rows having common values into a +// smaller set of rows. +// +// For example +// +// SELECT Country, sum(Qty) FROM Sales GROUP BY Country; +// +// SELECT Country, Product FROM Sales GROUP BY Country, Product; +// +// SELECT DISTINCT Country, Product FROM Sales; +// +// Using the GROUP BY without any aggregate functions in the selected fields is +// in certain cases equal to using the DISTINCT modifier. The last two examples +// above produce the same resultsets. +// +// GroupByClause = "GROUP BY" ColumnNameList . +// +// Skipping records +// +// The optional OFFSET clause allows to ignore first N records. For example +// +// SELECT * FROM t OFFSET 10; +// +// The above will produce only rows 11, 12, ... of the record set, if they +// exist. The value of the expression must a non negative integer, but not +// bigint or duration. +// +// Offset = "OFFSET" Expression . +// +// Limiting the result set size +// +// The optional LIMIT clause allows to ignore all but first N records. For +// example +// +// SELECT * FROM t LIMIT 10; +// +// The above will return at most the first 10 records of the record set. The +// value of the expression must a non negative integer, but not bigint or +// duration. +// +// Limit = "Limit" Expression . +// +// The LIMIT and OFFSET clauses can be combined. For example +// +// SELECT * FROM t LIMIT 5 OFFSET 3; +// +// Considering table t has, say 10 records, the above will produce only records +// 4 - 8. +// +// #1: Ignore 1/3 +// #2: Ignore 2/3 +// #3: Ignore 3/3 +// #4: Return 1/5 +// #5: Return 2/5 +// #6: Return 3/5 +// #7: Return 4/5 +// #8: Return 5/5 +// +// After returning record #8, no more result rows/records are computed. +// +// Select statement evaluation order +// +// 1. The FROM clause is evaluated, producing a Cartesian product of its source +// record sets (tables or nested SELECT statements). +// +// 2. If present, the WHERE clause is evaluated on the result set of the +// previous evaluation. +// +// 3. If present, the GROUP BY clause is evaluated on the result set of the +// previous evaluation(s). +// +// 4. The SELECT field expressions are evaluated on the result set of the +// previous evaluation(s). +// +// 5. If present, the DISTINCT modifier is evaluated on the result set of the +// previous evaluation(s). +// +// 6. If present, the ORDER BY clause is evaluated on the result set of the +// previous evaluation(s). +// +// 7. If present, the OFFSET clause is evaluated on the result set of the +// previous evaluation(s). The offset expression is evaluated once for the +// first record produced by the previous evaluations. +// +// 8. If present, the LIMIT clause is evaluated on the result set of the +// previous evaluation(s). The limit expression is evaluated once for the first +// record produced by the previous evaluations. +// +// +// TRUNCATE TABLE +// +// Truncate table statements remove all records from a table. The table must +// exist. +// +// TruncateTableStmt = "TRUNCATE" "TABLE" TableName . +// +// For example +// +// BEGIN TRANSACTION +// TRUNCATE TABLE department; +// COMMIT; +// +// UPDATE +// +// Update statements change values of fields in rows of a table. +// +// UpdateStmt = "UPDATE" TableName [ "SET" ] AssignmentList [ WhereClause ] . +// +// AssignmentList = Assignment { "," Assignment } [ "," ] . +// Assignment = ColumnName "=" Expression . +// +// For example +// +// BEGIN TRANSACTION +// UPDATE department +// DepartmentName = DepartmentName + " dpt.", +// DepartmentID = 1000+DepartmentID, +// WHERE DepartmentID < 1000; +// COMMIT; +// +// Note: The SET clause is optional. +// +// System Tables +// +// To allow to query for DB meta data, there exist specially named virtual +// tables. +// +// Note: System tables have fake table-wise unique but meaningless and unstable +// record IDs. Do not apply the built-in id() to any system table. +// +// Tables Table +// +// The table __Table lists all tables in the DB. The schema is +// +// CREATE TABLE __Table (Name string, Schema string); +// +// The Schema column returns the statement to (re)create table Name. +// +// Columns Table +// +// The table __Colum lists all columns of all tables in the DB. The schema is +// +// CREATE TABLE __Column (TableName string, Ordinal int, Name string, Type string); +// +// The Ordinal column defines the 1-based index of the column in the record. +// +// Indices table +// +// The table __Index lists all indices in the DB. The schema is +// +// CREATE TABLE __Index (TableName string, ColumnName string, Name string, IsUnique bool); +// +// The IsUnique columns reflects if the index was created using the optional +// UNIQUE clause. +// +// Built-in functions +// +// Built-in functions are predeclared. +// +// Average +// +// The built-in aggregate function avg returns the average of values of an +// expression. Avg ignores NULL values, but returns NULL if all values of a +// column are NULL or if avg is applied to an empty record set. +// +// func avg(e numeric) typeof(e) +// +// The column values must be of a numeric type. +// +// SELECT salesperson, avg(sales) FROM salesforce GROUP BY salesperson; +// +// Contains +// +// The built-in function contains returns true if substr is within s. +// +// func contains(s, substr string) bool +// +// If any argument to contains is NULL the result is NULL. +// +// Count +// +// The built-in aggregate function count returns how many times an expression +// has a non NULL values or the number of rows in a record set. Note: count() +// returns 0 for an empty record set. +// +// func count() int // The number of rows in a record set. +// func count(e expression) int // The number of cases where the expression value is not NULL. +// +// For example +// +// SELECT count() FROM department; // # of rows +// +// SELECT count(DepartmentID) FROM department; // # of records with non NULL field DepartmentID +// +// SELECT count()-count(DepartmentID) FROM department; // # of records with NULL field DepartmentID +// +// SELECT count(foo+bar*3) AS y FROM t; // # of cases where 'foo+bar*3' is non NULL +// +// Date +// +// Date returns the time corresponding to +// +// yyyy-mm-dd hh:mm:ss + nsec nanoseconds +// +// in the appropriate zone for that time in the given location. +// +// The month, day, hour, min, sec, and nsec values may be outside their usual +// ranges and will be normalized during the conversion. For example, October 32 +// converts to November 1. +// +// A daylight savings time transition skips or repeats times. For example, in +// the United States, March 13, 2011 2:15am never occurred, while November 6, +// 2011 1:15am occurred twice. In such cases, the choice of time zone, and +// therefore the time, is not well-defined. Date returns a time that is correct +// in one of the two zones involved in the transition, but it does not +// guarantee which. +// +// func date(year, month, day, hour, min, sec, nsec int, loc string) time +// +// A location maps time instants to the zone in use at that time. Typically, +// the location represents the collection of time offsets in use in a +// geographical area, such as "CEST" and "CET" for central Europe. "local" +// represents the system's local time zone. "UTC" represents Universal +// Coordinated Time (UTC). +// +// The month specifies a month of the year (January = 1, ...). +// +// If any argument to date is NULL the result is NULL. +// +// Day +// +// The built-in function day returns the day of the month specified by t. +// +// func day(t time) int +// +// If the argument to day is NULL the result is NULL. +// +// Format time +// +// The built-in function formatTime returns a textual representation of the +// time value formatted according to layout, which defines the format by +// showing how the reference time, +// +// Mon Jan 2 15:04:05 -0700 MST 2006 +// +// would be displayed if it were the value; it serves as an example of the +// desired output. The same display rules will then be applied to the time +// value. +// +// func formatTime(t time, layout string) string +// +// If any argument to formatTime is NULL the result is NULL. +// +// NOTE: The string value of the time zone, like "CET" or "ACDT", is dependent +// on the time zone of the machine the function is run on. For example, if the +// t value is in "CET", but the machine is in "ACDT", instead of "CET" the +// result is "+0100". This is the same what Go (time.Time).String() returns and +// in fact formatTime directly calls t.String(). +// +// formatTime(date(2006, 1, 2, 15, 4, 5, 999999999, "CET")) +// +// returns +// +// 2006-01-02 15:04:05.999999999 +0100 CET +// +// on a machine in the CET time zone, but may return +// +// 2006-01-02 15:04:05.999999999 +0100 +0100 +// +// on a machine in the ACDT zone. The time value is in both cases the same so +// its ordering and comparing is correct. Only the display value can differ. +// +// HasPrefix +// +// The built-in function hasPrefix tests whether the string s begins with prefix. +// +// func hasPrefix(s, prefix string) bool +// +// If any argument to hasPrefix is NULL the result is NULL. +// +// HasSuffix +// +// The built-in function hasSuffix tests whether the string s ends with suffix. +// +// func hasSuffix(s, suffix string) bool +// +// If any argument to hasSuffix is NULL the result is NULL. +// +// Hour +// +// The built-in function hour returns the hour within the day specified by t, +// in the range [0, 23]. +// +// func hour(t time) int +// +// If the argument to hour is NULL the result is NULL. +// +// Hours +// +// The built-in function hours returns the duration as a floating point number +// of hours. +// +// func hours(d duration) float +// +// If the argument to hours is NULL the result is NULL. +// +// Record id +// +// The built-in function id takes zero or one arguments. If no argument is +// provided, id() returns a table-unique automatically assigned numeric +// identifier of type int. Ids of deleted records are not reused unless the DB +// becomes completely empty (has no tables). +// +// func id() int +// +// For example +// +// SELECT id(), LastName +// FROM employee; +// +// If id() without arguments is called for a row which is not a table record +// then the result value is NULL. +// +// For example +// +// SELECT id(), e.LastName, e.DepartmentID, d.DepartmentID +// FROM +// employee AS e, +// department AS d, +// WHERE e.DepartmentID == d.DepartmentID; +// // Will always return NULL in first field. +// +// SELECT e.ID, e.LastName, e.DepartmentID, d.DepartmentID +// FROM +// (SELECT id() AS ID, LastName, DepartmentID FROM employee) AS e, +// department as d, +// WHERE e.DepartmentID == d.DepartmentID; +// // Will work. +// +// If id() has one argument it must be a table name of a table in a cross join. +// +// For example +// +// SELECT * +// FROM foo, bar +// WHERE bar.fooID == id(foo) +// ORDER BY id(foo); +// +// Length +// +// The built-in function len takes a string argument and returns the lentgh of +// the string in bytes. +// +// func len(s string) int +// +// The expression len(s) is constant if s is a string constant. +// +// If the argument to len is NULL the result is NULL. +// +// Maximum +// +// The built-in aggregate function max returns the largest value of an +// expression in a record set. Max ignores NULL values, but returns NULL if +// all values of a column are NULL or if max is applied to an empty record set. +// +// func max(e expression) typeof(e) // The largest value of the expression. +// +// The expression values must be of an ordered type. +// +// For example +// +// SELECT department, max(sales) FROM t GROUP BY department; +// +// Minimum +// +// The built-in aggregate function min returns the smallest value of an +// expression in a record set. Min ignores NULL values, but returns NULL if +// all values of a column are NULL or if min is applied to an empty record set. +// +// func min(e expression) typeof(e) // The smallest value of the expression. +// +// For example +// +// SELECT a, min(b) FROM t GROUP BY a; +// +// The column values must be of an ordered type. +// +// Minute +// +// The built-in function minute returns the minute offset within the hour +// specified by t, in the range [0, 59]. +// +// func minute(t time) int +// +// If the argument to minute is NULL the result is NULL. +// +// Minutes +// +// The built-in function minutes returns the duration as a floating point +// number of minutes. +// +// func minutes(d duration) float +// +// If the argument to minutes is NULL the result is NULL. +// +// Month +// +// The built-in function month returns the month of the year specified by t +// (January = 1, ...). +// +// func month(t time) int +// +// If the argument to month is NULL the result is NULL. +// +// Nanosecond +// +// The built-in function nanosecond returns the nanosecond offset within the +// second specified by t, in the range [0, 999999999]. +// +// func nanosecond(t time) int +// +// If the argument to nanosecond is NULL the result is NULL. +// +// Nanoseconds +// +// The built-in function nanoseconds returns the duration as an integer +// nanosecond count. +// +// func nanoseconds(d duration) float +// +// If the argument to nanoseconds is NULL the result is NULL. +// +// Now +// +// The built-in function now returns the current local time. +// +// func now() time +// +// Parse time +// +// The built-in function parseTime parses a formatted string and returns the +// time value it represents. The layout defines the format by showing how the +// reference time, +// +// Mon Jan 2 15:04:05 -0700 MST 2006 +// +// would be interpreted if it were the value; it serves as an example of the +// input format. The same interpretation will then be made to the input string. +// +// Elements omitted from the value are assumed to be zero or, when zero is +// impossible, one, so parsing "3:04pm" returns the time corresponding to Jan +// 1, year 0, 15:04:00 UTC (note that because the year is 0, this time is +// before the zero Time). Years must be in the range 0000..9999. The day of the +// week is checked for syntax but it is otherwise ignored. +// +// In the absence of a time zone indicator, parseTime returns a time in UTC. +// +// When parsing a time with a zone offset like -0700, if the offset corresponds +// to a time zone used by the current location, then parseTime uses that +// location and zone in the returned time. Otherwise it records the time as +// being in a fabricated location with time fixed at the given zone offset. +// +// When parsing a time with a zone abbreviation like MST, if the zone +// abbreviation has a defined offset in the current location, then that offset +// is used. The zone abbreviation "UTC" is recognized as UTC regardless of +// location. If the zone abbreviation is unknown, Parse records the time as +// being in a fabricated location with the given zone abbreviation and a zero +// offset. This choice means that such a time can be parses and reformatted +// with the same layout losslessly, but the exact instant used in the +// representation will differ by the actual zone offset. To avoid such +// problems, prefer time layouts that use a numeric zone offset. +// +// func parseTime(layout, value string) time +// +// If any argument to parseTime is NULL the result is NULL. +// +// Second +// +// The built-in function second returns the second offset within the minute +// specified by t, in the range [0, 59]. +// +// func second(t time) int +// +// If the argument to second is NULL the result is NULL. +// +// Seconds +// +// The built-in function seconds returns the duration as a floating point +// number of seconds. +// +// func seconds(d duration) float +// +// If the argument to seconds is NULL the result is NULL. +// +// Since +// +// The built-in function since returns the time elapsed since t. It is +// shorthand for now()-t. +// +// func since(t time) duration +// +// If the argument to since is NULL the result is NULL. +// +// Sum +// +// The built-in aggregate function sum returns the sum of values of an +// expression for all rows of a record set. Sum ignores NULL values, but +// returns NULL if all values of a column are NULL or if sum is applied to an +// empty record set. +// +// func sum(e expression) typeof(e) // The sum of the values of the expression. +// +// The column values must be of a numeric type. +// +// SELECT salesperson, sum(sales) FROM salesforce GROUP BY salesperson; +// +// Time in a specific zone +// +// The built-in function timeIn returns t with the location information set to +// loc. For discussion of the loc argument please see date(). +// +// func timeIn(t time, loc string) time +// +// If any argument to timeIn is NULL the result is NULL. +// +// Weekday +// +// The built-in function weekday returns the day of the week specified by t. +// Sunday == 0, Monday == 1, ... +// +// func weekday(t time) int +// +// If the argument to weekday is NULL the result is NULL. +// +// Year +// +// The built-in function year returns the year in which t occurs. +// +// func year(t time) int +// +// If the argument to year is NULL the result is NULL. +// +// Year day +// +// The built-in function yearDay returns the day of the year specified by t, in +// the range [1,365] for non-leap years, and [1,366] in leap years. +// +// func yearDay(t time) int +// +// If the argument to yearDay is NULL the result is NULL. +// +// Manipulating complex numbers +// +// Three functions assemble and disassemble complex numbers. The built-in +// function complex constructs a complex value from a floating-point real and +// imaginary part, while real and imag extract the real and imaginary parts of +// a complex value. +// +// complex(realPart, imaginaryPart floatT) complexT +// real(complexT) floatT +// imag(complexT) floatT +// +// The type of the arguments and return value correspond. For complex, the two +// arguments must be of the same floating-point type and the return type is the +// complex type with the corresponding floating-point constituents: complex64 +// for float32, complex128 for float64. The real and imag functions together +// form the inverse, so for a complex value z, z == complex(real(z), imag(z)). +// +// If the operands of these functions are all constants, the return value is a +// constant. +// +// complex(2, -2) // complex128 +// complex(1.0, -1.4) // complex128 +// float32(math.Cos(math.Pi/2)) // float32 +// complex(5, float32(-x)) // complex64 +// imag(b) // float64 +// real(complex(5, float32(-x))) // float32 +// +// If any argument to any of complex, real, imag functions is NULL the result +// is NULL. +// +// Size guarantees +// +// For the numeric types, the following sizes are guaranteed +// +// type size in bytes +// +// byte, uint8, int8 1 +// uint16, int16 2 +// uint32, int32, float32 4 +// uint, uint64, int, int64, float64, complex64 8 +// complex128 16 +// +// License +// +// Portions of this specification page are modifications based on work[2] +// created and shared by Google[3] and used according to terms described in the +// Creative Commons 3.0 Attribution License[4]. +// +// This specification is licensed under the Creative Commons Attribution 3.0 +// License, and code is licensed under a BSD license[5]. +// +// References +// +// Links from the above documentation +// +// [1]: http://golang.org/ref/spec#Notation +// [2]: http://golang.org/ref/spec +// [3]: http://code.google.com/policies.html +// [4]: http://creativecommons.org/licenses/by/3.0/ +// [5]: http://golang.org/LICENSE +// [6]: http://golang.org/pkg/regexp/#Regexp.MatchString +// [7]: http://developer.mimer.com/validator/sql-reserved-words.tml +// +// Implementation details +// +// This section is not part of the specification. +// +// Indices +// +// WARNING: The implementation of indices is new and it surely needs more time +// to become mature. +// +// Indices are used currently used only by the WHERE clause. The following +// expression patterns of 'WHERE expression' are recognized and trigger index +// use. +// +// - WHERE c // For bool typed indexed column c +// - WHERE !c // For bool typed indexed column c +// - WHERE c relOp constExpr // For indexed column c +// - WHERE c relOp parameter // For indexed column c +// - WHERE parameter relOp c // For indexed column c +// - WHERE constExpr relOp c // For indexed column c +// +// The relOp is one of the relation operators <, <=, ==, >=, >. For the +// equality operator both operands must be of comparable types. For all other +// operators both operands must be of ordered types. The constant expression is +// a compile time constant expression. Some constant folding is still a TODO. +// Parameter is a QL parameter ($1 etc.). +// +// Query rewriting +// +// Consider tables t and u, both with an indexed field f. The WHERE expression +// doesn't comply with the above simple detected cases. +// +// SELECT * FROM t, u WHERE t.f < x && u.f < y; +// +// However, such query is now automatically rewritten to +// +// SELECT * FROM +// (SELECT * FROM t WHERE f < x), +// (SELECT * FROM u WHERE f < y); +// +// which will use both of the indices. The impact of using the indices can be +// substantial (cf. BenchmarkCrossJoin*) if the resulting rows have low +// "selectivity", ie. only few rows from both tables are selected by the +// respective WHERE filtering. +// +// Note: Existing QL DBs can be used and indices can be added to them. However, +// once any indices are present in the DB, the old QL versions cannot work with +// such DB anymore. +// +// Benchmarks +// +// Running a benchmark with -v (-test.v) outputs information about the scale +// used to report records/s and a brief description of the benchmark. For +// example +// +// $ go test -run NONE -bench 'SelectMem.*1e[23]' -v +// PASS +// BenchmarkSelectMem1kBx1e2 50000 67680 ns/op 1477537.05 MB/s +// --- BENCH: BenchmarkSelectMem1kBx1e2 +// all_test.go:310: +// ============================================================= +// NOTE: All benchmarks report records/s as 1000000 bytes/s. +// ============================================================= +// all_test.go:321: Having a table of 100 records, each of size 1kB, measure the performance of +// SELECT * FROM t; +// +// BenchmarkSelectMem1kBx1e3 5000 634819 ns/op 1575251.01 MB/s +// --- BENCH: BenchmarkSelectMem1kBx1e3 +// all_test.go:321: Having a table of 1000 records, each of size 1kB, measure the performance of +// SELECT * FROM t; +// +// ok github.com/cznic/ql 7.496s +// $ +// +// Running the full suite of benchmarks takes a lot of time. Use the -timeout +// flag to avoid them being killed after the default time limit (10 minutes). +package ql diff --git a/Godeps/_workspace/src/github.com/cznic/ql/driver.go b/Godeps/_workspace/src/github.com/cznic/ql/driver.go new file mode 100644 index 0000000..7aa69b4 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/ql/driver.go @@ -0,0 +1,528 @@ +// Copyright 2014 The ql Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// database/sql/driver + +package ql + +import ( + "bytes" + "database/sql" + "database/sql/driver" + "errors" + "fmt" + "io" + "math/big" + "os" + "path/filepath" + "strings" + "sync" + "time" +) + +var ( + _ driver.Conn = (*driverConn)(nil) + _ driver.Driver = (*sqlDriver)(nil) + _ driver.Execer = (*driverConn)(nil) + _ driver.Queryer = (*driverConn)(nil) + _ driver.Result = (*driverResult)(nil) + _ driver.Rows = (*driverRows)(nil) + _ driver.Stmt = (*driverStmt)(nil) + _ driver.Tx = (*driverConn)(nil) + + txBegin = MustCompile("BEGIN TRANSACTION;") + txCommit = MustCompile("COMMIT;") + txRollback = MustCompile("ROLLBACK;") + + errNoResult = errors.New("query statement does not produce a result set (no top level SELECT)") +) + +type errList []error + +func (e *errList) append(err error) { + if err != nil { + *e = append(*e, err) + } +} + +func (e errList) error() error { + if len(e) == 0 { + return nil + } + + return e +} + +func (e errList) Error() string { + a := make([]string, len(e)) + for i, v := range e { + a[i] = v.Error() + } + return strings.Join(a, "\n") +} + +func params(args []driver.Value) []interface{} { + r := make([]interface{}, len(args)) + for i, v := range args { + r[i] = interface{}(v) + } + return r +} + +var ( + fileDriver = &sqlDriver{dbs: map[string]*driverDB{}} + fileDriverOnce sync.Once + memDriver = &sqlDriver{isMem: true, dbs: map[string]*driverDB{}} + memDriverOnce sync.Once +) + +// RegisterDriver registers a QL database/sql/driver[0] named "ql". The name +// parameter of +// +// sql.Open("ql", name) +// +// is interpreted as a path name to a named DB file which will be created if +// not present. The underlying QL database data are persisted on db.Close(). +// RegisterDriver can be safely called multiple times, it'll register the +// driver only once. +// +// The name argument can be optionally prefixed by "file://". In that case the +// prefix is stripped before interpreting it as a file name. +// +// The name argument can be optionally prefixed by "memory://". In that case +// the prefix is stripped before interpreting it as a name of a memory-only, +// volatile DB. +// +// [0]: http://golang.org/pkg/database/sql/driver/ +func RegisterDriver() { + fileDriverOnce.Do(func() { sql.Register("ql", fileDriver) }) +} + +// RegisterMemDriver registers a QL memory database/sql/driver[0] named +// "ql-mem". The name parameter of +// +// sql.Open("ql-mem", name) +// +// is interpreted as an unique memory DB name which will be created if not +// present. The underlying QL memory database data are not persisted on +// db.Close(). RegisterMemDriver can be safely called multiple times, it'll +// register the driver only once. +// +// [0]: http://golang.org/pkg/database/sql/driver/ +func RegisterMemDriver() { + memDriverOnce.Do(func() { sql.Register("ql-mem", memDriver) }) +} + +type driverDB struct { + db *DB + name string + refcount int +} + +func newDriverDB(db *DB, name string) *driverDB { + return &driverDB{db: db, name: name, refcount: 1} +} + +// sqlDriver implements the interface required by database/sql/driver. +type sqlDriver struct { + dbs map[string]*driverDB + isMem bool + mu sync.Mutex +} + +func (d *sqlDriver) lock() func() { + d.mu.Lock() + return d.mu.Unlock +} + +// Open returns a new connection to the database. The name is a string in a +// driver-specific format. +// +// Open may return a cached connection (one previously closed), but doing so is +// unnecessary; the sql package maintains a pool of idle connections for +// efficient re-use. +// +// The returned connection is only used by one goroutine at a time. +func (d *sqlDriver) Open(name string) (driver.Conn, error) { + if d != fileDriver && d != memDriver { + return nil, fmt.Errorf("open: unexpected/unsupported instance of driver.Driver: %p", d) + } + + switch { + case d == fileDriver && strings.HasPrefix(name, "file://"): + name = name[len("file://"):] + case d == fileDriver && strings.HasPrefix(name, "memory://"): + d = memDriver + name = name[len("memory://"):] + } + name = filepath.Clean(name) + if name == "" || name == "." || name == string(os.PathSeparator) { + return nil, fmt.Errorf("invalid DB name %q", name) + } + + defer d.lock()() + db := d.dbs[name] + if db == nil { + var err error + var db0 *DB + switch d.isMem { + case true: + db0, err = OpenMem() + default: + db0, err = OpenFile(name, &Options{CanCreate: true}) + } + if err != nil { + return nil, err + } + + db = newDriverDB(db0, name) + d.dbs[name] = db + return newDriverConn(d, db), nil + } + + db.refcount++ + return newDriverConn(d, db), nil +} + +// driverConn is a connection to a database. It is not used concurrently by +// multiple goroutines. +// +// Conn is assumed to be stateful. +type driverConn struct { + ctx *TCtx + db *driverDB + driver *sqlDriver + stop map[*driverStmt]struct{} + tnl int +} + +func newDriverConn(d *sqlDriver, ddb *driverDB) driver.Conn { + r := &driverConn{ + db: ddb, + driver: d, + stop: map[*driverStmt]struct{}{}, + } + return r +} + +// Prepare returns a prepared statement, bound to this connection. +func (c *driverConn) Prepare(query string) (driver.Stmt, error) { + list, err := Compile(query) + if err != nil { + return nil, err + } + + s := &driverStmt{conn: c, stmt: list} + c.stop[s] = struct{}{} + return s, nil +} + +// Close invalidates and potentially stops any current prepared statements and +// transactions, marking this connection as no longer in use. +// +// Because the sql package maintains a free pool of connections and only calls +// Close when there's a surplus of idle connections, it shouldn't be necessary +// for drivers to do their own connection caching. +func (c *driverConn) Close() error { + var err errList + for s := range c.stop { + err.append(s.Close()) + } + defer c.driver.lock()() + dbs, name := c.driver.dbs, c.db.name + v := dbs[name] + v.refcount-- + if v.refcount == 0 { + err.append(c.db.db.Close()) + delete(dbs, name) + } + return err.error() +} + +// Begin starts and returns a new transaction. +func (c *driverConn) Begin() (driver.Tx, error) { + if c.ctx == nil { + c.ctx = NewRWCtx() + } + + if _, _, err := c.db.db.Execute(c.ctx, txBegin); err != nil { + return nil, err + } + + c.tnl++ + return c, nil +} + +func (c *driverConn) Commit() error { + if c.tnl == 0 || c.ctx == nil { + return errCommitNotInTransaction + } + + if _, _, err := c.db.db.Execute(c.ctx, txCommit); err != nil { + return err + } + + c.tnl-- + if c.tnl == 0 { + c.ctx = nil + } + return nil +} + +func (c *driverConn) Rollback() error { + if c.tnl == 0 || c.ctx == nil { + return errRollbackNotInTransaction + } + + if _, _, err := c.db.db.Execute(c.ctx, txRollback); err != nil { + return err + } + + c.tnl-- + if c.tnl == 0 { + c.ctx = nil + } + return nil +} + +// Execer is an optional interface that may be implemented by a Conn. +// +// If a Conn does not implement Execer, the sql package's DB.Exec will first +// prepare a query, execute the statement, and then close the statement. +// +// Exec may return driver.ErrSkip. +func (c *driverConn) Exec(query string, args []driver.Value) (driver.Result, error) { + list, err := Compile(query) + if err != nil { + return nil, err + } + + return driverExec(c.db, c.ctx, list, args) +} + +func driverExec(db *driverDB, ctx *TCtx, list List, args []driver.Value) (driver.Result, error) { + if _, _, err := db.db.Execute(ctx, list, params(args)...); err != nil { + return nil, err + } + + if len(list.l) == 1 { + switch list.l[0].(type) { + case *createTableStmt, *dropTableStmt, *alterTableAddStmt, + *alterTableDropColumnStmt, *truncateTableStmt: + return driver.ResultNoRows, nil + } + } + + r := &driverResult{} + if ctx != nil { + r.lastInsertID, r.rowsAffected = ctx.LastInsertID, ctx.RowsAffected + } + return r, nil +} + +// Queryer is an optional interface that may be implemented by a Conn. +// +// If a Conn does not implement Queryer, the sql package's DB.Query will first +// prepare a query, execute the statement, and then close the statement. +// +// Query may return driver.ErrSkip. +func (c *driverConn) Query(query string, args []driver.Value) (driver.Rows, error) { + list, err := Compile(query) + if err != nil { + return nil, err + } + + return driverQuery(c.db, c.ctx, list, args) +} + +func driverQuery(db *driverDB, ctx *TCtx, list List, args []driver.Value) (driver.Rows, error) { + rss, _, err := db.db.Execute(ctx, list, params(args)...) + if err != nil { + return nil, err + } + + switch n := len(rss); n { + case 0: + return nil, errNoResult + case 1: + rs := rss[n-1] + if x, ok := rss[n-1].(recordset); ok { + x.tx = ctx + rs = x + } + return newdriverRows(rs), nil + default: + return nil, fmt.Errorf("query produced %d result sets, expected only one", n) + } +} + +// driverResult is the result of a query execution. +type driverResult struct { + lastInsertID int64 + rowsAffected int64 +} + +// LastInsertId returns the database's auto-generated ID after, for example, an +// INSERT into a table with primary key. +func (r *driverResult) LastInsertId() (int64, error) { // -golint + return r.lastInsertID, nil +} + +// RowsAffected returns the number of rows affected by the query. +func (r *driverResult) RowsAffected() (int64, error) { + return r.rowsAffected, nil +} + +// driverRows is an iterator over an executed query's results. +type driverRows struct { + rs Recordset + done chan int + rows chan interface{} +} + +func newdriverRows(rs Recordset) *driverRows { + r := &driverRows{ + rs: rs, + done: make(chan int), + rows: make(chan interface{}, 500), + } + go func() { + err := io.EOF + if e := r.rs.Do(false, func(data []interface{}) (bool, error) { + select { + case r.rows <- data: + return true, nil + case <-r.done: + return false, nil + } + }); e != nil { + err = e + } + + select { + case r.rows <- err: + case <-r.done: + } + }() + return r +} + +// Columns returns the names of the columns. The number of columns of the +// result is inferred from the length of the slice. If a particular column +// name isn't known, an empty string should be returned for that entry. +func (r *driverRows) Columns() []string { + f, _ := r.rs.Fields() + return f +} + +// Close closes the rows iterator. +func (r *driverRows) Close() error { + close(r.done) + return nil +} + +// Next is called to populate the next row of data into the provided slice. The +// provided slice will be the same size as the Columns() are wide. +// +// The dest slice may be populated only with a driver Value type, but excluding +// string. All string values must be converted to []byte. +// +// Next should return io.EOF when there are no more rows. +func (r *driverRows) Next(dest []driver.Value) error { + select { + case rx := <-r.rows: + switch x := rx.(type) { + case error: + return x + case []interface{}: + if g, e := len(x), len(dest); g != e { + return fmt.Errorf("field count mismatch: got %d, need %d", g, e) + } + + for i, xi := range x { + switch v := xi.(type) { + case nil, int64, float64, bool, []byte, time.Time: + dest[i] = v + case complex64, complex128, *big.Int, *big.Rat: + var buf bytes.Buffer + fmt.Fprintf(&buf, "%v", v) + dest[i] = buf.Bytes() + case int8: + dest[i] = int64(v) + case int16: + dest[i] = int64(v) + case int32: + dest[i] = int64(v) + case int: + dest[i] = int64(v) + case uint8: + dest[i] = int64(v) + case uint16: + dest[i] = int64(v) + case uint32: + dest[i] = int64(v) + case uint64: + dest[i] = int64(v) + case uint: + dest[i] = int64(v) + case time.Duration: + dest[i] = int64(v) + case string: + dest[i] = []byte(v) + default: + return fmt.Errorf("internal error 004") + } + } + return nil + default: + return fmt.Errorf("internal error 005") + } + case <-r.done: + return io.EOF + } +} + +// driverStmt is a prepared statement. It is bound to a driverConn and not used +// by multiple goroutines concurrently. +type driverStmt struct { + conn *driverConn + stmt List +} + +// Close closes the statement. +// +// As of Go 1.1, a Stmt will not be closed if it's in use by any queries. +func (s *driverStmt) Close() error { + delete(s.conn.stop, s) + return nil +} + +// NumInput returns the number of placeholder parameters. +// +// If NumInput returns >= 0, the sql package will sanity check argument counts +// from callers and return errors to the caller before the statement's Exec or +// Query methods are called. +// +// NumInput may also return -1, if the driver doesn't know its number of +// placeholders. In that case, the sql package will not sanity check Exec or +// Query argument counts. +func (s *driverStmt) NumInput() int { + if x := s.stmt; len(x.l) == 1 { + return x.params + } + + return -1 +} + +// Exec executes a query that doesn't return rows, such as an INSERT or UPDATE. +func (s *driverStmt) Exec(args []driver.Value) (driver.Result, error) { + c := s.conn + return driverExec(c.db, c.ctx, s.stmt, args) +} + +// Exec executes a query that may return rows, such as a SELECT. +func (s *driverStmt) Query(args []driver.Value) (driver.Rows, error) { + c := s.conn + return driverQuery(c.db, c.ctx, s.stmt, args) +} diff --git a/Godeps/_workspace/src/github.com/cznic/ql/driver/Makefile b/Godeps/_workspace/src/github.com/cznic/ql/driver/Makefile new file mode 100644 index 0000000..f1b64ee --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/ql/driver/Makefile @@ -0,0 +1,40 @@ +# Copyright (c) 2014 The ql Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +.PHONY: all clean nuke + +all: editor + go install + go vet + golint . + make todo + +bench: all + go test -run NONE -bench . + +clean: + go clean + rm -f *~ + +cover: + t=$(shell tempfile) ; go test -coverprofile $$t && go tool cover -html $$t && unlink $$t + +editor: + go fmt + go test -i + go test + go build + +nuke: + go clean -i + +todo: + @grep -n ^[[:space:]]*_[[:space:]]*=[[:space:]][[:alpha:]][[:alnum:]]* *.go || true + @grep -n TODO *.go || true + @grep -n BUG *.go || true + @grep -n println *.go || true + +later: + @grep -n LATER *.go || true + @grep -n MAYBE *.go || true diff --git a/Godeps/_workspace/src/github.com/cznic/ql/driver/all_test.go b/Godeps/_workspace/src/github.com/cznic/ql/driver/all_test.go new file mode 100644 index 0000000..db28d1d --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/ql/driver/all_test.go @@ -0,0 +1,202 @@ +// Copyright 2014 The ql 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 driver + +import ( + "database/sql" + "fmt" + "io/ioutil" + "os" + "path/filepath" +) + +func Example_testFile() { + dir, err := ioutil.TempDir("", "ql-driver-test") + if err != nil { + return + } + + defer func() { + os.RemoveAll(dir) + }() + + db, err := sql.Open("ql", filepath.Join(dir, "ql.db")) + if err != nil { + return + } + + defer func() { + if err := db.Close(); err != nil { + return + } + + fmt.Println("OK") + }() + + tx, err := db.Begin() + if err != nil { + return + } + + if _, err := tx.Exec("CREATE TABLE t (Qty int, Name string);"); err != nil { + return + } + + result, err := tx.Exec(` + INSERT INTO t VALUES + ($1, $2), + ($3, $4), + ; + `, + 42, "foo", + 314, "bar", + ) + if err != nil { + return + } + + if err = tx.Commit(); err != nil { + return + } + + id, err := result.LastInsertId() + if err != nil { + return + } + + aff, err := result.RowsAffected() + if err != nil { + return + } + + fmt.Printf("LastInsertId %d, RowsAffected %d\n", id, aff) + + rows, err := db.Query("SELECT * FROM t;") + if err != nil { + return + } + + cols, err := rows.Columns() + if err != nil { + return + } + + fmt.Printf("Columns: %v\n", cols) + + var data struct { + Qty int + Name string + } + + for rows.Next() { + if err = rows.Scan(&data.Qty, &data.Name); err != nil { + rows.Close() + break + } + + fmt.Printf("%+v\n", data) + } + + if err = rows.Err(); err != nil { + return + } + + // Output: + // LastInsertId 2, RowsAffected 2 + // Columns: [Qty Name] + // {Qty:314 Name:bar} + // {Qty:42 Name:foo} + // OK +} + +func Example_testMem() { + db, err := sql.Open("ql-mem", "mem.db") + if err != nil { + return + } + + defer func() { + if err := db.Close(); err != nil { + return + } + + fmt.Println("OK") + }() + + tx, err := db.Begin() + if err != nil { + return + } + + if _, err := tx.Exec("CREATE TABLE t (Qty int, Name string);"); err != nil { + return + } + + result, err := tx.Exec(` + INSERT INTO t VALUES + ($1, $2), + ($3, $4), + ; + `, + 1042, "foo-mem", + 1314, "bar-mem", + ) + if err != nil { + return + } + + if err = tx.Commit(); err != nil { + return + } + + id, err := result.LastInsertId() + if err != nil { + return + } + + aff, err := result.RowsAffected() + if err != nil { + return + } + + fmt.Printf("LastInsertId %d, RowsAffected %d\n", id, aff) + + rows, err := db.Query("SELECT * FROM t;") + if err != nil { + return + } + + cols, err := rows.Columns() + if err != nil { + return + } + + fmt.Printf("Columns: %v\n", cols) + + var data struct { + Qty int + Name string + } + + for rows.Next() { + if err = rows.Scan(&data.Qty, &data.Name); err != nil { + rows.Close() + break + } + + fmt.Printf("%+v\n", data) + } + + if err = rows.Err(); err != nil { + return + } + + // Output: + // LastInsertId 2, RowsAffected 2 + // Columns: [Qty Name] + // {Qty:1314 Name:bar-mem} + // {Qty:1042 Name:foo-mem} + // OK +} diff --git a/Godeps/_workspace/src/github.com/cznic/ql/driver/driver.go b/Godeps/_workspace/src/github.com/cznic/ql/driver/driver.go new file mode 100644 index 0000000..5e4a2f4 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/ql/driver/driver.go @@ -0,0 +1,61 @@ +// Copyright 2014 The ql 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 driver registers a QL sql/driver named "ql" and a memory driver named "ql-mem". + +See also [0], [1] and [3]. + +Usage + +A skeleton program using ql/driver. + + package main + + import ( + "database/sql" + + _ "github.com/cznic/ql/driver" + ) + + func main() { + ... + // Disk file DB + db, err := sql.Open("ql", "ql.db") // [2] + // alternatively + db, err := sql.Open("ql", "file://ql.db") + + // and/or + + // RAM DB + mdb, err := sql.Open("ql-mem", "mem.db") + // alternatively + mdb, err := sql.Open("ql", "memory://mem.db") + if err != nil { + log.Fatal(err) + } + + // Use db/mdb here + ... + } + +This package exports nothing. + +Links + +Referenced from above: + + [0]: http://godoc.org/github.com/cznic/ql + [1]: http://golang.org/pkg/database/sql/ + [2]: http://golang.org/pkg/database/sql/#Open + [3]: http://golang.org/pkg/database/sql/driver +*/ +package driver + +import "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/ql" + +func init() { + ql.RegisterDriver() + ql.RegisterMemDriver() +} diff --git a/Godeps/_workspace/src/github.com/cznic/ql/errors.go b/Godeps/_workspace/src/github.com/cznic/ql/errors.go new file mode 100644 index 0000000..305414f --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/ql/errors.go @@ -0,0 +1,18 @@ +// Copyright 2014 The ql 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 ql + +import ( + "errors" +) + +var ( + errBeginTransNoCtx = errors.New("BEGIN TRANSACTION: Must use R/W context, have nil") + errCommitNotInTransaction = errors.New("COMMIT: Not in transaction") + errDivByZero = errors.New("division by zero") + errIncompatibleDBFormat = errors.New("incompatible DB format") + errNoDataForHandle = errors.New("read: no data for handle") + errRollbackNotInTransaction = errors.New("ROLLBACK: Not in transaction") +) diff --git a/Godeps/_workspace/src/github.com/cznic/ql/etc.go b/Godeps/_workspace/src/github.com/cznic/ql/etc.go new file mode 100644 index 0000000..7ac74bb --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/ql/etc.go @@ -0,0 +1,2798 @@ +// Copyright 2014 The ql 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 ql + +import ( + "bytes" + "fmt" + "io" + "log" + "math" + "math/big" + "strings" + "time" +) + +// QL types. +const ( + qBool = 0x62 // 'b' + qComplex64 = 0x63 // 'c' + qComplex128 = 0x64 // 'd' + qFloat32 = 0x66 // 'f' + qFloat64 = 0x67 // 'g', alias float + qInt8 = 0x69 // 'i' + qInt16 = 0x6a // 'j' + qInt32 = 0x6b // 'k' + qInt64 = 0x6c // 'l', alias int + qString = 0x73 // 's' + qUint8 = 0x75 // 'u', alias byte + qUint16 = 0x76 // 'v' + qUint32 = 0x77 // 'w' + qUint64 = 0x78 // 'x', alias uint + + qBigInt = 0x49 // 'I' + qBigRat = 0x52 // 'R' + qBlob = 0x42 // 'B' + qDuration = 0x44 // 'D' + qTime = 0x54 // 'T' +) + +var ( + type2Str = map[int]string{ + qBigInt: "bigint", + qBigRat: "bigrat", + qBlob: "blob", + qBool: "bool", + qComplex128: "complex128", + qComplex64: "complex64", + qDuration: "duration", + qFloat32: "float32", + qFloat64: "float64", + qInt16: "int16", + qInt32: "int32", + qInt64: "int64", + qInt8: "int8", + qString: "string", + qTime: "time", + qUint16: "uint16", + qUint32: "uint32", + qUint64: "uint64", + qUint8: "uint8", + } +) + +func typeStr(typ int) (r string) { + return type2Str[typ] +} + +func noEOF(err error) error { + if err == io.EOF { + err = nil + } + return err +} + +func runErr(err error) error { return fmt.Errorf("run time error: %s", err) } + +func invXOp(s, x interface{}) error { + return fmt.Errorf("invalid operation: %v[%v] (index of type %T)", s, x, x) +} + +func invSOp(s interface{}) error { + return fmt.Errorf("cannot slice %s (type %T)", s, s) +} + +func invNegX(x interface{}) error { + return fmt.Errorf("invalid string index %v (index must be non-negative)", x) +} + +func invNegLO(x interface{}) error { + return fmt.Errorf("invalid LIMIT or OFFSET value %v (must be non-negative)", x) +} + +func invSliceNegX(x interface{}) error { + return fmt.Errorf("invalid slice index %v (index must be non-negative)", x) +} + +func invBoundX(s string, x uint64) error { + return fmt.Errorf("invalid string index %d (out of bounds for %d-byte string)", x, len(s)) +} + +func invSliceBoundX(s string, x uint64) error { + return fmt.Errorf("invalid slice index %d (out of bounds for %d-byte string)", x, len(s)) +} + +func intExpr(x interface{}) (i int64, err error) { + switch x := x.(type) { + case idealInt: + if x < 0 { + return 0, invNegLO(x) + } + + return int64(x), nil + case idealRune: + if x < 0 { + return 0, invNegLO(x) + } + + return int64(x), nil + case idealUint: + if x < 0 { + return 0, invNegLO(x) + } + + return int64(x), nil + case int8: + if x < 0 { + return 0, invNegLO(x) + } + + return int64(x), nil + case int16: + if x < 0 { + return 0, invNegLO(x) + } + + return int64(x), nil + case int32: + if x < 0 { + return 0, invNegLO(x) + } + + return int64(x), nil + case int64: + if x < 0 { + return 0, invNegLO(x) + } + + return int64(x), nil + case uint8: + return int64(x), nil + case uint16: + return int64(x), nil + case uint32: + return int64(x), nil + case uint64: + return int64(x), nil + default: + return 0, fmt.Errorf("non-integer expression: %v (value of type %T)", x, x) + } +} + +func limOffExpr(x interface{}) (i uint64, err error) { + switch x := x.(type) { + case idealInt: + if x < 0 { + return 0, invNegLO(x) + } + + return uint64(x), nil + case idealRune: + if x < 0 { + return 0, invNegLO(x) + } + + return uint64(x), nil + case idealUint: + if x < 0 { + return 0, invNegLO(x) + } + + return uint64(x), nil + case int8: + if x < 0 { + return 0, invNegLO(x) + } + + return uint64(x), nil + case int16: + if x < 0 { + return 0, invNegLO(x) + } + + return uint64(x), nil + case int32: + if x < 0 { + return 0, invNegLO(x) + } + + return uint64(x), nil + case int64: + if x < 0 { + return 0, invNegLO(x) + } + + return uint64(x), nil + case uint8: + return uint64(x), nil + case uint16: + return uint64(x), nil + case uint32: + return uint64(x), nil + case uint64: + return uint64(x), nil + default: + return 0, fmt.Errorf("non-integer used in LIMIT or OFFSET: %v (value of type %T)", x, x) + } +} + +func indexExpr(s *string, x interface{}) (i uint64, err error) { + switch x := x.(type) { + case idealFloat: + if x < 0 { + return 0, invNegX(x) + } + + if s != nil && int(x) >= len(*s) { + return 0, invBoundX(*s, uint64(x)) + } + + return uint64(x), nil + case idealInt: + if x < 0 { + return 0, invNegX(x) + } + + if s != nil && int64(x) >= int64(len(*s)) { + return 0, invBoundX(*s, uint64(x)) + } + + return uint64(x), nil + case idealRune: + if x < 0 { + return 0, invNegX(x) + } + + if s != nil && int32(x) >= int32(len(*s)) { + return 0, invBoundX(*s, uint64(x)) + } + + return uint64(x), nil + case idealUint: + if x < 0 { + return 0, invNegX(x) + } + + if s != nil && uint64(x) >= uint64(len(*s)) { + return 0, invBoundX(*s, uint64(x)) + } + + return uint64(x), nil + case int8: + if x < 0 { + return 0, invNegX(x) + } + + if s != nil && int(x) >= len(*s) { + return 0, invBoundX(*s, uint64(x)) + } + + return uint64(x), nil + case int16: + if x < 0 { + return 0, invNegX(x) + } + + if s != nil && int(x) >= len(*s) { + return 0, invBoundX(*s, uint64(x)) + } + + return uint64(x), nil + case int32: + if x < 0 { + return 0, invNegX(x) + } + + if s != nil && int(x) >= len(*s) { + return 0, invBoundX(*s, uint64(x)) + } + + return uint64(x), nil + case int64: + if x < 0 { + return 0, invNegX(x) + } + + if s != nil && x >= int64(len(*s)) { + return 0, invBoundX(*s, uint64(x)) + } + + return uint64(x), nil + case uint8: + if s != nil && int(x) >= len(*s) { + return 0, invBoundX(*s, uint64(x)) + } + + return uint64(x), nil + case uint16: + if s != nil && int(x) >= len(*s) { + return 0, invBoundX(*s, uint64(x)) + } + + return uint64(x), nil + case uint32: + if s != nil && x >= uint32(len(*s)) { + return 0, invBoundX(*s, uint64(x)) + } + + return uint64(x), nil + case uint64: + if s != nil && x >= uint64(len(*s)) { + return 0, invBoundX(*s, uint64(x)) + } + + return uint64(x), nil + default: + return 0, fmt.Errorf("non-integer string index %v", x) + } +} + +func sliceExpr(s *string, x interface{}, mod int) (i uint64, err error) { + switch x := x.(type) { + case idealFloat: + if x < 0 { + return 0, invSliceNegX(x) + } + + if s != nil && int(x) >= len(*s)+mod { + return 0, invSliceBoundX(*s, uint64(x)) + } + + return uint64(x), nil + case idealInt: + if x < 0 { + return 0, invSliceNegX(x) + } + + if s != nil && int64(x) >= int64(len(*s)+mod) { + return 0, invSliceBoundX(*s, uint64(x)) + } + + return uint64(x), nil + case idealRune: + if x < 0 { + return 0, invSliceNegX(x) + } + + if s != nil && int32(x) >= int32(len(*s)+mod) { + return 0, invSliceBoundX(*s, uint64(x)) + } + + return uint64(x), nil + case idealUint: + if x < 0 { + return 0, invSliceNegX(x) + } + + if s != nil && uint64(x) >= uint64(len(*s)+mod) { + return 0, invSliceBoundX(*s, uint64(x)) + } + + return uint64(x), nil + case int8: + if x < 0 { + return 0, invSliceNegX(x) + } + + if s != nil && int(x) >= len(*s)+mod { + return 0, invSliceBoundX(*s, uint64(x)) + } + + return uint64(x), nil + case int16: + if x < 0 { + return 0, invSliceNegX(x) + } + + if s != nil && int(x) >= len(*s)+mod { + return 0, invSliceBoundX(*s, uint64(x)) + } + + return uint64(x), nil + case int32: + if x < 0 { + return 0, invSliceNegX(x) + } + + if s != nil && int(x) >= len(*s)+mod { + return 0, invSliceBoundX(*s, uint64(x)) + } + + return uint64(x), nil + case int64: + if x < 0 { + return 0, invSliceNegX(x) + } + + if s != nil && x >= int64(len(*s)+mod) { + return 0, invSliceBoundX(*s, uint64(x)) + } + + return uint64(x), nil + case uint8: + if s != nil && int(x) >= len(*s)+mod { + return 0, invSliceBoundX(*s, uint64(x)) + } + + return uint64(x), nil + case uint16: + if s != nil && int(x) >= len(*s)+mod { + return 0, invSliceBoundX(*s, uint64(x)) + } + + return uint64(x), nil + case uint32: + if s != nil && x >= uint32(len(*s)+mod) { + return 0, invSliceBoundX(*s, uint64(x)) + } + + return uint64(x), nil + case uint64: + if s != nil && x >= uint64(len(*s)+mod) { + return 0, invSliceBoundX(*s, uint64(x)) + } + + return uint64(x), nil + default: + return 0, fmt.Errorf("invalid slice index %s (type %T)", x, x) + } +} + +type iop int + +func (o iop) String() string { + switch i := int(o); i { + case andand: + return "&&" + case andnot: + return "&^" + case lsh: + return "<<" + case le: + return "<=" + case eq: + return "==" + case ge: + return ">=" + case neq: + return "!=" + case oror: + return "||" + case rsh: + return ">>" + default: + return string(i) + } +} + +func ideal(v interface{}) interface{} { + switch x := v.(type) { + case idealComplex: + return complex128(x) + case idealFloat: + return float64(x) + case idealInt: + return int64(x) + case idealRune: + return int64(x) + case idealUint: + return uint64(x) + default: + return v + } +} + +func eval(v expression, execCtx *execCtx, ctx map[interface{}]interface{}, arg []interface{}) (y interface{}) { + y, err := expand1(v.eval(execCtx, ctx, arg)) + if err != nil { + panic(err) // panic ok here + } + return +} + +func eval2(a, b expression, execCtx *execCtx, ctx map[interface{}]interface{}, arg []interface{}) (x, y interface{}) { + return eval(a, execCtx, ctx, arg), eval(b, execCtx, ctx, arg) +} + +func invOp2(x, y interface{}, o int) (interface{}, error) { + return nil, fmt.Errorf("invalid operation: %v %v %v (mismatched types %T and %T)", x, iop(o), y, ideal(x), ideal(y)) +} + +func undOp(x interface{}, o int) (interface{}, error) { + return nil, fmt.Errorf("invalid operation: %v%v (operator %v not defined on %T)", iop(o), x, iop(o), x) +} + +func undOp2(x, y interface{}, o int) (interface{}, error) { + return nil, fmt.Errorf("invalid operation: %v %v %v (operator %v not defined on %T)", x, iop(o), y, iop(o), x) +} + +func invConv(val interface{}, typ int) (interface{}, error) { + return nil, fmt.Errorf("cannot convert %v (type %T) to type %s", val, val, typeStr(typ)) +} + +func truncConv(val interface{}) (interface{}, error) { + return nil, fmt.Errorf("constant %v truncated to integer", val) +} + +func convert(val interface{}, typ int) (v interface{}, err error) { //NTYPE + if val == nil { + return nil, nil + } + + switch typ { + case qBool: + switch x := val.(type) { + //case nil: + //case idealComplex: + //case idealFloat: + //case idealInt: + //case idealRune: + //case idealUint: + case bool: + return bool(x), nil + //case complex64: + //case complex128: + //case float32: + //case float64: + //case int8: + //case int16: + //case int32: + //case int64: + //case string: + //case uint8: + //case uint16: + //case uint32: + //case uint64: + default: + return invConv(val, typ) + } + case qComplex64: + switch x := val.(type) { + //case nil: + case idealComplex: + return complex64(x), nil + case idealFloat: + return complex(float32(x), 0), nil + case idealInt: + return complex(float32(x), 0), nil + case idealRune: + return complex(float32(x), 0), nil + case idealUint: + return complex(float32(x), 0), nil + //case bool: + case complex64: + return complex64(x), nil + case complex128: + return complex64(x), nil + //case float32: + //case float64: + //case int8: + //case int16: + //case int32: + //case int64: + //case string: + //case uint8: + //case uint16: + //case uint32: + //case uint64: + default: + return invConv(val, typ) + } + case qComplex128: + switch x := val.(type) { + //case nil: + case idealComplex: + return complex128(x), nil + case idealFloat: + return complex(float64(x), 0), nil + case idealInt: + return complex(float64(x), 0), nil + case idealRune: + return complex(float64(x), 0), nil + case idealUint: + return complex(float64(x), 0), nil + //case bool: + case complex64: + return complex128(x), nil + case complex128: + return complex128(x), nil + //case float32: + //case float64: + //case int8: + //case int16: + //case int32: + //case int64: + //case string: + //case uint8: + //case uint16: + //case uint32: + //case uint64: + default: + return invConv(val, typ) + } + case qFloat32: + switch x := val.(type) { + //case nil: + //case idealComplex: + case idealFloat: + return float32(x), nil + case idealInt: + return float32(x), nil + case idealRune: + return float32(x), nil + case idealUint: + return float32(x), nil + //case bool: + //case complex64: + //case complex128: + case float32: + return float32(x), nil + case float64: + return float32(x), nil + case int8: + return float32(x), nil + case int16: + return float32(x), nil + case int32: + return float32(x), nil + case int64: + return float32(x), nil + //case string: + case uint8: + return float32(x), nil + case uint16: + return float32(x), nil + case uint32: + return float32(x), nil + case uint64: + return float32(x), nil + case *big.Int: + v, _ := big.NewRat(1, 1).SetInt(x).Float64() + return float32(v), nil + case *big.Rat: + v, _ := x.Float64() + return float32(v), nil + case time.Duration: + return float32(x), nil + default: + return invConv(val, typ) + } + case qFloat64: + switch x := val.(type) { + //case nil: + //case idealComplex: + case idealFloat: + return float64(x), nil + case idealInt: + return float64(x), nil + case idealRune: + return float64(x), nil + case idealUint: + return float64(x), nil + //case bool: + //case complex64: + //case complex128: + case float32: + return float64(x), nil + case float64: + return float64(x), nil + case int8: + return float64(x), nil + case int16: + return float64(x), nil + case int32: + return float64(x), nil + case int64: + return float64(x), nil + //case string: + case uint8: + return float64(x), nil + case uint16: + return float64(x), nil + case uint32: + return float64(x), nil + case uint64: + return float64(x), nil + case *big.Int: + v, _ := big.NewRat(1, 1).SetInt(x).Float64() + return v, nil + case *big.Rat: + v, _ := x.Float64() + return v, nil + case time.Duration: + return float64(x), nil + default: + return invConv(val, typ) + } + case qInt8: + switch x := val.(type) { + //case nil: + //case idealComplex: + case idealFloat: + if _, frac := math.Modf(float64(x)); frac != 0 { + return truncConv(x) + } + + return int8(x), nil + case idealInt: + return int8(x), nil + case idealRune: + return int8(x), nil + case idealUint: + return int8(x), nil + //case bool: + //case complex64: + //case complex128: + case float32: + return int8(x), nil + case float64: + return int8(x), nil + case int8: + return int8(x), nil + case int16: + return int8(x), nil + case int32: + return int8(x), nil + case int64: + return int8(x), nil + //case string: + case uint8: + return int8(x), nil + case uint16: + return int8(x), nil + case uint32: + return int8(x), nil + case uint64: + return int8(x), nil + case *big.Int: + return int8(x.Int64()), nil + case time.Duration: + return int8(x), nil + default: + return invConv(val, typ) + } + case qInt16: + switch x := val.(type) { + //case nil: + //case idealComplex: + case idealFloat: + if _, frac := math.Modf(float64(x)); frac != 0 { + return truncConv(x) + } + + return int16(x), nil + case idealInt: + return int16(x), nil + case idealRune: + return int16(x), nil + case idealUint: + return int16(x), nil + //case bool: + //case complex64: + //case complex128: + case float32: + return int16(x), nil + case float64: + return int16(x), nil + case int8: + return int16(x), nil + case int16: + return int16(x), nil + case int32: + return int16(x), nil + case int64: + return int16(x), nil + //case string: + case uint8: + return int16(x), nil + case uint16: + return int16(x), nil + case uint32: + return int16(x), nil + case uint64: + return int16(x), nil + case *big.Int: + return int16(x.Int64()), nil + case time.Duration: + return int16(x), nil + default: + return invConv(val, typ) + } + case qInt32: + switch x := val.(type) { + //case nil: + //case idealComplex: + case idealFloat: + if _, frac := math.Modf(float64(x)); frac != 0 { + return truncConv(x) + } + + return int32(x), nil + case idealInt: + return int32(x), nil + case idealRune: + return int32(x), nil + case idealUint: + return int32(x), nil + //case bool: + //case complex64: + //case complex128: + case float32: + return int32(x), nil + case float64: + return int32(x), nil + case int8: + return int32(x), nil + case int16: + return int32(x), nil + case int32: + return int32(x), nil + case int64: + return int32(x), nil + //case string: + case uint8: + return int32(x), nil + case uint16: + return int32(x), nil + case uint32: + return int32(x), nil + case uint64: + return int32(x), nil + case *big.Int: + return int32(x.Int64()), nil + case time.Duration: + return int32(x), nil + default: + return invConv(val, typ) + } + case qInt64: + switch x := val.(type) { + //case nil: + //case idealComplex: + case idealFloat: + if _, frac := math.Modf(float64(x)); frac != 0 { + return truncConv(x) + } + + return int64(x), nil + case idealInt: + return int64(x), nil + case idealRune: + return int64(x), nil + case idealUint: + return int64(x), nil + //case bool: + //case complex64: + //case complex128: + case float32: + return int64(x), nil + case float64: + return int64(x), nil + case int8: + return int64(x), nil + case int16: + return int64(x), nil + case int32: + return int64(x), nil + case int64: + return int64(x), nil + //case string: + case uint8: + return int64(x), nil + case uint16: + return int64(x), nil + case uint32: + return int64(x), nil + case uint64: + return int64(x), nil + case *big.Int: + return x.Int64(), nil + case time.Duration: + return int64(x), nil + default: + return invConv(val, typ) + } + case qString: + switch x := val.(type) { + //case nil: + //case idealComplex: + //case idealFloat: + case idealInt: + return string(x), nil + case idealRune: + return string(x), nil + case idealUint: + return string(x), nil + //case bool: + //case complex64: + //case complex128: + //case float32: + //case float64: + case int8: + return string(x), nil + case int16: + return string(x), nil + case int32: + return string(x), nil + case int64: + return string(x), nil + case string: + return string(x), nil + case uint8: + return string(x), nil + case uint16: + return string(x), nil + case uint32: + return string(x), nil + case uint64: + return string(x), nil + case []byte: + return string(x), nil + case *big.Int: + return x.String(), nil + case time.Time: + return x.String(), nil + case time.Duration: + return x.String(), nil + default: + return invConv(val, typ) + } + case qUint8: + switch x := val.(type) { + //case nil: + //case idealComplex: + case idealFloat: + if _, frac := math.Modf(float64(x)); frac != 0 { + return truncConv(x) + } + + return uint8(x), nil + case idealInt: + return uint8(x), nil + case idealRune: + return uint8(x), nil + case idealUint: + return uint8(x), nil + //case bool: + //case complex64: + //case complex128: + case float32: + return uint8(x), nil + case float64: + return uint8(x), nil + case int8: + return uint8(x), nil + case int16: + return uint8(x), nil + case int32: + return uint8(x), nil + case int64: + return uint8(x), nil + //case string: + case uint8: + return uint8(x), nil + case uint16: + return uint8(x), nil + case uint32: + return uint8(x), nil + case uint64: + return uint8(x), nil + case *big.Int: + return uint8(x.Int64()), nil + case time.Duration: + return uint8(x), nil + default: + return invConv(val, typ) + } + case qUint16: + switch x := val.(type) { + //case nil: + //case idealComplex: + case idealFloat: + if _, frac := math.Modf(float64(x)); frac != 0 { + return truncConv(x) + } + + return uint16(x), nil + case idealInt: + return uint16(x), nil + case idealRune: + return uint16(x), nil + case idealUint: + return uint16(x), nil + //case bool: + //case complex64: + //case complex128: + case float32: + return uint16(x), nil + case float64: + return uint16(x), nil + case int8: + return uint16(x), nil + case int16: + return uint16(x), nil + case int32: + return uint16(x), nil + case int64: + return uint16(x), nil + //case string: + case uint8: + return uint16(x), nil + case uint16: + return uint16(x), nil + case uint32: + return uint16(x), nil + case uint64: + return uint16(x), nil + case *big.Int: + return uint16(x.Int64()), nil + case time.Duration: + return uint16(x), nil + default: + return invConv(val, typ) + } + case qUint32: + switch x := val.(type) { + //case nil: + //case idealComplex: + case idealFloat: + if _, frac := math.Modf(float64(x)); frac != 0 { + return truncConv(x) + } + + return uint32(x), nil + case idealInt: + return uint32(x), nil + case idealRune: + return uint32(x), nil + case idealUint: + return uint32(x), nil + //case bool: + //case complex64: + //case complex128: + case float32: + return uint32(x), nil + case float64: + return uint32(x), nil + case int8: + return uint32(x), nil + case int16: + return uint32(x), nil + case int32: + return uint32(x), nil + case int64: + return uint32(x), nil + //case string: + case uint8: + return uint32(x), nil + case uint16: + return uint32(x), nil + case uint32: + return uint32(x), nil + case uint64: + return uint32(x), nil + case *big.Int: + return uint32(x.Int64()), nil + case time.Duration: + return uint32(x), nil + default: + return invConv(val, typ) + } + case qUint64: + switch x := val.(type) { + //case nil: + //case idealComplex: + case idealFloat: + if _, frac := math.Modf(float64(x)); frac != 0 { + return truncConv(x) + } + + return uint64(x), nil + case idealInt: + return uint64(x), nil + case idealRune: + return uint64(x), nil + case idealUint: + return uint64(x), nil + //case bool: + //case complex64: + //case complex128: + case float32: + return uint64(x), nil + case float64: + return uint64(x), nil + case int8: + return uint64(x), nil + case int16: + return uint64(x), nil + case int32: + return uint64(x), nil + case int64: + return uint64(x), nil + //case string: + case uint8: + return uint64(x), nil + case uint16: + return uint64(x), nil + case uint32: + return uint64(x), nil + case uint64: + return uint64(x), nil + case *big.Int: + return x.Uint64(), nil + case time.Duration: + return uint64(x), nil + default: + return invConv(val, typ) + } + case qBlob: + switch x := val.(type) { + case string: + return []byte(x), nil + case []byte: + return x, nil + default: + return invConv(val, typ) + } + case qBigInt: + switch x := val.(type) { + // case blob + // case bool + //case idealComplex: + case idealFloat: + if _, frac := math.Modf(float64(x)); frac != 0 { + return truncConv(x) + } + + rr := big.NewRat(1, 1).SetFloat64(float64(x)) + ii := big.NewInt(0).Set(rr.Num()) + ii.Quo(ii, rr.Denom()) + return ii, nil + case idealInt: + return big.NewInt(0).SetInt64(int64(x)), nil + case idealRune: + return big.NewInt(0).SetInt64(int64(x)), nil + case idealUint: + return big.NewInt(0).SetUint64(uint64(x)), nil + //case complex64 + //case complex128 + case float32: + rr := big.NewRat(1, 1).SetFloat64(float64(x)) + ii := big.NewInt(0).Set(rr.Num()) + ii.Quo(ii, rr.Denom()) + return ii, nil + case float64: + rr := big.NewRat(1, 1).SetFloat64(float64(x)) + ii := big.NewInt(0).Set(rr.Num()) + ii.Quo(ii, rr.Denom()) + return ii, nil + case int8: + return big.NewInt(0).SetInt64(int64(x)), nil + case int16: + return big.NewInt(0).SetInt64(int64(x)), nil + case int32: + return big.NewInt(0).SetInt64(int64(x)), nil + case int64: + return big.NewInt(0).SetInt64(x), nil + case string: + y := big.NewInt(0) + if _, ok := y.SetString(x, 0); !ok { + return invConv(val, typ) + } + + return y, nil + case uint8: + return big.NewInt(0).SetUint64(uint64(x)), nil + case uint16: + return big.NewInt(0).SetUint64(uint64(x)), nil + case uint32: + return big.NewInt(0).SetUint64(uint64(x)), nil + case uint64: + return big.NewInt(0).SetUint64(x), nil + case *big.Int: + return x, nil + case *big.Rat: + ii := big.NewInt(0).Set(x.Num()) + ii.Div(ii, x.Denom()) + return ii, nil + default: + return invConv(val, typ) + } + case qBigRat: + switch x := val.(type) { + // case blob + // case bool + //case idealComplex: + case idealFloat: + return big.NewRat(1, 1).SetFloat64(float64(x)), nil + case idealInt: + return big.NewRat(1, 1).SetInt64(int64(x)), nil + case idealRune: + return big.NewRat(1, 1).SetInt64(int64(x)), nil + case idealUint: + return big.NewRat(1, 1).SetInt(big.NewInt(0).SetUint64(uint64(x))), nil + //case complex64 + //case complex128 + case float32: + return big.NewRat(1, 1).SetFloat64(float64(x)), nil + case float64: + return big.NewRat(1, 1).SetFloat64(x), nil + case int8: + return big.NewRat(1, 1).SetInt64(int64(x)), nil + case int16: + return big.NewRat(1, 1).SetInt64(int64(x)), nil + case int32: + return big.NewRat(1, 1).SetInt64(int64(x)), nil + case int64: + return big.NewRat(1, 1).SetInt64(x), nil + case string: + y := big.NewRat(1, 1) + if _, ok := y.SetString(x); !ok { + return invConv(val, typ) + } + + return y, nil + case uint8: + return big.NewRat(1, 1).SetInt64(int64(x)), nil + case uint16: + return big.NewRat(1, 1).SetInt64(int64(x)), nil + case uint32: + return big.NewRat(1, 1).SetInt64(int64(x)), nil + case uint64: + return big.NewRat(1, 1).SetInt(big.NewInt(0).SetUint64(x)), nil + case *big.Int: + return big.NewRat(1, 1).SetInt(x), nil + case *big.Rat: + return x, nil + default: + return invConv(val, typ) + } + case qDuration: + switch x := val.(type) { + // case blob + // case bool + //case idealComplex: + case idealFloat: + return time.Duration(x), nil + case idealInt: + return time.Duration(x), nil + case idealRune: + return time.Duration(x), nil + case idealUint: + return time.Duration(x), nil + //case complex64 + //case complex128 + case float32: + return time.Duration(x), nil + case float64: + return time.Duration(x), nil + case int8: + return time.Duration(x), nil + case int16: + return time.Duration(x), nil + case int32: + return time.Duration(x), nil + case int64: + return time.Duration(x), nil + case string: + return time.ParseDuration(x) + case uint8: + return time.Duration(x), nil + case uint16: + return time.Duration(x), nil + case uint32: + return time.Duration(x), nil + case uint64: + return time.Duration(x), nil + case *big.Int: + return time.Duration(x.Int64()), nil + case *big.Rat: + f, _ := x.Float64() + return time.Duration(f), nil + case time.Duration: + return x, nil + default: + return invConv(val, typ) + } + case qTime: + switch x := val.(type) { + // case blob + // case bool + //case idealComplex: + //case idealFloat: + //case idealInt: + //case idealRune: + //case idealUint: + //case complex64 + //case complex128 + //case float32: + //case float64: + //case int8: + //case int16: + //case int32: + //case int64: + //case string: + //case uint8: + //case uint16: + //case uint32: + //case uint64: + //case *big.Int: + //case *big.Rat: + //case time.Duration: + case time.Time: + return x, nil + default: + return invConv(val, typ) + } + default: + log.Panic("internal error 006") + } + //dbg("%T(%v) %s", val, val, typeStr(typ)) + panic("unreachable") +} + +func invShiftRHS(lhs, rhs interface{}) (interface{}, error) { + return nil, fmt.Errorf("invalid operation: %v << %v (shift count type %T, must be unsigned integer)", lhs, rhs, rhs) +} + +func invTruncInt(v interface{}) error { + return fmt.Errorf("constant %v truncated to integer", v) +} + +func overflow(v interface{}, typ int) error { + return fmt.Errorf("constant %v overflows %s", v, typeStr(typ)) +} + +func typeCheck(rec []interface{}, cols []*col) (err error) { + for _, c := range cols { + i := c.index + if v := rec[i]; !c.typeCheck(v) { + switch v.(type) { + case idealComplex: + y := complex128(v.(idealComplex)) + switch c.typ { + case qBool: + case qComplex64: + rec[i] = complex64(y) + continue + case qComplex128: + rec[i] = complex128(y) + continue + case qFloat32, qFloat64, qInt8, qInt16, qInt32, qInt64, qUint8, qUint16, qUint32, qUint64: + return fmt.Errorf("constant %v truncated to real", y) + case qString: + default: + log.Panic("internal error 007") + } + case idealFloat: + y := float64(v.(idealFloat)) + switch c.typ { + case qBool: + case qComplex64: + rec[i] = complex(float32(y), 0) + continue + case qComplex128: + rec[i] = complex(float64(y), 0) + continue + case qFloat32: + rec[i] = float32(y) + continue + case qFloat64: + rec[i] = float64(y) + continue + case qInt8: + if math.Floor(y) != y { + return invTruncInt(y) + } + + if y < math.MinInt8 || y > math.MaxInt8 { + return overflow(y, c.typ) + } + + rec[i] = int8(y) + continue + case qInt16: + if math.Floor(y) != y { + return invTruncInt(y) + } + + if y < math.MinInt16 || y > math.MaxInt16 { + return overflow(y, c.typ) + } + + rec[i] = int16(y) + continue + case qInt32: + if math.Floor(y) != y { + return invTruncInt(y) + } + + if y < math.MinInt32 || y > math.MaxInt32 { + return overflow(y, c.typ) + } + + rec[i] = int32(y) + continue + case qInt64: + if math.Floor(y) != y { + return invTruncInt(y) + } + + if y < math.MinInt64 || y > math.MaxInt64 { + return overflow(y, c.typ) + } + + rec[i] = int64(y) + continue + case qString: + case qUint8: + if math.Floor(y) != y { + return invTruncInt(y) + } + + if y < 0 || y > math.MaxUint8 { + return overflow(y, c.typ) + } + + rec[i] = uint8(y) + continue + case qUint16: + if math.Floor(y) != y { + return invTruncInt(y) + } + + if y < 0 || y > math.MaxUint16 { + return overflow(y, c.typ) + } + + rec[i] = uint16(y) + continue + case qUint32: + if math.Floor(y) != y { + return invTruncInt(y) + } + + if y < 0 || y > math.MaxUint32 { + return overflow(y, c.typ) + } + + rec[i] = uint32(y) + continue + case qUint64: + if math.Floor(y) != y { + return invTruncInt(y) + } + + if y < 0 || y > math.MaxUint64 { + return overflow(y, c.typ) + } + + rec[i] = uint64(y) + continue + case qBigInt: + if math.Floor(y) != y { + return invTruncInt(y) + } + + rr := big.NewRat(1, 1).SetFloat64(y) + ii := big.NewInt(0) + ii.Set(rr.Num()) + ii.Quo(ii, rr.Denom()) + rec[i] = ii + continue + case qBigRat: + rec[i] = big.NewRat(1, 1).SetFloat64(y) + continue + default: + log.Panic("internal error 008") + } + case idealInt: + y := int64(v.(idealInt)) + switch c.typ { + case qBool: + case qComplex64: + rec[i] = complex(float32(y), 0) + continue + case qComplex128: + rec[i] = complex(float64(y), 0) + continue + case qFloat32: + rec[i] = float32(y) + continue + case qFloat64: + rec[i] = float64(y) + continue + case qInt8: + if y < math.MinInt8 || y > math.MaxInt8 { + return overflow(y, c.typ) + } + + rec[i] = int8(y) + continue + case qInt16: + if y < math.MinInt16 || y > math.MaxInt16 { + return overflow(y, c.typ) + } + + rec[i] = int16(y) + continue + case qInt32: + if y < math.MinInt32 || y > math.MaxInt32 { + return overflow(y, c.typ) + } + + rec[i] = int32(y) + continue + case qInt64: + if y < math.MinInt64 || y > math.MaxInt64 { + return overflow(y, c.typ) + } + + rec[i] = int64(y) + continue + case qString: + case qUint8: + if y < 0 || y > math.MaxUint8 { + return overflow(y, c.typ) + } + + rec[i] = uint8(y) + continue + case qUint16: + if y < 0 || y > math.MaxUint16 { + return overflow(y, c.typ) + } + + rec[i] = uint16(y) + continue + case qUint32: + if y < 0 || y > math.MaxUint32 { + return overflow(y, c.typ) + } + + rec[i] = uint32(y) + continue + case qUint64: + if y < 0 { + return overflow(y, c.typ) + } + + rec[i] = uint64(y) + continue + case qBigInt: + rec[i] = big.NewInt(y) + continue + case qBigRat: + rec[i] = big.NewRat(1, 1).SetInt64(y) + continue + default: + log.Panic("internal error 009") + } + case idealRune: + y := int64(v.(idealRune)) + switch c.typ { + case qBool: + case qComplex64: + rec[i] = complex(float32(y), 0) + continue + case qComplex128: + rec[i] = complex(float64(y), 0) + continue + case qFloat32: + rec[i] = float32(y) + continue + case qFloat64: + rec[i] = float64(y) + continue + case qInt8: + if y < math.MinInt8 || y > math.MaxInt8 { + return overflow(y, c.typ) + } + + rec[i] = int8(y) + continue + case qInt16: + if y < math.MinInt16 || y > math.MaxInt16 { + return overflow(y, c.typ) + } + + rec[i] = int16(y) + continue + case qInt32: + if y < math.MinInt32 || y > math.MaxInt32 { + return overflow(y, c.typ) + } + + rec[i] = int32(y) + continue + case qInt64: + if y < math.MinInt64 || y > math.MaxInt64 { + return overflow(y, c.typ) + } + + rec[i] = int64(y) + continue + case qString: + case qUint8: + if y < 0 || y > math.MaxUint8 { + return overflow(y, c.typ) + } + + rec[i] = uint8(y) + continue + case qUint16: + if y < 0 || y > math.MaxUint16 { + return overflow(y, c.typ) + } + + rec[i] = uint16(y) + continue + case qUint32: + if y < 0 { + return overflow(y, c.typ) + } + + rec[i] = uint32(y) + continue + case qUint64: + if y < 0 { + return overflow(y, c.typ) + } + + rec[i] = uint64(y) + continue + case qBigInt: + rec[i] = big.NewInt(y) + continue + case qBigRat: + rec[i] = big.NewRat(1, 1).SetInt64(y) + continue + default: + log.Panic("internal error 010") + } + case idealUint: + y := uint64(v.(idealUint)) + switch c.typ { + case qBool: + case qComplex64: + rec[i] = complex(float32(y), 0) + continue + case qComplex128: + rec[i] = complex(float64(y), 0) + continue + case qFloat32: + rec[i] = float32(y) + continue + case qFloat64: + rec[i] = float64(y) + continue + case qInt8: + if y > math.MaxInt8 { + return overflow(y, c.typ) + } + + rec[i] = int8(y) + continue + case qInt16: + if y > math.MaxInt16 { + return overflow(y, c.typ) + } + + rec[i] = int16(y) + continue + case qInt32: + if y > math.MaxInt32 { + return overflow(y, c.typ) + } + + rec[i] = int32(y) + continue + case qInt64: + if y > math.MaxInt64 { + return overflow(y, c.typ) + } + + rec[i] = int64(y) + continue + case qString: + rec[i] = string(y) + continue + case qUint8: + if y > math.MaxUint8 { + return overflow(y, c.typ) + } + + rec[i] = uint8(y) + continue + case qUint16: + if y > math.MaxUint16 { + return overflow(y, c.typ) + } + + rec[i] = uint16(y) + continue + case qUint32: + if y > math.MaxUint32 { + return overflow(y, c.typ) + } + + rec[i] = uint32(y) + continue + case qUint64: + rec[i] = uint64(y) + continue + case qBigInt: + rec[i] = big.NewInt(0).SetUint64(y) + continue + case qBigRat: + ii := big.NewInt(0).SetUint64(y) + rec[i] = big.NewRat(1, 1).SetInt(ii) + continue + default: + log.Panic("internal error 011") + } + } + //dbg("v %T(%v), typ %s", v, v, typeStr(c.typ)) + return fmt.Errorf("cannot use %v (type %T) as %s in assignment/comparison to/with column %s", v, ideal(v), typeStr(c.typ), c.name) + } + } + return +} + +//TODO collate1 should return errors instead of panicing +func collate1(a, b interface{}) int { + switch x := a.(type) { + case nil: + if b != nil { + return -1 + } + + return 0 + case bool: + switch y := b.(type) { + case nil: + return 1 + case bool: + if !x && y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + default: + // Make bool collate before anything except nil and + // other bool for index seeking first non NULL value. + return -1 + } + case idealComplex: + switch y := b.(type) { + case nil: + return 1 + case idealComplex: + if x == y { + return 0 + } + + if real(x) < real(y) { + return -1 + } + + if real(x) > real(y) { + return 1 + } + + if imag(x) < imag(y) { + return -1 + } + + return 1 + case complex64: + { + x, y := complex64(x), complex64(y) + if x == y { + return 0 + } + + if real(x) < real(y) { + return -1 + } + + if real(x) > real(y) { + return 1 + } + + if imag(x) < imag(y) { + return -1 + } + + return 1 + } + case complex128: + { + x := complex128(x) + if x == y { + return 0 + } + + if real(x) < real(y) { + return -1 + } + + if real(x) > real(y) { + return 1 + } + + if imag(x) < imag(y) { + return -1 + } + + return 1 + } + default: + panic("internal error 012") + } + case idealUint: + switch y := b.(type) { + case nil: + return 1 + case idealUint: + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + case uint8: + { + x, y := uint64(x), uint64(y) + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + } + case uint16: + { + x, y := uint64(x), uint64(y) + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + } + case uint32: + { + x, y := uint64(x), uint64(y) + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + } + case uint64: + { + x, y := uint64(x), uint64(y) + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + } + case uint: + { + x, y := uint64(x), uint64(y) + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + } + default: + panic("internal error 013") + } + case idealRune: + switch y := b.(type) { + case nil: + return 1 + case idealRune: + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + case int8: + { + x, y := int64(x), int64(y) + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + } + case int16: + { + x, y := int64(x), int64(y) + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + } + case int32: + { + x, y := int64(x), int64(y) + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + } + case int64: + { + x, y := int64(x), int64(y) + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + } + case int: + { + x, y := int64(x), int64(y) + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + } + default: + panic("internal error 014") + } + case idealInt: + switch y := b.(type) { + case nil: + return 1 + case idealInt: + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + case int8: + { + x, y := int64(x), int64(y) + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + } + case int16: + { + x, y := int64(x), int64(y) + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + } + case int32: + { + x, y := int64(x), int64(y) + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + } + case int64: + { + x, y := int64(x), int64(y) + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + } + case int: + { + x, y := int64(x), int64(y) + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + } + default: + panic("internal error 015") + } + case idealFloat: + switch y := b.(type) { + case nil: + return 1 + case idealFloat: + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + case float32: + { + x, y := float64(x), float64(y) + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + } + case float64: + { + x, y := float64(x), float64(y) + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + } + default: + panic("internal error 016") + } + case complex64: + switch y := b.(type) { + case nil: + return 1 + case complex64: + if x == y { + return 0 + } + + if real(x) < real(y) { + return -1 + } + + if real(x) > real(y) { + return 1 + } + + if imag(x) < imag(y) { + return -1 + } + + return 1 + case idealComplex: + { + x, y := complex64(x), complex64(y) + if x == y { + return 0 + } + + if real(x) < real(y) { + return -1 + } + + if real(x) > real(y) { + return 1 + } + + if imag(x) < imag(y) { + return -1 + } + + return 1 + } + default: + panic("internal error 017") + } + case complex128: + switch y := b.(type) { + case nil: + return 1 + case complex128: + if x == y { + return 0 + } + + if real(x) < real(y) { + return -1 + } + + if real(x) > real(y) { + return 1 + } + + if imag(x) < imag(y) { + return -1 + } + + return 1 + case idealComplex: + { + x, y := complex128(x), complex128(y) + if x == y { + return 0 + } + + if real(x) < real(y) { + return -1 + } + + if real(x) > real(y) { + return 1 + } + + if imag(x) < imag(y) { + return -1 + } + + return 1 + } + default: + panic("internal error 018") + } + case float32: + switch y := b.(type) { + case nil: + return 1 + case float32: + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + case idealFloat: + { + x, y := float32(x), float32(y) + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + } + default: + panic("internal error 019") + } + case float64: + switch y := b.(type) { + case nil: + return 1 + case float64: + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + case idealFloat: + { + x, y := float64(x), float64(y) + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + } + default: + panic("internal error 020") + } + case int8: + switch y := b.(type) { + case nil: + return 1 + case int8: + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + case idealInt: + { + x, y := int64(x), int64(y) + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + } + default: + panic("internal error 021") + } + case int16: + switch y := b.(type) { + case nil: + return 1 + case int16: + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + case idealInt: + { + x, y := int64(x), int64(y) + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + } + default: + panic("internal error 022") + } + case int32: + switch y := b.(type) { + case nil: + return 1 + case int32: + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + case idealInt: + { + x, y := int64(x), int64(y) + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + } + default: + panic("internal error 023") + } + case int64: + switch y := b.(type) { + case nil: + return 1 + case int64: + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + case idealInt: + { + x, y := int64(x), int64(y) + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + } + default: + //dbg("%T(%#v)", b, b) + panic("internal error 024") + } + case uint8: + switch y := b.(type) { + case nil: + return 1 + case uint8: + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + case idealInt: + { + x, y := uint64(x), uint64(y) + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + } + case idealUint: + { + x, y := uint64(x), uint64(y) + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + } + default: + panic("internal error 025") + } + case uint16: + switch y := b.(type) { + case nil: + return 1 + case uint16: + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + case idealInt: + { + x, y := uint64(x), uint64(y) + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + } + case idealUint: + { + x, y := uint64(x), uint64(y) + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + } + default: + panic("internal error 026") + } + case uint32: + switch y := b.(type) { + case nil: + return 1 + case uint32: + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + case idealInt: + { + x, y := uint64(x), uint64(y) + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + } + case idealUint: + { + x, y := uint64(x), uint64(y) + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + } + default: + panic("internal error 027") + } + case uint64: + switch y := b.(type) { + case nil: + return 1 + case uint64: + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + case idealInt: + { + x, y := uint64(x), uint64(y) + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + } + case idealUint: + { + x, y := uint64(x), uint64(y) + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + } + default: + panic("internal error 028") + } + case string: + switch y := b.(type) { + case nil: + return 1 + case string: + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + default: + panic("internal error 029") + } + case []byte: + switch y := b.(type) { + case nil: + return 1 + case []byte: + return bytes.Compare(x, y) + default: + panic("internal error 030") + } + case *big.Int: + switch y := b.(type) { + case nil: + return 1 + case *big.Int: + return x.Cmp(y) + case idealInt: + { + y := big.NewInt(int64(y)) + return x.Cmp(y) + } + case idealUint: + { + u := big.NewInt(0) + u.SetUint64(uint64(y)) + return x.Cmp(u) + } + default: + panic("internal error 031") + } + case *big.Rat: + switch y := b.(type) { + case nil: + return 1 + case *big.Rat: + return x.Cmp(y) + case idealInt: + { + y := big.NewRat(int64(y), 1) + return x.Cmp(y) + } + case idealUint: + { + u := big.NewInt(0) + u.SetUint64(uint64(y)) + var y big.Rat + y.SetInt(u) + return x.Cmp(&y) + } + default: + panic("internal error 032") + } + case time.Time: + switch y := b.(type) { + case nil: + return 1 + case time.Time: + if x.Before(y) { + return -1 + } + + if x.Equal(y) { + return 0 + } + + return 1 + default: + panic("internal error 033") + } + case time.Duration: + switch y := b.(type) { + case nil: + return 1 + case time.Duration: + if x < y { + return -1 + } + + if x == y { + return 0 + } + + return 1 + default: + panic("internal error 034") + } + case chunk: + switch y := b.(type) { + case nil: + return 1 + case chunk: + a, err := x.expand() + if err != nil { + log.Panic(err) + } + + b, err := y.expand() + if err != nil { + log.Panic(err) + } + + return collate1(a, b) + default: + panic("internal error 035") + } + default: + //dbg("%T(%v) %T(%v)", a, a, b, b) + panic("internal error 036") + } +} + +//TODO collate should return errors from collate1 +func collate(x, y []interface{}) (r int) { + //defer func() { dbg("%v %v -> %v", x, y, r) }() + nx, ny := len(x), len(y) + + switch { + case nx == 0 && ny != 0: + return -1 + case nx == 0 && ny == 0: + return 0 + case nx != 0 && ny == 0: + return 1 + } + + r = 1 + if nx > ny { + x, y, r = y, x, -r + } + + for i, xi := range x { + if c := collate1(xi, y[i]); c != 0 { + return c * r + } + } + + if nx == ny { + return 0 + } + + return -r +} + +var collators = map[bool]func(a, b []interface{}) int{false: collateDesc, true: collate} + +func collateDesc(a, b []interface{}) int { + return -collate(a, b) +} + +func isOrderedType(v interface{}) (y interface{}, r bool, err error) { + //dbg("====") + //dbg("%T(%v)", v, v) + //defer func() { dbg("%T(%v)", y, y) }() + switch x := v.(type) { + case idealFloat, idealInt, idealRune, idealUint, + float32, float64, + int8, int16, int32, int64, + uint8, uint16, uint32, uint64, + string: + return v, true, nil + case *big.Int, *big.Rat, time.Time, time.Duration: + return x, true, nil + case chunk: + if y, err = x.expand(); err != nil { + return + } + + return isOrderedType(y) + } + + return v, false, nil +} + +var isSystemName = map[string]bool{ + "__Column": true, + "__Index": true, + "__Table": true, +} + +func qualifier(s string) string { + if pos := strings.IndexByte(s, '.'); pos >= 0 { + s = s[:pos] + } + return s +} + +func mustQualifier(s string) string { + q := qualifier(s) + if q == s { + panic("internal error 068") + } + + return q +} + +func selector(s string) string { + if pos := strings.IndexByte(s, '.'); pos >= 0 { + s = s[pos+1:] + } + return s +} + +func mustSelector(s string) string { + q := selector(s) + if q == s { + panic("internal error 069") + } + + return q +} diff --git a/Godeps/_workspace/src/github.com/cznic/ql/expr.go b/Godeps/_workspace/src/github.com/cznic/ql/expr.go new file mode 100644 index 0000000..221a85b --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/ql/expr.go @@ -0,0 +1,3653 @@ +// Copyright 2014 The ql Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found pIn the LICENSE file. + +package ql + +import ( + "fmt" + "log" + "math/big" + "regexp" + "strings" + "time" +) + +var ( + _ expression = (*binaryOperation)(nil) + _ expression = (*call)(nil) + _ expression = (*conversion)(nil) + _ expression = (*ident)(nil) + _ expression = (*indexOp)(nil) + _ expression = (*isNull)(nil) + _ expression = (*pIn)(nil) + _ expression = (*pLike)(nil) + _ expression = (*parameter)(nil) + _ expression = (*pexpr)(nil) + _ expression = (*slice)(nil) + _ expression = (*unaryOperation)(nil) + _ expression = value{} +) + +type expression interface { + eval(execCtx *execCtx, ctx map[interface{}]interface{}, arg []interface{}) (v interface{}, err error) + isStatic() bool + String() string +} + +func staticExpr(e expression) (expression, error) { + if e.isStatic() { + v, err := e.eval(nil, nil, nil) + if err != nil { + return nil, err + } + + if v == nil { + return value{nil}, nil + } + + return value{v}, nil + } + + return e, nil +} + +type ( + idealComplex complex128 + idealFloat float64 + idealInt int64 + idealRune int32 + idealUint uint64 +) + +type exprTab struct { + expr expression + table string +} + +func isPossiblyRewriteableCrossJoinWhereExpression(expr expression) (bool, []exprTab) { + //dbg("....\n\texpr %v", expr) + //defer func() { dbg("\t\t%v: %v %v", expr, TODOb, TODOl) }() + switch x := expr.(type) { + case *binaryOperation: + if ok, tab, nx := x.isQIdentRelOpFixedValue(); ok { + return true, []exprTab{{nx, tab}} + } + + if x.op != andand { + return false, nil + } + + ok, rlist := isPossiblyRewriteableCrossJoinWhereExpression(x.r) + if !ok { + return false, nil + } + + ok, llist := isPossiblyRewriteableCrossJoinWhereExpression(x.l) + if !ok { + return false, nil + } + + return true, append(llist, rlist...) + case *ident: + if !x.isQualified() { + return false, nil + } + + return true, []exprTab{{&ident{mustSelector(x.s)}, mustQualifier(x.s)}} + case *unaryOperation: + ok, tab, nx := x.isNotQIdent() + if !ok { + return false, nil + } + + return true, []exprTab{{nx, tab}} + default: + //dbg("%T: %v", x, x) + return false, nil + } +} + +type pexpr struct { + expr expression +} + +func (p *pexpr) isStatic() bool { return p.expr.isStatic() } + +func (p *pexpr) String() string { + return fmt.Sprintf("(%s)", p.expr) +} + +func (p *pexpr) eval(execCtx *execCtx, ctx map[interface{}]interface{}, arg []interface{}) (v interface{}, err error) { + return p.expr.eval(execCtx, ctx, arg) +} + +//DONE newBetween +//LATER like newBetween, check all others have and use new* + +func newBetween(expr, lo, hi interface{}, not bool) (expression, error) { + e, err := staticExpr(expr.(expression)) + if err != nil { + return nil, err + } + + l, err := staticExpr(lo.(expression)) + if err != nil { + return nil, err + } + + h, err := staticExpr(hi.(expression)) + if err != nil { + return nil, err + } + + var a, b expression + op := andand + switch { + case not: // e < l || e > h + op = oror + if a, err = newBinaryOperation('<', e, l); err != nil { + return nil, err + } + + if b, err = newBinaryOperation('>', e, h); err != nil { + return nil, err + } + default: // e >= l && e <= h + if a, err = newBinaryOperation(ge, e, l); err != nil { + return nil, err + } + + if b, err = newBinaryOperation(le, e, h); err != nil { + return nil, err + } + } + + if a, err = staticExpr(a); err != nil { + return nil, err + } + + if b, err = staticExpr(b); err != nil { + return nil, err + } + + ret, err := newBinaryOperation(op, a, b) + if err != nil { + return nil, err + } + + return staticExpr(ret) +} + +type pLike struct { + expr expression + pattern expression + re *regexp.Regexp + sexpr *string +} + +func (p *pLike) isStatic() bool { return p.expr.isStatic() && p.pattern.isStatic() } +func (p *pLike) String() string { return fmt.Sprintf("%q LIKE %q", p.expr, p.pattern) } + +func (p *pLike) eval(execCtx *execCtx, ctx map[interface{}]interface{}, arg []interface{}) (v interface{}, err error) { + var sexpr string + var ok bool + switch { + case p.sexpr != nil: + sexpr = *p.sexpr + default: + expr, err := expand1(p.expr.eval(execCtx, ctx, arg)) + if err != nil { + return nil, err + } + + if expr == nil { + return nil, nil + } + + sexpr, ok = expr.(string) + if !ok { + return nil, fmt.Errorf("non-string expression in LIKE: %v (value of type %T)", expr, expr) + } + + if p.expr.isStatic() { + p.sexpr = new(string) + *p.sexpr = sexpr + } + } + + re := p.re + if re == nil { + pattern, err := expand1(p.pattern.eval(execCtx, ctx, arg)) + if err != nil { + return nil, err + } + + if pattern == nil { + return nil, nil + } + + spattern, ok := pattern.(string) + if !ok { + return nil, fmt.Errorf("non-string pattern in LIKE: %v (value of type %T)", pattern, pattern) + } + + if re, err = regexp.Compile(spattern); err != nil { + return nil, err + } + + if p.pattern.isStatic() { + p.re = re + } + } + + return re.MatchString(sexpr), nil +} + +type binaryOperation struct { + op int + l, r expression +} + +func newBinaryOperation(op int, x, y interface{}) (v expression, err error) { + b := binaryOperation{op, x.(expression), y.(expression)} + //dbg("newBinaryOperation %s", &b) + //defer func() { dbg("newBinaryOperation -> %v, %v", v, err) }() + var lv interface{} + if e := b.l; e.isStatic() { + if lv, err = e.eval(nil, nil, nil); err != nil { + return nil, err + } + + b.l = value{lv} + } + + if e := b.r; e.isStatic() { + v, err := e.eval(nil, nil, nil) + if err != nil { + return nil, err + } + + if v == nil { + return value{nil}, nil + } + + if op == '/' || op == '%' { + rb := binaryOperation{eq, e, value{idealInt(0)}} + val, err := rb.eval(nil, nil, nil) + if err != nil { + return nil, err + } + + if val.(bool) { + return nil, errDivByZero + } + } + + if b.l.isStatic() && lv == nil { + return value{nil}, nil + } + + b.r = value{v} + } + + if !b.isStatic() { + return &b, nil + } + + val, err := b.eval(nil, nil, nil) + return value{val}, err +} + +func (o *binaryOperation) isRelOp() bool { + op := o.op + return op == '<' || op == le || op == eq || op == neq || op == ge || op == '>' +} + +// [!]qident relOp fixedValue or vice versa +func (o *binaryOperation) isQIdentRelOpFixedValue() ( /* ok */ bool /* tableName */, string, expression) { + if !o.isRelOp() { + return false, "", nil + } + + switch lhs := o.l.(type) { + case *unaryOperation: + ok, tab, nx := lhs.isNotQIdent() + if !ok { + return false, "", nil + } + + switch rhs := o.r.(type) { + case *parameter, value: + return true, tab, &binaryOperation{o.op, nx, rhs} + } + case *ident: + if !lhs.isQualified() { + return false, "", nil + } + + switch rhs := o.r.(type) { + case *parameter, value: + return true, mustQualifier(lhs.s), &binaryOperation{o.op, &ident{mustSelector(lhs.s)}, rhs} + } + case *parameter, value: + switch rhs := o.r.(type) { + case *ident: + if !rhs.isQualified() { + return false, "", nil + } + + return true, mustQualifier(rhs.s), &binaryOperation{o.op, lhs, &ident{mustSelector(rhs.s)}} + case *unaryOperation: + ok, tab, nx := rhs.isNotQIdent() + if !ok { + return false, "", nil + } + + return true, tab, &binaryOperation{o.op, lhs, nx} + } + } + return false, "", nil +} + +func (o *binaryOperation) isBoolAnd() bool { return o.op == andand } + +func (o *binaryOperation) isStatic() bool { return o.l.isStatic() && o.r.isStatic() } + +func (o *binaryOperation) String() string { + return fmt.Sprintf("%s%s%s", o.l, iop(o.op), o.r) +} + +func (o *binaryOperation) eval(execCtx *execCtx, ctx map[interface{}]interface{}, arg []interface{}) (r interface{}, err error) { + defer func() { + if e := recover(); e != nil { + switch x := e.(type) { + case error: + r, err = nil, x + default: + r, err = nil, fmt.Errorf("%v", x) + } + } + }() + + switch op := o.op; op { + case andand: + a, err := expand1(o.l.eval(execCtx, ctx, arg)) + if err != nil { + return nil, err + } + + switch x := a.(type) { + case nil: + b, err := expand1(o.r.eval(execCtx, ctx, arg)) + if err != nil { + return nil, err + } + + switch y := b.(type) { + case nil: + return nil, nil + case bool: + if !y { + return false, nil + } + + return nil, nil + default: + return invOp2(x, y, op) + } + case bool: + if !x { + return false, nil + } + + b, err := expand1(o.r.eval(execCtx, ctx, arg)) + if err != nil { + return nil, err + } + + switch y := b.(type) { + case nil: + return nil, nil + case bool: + return y, nil + default: + return invOp2(x, y, op) + } + default: + return undOp(x, op) + } + case oror: + a, err := expand1(o.l.eval(execCtx, ctx, arg)) + if err != nil { + return nil, err + } + + switch x := a.(type) { + case nil: + b, err := expand1(o.r.eval(execCtx, ctx, arg)) + if err != nil { + return nil, err + } + + switch y := b.(type) { + case nil: + return nil, nil + case bool: + if y { + return y, nil + } + + return nil, nil + default: + return invOp2(x, y, op) + } + case bool: + if x { + return x, nil + } + + b, err := expand1(o.r.eval(execCtx, ctx, arg)) + if err != nil { + return nil, err + } + + switch y := b.(type) { + case nil: + return nil, nil + case bool: + return y, nil + default: + return invOp2(x, y, op) + } + default: + return undOp(x, op) + } + case '>': + a, b := o.get2(execCtx, ctx, arg) + if a == nil || b == nil { + return + } + switch x := a.(type) { + //case nil: + case idealComplex: + return undOp2(a, b, op) + case idealFloat: + switch y := b.(type) { + case idealFloat: + return x > y, nil + default: + return invOp2(x, y, op) + } + case idealInt: + switch y := b.(type) { + case idealInt: + return x > y, nil + default: + return invOp2(x, y, op) + } + case idealRune: + switch y := b.(type) { + case idealRune: + return x > y, nil + default: + return invOp2(x, y, op) + } + case idealUint: + switch y := b.(type) { + case idealUint: + return x > y, nil + default: + return invOp2(x, y, op) + } + case bool: + return undOp2(a, b, op) + case complex64: + return undOp2(a, b, op) + case complex128: + return undOp2(a, b, op) + case float32: + switch y := b.(type) { + case float32: + return x > y, nil + default: + return invOp2(x, y, op) + } + case float64: + switch y := b.(type) { + case float64: + return x > y, nil + default: + return invOp2(x, y, op) + } + case int8: + switch y := b.(type) { + case int8: + return x > y, nil + default: + return invOp2(x, y, op) + } + case int16: + switch y := b.(type) { + case int16: + return x > y, nil + default: + return invOp2(x, y, op) + } + case int32: + switch y := b.(type) { + case int32: + return x > y, nil + default: + return invOp2(x, y, op) + } + case int64: + switch y := b.(type) { + case int64: + return x > y, nil + default: + return invOp2(x, y, op) + } + case string: + switch y := b.(type) { + case string: + return x > y, nil + default: + return invOp2(x, y, op) + } + case uint8: + switch y := b.(type) { + case uint8: + return x > y, nil + default: + return invOp2(x, y, op) + } + case uint16: + switch y := b.(type) { + case uint16: + return x > y, nil + default: + return invOp2(x, y, op) + } + case uint32: + switch y := b.(type) { + case uint32: + return x > y, nil + default: + return invOp2(x, y, op) + } + case uint64: + switch y := b.(type) { + case uint64: + return x > y, nil + default: + return invOp2(x, y, op) + } + case *big.Int: + switch y := b.(type) { + case *big.Int: + return x.Cmp(y) > 0, nil + default: + return invOp2(x, y, op) + } + case *big.Rat: + switch y := b.(type) { + case *big.Rat: + return x.Cmp(y) > 0, nil + default: + return invOp2(x, y, op) + } + case time.Duration: + switch y := b.(type) { + case time.Duration: + return x > y, nil + default: + return invOp2(x, y, op) + } + case time.Time: + switch y := b.(type) { + case time.Time: + return x.After(y), nil + default: + return invOp2(x, y, op) + } + default: + return invOp2(a, b, op) + } + case '<': + a, b := o.get2(execCtx, ctx, arg) + if a == nil || b == nil { + return + } + switch x := a.(type) { + //case nil: + case idealComplex: + return undOp2(a, b, op) + case idealFloat: + switch y := b.(type) { + case idealFloat: + return x < y, nil + default: + return invOp2(x, y, op) + } + case idealInt: + switch y := b.(type) { + case idealInt: + return x < y, nil + default: + return invOp2(x, y, op) + } + case idealRune: + switch y := b.(type) { + case idealRune: + return x < y, nil + default: + return invOp2(x, y, op) + } + case idealUint: + switch y := b.(type) { + case idealUint: + return x < y, nil + default: + return invOp2(x, y, op) + } + case bool: + return undOp2(a, b, op) + case complex64: + return undOp2(a, b, op) + case complex128: + return undOp2(a, b, op) + case float32: + switch y := b.(type) { + case float32: + return x < y, nil + default: + return invOp2(x, y, op) + } + case float64: + switch y := b.(type) { + case float64: + return x < y, nil + default: + return invOp2(x, y, op) + } + case int8: + switch y := b.(type) { + case int8: + return x < y, nil + default: + return invOp2(x, y, op) + } + case int16: + switch y := b.(type) { + case int16: + return x < y, nil + default: + return invOp2(x, y, op) + } + case int32: + switch y := b.(type) { + case int32: + return x < y, nil + default: + return invOp2(x, y, op) + } + case int64: + switch y := b.(type) { + case int64: + return x < y, nil + default: + return invOp2(x, y, op) + } + case string: + switch y := b.(type) { + case string: + return x < y, nil + default: + return invOp2(x, y, op) + } + case uint8: + switch y := b.(type) { + case uint8: + return x < y, nil + default: + return invOp2(x, y, op) + } + case uint16: + switch y := b.(type) { + case uint16: + return x < y, nil + default: + return invOp2(x, y, op) + } + case uint32: + switch y := b.(type) { + case uint32: + return x < y, nil + default: + return invOp2(x, y, op) + } + case uint64: + switch y := b.(type) { + case uint64: + return x < y, nil + default: + return invOp2(x, y, op) + } + case *big.Int: + switch y := b.(type) { + case *big.Int: + return x.Cmp(y) < 0, nil + default: + return invOp2(x, y, op) + } + case *big.Rat: + switch y := b.(type) { + case *big.Rat: + return x.Cmp(y) < 0, nil + default: + return invOp2(x, y, op) + } + case time.Duration: + switch y := b.(type) { + case time.Duration: + return x < y, nil + default: + return invOp2(x, y, op) + } + case time.Time: + switch y := b.(type) { + case time.Time: + return x.Before(y), nil + default: + return invOp2(x, y, op) + } + default: + return invOp2(a, b, op) + } + case le: + a, b := o.get2(execCtx, ctx, arg) + if a == nil || b == nil { + return + } + switch x := a.(type) { + //case nil: + case idealComplex: + return undOp2(a, b, op) + case idealFloat: + switch y := b.(type) { + case idealFloat: + return x <= y, nil + default: + return invOp2(x, y, op) + } + case idealInt: + switch y := b.(type) { + case idealInt: + return x <= y, nil + default: + return invOp2(x, y, op) + } + case idealRune: + switch y := b.(type) { + case idealRune: + return x <= y, nil + default: + return invOp2(x, y, op) + } + case idealUint: + switch y := b.(type) { + case idealUint: + return x <= y, nil + default: + return invOp2(x, y, op) + } + case bool: + return undOp2(a, b, op) + case complex64: + return undOp2(a, b, op) + case complex128: + return undOp2(a, b, op) + case float32: + switch y := b.(type) { + case float32: + return x <= y, nil + default: + return invOp2(x, y, op) + } + case float64: + switch y := b.(type) { + case float64: + return x <= y, nil + default: + return invOp2(x, y, op) + } + case int8: + switch y := b.(type) { + case int8: + return x <= y, nil + default: + return invOp2(x, y, op) + } + case int16: + switch y := b.(type) { + case int16: + return x <= y, nil + default: + return invOp2(x, y, op) + } + case int32: + switch y := b.(type) { + case int32: + return x <= y, nil + default: + return invOp2(x, y, op) + } + case int64: + switch y := b.(type) { + case int64: + return x <= y, nil + default: + return invOp2(x, y, op) + } + case string: + switch y := b.(type) { + case string: + return x <= y, nil + default: + return invOp2(x, y, op) + } + case uint8: + switch y := b.(type) { + case uint8: + return x <= y, nil + default: + return invOp2(x, y, op) + } + case uint16: + switch y := b.(type) { + case uint16: + return x <= y, nil + default: + return invOp2(x, y, op) + } + case uint32: + switch y := b.(type) { + case uint32: + return x <= y, nil + default: + return invOp2(x, y, op) + } + case uint64: + switch y := b.(type) { + case uint64: + return x <= y, nil + default: + return invOp2(x, y, op) + } + case *big.Int: + switch y := b.(type) { + case *big.Int: + return x.Cmp(y) <= 0, nil + default: + return invOp2(x, y, op) + } + case *big.Rat: + switch y := b.(type) { + case *big.Rat: + return x.Cmp(y) <= 0, nil + default: + return invOp2(x, y, op) + } + case time.Duration: + switch y := b.(type) { + case time.Duration: + return x <= y, nil + default: + return invOp2(x, y, op) + } + case time.Time: + switch y := b.(type) { + case time.Time: + return x.Before(y) || x.Equal(y), nil + default: + return invOp2(x, y, op) + } + default: + return invOp2(a, b, op) + } + case ge: + a, b := o.get2(execCtx, ctx, arg) + if a == nil || b == nil { + return + } + switch x := a.(type) { + //case nil: + case idealComplex: + return undOp2(a, b, op) + case idealFloat: + switch y := b.(type) { + case idealFloat: + return x >= y, nil + default: + return invOp2(x, y, op) + } + case idealInt: + switch y := b.(type) { + case idealInt: + return x >= y, nil + default: + return invOp2(x, y, op) + } + case idealRune: + switch y := b.(type) { + case idealRune: + return x >= y, nil + default: + return invOp2(x, y, op) + } + case idealUint: + switch y := b.(type) { + case idealUint: + return x >= y, nil + default: + return invOp2(x, y, op) + } + case bool: + return undOp2(a, b, op) + case complex64: + return undOp2(a, b, op) + case complex128: + return undOp2(a, b, op) + case float32: + switch y := b.(type) { + case float32: + return x >= y, nil + default: + return invOp2(x, y, op) + } + case float64: + switch y := b.(type) { + case float64: + return x >= y, nil + default: + return invOp2(x, y, op) + } + case int8: + switch y := b.(type) { + case int8: + return x >= y, nil + default: + return invOp2(x, y, op) + } + case int16: + switch y := b.(type) { + case int16: + return x >= y, nil + default: + return invOp2(x, y, op) + } + case int32: + switch y := b.(type) { + case int32: + return x >= y, nil + default: + return invOp2(x, y, op) + } + case int64: + switch y := b.(type) { + case int64: + return x >= y, nil + default: + return invOp2(x, y, op) + } + case string: + switch y := b.(type) { + case string: + return x >= y, nil + default: + return invOp2(x, y, op) + } + case uint8: + switch y := b.(type) { + case uint8: + return x >= y, nil + default: + return invOp2(x, y, op) + } + case uint16: + switch y := b.(type) { + case uint16: + return x >= y, nil + default: + return invOp2(x, y, op) + } + case uint32: + switch y := b.(type) { + case uint32: + return x >= y, nil + default: + return invOp2(x, y, op) + } + case uint64: + switch y := b.(type) { + case uint64: + return x >= y, nil + default: + return invOp2(x, y, op) + } + case *big.Int: + switch y := b.(type) { + case *big.Int: + return x.Cmp(y) >= 0, nil + default: + return invOp2(x, y, op) + } + case *big.Rat: + switch y := b.(type) { + case *big.Rat: + return x.Cmp(y) >= 0, nil + default: + return invOp2(x, y, op) + } + case time.Duration: + switch y := b.(type) { + case time.Duration: + return x >= y, nil + default: + return invOp2(x, y, op) + } + case time.Time: + switch y := b.(type) { + case time.Time: + return x.After(y) || x.Equal(y), nil + default: + return invOp2(x, y, op) + } + default: + return invOp2(a, b, op) + } + case neq: + a, b := o.get2(execCtx, ctx, arg) + if a == nil || b == nil { + return + } + switch x := a.(type) { + //case nil: + case idealComplex: + switch y := b.(type) { + case idealComplex: + return x != y, nil + default: + return invOp2(x, y, op) + } + case idealFloat: + switch y := b.(type) { + case idealFloat: + return x != y, nil + default: + return invOp2(x, y, op) + } + case idealInt: + switch y := b.(type) { + case idealInt: + return x != y, nil + default: + return invOp2(x, y, op) + } + case idealRune: + switch y := b.(type) { + case idealRune: + return x != y, nil + default: + return invOp2(x, y, op) + } + case idealUint: + switch y := b.(type) { + case idealUint: + return x != y, nil + default: + return invOp2(x, y, op) + } + case bool: + switch y := b.(type) { + case bool: + return x != y, nil + default: + return invOp2(x, y, op) + } + case complex64: + switch y := b.(type) { + case complex64: + return x != y, nil + default: + return invOp2(x, y, op) + } + case complex128: + switch y := b.(type) { + case complex128: + return x != y, nil + default: + return invOp2(x, y, op) + } + case float32: + switch y := b.(type) { + case float32: + return x != y, nil + default: + return invOp2(x, y, op) + } + case float64: + switch y := b.(type) { + case float64: + return x != y, nil + default: + return invOp2(x, y, op) + } + case int8: + switch y := b.(type) { + case int8: + return x != y, nil + default: + return invOp2(x, y, op) + } + case int16: + switch y := b.(type) { + case int16: + return x != y, nil + default: + return invOp2(x, y, op) + } + case int32: + switch y := b.(type) { + case int32: + return x != y, nil + default: + return invOp2(x, y, op) + } + case int64: + switch y := b.(type) { + case int64: + return x != y, nil + default: + return invOp2(x, y, op) + } + case string: + switch y := b.(type) { + case string: + return x != y, nil + default: + return invOp2(x, y, op) + } + case uint8: + switch y := b.(type) { + case uint8: + return x != y, nil + default: + return invOp2(x, y, op) + } + case uint16: + switch y := b.(type) { + case uint16: + return x != y, nil + default: + return invOp2(x, y, op) + } + case uint32: + switch y := b.(type) { + case uint32: + return x != y, nil + default: + return invOp2(x, y, op) + } + case uint64: + switch y := b.(type) { + case uint64: + return x != y, nil + default: + return invOp2(x, y, op) + } + case *big.Int: + switch y := b.(type) { + case *big.Int: + return x.Cmp(y) != 0, nil + default: + return invOp2(x, y, op) + } + case *big.Rat: + switch y := b.(type) { + case *big.Rat: + return x.Cmp(y) != 0, nil + default: + return invOp2(x, y, op) + } + case time.Duration: + switch y := b.(type) { + case time.Duration: + return x != y, nil + default: + return invOp2(x, y, op) + } + case time.Time: + switch y := b.(type) { + case time.Time: + return !x.Equal(y), nil + default: + return invOp2(x, y, op) + } + default: + return invOp2(a, b, op) + } + case eq: + a, b := o.get2(execCtx, ctx, arg) + if a == nil || b == nil { + return + } + switch x := a.(type) { + //case nil: + case idealComplex: + switch y := b.(type) { + case idealComplex: + return x == y, nil + default: + return invOp2(x, y, op) + } + case idealFloat: + switch y := b.(type) { + case idealFloat: + return x == y, nil + default: + return invOp2(x, y, op) + } + case idealInt: + switch y := b.(type) { + case idealInt: + return x == y, nil + default: + return invOp2(x, y, op) + } + case idealRune: + switch y := b.(type) { + case idealRune: + return x == y, nil + default: + return invOp2(x, y, op) + } + case idealUint: + switch y := b.(type) { + case idealUint: + return x == y, nil + default: + return invOp2(x, y, op) + } + case bool: + switch y := b.(type) { + case bool: + return x == y, nil + default: + return invOp2(x, y, op) + } + case complex64: + switch y := b.(type) { + case complex64: + return x == y, nil + default: + return invOp2(x, y, op) + } + case complex128: + switch y := b.(type) { + case complex128: + return x == y, nil + default: + return invOp2(x, y, op) + } + case float32: + switch y := b.(type) { + case float32: + return x == y, nil + default: + return invOp2(x, y, op) + } + case float64: + switch y := b.(type) { + case float64: + return x == y, nil + default: + return invOp2(x, y, op) + } + case int8: + switch y := b.(type) { + case int8: + return x == y, nil + default: + return invOp2(x, y, op) + } + case int16: + switch y := b.(type) { + case int16: + return x == y, nil + default: + return invOp2(x, y, op) + } + case int32: + switch y := b.(type) { + case int32: + return x == y, nil + default: + return invOp2(x, y, op) + } + case int64: + switch y := b.(type) { + case int64: + return x == y, nil + default: + return invOp2(x, y, op) + } + case string: + switch y := b.(type) { + case string: + return x == y, nil + default: + return invOp2(x, y, op) + } + case uint8: + switch y := b.(type) { + case uint8: + return x == y, nil + default: + return invOp2(x, y, op) + } + case uint16: + switch y := b.(type) { + case uint16: + return x == y, nil + default: + return invOp2(x, y, op) + } + case uint32: + switch y := b.(type) { + case uint32: + return x == y, nil + default: + return invOp2(x, y, op) + } + case uint64: + switch y := b.(type) { + case uint64: + return x == y, nil + default: + return invOp2(x, y, op) + } + case *big.Int: + switch y := b.(type) { + case *big.Int: + return x.Cmp(y) == 0, nil + default: + return invOp2(x, y, op) + } + case *big.Rat: + switch y := b.(type) { + case *big.Rat: + return x.Cmp(y) == 0, nil + default: + return invOp2(x, y, op) + } + case time.Duration: + switch y := b.(type) { + case time.Duration: + return x == y, nil + default: + return invOp2(x, y, op) + } + case time.Time: + switch y := b.(type) { + case time.Time: + return x.Equal(y), nil + default: + return invOp2(x, y, op) + } + default: + return invOp2(a, b, op) + } + case '+': + a, b := o.get2(execCtx, ctx, arg) + if a == nil || b == nil { + return + } + switch x := a.(type) { + //case nil: + case idealComplex: + switch y := b.(type) { + case idealComplex: + return idealComplex(complex64(x) + complex64(y)), nil + default: + return invOp2(x, y, op) + } + case idealFloat: + switch y := b.(type) { + case idealFloat: + return idealFloat(float64(x) + float64(y)), nil + default: + return invOp2(x, y, op) + } + case idealInt: + switch y := b.(type) { + case idealInt: + return idealInt(int64(x) + int64(y)), nil + default: + return invOp2(x, y, op) + } + case idealRune: + switch y := b.(type) { + case idealRune: + return idealRune(int64(x) + int64(y)), nil + default: + return invOp2(x, y, op) + } + case idealUint: + switch y := b.(type) { + case idealUint: + return idealUint(uint64(x) + uint64(y)), nil + default: + return invOp2(x, y, op) + } + case bool: + return undOp2(a, b, op) + case complex64: + switch y := b.(type) { + case complex64: + return x + y, nil + default: + return invOp2(x, y, op) + } + case complex128: + switch y := b.(type) { + case complex128: + return x + y, nil + default: + return invOp2(x, y, op) + } + case float32: + switch y := b.(type) { + case float32: + return x + y, nil + default: + return invOp2(x, y, op) + } + case float64: + switch y := b.(type) { + case float64: + return x + y, nil + default: + return invOp2(x, y, op) + } + case int8: + switch y := b.(type) { + case int8: + return x + y, nil + default: + return invOp2(x, y, op) + } + case int16: + switch y := b.(type) { + case int16: + return x + y, nil + default: + return invOp2(x, y, op) + } + case int32: + switch y := b.(type) { + case int32: + return x + y, nil + default: + return invOp2(x, y, op) + } + case int64: + switch y := b.(type) { + case int64: + return x + y, nil + default: + return invOp2(x, y, op) + } + case string: + switch y := b.(type) { + case string: + return x + y, nil + default: + return invOp2(x, y, op) + } + case uint8: + switch y := b.(type) { + case uint8: + return x + y, nil + default: + return invOp2(x, y, op) + } + case uint16: + switch y := b.(type) { + case uint16: + return x + y, nil + default: + return invOp2(x, y, op) + } + case uint32: + switch y := b.(type) { + case uint32: + return x + y, nil + default: + return invOp2(x, y, op) + } + case uint64: + switch y := b.(type) { + case uint64: + return x + y, nil + default: + return invOp2(x, y, op) + } + case *big.Int: + switch y := b.(type) { + case *big.Int: + var z big.Int + return z.Add(x, y), nil + default: + return invOp2(x, y, op) + } + case *big.Rat: + switch y := b.(type) { + case *big.Rat: + var z big.Rat + return z.Add(x, y), nil + default: + return invOp2(x, y, op) + } + case time.Duration: + switch y := b.(type) { + case time.Duration: + return x + y, nil + case time.Time: + return y.Add(x), nil + default: + return invOp2(x, y, op) + } + case time.Time: + switch y := b.(type) { + case time.Duration: + return x.Add(y), nil + default: + return invOp2(x, y, op) + } + default: + return invOp2(a, b, op) + } + case '-': + a, b := o.get2(execCtx, ctx, arg) + if a == nil || b == nil { + return + } + switch x := a.(type) { + //case nil: + case idealComplex: + switch y := b.(type) { + case idealComplex: + return idealComplex(complex64(x) - complex64(y)), nil + default: + return invOp2(x, y, op) + } + case idealFloat: + switch y := b.(type) { + case idealFloat: + return idealFloat(float64(x) - float64(y)), nil + default: + return invOp2(x, y, op) + } + case idealInt: + switch y := b.(type) { + case idealInt: + return idealInt(int64(x) - int64(y)), nil + default: + return invOp2(x, y, op) + } + case idealRune: + switch y := b.(type) { + case idealRune: + return idealRune(int64(x) - int64(y)), nil + default: + return invOp2(x, y, op) + } + case idealUint: + switch y := b.(type) { + case idealUint: + return idealUint(uint64(x) - uint64(y)), nil + default: + return invOp2(x, y, op) + } + case bool: + return undOp2(a, b, op) + case complex64: + switch y := b.(type) { + case complex64: + return x - y, nil + default: + return invOp2(x, y, op) + } + case complex128: + switch y := b.(type) { + case complex128: + return x - y, nil + default: + return invOp2(x, y, op) + } + case float32: + switch y := b.(type) { + case float32: + return x - y, nil + default: + return invOp2(x, y, op) + } + case float64: + switch y := b.(type) { + case float64: + return x - y, nil + default: + return invOp2(x, y, op) + } + case int8: + switch y := b.(type) { + case int8: + return x - y, nil + default: + return invOp2(x, y, op) + } + case int16: + switch y := b.(type) { + case int16: + return x - y, nil + default: + return invOp2(x, y, op) + } + case int32: + switch y := b.(type) { + case int32: + return x - y, nil + default: + return invOp2(x, y, op) + } + case int64: + switch y := b.(type) { + case int64: + return x - y, nil + default: + return invOp2(x, y, op) + } + case string: + return undOp2(a, b, op) + case uint8: + switch y := b.(type) { + case uint8: + return x - y, nil + default: + return invOp2(x, y, op) + } + case uint16: + switch y := b.(type) { + case uint16: + return x - y, nil + default: + return invOp2(x, y, op) + } + case uint32: + switch y := b.(type) { + case uint32: + return x - y, nil + default: + return invOp2(x, y, op) + } + case uint64: + switch y := b.(type) { + case uint64: + return x - y, nil + default: + return invOp2(x, y, op) + } + case *big.Int: + switch y := b.(type) { + case *big.Int: + var z big.Int + return z.Sub(x, y), nil + default: + return invOp2(x, y, op) + } + case *big.Rat: + switch y := b.(type) { + case *big.Rat: + var z big.Rat + return z.Sub(x, y), nil + default: + return invOp2(x, y, op) + } + case time.Duration: + switch y := b.(type) { + case time.Duration: + return x - y, nil + default: + return invOp2(x, y, op) + } + case time.Time: + switch y := b.(type) { + case time.Duration: + return x.Add(-y), nil + case time.Time: + return x.Sub(y), nil + default: + return invOp2(x, y, op) + } + default: + return invOp2(a, b, op) + } + case rsh: + a, b := eval2(o.l, o.r, execCtx, ctx, arg) + if a == nil || b == nil { + return + } + + var cnt uint64 + switch y := b.(type) { + //case nil: + case idealComplex: + return invShiftRHS(a, b) + case idealFloat: + return invShiftRHS(a, b) + case idealInt: + cnt = uint64(y) + case idealRune: + cnt = uint64(y) + case idealUint: + cnt = uint64(y) + case bool: + return invShiftRHS(a, b) + case complex64: + return invShiftRHS(a, b) + case complex128: + return invShiftRHS(a, b) + case float32: + return invShiftRHS(a, b) + case float64: + return invShiftRHS(a, b) + case int8: + return invShiftRHS(a, b) + case int16: + return invShiftRHS(a, b) + case int32: + return invShiftRHS(a, b) + case int64: + return invShiftRHS(a, b) + case string: + return invShiftRHS(a, b) + case uint8: + cnt = uint64(y) + case uint16: + cnt = uint64(y) + case uint32: + cnt = uint64(y) + case uint64: + cnt = uint64(y) + default: + return invOp2(a, b, op) + } + + switch x := a.(type) { + //case nil: + case idealComplex: + return undOp2(a, b, op) + case idealFloat: + return undOp2(a, b, op) + case idealInt: + return idealInt(int64(x) >> cnt), nil + case idealRune: + return idealRune(int64(x) >> cnt), nil + case idealUint: + return idealUint(uint64(x) >> cnt), nil + case bool: + return undOp2(a, b, op) + case complex64: + return undOp2(a, b, op) + case complex128: + return undOp2(a, b, op) + case float32: + return undOp2(a, b, op) + case float64: + return undOp2(a, b, op) + case int8: + return x >> cnt, nil + case int16: + return x >> cnt, nil + case int32: + return x >> cnt, nil + case int64: + return x >> cnt, nil + case string: + return undOp2(a, b, op) + case uint8: + return x >> cnt, nil + case uint16: + return x >> cnt, nil + case uint32: + return x >> cnt, nil + case uint64: + return x >> cnt, nil + case *big.Int: + var z big.Int + return z.Rsh(x, uint(cnt)), nil + case time.Duration: + return x >> cnt, nil + default: + return invOp2(a, b, op) + } + case lsh: + a, b := eval2(o.l, o.r, execCtx, ctx, arg) + if a == nil || b == nil { + return + } + + var cnt uint64 + switch y := b.(type) { + //case nil: + case idealComplex: + return invShiftRHS(a, b) + case idealFloat: + return invShiftRHS(a, b) + case idealInt: + cnt = uint64(y) + case idealRune: + cnt = uint64(y) + case idealUint: + cnt = uint64(y) + case bool: + return invShiftRHS(a, b) + case complex64: + return invShiftRHS(a, b) + case complex128: + return invShiftRHS(a, b) + case float32: + return invShiftRHS(a, b) + case float64: + return invShiftRHS(a, b) + case int8: + return invShiftRHS(a, b) + case int16: + return invShiftRHS(a, b) + case int32: + return invShiftRHS(a, b) + case int64: + return invShiftRHS(a, b) + case string: + return invShiftRHS(a, b) + case uint8: + cnt = uint64(y) + case uint16: + cnt = uint64(y) + case uint32: + cnt = uint64(y) + case uint64: + cnt = uint64(y) + default: + return invOp2(a, b, op) + } + + switch x := a.(type) { + //case nil: + case idealComplex: + return undOp2(a, b, op) + case idealFloat: + return undOp2(a, b, op) + case idealInt: + return idealInt(int64(x) << cnt), nil + case idealRune: + return idealRune(int64(x) << cnt), nil + case idealUint: + return idealUint(uint64(x) << cnt), nil + case bool: + return undOp2(a, b, op) + case complex64: + return undOp2(a, b, op) + case complex128: + return undOp2(a, b, op) + case float32: + return undOp2(a, b, op) + case float64: + return undOp2(a, b, op) + case int8: + return x << cnt, nil + case int16: + return x << cnt, nil + case int32: + return x << cnt, nil + case int64: + return x << cnt, nil + case string: + return undOp2(a, b, op) + case uint8: + return x << cnt, nil + case uint16: + return x << cnt, nil + case uint32: + return x << cnt, nil + case uint64: + return x << cnt, nil + case *big.Int: + var z big.Int + return z.Lsh(x, uint(cnt)), nil + case time.Duration: + return x << cnt, nil + default: + return invOp2(a, b, op) + } + case '&': + a, b := o.get2(execCtx, ctx, arg) + if a == nil || b == nil { + return + } + switch x := a.(type) { + //case nil: + case idealComplex: + return undOp2(a, b, op) + case idealFloat: + return undOp2(a, b, op) + case idealInt: + switch y := b.(type) { + case idealInt: + return idealInt(int64(x) & int64(y)), nil + default: + return invOp2(x, y, op) + } + case idealRune: + switch y := b.(type) { + case idealRune: + return idealRune(int64(x) & int64(y)), nil + default: + return invOp2(x, y, op) + } + case idealUint: + switch y := b.(type) { + case idealUint: + return idealUint(uint64(x) & uint64(y)), nil + default: + return invOp2(x, y, op) + } + case bool: + return undOp2(a, b, op) + case complex64: + return undOp2(a, b, op) + case complex128: + return undOp2(a, b, op) + case float32: + return undOp2(a, b, op) + case float64: + return undOp2(a, b, op) + case int8: + switch y := b.(type) { + case int8: + return x & y, nil + default: + return invOp2(x, y, op) + } + case int16: + switch y := b.(type) { + case int16: + return x & y, nil + default: + return invOp2(x, y, op) + } + case int32: + switch y := b.(type) { + case int32: + return x & y, nil + default: + return invOp2(x, y, op) + } + case int64: + switch y := b.(type) { + case int64: + return x & y, nil + default: + return invOp2(x, y, op) + } + case string: + return undOp2(a, b, op) + case uint8: + switch y := b.(type) { + case uint8: + return x & y, nil + default: + return invOp2(x, y, op) + } + case uint16: + switch y := b.(type) { + case uint16: + return x & y, nil + default: + return invOp2(x, y, op) + } + case uint32: + switch y := b.(type) { + case uint32: + return x & y, nil + default: + return invOp2(x, y, op) + } + case uint64: + switch y := b.(type) { + case uint64: + return x & y, nil + default: + return invOp2(x, y, op) + } + case *big.Int: + switch y := b.(type) { + case *big.Int: + var z big.Int + return z.And(x, y), nil + default: + return invOp2(x, y, op) + } + case time.Duration: + switch y := b.(type) { + case time.Duration: + return x & y, nil + default: + return invOp2(x, y, op) + } + default: + return invOp2(a, b, op) + } + case '|': + a, b := o.get2(execCtx, ctx, arg) + if a == nil || b == nil { + return + } + switch x := a.(type) { + //case nil: + case idealComplex: + return undOp2(a, b, op) + case idealFloat: + return undOp2(a, b, op) + case idealInt: + switch y := b.(type) { + case idealInt: + return idealInt(int64(x) | int64(y)), nil + default: + return invOp2(x, y, op) + } + case idealRune: + switch y := b.(type) { + case idealRune: + return idealRune(int64(x) | int64(y)), nil + default: + return invOp2(x, y, op) + } + case idealUint: + switch y := b.(type) { + case idealUint: + return idealUint(uint64(x) | uint64(y)), nil + default: + return invOp2(x, y, op) + } + case bool: + return undOp2(a, b, op) + case complex64: + return undOp2(a, b, op) + case complex128: + return undOp2(a, b, op) + case float32: + return undOp2(a, b, op) + case float64: + return undOp2(a, b, op) + case int8: + switch y := b.(type) { + case int8: + return x | y, nil + default: + return invOp2(x, y, op) + } + case int16: + switch y := b.(type) { + case int16: + return x | y, nil + default: + return invOp2(x, y, op) + } + case int32: + switch y := b.(type) { + case int32: + return x | y, nil + default: + return invOp2(x, y, op) + } + case int64: + switch y := b.(type) { + case int64: + return x | y, nil + default: + return invOp2(x, y, op) + } + case string: + return undOp2(a, b, op) + case uint8: + switch y := b.(type) { + case uint8: + return x | y, nil + default: + return invOp2(x, y, op) + } + case uint16: + switch y := b.(type) { + case uint16: + return x | y, nil + default: + return invOp2(x, y, op) + } + case uint32: + switch y := b.(type) { + case uint32: + return x | y, nil + default: + return invOp2(x, y, op) + } + case uint64: + switch y := b.(type) { + case uint64: + return x | y, nil + default: + return invOp2(x, y, op) + } + case *big.Int: + switch y := b.(type) { + case *big.Int: + var z big.Int + return z.Or(x, y), nil + default: + return invOp2(x, y, op) + } + case time.Duration: + switch y := b.(type) { + case time.Duration: + return x | y, nil + default: + return invOp2(x, y, op) + } + default: + return invOp2(a, b, op) + } + case andnot: + a, b := o.get2(execCtx, ctx, arg) + if a == nil || b == nil { + return + } + switch x := a.(type) { + //case nil: + case idealComplex: + return undOp2(a, b, op) + case idealFloat: + return undOp2(a, b, op) + case idealInt: + switch y := b.(type) { + case idealInt: + return idealInt(int64(x) &^ int64(y)), nil + default: + return invOp2(x, y, op) + } + case idealRune: + switch y := b.(type) { + case idealRune: + return idealRune(int64(x) &^ int64(y)), nil + default: + return invOp2(x, y, op) + } + case idealUint: + switch y := b.(type) { + case idealUint: + return idealUint(uint64(x) &^ uint64(y)), nil + default: + return invOp2(x, y, op) + } + case bool: + return undOp2(a, b, op) + case complex64: + return undOp2(a, b, op) + case complex128: + return undOp2(a, b, op) + case float32: + return undOp2(a, b, op) + case float64: + return undOp2(a, b, op) + case int8: + switch y := b.(type) { + case int8: + return x &^ y, nil + default: + return invOp2(x, y, op) + } + case int16: + switch y := b.(type) { + case int16: + return x &^ y, nil + default: + return invOp2(x, y, op) + } + case int32: + switch y := b.(type) { + case int32: + return x &^ y, nil + default: + return invOp2(x, y, op) + } + case int64: + switch y := b.(type) { + case int64: + return x &^ y, nil + default: + return invOp2(x, y, op) + } + case string: + return undOp2(a, b, op) + case uint8: + switch y := b.(type) { + case uint8: + return x &^ y, nil + default: + return invOp2(x, y, op) + } + case uint16: + switch y := b.(type) { + case uint16: + return x &^ y, nil + default: + return invOp2(x, y, op) + } + case uint32: + switch y := b.(type) { + case uint32: + return x &^ y, nil + default: + return invOp2(x, y, op) + } + case uint64: + switch y := b.(type) { + case uint64: + return x &^ y, nil + default: + return invOp2(x, y, op) + } + case *big.Int: + switch y := b.(type) { + case *big.Int: + var z big.Int + return z.AndNot(x, y), nil + default: + return invOp2(x, y, op) + } + case time.Duration: + switch y := b.(type) { + case time.Duration: + return x &^ y, nil + default: + return invOp2(x, y, op) + } + default: + return invOp2(a, b, op) + } + case '^': + a, b := o.get2(execCtx, ctx, arg) + if a == nil || b == nil { + return + } + switch x := a.(type) { + //case nil: + case idealComplex: + return undOp2(a, b, op) + case idealFloat: + return undOp2(a, b, op) + case idealInt: + switch y := b.(type) { + case idealInt: + return idealInt(int64(x) ^ int64(y)), nil + default: + return invOp2(x, y, op) + } + case idealRune: + switch y := b.(type) { + case idealRune: + return idealRune(int64(x) ^ int64(y)), nil + default: + return invOp2(x, y, op) + } + case idealUint: + switch y := b.(type) { + case idealUint: + return idealUint(uint64(x) ^ uint64(y)), nil + default: + return invOp2(x, y, op) + } + case bool: + return undOp2(a, b, op) + case complex64: + return undOp2(a, b, op) + case complex128: + return undOp2(a, b, op) + case float32: + return undOp2(a, b, op) + case float64: + return undOp2(a, b, op) + case int8: + switch y := b.(type) { + case int8: + return x ^ y, nil + default: + return invOp2(x, y, op) + } + case int16: + switch y := b.(type) { + case int16: + return x ^ y, nil + default: + return invOp2(x, y, op) + } + case int32: + switch y := b.(type) { + case int32: + return x ^ y, nil + default: + return invOp2(x, y, op) + } + case int64: + switch y := b.(type) { + case int64: + return x ^ y, nil + default: + return invOp2(x, y, op) + } + case string: + return undOp2(a, b, op) + case uint8: + switch y := b.(type) { + case uint8: + return x ^ y, nil + default: + return invOp2(x, y, op) + } + case uint16: + switch y := b.(type) { + case uint16: + return x ^ y, nil + default: + return invOp2(x, y, op) + } + case uint32: + switch y := b.(type) { + case uint32: + return x ^ y, nil + default: + return invOp2(x, y, op) + } + case uint64: + switch y := b.(type) { + case uint64: + return x ^ y, nil + default: + return invOp2(x, y, op) + } + case *big.Int: + switch y := b.(type) { + case *big.Int: + var z big.Int + return z.Xor(x, y), nil + default: + return invOp2(x, y, op) + } + case time.Duration: + switch y := b.(type) { + case time.Duration: + return x ^ y, nil + default: + return invOp2(x, y, op) + } + default: + return invOp2(a, b, op) + } + case '%': + a, b := o.get2(execCtx, ctx, arg) + if a == nil || b == nil { + return + } + switch x := a.(type) { + //case nil: + case idealComplex: + return undOp2(a, b, op) + case idealFloat: + return undOp2(a, b, op) + case idealInt: + switch y := b.(type) { + case idealInt: + return idealInt(int64(x) % int64(y)), nil + default: + return invOp2(x, y, op) + } + case idealRune: + switch y := b.(type) { + case idealRune: + return idealRune(int64(x) % int64(y)), nil + default: + return invOp2(x, y, op) + } + case idealUint: + switch y := b.(type) { + case idealUint: + return idealUint(uint64(x) % uint64(y)), nil + default: + return invOp2(x, y, op) + } + case bool: + return undOp2(a, b, op) + case complex64: + return undOp2(a, b, op) + case complex128: + return undOp2(a, b, op) + case float32: + return undOp2(a, b, op) + case float64: + return undOp2(a, b, op) + case int8: + switch y := b.(type) { + case int8: + return x % y, nil + default: + return invOp2(x, y, op) + } + case int16: + switch y := b.(type) { + case int16: + return x % y, nil + default: + return invOp2(x, y, op) + } + case int32: + switch y := b.(type) { + case int32: + return x % y, nil + default: + return invOp2(x, y, op) + } + case int64: + switch y := b.(type) { + case int64: + return x % y, nil + default: + return invOp2(x, y, op) + } + case string: + return undOp2(a, b, op) + case uint8: + switch y := b.(type) { + case uint8: + return x % y, nil + default: + return invOp2(x, y, op) + } + case uint16: + switch y := b.(type) { + case uint16: + return x % y, nil + default: + return invOp2(x, y, op) + } + case uint32: + switch y := b.(type) { + case uint32: + return x % y, nil + default: + return invOp2(x, y, op) + } + case uint64: + switch y := b.(type) { + case uint64: + return x % y, nil + default: + return invOp2(x, y, op) + } + case *big.Int: + switch y := b.(type) { + case *big.Int: + if y.Sign() == 0 { + return nil, errDivByZero + } + + var z big.Int + return z.Mod(x, y), nil + default: + return invOp2(x, y, op) + } + case time.Duration: + switch y := b.(type) { + case time.Duration: + return x % y, nil + default: + return invOp2(x, y, op) + } + default: + return invOp2(a, b, op) + } + case '/': + a, b := o.get2(execCtx, ctx, arg) + if a == nil || b == nil { + return + } + switch x := a.(type) { + //case nil: + case idealComplex: + switch y := b.(type) { + case idealComplex: + return idealComplex(complex64(x) / complex64(y)), nil + default: + return invOp2(x, y, op) + } + case idealFloat: + switch y := b.(type) { + case idealFloat: + return idealFloat(float64(x) / float64(y)), nil + default: + return invOp2(x, y, op) + } + case idealInt: + switch y := b.(type) { + case idealInt: + return idealInt(int64(x) / int64(y)), nil + default: + return invOp2(x, y, op) + } + case idealRune: + switch y := b.(type) { + case idealRune: + return idealRune(int64(x) / int64(y)), nil + default: + return invOp2(x, y, op) + } + case idealUint: + switch y := b.(type) { + case idealUint: + return idealUint(uint64(x) / uint64(y)), nil + default: + return invOp2(x, y, op) + } + case bool: + return undOp2(a, b, op) + case complex64: + switch y := b.(type) { + case complex64: + return x / y, nil + default: + return invOp2(x, y, op) + } + case complex128: + switch y := b.(type) { + case complex128: + return x / y, nil + default: + return invOp2(x, y, op) + } + case float32: + switch y := b.(type) { + case float32: + return x / y, nil + default: + return invOp2(x, y, op) + } + case float64: + switch y := b.(type) { + case float64: + return x / y, nil + default: + return invOp2(x, y, op) + } + case int8: + switch y := b.(type) { + case int8: + return x / y, nil + default: + return invOp2(x, y, op) + } + case int16: + switch y := b.(type) { + case int16: + return x / y, nil + default: + return invOp2(x, y, op) + } + case int32: + switch y := b.(type) { + case int32: + return x / y, nil + default: + return invOp2(x, y, op) + } + case int64: + switch y := b.(type) { + case int64: + return x / y, nil + default: + return invOp2(x, y, op) + } + case string: + return undOp2(a, b, op) + case uint8: + switch y := b.(type) { + case uint8: + return x / y, nil + default: + return invOp2(x, y, op) + } + case uint16: + switch y := b.(type) { + case uint16: + return x / y, nil + default: + return invOp2(x, y, op) + } + case uint32: + switch y := b.(type) { + case uint32: + return x / y, nil + default: + return invOp2(x, y, op) + } + case uint64: + switch y := b.(type) { + case uint64: + return x / y, nil + default: + return invOp2(x, y, op) + } + case *big.Int: + switch y := b.(type) { + case *big.Int: + if y.Sign() == 0 { + return nil, errDivByZero + } + + var z big.Int + return z.Quo(x, y), nil + default: + return invOp2(x, y, op) + } + case *big.Rat: + switch y := b.(type) { + case *big.Rat: + if y.Sign() == 0 { + return nil, errDivByZero + } + + var z big.Rat + return z.Quo(x, y), nil + default: + return invOp2(x, y, op) + } + case time.Duration: + switch y := b.(type) { + case time.Duration: + return x / y, nil + default: + return invOp2(x, y, op) + } + default: + return invOp2(a, b, op) + } + case '*': + a, b := o.get2(execCtx, ctx, arg) + if a == nil || b == nil { + return + } + switch x := a.(type) { + //case nil: + case idealComplex: + switch y := b.(type) { + case idealComplex: + return idealComplex(complex64(x) * complex64(y)), nil + default: + return invOp2(x, y, op) + } + case idealFloat: + switch y := b.(type) { + case idealFloat: + return idealFloat(float64(x) * float64(y)), nil + default: + return invOp2(x, y, op) + } + case idealInt: + switch y := b.(type) { + case idealInt: + return idealInt(int64(x) * int64(y)), nil + default: + return invOp2(x, y, op) + } + case idealRune: + switch y := b.(type) { + case idealRune: + return idealRune(int64(x) * int64(y)), nil + default: + return invOp2(x, y, op) + } + case idealUint: + switch y := b.(type) { + case idealUint: + return idealUint(uint64(x) * uint64(y)), nil + default: + return invOp2(x, y, op) + } + case bool: + return undOp2(a, b, op) + case complex64: + switch y := b.(type) { + case complex64: + return x * y, nil + default: + return invOp2(x, y, op) + } + case complex128: + switch y := b.(type) { + case complex128: + return x * y, nil + default: + return invOp2(x, y, op) + } + case float32: + switch y := b.(type) { + case float32: + return x * y, nil + default: + return invOp2(x, y, op) + } + case float64: + switch y := b.(type) { + case float64: + return x * y, nil + default: + return invOp2(x, y, op) + } + case int8: + switch y := b.(type) { + case int8: + return x * y, nil + default: + return invOp2(x, y, op) + } + case int16: + switch y := b.(type) { + case int16: + return x * y, nil + default: + return invOp2(x, y, op) + } + case int32: + switch y := b.(type) { + case int32: + return x * y, nil + default: + return invOp2(x, y, op) + } + case int64: + switch y := b.(type) { + case int64: + return x * y, nil + default: + return invOp2(x, y, op) + } + case string: + return undOp2(a, b, op) + case uint8: + switch y := b.(type) { + case uint8: + return x * y, nil + default: + return invOp2(x, y, op) + } + case uint16: + switch y := b.(type) { + case uint16: + return x * y, nil + default: + return invOp2(x, y, op) + } + case uint32: + switch y := b.(type) { + case uint32: + return x * y, nil + default: + return invOp2(x, y, op) + } + case uint64: + switch y := b.(type) { + case uint64: + return x * y, nil + default: + return invOp2(x, y, op) + } + case *big.Int: + switch y := b.(type) { + case *big.Int: + var z big.Int + return z.Mul(x, y), nil + default: + return invOp2(x, y, op) + } + case *big.Rat: + switch y := b.(type) { + case *big.Rat: + var z big.Rat + return z.Mul(x, y), nil + default: + return invOp2(x, y, op) + } + case time.Duration: + switch y := b.(type) { + case time.Duration: + return x * y, nil + default: + return invOp2(x, y, op) + } + default: + return invOp2(a, b, op) + } + default: + log.Panic("internal error 037") + panic("unreachable") + } +} + +func (o *binaryOperation) get2(execCtx *execCtx, ctx map[interface{}]interface{}, arg []interface{}) (x, y interface{}) { + x, y = eval2(o.l, o.r, execCtx, ctx, arg) + //dbg("get2 pIn - ", x, y) + //defer func() {dbg("get2 coerced ", x, y)}() + return coerce(x, y) +} + +type ident struct { + s string +} + +func (i *ident) isQualified() bool { return strings.Contains(i.s, ".") } + +func (i *ident) isStatic() bool { return false } + +func (i *ident) String() string { return i.s } + +func (i *ident) eval(execCtx *execCtx, ctx map[interface{}]interface{}, _ []interface{}) (v interface{}, err error) { + if _, ok := ctx["$agg0"]; ok { + return int64(0), nil + } + + //defer func() { dbg("ident %q -> %v %v", i.s, v, err) }() + v, ok := ctx[i.s] + if !ok { + err = fmt.Errorf("unknown field %s", i.s) + } + return +} + +type pIn struct { + expr expression + list []expression + m map[interface{}]struct{} // IN (SELECT...) results + not bool + sample interface{} + sel *selectStmt +} + +func (n *pIn) isStatic() bool { + if !n.expr.isStatic() || n.sel != nil { + return false + } + + for _, v := range n.list { + if !v.isStatic() { + return false + } + } + return true +} + +//LATER newIn + +func (n *pIn) String() string { + if n.sel == nil { + a := []string{} + for _, v := range n.list { + a = append(a, v.String()) + } + if n.not { + return fmt.Sprintf("%s NOT IN (%s)", n.expr, strings.Join(a, ",")) + } + + return fmt.Sprintf("%s IN (%s)", n.expr, strings.Join(a, ",")) + } + + if n.not { + return fmt.Sprintf("%s NOT IN (%s)", n.expr, n.sel) + } + + return fmt.Sprintf("%s IN (%s)", n.expr, n.sel) +} + +func (n *pIn) eval(execCtx *execCtx, ctx map[interface{}]interface{}, arg []interface{}) (v interface{}, err error) { + lhs, err := expand1(n.expr.eval(execCtx, ctx, arg)) + if err != nil { + return nil, err + } + + if lhs == nil { + return nil, nil //TODO Add test for NULL LHS. + } + + if n.sel == nil { + for _, v := range n.list { + b, err := newBinaryOperation(eq, value{lhs}, v) + if err != nil { + return nil, err + } + + eval, err := b.eval(execCtx, ctx, arg) + if err != nil { + return nil, err + } + + if x, ok := eval.(bool); ok && x { + return !n.not, nil + } + } + return n.not, nil + } + + if n.m == nil { // SELECT not yet evaluated. + r := n.sel.exec0() + n.m = map[interface{}]struct{}{} + ok := false + typechecked := false + if err := r.do(execCtx, false, func(id interface{}, data []interface{}) (more bool, err error) { + if typechecked { + if data[0] == nil { + return true, nil + } + + n.m[data[0]] = struct{}{} + } + + if ok { + if data[0] == nil { + return true, nil + } + + n.sample = data[0] + switch n.sample.(type) { + case bool, byte, complex128, complex64, float32, + float64, int16, int32, int64, int8, + string, uint16, uint32, uint64: + typechecked = true + n.m[n.sample] = struct{}{} + return true, nil + default: + return false, fmt.Errorf("IN (%s): invalid field type: %T", n.sel, data[0]) + } + + } + + flds := data[0].([]*fld) + if g, e := len(flds), 1; g != e { + return false, fmt.Errorf("IN (%s): mismatched field count, have %d, need %d", n.sel, g, e) + } + + ok = true + return true, nil + }); err != nil { + return nil, err + } + } + + if n.sample == nil { + return nil, nil + } + + _, ok := n.m[coerce1(lhs, n.sample)] + return ok != n.not, nil +} + +type value struct { + val interface{} +} + +func (l value) isStatic() bool { return true } + +func (l value) String() string { + switch x := l.val.(type) { + case nil: + return "NULL" + case string: + return fmt.Sprintf("%q", x) + default: + return fmt.Sprintf("%v", l.val) + } +} + +func (l value) eval(execCtx *execCtx, ctx map[interface{}]interface{}, _ []interface{}) (interface{}, error) { + return l.val, nil +} + +type conversion struct { + typ int + val expression +} + +func (c *conversion) isStatic() bool { + return c.val.isStatic() +} + +//LATER newConversion or fake unary op + +func (c *conversion) String() string { + return fmt.Sprintf("%s(%s)", typeStr(c.typ), c.val) +} + +func (c *conversion) eval(execCtx *execCtx, ctx map[interface{}]interface{}, arg []interface{}) (v interface{}, err error) { + val, err := expand1(c.val.eval(execCtx, ctx, arg)) + if err != nil { + return + } + + return convert(val, c.typ) +} + +type unaryOperation struct { + op int + v expression +} + +func newUnaryOperation(op int, x interface{}) (v expression, err error) { + l, ok := x.(expression) + if !ok { + log.Panic("internal error 038") + } + + u := unaryOperation{op, l} + if !l.isStatic() { + return &u, nil + } + + val, err := u.eval(nil, nil, nil) + if val == nil { + return value{nil}, nil + } + + return value{val}, err +} + +func (u *unaryOperation) isStatic() bool { return u.v.isStatic() } + +func (u *unaryOperation) String() string { return fmt.Sprintf("%s%s", iop(u.op), u.v) } + +// !ident +func (u *unaryOperation) isNotQIdent() (bool, string, expression) { + if u.op != '!' { + return false, "", nil + } + + id, ok := u.v.(*ident) + if ok && id.isQualified() { + return true, mustQualifier(id.s), &unaryOperation{'!', &ident{mustSelector(id.s)}} + } + + return false, "", nil +} + +func (u *unaryOperation) eval(execCtx *execCtx, ctx map[interface{}]interface{}, arg []interface{}) (r interface{}, err error) { + defer func() { + if e := recover(); e != nil { + switch x := e.(type) { + case error: + r, err = nil, x + default: + r, err = nil, fmt.Errorf("%v", x) + } + } + }() + + switch op := u.op; op { + case '!': + a := eval(u.v, execCtx, ctx, arg) + if a == nil { + return + } + + switch x := a.(type) { + case bool: + return !x, nil + default: + return undOp(a, op) + } + case '^': + a := eval(u.v, execCtx, ctx, arg) + if a == nil { + return + } + + switch x := a.(type) { + //case nil: + case idealComplex: + return undOp(a, op) + case idealFloat: + return undOp(a, op) + case idealInt: + return ^x, nil + case idealRune: + return ^x, nil + case idealUint: + return ^x, nil + case bool: + return undOp(a, op) + case complex64: + return undOp(a, op) + case complex128: + return undOp(a, op) + case float32: + return undOp(a, op) + case float64: + return undOp(a, op) + case int8: + return ^x, nil + case int16: + return ^x, nil + case int32: + return ^x, nil + case int64: + return ^x, nil + case string: + return undOp(a, op) + case uint8: + return ^x, nil + case uint16: + return ^x, nil + case uint32: + return ^x, nil + case uint64: + return ^x, nil + case *big.Int: + var z big.Int + return z.Not(x), nil + case time.Duration: + return ^x, nil + default: + return undOp(a, op) + } + case '+': + a := eval(u.v, execCtx, ctx, arg) + if a == nil { + return + } + + switch x := a.(type) { + //case nil: + case idealComplex: + return +x, nil + case idealFloat: + return +x, nil + case idealInt: + return +x, nil + case idealRune: + return +x, nil + case idealUint: + return +x, nil + case bool: + return undOp(a, op) + case complex64: + return +x, nil + case complex128: + return +x, nil + case float32: + return +x, nil + case float64: + return +x, nil + case int8: + return +x, nil + case int16: + return +x, nil + case int32: + return +x, nil + case int64: + return +x, nil + case string: + return undOp(a, op) + case uint8: + return +x, nil + case uint16: + return +x, nil + case uint32: + return +x, nil + case uint64: + return +x, nil + case *big.Int: + var z big.Int + return z.Set(x), nil + case *big.Rat: + var z big.Rat + return z.Set(x), nil + case time.Duration: + return x, nil + default: + return undOp(a, op) + } + case '-': + a := eval(u.v, execCtx, ctx, arg) + if a == nil { + return + } + + switch x := a.(type) { + //case nil: + case idealComplex: + return -x, nil + case idealFloat: + return -x, nil + case idealInt: + return -x, nil + case idealRune: + return -x, nil + case idealUint: + return -x, nil + case bool: + return undOp(a, op) + case complex64: + return -x, nil + case complex128: + return -x, nil + case float32: + return -x, nil + case float64: + return -x, nil + case int8: + return -x, nil + case int16: + return -x, nil + case int32: + return -x, nil + case int64: + return -x, nil + case string: + return undOp(a, op) + case uint8: + return -x, nil + case uint16: + return -x, nil + case uint32: + return -x, nil + case uint64: + return -x, nil + case *big.Int: + var z big.Int + return z.Neg(x), nil + case *big.Rat: + var z big.Rat + return z.Neg(x), nil + case time.Duration: + return -x, nil + default: + return undOp(a, op) + } + default: + log.Panic("internal error 039") + panic("unreachable") + } +} + +type call struct { + f string + arg []expression +} + +func newCall(f string, arg []expression) (v expression, isAgg bool, err error) { + x := builtin[f] + if x.f == nil { + return nil, false, fmt.Errorf("undefined: %s", f) + } + + isAgg = x.isAggregate + if g, min, max := len(arg), x.minArgs, x.maxArgs; g < min || g > max { + a := []interface{}{} + for _, v := range arg { + a = append(a, v) + } + return nil, false, badNArgs(min, f, a) + } + + c := call{f: f} + for _, val := range arg { + if !val.isStatic() { + c.arg = append(c.arg, val) + continue + } + + eval, err := val.eval(nil, nil, nil) + if err != nil { + return nil, isAgg, err + } + + c.arg = append(c.arg, value{eval}) + } + + return &c, isAgg, nil +} + +func (c *call) isStatic() bool { + v := builtin[c.f] + if v.f == nil || !v.isStatic { + return false + } + + for _, v := range c.arg { + if !v.isStatic() { + return false + } + } + return true +} + +func (c *call) String() string { + a := []string{} + for _, v := range c.arg { + a = append(a, v.String()) + } + return fmt.Sprintf("%s(%s)", c.f, strings.Join(a, ", ")) +} + +func (c *call) eval(execCtx *execCtx, ctx map[interface{}]interface{}, args []interface{}) (v interface{}, err error) { + f, ok := builtin[c.f] + if !ok { + return nil, fmt.Errorf("unknown function %s", c.f) + } + + isId := c.f == "id" + a := make([]interface{}, len(c.arg)) + for i, arg := range c.arg { + if v, err = expand1(arg.eval(execCtx, ctx, args)); err != nil { + if !isId { + return nil, err + } + + if _, ok := arg.(*ident); !ok { + return nil, err + } + + a[i] = arg + continue + } + + a[i] = v + } + + if ctx != nil { + ctx["$fn"] = c + } + return f.f(a, ctx) +} + +type parameter struct { + n int +} + +func (parameter) isStatic() bool { return false } + +func (p parameter) String() string { return fmt.Sprintf("$%d", p.n) } + +func (p parameter) eval(execCtx *execCtx, ctx map[interface{}]interface{}, arg []interface{}) (v interface{}, err error) { + i := p.n - 1 + if i < len(arg) { + return arg[i], nil + } + + return nil, fmt.Errorf("missing %s", p) +} + +//MAYBE make it an unary operation +type isNull struct { + expr expression + not bool +} + +//LATER newIsNull + +func (is *isNull) isStatic() bool { return is.expr.isStatic() } + +func (is *isNull) String() string { + if is.not { + return fmt.Sprintf("%s IS NOT NULL", is.expr) + } + + return fmt.Sprintf("%s IS NULL", is.expr) +} + +func (is *isNull) eval(execCtx *execCtx, ctx map[interface{}]interface{}, arg []interface{}) (v interface{}, err error) { + val, err := is.expr.eval(execCtx, ctx, arg) + if err != nil { + return + } + + return val == nil != is.not, nil +} + +type indexOp struct { + expr, x expression +} + +func newIndex(sv, xv expression) (v expression, err error) { + s, fs, i := "", false, uint64(0) + x := indexOp{sv, xv} + if x.expr.isStatic() { + v, err := x.expr.eval(nil, nil, nil) + if err != nil { + return nil, err + } + + if v == nil { + return value{nil}, nil + } + + if s, fs = v.(string); !fs { + return nil, invXOp(sv, xv) + } + + x.expr = value{s} + } + + if x.x.isStatic() { + v, err := x.x.eval(nil, nil, nil) + if err != nil { + return nil, err + } + + if v == nil { + return value{nil}, nil + } + + var p *string + if fs { + p = &s + } + if i, err = indexExpr(p, v); err != nil { + return nil, err + } + + x.x = value{i} + } + + return &x, nil +} + +func (x *indexOp) isStatic() bool { + return x.expr.isStatic() && x.x.isStatic() +} + +func (x *indexOp) String() string { return fmt.Sprintf("%s[%s]", x.expr, x.x) } + +func (x *indexOp) eval(execCtx *execCtx, ctx map[interface{}]interface{}, arg []interface{}) (v interface{}, err error) { + s0, err := x.expr.eval(execCtx, ctx, arg) + if err != nil { + return nil, runErr(err) + } + + s, ok := s0.(string) + if !ok { + return nil, runErr(invXOp(s0, x.x)) + } + + i0, err := x.x.eval(execCtx, ctx, arg) + if err != nil { + return nil, runErr(err) + } + + if i0 == nil { + return nil, nil + } + + i, err := indexExpr(&s, i0) + if err != nil { + return nil, runErr(err) + } + + return s[i], nil +} + +type slice struct { + expr expression + lo, hi *expression +} + +func newSlice(expr expression, lo, hi *expression) (v expression, err error) { + y := slice{expr, lo, hi} + var val interface{} + if e := y.expr; e.isStatic() { + if val, err = e.eval(nil, nil, nil); err != nil { + return nil, err + } + + if val == nil { + return value{nil}, nil + } + + y.expr = value{val} + } + + if p := y.lo; p != nil { + if e := *p; e.isStatic() { + if val, err = e.eval(nil, nil, nil); err != nil { + return nil, err + } + + if val == nil { + return value{nil}, nil + } + + v := expression(value{val}) + y.lo = &v + } + } + + if p := y.hi; p != nil { + if e := *p; e.isStatic() { + if val, err = e.eval(nil, nil, nil); err != nil { + return nil, err + } + + if val == nil { + return value{nil}, nil + } + + v := expression(value{val}) + y.hi = &v + } + } + return &y, nil +} + +func (s *slice) eval(execCtx *execCtx, ctx map[interface{}]interface{}, arg []interface{}) (v interface{}, err error) { + s0, err := s.expr.eval(execCtx, ctx, arg) + if err != nil { + return + } + + if s0 == nil { + return + } + + ss, ok := s0.(string) + if !ok { + return nil, runErr(invSOp(s0)) + } + + var iLo, iHi uint64 + if s.lo != nil { + i, err := (*s.lo).eval(execCtx, ctx, arg) + if err != nil { + return nil, err + } + + if i == nil { + return nil, err + } + + if iLo, err = sliceExpr(&ss, i, 0); err != nil { + return nil, err + } + } + + iHi = uint64(len(ss)) + if s.hi != nil { + i, err := (*s.hi).eval(execCtx, ctx, arg) + if err != nil { + return nil, err + } + + if i == nil { + return nil, err + } + + if iHi, err = sliceExpr(&ss, i, 1); err != nil { + return nil, err + } + } + + return ss[iLo:iHi], nil +} + +func (s *slice) isStatic() bool { + if !s.expr.isStatic() { + return false + } + + if p := s.lo; p != nil && !(*p).isStatic() { + return false + } + + if p := s.hi; p != nil && !(*p).isStatic() { + return false + } + + return false +} + +func (s *slice) String() string { + switch { + case s.lo == nil && s.hi == nil: + return fmt.Sprintf("%v[:]", s.expr) + case s.lo == nil && s.hi != nil: + return fmt.Sprintf("%v[:%v]", s.expr, *s.hi) + case s.lo != nil && s.hi == nil: + return fmt.Sprintf("%v[%v:]", s.expr, *s.lo) + default: //case s.lo != nil && s.hi != nil: + return fmt.Sprintf("%v[%v:%v]", s.expr, *s.lo, *s.hi) + } +} diff --git a/Godeps/_workspace/src/github.com/cznic/ql/file.go b/Godeps/_workspace/src/github.com/cznic/ql/file.go new file mode 100644 index 0000000..29d4324 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/ql/file.go @@ -0,0 +1,1258 @@ +// Copyright 2014 The ql Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Well known handles +// 1: root +// 2: id + +package ql + +import ( + "crypto/sha1" + "fmt" + "io" + "io/ioutil" + "log" + "math/big" + "os" + "path/filepath" + "sync" + "time" + + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/camlistore/lock" + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/exp/lldb" + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/mathutil" +) + +const ( + magic = "\x60\xdbql" +) + +var ( + _ btreeIndex = (*fileIndex)(nil) + _ btreeIterator = (*fileBTreeIterator)(nil) + _ indexIterator = (*fileIndexIterator)(nil) + _ storage = (*file)(nil) + _ temp = (*fileTemp)(nil) +) + +type chunk struct { // expanded to blob types lazily + f *file + b []byte +} + +func (c chunk) expand() (v interface{}, err error) { + return c.f.loadChunks(c.b) +} + +func expand1(data interface{}, e error) (v interface{}, err error) { + if e != nil { + return nil, e + } + + c, ok := data.(chunk) + if !ok { + return data, nil + } + + return c.expand() +} + +func expand(data []interface{}) (err error) { + for i, v := range data { + if data[i], err = expand1(v, nil); err != nil { + return + } + } + return +} + +// OpenFile returns a DB backed by a named file. The back end limits the size +// of a record to about 64 kB. +func OpenFile(name string, opt *Options) (db *DB, err error) { + var f lldb.OSFile + if f = opt.OSFile; f == nil { + f, err = os.OpenFile(name, os.O_RDWR, 0666) + if err != nil { + if !os.IsNotExist(err) { + return nil, err + } + + if !opt.CanCreate { + return nil, err + } + + f, err = os.OpenFile(name, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666) + if err != nil { + return nil, err + } + } + } + + fi, err := newFileFromOSFile(f) // always ACID + if err != nil { + return + } + + if fi.tempFile = opt.TempFile; fi.tempFile == nil { + fi.tempFile = func(dir, prefix string) (f lldb.OSFile, err error) { + f0, err := ioutil.TempFile(dir, prefix) + return f0, err + } + } + + return newDB(fi) +} + +// Options amend the behavior of OpenFile. +// +// CanCreate +// +// The CanCreate option enables OpenFile to create the DB file if it does not +// exists. +// +// OSFile +// +// OSFile allows to pass an os.File like back end providing, for example, +// encrypted storage. If this field is nil then OpenFile uses the file named by +// the 'name' parameter instead. +// +// TempFile +// +// TempFile provides a temporary file used for evaluating the GROUP BY, ORDER +// BY, ... clauses. The hook is intended to be used by encrypted DB back ends +// to avoid leaks of unecrypted data to such temp files by providing temp files +// which are encrypted as well. Note that *os.File satisfies the lldb.OSFile +// interface. +// +// If TempFile is nil it defaults to ioutil.TempFile. +type Options struct { + CanCreate bool + OSFile lldb.OSFile + TempFile func(dir, prefix string) (f lldb.OSFile, err error) +} + +type fileBTreeIterator struct { + en *lldb.BTreeEnumerator + t *fileTemp +} + +func (it *fileBTreeIterator) Next() (k, v []interface{}, err error) { + bk, bv, err := it.en.Next() + if err != nil { + return + } + + if k, err = lldb.DecodeScalars(bk); err != nil { + return + } + + for i, val := range k { + b, ok := val.([]byte) + if !ok { + continue + } + + c := chunk{it.t.file, b} + if k[i], err = c.expand(); err != nil { + return nil, nil, err + } + } + + if err = enforce(k, it.t.colsK); err != nil { + return + } + + if v, err = lldb.DecodeScalars(bv); err != nil { + return + } + + for i, val := range v { + b, ok := val.([]byte) + if !ok { + continue + } + + c := chunk{it.t.file, b} + if v[i], err = c.expand(); err != nil { + return nil, nil, err + } + } + + err = enforce(v, it.t.colsV) + return +} + +func enforce(val []interface{}, cols []*col) (err error) { + for i, v := range val { + if val[i], err = convert(v, cols[i].typ); err != nil { + return + } + } + return +} + +//NTYPE +func infer(from []interface{}, to *[]*col) { + if len(*to) == 0 { + *to = make([]*col, len(from)) + for i := range *to { + (*to)[i] = &col{} + } + } + for i, c := range *to { + if f := from[i]; f != nil { + switch x := f.(type) { + //case nil: + case idealComplex: + c.typ = qComplex128 + from[i] = complex128(x) + case idealFloat: + c.typ = qFloat64 + from[i] = float64(x) + case idealInt: + c.typ = qInt64 + from[i] = int64(x) + case idealRune: + c.typ = qInt32 + from[i] = int32(x) + case idealUint: + c.typ = qUint64 + from[i] = uint64(x) + case bool: + c.typ = qBool + case complex128: + c.typ = qComplex128 + case complex64: + c.typ = qComplex64 + case float64: + c.typ = qFloat64 + case float32: + c.typ = qFloat32 + case int8: + c.typ = qInt8 + case int16: + c.typ = qInt16 + case int32: + c.typ = qInt32 + case int64: + c.typ = qInt64 + case string: + c.typ = qString + case uint8: + c.typ = qUint8 + case uint16: + c.typ = qUint16 + case uint32: + c.typ = qUint32 + case uint64: + c.typ = qUint64 + case []byte: + c.typ = qBlob + case *big.Int: + c.typ = qBigInt + case *big.Rat: + c.typ = qBigRat + case time.Time: + c.typ = qTime + case time.Duration: + c.typ = qDuration + case chunk: + vals, err := lldb.DecodeScalars([]byte(x.b)) + if err != nil { + log.Panic("err") + } + + if len(vals) == 0 { + log.Panic("internal error 040") + } + + i, ok := vals[0].(int64) + if !ok { + log.Panic("internal error 041") + } + + c.typ = int(i) + case map[string]interface{}: // map of ids of a cross join + default: + log.Panic("internal error 042") + } + } + } +} + +type fileTemp struct { + *file + colsK []*col + colsV []*col + t *lldb.BTree +} + +func (t *fileTemp) BeginTransaction() error { + return nil +} + +func (t *fileTemp) Get(k []interface{}) (v []interface{}, err error) { + if err = expand(k); err != nil { + return + } + + if err = t.flatten(k); err != nil { + return nil, err + } + + bk, err := lldb.EncodeScalars(k...) + if err != nil { + return + } + + bv, err := t.t.Get(nil, bk) + if err != nil { + return + } + + return lldb.DecodeScalars(bv) +} + +func (t *fileTemp) Drop() (err error) { + if t.f0 == nil { + return + } + + fn := t.f0.Name() + if err = t.f0.Close(); err != nil { + return + } + + if fn == "" { + return + } + + return os.Remove(fn) +} + +func (t *fileTemp) SeekFirst() (it btreeIterator, err error) { + en, err := t.t.SeekFirst() + if err != nil { + return + } + + return &fileBTreeIterator{t: t, en: en}, nil +} + +func (t *fileTemp) Set(k, v []interface{}) (err error) { + if err = expand(k); err != nil { + return + } + + if err = expand(v); err != nil { + return + } + + infer(k, &t.colsK) + infer(v, &t.colsV) + + if err = t.flatten(k); err != nil { + return + } + + bk, err := lldb.EncodeScalars(k...) + if err != nil { + return + } + + if err = t.flatten(v); err != nil { + return + } + + bv, err := lldb.EncodeScalars(v...) + if err != nil { + return + } + + return t.t.Set(bk, bv) +} + +type file struct { + a *lldb.Allocator + codec *gobCoder + f lldb.Filer + f0 lldb.OSFile + id int64 + lck io.Closer + mu sync.Mutex + name string + tempFile func(dir, prefix string) (f lldb.OSFile, err error) + wal *os.File +} + +func newFileFromOSFile(f lldb.OSFile) (fi *file, err error) { + nm := lockName(f.Name()) + lck, err := lock.Lock(nm) + if err != nil { + if lck != nil { + lck.Close() + } + return nil, err + } + + close := true + defer func() { + if close && lck != nil { + lck.Close() + } + }() + + var w *os.File + closew := false + wn := walName(f.Name()) + w, err = os.OpenFile(wn, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666) + closew = true + defer func() { + if closew { + nm := w.Name() + w.Close() + os.Remove(nm) + w = nil + } + }() + + if err != nil { + if !os.IsExist(err) { + return nil, err + } + + closew = false + w, err = os.OpenFile(wn, os.O_RDWR, 0666) + if err != nil { + return nil, err + } + + closew = true + st, err := w.Stat() + if err != nil { + return nil, err + } + + if st.Size() != 0 { + return nil, fmt.Errorf("(file-001) non empty WAL file %s exists", wn) + } + } + + info, err := f.Stat() + if err != nil { + return nil, err + } + + switch sz := info.Size(); { + case sz == 0: + b := make([]byte, 16) + copy(b, []byte(magic)) + if _, err := f.Write(b); err != nil { + return nil, err + } + + filer := lldb.Filer(lldb.NewOSFiler(f)) + filer = lldb.NewInnerFiler(filer, 16) + if filer, err = lldb.NewACIDFiler(filer, w); err != nil { + return nil, err + } + + a, err := lldb.NewAllocator(filer, &lldb.Options{}) + if err != nil { + return nil, err + } + + a.Compress = true + s := &file{ + a: a, + codec: newGobCoder(), + f0: f, + f: filer, + lck: lck, + name: f.Name(), + wal: w, + } + if err = s.BeginTransaction(); err != nil { + return nil, err + } + + h, err := s.Create() + if err != nil { + return nil, err + } + + if h != 1 { // root + log.Panic("internal error 043") + } + + if h, err = s.a.Alloc(make([]byte, 8)); err != nil { + return nil, err + } + + if h != 2 { // id + log.Panic("internal error 044") + } + + close, closew = false, false + return s, s.Commit() + default: + b := make([]byte, 16) + if _, err := f.Read(b); err != nil { + return nil, err + } + + if string(b[:len(magic)]) != magic { + return nil, fmt.Errorf("(file-002) unknown file format") + } + + filer := lldb.Filer(lldb.NewOSFiler(f)) + filer = lldb.NewInnerFiler(filer, 16) + if filer, err = lldb.NewACIDFiler(filer, w); err != nil { + return nil, err + } + + a, err := lldb.NewAllocator(filer, &lldb.Options{}) + if err != nil { + return nil, err + } + + bid, err := a.Get(nil, 2) // id + if err != nil { + return nil, err + } + + if len(bid) != 8 { + return nil, fmt.Errorf("(file-003) corrupted DB: id |% x|", bid) + } + + id := int64(0) + for _, v := range bid { + id = (id << 8) | int64(v) + } + + a.Compress = true + s := &file{ + a: a, + codec: newGobCoder(), + f0: f, + f: filer, + id: id, + lck: lck, + name: f.Name(), + wal: w, + } + + close, closew = false, false + return s, nil + } +} + +func (s *file) OpenIndex(unique bool, handle int64) (btreeIndex, error) { + t, err := lldb.OpenBTree(s.a, s.collate, handle) + if err != nil { + return nil, err + } + + return &fileIndex{s, handle, t, unique}, nil +} + +func (s *file) CreateIndex(unique bool) ( /* handle */ int64, btreeIndex, error) { + t, h, err := lldb.CreateBTree(s.a, s.collate) + if err != nil { + return -1, nil, err + } + + return h, &fileIndex{s, h, t, unique}, nil +} + +func (s *file) Acid() bool { return s.wal != nil } + +func errSet(p *error, errs ...error) (err error) { + err = *p + for _, e := range errs { + if err != nil { + return + } + *p, err = e, e + } + return +} + +func (s *file) lock() func() { + s.mu.Lock() + return s.mu.Unlock +} + +func (s *file) Close() (err error) { + defer s.lock()() + + es := s.f0.Sync() + ef := s.f0.Close() + var ew error + if s.wal != nil { + ew = s.wal.Close() + } + el := s.lck.Close() + return errSet(&err, es, ef, ew, el) +} + +func (s *file) Name() string { return s.name } + +func (s *file) Verify() (allocs int64, err error) { + defer s.lock()() + var stat lldb.AllocStats + if err = s.a.Verify(lldb.NewMemFiler(), nil, &stat); err != nil { + return + } + + allocs = stat.AllocAtoms + return +} + +func (s *file) expandBytes(d []interface{}) (err error) { + for i, v := range d { + b, ok := v.([]byte) + if !ok { + continue + } + + d[i], err = s.loadChunks(b) + if err != nil { + return + } + } + return +} + +func (s *file) collate(a, b []byte) int { //TODO w/ error return + da, err := lldb.DecodeScalars(a) + if err != nil { + log.Panic(err) + } + + if err = s.expandBytes(da); err != nil { + log.Panic(err) + } + + db, err := lldb.DecodeScalars(b) + if err != nil { + log.Panic(err) + } + + if err = s.expandBytes(db); err != nil { + log.Panic(err) + } + + return collate(da, db) +} + +func (s *file) CreateTemp(asc bool) (bt temp, err error) { + f, err := s.tempFile("", "ql-tmp-") + if err != nil { + return nil, err + } + + fn := f.Name() + filer := lldb.NewOSFiler(f) + a, err := lldb.NewAllocator(filer, &lldb.Options{}) + if err != nil { + f.Close() + os.Remove(fn) + return nil, err + } + + k := 1 + if !asc { + k = -1 + } + + t, _, err := lldb.CreateBTree(a, func(a, b []byte) int { //TODO w/ error return + return k * s.collate(a, b) + }) + if err != nil { + f.Close() + if fn != "" { + os.Remove(fn) + } + return nil, err + } + + x := &fileTemp{file: &file{ + a: a, + codec: newGobCoder(), + f0: f, + }, + t: t} + return x, nil +} + +func (s *file) BeginTransaction() (err error) { + defer s.lock()() + return s.f.BeginUpdate() +} + +func (s *file) Rollback() (err error) { + defer s.lock()() + return s.f.Rollback() +} + +func (s *file) Commit() (err error) { + defer s.lock()() + return s.f.EndUpdate() +} + +func (s *file) Create(data ...interface{}) (h int64, err error) { + if err = expand(data); err != nil { + return + } + + if err = s.flatten(data); err != nil { + return + } + + b, err := lldb.EncodeScalars(data...) + if err != nil { + return + } + + defer s.lock()() + return s.a.Alloc(b) +} + +func (s *file) Delete(h int64, blobCols ...*col) (err error) { + switch len(blobCols) { + case 0: + defer s.lock()() + return s.a.Free(h) + default: + return s.free(h, blobCols) + } +} + +func (s *file) ResetID() (err error) { + s.id = 0 + return +} + +func (s *file) ID() (int64, error) { + defer s.lock()() + + s.id++ + b := make([]byte, 8) + id := s.id + for i := 7; i >= 0; i-- { + b[i] = byte(id) + id >>= 8 + } + + return s.id, s.a.Realloc(2, b) +} + +func (s *file) free(h int64, blobCols []*col) (err error) { + s.mu.Lock() + b, err := s.a.Get(nil, h) //LATER +bufs + s.mu.Unlock() + if err != nil { + return + } + + rec, err := lldb.DecodeScalars(b) + if err != nil { + return + } + + for _, col := range blobCols { + if col.index >= len(rec) { + return fmt.Errorf("(file-004) file.free: corrupted DB (record len)") + } + + switch x := rec[col.index+2].(type) { + case nil: + // nop + case []byte: + if err = s.freeChunks(x); err != nil { + return + } + } + } + defer s.lock()() + return s.a.Free(h) +} + +func (s *file) Read(dst []interface{}, h int64, cols ...*col) (data []interface{}, err error) { //NTYPE + s.mu.Lock() + b, err := s.a.Get(nil, h) //LATER +bufs + s.mu.Unlock() + if err != nil { + return + } + + rec, err := lldb.DecodeScalars(b) + if err != nil { + return + } + + for _, col := range cols { + i := col.index + 2 + switch col.typ { + case 0: + case qBool: + case qComplex64: + rec[i] = complex64(rec[i].(complex128)) + case qComplex128: + case qFloat32: + rec[i] = float32(rec[i].(float64)) + case qFloat64: + case qInt8: + rec[i] = int8(rec[i].(int64)) + case qInt16: + rec[i] = int16(rec[i].(int64)) + case qInt32: + rec[i] = int32(rec[i].(int64)) + case qInt64: + case qString: + case qUint8: + rec[i] = uint8(rec[i].(uint64)) + case qUint16: + rec[i] = uint16(rec[i].(uint64)) + case qUint32: + rec[i] = uint32(rec[i].(uint64)) + case qUint64: + case qBlob, qBigInt, qBigRat, qTime, qDuration: + switch x := rec[i].(type) { + case nil: + rec[i] = nil + case []byte: + rec[i] = chunk{f: s, b: x} + default: + return nil, fmt.Errorf("(file-006) corrupted DB: non nil chunk type is not []byte") + } + default: + log.Panic("internal error 045") + } + } + + if cols != nil { + for n, dn := len(cols)+2, len(rec); dn < n; dn++ { + rec = append(rec, nil) + } + } + + return rec, nil +} + +func (s *file) freeChunks(enc []byte) (err error) { + items, err := lldb.DecodeScalars(enc) + if err != nil { + return + } + + var ok bool + var next int64 + switch len(items) { + case 2: + return + case 3: + if next, ok = items[1].(int64); !ok || next == 0 { + return fmt.Errorf("(file-007) corrupted DB: first chunk link") + } + default: + return fmt.Errorf("(file-008) corrupted DB: first chunk") + } + + for next != 0 { + s.mu.Lock() + b, err := s.a.Get(nil, next) + s.mu.Unlock() + if err != nil { + return err + } + + if items, err = lldb.DecodeScalars(b); err != nil { + return err + } + + var h int64 + switch len(items) { + case 1: + // nop + case 2: + if h, ok = items[0].(int64); !ok { + return fmt.Errorf("(file-009) corrupted DB: chunk link") + } + + default: + return fmt.Errorf("(file-010) corrupted DB: chunk items %d (%v)", len(items), items) + } + + s.mu.Lock() + if err = s.a.Free(next); err != nil { + s.mu.Unlock() + return err + } + + s.mu.Unlock() + next = h + } + return +} + +func (s *file) loadChunks(enc []byte) (v interface{}, err error) { + items, err := lldb.DecodeScalars(enc) + if err != nil { + return + } + + var ok bool + var next int64 + switch len(items) { + case 2: + // nop + case 3: + if next, ok = items[1].(int64); !ok || next == 0 { + return nil, fmt.Errorf("(file-011) corrupted DB: first chunk link") + } + default: + //fmt.Printf("%d: %#v\n", len(items), items) + return nil, fmt.Errorf("(file-012) corrupted DB: first chunk") + } + + typ, ok := items[0].(int64) + if !ok { + return nil, fmt.Errorf("(file-013) corrupted DB: first chunk tag") + } + + buf, ok := items[len(items)-1].([]byte) + if !ok { + return nil, fmt.Errorf("(file-014) corrupted DB: first chunk data") + } + + for next != 0 { + s.mu.Lock() + b, err := s.a.Get(nil, next) + s.mu.Unlock() + if err != nil { + return nil, err + } + + if items, err = lldb.DecodeScalars(b); err != nil { + return nil, err + } + + switch len(items) { + case 1: + next = 0 + case 2: + if next, ok = items[0].(int64); !ok { + return nil, fmt.Errorf("(file-015) corrupted DB: chunk link") + } + + items = items[1:] + default: + return nil, fmt.Errorf("(file-016) corrupted DB: chunk items %d (%v)", len(items), items) + } + + if b, ok = items[0].([]byte); !ok { + return nil, fmt.Errorf("(file-017) corrupted DB: chunk data") + } + + buf = append(buf, b...) + } + return s.codec.decode(buf, int(typ)) +} + +func (s *file) Update(h int64, data ...interface{}) (err error) { + b, err := lldb.EncodeScalars(data...) + if err != nil { + return + } + + defer s.lock()() + return s.a.Realloc(h, b) +} + +func (s *file) UpdateRow(h int64, blobCols []*col, data ...interface{}) (err error) { + if len(blobCols) == 0 { + return s.Update(h, data...) + } + + if err = expand(data); err != nil { + return + } + + data0, err := s.Read(nil, h, blobCols...) + if err != nil { + return + } + + for _, c := range blobCols { + if err = s.freeChunks(data0[c.index+2].(chunk).b); err != nil { + return + } + } + + if err = s.flatten(data); err != nil { + return + } + + return s.Update(h, data...) +} + +// []interface{}{qltype, ...}->[]interface{}{lldb scalar type, ...} +// + long blobs are (pre)written to a chain of chunks. +func (s *file) flatten(data []interface{}) (err error) { + for i, v := range data { + tag := 0 + var b []byte + switch x := v.(type) { + case []byte: + tag = qBlob + b = x + case *big.Int: + tag = qBigInt + b, err = s.codec.encode(x) + case *big.Rat: + tag = qBigRat + b, err = s.codec.encode(x) + case time.Time: + tag = qTime + b, err = s.codec.encode(x) + case time.Duration: + tag = qDuration + b, err = s.codec.encode(x) + default: + continue + } + if err != nil { + return + } + + const chunk = 1 << 16 + chunks := 0 + var next int64 + var buf []byte + for rem := len(b); rem > shortBlob; { + n := mathutil.Min(rem, chunk) + part := b[rem-n:] + b = b[:rem-n] + rem -= n + switch next { + case 0: // last chunk + buf, err = lldb.EncodeScalars([]interface{}{part}...) + default: // middle chunk + buf, err = lldb.EncodeScalars([]interface{}{next, part}...) + } + if err != nil { + return + } + + s.mu.Lock() + h, err := s.a.Alloc(buf) + s.mu.Unlock() + if err != nil { + return err + } + + next = h + chunks++ + } + + switch next { + case 0: // single chunk + buf, err = lldb.EncodeScalars([]interface{}{tag, b}...) + default: // multi chunks + buf, err = lldb.EncodeScalars([]interface{}{tag, next, b}...) + } + if err != nil { + return + } + + data[i] = buf + } + return +} + +func lockName(dbname string) string { + base := filepath.Base(filepath.Clean(dbname)) + "lockfile" + h := sha1.New() + io.WriteString(h, base) + return filepath.Join(filepath.Dir(dbname), fmt.Sprintf(".%x", h.Sum(nil))) +} + +func walName(dbname string) (r string) { + base := filepath.Base(filepath.Clean(dbname)) + h := sha1.New() + io.WriteString(h, base) + return filepath.Join(filepath.Dir(dbname), fmt.Sprintf(".%x", h.Sum(nil))) +} + +type fileIndex struct { + f *file + h int64 + t *lldb.BTree + unique bool +} + +func (x *fileIndex) Clear() error { + return x.t.Clear() +} + +var gbZeroInt64 []byte + +func init() { + var err error + if gbZeroInt64, err = lldb.EncodeScalars(int64(0)); err != nil { + panic(err) + } +} + +// The []byte version of the key in the BTree shares chunks, if any, with +// the value stored in the record. +func (x *fileIndex) Create(indexedValue interface{}, h int64) error { + t := x.t + switch { + case !x.unique: + k, err := lldb.EncodeScalars(indexedValue, h) + if err != nil { + return err + } + + return t.Set(k, gbZeroInt64) + case indexedValue == nil: // unique, NULL + k, err := lldb.EncodeScalars(nil, h) + if err != nil { + return err + } + + return t.Set(k, gbZeroInt64) + default: // unique, non NULL + k, err := lldb.EncodeScalars(indexedValue, int64(0)) + if err != nil { + return err + } + + v, err := lldb.EncodeScalars(h) + if err != nil { + return err + } + + _, _, err = t.Put(nil, k, func(key, old []byte) (new []byte, write bool, err error) { + if old == nil { + return v, true, nil + } + + return nil, false, fmt.Errorf("(file-018) cannot insert into unique index: duplicate value: %v", indexedValue) + }) + return err + } +} + +func (x *fileIndex) Delete(indexedValue interface{}, h int64) error { + chunk, ok := indexedValue.(chunk) + if ok { + indexedValue = chunk.b + } + + t := x.t + var k []byte + var err error + switch { + case !x.unique: + k, err = lldb.EncodeScalars(indexedValue, h) + case indexedValue == nil: // unique, NULL + k, err = lldb.EncodeScalars(nil, h) + default: // unique, non NULL + k, err = lldb.EncodeScalars(indexedValue, int64(0)) + } + if err != nil { + return err + } + + return t.Delete(k) +} + +func (x *fileIndex) Drop() error { + if err := x.Clear(); err != nil { + return err + } + + return x.f.a.Free(x.h) +} + +func (x *fileIndex) Seek(indexedValue interface{}) (indexIterator, bool, error) { //TODO(indices) blobs: +test + k, err := lldb.EncodeScalars(indexedValue, 0) + if err != nil { + return nil, false, err + } + + en, hit, err := x.t.Seek(k) + if err != nil { + return nil, false, err + } + + return &fileIndexIterator{x.f, en, x.unique}, hit, nil +} + +func (x *fileIndex) SeekFirst() (iter indexIterator, err error) { + en, err := x.t.SeekFirst() + return &fileIndexIterator{x.f, en, x.unique}, err +} + +func (x *fileIndex) SeekLast() (iter indexIterator, err error) { + en, err := x.t.SeekLast() + return &fileIndexIterator{x.f, en, x.unique}, err +} + +type fileIndexIterator struct { + f *file + en *lldb.BTreeEnumerator + unique bool +} + +func (i *fileIndexIterator) nextPrev(f func() ([]byte, []byte, error)) (interface{}, int64, error) { //TODO(indices) blobs: +test + bk, bv, err := f() + if err != nil { + return nil, -1, err + } + + dk, err := lldb.DecodeScalars(bk) + if err != nil { + return nil, -1, err + } + + b, ok := dk[0].([]byte) + if ok { + dk[0] = chunk{i.f, b} + if expand(dk[:1]); err != nil { + return nil, -1, err + } + } + + var k indexKey + k.value = dk[0] + switch i.unique { + case true: + if k.value == nil { + return nil, dk[1].(int64), nil + } + + dv, err := lldb.DecodeScalars(bv) + if err != nil { + return nil, -1, err + } + + return k.value, dv[0].(int64), nil + default: + return k.value, dk[1].(int64), nil + } +} + +func (i *fileIndexIterator) Next() (interface{}, int64, error) { //TODO(indices) blobs: +test + return i.nextPrev(i.en.Next) +} + +func (i *fileIndexIterator) Prev() (interface{}, int64, error) { //TODO(indices) blobs: +test + return i.nextPrev(i.en.Prev) +} diff --git a/Godeps/_workspace/src/github.com/cznic/ql/helper.go b/Godeps/_workspace/src/github.com/cznic/ql/helper.go new file mode 100644 index 0000000..a21a461 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/ql/helper.go @@ -0,0 +1,338 @@ +// +build ignore + +// Copyright 2014 The ql 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 main + +import ( + "bufio" + "flag" + "fmt" + "io" + "log" + "os" +) + +type t int + +const ( + qNil t = iota + idealComplex + idealFloat + idealInt + idealRune + idealUint + qBool + qComplex64 + qComplex128 + qFloat32 + qFloat64 + qInt8 + qInt16 + qInt32 + qInt64 + qString + qUint8 + qUint16 + qUint32 + qUint64 + qBigInt + qBigRat + qTime + qDuration + + qEnd +) + +func (n t) String() string { + switch n { + case qNil: + return "nil" + case idealComplex: + return "idealComplex" + case idealFloat: + return "idealFloat" + case idealInt: + return "idealInt" + case idealRune: + return "idealRune" + case idealUint: + return "idealUint" + case qBool: + return "bool" + case qComplex64: + return "complex64" + case qComplex128: + return "complex128" + case qFloat32: + return "float32" + case qFloat64: + return "float64" + case qInt8: + return "int8" + case qInt16: + return "int16" + case qInt32: + return "int32" + case qInt64: + return "int64" + case qString: + return "string" + case qUint8: + return "uint8" + case qUint16: + return "uint16" + case qUint32: + return "uint32" + case qUint64: + return "uint64" + case qBigInt: + return "*big.Int" + case qBigRat: + return "*big.Rat" + case qTime: + return "time.Time" + case qDuration: + return "time.Duration" + default: + panic("internal error 046") + } +} + +func coerceIdealComplex(typ t) string { + switch typ { + case qComplex64, qComplex128: + return fmt.Sprintf("return %s(x)\n", typ) + default: + return "" + } +} + +func coerceIdealFloat(typ t) string { + switch typ { + case idealComplex: + return fmt.Sprintf("return %s(complex(float64(x), 0))\n", typ) + case qComplex64: + return fmt.Sprintf("return %s(complex(float32(x), 0))\n", typ) + case qComplex128: + return fmt.Sprintf("return %s(complex(float64(x), 0))\n", typ) + case idealFloat, qFloat32, qFloat64: + return fmt.Sprintf("return %s(float64(x))\n", typ) + case qBigRat: + return fmt.Sprintf("return big.NewRat(1, 1).SetFloat64(float64(x))\n") + default: + return "" + } + return "" +} + +func coerceIdealInt(typ t) string { + switch typ { + case idealComplex: + return fmt.Sprintf("return %s(complex(float64(x), 0))\n", typ) + case qComplex64: + return fmt.Sprintf("return %s(complex(float32(x), 0))\n", typ) + case qComplex128: + return fmt.Sprintf("return %s(complex(float64(x), 0))\n", typ) + case idealFloat, idealInt, qFloat32, qFloat64, qInt64: + return fmt.Sprintf("return %s(int64(x))\n", typ) + case idealUint: + return fmt.Sprintf("if x >= 0 { return %s(int64(x)) }\n", typ) + case qInt8: + return fmt.Sprintf("if x >= math.MinInt8 && x<= math.MaxInt8 { return %s(int64(x)) }\n", typ) + case qInt16: + return fmt.Sprintf("if x >= math.MinInt16 && x<= math.MaxInt16 { return %s(int64(x)) }\n", typ) + case qInt32: + return fmt.Sprintf("if x >= math.MinInt32 && x<= math.MaxInt32 { return %s(int64(x)) }\n", typ) + case qUint8: + return fmt.Sprintf("if x >= 0 && x<= math.MaxUint8 { return %s(int64(x)) }\n", typ) + case qUint16: + return fmt.Sprintf("if x >= 0 && x<= math.MaxUint16 { return %s(int64(x)) }\n", typ) + case qUint32: + return fmt.Sprintf("if x >= 0 && x<= math.MaxUint32 { return %s(int64(x)) }\n", typ) + case qUint64: + return fmt.Sprintf("if x >= 0 { return %s(int64(x)) }\n", typ) + case qBigInt: + return fmt.Sprintf("return big.NewInt(int64(x))\n") + case qBigRat: + return fmt.Sprintf("return big.NewRat(1, 1).SetInt64(int64(x))\n") + case qDuration: + return fmt.Sprintf("return time.Duration(int64(x))\n") + default: + return "" + } + return "" +} + +func coerceIdealRune(typ t) string { + switch typ { + case idealComplex: + return fmt.Sprintf("return %s(complex(float64(x), 0))\n", typ) + case qComplex64: + return fmt.Sprintf("return %s(complex(float32(x), 0))\n", typ) + case qComplex128: + return fmt.Sprintf("return %s(complex(float64(x), 0))\n", typ) + case idealFloat, idealInt, idealRune, idealUint, qFloat32, qFloat64, qInt8, qInt16, qInt32, qInt64, qUint8, qUint16, qUint32, qUint64: + return fmt.Sprintf("return %s(int64(x))\n", typ) + case qBigInt: + return fmt.Sprintf("return big.NewInt(int64(x))\n") + case qBigRat: + return fmt.Sprintf("return big.NewRat(1, 1).SetInt64(int64(x))\n") + case qDuration: + return fmt.Sprintf("return time.Duration(int64(x))\n") + default: + return "" + } + return "" +} + +func coerceIdealUint(typ t) string { + switch typ { + case idealComplex: + return fmt.Sprintf("return %s(complex(float64(x), 0))\n", typ) + case qComplex64: + return fmt.Sprintf("return %s(complex(float32(x), 0))\n", typ) + case qComplex128: + return fmt.Sprintf("return %s(complex(float64(x), 0))\n", typ) + case idealFloat, idealUint, qFloat32, qFloat64, qUint64: + return fmt.Sprintf("return %s(uint64(x))\n", typ) + case idealInt: + return fmt.Sprintf("if x <= math.MaxInt64 { return %s(int64(x)) }\n", typ) + case qInt8: + return fmt.Sprintf("if x <= math.MaxInt8 { return %s(int64(x)) }\n", typ) + case qInt16: + return fmt.Sprintf("if x<= math.MaxInt16 { return %s(int64(x)) }\n", typ) + case qInt32: + return fmt.Sprintf("if x<= math.MaxInt32 { return %s(int64(x)) }\n", typ) + case qInt64: + return fmt.Sprintf("if x<= math.MaxInt64 { return %s(int64(x)) }\n", typ) + case qUint8: + return fmt.Sprintf("if x >= 0 && x<= math.MaxUint8 { return %s(int64(x)) }\n", typ) + case qUint16: + return fmt.Sprintf("if x >= 0 && x<= math.MaxUint16 { return %s(int64(x)) }\n", typ) + case qUint32: + return fmt.Sprintf("if x >= 0 && x<= math.MaxUint32 { return %s(int64(x)) }\n", typ) + case qBigInt: + return fmt.Sprintf("return big.NewInt(0).SetUint64(uint64(x))\n") + case qBigRat: + return fmt.Sprintf("return big.NewRat(1, 1).SetInt(big.NewInt(0).SetUint64(uint64(x)))\n") + case qDuration: + return fmt.Sprintf("if x <= math.MaxInt64 { return time.Duration(int64(x)) }\n") + default: + return "" + } + return "" +} + +func genCoerce1(w io.Writer, in t, f func(out t) string) { + fmt.Fprintf(w, "\tcase %s:\n", in) + fmt.Fprintf(w, "\t\tswitch otherVal.(type) {\n") + + for i := idealComplex; i < qEnd; i++ { + s := f(i) + switch s { + case "": + fmt.Fprintf(w, "\t\t//case %s:\n", i) + default: + fmt.Fprintf(w, "\t\tcase %s:\n", i) + fmt.Fprintf(w, "\t\t\t%s", s) + } + } + + fmt.Fprintf(w, "\t\t}\n") // switch +} + +func genCoerce(w io.Writer) { + fmt.Fprintf(w, + ` +func coerce1(inVal, otherVal interface{}) (coercedInVal interface{}) { + coercedInVal = inVal + if otherVal == nil { + return + } + + switch x := inVal.(type) { + case nil: + return +`) + genCoerce1(w, idealComplex, coerceIdealComplex) + genCoerce1(w, idealFloat, coerceIdealFloat) + genCoerce1(w, idealInt, coerceIdealInt) + genCoerce1(w, idealRune, coerceIdealRune) + genCoerce1(w, idealUint, coerceIdealUint) + fmt.Fprintf(w, "\t}\n") // switch + + fmt.Fprintf(w, "\treturn\n}\n") // func +} + +func main() { + ofn := flag.String("o", "", "") + flag.Parse() + _, err := os.Stat(*ofn) + if err == nil { + log.Fatalf("%s exists", *ofn) + } + + w := bufio.NewWriter(os.Stdout) + if s := *ofn; s != "" { + f, err := os.Create(s) + if err != nil { + log.Fatal(err) + } + + defer f.Close() + w = bufio.NewWriter(f) + } + defer w.Flush() + + fmt.Fprintf(w, `// Copyright 2013 The ql Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// CAUTION: This file was generated automatically by +// +// $ go run helper -o coerce.go +// +// DO NOT EDIT! + + package ql + +import ( + "math" + "math/big" + "reflect" + "time" +) + +func coerce(a, b interface{}) (x, y interface{}) { + if reflect.TypeOf(a) == reflect.TypeOf(b) { + return a, b + } + + switch a.(type) { + case idealComplex, idealFloat, idealInt, idealRune, idealUint: + switch b.(type) { + case idealComplex, idealFloat, idealInt, idealRune, idealUint: + x, y = coerce1(a, b), b + if reflect.TypeOf(x) == reflect.TypeOf(y) { + return + } + + return a, coerce1(b, a) + default: + return coerce1(a, b), b + } + default: + switch b.(type) { + case idealComplex, idealFloat, idealInt, idealRune, idealUint: + return a, coerce1(b, a) + default: + return a, b + } + } +} +`) + genCoerce(w) +} diff --git a/Godeps/_workspace/src/github.com/cznic/ql/httpfs.go b/Godeps/_workspace/src/github.com/cznic/ql/httpfs.go new file mode 100644 index 0000000..f62c2da --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/ql/httpfs.go @@ -0,0 +1,302 @@ +// Copyright (c) 2014 ql 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 ql + +import ( + "fmt" + "io" + "net/http" + "os" + "path" + "path/filepath" + "strings" + "time" + + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/mathutil" +) + +var ( + _ http.FileSystem = (*HTTPFS)(nil) + _ http.File = (*HTTPFile)(nil) + _ os.FileInfo = (*HTTPFile)(nil) + _ os.FileInfo = (*dirEntry)(nil) +) + +type dirEntry string + +func (d dirEntry) Name() string { return string(d) } +func (d dirEntry) Size() int64 { return -1 } +func (d dirEntry) Mode() os.FileMode { return os.ModeDir } +func (d dirEntry) ModTime() time.Time { return time.Time{} } +func (d dirEntry) IsDir() bool { return true } +func (d dirEntry) Sys() interface{} { return interface{}(nil) } + +// A HTTPFile is returned by the HTTPFS's Open method and can be served by the +// http.FileServer implementation. +type HTTPFile struct { + closed bool + content []byte + dirEntries []os.FileInfo + isFile bool + name string + off int + sz int +} + +// Close implements http.File. +func (f *HTTPFile) Close() error { + if f.closed { + return os.ErrInvalid + } + + f.closed = true + return nil +} + +// IsDir implements os.FileInfo +func (f *HTTPFile) IsDir() bool { return !f.isFile } + +// Mode implements os.FileInfo +func (f *HTTPFile) Mode() os.FileMode { + switch f.isFile { + case false: + return os.FileMode(0444) + default: + return os.ModeDir + } +} + +// ModTime implements os.FileInfo +func (f *HTTPFile) ModTime() time.Time { + return time.Time{} +} + +// Name implements os.FileInfo +func (f *HTTPFile) Name() string { return path.Base(f.name) } + +// Size implements os.FileInfo +func (f *HTTPFile) Size() int64 { + switch f.isFile { + case false: + return -1 + default: + return int64(len(f.content)) + } +} + +// Stat implements http.File. +func (f *HTTPFile) Stat() (os.FileInfo, error) { return f, nil } + +// Sys implements os.FileInfo +func (f *HTTPFile) Sys() interface{} { return interface{}(nil) } + +// Readdir implements http.File. +func (f *HTTPFile) Readdir(count int) ([]os.FileInfo, error) { + if f.isFile { + return nil, fmt.Errorf("not a directory: %s", f.name) + } + + if count <= 0 { + r := f.dirEntries + f.dirEntries = f.dirEntries[:0] + return r, nil + } + + rq := mathutil.Min(count, len(f.dirEntries)) + r := f.dirEntries[:rq] + f.dirEntries = f.dirEntries[rq:] + if len(r) != 0 { + return r, nil + } + + return nil, io.EOF +} + +// Read implements http.File. +func (f *HTTPFile) Read(b []byte) (int, error) { + if f.closed { + return 0, os.ErrInvalid + } + + n := copy(b, f.content[f.off:]) + f.off += n + if n != 0 { + return n, nil + } + + return 0, io.EOF +} + +// Seek implements http.File. +func (f *HTTPFile) Seek(offset int64, whence int) (int64, error) { + if f.closed { + return 0, os.ErrInvalid + } + + if offset < 0 { + return int64(f.off), fmt.Errorf("cannot seek before start of file") + } + + switch whence { + case 0: + noff := int64(f.off) + offset + if noff > mathutil.MaxInt { + return int64(f.off), fmt.Errorf("seek target overflows int: %d", noff) + } + + f.off = mathutil.Min(int(offset), len(f.content)) + if f.off == int(offset) { + return offset, nil + } + + return int64(f.off), io.EOF + case 1: + noff := int64(f.off) + offset + if noff > mathutil.MaxInt { + return int64(f.off), fmt.Errorf("seek target overflows int: %d", noff) + } + + off := mathutil.Min(f.off+int(offset), len(f.content)) + if off == f.off+int(offset) { + f.off = off + return int64(off), nil + } + + f.off = off + return int64(off), io.EOF + case 2: + noff := int64(f.off) - offset + if noff < 0 { + return int64(f.off), fmt.Errorf("cannot seek before start of file") + } + + f.off = len(f.content) - int(offset) + return int64(f.off), nil + default: + return int64(f.off), fmt.Errorf("seek: invalid whence %d", whence) + } +} + +// HTTPFS implements a http.FileSystem backed by data in a DB. +type HTTPFS struct { + db *DB + dir, get List +} + +// NewHTTPFS returns a http.FileSystem backed by a result record set of query. +// The record set provides two mandatory fields: path and content (the field +// names are case sensitive). Type of name must be string and type of content +// must be blob (ie. []byte). Field 'path' value is the "file" pathname, which +// must be rooted; and field 'content' value is its "data". +func (db *DB) NewHTTPFS(query string) (*HTTPFS, error) { + if _, err := Compile(query); err != nil { + return nil, err + } + + dir, err := Compile(fmt.Sprintf("SELECT path FROM (%s) WHERE hasPrefix(path, $1)", query)) + if err != nil { + return nil, err + } + + get, err := Compile(fmt.Sprintf("SELECT content FROM (%s) WHERE path == $1", query)) + if err != nil { + return nil, err + } + + return &HTTPFS{db: db, dir: dir, get: get}, nil +} + +// Open implements http.FileSystem. The name parameter represents a file path. +// The elements in a file path are separated by slash ('/', U+002F) characters, +// regardless of host operating system convention. +func (f *HTTPFS) Open(name string) (http.File, error) { + if filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0 || + strings.Contains(name, "\x00") { + return nil, fmt.Errorf("invalid character in file path: %q", name) + } + + name = path.Clean("/" + name) + rs, _, err := f.db.Execute(nil, f.get, name) + if err != nil { + return nil, err + } + + n := 0 + var fdata []byte + if err = rs[0].Do(false, func(data []interface{}) (more bool, err error) { + switch n { + case 0: + var ok bool + fdata, ok = data[0].([]byte) + if !ok { + return false, fmt.Errorf("open: expected blob, got %T", data[0]) + } + n++ + return true, nil + default: + return false, fmt.Errorf("open: more than one result was returned for %s", name) + } + }); err != nil { + return nil, err + } + + if n == 1 { // file found + return &HTTPFile{name: name, isFile: true, content: fdata}, nil + } + + dirName := name + if dirName[len(dirName)-1] != filepath.Separator { + dirName += string(filepath.Separator) + } + // Open("/a/b"): {/a/b/c.x,/a/b/d.x,/a/e.x,/a/b/f/g.x} -> {c.x,d.x,f} + rs, _, err = f.db.Execute(nil, f.dir, dirName) + if err != nil { + return nil, err + } + + n = 0 + r := &HTTPFile{name: dirName} + m := map[string]bool{} + x := len(dirName) + if err = rs[0].Do(false, func(data []interface{}) (more bool, err error) { + n++ + switch name := data[0].(type) { + case string: + if filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0 || + strings.Contains(name, "\x00") { + return false, fmt.Errorf("invalid character in file path: %q", name) + } + + name = path.Clean("/" + name) + rest := name[x:] + parts := strings.Split(rest, "/") + if len(parts) == 0 { + return true, nil + } + + nm := parts[0] + switch len(parts) { + case 1: // file + r.dirEntries = append(r.dirEntries, &HTTPFile{isFile: true, name: nm}) + default: // directory + if !m[nm] { + r.dirEntries = append(r.dirEntries, dirEntry(nm)) + } + m[nm] = true + } + return true, nil + default: + return false, fmt.Errorf("expected string path, got %T(%v)", name, name) + } + }); err != nil { + return nil, err + } + + if n != 0 { + return r, nil + } + + return nil, os.ErrNotExist +} diff --git a/Godeps/_workspace/src/github.com/cznic/ql/httpfs_test.go b/Godeps/_workspace/src/github.com/cznic/ql/httpfs_test.go new file mode 100644 index 0000000..1ae79d3 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/ql/httpfs_test.go @@ -0,0 +1,547 @@ +// Copyright (c) 2014 ql 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 ql + +import ( + "io" + "os" + "path" + "testing" +) + +func TestHTTP(t *testing.T) { + db, err := OpenMem() + if err != nil { + t.Fatal(err) + } + if _, _, err = db.Run( + NewRWCtx(), + ` + BEGIN TRANSACTION; + CREATE TABLE t (path string); + INSERT INTO t VALUES + ("/a/b/c/1"), + ("/a/b/c/2"), + ("/a/b/3"), + ("/a/b/4"), + ("/a/5"), + ("/a/6"), + ; + COMMIT; + `, + ); err != nil { + t.Fatal(err) + } + + fs, err := db.NewHTTPFS("SELECT path, blob(path+`-c`) AS content FROM t") + if err != nil { + t.Fatal(err) + } + + for _, nm := range []string{"/a/b/c/1", "/a/b/4", "/a/5"} { + f, err := fs.Open(nm) + if err != nil { + t.Fatal(err) + } + + stat, err := f.Stat() + if err != nil { + t.Fatal(err) + } + + b := make([]byte, 100) + n, err := f.Read(b) + if err != nil { + t.Fatal(nm, n, err) + } + + g := string(b[:n]) + if e := nm + "-c"; g != e { + t.Fatal(g, e) + } + + if g, e := stat.Name(), path.Base(nm); g != e { + t.Fatal(g, e) + } + + if g, e := stat.Size(), int64(len(g)); g != e { + t.Fatal(g, e) + } + + if g, e := stat.IsDir(), false; g != e { + t.Fatal(g, e) + } + + b = make([]byte, 100) + n, err = f.Read(b) + if n != 0 { + t.Error(n) + } + + if err != io.EOF { + t.Fatal(err) + } + + if n, err := f.Seek(0, 0); err != nil || n != 0 { + t.Fatal(n, err) + } + + exp := []byte(nm + "-c") + b = make([]byte, 1) + for _, e := range exp { + n, err := f.Read(b) + if n != 1 || err != nil { + t.Fatal(n, err) + } + + if g := b[0]; g != e { + t.Fatal(g, e) + } + } + if n, err := f.Read(b); n != 0 || err != io.EOF { + t.Fatal(n, err) + } + + if err = f.Close(); err != nil { + t.Fatal(err) + } + + if n, err := f.Seek(0, 0); err != os.ErrInvalid { + t.Fatal(n, err) + } + } + + if _, err = fs.Open("nonexistent"); err != os.ErrNotExist { + t.Fatal(err) + } + + // ------------------------------------------------------------------ / + d, err := fs.Open("") + if err != nil { + t.Fatal(err) + } + + stat, err := d.Stat() + if err != nil { + t.Fatal(err) + } + + if g, e := stat.IsDir(), true; g != e { + t.Fatal(g, e) + } + + list, err := d.Readdir(0) + if err != nil { + t.Fatal(err) + } + + if g, e := len(list), 1; g != e { + t.Fatal(g, e) + } + + var a bool + for _, v := range list { + switch v.IsDir() { + case true: + switch v.Name() { + case "a": + a = true + default: + t.Fatal(v.Name()) + } + default: + t.Fatal(v.IsDir()) + } + } + if !a { + t.Fatal(a) + } + + // ------------------------------------------------------------------ a + d, err = fs.Open("a") + if err != nil { + t.Fatal(err) + } + + stat, err = d.Stat() + if err != nil { + t.Fatal(err) + } + + if g, e := stat.IsDir(), true; g != e { + t.Fatal(g, e) + } + + list, err = d.Readdir(0) + if err != nil { + t.Fatal(err) + } + + if g, e := len(list), 3; g != e { + t.Fatal(g, e) + } + + var aB, a5, a6 bool + for _, v := range list { + switch v.IsDir() { + case true: + switch v.Name() { + case "b": + aB = true + default: + t.Fatal(v.Name()) + } + default: + switch v.Name() { + case "5": + a5 = true + case "6": + a6 = true + default: + t.Fatal(v.Name()) + } + } + } + if !(aB && a5 && a6) { + t.Fatal(aB, a5, a6) + } + + // ----------------------------------------------------------------- a/ + d, err = fs.Open("a/") + if err != nil { + t.Fatal(err) + } + + stat, err = d.Stat() + if err != nil { + t.Fatal(err) + } + + if g, e := stat.IsDir(), true; g != e { + t.Fatal(g, e) + } + + list, err = d.Readdir(0) + if err != nil { + t.Fatal(err) + } + + if g, e := len(list), 3; g != e { + t.Fatal(g, e) + } + + for _, v := range list { + switch v.IsDir() { + case true: + switch v.Name() { + case "b": + aB = true + default: + t.Fatal(v.Name()) + } + default: + switch v.Name() { + case "5": + a5 = true + case "6": + a6 = true + default: + t.Fatal(v.Name()) + } + } + } + if !(aB && a5 && a6) { + t.Fatal(aB, a5, a6) + } + + // ----------------------------------------------------------------- /a + d, err = fs.Open("/a") + if err != nil { + t.Fatal(err) + } + + stat, err = d.Stat() + if err != nil { + t.Fatal(err) + } + + if g, e := stat.IsDir(), true; g != e { + t.Fatal(g, e) + } + + list, err = d.Readdir(0) + if err != nil { + t.Fatal(err) + } + + if g, e := len(list), 3; g != e { + t.Fatal(g, e) + } + + for _, v := range list { + switch v.IsDir() { + case true: + switch v.Name() { + case "b": + aB = true + default: + t.Fatal(v.Name()) + } + default: + switch v.Name() { + case "5": + a5 = true + case "6": + a6 = true + default: + t.Fatal(v.Name()) + } + } + } + if !(aB && a5 && a6) { + t.Fatal(aB, a5, a6) + } + + // ---------------------------------------------------------------- /a/ + d, err = fs.Open("/a/") + if err != nil { + t.Fatal(err) + } + + stat, err = d.Stat() + if err != nil { + t.Fatal(err) + } + + if g, e := stat.IsDir(), true; g != e { + t.Fatal(g, e) + } + + list, err = d.Readdir(0) + if err != nil { + t.Fatal(err) + } + + if g, e := len(list), 3; g != e { + t.Fatal(g, e) + } + + for _, v := range list { + switch v.IsDir() { + case true: + switch v.Name() { + case "b": + aB = true + default: + t.Fatal(v.Name()) + } + default: + switch v.Name() { + case "5": + a5 = true + case "6": + a6 = true + default: + t.Fatal(v.Name()) + } + } + } + if !(aB && a5 && a6) { + t.Fatal(aB, a5, a6) + } + + // ---------------------------------------------------------------- a/b + d, err = fs.Open("a/b") + if err != nil { + t.Fatal(err) + } + + stat, err = d.Stat() + if err != nil { + t.Fatal(err) + } + + if g, e := stat.IsDir(), true; g != e { + t.Fatal(g, e) + } + + list, err = d.Readdir(0) + if err != nil { + t.Fatal(err) + } + + if g, e := len(list), 3; g != e { + t.Fatal(g, e) + } + + var aB3, aB4, aBC bool + for _, v := range list { + switch v.IsDir() { + case true: + switch v.Name() { + case "c": + aBC = true + default: + t.Fatal(v.Name()) + } + default: + switch v.Name() { + case "3": + aB3 = true + case "4": + aB4 = true + default: + t.Fatal(v.Name()) + } + } + } + if !(aB3 && aB4 && aBC) { + t.Fatal(aB4, aB4, aBC) + } + + // --------------------------------------------------------------- a/b/ + d, err = fs.Open("a/b/") + if err != nil { + t.Fatal(err) + } + + stat, err = d.Stat() + if err != nil { + t.Fatal(err) + } + + if g, e := stat.IsDir(), true; g != e { + t.Fatal(g, e) + } + + list, err = d.Readdir(0) + if err != nil { + t.Fatal(err) + } + + if g, e := len(list), 3; g != e { + t.Fatal(g, e) + } + + for _, v := range list { + switch v.IsDir() { + case true: + switch v.Name() { + case "c": + aBC = true + default: + t.Fatal(v.Name()) + } + default: + switch v.Name() { + case "3": + aB3 = true + case "4": + aB4 = true + default: + t.Fatal(v.Name()) + } + } + } + if !(aB3 && aB4 && aBC) { + t.Fatal(aB4, aB4, aBC) + } + + // -------------------------------------------------------------- /a/b/ + d, err = fs.Open("/a/b/") + if err != nil { + t.Fatal(err) + } + + stat, err = d.Stat() + if err != nil { + t.Fatal(err) + } + + if g, e := stat.IsDir(), true; g != e { + t.Fatal(g, e) + } + + list, err = d.Readdir(0) + if err != nil { + t.Fatal(err) + } + + if g, e := len(list), 3; g != e { + t.Fatal(g, e) + } + + for _, v := range list { + switch v.IsDir() { + case true: + switch v.Name() { + case "c": + aBC = true + default: + t.Fatal(v.Name()) + } + default: + switch v.Name() { + case "3": + aB3 = true + case "4": + aB4 = true + default: + t.Fatal(v.Name()) + } + } + } + if !(aB3 && aB4 && aBC) { + t.Fatal(aB4, aB4, aBC) + } + + // --------------------------------------------------------------- /a/b + d, err = fs.Open("/a/b") + if err != nil { + t.Fatal(err) + } + + stat, err = d.Stat() + if err != nil { + t.Fatal(err) + } + + if g, e := stat.IsDir(), true; g != e { + t.Fatal(g, e) + } + + list, err = d.Readdir(0) + if err != nil { + t.Fatal(err) + } + + if g, e := len(list), 3; g != e { + t.Fatal(g, e) + } + + for _, v := range list { + switch v.IsDir() { + case true: + switch v.Name() { + case "c": + aBC = true + default: + t.Fatal(v.Name()) + } + default: + switch v.Name() { + case "3": + aB3 = true + case "4": + aB4 = true + default: + t.Fatal(v.Name()) + } + } + } + if !(aB3 && aB4 && aBC) { + t.Fatal(aB4, aB4, aBC) + } +} diff --git a/Godeps/_workspace/src/github.com/cznic/ql/introspection.go b/Godeps/_workspace/src/github.com/cznic/ql/introspection.go new file mode 100644 index 0000000..61ac9a9 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/ql/introspection.go @@ -0,0 +1,625 @@ +// Copyright 2014 The ql 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 ql + +import ( + "bytes" + "fmt" + "go/ast" + "reflect" + "strings" + "sync" +) + +var ( + schemaCache = map[reflect.Type]*StructInfo{} + schemaMu sync.RWMutex +) + +// StructInfo describes a struct type. An instance of StructInfo obtained from +// StructSchema is shared and must not be mutated. That includes the values +// pointed to by the elements of Fields and Indices. +type StructInfo struct { + Fields []*StructField // Fields describe the considered fields of a struct type. + HasID bool // Whether the struct has a considered field named ID of type int64. + Indices []*StructIndex // Indices describe indices defined by the index or uindex ql tags. + IsPtr bool // Whether the StructInfo was derived from a pointer to a struct. +} + +// StructIndex describes an index defined by the ql tag index or uindex. +type StructIndex struct { + ColumnName string // Name of the column the index is on. + Name string // Name of the index. + Unique bool // Whether the index is unique. +} + +// StructField describes a considered field of a struct type. +type StructField struct { + Index int // Index is the index of the field for reflect.Value.Field. + IsID bool // Whether the field corresponds to record id(). + IsPtr bool // Whether the field is a pointer type. + MarshalType reflect.Type // The reflect.Type a field must be converted to when marshaling or nil when it is assignable directly. (Field->value) + Name string // Field name or value of the name tag (like in `ql:"name foo"`). + ReflectType reflect.Type // The reflect.Type of the field. + Tags map[string]string // QL tags of this field. (`ql:"a, b c, d"` -> {"a": "", "b": "c", "d": ""}) + Type Type // QL type of the field. + UnmarshalType reflect.Type // The reflect.Type a value must be converted to when unmarshaling or nil when it is assignable directly. (Field<-value) + ZeroPtr reflect.Value // The reflect.Zero value of the field if it's a pointer type. +} + +func (s *StructField) check(v interface{}) error { + t := reflect.TypeOf(v) + if !s.ReflectType.AssignableTo(t) { + if !s.ReflectType.ConvertibleTo(t) { + return fmt.Errorf("type %s (%v) cannot be converted to %T", s.ReflectType.Name(), s.ReflectType.Kind(), t.Name()) + } + + s.MarshalType = t + } + + if !t.AssignableTo(s.ReflectType) { + if !t.ConvertibleTo(s.ReflectType) { + return fmt.Errorf("type %s (%v) cannot be converted to %T", t.Name(), t.Kind(), s.ReflectType.Name()) + } + + s.UnmarshalType = s.ReflectType + } + return nil +} + +func parseTag(s string) map[string]string { + m := map[string]string{} + for _, v := range strings.Split(s, ",") { + v = strings.TrimSpace(v) + switch n := strings.IndexRune(v, ' '); { + case n < 0: + m[v] = "" + default: + m[v[:n]] = v[n+1:] + } + } + return m +} + +// StructSchema returns StructInfo for v which must be a struct instance or a +// pointer to a struct. The info is computed only once for every type. +// Subsequent calls to StructSchema for the same type return a cached +// StructInfo. +// +// Note: The returned StructSchema is shared and must be not mutated, including +// any other data structures it may point to. +func StructSchema(v interface{}) (*StructInfo, error) { + if v == nil { + return nil, fmt.Errorf("cannot derive schema for %T(%v)", v, v) + } + + typ := reflect.TypeOf(v) + schemaMu.RLock() + if r, ok := schemaCache[typ]; ok { + schemaMu.RUnlock() + return r, nil + } + + schemaMu.RUnlock() + var schemaPtr bool + t := typ + if t.Kind() == reflect.Ptr { + t = t.Elem() + schemaPtr = true + } + if k := t.Kind(); k != reflect.Struct { + return nil, fmt.Errorf("cannot derive schema for type %T (%v)", v, k) + } + + r := &StructInfo{IsPtr: schemaPtr} + for i := 0; i < t.NumField(); i++ { + f := t.Field(i) + fn := f.Name + if !ast.IsExported(fn) { + continue + } + + tags := parseTag(f.Tag.Get("ql")) + if _, ok := tags["-"]; ok { + continue + } + + if s := tags["name"]; s != "" { + fn = s + } + + if fn == "ID" && f.Type.Kind() == reflect.Int64 { + r.HasID = true + } + var ix, unique bool + var xn string + xfn := fn + if s := tags["index"]; s != "" { + if _, ok := tags["uindex"]; ok { + return nil, fmt.Errorf("both index and uindex in QL struct tag") + } + + ix, xn = true, s + } else if s := tags["uindex"]; s != "" { + if _, ok := tags["index"]; ok { + return nil, fmt.Errorf("both index and uindex in QL struct tag") + } + + ix, unique, xn = true, true, s + } + if ix { + if fn == "ID" && r.HasID { + xfn = "id()" + } + r.Indices = append(r.Indices, &StructIndex{Name: xn, ColumnName: xfn, Unique: unique}) + } + + sf := &StructField{Index: i, Name: fn, Tags: tags, Type: Type(-1), ReflectType: f.Type} + fk := sf.ReflectType.Kind() + if fk == reflect.Ptr { + sf.IsPtr = true + sf.ZeroPtr = reflect.Zero(sf.ReflectType) + sf.ReflectType = sf.ReflectType.Elem() + fk = sf.ReflectType.Kind() + } + + switch fk { + case reflect.Bool: + sf.Type = Bool + if err := sf.check(false); err != nil { + return nil, err + } + case reflect.Int, reflect.Uint: + return nil, fmt.Errorf("only integers of fixed size can be used to derive a schema: %v", fk) + case reflect.Int8: + sf.Type = Int8 + if err := sf.check(int8(0)); err != nil { + return nil, err + } + case reflect.Int16: + if err := sf.check(int16(0)); err != nil { + return nil, err + } + sf.Type = Int16 + case reflect.Int32: + if err := sf.check(int32(0)); err != nil { + return nil, err + } + sf.Type = Int32 + case reflect.Int64: + if sf.ReflectType.Name() == "Duration" && sf.ReflectType.PkgPath() == "time" { + sf.Type = Duration + break + } + + sf.Type = Int64 + if err := sf.check(int64(0)); err != nil { + return nil, err + } + case reflect.Uint8: + sf.Type = Uint8 + if err := sf.check(uint8(0)); err != nil { + return nil, err + } + case reflect.Uint16: + sf.Type = Uint16 + if err := sf.check(uint16(0)); err != nil { + return nil, err + } + case reflect.Uint32: + sf.Type = Uint32 + if err := sf.check(uint32(0)); err != nil { + return nil, err + } + case reflect.Uint64: + sf.Type = Uint64 + if err := sf.check(uint64(0)); err != nil { + return nil, err + } + case reflect.Float32: + sf.Type = Float32 + if err := sf.check(float32(0)); err != nil { + return nil, err + } + case reflect.Float64: + sf.Type = Float64 + if err := sf.check(float64(0)); err != nil { + return nil, err + } + case reflect.Complex64: + sf.Type = Complex64 + if err := sf.check(complex64(0)); err != nil { + return nil, err + } + case reflect.Complex128: + sf.Type = Complex128 + if err := sf.check(complex128(0)); err != nil { + return nil, err + } + case reflect.Slice: + sf.Type = Blob + if err := sf.check([]byte(nil)); err != nil { + return nil, err + } + case reflect.Struct: + switch sf.ReflectType.PkgPath() { + case "math/big": + switch sf.ReflectType.Name() { + case "Int": + sf.Type = BigInt + case "Rat": + sf.Type = BigRat + } + case "time": + switch sf.ReflectType.Name() { + case "Time": + sf.Type = Time + } + } + case reflect.String: + sf.Type = String + if err := sf.check(""); err != nil { + return nil, err + } + } + + if sf.Type < 0 { + return nil, fmt.Errorf("cannot derive schema for type %s (%v)", sf.ReflectType.Name(), fk) + } + + sf.IsID = fn == "ID" && r.HasID + r.Fields = append(r.Fields, sf) + } + + schemaMu.Lock() + schemaCache[typ] = r + if t != typ { + r2 := *r + r2.IsPtr = false + schemaCache[t] = &r2 + } + schemaMu.Unlock() + return r, nil +} + +// MustStructSchema is like StructSchema but panics on error. It simplifies +// safe initialization of global variables holding StructInfo. +// +// MustStructSchema is safe for concurrent use by multiple goroutines. +func MustStructSchema(v interface{}) *StructInfo { + s, err := StructSchema(v) + if err != nil { + panic(err) + } + + return s +} + +// SchemaOptions amend the result of Schema. +type SchemaOptions struct { + // Don't wrap the CREATE statement(s) in a transaction. + NoTransaction bool + + // Don't insert the IF NOT EXISTS clause in the CREATE statement(s). + NoIfNotExists bool + + // Do not strip the "pkg." part from type name "pkg.Type", produce + // "pkg_Type" table name instead. Applies only when no name is passed + // to Schema(). + KeepPrefix bool +} + +var zeroSchemaOptions SchemaOptions + +// Schema returns a CREATE TABLE/INDEX statement(s) for a table derived from a +// struct or an error, if any. The table is named using the name parameter. If +// name is an empty string then the type name of the struct is used while non +// conforming characters are replaced by underscores. Value v can be also a +// pointer to a struct. +// +// Every considered struct field type must be one of the QL types or a type +// convertible to string, bool, int*, uint*, float* or complex* type or pointer +// to such type. Integers with a width dependent on the architecture can not be +// used. Only exported fields are considered. If an exported field QL tag +// contains "-" (`ql:"-"`) then such field is not considered. A field with name +// ID, having type int64, corresponds to id() - and is thus not a part of the +// CREATE statement. A field QL tag containing "index name" or "uindex name" +// triggers additionally creating an index or unique index on the respective +// field. Fields can be renamed using a QL tag "name newName". Fields are +// considered in the order of appearance. A QL tag is a struct tag part +// prefixed by "ql:". Tags can be combined, for example: +// +// type T struct { +// Foo string `ql:"index xFoo, name Bar"` +// } +// +// If opts.NoTransaction == true then the statement(s) are not wrapped in a +// transaction. If opt.NoIfNotExists == true then the CREATE statement(s) omits +// the IF NOT EXISTS clause. Passing nil opts is equal to passing +// &SchemaOptions{} +// +// Schema is safe for concurrent use by multiple goroutines. +func Schema(v interface{}, name string, opt *SchemaOptions) (List, error) { + if opt == nil { + opt = &zeroSchemaOptions + } + s, err := StructSchema(v) + if err != nil { + return List{}, err + } + + var buf bytes.Buffer + if !opt.NoTransaction { + buf.WriteString("BEGIN TRANSACTION; ") + } + buf.WriteString("CREATE TABLE ") + if !opt.NoIfNotExists { + buf.WriteString("IF NOT EXISTS ") + } + if name == "" { + name = fmt.Sprintf("%T", v) + if !opt.KeepPrefix { + a := strings.Split(name, ".") + if l := len(a); l > 1 { + name = a[l-1] + } + } + nm := []rune{} + for _, v := range name { + switch { + case v >= '0' && v <= '9' || v == '_' || v >= 'a' && v <= 'z' || v >= 'A' && v <= 'Z': + // ok + default: + v = '_' + } + nm = append(nm, v) + } + name = string(nm) + } + buf.WriteString(name + " (") + for _, v := range s.Fields { + if v.IsID { + continue + } + + buf.WriteString(fmt.Sprintf("%s %s, ", v.Name, v.Type)) + } + buf.WriteString("); ") + for _, v := range s.Indices { + buf.WriteString("CREATE ") + if v.Unique { + buf.WriteString("UNIQUE ") + } + buf.WriteString("INDEX ") + if !opt.NoIfNotExists { + buf.WriteString("IF NOT EXISTS ") + } + buf.WriteString(fmt.Sprintf("%s ON %s (%s); ", v.Name, name, v.ColumnName)) + } + if !opt.NoTransaction { + buf.WriteString("COMMIT; ") + } + l, err := Compile(buf.String()) + if err != nil { + return List{}, fmt.Errorf("%s: %v", buf.String(), err) + } + + return l, nil +} + +// MustSchema is like Schema but panics on error. It simplifies safe +// initialization of global variables holding compiled schemas. +// +// MustSchema is safe for concurrent use by multiple goroutines. +func MustSchema(v interface{}, name string, opt *SchemaOptions) List { + l, err := Schema(v, name, opt) + if err != nil { + panic(err) + } + + return l +} + +// Marshal converts, in the order of appearance, fields of a struct instance v +// to []interface{} or an error, if any. Value v can be also a pointer to a +// struct. +// +// Every considered struct field type must be one of the QL types or a type +// convertible to string, bool, int*, uint*, float* or complex* type or pointer +// to such type. Integers with a width dependent on the architecture can not be +// used. Only exported fields are considered. If an exported field QL tag +// contains "-" then such field is not considered. A QL tag is a struct tag +// part prefixed by "ql:". Field with name ID, having type int64, corresponds +// to id() - and is thus not part of the result. +// +// Marshal is safe for concurrent use by multiple goroutines. +func Marshal(v interface{}) ([]interface{}, error) { + s, err := StructSchema(v) + if err != nil { + return nil, err + } + + val := reflect.ValueOf(v) + if s.IsPtr { + val = val.Elem() + } + n := len(s.Fields) + if s.HasID { + n-- + } + r := make([]interface{}, n) + j := 0 + for _, v := range s.Fields { + if v.IsID { + continue + } + + f := val.Field(v.Index) + if v.IsPtr { + if f.IsNil() { + r[j] = nil + j++ + continue + } + + f = f.Elem() + } + if m := v.MarshalType; m != nil { + f = f.Convert(m) + } + r[j] = f.Interface() + j++ + } + return r, nil +} + +// MustMarshal is like Marshal but panics on error. It simplifies marshaling of +// "safe" types, like eg. those which were already verified by Schema or +// MustSchema. When the underlying Marshal returns an error, MustMarshal +// panics. +// +// MustMarshal is safe for concurrent use by multiple goroutines. +func MustMarshal(v interface{}) []interface{} { + r, err := Marshal(v) + if err != nil { + panic(err) + } + + return r +} + +// Unmarshal stores data from []interface{} in the struct value pointed to by +// v. +// +// Every considered struct field type must be one of the QL types or a type +// convertible to string, bool, int*, uint*, float* or complex* type or pointer +// to such type. Integers with a width dependent on the architecture can not be +// used. Only exported fields are considered. If an exported field QL tag +// contains "-" then such field is not considered. A QL tag is a struct tag +// part prefixed by "ql:". Fields are considered in the order of appearance. +// Types of values in data must be compatible with the corresponding considered +// field of v. +// +// If the struct has no ID field then the number of values in data must be equal +// to the number of considered fields of v. +// +// type T struct { +// A bool +// B string +// } +// +// Assuming the schema is +// +// CREATE TABLE T (A bool, B string); +// +// Data might be a result of queries like +// +// SELECT * FROM T; +// SELECT A, B FROM T; +// +// If the struct has a considered ID field then the number of values in data +// must be equal to the number of considered fields in v - or one less. In the +// later case the ID field is not set. +// +// type U struct { +// ID int64 +// A bool +// B string +// } +// +// Assuming the schema is +// +// CREATE TABLE T (A bool, B string); +// +// Data might be a result of queries like +// +// SELECT * FROM T; // ID not set +// SELECT A, B FROM T; // ID not set +// SELECT id(), A, B FROM T; // ID is set +// +// To unmarshal a value from data into a pointer field of v, Unmarshal first +// handles the case of the value being nil. In that case, Unmarshal sets the +// pointer to nil. Otherwise, Unmarshal unmarshals the data value into value +// pointed at by the pointer. If the pointer is nil, Unmarshal allocates a new +// value for it to point to. +// +// Unmarshal is safe for concurrent use by multiple goroutines. +func Unmarshal(v interface{}, data []interface{}) (err error) { + defer func() { + if r := recover(); r != nil { + var ok bool + if err, ok = r.(error); !ok { + err = fmt.Errorf("%v", r) + } + err = fmt.Errorf("unmarshal: %v", err) + } + }() + + s, err := StructSchema(v) + if err != nil { + return err + } + + if !s.IsPtr { + return fmt.Errorf("unmarshal: need a pointer to a struct") + } + + id := false + nv, nf := len(data), len(s.Fields) + switch s.HasID { + case true: + switch { + case nv == nf: + id = true + case nv == nf-1: + // ok + default: + return fmt.Errorf("unmarshal: got %d values, need %d or %d", nv, nf-1, nf) + } + default: + switch { + case nv == nf: + // ok + default: + return fmt.Errorf("unmarshal: got %d values, need %d", nv, nf) + } + } + + j := 0 + vVal := reflect.ValueOf(v) + if s.IsPtr { + vVal = vVal.Elem() + } + for _, sf := range s.Fields { + if sf.IsID && !id { + continue + } + + d := data[j] + val := reflect.ValueOf(d) + j++ + + fVal := vVal.Field(sf.Index) + if u := sf.UnmarshalType; u != nil { + val = val.Convert(u) + } + if !sf.IsPtr { + fVal.Set(val) + continue + } + + if d == nil { + fVal.Set(sf.ZeroPtr) + continue + } + + if fVal.IsNil() { + fVal.Set(reflect.New(sf.ReflectType)) + } + + fVal.Elem().Set(val) + } + return nil +} diff --git a/Godeps/_workspace/src/github.com/cznic/ql/introspection_test.go b/Godeps/_workspace/src/github.com/cznic/ql/introspection_test.go new file mode 100644 index 0000000..792690c --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/ql/introspection_test.go @@ -0,0 +1,1073 @@ +// Copyright 2014 The ql 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 ql + +import ( + "bytes" + "fmt" + "math/big" + //"reflect" + "testing" + "time" + + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/mathutil" +) + +type ( + testSchema struct { + a int8 + ID int64 + A int8 + b int + B int `ql:"-"` + } + + testSchema2 struct{} + + testSchema3 struct { + a int8 + ID uint64 + A int8 + b int + B int `ql:"-"` + c bool + C bool `ql:"name cc"` + } + + testSchema4 struct { + a int8 + ID int64 `ql:"name id"` + A int8 + b int + B int `ql:"-"` + c bool + C bool `ql:"name cc"` + } + + testSchema5 struct { + I int `ql:"index x,uindex u"` + } + + testSchema6 struct { + A string `ql:"index x"` + } + + testSchema7 struct { + A int64 + B string `ql:"uindex x"` + C bool + } + + testSchema8 struct { + A bool + //B int + C int8 + D int16 + E int32 + F int64 + //G uint + H uint8 + I uint16 + J uint32 + K uint64 + L float32 + M float64 + N complex64 + O complex128 + P []byte + Q big.Int + R big.Rat + S string + T time.Time + U time.Duration + PA *bool + //PB *int + PC *int8 + PD *int16 + PE *int32 + PF *int64 + //PG *uint + PH *uint8 + PI *uint16 + PJ *uint32 + PK *uint64 + PL *float32 + PM *float64 + PN *complex64 + PO *complex128 + PP *[]byte + PQ *big.Int + PR *big.Rat + PS *string + PT *time.Time + PU *time.Duration + } + + testSchema9 struct { + i int + ID int64 `ql:"index xID"` + Other string `ql:"-"` + DepartmentName string `ql:"uindex xDepartmentName"` + } +) + +const ( + testSchemaSFFF = "begin transaction; create table if not exists testSchema (A int8); commit;" + testSchemaSFFT = "begin transaction; create table if not exists ql_testSchema (A int8); commit;" + testSchemaSFTF = "begin transaction; create table testSchema (A int8); commit;" + testSchemaSFTT = "begin transaction; create table ql_testSchema (A int8); commit;" + testSchemaSTFF = "create table if not exists testSchema (A int8)" + testSchemaSTFT = "create table if not exists ql_testSchema (A int8)" + testSchemaSTTF = "create table testSchema (A int8)" + testSchemaSTTT = "create table ql_testSchema (A int8)" + testSchema3S = "begin transaction; create table if not exists testSchema3 (ID uint64, A int8, cc bool); commit;" + testSchema4S = "begin transaction; create table if not exists testSchema4 (id int64, A int8, cc bool); commit;" + testSchema6S = "create table testSchema6 (A string); create index x on testSchema6 (A);" + testSchema7S = "begin transaction; create table testSchema7 (A int64, B string, C bool); create unique index x on testSchema7 (B); commit;" + testSchema8S = ` + begin transaction; + create table if not exists testSchema8 ( + A bool, + //B int64, + C int8, + D int16, + E int32, + F int64, + //G uint64, + H uint8, + I uint16, + J uint32, + K uint64, + L float32, + M float64, + N complex64, + O complex128, + P blob, + Q bigInt, + R bigRat, + S string, + T time, + U duration, + PA bool, + //PB int64, + PC int8, + PD int16, + PE int32, + PF int64, + //PG uint64, + PH uint8, + PI uint16, + PJ uint32, + PK uint64, + PL float32, + PM float64, + PN complex64, + PO complex128, + PP blob, + PQ bigInt, + PR bigRat, + PS string, + PT time, + PU duration, + ); + commit;` + testSchema9S = ` + begin transaction; + create table if not exists testSchema9 (DepartmentName string); + create index if not exists xID on testSchema9 (id()); + create unique index if not exists xDepartmentName on testSchema9 (DepartmentName); + commit;` +) + +func TestSchema(t *testing.T) { + tab := []struct { + inst interface{} + name string + opts *SchemaOptions + err bool + s string + }{ + // 0 + {inst: nil, err: true}, + {inst: interface{}(nil), err: true}, + {testSchema{}, "", nil, false, testSchemaSFFF}, + {testSchema{}, "", &SchemaOptions{}, false, testSchemaSFFF}, + {testSchema{}, "", &SchemaOptions{KeepPrefix: true}, false, testSchemaSFFT}, + // 5 + {testSchema{}, "", &SchemaOptions{NoIfNotExists: true}, false, testSchemaSFTF}, + {testSchema{}, "", &SchemaOptions{NoIfNotExists: true, KeepPrefix: true}, false, testSchemaSFTT}, + {testSchema{}, "", &SchemaOptions{NoTransaction: true}, false, testSchemaSTFF}, + {testSchema{}, "", &SchemaOptions{NoTransaction: true, KeepPrefix: true}, false, testSchemaSTFT}, + {testSchema{}, "", &SchemaOptions{NoTransaction: true, NoIfNotExists: true}, false, testSchemaSTTF}, + // 10 + {testSchema{}, "", &SchemaOptions{NoTransaction: true, NoIfNotExists: true, KeepPrefix: true}, false, testSchemaSTTT}, + {testSchema2{}, "", nil, true, ""}, + {testSchema3{}, "", nil, false, testSchema3S}, + {testSchema4{}, "", nil, false, testSchema4S}, + {testSchema5{}, "", nil, true, ""}, + // 15 + {testSchema6{}, "", &SchemaOptions{NoTransaction: true, NoIfNotExists: true}, false, testSchema6S}, + {testSchema7{}, "", &SchemaOptions{NoIfNotExists: true}, false, testSchema7S}, + {testSchema8{}, "", nil, false, testSchema8S}, + {&testSchema8{}, "", nil, false, testSchema8S}, + {&testSchema9{}, "", nil, false, testSchema9S}, + } + + for iTest, test := range tab { + l, err := Schema(test.inst, test.name, test.opts) + if g, e := err != nil, test.err; g != e { + t.Fatal(iTest, g, e, err) + } + + if err != nil { + t.Log(iTest, err) + continue + } + + s, err := Compile(test.s) + if err != nil { + panic("internal error 070") + } + + if g, e := l.String(), s.String(); g != e { + t.Fatalf("%d\n----\n%s\n----\n%s", iTest, g, e) + } + } +} + +func ExampleSchema() { + type department struct { + a int // unexported -> ignored + ID int64 `ql:"index xID"` + Other string `xml:"-" ql:"-"` // ignored by QL tag + DepartmentName string `ql:"name Name, uindex xName" json:"foo"` + m bool + HQ int32 + z string + } + + schema := MustSchema((*department)(nil), "", nil) + sel := MustCompile(` + SELECT * FROM __Table; + SELECT * FROM __Column; + SELECT * FROM __Index;`, + ) + fmt.Print(schema) + + db, err := OpenMem() + if err != nil { + panic(err) + } + + if _, _, err = db.Execute(NewRWCtx(), schema); err != nil { + panic(err) + } + + rs, _, err := db.Execute(nil, sel) + if err != nil { + panic(err) + } + + for _, rs := range rs { + fmt.Println("----") + if err = rs.Do(true, func(data []interface{}) (bool, error) { + fmt.Println(data) + return true, nil + }); err != nil { + panic(err) + } + } + // Output: + // BEGIN TRANSACTION; + // CREATE TABLE IF NOT EXISTS department (Name string, HQ int32); + // CREATE INDEX IF NOT EXISTS xID ON department (id()); + // CREATE UNIQUE INDEX IF NOT EXISTS xName ON department (Name); + // COMMIT; + // ---- + // [Name Schema] + // [department CREATE TABLE department (Name string, HQ int32);] + // ---- + // [TableName Ordinal Name Type] + // [department 1 Name string] + // [department 2 HQ int32] + // ---- + // [TableName ColumnName Name IsUnique] + // [department id() xID false] + // [department Name xName true] +} + +func TestMarshal(t *testing.T) { + now := time.Now() + dur := time.Millisecond + schema8 := testSchema8{ + A: true, + //B: 1, + C: 2, + D: 3, + E: 4, + F: 5, + //G: 6, + H: 7, + I: 8, + J: 9, + K: 10, + L: 11, + M: 12, + N: -1, + O: -2, + P: []byte("abc"), + Q: *big.NewInt(1), + R: *big.NewRat(3, 2), + S: "string", + T: now, + U: dur, + } + schema8.PA = &schema8.A + //schema8.PB = &schema8.B + schema8.PC = &schema8.C + schema8.PD = &schema8.D + schema8.PE = &schema8.E + schema8.PF = &schema8.F + //schema8.PG = &schema8.G + schema8.PH = &schema8.H + schema8.PI = &schema8.I + schema8.PJ = &schema8.J + schema8.PK = &schema8.K + schema8.PL = &schema8.L + schema8.PM = &schema8.M + schema8.PN = &schema8.N + schema8.PO = &schema8.O + schema8.PP = &schema8.P + schema8.PQ = &schema8.Q + schema8.PR = &schema8.R + schema8.PS = &schema8.S + schema8.PT = &schema8.T + schema8.PU = &schema8.U + + type u int + tab := []struct { + inst interface{} + err bool + r []interface{} + }{ + {42, true, nil}, + {new(u), true, nil}, + {testSchema8{}, false, []interface{}{ + false, + //int64(0), + int8(0), + int16(0), + int32(0), + int64(0), + //uint64(0), + uint8(0), + uint16(0), + uint32(0), + uint64(0), + float32(0), + float64(0), + complex64(0), + complex128(0), + []byte(nil), + big.Int{}, + big.Rat{}, + "", + time.Time{}, + time.Duration(0), + nil, + //nil, + nil, + nil, + nil, + nil, + //nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + }}, + {&testSchema8{}, false, []interface{}{ + false, + //int64(0), + int8(0), + int16(0), + int32(0), + int64(0), + //uint64(0), + uint8(0), + uint16(0), + uint32(0), + uint64(0), + float32(0), + float64(0), + complex64(0), + complex128(0), + []byte(nil), + big.Int{}, + big.Rat{}, + "", + time.Time{}, + time.Duration(0), + nil, + //nil, + nil, + nil, + nil, + nil, + //nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + nil, + }}, + {schema8, false, []interface{}{ + true, + //int64(1), + int8(2), + int16(3), + int32(4), + int64(5), + //uint64(6), + uint8(7), + uint16(8), + uint32(9), + uint64(10), + float32(11), + float64(12), + complex64(-1), + complex128(-2), + []byte("abc"), + *big.NewInt(1), + *big.NewRat(3, 2), + "string", + now, + dur, + true, + //int64(1), + int8(2), + int16(3), + int32(4), + int64(5), + //uint64(6), + uint8(7), + uint16(8), + uint32(9), + uint64(10), + float32(11), + float64(12), + complex64(-1), + complex128(-2), + []byte("abc"), + *big.NewInt(1), + *big.NewRat(3, 2), + "string", + now, + dur, + }}, + {&schema8, false, []interface{}{ + true, + //int64(1), + int8(2), + int16(3), + int32(4), + int64(5), + //uint64(6), + uint8(7), + uint16(8), + uint32(9), + uint64(10), + float32(11), + float64(12), + complex64(-1), + complex128(-2), + []byte("abc"), + *big.NewInt(1), + *big.NewRat(3, 2), + "string", + now, + dur, + true, + //int64(1), + int8(2), + int16(3), + int32(4), + int64(5), + //uint64(6), + uint8(7), + uint16(8), + uint32(9), + uint64(10), + float32(11), + float64(12), + complex64(-1), + complex128(-2), + []byte("abc"), + *big.NewInt(1), + *big.NewRat(3, 2), + "string", + now, + dur, + }}, + } + for iTest, test := range tab { + r, err := Marshal(test.inst) + if g, e := err != nil, test.err; g != e { + t.Fatal(iTest, g, e) + } + + if err != nil { + t.Log(err) + continue + } + + for i := 0; i < mathutil.Min(len(r), len(test.r)); i++ { + g, e := r[i], test.r[i] + use(e) + switch x := g.(type) { + case bool: + switch y := e.(type) { + case bool: + if x != y { + t.Fatal(iTest, x, y) + } + default: + t.Fatalf("%d: %T <-> %T", iTest, x, y) + } + case int: + switch y := e.(type) { + case int64: + if int64(x) != y { + t.Fatal(iTest, x, y) + } + default: + t.Fatalf("%d: %T <-> %T", iTest, x, y) + } + case int8: + switch y := e.(type) { + case int8: + if x != y { + t.Fatal(iTest, x, y) + } + default: + t.Fatalf("%d: %T <-> %T", iTest, x, y) + } + case int16: + switch y := e.(type) { + case int16: + if x != y { + t.Fatal(iTest, x, y) + } + default: + t.Fatalf("%d: %T <-> %T", iTest, x, y) + } + case int32: + switch y := e.(type) { + case int32: + if x != y { + t.Fatal(iTest, x, y) + } + default: + t.Fatalf("%d: %T <-> %T", iTest, x, y) + } + case int64: + switch y := e.(type) { + case int64: + if x != y { + t.Fatal(iTest, x, y) + } + default: + t.Fatalf("%d: %T <-> %T", iTest, x, y) + } + case uint: + switch y := e.(type) { + case uint64: + if uint64(x) != y { + t.Fatal(iTest, x, y) + } + default: + t.Fatalf("%d: %T <-> %T", iTest, x, y) + } + case uint8: + switch y := e.(type) { + case uint8: + if x != y { + t.Fatal(iTest, x, y) + } + default: + t.Fatalf("%d: %T <-> %T", iTest, x, y) + } + case uint16: + switch y := e.(type) { + case uint16: + if x != y { + t.Fatal(iTest, x, y) + } + default: + t.Fatalf("%d: %T <-> %T", iTest, x, y) + } + case uint32: + switch y := e.(type) { + case uint32: + if x != y { + t.Fatal(iTest, x, y) + } + default: + t.Fatalf("%d: %T <-> %T", iTest, x, y) + } + case uint64: + switch y := e.(type) { + case uint64: + if x != y { + t.Fatal(iTest, x, y) + } + default: + t.Fatalf("%d: %T <-> %T", iTest, x, y) + } + case float32: + switch y := e.(type) { + case float32: + if x != y { + t.Fatal(iTest, x, y) + } + default: + t.Fatalf("%d: %T <-> %T", iTest, x, y) + } + case float64: + switch y := e.(type) { + case float64: + if x != y { + t.Fatal(iTest, x, y) + } + default: + t.Fatalf("%d: %T <-> %T", iTest, x, y) + } + case complex64: + switch y := e.(type) { + case complex64: + if x != y { + t.Fatal(iTest, x, y) + } + default: + t.Fatalf("%d: %T <-> %T", iTest, x, y) + } + case complex128: + switch y := e.(type) { + case complex128: + if x != y { + t.Fatal(iTest, x, y) + } + default: + t.Fatalf("%d: %T <-> %T", iTest, x, y) + } + case []byte: + switch y := e.(type) { + case []byte: + if bytes.Compare(x, y) != 0 { + t.Fatal(iTest, x, y) + } + default: + t.Fatalf("%d: %T <-> %T", iTest, x, y) + } + case big.Int: + switch y := e.(type) { + case big.Int: + if x.Cmp(&y) != 0 { + t.Fatal(iTest, &x, &y) + } + default: + t.Fatalf("%d: %T <-> %T", iTest, x, y) + } + case big.Rat: + switch y := e.(type) { + case big.Rat: + if x.Cmp(&y) != 0 { + t.Fatal(iTest, &x, &y) + } + default: + t.Fatalf("%d: %T <-> %T", iTest, x, y) + } + case string: + switch y := e.(type) { + case string: + if x != y { + t.Fatal(iTest, x, y) + } + default: + t.Fatalf("%d: %T <-> %T", iTest, x, y) + } + case time.Time: + switch y := e.(type) { + case time.Time: + if !x.Equal(y) { + t.Fatal(iTest, x, y) + } + default: + t.Fatalf("%d: %T <-> %T", iTest, x, y) + } + case time.Duration: + switch y := e.(type) { + case time.Duration: + if x != y { + t.Fatal(iTest, x, y) + } + default: + t.Fatalf("%d: %T <-> %T", iTest, x, y) + } + case nil: + switch y := e.(type) { + case nil: + // ok + default: + t.Fatalf("%d: %T <-> %T", iTest, x, y) + } + default: + panic(fmt.Errorf("%T", x)) + } + } + + if g, e := len(r), len(test.r); g != e { + t.Fatal(iTest, g, e) + } + + } +} + +func ExampleMarshal() { + type myInt int16 + + type myString string + + type item struct { + ID int64 + Name myString + Qty *myInt // pointer enables nil values + Bar int8 + } + + schema := MustSchema((*item)(nil), "", nil) + ins := MustCompile(` + BEGIN TRANSACTION; + INSERT INTO item VALUES($1, $2, $3); + COMMIT;`, + ) + + db, err := OpenMem() + if err != nil { + panic(err) + } + + ctx := NewRWCtx() + if _, _, err := db.Execute(ctx, schema); err != nil { + panic(err) + } + + if _, _, err := db.Execute(ctx, ins, MustMarshal(&item{Name: "foo", Bar: -1})...); err != nil { + panic(err) + } + + q := myInt(42) + if _, _, err := db.Execute(ctx, ins, MustMarshal(&item{Name: "bar", Qty: &q})...); err != nil { + panic(err) + } + + rs, _, err := db.Run(nil, "SELECT * FROM item ORDER BY id();") + if err != nil { + panic(err) + } + + if err = rs[0].Do(true, func(data []interface{}) (bool, error) { + fmt.Println(data) + return true, nil + }); err != nil { + panic(err) + } + // Output: + // [Name Qty Bar] + // [foo -1] + // [bar 42 0] +} + +func TestUnmarshal0(t *testing.T) { + type t1 struct { + I, J int64 + } + + // ---- value field + v1 := &t1{-1, -2} + if err := Unmarshal(v1, []interface{}{int64(42), int64(314)}); err != nil { + t.Fatal(err) + } + + if g, e := v1.I, int64(42); g != e { + t.Fatal(g, e) + } + + if g, e := v1.J, int64(314); g != e { + t.Fatal(g, e) + } + + type t2 struct { + P *int64 + } + + // ---- nil into nil ptr field + v2 := &t2{P: nil} + if err := Unmarshal(v2, []interface{}{nil}); err != nil { + t.Fatal(err) + } + + if g, e := v2.P, (*int64)(nil); g != e { + t.Fatal(g, e) + } + + v2 = &t2{P: nil} + if err := Unmarshal(v2, []interface{}{interface{}(nil)}); err != nil { + t.Fatal(err) + } + + if g, e := v2.P, (*int64)(nil); g != e { + t.Fatal(g, e) + } + + // ---- nil into non nil ptr field + i := int64(42) + v2 = &t2{P: &i} + if err := Unmarshal(v2, []interface{}{nil}); err != nil { + t.Fatal(err) + } + + if g, e := v2.P, (*int64)(nil); g != e { + t.Fatal(g, e) + } + + if g, e := i, int64(42); g != e { + t.Fatal(g, e) + } + + v2 = &t2{P: &i} + if err := Unmarshal(v2, []interface{}{interface{}(nil)}); err != nil { + t.Fatal(err) + } + + if g, e := v2.P, (*int64)(nil); g != e { + t.Fatal(g, e) + } + + if g, e := i, int64(42); g != e { + t.Fatal(g, e) + } + + // ---- non nil value into non nil ptr field + i = 42 + v2 = &t2{P: &i} + if err := Unmarshal(v2, []interface{}{int64(314)}); err != nil { + t.Fatal(err) + } + + if g, e := v2.P, &i; g != e { + t.Fatal(g, e) + } + + if g, e := i, int64(314); g != e { + t.Fatal(g, e) + } + + // ---- non nil value into nil ptr field + v2 = &t2{P: nil} + if err := Unmarshal(v2, []interface{}{int64(314)}); err != nil { + t.Fatal(err) + } + + if g, e := v2.P != nil, true; g != e { + t.Fatal(g, e) + } + + if g, e := *v2.P, int64(314); g != e { + t.Fatal(g, e) + } +} + +func TestUnmarshal(t *testing.T) { + type myString string + + type t1 struct { + A bool + B myString + } + + type t2 struct { + A bool + ID int64 + B myString + } + + f := func(v interface{}) int64 { + if x, ok := v.(*t2); ok { + return x.ID + } + + return -1 + } + + tab := []struct { + inst interface{} + data []interface{} + err bool + }{ + // 0 + {t1{}, []interface{}{true, "foo"}, true}, // not a ptr + {&t1{}, []interface{}{true}, true}, // too few values + {&t1{}, []interface{}{"foo"}, true}, // too few values + {&t1{}, []interface{}{true, "foo", 42}, true}, // too many values + {&t1{}, []interface{}{"foo", true, 42}, true}, // too many values + // 5 + {&t1{}, []interface{}{true, "foo"}, false}, + {&t1{}, []interface{}{false, "bar"}, false}, + {&t1{}, []interface{}{"bar", "baz"}, true}, + {&t1{}, []interface{}{true, 42.7}, true}, + {&t2{}, []interface{}{1}, true}, // too few values + // 10 + {&t2{}, []interface{}{1, 2, 3, 4}, true}, // too many values + {&t2{}, []interface{}{false, int64(314), "foo"}, false}, + {&t2{}, []interface{}{true, int64(42), "foo"}, false}, + {&t2{}, []interface{}{false, "foo"}, false}, + // 15 + {&t2{}, []interface{}{true, "foo"}, false}, + } + + for iTest, test := range tab { + inst := test.inst + err := Unmarshal(inst, test.data) + if g, e := err != nil, test.err; g != e { + t.Fatal(iTest, g, e) + } + + if err != nil { + t.Log(iTest, err) + continue + } + + data, err := Marshal(inst) + if err != nil { + t.Fatal(iTest, err) + } + + if g, e := len(data), len(test.data); g > e { + t.Fatal(iTest, g, e) + } + + j := 0 + for _, v := range data { + v2 := test.data[j] + j++ + if _, ok := v2.(int64); ok { + if g, e := f(inst), v2; g != e { + t.Fatal(iTest, g, e) + } + + continue + } + + if g, e := v, v2; g != e { + t.Fatal(iTest, g, e) + } + } + } +} + +func ExampleUnmarshal() { + type myString string + + type row struct { + ID int64 + S myString + P *int64 + } + + schema := MustSchema((*row)(nil), "", nil) + ins := MustCompile(` + BEGIN TRANSACTION; + INSERT INTO row VALUES($1, $2); + COMMIT;`, + ) + sel := MustCompile(` + SELECT id(), S, P FROM row ORDER by id(); + SELECT * FROM row ORDER by id();`, + ) + + db, err := OpenMem() + if err != nil { + panic(err) + } + + ctx := NewRWCtx() + if _, _, err = db.Execute(ctx, schema); err != nil { + panic(err) + } + + r := &row{S: "foo"} + if _, _, err = db.Execute(ctx, ins, MustMarshal(r)...); err != nil { + panic(err) + } + + i42 := int64(42) + r = &row{S: "bar", P: &i42} + if _, _, err = db.Execute(ctx, ins, MustMarshal(r)...); err != nil { + panic(err) + } + + rs, _, err := db.Execute(nil, sel) + if err != nil { + panic(err) + } + + for _, rs := range rs { + fmt.Println("----") + if err := rs.Do(false, func(data []interface{}) (bool, error) { + r := &row{} + if err := Unmarshal(r, data); err != nil { + return false, err + } + + fmt.Printf("ID %d, S %q, P ", r.ID, r.S) + switch r.P == nil { + case true: + fmt.Println("") + default: + fmt.Println(*r.P) + } + return true, nil + }); err != nil { + panic(err) + } + } + // Output: + // ---- + // ID 1, S "foo", P + // ID 2, S "bar", P 42 + // ---- + // ID 0, S "foo", P + // ID 0, S "bar", P 42 +} diff --git a/Godeps/_workspace/src/github.com/cznic/ql/mem.go b/Godeps/_workspace/src/github.com/cznic/ql/mem.go new file mode 100644 index 0000000..9f5cc68 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/ql/mem.go @@ -0,0 +1,1270 @@ +// Copyright (c) 2014 ql Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Plain memory storage back end. + +package ql + +import ( + "bytes" + "fmt" + "io" + "log" + "math/big" + "time" +) + +var ( + _ btreeIndex = (*memIndex)(nil) + _ btreeIterator = (*memBTreeIterator)(nil) + _ indexIterator = (*xenumerator2)(nil) + _ storage = (*mem)(nil) + _ temp = (*memTemp)(nil) +) + +type memIndex struct { + m *mem + t *xtree + unique bool +} + +func newMemIndex(m *mem, unique bool) *memIndex { + return &memIndex{t: xtreeNew(), unique: unique, m: m} +} + +func (x *memIndex) Clear() error { + x.m.newUndo(undoClearX, 0, []interface{}{x, x.t}) + x.t = xtreeNew() + return nil +} + +func (x *memIndex) Create(indexedValue interface{}, h int64) error { + t := x.t + switch { + case !x.unique: + k := indexKey{indexedValue, h} + x.m.newUndo(undoCreateX, 0, []interface{}{x, k}) + t.Set(k, 0) + case indexedValue == nil: // unique, NULL + k := indexKey{nil, h} + x.m.newUndo(undoCreateX, 0, []interface{}{x, k}) + t.Set(k, 0) + default: // unique, non NULL + k := indexKey{indexedValue, 0} + if _, ok := t.Get(k); ok { //LATER need .Put + return fmt.Errorf("cannot insert into unique index: duplicate value: %v", indexedValue) + } + + x.m.newUndo(undoCreateX, 0, []interface{}{x, k}) + t.Set(k, int(h)) + } + return nil +} + +func (x *memIndex) Delete(indexedValue interface{}, h int64) error { + t := x.t + var k indexKey + var v interface{} + var ok, okv bool + switch { + case !x.unique: + k = indexKey{indexedValue, h} + v, okv = t.Get(k) + ok = t.delete(k) + case indexedValue == nil: // unique, NULL + k = indexKey{nil, h} + v, okv = t.Get(k) + ok = t.delete(k) + default: // unique, non NULL + k = indexKey{indexedValue, 0} + v, okv = t.Get(k) + ok = t.delete(k) + } + if ok { + if okv { + x.m.newUndo(undoDeleteX, int64(v.(int)), []interface{}{x, k}) + } + return nil + } + + return fmt.Errorf("internal error 047") +} + +func (x *memIndex) Drop() error { + x.m.newUndo(undoDropX, 0, []interface{}{x, *x}) + *x = memIndex{} + return nil +} + +func (x *memIndex) Seek(indexedValue interface{}) (indexIterator, bool, error) { + it, hit := x.t.Seek(indexKey{indexedValue, 0}) + return &xenumerator2{*it, x.unique}, hit, nil +} + +func (x *memIndex) SeekFirst() (iter indexIterator, err error) { + it, err := x.t.SeekFirst() + if err != nil { + return nil, err + } + + return &xenumerator2{*it, x.unique}, nil +} + +func (x *memIndex) SeekLast() (iter indexIterator, err error) { + it, err := x.t.SeekLast() + if err != nil { + return nil, err + } + + return &xenumerator2{*it, x.unique}, nil +} + +type xenumerator2 struct { + it xenumerator + unique bool +} + +func (it *xenumerator2) Next() (interface{}, int64, error) { + k, h, err := it.it.Next() + if err != nil { + return nil, -1, err + } + + switch it.unique { + case true: + if k.value == nil { + return nil, k.h, nil + } + + return k.value, h, nil + default: + return k.value, k.h, nil + } +} + +func (it *xenumerator2) Prev() (interface{}, int64, error) { + k, h, err := it.it.Prev() + if err != nil { + return nil, -1, err + } + + switch it.unique { + case true: + if k.value == nil { + return nil, k.h, nil + } + + return k.value, h, nil + default: + return k.value, k.h, nil + } +} + +type memBTreeIterator enumerator + +func (it *memBTreeIterator) Next() (k, v []interface{}, err error) { + return (*enumerator)(it).Next() +} + +type memTemp struct { + tree *tree + store *mem +} + +func (t *memTemp) BeginTransaction() (err error) { + return nil +} + +func (t *memTemp) Get(k []interface{}) (v []interface{}, err error) { + v, _ = t.tree.Get(k) + return +} + +func (t *memTemp) Create(data ...interface{}) (h int64, err error) { + s := t.store + switch n := len(s.recycler); { + case n != 0: + h = int64(s.recycler[n-1]) + s.recycler = s.recycler[:n-1] + s.data[h] = s.clone(data...) + default: + h = int64(len(s.data)) + s.data = append(s.data, s.clone(data...)) + } + return +} + +func (t *memTemp) Read(dst []interface{}, h int64, cols ...*col) (data []interface{}, err error) { + return t.store.Read(dst, h, cols...) +} + +func (*memTemp) Drop() (err error) { return } + +func (t *memTemp) Set(k, v []interface{}) (err error) { + t.tree.Set(append([]interface{}(nil), k...), t.store.clone(v...)) + return +} + +func (t *memTemp) SeekFirst() (e btreeIterator, err error) { + en, err := t.tree.SeekFirst() + if err != nil { + return + } + + return (*memBTreeIterator)(en), nil +} + +const ( + undoCreateNewHandle = iota + undoCreateRecycledHandle + undoUpdate + undoDelete + undoClearX // {0: *memIndex, 1: *xtree} + undoCreateX // {0: *memIndex, 1: indexKey} + undoDeleteX // {0: *memIndex, 1: indexKey} + undoDropX // {0: *memIndex, 1: memIndex} +) + +type undo struct { + tag int + h int64 + data []interface{} +} + +type undos struct { + list []undo + parent *undos +} + +type mem struct { + data [][]interface{} + id int64 + recycler []int + tnl int + rollback *undos +} + +func newMemStorage() (s *mem, err error) { + s = &mem{data: [][]interface{}{nil}} + if err = s.BeginTransaction(); err != nil { + return nil, err + } + + h, err := s.Create() + if h != 1 { + log.Panic("internal error 048") + } + + if err = s.Commit(); err != nil { + return nil, err + } + + return +} + +func (s *mem) OpenIndex(unique bool, handle int64) (btreeIndex, error) { // Never called on the memory backend. + panic("internal error 049") +} + +func (s *mem) newUndo(tag int, h int64, data []interface{}) { + s.rollback.list = append(s.rollback.list, undo{tag, h, data}) +} + +func (s *mem) Acid() bool { return false } + +func (s *mem) Close() (err error) { + *s = mem{} + return +} + +func (s *mem) CreateIndex(unique bool) ( /* handle */ int64, btreeIndex, error) { + return -1, newMemIndex(s, unique), nil // handle of memIndex should never be used +} + +func (s *mem) Name() string { return fmt.Sprintf("/proc/self/mem/%p", s) } // fake, non existing name + +// OpenMem returns a new, empty DB backed by the process' memory. The back end +// has no limits on field/record/table/DB size other than memory available to +// the process. +func OpenMem() (db *DB, err error) { + s, err := newMemStorage() + if err != nil { + return + } + + if db, err = newDB(s); err != nil { + return nil, err + } + + db.isMem = true + return db, nil +} + +func (s *mem) Verify() (allocs int64, err error) { + for _, v := range s.recycler { + if s.data[v] != nil { + return 0, fmt.Errorf("corrupted: non nil free handle %d", s.data[v]) + } + } + + for _, v := range s.data { + if v != nil { + allocs++ + } + } + + if allocs != int64(len(s.data))-1-int64(len(s.recycler)) { + return 0, fmt.Errorf("corrupted: len(data) %d, len(recycler) %d, allocs %d", len(s.data), len(s.recycler), allocs) + } + + return +} + +func (s *mem) String() string { + var b bytes.Buffer + for i, v := range s.data { + b.WriteString(fmt.Sprintf("s.data[%d] %#v\n", i, v)) + } + for i, v := range s.recycler { + b.WriteString(fmt.Sprintf("s.recycler[%d] %v\n", i, v)) + } + return b.String() +} + +func (s *mem) CreateTemp(asc bool) (_ temp, err error) { + st, err := newMemStorage() + if err != nil { + return + } + + return &memTemp{ + tree: treeNew(collators[asc]), + store: st, + }, nil +} + +func (s *mem) ResetID() (err error) { + s.id = 0 + return +} + +func (s *mem) ID() (id int64, err error) { + s.id++ + return s.id, nil +} + +func (s *mem) clone(data ...interface{}) []interface{} { + r := make([]interface{}, len(data)) + for i, v := range data { + switch x := v.(type) { + case nil: + // nop + case idealComplex: + r[i] = complex128(x) + case idealFloat: + r[i] = float64(x) + case idealInt: + r[i] = int64(x) + case idealRune: + r[i] = int32(x) + case idealUint: + r[i] = uint64(x) + case bool: + r[i] = x + case complex64: + r[i] = x + case complex128: + r[i] = x + case float32: + r[i] = x + case float64: + r[i] = x + case int: + r[i] = int64(x) + case int8: + r[i] = x + case int16: + r[i] = x + case int32: + r[i] = x + case int64: + r[i] = x + case string: + r[i] = x + case uint: + r[i] = uint64(x) + case uint8: + r[i] = x + case uint16: + r[i] = x + case uint32: + r[i] = x + case uint64: + r[i] = x + case []byte: + r[i] = append([]byte(nil), x...) + case *big.Int: + r[i] = big.NewInt(0).Set(x) + case *big.Rat: + r[i] = big.NewRat(1, 2).Set(x) + case time.Time: + t := x + r[i] = t + case time.Duration: + r[i] = x + case map[string]interface{}: // map of ids of a cross join + r[i] = x + default: + log.Panic("internal error 050") + } + } + return r +} + +func (s *mem) Create(data ...interface{}) (h int64, err error) { + switch n := len(s.recycler); { + case n != 0: + h = int64(s.recycler[n-1]) + s.recycler = s.recycler[:n-1] + s.data[h] = s.clone(data...) + r := s.rollback + r.list = append(r.list, undo{ + tag: undoCreateRecycledHandle, + h: h, + }) + default: + h = int64(len(s.data)) + s.data = append(s.data, s.clone(data...)) + r := s.rollback + r.list = append(r.list, undo{ + tag: undoCreateNewHandle, + h: h, + }) + } + return +} + +func (s *mem) Read(dst []interface{}, h int64, cols ...*col) (data []interface{}, err error) { + if i := int(h); i != 0 && i < len(s.data) { + d := s.clone(s.data[h]...) + if cols == nil { + return d, nil + } + + for n, dn := len(cols)+2, len(d); dn < n; dn++ { + d = append(d, nil) + } + return d, nil + } + + return nil, errNoDataForHandle +} + +func (s *mem) UpdateRow(h int64, _ []*col, data ...interface{}) (err error) { + return s.Update(h, data...) +} + +func (s *mem) Update(h int64, data ...interface{}) (err error) { + r := s.rollback + r.list = append(r.list, undo{ + tag: undoUpdate, + h: h, + data: s.data[h], + }) + s.data[h] = s.clone(data...) + return +} + +func (s *mem) Delete(h int64, _ ...*col) (err error) { + r := s.rollback + r.list = append(r.list, undo{ + tag: undoDelete, + h: h, + data: s.data[h], + }) + s.recycler = append(s.recycler, int(h)) + s.data[h] = nil + return +} + +func (s *mem) BeginTransaction() (err error) { + s.rollback = &undos{parent: s.rollback} + s.tnl++ + return nil +} + +func (s *mem) Rollback() (err error) { + if s.tnl == 0 { + return errRollbackNotInTransaction + } + + list := s.rollback.list + for i := len(list) - 1; i >= 0; i-- { + undo := list[i] + switch h, data := int(undo.h), undo.data; undo.tag { + case undoCreateNewHandle: + d := s.data + s.data = d[:len(d)-1] + case undoCreateRecycledHandle: + s.data[h] = nil + r := s.recycler + s.recycler = append(r, h) + case undoUpdate: + s.data[h] = data + case undoDelete: + s.data[h] = data + s.recycler = s.recycler[:len(s.recycler)-1] + case undoClearX: + x, t := data[0].(*memIndex), data[1].(*xtree) + x.t = t + case undoCreateX: + x, k := data[0].(*memIndex), data[1].(indexKey) + x.t.delete(k) + case undoDeleteX: + x, k := data[0].(*memIndex), data[1].(indexKey) + x.t.Set(k, h) + case undoDropX: + x, v := data[0].(*memIndex), data[1].(memIndex) + *x = v + default: + log.Panic("internal error 051") + } + } + + s.tnl-- + s.rollback = s.rollback.parent + return nil +} + +func (s *mem) Commit() (err error) { + if s.tnl == 0 { + return errCommitNotInTransaction + } + + s.tnl-- + s.rollback = s.rollback.parent + return nil +} + +// Transaction index B+Tree +//LATER make it just a wrapper of the implementation in btree.go. + +type ( + xd struct { // data page + c int + xd [2*kd + 1]xde + n *xd + p *xd + } + + xde struct { // xd element + k indexKey + v int + } + + // xenumerator captures the state of enumerating a tree. It is returned + // from the Seek* methods. The enumerator is aware of any mutations + // made to the tree in the process of enumerating it and automatically + // resumes the enumeration at the proper key, if possible. + // + // However, once an xenumerator returns io.EOF to signal "no more + // items", it does no more attempt to "resync" on tree mutation(s). In + // other words, io.EOF from an Enumaretor is "sticky" (idempotent). + xenumerator struct { + err error + hit bool + i int + k indexKey + q *xd + t *xtree + ver int64 + } + + // xtree is a B+tree. + xtree struct { + c int + first *xd + last *xd + r interface{} + ver int64 + } + + xxe struct { // xx element + ch interface{} + sep *xd + } + + xx struct { // index page + c int + xx [2*kx + 2]xxe + } +) + +func (a *indexKey) cmp(b *indexKey) int { + r := collate1(a.value, b.value) + if r != 0 { + return r + } + + return int(a.h) - int(b.h) +} + +var ( // R/O zero values + zxd xd + zxde xde + zxx xx + zxxe xxe +) + +func xclr(q interface{}) { + switch xx := q.(type) { + case *xx: + for i := 0; i <= xx.c; i++ { // Ch0 Sep0 ... Chn-1 Sepn-1 Chn + xclr(xx.xx[i].ch) + } + *xx = zxx // GC + case *xd: + *xx = zxd // GC + } +} + +// -------------------------------------------------------------------------- xx + +func xnewX(ch0 interface{}) *xx { + r := &xx{} + r.xx[0].ch = ch0 + return r +} + +func (q *xx) extract(i int) { + q.c-- + if i < q.c { + copy(q.xx[i:], q.xx[i+1:q.c+1]) + q.xx[q.c].ch = q.xx[q.c+1].ch + q.xx[q.c].sep = nil // GC + q.xx[q.c+1] = zxxe // GC + } +} + +func (q *xx) insert(i int, xd *xd, ch interface{}) *xx { + c := q.c + if i < c { + q.xx[c+1].ch = q.xx[c].ch + copy(q.xx[i+2:], q.xx[i+1:c]) + q.xx[i+1].sep = q.xx[i].sep + } + c++ + q.c = c + q.xx[i].sep = xd + q.xx[i+1].ch = ch + return q +} + +func (q *xx) siblings(i int) (l, r *xd) { + if i >= 0 { + if i > 0 { + l = q.xx[i-1].ch.(*xd) + } + if i < q.c { + r = q.xx[i+1].ch.(*xd) + } + } + return +} + +// -------------------------------------------------------------------------- xd + +func (l *xd) mvL(r *xd, c int) { + copy(l.xd[l.c:], r.xd[:c]) + copy(r.xd[:], r.xd[c:r.c]) + l.c += c + r.c -= c +} + +func (l *xd) mvR(r *xd, c int) { + copy(r.xd[c:], r.xd[:r.c]) + copy(r.xd[:c], l.xd[l.c-c:]) + r.c += c + l.c -= c +} + +// ----------------------------------------------------------------------- xtree + +// xtreeNew returns a newly created, empty xtree. The compare function is used +// for key collation. +func xtreeNew() *xtree { + return &xtree{} +} + +// Clear removes all K/V pairs from the tree. +func (t *xtree) Clear() { + if t.r == nil { + return + } + + xclr(t.r) + t.c, t.first, t.last, t.r = 0, nil, nil, nil + t.ver++ +} + +func (t *xtree) cat(p *xx, q, r *xd, pi int) { + t.ver++ + q.mvL(r, r.c) + if r.n != nil { + r.n.p = q + } else { + t.last = q + } + q.n = r.n + if p.c > 1 { + p.extract(pi) + p.xx[pi].ch = q + } else { + t.r = q + } +} + +func (t *xtree) catX(p, q, r *xx, pi int) { + t.ver++ + q.xx[q.c].sep = p.xx[pi].sep + copy(q.xx[q.c+1:], r.xx[:r.c]) + q.c += r.c + 1 + q.xx[q.c].ch = r.xx[r.c].ch + if p.c > 1 { + p.c-- + pc := p.c + if pi < pc { + p.xx[pi].sep = p.xx[pi+1].sep + copy(p.xx[pi+1:], p.xx[pi+2:pc+1]) + p.xx[pc].ch = p.xx[pc+1].ch + p.xx[pc].sep = nil // GC + p.xx[pc+1].ch = nil // GC + } + return + } + + t.r = q +} + +//Delete removes the k's KV pair, if it exists, in which case Delete returns +//true. +func (t *xtree) delete(k indexKey) (ok bool) { + pi := -1 + var p *xx + q := t.r + if q == nil { + return + } + + for { + var i int + i, ok = t.find(q, k) + if ok { + switch xx := q.(type) { + case *xx: + dp := xx.xx[i].sep + switch { + case dp.c > kd: + t.extract(dp, 0) + default: + if xx.c < kx && q != t.r { + t.underflowX(p, &xx, pi, &i) + } + pi = i + 1 + p = xx + q = xx.xx[pi].ch + ok = false + continue + } + case *xd: + t.extract(xx, i) + if xx.c >= kd { + return + } + + if q != t.r { + t.underflow(p, xx, pi) + } else if t.c == 0 { + t.Clear() + } + } + return + } + + switch xx := q.(type) { + case *xx: + if xx.c < kx && q != t.r { + t.underflowX(p, &xx, pi, &i) + } + pi = i + p = xx + q = xx.xx[i].ch + case *xd: + return + } + } +} + +func (t *xtree) extract(q *xd, i int) { // (r int64) { + t.ver++ + //r = q.xd[i].v // prepared for Extract + q.c-- + if i < q.c { + copy(q.xd[i:], q.xd[i+1:q.c+1]) + } + q.xd[q.c] = zxde // GC + t.c-- + return +} + +func (t *xtree) find(q interface{}, k indexKey) (i int, ok bool) { + var mk indexKey + l := 0 + switch xx := q.(type) { + case *xx: + h := xx.c - 1 + for l <= h { + m := (l + h) >> 1 + mk = xx.xx[m].sep.xd[0].k + switch cmp := k.cmp(&mk); { + case cmp > 0: + l = m + 1 + case cmp == 0: + return m, true + default: + h = m - 1 + } + } + case *xd: + h := xx.c - 1 + for l <= h { + m := (l + h) >> 1 + mk = xx.xd[m].k + switch cmp := k.cmp(&mk); { + case cmp > 0: + l = m + 1 + case cmp == 0: + return m, true + default: + h = m - 1 + } + } + } + return l, false +} + +// First returns the first item of the tree in the key collating order, or +// (nil, nil) if the tree is empty. +func (t *xtree) First() (k indexKey, v int) { + if q := t.first; q != nil { + q := &q.xd[0] + k, v = q.k, q.v + } + return +} + +// Get returns the value associated with k and true if it exists. Otherwise Get +// returns (nil, false). +func (t *xtree) Get(k indexKey) (v int, ok bool) { + q := t.r + if q == nil { + return + } + + for { + var i int + if i, ok = t.find(q, k); ok { + switch xx := q.(type) { + case *xx: + return xx.xx[i].sep.xd[0].v, true + case *xd: + return xx.xd[i].v, true + } + } + switch xx := q.(type) { + case *xx: + q = xx.xx[i].ch + default: + return + } + } +} + +func (t *xtree) insert(q *xd, i int, k indexKey, v int) *xd { + t.ver++ + c := q.c + if i < c { + copy(q.xd[i+1:], q.xd[i:c]) + } + c++ + q.c = c + q.xd[i].k, q.xd[i].v = k, v + t.c++ + return q +} + +// Last returns the last item of the tree in the key collating order, or (nil, +// nil) if the tree is empty. +func (t *xtree) Last() (k indexKey, v int) { + if q := t.last; q != nil { + q := &q.xd[q.c-1] + k, v = q.k, q.v + } + return +} + +// Len returns the number of items in the tree. +func (t *xtree) Len() int { + return t.c +} + +func (t *xtree) overflow(p *xx, q *xd, pi, i int, k indexKey, v int) { + t.ver++ + l, r := p.siblings(pi) + + if l != nil && l.c < 2*kd { + l.mvL(q, 1) + t.insert(q, i-1, k, v) + return + } + + if r != nil && r.c < 2*kd { + if i < 2*kd { + q.mvR(r, 1) + t.insert(q, i, k, v) + } else { + t.insert(r, 0, k, v) + } + return + } + + t.split(p, q, pi, i, k, v) +} + +// Seek returns an xenumerator positioned on a an item such that k >= item's +// key. ok reports if k == item.key The xenumerator's position is possibly +// after the last item in the tree. +func (t *xtree) Seek(k indexKey) (e *xenumerator, ok bool) { + q := t.r + if q == nil { + e = &xenumerator{nil, false, 0, k, nil, t, t.ver} + return + } + + for { + var i int + if i, ok = t.find(q, k); ok { + switch xx := q.(type) { + case *xx: + e = &xenumerator{nil, ok, 0, k, xx.xx[i].sep, t, t.ver} + return + case *xd: + e = &xenumerator{nil, ok, i, k, xx, t, t.ver} + return + } + } + switch xx := q.(type) { + case *xx: + q = xx.xx[i].ch + case *xd: + e = &xenumerator{nil, ok, i, k, xx, t, t.ver} + return + } + } +} + +// SeekFirst returns an enumerator positioned on the first KV pair in the tree, +// if any. For an empty tree, err == io.EOF is returned and e will be nil. +func (t *xtree) SeekFirst() (e *xenumerator, err error) { + q := t.first + if q == nil { + return nil, io.EOF + } + + return &xenumerator{nil, true, 0, q.xd[0].k, q, t, t.ver}, nil +} + +// SeekLast returns an enumerator positioned on the last KV pair in the tree, +// if any. For an empty tree, err == io.EOF is returned and e will be nil. +func (t *xtree) SeekLast() (e *xenumerator, err error) { + q := t.last + if q == nil { + return nil, io.EOF + } + + return &xenumerator{nil, true, q.c - 1, q.xd[q.c-1].k, q, t, t.ver}, nil +} + +// Set sets the value associated with k. +func (t *xtree) Set(k indexKey, v int) { + pi := -1 + var p *xx + q := t.r + if q != nil { + for { + i, ok := t.find(q, k) + if ok { + switch xx := q.(type) { + case *xx: + xx.xx[i].sep.xd[0].v = v + case *xd: + xx.xd[i].v = v + } + return + } + + switch xx := q.(type) { + case *xx: + if xx.c > 2*kx { + t.splitX(p, &xx, pi, &i) + } + pi = i + p = xx + q = xx.xx[i].ch + case *xd: + switch { + case xx.c < 2*kd: + t.insert(xx, i, k, v) + default: + t.overflow(p, xx, pi, i, k, v) + } + return + } + } + } + + z := t.insert(&xd{}, 0, k, v) + t.r, t.first, t.last = z, z, z + return +} + +func (t *xtree) split(p *xx, q *xd, pi, i int, k indexKey, v int) { + t.ver++ + r := &xd{} + if q.n != nil { + r.n = q.n + r.n.p = r + } else { + t.last = r + } + q.n = r + r.p = q + + copy(r.xd[:], q.xd[kd:2*kd]) + for i := range q.xd[kd:] { + q.xd[kd+i] = zxde + } + q.c = kd + r.c = kd + if pi >= 0 { + p.insert(pi, r, r) + } else { + t.r = xnewX(q).insert(0, r, r) + } + if i > kd { + t.insert(r, i-kd, k, v) + return + } + + t.insert(q, i, k, v) +} + +func (t *xtree) splitX(p *xx, pp **xx, pi int, i *int) { + t.ver++ + q := *pp + r := &xx{} + copy(r.xx[:], q.xx[kx+1:]) + q.c = kx + r.c = kx + if pi >= 0 { + p.insert(pi, q.xx[kx].sep, r) + } else { + t.r = xnewX(q).insert(0, q.xx[kx].sep, r) + } + q.xx[kx].sep = nil + for i := range q.xx[kx+1:] { + q.xx[kx+i+1] = zxxe + } + if *i > kx { + *pp = r + *i -= kx + 1 + } +} + +func (t *xtree) underflow(p *xx, q *xd, pi int) { + t.ver++ + l, r := p.siblings(pi) + + if l != nil && l.c+q.c >= 2*kd { + l.mvR(q, 1) + } else if r != nil && q.c+r.c >= 2*kd { + q.mvL(r, 1) + r.xd[r.c] = zxde // GC + } else if l != nil { + t.cat(p, l, q, pi-1) + } else { + t.cat(p, q, r, pi) + } +} + +func (t *xtree) underflowX(p *xx, pp **xx, pi int, i *int) { + t.ver++ + var l, r *xx + q := *pp + + if pi >= 0 { + if pi > 0 { + l = p.xx[pi-1].ch.(*xx) + } + if pi < p.c { + r = p.xx[pi+1].ch.(*xx) + } + } + + if l != nil && l.c > kx { + q.xx[q.c+1].ch = q.xx[q.c].ch + copy(q.xx[1:], q.xx[:q.c]) + q.xx[0].ch = l.xx[l.c].ch + q.xx[0].sep = p.xx[pi-1].sep + q.c++ + *i++ + l.c-- + p.xx[pi-1].sep = l.xx[l.c].sep + return + } + + if r != nil && r.c > kx { + q.xx[q.c].sep = p.xx[pi].sep + q.c++ + q.xx[q.c].ch = r.xx[0].ch + p.xx[pi].sep = r.xx[0].sep + copy(r.xx[:], r.xx[1:r.c]) + r.c-- + rc := r.c + r.xx[rc].ch = r.xx[rc+1].ch + r.xx[rc].sep = nil + r.xx[rc+1].ch = nil + return + } + + if l != nil { + *i += l.c + 1 + t.catX(p, l, q, pi-1) + *pp = l + return + } + + t.catX(p, q, r, pi) +} + +// ----------------------------------------------------------------- xenumerator + +// Next returns the currently enumerated item, if it exists and moves to the +// next item in the key collation order. If there is no item to return, err == +// io.EOF is returned. +func (e *xenumerator) Next() (k indexKey, v int64, err error) { + if err = e.err; err != nil { + return + } + + if e.ver != e.t.ver { + f, hit := e.t.Seek(e.k) + if !e.hit && hit { + if err = f.next(); err != nil { + return + } + } + + *e = *f + } + if e.q == nil { + e.err, err = io.EOF, io.EOF + return + } + + if e.i >= e.q.c { + if err = e.next(); err != nil { + return + } + } + + i := e.q.xd[e.i] + k, v = i.k, int64(i.v) + e.k, e.hit = k, false + e.next() + return +} + +func (e *xenumerator) next() error { + if e.q == nil { + e.err = io.EOF + return io.EOF + } + + switch { + case e.i < e.q.c-1: + e.i++ + default: + if e.q, e.i = e.q.n, 0; e.q == nil { + e.err = io.EOF + } + } + return e.err +} + +// Prev returns the currently enumerated item, if it exists and moves to the +// previous item in the key collation order. If there is no item to return, err +// == io.EOF is returned. +func (e *xenumerator) Prev() (k indexKey, v int64, err error) { + if err = e.err; err != nil { + return + } + + if e.ver != e.t.ver { + f, hit := e.t.Seek(e.k) + if !e.hit && hit { + if err = f.prev(); err != nil { + return + } + } + + *e = *f + } + if e.q == nil { + e.err, err = io.EOF, io.EOF + return + } + + if e.i >= e.q.c { + if err = e.next(); err != nil { + return + } + } + + i := e.q.xd[e.i] + k, v = i.k, int64(i.v) + e.k, e.hit = k, false + e.prev() + return +} + +func (e *xenumerator) prev() error { + if e.q == nil { + e.err = io.EOF + return io.EOF + } + + switch { + case e.i > 0: + e.i-- + default: + if e.q = e.q.p; e.q == nil { + e.err = io.EOF + break + } + + e.i = e.q.c - 1 + } + return e.err +} diff --git a/Godeps/_workspace/src/github.com/cznic/ql/parser.go b/Godeps/_workspace/src/github.com/cznic/ql/parser.go new file mode 100644 index 0000000..ac062e6 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/ql/parser.go @@ -0,0 +1,2061 @@ +// Copyright (c) 2014 The ql Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Inital yacc source generated by ebnf2y[1] +// at 2013-10-04 23:10:47.861401015 +0200 CEST +// +// $ ebnf2y -o ql.y -oe ql.ebnf -start StatementList -pkg ql -p _ +// +// CAUTION: If this file is a Go source file (*.go), it was generated +// automatically by '$ goyacc' from a *.y file - DO NOT EDIT in that case! +// +// [1]: http://github.com/cznic/ebnf2y + +package ql + +import __yyfmt__ "fmt" + +import ( + "fmt" + + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/mathutil" +) + +type yySymType struct { + yys int + line int + col int + item interface{} + list []interface{} +} + +type yyXError struct { + state, xsym int +} + +const ( + yyDefault = 57429 + yyEOFCode = 57344 + add = 57346 + alter = 57347 + and = 57348 + andand = 57349 + andnot = 57350 + as = 57351 + asc = 57352 + begin = 57353 + between = 57354 + bigIntType = 57355 + bigRatType = 57356 + blobType = 57357 + boolType = 57358 + by = 57359 + byteType = 57360 + column = 57361 + commit = 57362 + complex128Type = 57363 + complex64Type = 57364 + create = 57365 + deleteKwd = 57366 + desc = 57367 + distinct = 57368 + drop = 57369 + durationType = 57370 + eq = 57371 + yyErrCode = 57345 + exists = 57372 + falseKwd = 57373 + float32Type = 57375 + float64Type = 57376 + floatLit = 57377 + floatType = 57374 + from = 57378 + ge = 57379 + group = 57380 + identifier = 57381 + ifKwd = 57382 + imaginaryLit = 57383 + in = 57384 + index = 57385 + insert = 57386 + int16Type = 57388 + int32Type = 57389 + int64Type = 57390 + int8Type = 57391 + intLit = 57393 + intType = 57387 + into = 57392 + is = 57394 + le = 57395 + like = 57396 + limit = 57397 + lsh = 57398 + neq = 57399 + not = 57400 + null = 57401 + offset = 57402 + on = 57403 + or = 57404 + order = 57405 + oror = 57406 + qlParam = 57407 + rollback = 57408 + rsh = 57409 + runeType = 57410 + selectKwd = 57411 + set = 57412 + stringLit = 57414 + stringType = 57413 + tableKwd = 57415 + timeType = 57416 + transaction = 57417 + trueKwd = 57418 + truncate = 57419 + uint16Type = 57421 + uint32Type = 57422 + uint64Type = 57423 + uint8Type = 57424 + uintType = 57420 + unique = 57425 + update = 57426 + values = 57427 + where = 57428 + + yyMaxDepth = 200 + yyTabOfs = -206 +) + +var ( + yyXLAT = map[int]int{ + 59: 0, // ';' (181x) + 57344: 1, // $end (180x) + 41: 2, // ')' (156x) + 44: 3, // ',' (122x) + 40: 4, // '(' (119x) + 43: 5, // '+' (103x) + 45: 6, // '-' (103x) + 94: 7, // '^' (103x) + 57402: 8, // offset (102x) + 57397: 9, // limit (99x) + 57381: 10, // identifier (87x) + 57405: 11, // order (87x) + 57428: 12, // where (82x) + 57380: 13, // group (77x) + 57404: 14, // or (76x) + 57406: 15, // oror (76x) + 57378: 16, // from (74x) + 57352: 17, // asc (70x) + 57367: 18, // desc (70x) + 93: 19, // ']' (69x) + 57351: 20, // as (68x) + 58: 21, // ':' (66x) + 57348: 22, // and (66x) + 57349: 23, // andand (64x) + 124: 24, // '|' (55x) + 57400: 25, // not (55x) + 57355: 26, // bigIntType (54x) + 57356: 27, // bigRatType (54x) + 57357: 28, // blobType (54x) + 57358: 29, // boolType (54x) + 57360: 30, // byteType (54x) + 57363: 31, // complex128Type (54x) + 57364: 32, // complex64Type (54x) + 57370: 33, // durationType (54x) + 57375: 34, // float32Type (54x) + 57376: 35, // float64Type (54x) + 57374: 36, // floatType (54x) + 57388: 37, // int16Type (54x) + 57389: 38, // int32Type (54x) + 57390: 39, // int64Type (54x) + 57391: 40, // int8Type (54x) + 57387: 41, // intType (54x) + 57401: 42, // null (54x) + 57410: 43, // runeType (54x) + 57413: 44, // stringType (54x) + 57416: 45, // timeType (54x) + 57421: 46, // uint16Type (54x) + 57422: 47, // uint32Type (54x) + 57423: 48, // uint64Type (54x) + 57424: 49, // uint8Type (54x) + 57420: 50, // uintType (54x) + 57354: 51, // between (53x) + 57384: 52, // in (53x) + 60: 53, // '<' (52x) + 62: 54, // '>' (52x) + 57371: 55, // eq (52x) + 57373: 56, // falseKwd (52x) + 57377: 57, // floatLit (52x) + 57379: 58, // ge (52x) + 57383: 59, // imaginaryLit (52x) + 57393: 60, // intLit (52x) + 57394: 61, // is (52x) + 57395: 62, // le (52x) + 57396: 63, // like (52x) + 57399: 64, // neq (52x) + 57407: 65, // qlParam (52x) + 57414: 66, // stringLit (52x) + 57418: 67, // trueKwd (52x) + 33: 68, // '!' (48x) + 57499: 69, // Type (47x) + 42: 70, // '*' (46x) + 57444: 71, // Conversion (46x) + 57471: 72, // Literal (46x) + 57472: 73, // Operand (46x) + 57475: 74, // PrimaryExpression (46x) + 57478: 75, // QualifiedIdent (46x) + 37: 76, // '%' (43x) + 38: 77, // '&' (43x) + 47: 78, // '/' (43x) + 57350: 79, // andnot (43x) + 57398: 80, // lsh (43x) + 57409: 81, // rsh (43x) + 57500: 82, // UnaryExpr (42x) + 57477: 83, // PrimaryTerm (35x) + 57476: 84, // PrimaryFactor (31x) + 91: 85, // '[' (30x) + 57460: 86, // Factor (20x) + 57461: 87, // Factor1 (20x) + 57497: 88, // Term (19x) + 57456: 89, // Expression (18x) + 57505: 90, // logOr (12x) + 57439: 91, // ColumnName (10x) + 57411: 92, // selectKwd (9x) + 57496: 93, // TableName (9x) + 57457: 94, // ExpressionList (6x) + 57485: 95, // SelectStmt (6x) + 57436: 96, // Call (5x) + 57466: 97, // Index (5x) + 57493: 98, // Slice (5x) + 57438: 99, // ColumnDef (4x) + 57369: 100, // drop (4x) + 57372: 101, // exists (4x) + 57382: 102, // ifKwd (4x) + 57385: 103, // index (4x) + 57415: 104, // tableKwd (4x) + 57427: 105, // values (4x) + 57503: 106, // WhereClause (4x) + 61: 107, // '=' (2x) + 57346: 108, // add (2x) + 57347: 109, // alter (2x) + 57430: 110, // AlterTableStmt (2x) + 57431: 111, // Assignment (2x) + 57353: 112, // begin (2x) + 57435: 113, // BeginTransactionStmt (2x) + 57359: 114, // by (2x) + 57440: 115, // ColumnNameList (2x) + 57362: 116, // commit (2x) + 57443: 117, // CommitStmt (2x) + 57365: 118, // create (2x) + 57446: 119, // CreateIndexStmt (2x) + 57448: 120, // CreateTableStmt (2x) + 57449: 121, // CreateTableStmt1 (2x) + 57450: 122, // CreateTableStmt2 (2x) + 57451: 123, // DeleteFromStmt (2x) + 57366: 124, // deleteKwd (2x) + 57453: 125, // DropIndexStmt (2x) + 57454: 126, // DropTableStmt (2x) + 57455: 127, // EmptyStmt (2x) + 57462: 128, // Field (2x) + 57465: 129, // GroupByClause (2x) + 57386: 130, // insert (2x) + 57467: 131, // InsertIntoStmt (2x) + 57504: 132, // logAnd (2x) + 57473: 133, // OrderBy (2x) + 57479: 134, // RecordSet (2x) + 57480: 135, // RecordSet1 (2x) + 57408: 136, // rollback (2x) + 57484: 137, // RollbackStmt (2x) + 57488: 138, // SelectStmtGroup (2x) + 57489: 139, // SelectStmtLimit (2x) + 57490: 140, // SelectStmtOffset (2x) + 57491: 141, // SelectStmtOrder (2x) + 57492: 142, // SelectStmtWhere (2x) + 57412: 143, // set (2x) + 57494: 144, // Statement (2x) + 57419: 145, // truncate (2x) + 57498: 146, // TruncateTableStmt (2x) + 57426: 147, // update (2x) + 57501: 148, // UpdateStmt (2x) + 46: 149, // '.' (1x) + 57432: 150, // AssignmentList (1x) + 57433: 151, // AssignmentList1 (1x) + 57434: 152, // AssignmentList2 (1x) + 57437: 153, // Call1 (1x) + 57361: 154, // column (1x) + 57441: 155, // ColumnNameList1 (1x) + 57442: 156, // ColumnNameList2 (1x) + 57445: 157, // CreateIndexIfNotExists (1x) + 57447: 158, // CreateIndexStmtUnique (1x) + 57368: 159, // distinct (1x) + 57452: 160, // DropIndexIfExists (1x) + 57458: 161, // ExpressionList1 (1x) + 57459: 162, // ExpressionList2 (1x) + 57463: 163, // Field1 (1x) + 57464: 164, // FieldList (1x) + 57468: 165, // InsertIntoStmt1 (1x) + 57469: 166, // InsertIntoStmt2 (1x) + 57470: 167, // InsertIntoStmt3 (1x) + 57392: 168, // into (1x) + 57403: 169, // on (1x) + 57474: 170, // OrderBy1 (1x) + 57506: 171, // oSet (1x) + 57481: 172, // RecordSet11 (1x) + 57482: 173, // RecordSet2 (1x) + 57483: 174, // RecordSetList (1x) + 57486: 175, // SelectStmtDistinct (1x) + 57487: 176, // SelectStmtFieldList (1x) + 57495: 177, // StatementList (1x) + 57417: 178, // transaction (1x) + 57425: 179, // unique (1x) + 57502: 180, // UpdateStmt1 (1x) + 57429: 181, // $default (0x) + 57345: 182, // error (0x) + } + + yySymNames = []string{ + "';'", + "$end", + "')'", + "','", + "'('", + "'+'", + "'-'", + "'^'", + "offset", + "limit", + "identifier", + "order", + "where", + "group", + "or", + "oror", + "from", + "asc", + "desc", + "']'", + "as", + "':'", + "and", + "andand", + "'|'", + "not", + "bigIntType", + "bigRatType", + "blobType", + "boolType", + "byteType", + "complex128Type", + "complex64Type", + "durationType", + "float32Type", + "float64Type", + "floatType", + "int16Type", + "int32Type", + "int64Type", + "int8Type", + "intType", + "null", + "runeType", + "stringType", + "timeType", + "uint16Type", + "uint32Type", + "uint64Type", + "uint8Type", + "uintType", + "between", + "in", + "'<'", + "'>'", + "eq", + "falseKwd", + "floatLit", + "ge", + "imaginaryLit", + "intLit", + "is", + "le", + "like", + "neq", + "qlParam", + "stringLit", + "trueKwd", + "'!'", + "Type", + "'*'", + "Conversion", + "Literal", + "Operand", + "PrimaryExpression", + "QualifiedIdent", + "'%'", + "'&'", + "'/'", + "andnot", + "lsh", + "rsh", + "UnaryExpr", + "PrimaryTerm", + "PrimaryFactor", + "'['", + "Factor", + "Factor1", + "Term", + "Expression", + "logOr", + "ColumnName", + "selectKwd", + "TableName", + "ExpressionList", + "SelectStmt", + "Call", + "Index", + "Slice", + "ColumnDef", + "drop", + "exists", + "ifKwd", + "index", + "tableKwd", + "values", + "WhereClause", + "'='", + "add", + "alter", + "AlterTableStmt", + "Assignment", + "begin", + "BeginTransactionStmt", + "by", + "ColumnNameList", + "commit", + "CommitStmt", + "create", + "CreateIndexStmt", + "CreateTableStmt", + "CreateTableStmt1", + "CreateTableStmt2", + "DeleteFromStmt", + "deleteKwd", + "DropIndexStmt", + "DropTableStmt", + "EmptyStmt", + "Field", + "GroupByClause", + "insert", + "InsertIntoStmt", + "logAnd", + "OrderBy", + "RecordSet", + "RecordSet1", + "rollback", + "RollbackStmt", + "SelectStmtGroup", + "SelectStmtLimit", + "SelectStmtOffset", + "SelectStmtOrder", + "SelectStmtWhere", + "set", + "Statement", + "truncate", + "TruncateTableStmt", + "update", + "UpdateStmt", + "'.'", + "AssignmentList", + "AssignmentList1", + "AssignmentList2", + "Call1", + "column", + "ColumnNameList1", + "ColumnNameList2", + "CreateIndexIfNotExists", + "CreateIndexStmtUnique", + "distinct", + "DropIndexIfExists", + "ExpressionList1", + "ExpressionList2", + "Field1", + "FieldList", + "InsertIntoStmt1", + "InsertIntoStmt2", + "InsertIntoStmt3", + "into", + "on", + "OrderBy1", + "oSet", + "RecordSet11", + "RecordSet2", + "RecordSetList", + "SelectStmtDistinct", + "SelectStmtFieldList", + "StatementList", + "transaction", + "unique", + "UpdateStmt1", + "$default", + "error", + } + + yyReductions = map[int]struct{ xsym, components int }{ + 0: {0, 1}, + 1: {110, 5}, + 2: {110, 6}, + 3: {111, 3}, + 4: {150, 3}, + 5: {151, 0}, + 6: {151, 3}, + 7: {152, 0}, + 8: {152, 1}, + 9: {113, 2}, + 10: {96, 3}, + 11: {153, 0}, + 12: {153, 1}, + 13: {99, 2}, + 14: {91, 1}, + 15: {115, 3}, + 16: {155, 0}, + 17: {155, 3}, + 18: {156, 0}, + 19: {156, 1}, + 20: {117, 1}, + 21: {71, 4}, + 22: {119, 10}, + 23: {119, 12}, + 24: {157, 0}, + 25: {157, 3}, + 26: {158, 0}, + 27: {158, 1}, + 28: {120, 8}, + 29: {120, 11}, + 30: {121, 0}, + 31: {121, 3}, + 32: {122, 0}, + 33: {122, 1}, + 34: {123, 3}, + 35: {123, 4}, + 36: {125, 4}, + 37: {160, 0}, + 38: {160, 2}, + 39: {126, 3}, + 40: {126, 5}, + 41: {127, 0}, + 42: {89, 1}, + 43: {89, 3}, + 44: {90, 1}, + 45: {90, 1}, + 46: {94, 3}, + 47: {161, 0}, + 48: {161, 3}, + 49: {162, 0}, + 50: {162, 1}, + 51: {86, 1}, + 52: {86, 5}, + 53: {86, 6}, + 54: {86, 5}, + 55: {86, 6}, + 56: {86, 5}, + 57: {86, 6}, + 58: {86, 3}, + 59: {86, 4}, + 60: {87, 1}, + 61: {87, 3}, + 62: {87, 3}, + 63: {87, 3}, + 64: {87, 3}, + 65: {87, 3}, + 66: {87, 3}, + 67: {87, 3}, + 68: {128, 2}, + 69: {163, 0}, + 70: {163, 2}, + 71: {164, 1}, + 72: {164, 3}, + 73: {129, 3}, + 74: {97, 3}, + 75: {131, 10}, + 76: {131, 5}, + 77: {165, 0}, + 78: {165, 3}, + 79: {166, 0}, + 80: {166, 5}, + 81: {167, 0}, + 82: {167, 1}, + 83: {72, 1}, + 84: {72, 1}, + 85: {72, 1}, + 86: {72, 1}, + 87: {72, 1}, + 88: {72, 1}, + 89: {72, 1}, + 90: {73, 1}, + 91: {73, 1}, + 92: {73, 1}, + 93: {73, 3}, + 94: {133, 4}, + 95: {170, 0}, + 96: {170, 1}, + 97: {170, 1}, + 98: {74, 1}, + 99: {74, 1}, + 100: {74, 2}, + 101: {74, 2}, + 102: {74, 2}, + 103: {84, 1}, + 104: {84, 3}, + 105: {84, 3}, + 106: {84, 3}, + 107: {84, 3}, + 108: {83, 1}, + 109: {83, 3}, + 110: {83, 3}, + 111: {83, 3}, + 112: {83, 3}, + 113: {83, 3}, + 114: {83, 3}, + 115: {83, 3}, + 116: {75, 1}, + 117: {75, 3}, + 118: {134, 2}, + 119: {135, 1}, + 120: {135, 4}, + 121: {172, 0}, + 122: {172, 1}, + 123: {173, 0}, + 124: {173, 2}, + 125: {174, 1}, + 126: {174, 3}, + 127: {137, 1}, + 128: {95, 10}, + 129: {95, 11}, + 130: {139, 0}, + 131: {139, 2}, + 132: {140, 0}, + 133: {140, 2}, + 134: {175, 0}, + 135: {175, 1}, + 136: {176, 1}, + 137: {176, 1}, + 138: {176, 2}, + 139: {142, 0}, + 140: {142, 1}, + 141: {138, 0}, + 142: {138, 1}, + 143: {141, 0}, + 144: {141, 1}, + 145: {98, 3}, + 146: {98, 4}, + 147: {98, 4}, + 148: {98, 5}, + 149: {144, 1}, + 150: {144, 1}, + 151: {144, 1}, + 152: {144, 1}, + 153: {144, 1}, + 154: {144, 1}, + 155: {144, 1}, + 156: {144, 1}, + 157: {144, 1}, + 158: {144, 1}, + 159: {144, 1}, + 160: {144, 1}, + 161: {144, 1}, + 162: {144, 1}, + 163: {177, 1}, + 164: {177, 3}, + 165: {93, 1}, + 166: {88, 1}, + 167: {88, 3}, + 168: {132, 1}, + 169: {132, 1}, + 170: {146, 3}, + 171: {69, 1}, + 172: {69, 1}, + 173: {69, 1}, + 174: {69, 1}, + 175: {69, 1}, + 176: {69, 1}, + 177: {69, 1}, + 178: {69, 1}, + 179: {69, 1}, + 180: {69, 1}, + 181: {69, 1}, + 182: {69, 1}, + 183: {69, 1}, + 184: {69, 1}, + 185: {69, 1}, + 186: {69, 1}, + 187: {69, 1}, + 188: {69, 1}, + 189: {69, 1}, + 190: {69, 1}, + 191: {69, 1}, + 192: {69, 1}, + 193: {69, 1}, + 194: {69, 1}, + 195: {148, 5}, + 196: {180, 0}, + 197: {180, 1}, + 198: {82, 1}, + 199: {82, 2}, + 200: {82, 2}, + 201: {82, 2}, + 202: {82, 2}, + 203: {106, 2}, + 204: {171, 0}, + 205: {171, 1}, + } + + yyXErrors = map[yyXError]string{} + + yyParseTab = [335][]uint16{ + // 0 + {165, 165, 92: 216, 95: 228, 100: 213, 109: 208, 218, 112: 209, 219, 116: 210, 220, 211, 221, 222, 123: 223, 212, 224, 225, 217, 130: 214, 226, 136: 215, 227, 144: 231, 232, 229, 233, 230, 177: 207}, + {539, 206}, + {104: 532}, + {178: 531}, + {186, 186}, + // 5 + {103: 180, 497, 158: 495, 179: 496}, + {16: 492}, + {103: 482, 483}, + {168: 465}, + {79, 79}, + // 10 + {4: 72, 72, 72, 72, 10: 72, 26: 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 56: 72, 72, 59: 72, 72, 65: 72, 72, 72, 72, 70: 72, 159: 408, 175: 407}, + {57, 57}, + {56, 56}, + {55, 55}, + {54, 54}, + // 15 + {53, 53}, + {52, 52}, + {51, 51}, + {50, 50}, + {49, 49}, + // 20 + {48, 48}, + {47, 47}, + {46, 46}, + {45, 45}, + {44, 44}, + // 25 + {43, 43}, + {104: 405}, + {10: 234, 93: 235}, + {41, 41, 4: 41, 10: 41, 12: 41, 92: 41, 100: 41, 105: 41, 108: 41, 143: 41}, + {10: 2, 143: 237, 171: 236}, + // 30 + {10: 240, 91: 238, 111: 239, 150: 241}, + {10: 1}, + {107: 403}, + {201, 201, 3: 201, 12: 201, 151: 399}, + {192, 192, 192, 192, 8: 192, 192, 11: 192, 26: 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 43: 192, 192, 192, 192, 192, 192, 192, 192, 107: 192}, + // 35 + {10, 10, 12: 244, 106: 243, 180: 242}, + {11, 11}, + {9, 9}, + {4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 265, 264, 249, 86: 267, 248, 246, 247}, + {4: 396}, + // 40 + {164, 164, 164, 164, 8: 164, 164, 11: 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 313, 312, 132: 311}, + {3, 3, 3, 8: 3, 3, 11: 3, 13: 3, 308, 307, 90: 306}, + {155, 155, 155, 155, 8: 155, 155, 11: 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 25: 358, 51: 359, 357, 364, 362, 366, 58: 361, 61: 360, 363, 367, 365}, + {146, 146, 146, 146, 5: 352, 351, 349, 146, 146, 11: 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 350, 146, 51: 146, 146, 146, 146, 146, 58: 146, 61: 146, 146, 146, 146}, + {123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 11: 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 51: 123, 123, 123, 123, 123, 58: 123, 61: 123, 123, 123, 123, 70: 123, 76: 123, 123, 123, 123, 123, 123, 85: 123}, + // 45 + {122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 11: 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 51: 122, 122, 122, 122, 122, 58: 122, 61: 122, 122, 122, 122, 70: 122, 76: 122, 122, 122, 122, 122, 122, 85: 122}, + {121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 11: 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 51: 121, 121, 121, 121, 121, 58: 121, 61: 121, 121, 121, 121, 70: 121, 76: 121, 121, 121, 121, 121, 121, 85: 121}, + {120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 11: 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 51: 120, 120, 120, 120, 120, 58: 120, 61: 120, 120, 120, 120, 70: 120, 76: 120, 120, 120, 120, 120, 120, 85: 120}, + {119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 11: 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 51: 119, 119, 119, 119, 119, 58: 119, 61: 119, 119, 119, 119, 70: 119, 76: 119, 119, 119, 119, 119, 119, 85: 119}, + {118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 11: 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 51: 118, 118, 118, 118, 118, 58: 118, 61: 118, 118, 118, 118, 70: 118, 76: 118, 118, 118, 118, 118, 118, 85: 118}, + // 50 + {117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 11: 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 51: 117, 117, 117, 117, 117, 58: 117, 61: 117, 117, 117, 117, 70: 117, 76: 117, 117, 117, 117, 117, 117, 85: 117}, + {116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 11: 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 51: 116, 116, 116, 116, 116, 58: 116, 61: 116, 116, 116, 116, 70: 116, 76: 116, 116, 116, 116, 116, 116, 85: 116}, + {115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 11: 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 51: 115, 115, 115, 115, 115, 58: 115, 61: 115, 115, 115, 115, 70: 115, 76: 115, 115, 115, 115, 115, 115, 85: 115}, + {114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 11: 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 51: 114, 114, 114, 114, 114, 58: 114, 61: 114, 114, 114, 114, 70: 114, 76: 114, 114, 114, 114, 114, 114, 85: 114}, + {4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 265, 264, 249, 86: 267, 248, 246, 347}, + // 55 + {108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 11: 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 51: 108, 108, 108, 108, 108, 58: 108, 61: 108, 108, 108, 108, 70: 108, 76: 108, 108, 108, 108, 108, 108, 85: 108}, + {107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 11: 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 51: 107, 107, 107, 107, 107, 58: 107, 61: 107, 107, 107, 107, 70: 107, 76: 107, 107, 107, 107, 107, 107, 85: 107}, + {8, 8, 8, 8, 297, 8, 8, 8, 8, 8, 11: 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 51: 8, 8, 8, 8, 8, 58: 8, 61: 8, 8, 8, 8, 70: 8, 76: 8, 8, 8, 8, 8, 8, 85: 298, 96: 301, 299, 300}, + {103, 103, 103, 103, 5: 103, 103, 103, 103, 103, 11: 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 51: 103, 103, 103, 103, 103, 58: 103, 61: 103, 103, 103, 103, 70: 339, 76: 337, 334, 338, 333, 335, 336}, + {98, 98, 98, 98, 5: 98, 98, 98, 98, 98, 11: 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 51: 98, 98, 98, 98, 98, 58: 98, 61: 98, 98, 98, 98, 70: 98, 76: 98, 98, 98, 98, 98, 98}, + // 60 + {90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 11: 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 51: 90, 90, 90, 90, 90, 58: 90, 61: 90, 90, 90, 90, 70: 90, 76: 90, 90, 90, 90, 90, 90, 85: 90, 149: 331}, + {40, 40, 40, 40, 8: 40, 40, 11: 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40}, + {35, 35, 35, 35, 35}, + {34, 34, 34, 34, 34}, + {33, 33, 33, 33, 33}, + // 65 + {32, 32, 32, 32, 32}, + {31, 31, 31, 31, 31}, + {30, 30, 30, 30, 30}, + {29, 29, 29, 29, 29}, + {28, 28, 28, 28, 28}, + // 70 + {27, 27, 27, 27, 27}, + {26, 26, 26, 26, 26}, + {25, 25, 25, 25, 25}, + {24, 24, 24, 24, 24}, + {23, 23, 23, 23, 23}, + // 75 + {22, 22, 22, 22, 22}, + {21, 21, 21, 21, 21}, + {20, 20, 20, 20, 20}, + {19, 19, 19, 19, 19}, + {18, 18, 18, 18, 18}, + // 80 + {17, 17, 17, 17, 17}, + {16, 16, 16, 16, 16}, + {15, 15, 15, 15, 15}, + {14, 14, 14, 14, 14}, + {13, 13, 13, 13, 13}, + // 85 + {12, 12, 12, 12, 12}, + {4: 260, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 69: 245, 71: 262, 257, 261, 330, 259}, + {4: 260, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 69: 245, 71: 262, 257, 261, 329, 259}, + {4: 260, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 69: 245, 71: 262, 257, 261, 328, 259}, + {4: 260, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 69: 245, 71: 262, 257, 261, 296, 259}, + // 90 + {4, 4, 4, 4, 297, 4, 4, 4, 4, 4, 11: 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 51: 4, 4, 4, 4, 4, 58: 4, 61: 4, 4, 4, 4, 70: 4, 76: 4, 4, 4, 4, 4, 4, 85: 298, 96: 301, 299, 300}, + {2: 195, 4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 265, 264, 249, 86: 267, 248, 246, 322, 94: 321, 153: 320}, + {4: 260, 295, 294, 292, 10: 266, 21: 303, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 265, 264, 249, 86: 267, 248, 246, 302}, + {106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 11: 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 51: 106, 106, 106, 106, 106, 58: 106, 61: 106, 106, 106, 106, 70: 106, 76: 106, 106, 106, 106, 106, 106, 85: 106}, + {105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 11: 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 51: 105, 105, 105, 105, 105, 58: 105, 61: 105, 105, 105, 105, 70: 105, 76: 105, 105, 105, 105, 105, 105, 85: 105}, + // 95 + {104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 11: 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 51: 104, 104, 104, 104, 104, 58: 104, 61: 104, 104, 104, 104, 70: 104, 76: 104, 104, 104, 104, 104, 104, 85: 104}, + {14: 308, 307, 19: 315, 21: 316, 90: 306}, + {4: 260, 295, 294, 292, 10: 266, 19: 305, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 265, 264, 249, 86: 267, 248, 246, 304}, + {14: 308, 307, 19: 309, 90: 306}, + {61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 11: 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 51: 61, 61, 61, 61, 61, 58: 61, 61: 61, 61, 61, 61, 70: 61, 76: 61, 61, 61, 61, 61, 61, 85: 61}, + // 100 + {4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 265, 264, 249, 86: 267, 248, 310}, + {4: 162, 162, 162, 162, 10: 162, 26: 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 56: 162, 162, 59: 162, 162, 65: 162, 162, 162, 162}, + {4: 161, 161, 161, 161, 10: 161, 26: 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 56: 161, 161, 59: 161, 161, 65: 161, 161, 161, 161}, + {60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 11: 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 51: 60, 60, 60, 60, 60, 58: 60, 61: 60, 60, 60, 60, 70: 60, 76: 60, 60, 60, 60, 60, 60, 85: 60}, + {163, 163, 163, 163, 8: 163, 163, 11: 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 313, 312, 132: 311}, + // 105 + {4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 265, 264, 249, 86: 314, 248}, + {4: 38, 38, 38, 38, 10: 38, 26: 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 56: 38, 38, 59: 38, 38, 65: 38, 38, 38, 38}, + {4: 37, 37, 37, 37, 10: 37, 26: 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 56: 37, 37, 59: 37, 37, 65: 37, 37, 37, 37}, + {39, 39, 39, 39, 8: 39, 39, 11: 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39}, + {132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 11: 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 51: 132, 132, 132, 132, 132, 58: 132, 61: 132, 132, 132, 132, 70: 132, 76: 132, 132, 132, 132, 132, 132, 85: 132}, + // 110 + {4: 260, 295, 294, 292, 10: 266, 19: 318, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 265, 264, 249, 86: 267, 248, 246, 317}, + {14: 308, 307, 19: 319, 90: 306}, + {59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 11: 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 51: 59, 59, 59, 59, 59, 58: 59, 61: 59, 59, 59, 59, 70: 59, 76: 59, 59, 59, 59, 59, 59, 85: 59}, + {58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 11: 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 51: 58, 58, 58, 58, 58, 58: 58, 61: 58, 58, 58, 58, 70: 58, 76: 58, 58, 58, 58, 58, 58, 85: 58}, + {2: 327}, + // 115 + {2: 194}, + {159, 159, 159, 159, 8: 159, 159, 14: 308, 307, 17: 159, 159, 90: 306, 161: 323}, + {157, 157, 157, 325, 8: 157, 157, 17: 157, 157, 162: 324}, + {160, 160, 160, 8: 160, 160, 17: 160, 160}, + {156, 156, 156, 4: 260, 295, 294, 292, 156, 156, 266, 17: 156, 156, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 265, 264, 249, 86: 267, 248, 246, 326}, + // 120 + {158, 158, 158, 158, 8: 158, 158, 14: 308, 307, 17: 158, 158, 90: 306}, + {196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 11: 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 51: 196, 196, 196, 196, 196, 58: 196, 61: 196, 196, 196, 196, 70: 196, 76: 196, 196, 196, 196, 196, 196, 85: 196}, + {5, 5, 5, 5, 297, 5, 5, 5, 5, 5, 11: 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 51: 5, 5, 5, 5, 5, 58: 5, 61: 5, 5, 5, 5, 70: 5, 76: 5, 5, 5, 5, 5, 5, 85: 298, 96: 301, 299, 300}, + {6, 6, 6, 6, 297, 6, 6, 6, 6, 6, 11: 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 51: 6, 6, 6, 6, 6, 58: 6, 61: 6, 6, 6, 6, 70: 6, 76: 6, 6, 6, 6, 6, 6, 85: 298, 96: 301, 299, 300}, + {7, 7, 7, 7, 297, 7, 7, 7, 7, 7, 11: 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 51: 7, 7, 7, 7, 7, 58: 7, 61: 7, 7, 7, 7, 70: 7, 76: 7, 7, 7, 7, 7, 7, 85: 298, 96: 301, 299, 300}, + // 125 + {10: 332}, + {89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 11: 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 51: 89, 89, 89, 89, 89, 58: 89, 61: 89, 89, 89, 89, 70: 89, 76: 89, 89, 89, 89, 89, 89, 85: 89}, + {4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 346}, + {4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 345}, + {4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 344}, + // 130 + {4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 343}, + {4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 342}, + {4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 341}, + {4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 340}, + {91, 91, 91, 91, 5: 91, 91, 91, 91, 91, 11: 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 51: 91, 91, 91, 91, 91, 58: 91, 61: 91, 91, 91, 91, 70: 91, 76: 91, 91, 91, 91, 91, 91}, + // 135 + {92, 92, 92, 92, 5: 92, 92, 92, 92, 92, 11: 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 51: 92, 92, 92, 92, 92, 58: 92, 61: 92, 92, 92, 92, 70: 92, 76: 92, 92, 92, 92, 92, 92}, + {93, 93, 93, 93, 5: 93, 93, 93, 93, 93, 11: 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 51: 93, 93, 93, 93, 93, 58: 93, 61: 93, 93, 93, 93, 70: 93, 76: 93, 93, 93, 93, 93, 93}, + {94, 94, 94, 94, 5: 94, 94, 94, 94, 94, 11: 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 51: 94, 94, 94, 94, 94, 58: 94, 61: 94, 94, 94, 94, 70: 94, 76: 94, 94, 94, 94, 94, 94}, + {95, 95, 95, 95, 5: 95, 95, 95, 95, 95, 11: 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 51: 95, 95, 95, 95, 95, 58: 95, 61: 95, 95, 95, 95, 70: 95, 76: 95, 95, 95, 95, 95, 95}, + {96, 96, 96, 96, 5: 96, 96, 96, 96, 96, 11: 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 51: 96, 96, 96, 96, 96, 58: 96, 61: 96, 96, 96, 96, 70: 96, 76: 96, 96, 96, 96, 96, 96}, + // 140 + {97, 97, 97, 97, 5: 97, 97, 97, 97, 97, 11: 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 51: 97, 97, 97, 97, 97, 58: 97, 61: 97, 97, 97, 97, 70: 97, 76: 97, 97, 97, 97, 97, 97}, + {2: 348, 14: 308, 307, 90: 306}, + {113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 11: 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 51: 113, 113, 113, 113, 113, 58: 113, 61: 113, 113, 113, 113, 70: 113, 76: 113, 113, 113, 113, 113, 113, 85: 113}, + {4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 265, 356}, + {4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 265, 355}, + // 145 + {4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 265, 354}, + {4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 265, 353}, + {99, 99, 99, 99, 5: 99, 99, 99, 99, 99, 11: 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 51: 99, 99, 99, 99, 99, 58: 99, 61: 99, 99, 99, 99, 70: 339, 76: 337, 334, 338, 333, 335, 336}, + {100, 100, 100, 100, 5: 100, 100, 100, 100, 100, 11: 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 51: 100, 100, 100, 100, 100, 58: 100, 61: 100, 100, 100, 100, 70: 339, 76: 337, 334, 338, 333, 335, 336}, + {101, 101, 101, 101, 5: 101, 101, 101, 101, 101, 11: 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 51: 101, 101, 101, 101, 101, 58: 101, 61: 101, 101, 101, 101, 70: 339, 76: 337, 334, 338, 333, 335, 336}, + // 150 + {102, 102, 102, 102, 5: 102, 102, 102, 102, 102, 11: 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 51: 102, 102, 102, 102, 102, 58: 102, 61: 102, 102, 102, 102, 70: 339, 76: 337, 334, 338, 333, 335, 336}, + {4: 391}, + {51: 382, 381}, + {4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 265, 264, 378}, + {25: 376, 42: 375}, + // 155 + {4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 265, 264, 374}, + {4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 265, 264, 373}, + {4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 265, 264, 372}, + {4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 265, 264, 371}, + {4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 265, 264, 370}, + // 160 + {4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 265, 264, 369}, + {4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 265, 264, 368}, + {139, 139, 139, 139, 5: 352, 351, 349, 139, 139, 11: 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 350, 139, 51: 139, 139, 139, 139, 139, 58: 139, 61: 139, 139, 139, 139}, + {140, 140, 140, 140, 5: 352, 351, 349, 140, 140, 11: 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 350, 140, 51: 140, 140, 140, 140, 140, 58: 140, 61: 140, 140, 140, 140}, + {141, 141, 141, 141, 5: 352, 351, 349, 141, 141, 11: 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 350, 141, 51: 141, 141, 141, 141, 141, 58: 141, 61: 141, 141, 141, 141}, + // 165 + {142, 142, 142, 142, 5: 352, 351, 349, 142, 142, 11: 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 350, 142, 51: 142, 142, 142, 142, 142, 58: 142, 61: 142, 142, 142, 142}, + {143, 143, 143, 143, 5: 352, 351, 349, 143, 143, 11: 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 350, 143, 51: 143, 143, 143, 143, 143, 58: 143, 61: 143, 143, 143, 143}, + {144, 144, 144, 144, 5: 352, 351, 349, 144, 144, 11: 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 350, 144, 51: 144, 144, 144, 144, 144, 58: 144, 61: 144, 144, 144, 144}, + {145, 145, 145, 145, 5: 352, 351, 349, 145, 145, 11: 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 350, 145, 51: 145, 145, 145, 145, 145, 58: 145, 61: 145, 145, 145, 145}, + {148, 148, 148, 148, 8: 148, 148, 11: 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148}, + // 170 + {42: 377}, + {147, 147, 147, 147, 8: 147, 147, 11: 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147}, + {5: 352, 351, 349, 22: 379, 24: 350}, + {4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 265, 264, 380}, + {150, 150, 150, 150, 5: 352, 351, 349, 150, 150, 11: 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 350}, + // 175 + {4: 386}, + {4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 265, 264, 383}, + {5: 352, 351, 349, 22: 384, 24: 350}, + {4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 265, 264, 385}, + {149, 149, 149, 149, 5: 352, 351, 349, 149, 149, 11: 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 350}, + // 180 + {4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 265, 264, 249, 86: 267, 248, 246, 322, 92: 216, 94: 387, 388}, + {2: 390}, + {2: 389}, + {151, 151, 151, 151, 8: 151, 151, 11: 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151}, + {153, 153, 153, 153, 8: 153, 153, 11: 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153}, + // 185 + {4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 265, 264, 249, 86: 267, 248, 246, 322, 92: 216, 94: 392, 393}, + {2: 395}, + {2: 394}, + {152, 152, 152, 152, 8: 152, 152, 11: 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152}, + {154, 154, 154, 154, 8: 154, 154, 11: 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154}, + // 190 + {4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 265, 264, 249, 86: 267, 248, 246, 397}, + {2: 398, 14: 308, 307, 90: 306}, + {185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 11: 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 51: 185, 185, 185, 185, 185, 58: 185, 61: 185, 185, 185, 185, 70: 185, 76: 185, 185, 185, 185, 185, 185, 85: 185}, + {199, 199, 3: 401, 12: 199, 152: 400}, + {202, 202, 12: 202}, + // 195 + {198, 198, 10: 240, 12: 198, 91: 238, 111: 402}, + {200, 200, 3: 200, 12: 200}, + {4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 265, 264, 249, 86: 267, 248, 246, 404}, + {203, 203, 3: 203, 12: 203, 14: 308, 307, 90: 306}, + {10: 234, 93: 406}, + // 200 + {36, 36}, + {4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 413, 262, 257, 261, 263, 259, 82: 265, 264, 249, 86: 267, 248, 246, 409, 128: 410, 164: 411, 176: 412}, + {4: 71, 71, 71, 71, 10: 71, 26: 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 56: 71, 71, 59: 71, 71, 65: 71, 71, 71, 71, 70: 71}, + {3: 137, 14: 308, 307, 137, 20: 463, 90: 306, 163: 462}, + {3: 135, 16: 135}, + // 205 + {3: 460, 16: 69}, + {16: 414}, + {16: 70}, + {4: 417, 10: 416, 134: 418, 415, 174: 419}, + {83, 83, 83, 83, 8: 83, 83, 11: 83, 83, 83, 20: 458, 173: 457}, + // 210 + {87, 87, 87, 87, 8: 87, 87, 11: 87, 87, 87, 20: 87}, + {92: 216, 95: 453}, + {81, 81, 81, 81, 8: 81, 81, 11: 81, 81, 81}, + {67, 67, 67, 420, 8: 67, 67, 11: 67, 244, 67, 106: 422, 142: 421}, + {67, 67, 67, 4: 417, 8: 67, 67, 416, 67, 244, 67, 106: 422, 134: 447, 415, 142: 448}, + // 215 + {65, 65, 65, 8: 65, 65, 11: 65, 13: 423, 129: 425, 138: 424}, + {66, 66, 66, 8: 66, 66, 11: 66, 13: 66}, + {114: 440}, + {63, 63, 63, 8: 63, 63, 11: 426, 133: 428, 141: 427}, + {64, 64, 64, 8: 64, 64, 11: 64}, + // 220 + {114: 435}, + {76, 76, 76, 8: 76, 430, 139: 429}, + {62, 62, 62, 8: 62, 62}, + {74, 74, 74, 8: 433, 140: 432}, + {4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 265, 264, 249, 86: 267, 248, 246, 431}, + // 225 + {75, 75, 75, 8: 75, 14: 308, 307, 90: 306}, + {78, 78, 78}, + {4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 265, 264, 249, 86: 267, 248, 246, 434}, + {73, 73, 73, 14: 308, 307, 90: 306}, + {4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 265, 264, 249, 86: 267, 248, 246, 322, 94: 436}, + // 230 + {111, 111, 111, 8: 111, 111, 17: 438, 439, 170: 437}, + {112, 112, 112, 8: 112, 112}, + {110, 110, 110, 8: 110, 110}, + {109, 109, 109, 8: 109, 109}, + {10: 240, 91: 441, 115: 442}, + // 235 + {190, 190, 190, 190, 8: 190, 190, 11: 190, 155: 443}, + {133, 133, 133, 8: 133, 133, 11: 133}, + {188, 188, 188, 445, 8: 188, 188, 11: 188, 156: 444}, + {191, 191, 191, 8: 191, 191, 11: 191}, + {187, 187, 187, 8: 187, 187, 240, 187, 91: 446}, + // 240 + {189, 189, 189, 189, 8: 189, 189, 11: 189}, + {80, 80, 80, 80, 8: 80, 80, 11: 80, 80, 80}, + {65, 65, 65, 8: 65, 65, 11: 65, 13: 423, 129: 425, 138: 449}, + {63, 63, 63, 8: 63, 63, 11: 426, 133: 428, 141: 450}, + {76, 76, 76, 8: 76, 430, 139: 451}, + // 245 + {74, 74, 74, 8: 433, 140: 452}, + {77, 77, 77}, + {455, 2: 85, 172: 454}, + {2: 456}, + {2: 84}, + // 250 + {86, 86, 86, 86, 8: 86, 86, 11: 86, 86, 86, 20: 86}, + {88, 88, 88, 88, 8: 88, 88, 11: 88, 88, 88}, + {10: 459}, + {82, 82, 82, 82, 8: 82, 82, 11: 82, 82, 82}, + {4: 260, 295, 294, 292, 10: 266, 16: 68, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 265, 264, 249, 86: 267, 248, 246, 409, 128: 461}, + // 255 + {3: 134, 16: 134}, + {3: 138, 16: 138}, + {10: 464}, + {3: 136, 16: 136}, + {10: 234, 93: 466}, + // 260 + {4: 468, 92: 129, 105: 129, 165: 467}, + {92: 216, 95: 472, 105: 471}, + {10: 240, 91: 441, 115: 469}, + {2: 470}, + {92: 128, 105: 128}, + // 265 + {4: 473}, + {130, 130}, + {4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 265, 264, 249, 86: 267, 248, 246, 322, 94: 474}, + {2: 475}, + {127, 127, 3: 127, 166: 476}, + // 270 + {125, 125, 3: 478, 167: 477}, + {131, 131}, + {124, 124, 4: 479}, + {4: 260, 295, 294, 292, 10: 266, 26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 251, 284, 285, 286, 288, 289, 290, 291, 287, 56: 250, 253, 59: 254, 255, 65: 258, 256, 252, 293, 245, 71: 262, 257, 261, 263, 259, 82: 265, 264, 249, 86: 267, 248, 246, 322, 94: 480}, + {2: 481}, + // 275 + {126, 126, 3: 126}, + {10: 169, 102: 489, 160: 488}, + {10: 234, 93: 484, 102: 485}, + {167, 167}, + {101: 486}, + // 280 + {10: 234, 93: 487}, + {166, 166}, + {10: 491}, + {101: 490}, + {10: 168}, + // 285 + {170, 170}, + {10: 234, 93: 493}, + {172, 172, 12: 244, 106: 494}, + {171, 171}, + {103: 517}, + // 290 + {103: 179}, + {10: 234, 93: 498, 102: 499}, + {4: 512}, + {25: 500}, + {101: 501}, + // 295 + {10: 234, 93: 502}, + {4: 503}, + {10: 240, 91: 504, 99: 505}, + {26: 268, 269, 270, 271, 272, 273, 274, 275, 277, 278, 276, 280, 281, 282, 283, 279, 43: 284, 285, 286, 288, 289, 290, 291, 287, 69: 511}, + {2: 176, 176, 121: 506}, + // 300 + {2: 174, 508, 122: 507}, + {2: 510}, + {2: 173, 10: 240, 91: 504, 99: 509}, + {2: 175, 175}, + {177, 177}, + // 305 + {193, 193, 193, 193}, + {10: 240, 91: 504, 99: 513}, + {2: 176, 176, 121: 514}, + {2: 174, 508, 122: 515}, + {2: 516}, + // 310 + {178, 178}, + {10: 182, 102: 519, 157: 518}, + {10: 522}, + {25: 520}, + {101: 521}, + // 315 + {10: 181}, + {169: 523}, + {10: 524}, + {4: 525}, + {10: 526}, + // 320 + {2: 527, 4: 528}, + {184, 184}, + {2: 529}, + {2: 530}, + {183, 183}, + // 325 + {197, 197}, + {10: 234, 93: 533}, + {100: 535, 108: 534}, + {10: 240, 91: 504, 99: 538}, + {154: 536}, + // 330 + {10: 240, 91: 537}, + {204, 204}, + {205, 205}, + {165, 165, 92: 216, 95: 228, 100: 213, 109: 208, 218, 112: 209, 219, 116: 210, 220, 211, 221, 222, 123: 223, 212, 224, 225, 217, 130: 214, 226, 136: 215, 227, 144: 540, 232, 229, 233, 230}, + {42, 42}, + } +) + +var yyDebug = 0 + +type yyLexer interface { + Lex(lval *yySymType) int + Error(s string) +} + +type yyLexerEx interface { + yyLexer + Reduced(rule, state int, lval *yySymType) bool +} + +func yySymName(c int) (s string) { + x, ok := yyXLAT[c] + if ok { + return yySymNames[x] + } + + return __yyfmt__.Sprintf("%d", c) +} + +func yylex1(yylex yyLexer, lval *yySymType) (n int) { + n = yylex.Lex(lval) + if n <= 0 { + n = yyEOFCode + } + if yyDebug >= 3 { + __yyfmt__.Printf("\nlex %s(%#x %d), lval: %+v\n", yySymName(n), n, n, lval) + } + return n +} + +func yyParse(yylex yyLexer) int { + const yyError = 182 + + yyEx, _ := yylex.(yyLexerEx) + var yyn int + var yylval yySymType + var yyVAL yySymType + yyS := make([]yySymType, 200) + + Nerrs := 0 /* number of errors */ + Errflag := 0 /* error recovery flag */ + yyerrok := func() { + if yyDebug >= 2 { + __yyfmt__.Printf("yyerrok()\n") + } + Errflag = 0 + } + _ = yyerrok + yystate := 0 + yychar := -1 + var yyxchar int + yyp := -1 + goto yystack + +ret0: + return 0 + +ret1: + return 1 + +yystack: + /* put a state and value onto the stack */ + yyp++ + if yyp >= len(yyS) { + nyys := make([]yySymType, len(yyS)*2) + copy(nyys, yyS) + yyS = nyys + } + yyS[yyp] = yyVAL + yyS[yyp].yys = yystate + +yynewstate: + if yychar < 0 { + yychar = yylex1(yylex, &yylval) + var ok bool + if yyxchar, ok = yyXLAT[yychar]; !ok { + yyxchar = len(yySymNames) // > tab width + } + } + if yyDebug >= 4 { + var a []int + for _, v := range yyS[:yyp+1] { + a = append(a, v.yys) + } + __yyfmt__.Printf("state stack %v\n", a) + } + row := yyParseTab[yystate] + yyn = 0 + if yyxchar < len(row) { + if yyn = int(row[yyxchar]); yyn != 0 { + yyn += yyTabOfs + } + } + switch { + case yyn > 0: // shift + yychar = -1 + yyVAL = yylval + yystate = yyn + if yyDebug >= 2 { + __yyfmt__.Printf("shift, and goto state %d\n", yystate) + } + if Errflag > 0 { + Errflag-- + } + goto yystack + case yyn < 0: // reduce + case yystate == 1: // accept + if yyDebug >= 2 { + __yyfmt__.Println("accept") + } + goto ret0 + } + + if yyn == 0 { + /* error ... attempt to resume parsing */ + switch Errflag { + case 0: /* brand new error */ + if yyDebug >= 1 { + __yyfmt__.Printf("no action for %s in state %d\n", yySymName(yychar), yystate) + } + k := yyXError{yystate, yyxchar} + msg, ok := yyXErrors[k] + if !ok { + k.xsym = -1 + msg, ok = yyXErrors[k] + } + if !ok { + msg = "syntax error" + } + if msg != "" { + yylex.Error(msg) + } + Nerrs++ + fallthrough + + case 1, 2: /* incompletely recovered error ... try again */ + Errflag = 3 + + /* find a state where "error" is a legal shift action */ + for yyp >= 0 { + row := yyParseTab[yyS[yyp].yys] + if yyError < len(row) { + yyn = int(row[yyError]) + yyTabOfs + if yyn > 0 { // hit + if yyDebug >= 2 { + __yyfmt__.Printf("error recovery found error shift in state %d\n", yyS[yyp].yys) + } + yystate = yyn /* simulate a shift of "error" */ + goto yystack + } + } + + /* the current p has no shift on "error", pop stack */ + if yyDebug >= 2 { + __yyfmt__.Printf("error recovery pops state %d\n", yyS[yyp].yys) + } + yyp-- + } + /* there is no state on the stack with an error shift ... abort */ + if yyDebug >= 2 { + __yyfmt__.Printf("error recovery failed\n") + } + goto ret1 + + case 3: /* no shift yet; clobber input char */ + if yyDebug >= 2 { + __yyfmt__.Printf("error recovery discards %s\n", yySymName(yychar)) + } + if yychar == yyEOFCode { + goto ret1 + } + + yychar = -1 + goto yynewstate /* try again in the same state */ + } + } + + r := -yyn + x0 := yyReductions[r] + x, n := x0.xsym, x0.components + yypt := yyp + _ = yypt // guard against "declared and not used" + + yyp -= n + if yyp+1 >= len(yyS) { + nyys := make([]yySymType, len(yyS)*2) + copy(nyys, yyS) + yyS = nyys + } + yyVAL = yyS[yyp+1] + + /* consult goto table to find next state */ + exState := yystate + yystate = int(yyParseTab[yyS[yyp].yys][x]) + yyTabOfs + /* reduction by production r */ + if yyDebug >= 2 { + __yyfmt__.Printf("reduce using rule %v (%s), and goto state %d\n", r, yySymNames[x], yystate) + } + + switch r { + case 1: + { + yyVAL.item = &alterTableAddStmt{tableName: yyS[yypt-2].item.(string), c: yyS[yypt-0].item.(*col)} + } + case 2: + { + yyVAL.item = &alterTableDropColumnStmt{tableName: yyS[yypt-3].item.(string), colName: yyS[yypt-0].item.(string)} + } + case 3: + { + yyVAL.item = assignment{colName: yyS[yypt-2].item.(string), expr: yyS[yypt-0].item.(expression)} + } + case 4: + { + yyVAL.item = append([]assignment{yyS[yypt-2].item.(assignment)}, yyS[yypt-1].item.([]assignment)...) + } + case 5: + { + yyVAL.item = []assignment{} + } + case 6: + { + yyVAL.item = append(yyS[yypt-2].item.([]assignment), yyS[yypt-0].item.(assignment)) + } + case 9: + { + yyVAL.item = beginTransactionStmt{} + } + case 10: + { + yyVAL.item = yyS[yypt-1].item + } + case 11: + { + yyVAL.item = []expression{} + } + case 13: + { + yyVAL.item = &col{name: yyS[yypt-1].item.(string), typ: yyS[yypt-0].item.(int)} + } + case 15: + { + yyVAL.item = append([]string{yyS[yypt-2].item.(string)}, yyS[yypt-1].item.([]string)...) + } + case 16: + { + yyVAL.item = []string{} + } + case 17: + { + yyVAL.item = append(yyS[yypt-2].item.([]string), yyS[yypt-0].item.(string)) + } + case 20: + { + yyVAL.item = commitStmt{} + } + case 21: + { + yyVAL.item = &conversion{typ: yyS[yypt-3].item.(int), val: yyS[yypt-1].item.(expression)} + } + case 22: + { + indexName, tableName, columnName := yyS[yypt-5].item.(string), yyS[yypt-3].item.(string), yyS[yypt-1].item.(string) + yyVAL.item = &createIndexStmt{unique: yyS[yypt-8].item.(bool), ifNotExists: yyS[yypt-6].item.(bool), indexName: indexName, tableName: tableName, colName: columnName} + if indexName == tableName || indexName == columnName { + yylex.(*lexer).err("index name collision: %s", indexName) + return 1 + } + + if isSystemName[indexName] || isSystemName[tableName] { + yylex.(*lexer).err("name is used for system tables: %s", indexName) + return 1 + } + } + case 23: + { + indexName, tableName, columnName := yyS[yypt-7].item.(string), yyS[yypt-5].item.(string), yyS[yypt-3].item.(string) + yyVAL.item = &createIndexStmt{unique: yyS[yypt-10].item.(bool), ifNotExists: yyS[yypt-8].item.(bool), indexName: indexName, tableName: tableName, colName: "id()"} + if yyS[yypt-3].item.(string) != "id" { + yylex.(*lexer).err("only the built-in function id() can be used in index: %s()", columnName) + return 1 + } + + if indexName == tableName { + yylex.(*lexer).err("index name collision: %s", indexName) + return 1 + } + + if isSystemName[indexName] || isSystemName[tableName] { + yylex.(*lexer).err("name is used for system tables: %s", indexName) + return 1 + } + } + case 24: + { + yyVAL.item = false + } + case 25: + { + yyVAL.item = true + } + case 26: + { + yyVAL.item = false + } + case 27: + { + yyVAL.item = true + } + case 28: + { + nm := yyS[yypt-5].item.(string) + yyVAL.item = &createTableStmt{tableName: nm, cols: append([]*col{yyS[yypt-3].item.(*col)}, yyS[yypt-2].item.([]*col)...)} + if isSystemName[nm] { + yylex.(*lexer).err("name is used for system tables: %s", nm) + return 1 + } + } + case 29: + { + nm := yyS[yypt-5].item.(string) + yyVAL.item = &createTableStmt{ifNotExists: true, tableName: nm, cols: append([]*col{yyS[yypt-3].item.(*col)}, yyS[yypt-2].item.([]*col)...)} + if isSystemName[nm] { + yylex.(*lexer).err("name is used for system tables: %s", nm) + return 1 + } + } + case 30: + { + yyVAL.item = []*col{} + } + case 31: + { + yyVAL.item = append(yyS[yypt-2].item.([]*col), yyS[yypt-0].item.(*col)) + } + case 34: + { + yyVAL.item = &truncateTableStmt{yyS[yypt-0].item.(string)} + } + case 35: + { + yyVAL.item = &deleteStmt{tableName: yyS[yypt-1].item.(string), where: yyS[yypt-0].item.(*whereRset).expr} + } + case 36: + { + yyVAL.item = &dropIndexStmt{ifExists: yyS[yypt-1].item.(bool), indexName: yyS[yypt-0].item.(string)} + } + case 37: + { + yyVAL.item = false + } + case 38: + { + yyVAL.item = true + } + case 39: + { + nm := yyS[yypt-0].item.(string) + yyVAL.item = &dropTableStmt{tableName: nm} + if isSystemName[nm] { + yylex.(*lexer).err("name is used for system tables: %s", nm) + return 1 + } + } + case 40: + { + nm := yyS[yypt-0].item.(string) + yyVAL.item = &dropTableStmt{ifExists: true, tableName: nm} + if isSystemName[nm] { + yylex.(*lexer).err("name is used for system tables: %s", nm) + return 1 + } + } + case 41: + { + yyVAL.item = nil + } + case 43: + { + var err error + if yyVAL.item, err = newBinaryOperation(oror, yyS[yypt-2].item, yyS[yypt-0].item); err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } + case 46: + { + yyVAL.item = append([]expression{yyS[yypt-2].item.(expression)}, yyS[yypt-1].item.([]expression)...) + } + case 47: + { + yyVAL.item = []expression(nil) + } + case 48: + { + yyVAL.item = append(yyS[yypt-2].item.([]expression), yyS[yypt-0].item.(expression)) + } + case 52: + { + yyVAL.item = &pIn{expr: yyS[yypt-4].item.(expression), list: yyS[yypt-1].item.([]expression)} + } + case 53: + { + yyVAL.item = &pIn{expr: yyS[yypt-5].item.(expression), not: true, list: yyS[yypt-1].item.([]expression)} + } + case 54: + { + yyVAL.item = &pIn{expr: yyS[yypt-4].item.(expression), sel: yyS[yypt-1].item.(*selectStmt)} + } + case 55: + { + yyVAL.item = &pIn{expr: yyS[yypt-5].item.(expression), not: true, sel: yyS[yypt-1].item.(*selectStmt)} + } + case 56: + { + var err error + if yyVAL.item, err = newBetween(yyS[yypt-4].item, yyS[yypt-2].item, yyS[yypt-0].item, false); err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } + case 57: + { + var err error + if yyVAL.item, err = newBetween(yyS[yypt-5].item, yyS[yypt-2].item, yyS[yypt-0].item, true); err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } + case 58: + { + yyVAL.item = &isNull{expr: yyS[yypt-2].item.(expression)} + } + case 59: + { + yyVAL.item = &isNull{expr: yyS[yypt-3].item.(expression), not: true} + } + case 61: + { + var err error + if yyVAL.item, err = newBinaryOperation(ge, yyS[yypt-2].item, yyS[yypt-0].item); err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } + case 62: + { + var err error + if yyVAL.item, err = newBinaryOperation('>', yyS[yypt-2].item, yyS[yypt-0].item); err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } + case 63: + { + var err error + if yyVAL.item, err = newBinaryOperation(le, yyS[yypt-2].item, yyS[yypt-0].item); err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } + case 64: + { + var err error + if yyVAL.item, err = newBinaryOperation('<', yyS[yypt-2].item, yyS[yypt-0].item); err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } + case 65: + { + var err error + if yyVAL.item, err = newBinaryOperation(neq, yyS[yypt-2].item, yyS[yypt-0].item); err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } + case 66: + { + var err error + if yyVAL.item, err = newBinaryOperation(eq, yyS[yypt-2].item, yyS[yypt-0].item); err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } + case 67: + { + yyVAL.item = &pLike{expr: yyS[yypt-2].item.(expression), pattern: yyS[yypt-0].item.(expression)} + } + case 68: + { + expr, name := yyS[yypt-1].item.(expression), yyS[yypt-0].item.(string) + if name == "" { + s, ok := expr.(*ident) + if ok { + name = s.s + } + } + yyVAL.item = &fld{expr: expr, name: name} + } + case 69: + { + yyVAL.item = "" + } + case 70: + { + yyVAL.item = yyS[yypt-0].item + } + case 71: + { + yyVAL.item = []*fld{yyS[yypt-0].item.(*fld)} + } + case 72: + { + l, f := yyS[yypt-2].item.([]*fld), yyS[yypt-0].item.(*fld) + if f.name != "" { + if f := findFld(l, f.name); f != nil { + yylex.(*lexer).err("duplicate field name %q", f.name) + return 1 + } + } + + yyVAL.item = append(yyS[yypt-2].item.([]*fld), yyS[yypt-0].item.(*fld)) + } + case 73: + { + yyVAL.item = &groupByRset{colNames: yyS[yypt-0].item.([]string)} + } + case 74: + { + yyVAL.item = yyS[yypt-1].item + } + case 75: + { + yyVAL.item = &insertIntoStmt{tableName: yyS[yypt-7].item.(string), colNames: yyS[yypt-6].item.([]string), lists: append([][]expression{yyS[yypt-3].item.([]expression)}, yyS[yypt-1].item.([][]expression)...)} + } + case 76: + { + yyVAL.item = &insertIntoStmt{tableName: yyS[yypt-2].item.(string), colNames: yyS[yypt-1].item.([]string), sel: yyS[yypt-0].item.(*selectStmt)} + } + case 77: + { + yyVAL.item = []string{} + } + case 78: + { + yyVAL.item = yyS[yypt-1].item + } + case 79: + { + yyVAL.item = [][]expression{} + } + case 80: + { + yyVAL.item = append(yyS[yypt-4].item.([][]expression), yyS[yypt-1].item.([]expression)) + } + case 90: + { + yyVAL.item = value{yyS[yypt-0].item} + } + case 91: + { + n := yyS[yypt-0].item.(int) + yyVAL.item = parameter{n} + l := yylex.(*lexer) + l.params = mathutil.Max(l.params, n) + if n == 0 { + l.err("parameter number must be non zero") + return 1 + } + } + case 92: + { + yyVAL.item = &ident{yyS[yypt-0].item.(string)} + } + case 93: + { + yyVAL.item = &pexpr{expr: yyS[yypt-1].item.(expression)} + } + case 94: + { + yyVAL.item = &orderByRset{by: yyS[yypt-1].item.([]expression), asc: yyS[yypt-0].item.(bool)} + } + case 95: + { + yyVAL.item = true // ASC by default + } + case 96: + { + yyVAL.item = true + } + case 97: + { + yyVAL.item = false + } + case 100: + { + var err error + if yyVAL.item, err = newIndex(yyS[yypt-1].item.(expression), yyS[yypt-0].item.(expression)); err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } + case 101: + { + var err error + s := yyS[yypt-0].item.([2]*expression) + if yyVAL.item, err = newSlice(yyS[yypt-1].item.(expression), s[0], s[1]); err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } + case 102: + { + x := yylex.(*lexer) + f, ok := yyS[yypt-1].item.(*ident) + if !ok { + x.err("expected identifier or qualified identifier") + return 1 + } + + var err error + var agg bool + if yyVAL.item, agg, err = newCall(f.s, yyS[yypt-0].item.([]expression)); err != nil { + x.err("%v", err) + return 1 + } + if n := len(x.agg); n > 0 { + x.agg[n-1] = x.agg[n-1] || agg + } + } + case 104: + { + var err error + if yyVAL.item, err = newBinaryOperation('^', yyS[yypt-2].item, yyS[yypt-0].item); err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } + case 105: + { + var err error + if yyVAL.item, err = newBinaryOperation('|', yyS[yypt-2].item, yyS[yypt-0].item); err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } + case 106: + { + var err error + if yyVAL.item, err = newBinaryOperation('-', yyS[yypt-2].item, yyS[yypt-0].item); err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } + case 107: + { + var err error + yyVAL.item, err = newBinaryOperation('+', yyS[yypt-2].item, yyS[yypt-0].item) + if err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } + case 109: + { + var err error + yyVAL.item, err = newBinaryOperation(andnot, yyS[yypt-2].item, yyS[yypt-0].item) + if err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } + case 110: + { + var err error + yyVAL.item, err = newBinaryOperation('&', yyS[yypt-2].item, yyS[yypt-0].item) + if err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } + case 111: + { + var err error + yyVAL.item, err = newBinaryOperation(lsh, yyS[yypt-2].item, yyS[yypt-0].item) + if err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } + case 112: + { + var err error + yyVAL.item, err = newBinaryOperation(rsh, yyS[yypt-2].item, yyS[yypt-0].item) + if err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } + case 113: + { + var err error + yyVAL.item, err = newBinaryOperation('%', yyS[yypt-2].item, yyS[yypt-0].item) + if err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } + case 114: + { + var err error + yyVAL.item, err = newBinaryOperation('/', yyS[yypt-2].item, yyS[yypt-0].item) + if err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } + case 115: + { + var err error + yyVAL.item, err = newBinaryOperation('*', yyS[yypt-2].item, yyS[yypt-0].item) + if err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } + case 117: + { + yyVAL.item = fmt.Sprintf("%s.%s", yyS[yypt-2].item.(string), yyS[yypt-0].item.(string)) + } + case 118: + { + yyVAL.item = []interface{}{yyS[yypt-1].item, yyS[yypt-0].item} + } + case 120: + { + yyVAL.item = yyS[yypt-2].item + } + case 123: + { + yyVAL.item = "" + } + case 124: + { + yyVAL.item = yyS[yypt-0].item + } + case 125: + { + yyVAL.list = []interface{}{yyS[yypt-0].item} + } + case 126: + { + yyVAL.list = append(yyS[yypt-2].list, yyS[yypt-0].item) + } + case 127: + { + yyVAL.item = rollbackStmt{} + } + case 128: + { + x := yylex.(*lexer) + n := len(x.agg) + yyVAL.item = &selectStmt{ + distinct: yyS[yypt-8].item.(bool), + flds: yyS[yypt-7].item.([]*fld), + from: &crossJoinRset{sources: yyS[yypt-5].list}, + hasAggregates: x.agg[n-1], + where: yyS[yypt-4].item.(*whereRset), + group: yyS[yypt-3].item.(*groupByRset), + order: yyS[yypt-2].item.(*orderByRset), + limit: yyS[yypt-1].item.(*limitRset), + offset: yyS[yypt-0].item.(*offsetRset), + } + x.agg = x.agg[:n-1] + } + case 129: + { + x := yylex.(*lexer) + n := len(x.agg) + yyVAL.item = &selectStmt{ + distinct: yyS[yypt-9].item.(bool), + flds: yyS[yypt-8].item.([]*fld), + from: &crossJoinRset{sources: yyS[yypt-6].list}, + hasAggregates: x.agg[n-1], + where: yyS[yypt-4].item.(*whereRset), + group: yyS[yypt-3].item.(*groupByRset), + order: yyS[yypt-2].item.(*orderByRset), + limit: yyS[yypt-1].item.(*limitRset), + offset: yyS[yypt-0].item.(*offsetRset), + } + x.agg = x.agg[:n-1] + } + case 130: + { + yyVAL.item = (*limitRset)(nil) + } + case 131: + { + yyVAL.item = &limitRset{expr: yyS[yypt-0].item.(expression)} + } + case 132: + { + yyVAL.item = (*offsetRset)(nil) + } + case 133: + { + yyVAL.item = &offsetRset{expr: yyS[yypt-0].item.(expression)} + } + case 134: + { + yyVAL.item = false + } + case 135: + { + yyVAL.item = true + } + case 136: + { + yyVAL.item = []*fld{} + } + case 137: + { + yyVAL.item = yyS[yypt-0].item + } + case 138: + { + yyVAL.item = yyS[yypt-1].item + } + case 139: + { + yyVAL.item = (*whereRset)(nil) + } + case 141: + { + yyVAL.item = (*groupByRset)(nil) + } + case 143: + { + yyVAL.item = (*orderByRset)(nil) + } + case 145: + { + yyVAL.item = [2]*expression{nil, nil} + } + case 146: + { + hi := yyS[yypt-1].item.(expression) + yyVAL.item = [2]*expression{nil, &hi} + } + case 147: + { + lo := yyS[yypt-2].item.(expression) + yyVAL.item = [2]*expression{&lo, nil} + } + case 148: + { + lo := yyS[yypt-3].item.(expression) + hi := yyS[yypt-1].item.(expression) + yyVAL.item = [2]*expression{&lo, &hi} + } + case 163: + { + if yyS[yypt-0].item != nil { + yylex.(*lexer).list = []stmt{yyS[yypt-0].item.(stmt)} + } + } + case 164: + { + if yyS[yypt-0].item != nil { + yylex.(*lexer).list = append(yylex.(*lexer).list, yyS[yypt-0].item.(stmt)) + } + } + case 167: + { + var err error + if yyVAL.item, err = newBinaryOperation(andand, yyS[yypt-2].item, yyS[yypt-0].item); err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } + case 170: + { + yyVAL.item = &truncateTableStmt{tableName: yyS[yypt-0].item.(string)} + } + case 195: + { + yyVAL.item = &updateStmt{tableName: yyS[yypt-3].item.(string), list: yyS[yypt-1].item.([]assignment), where: yyS[yypt-0].item.(*whereRset).expr} + } + case 196: + { + yyVAL.item = nowhere + } + case 199: + { + var err error + yyVAL.item, err = newUnaryOperation('^', yyS[yypt-0].item) + if err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } + case 200: + { + var err error + yyVAL.item, err = newUnaryOperation('!', yyS[yypt-0].item) + if err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } + case 201: + { + var err error + yyVAL.item, err = newUnaryOperation('-', yyS[yypt-0].item) + if err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } + case 202: + { + var err error + yyVAL.item, err = newUnaryOperation('+', yyS[yypt-0].item) + if err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } + case 203: + { + yyVAL.item = &whereRset{expr: yyS[yypt-0].item.(expression)} + } + + } + + if yyEx != nil && yyEx.Reduced(r, exState, &yyVAL) { + return -1 + } + goto yystack /* stack new state and value */ +} diff --git a/Godeps/_workspace/src/github.com/cznic/ql/parser.y b/Godeps/_workspace/src/github.com/cznic/ql/parser.y new file mode 100644 index 0000000..eeb489a --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/ql/parser.y @@ -0,0 +1,1062 @@ +%{ + +// Copyright (c) 2014 The ql Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Inital yacc source generated by ebnf2y[1] +// at 2013-10-04 23:10:47.861401015 +0200 CEST +// +// $ ebnf2y -o ql.y -oe ql.ebnf -start StatementList -pkg ql -p _ +// +// CAUTION: If this file is a Go source file (*.go), it was generated +// automatically by '$ goyacc' from a *.y file - DO NOT EDIT in that case! +// +// [1]: http://github.com/cznic/ebnf2y + +package ql + +import ( + "fmt" + + "github.com/cznic/mathutil" +) + +%} + +%union { + line int + col int + item interface{} + list []interface{} +} + +%token add alter and andand andnot as asc + begin between bigIntType bigRatType blobType boolType by byteType + column commit complex128Type complex64Type create + deleteKwd desc distinct drop durationType + eq exists + falseKwd floatType float32Type float64Type floatLit from + ge group + identifier ifKwd imaginaryLit in index insert intType int16Type + int32Type int64Type int8Type into intLit is + le like limit lsh + neq not null + offset on or order oror + qlParam + rollback rsh runeType + selectKwd set stringType stringLit + tableKwd timeType transaction trueKwd truncate + uintType uint16Type uint32Type uint64Type uint8Type unique update + values + where + +%token + floatLit imaginaryLit intLit stringLit + +%token + bigIntType bigRatType blobType boolType byteType + complex64Type complex128Type + durationType + falseKwd floatType float32Type float64Type + identifier intType int16Type int32Type int64Type int8Type + null + qlParam + runeType + stringType + timeType trueKwd + uintType uint16Type uint32Type uint64Type uint8Type + +%type + AlterTableStmt Assignment AssignmentList AssignmentList1 + BeginTransactionStmt + Call Call1 ColumnDef ColumnName ColumnNameList ColumnNameList1 + CommitStmt Conversion CreateIndexStmt CreateIndexIfNotExists + CreateIndexStmtUnique CreateTableStmt CreateTableStmt1 + DeleteFromStmt DropIndexStmt DropIndexIfExists DropTableStmt + EmptyStmt Expression ExpressionList ExpressionList1 + Factor Factor1 Field Field1 FieldList + GroupByClause + Index InsertIntoStmt InsertIntoStmt1 InsertIntoStmt2 + Literal + Operand OrderBy OrderBy1 + QualifiedIdent + PrimaryExpression PrimaryFactor PrimaryTerm + RecordSet RecordSet1 RecordSet2 RollbackStmt + SelectStmt SelectStmtDistinct SelectStmtFieldList SelectStmtLimit + SelectStmtWhere SelectStmtGroup SelectStmtOffset SelectStmtOrder Slice + Statement StatementList + TableName Term TruncateTableStmt Type + UnaryExpr UpdateStmt UpdateStmt1 + WhereClause + +%type RecordSetList + +%start StatementList + +%% + +AlterTableStmt: + alter tableKwd TableName add ColumnDef + { + $$ = &alterTableAddStmt{tableName: $3.(string), c: $5.(*col)} + } +| alter tableKwd TableName drop column ColumnName + { + $$ = &alterTableDropColumnStmt{tableName: $3.(string), colName: $6.(string)} + } + +Assignment: + ColumnName '=' Expression + { + $$ = assignment{colName: $1.(string), expr: $3.(expression)} + } + +AssignmentList: + Assignment AssignmentList1 AssignmentList2 + { + $$ = append([]assignment{$1.(assignment)}, $2.([]assignment)...) + } + +AssignmentList1: + /* EMPTY */ + { + $$ = []assignment{} + } +| AssignmentList1 ',' Assignment + { + $$ = append($1.([]assignment), $3.(assignment)) + } + +AssignmentList2: + /* EMPTY */ +| ',' + +BeginTransactionStmt: + begin transaction + { + $$ = beginTransactionStmt{} + } + +Call: + '(' Call1 ')' + { + $$ = $2 + } + +Call1: + /* EMPTY */ + { + $$ = []expression{} + } +| ExpressionList + +ColumnDef: + ColumnName Type + { + $$ = &col{name: $1.(string), typ: $2.(int)} + } + +ColumnName: + identifier + +ColumnNameList: + ColumnName ColumnNameList1 ColumnNameList2 + { + $$ = append([]string{$1.(string)}, $2.([]string)...) + } + +ColumnNameList1: + /* EMPTY */ + { + $$ = []string{} + } +| ColumnNameList1 ',' ColumnName + { + $$ = append($1.([]string), $3.(string)) + } + +ColumnNameList2: + /* EMPTY */ +| ',' + +CommitStmt: + commit + { + $$ = commitStmt{} + } + +Conversion: + Type '(' Expression ')' + { + $$ = &conversion{typ: $1.(int), val: $3.(expression)} + } + +CreateIndexStmt: + create CreateIndexStmtUnique index CreateIndexIfNotExists identifier on identifier '(' identifier ')' + { + indexName, tableName, columnName := $5.(string), $7.(string), $9.(string) + $$ = &createIndexStmt{unique: $2.(bool), ifNotExists: $4.(bool), indexName: indexName, tableName: tableName, colName: columnName} + if indexName == tableName || indexName == columnName { + yylex.(*lexer).err("index name collision: %s", indexName) + return 1 + } + + if isSystemName[indexName] || isSystemName[tableName] { + yylex.(*lexer).err("name is used for system tables: %s", indexName) + return 1 + } + } +| create CreateIndexStmtUnique index CreateIndexIfNotExists identifier on identifier '(' identifier '(' ')' ')' + { + indexName, tableName, columnName := $5.(string), $7.(string), $9.(string) + $$ = &createIndexStmt{unique: $2.(bool), ifNotExists: $4.(bool), indexName: indexName, tableName: tableName, colName: "id()"} + if $9.(string) != "id" { + yylex.(*lexer).err("only the built-in function id() can be used in index: %s()", columnName) + return 1 + } + + if indexName == tableName { + yylex.(*lexer).err("index name collision: %s", indexName) + return 1 + } + + if isSystemName[indexName] || isSystemName[tableName] { + yylex.(*lexer).err("name is used for system tables: %s", indexName) + return 1 + } + } + +CreateIndexIfNotExists: + { + $$ = false + } +| ifKwd not exists + { + $$ = true + } + +CreateIndexStmtUnique: + { + $$ = false + } +| unique + { + $$ = true + } + +CreateTableStmt: + create tableKwd TableName '(' ColumnDef CreateTableStmt1 CreateTableStmt2 ')' + { + nm := $3.(string) + $$ = &createTableStmt{tableName: nm, cols: append([]*col{$5.(*col)}, $6.([]*col)...)} + if isSystemName[nm] { + yylex.(*lexer).err("name is used for system tables: %s", nm) + return 1 + } + } +| create tableKwd ifKwd not exists TableName '(' ColumnDef CreateTableStmt1 CreateTableStmt2 ')' + { + nm := $6.(string) + $$ = &createTableStmt{ifNotExists: true, tableName: nm, cols: append([]*col{$8.(*col)}, $9.([]*col)...)} + if isSystemName[nm] { + yylex.(*lexer).err("name is used for system tables: %s", nm) + return 1 + } + } + +CreateTableStmt1: + /* EMPTY */ + { + $$ = []*col{} + } +| CreateTableStmt1 ',' ColumnDef + { + $$ = append($1.([]*col), $3.(*col)) + } + +CreateTableStmt2: + /* EMPTY */ +| ',' + +DeleteFromStmt: + deleteKwd from TableName + { + $$ = &truncateTableStmt{$3.(string)} + } +| deleteKwd from TableName WhereClause + { + $$ = &deleteStmt{tableName: $3.(string), where: $4.(*whereRset).expr} + } + +DropIndexStmt: + drop index DropIndexIfExists identifier + { + $$ = &dropIndexStmt{ifExists: $3.(bool), indexName: $4.(string)} + } + +DropIndexIfExists: + { + $$ = false + } +| ifKwd exists + { + $$ = true + } + +DropTableStmt: + drop tableKwd TableName + { + nm := $3.(string) + $$ = &dropTableStmt{tableName: nm} + if isSystemName[nm] { + yylex.(*lexer).err("name is used for system tables: %s", nm) + return 1 + } + } +| drop tableKwd ifKwd exists TableName + { + nm := $5.(string) + $$ = &dropTableStmt{ifExists: true, tableName: nm} + if isSystemName[nm] { + yylex.(*lexer).err("name is used for system tables: %s", nm) + return 1 + } + } + +EmptyStmt: + /* EMPTY */ + { + $$ = nil + } + +Expression: + Term +| Expression logOr Term + { + var err error + if $$, err = newBinaryOperation(oror, $1, $3); err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } + +logOr: + oror +| or + +ExpressionList: + Expression ExpressionList1 ExpressionList2 + { + $$ = append([]expression{$1.(expression)}, $2.([]expression)...) + } + +ExpressionList1: + /* EMPTY */ + { + $$ = []expression(nil) + } +| ExpressionList1 ',' Expression + { + $$ = append($1.([]expression), $3.(expression)) + } + +ExpressionList2: + /* EMPTY */ +| ',' + +Factor: + Factor1 +| Factor1 in '(' ExpressionList ')' + { + $$ = &pIn{expr: $1.(expression), list: $4.([]expression)} + } +| Factor1 not in '(' ExpressionList ')' + { + $$ = &pIn{expr: $1.(expression), not: true, list: $5.([]expression)} + } +| Factor1 in '(' SelectStmt ')' + { + $$ = &pIn{expr: $1.(expression), sel: $4.(*selectStmt)} + } +| Factor1 not in '(' SelectStmt ')' + { + $$ = &pIn{expr: $1.(expression), not: true, sel: $5.(*selectStmt)} + } +| Factor1 between PrimaryFactor and PrimaryFactor + { + var err error + if $$, err = newBetween($1, $3, $5, false); err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } +| Factor1 not between PrimaryFactor and PrimaryFactor + { + var err error + if $$, err = newBetween($1, $4, $6, true); err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } +| Factor1 is null + { + $$ = &isNull{expr: $1.(expression)} + } +| Factor1 is not null + { + $$ = &isNull{expr: $1.(expression), not: true} + } + +Factor1: + PrimaryFactor +| Factor1 ge PrimaryFactor + { + var err error + if $$, err = newBinaryOperation(ge, $1, $3); err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } +| Factor1 '>' PrimaryFactor + { + var err error + if $$, err = newBinaryOperation('>', $1, $3); err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } +| Factor1 le PrimaryFactor + { + var err error + if $$, err = newBinaryOperation(le, $1, $3); err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } +| Factor1 '<' PrimaryFactor + { + var err error + if $$, err = newBinaryOperation('<', $1, $3); err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } +| Factor1 neq PrimaryFactor + { + var err error + if $$, err = newBinaryOperation(neq, $1, $3); err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } +| Factor1 eq PrimaryFactor + { + var err error + if $$, err = newBinaryOperation(eq, $1, $3); err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } +| Factor1 like PrimaryFactor + { + $$ = &pLike{expr: $1.(expression), pattern: $3.(expression)} + } + +Field: + Expression Field1 + { + expr, name := $1.(expression), $2.(string) + if name == "" { + s, ok := expr.(*ident) + if ok { + name = s.s + } + } + $$ = &fld{expr: expr, name: name} + } + +Field1: + /* EMPTY */ + { + $$ = "" + } +| as identifier + { + $$ = $2 + } + +FieldList: + Field + { + $$ = []*fld{$1.(*fld)} + } +| FieldList ',' Field + { + l, f := $1.([]*fld), $3.(*fld) + if f.name != "" { + if f := findFld(l, f.name); f != nil { + yylex.(*lexer).err("duplicate field name %q", f.name) + return 1 + } + } + + $$ = append($1.([]*fld), $3.(*fld)) + } + +GroupByClause: + group by ColumnNameList + { + $$ = &groupByRset{colNames: $3.([]string)} + } + +Index: + '[' Expression ']' + { + $$ = $2 + } + +InsertIntoStmt: + insert into TableName InsertIntoStmt1 values '(' ExpressionList ')' InsertIntoStmt2 InsertIntoStmt3 + { + $$ = &insertIntoStmt{tableName: $3.(string), colNames: $4.([]string), lists: append([][]expression{$7.([]expression)}, $9.([][]expression)...)} + } +| insert into TableName InsertIntoStmt1 SelectStmt + { + $$ = &insertIntoStmt{tableName: $3.(string), colNames: $4.([]string), sel: $5.(*selectStmt)} + } + +InsertIntoStmt1: + /* EMPTY */ + { + $$ = []string{} + } +| '(' ColumnNameList ')' + { + $$ = $2 + } + +InsertIntoStmt2: + /* EMPTY */ + { + $$ = [][]expression{} + } +| InsertIntoStmt2 ',' '(' ExpressionList ')' + { + $$ = append($1.([][]expression), $4.([]expression)) + } + +InsertIntoStmt3: +| ',' + + +Literal: + falseKwd +| null +| trueKwd +| floatLit +| imaginaryLit +| intLit +| stringLit + +Operand: + Literal + { + $$ = value{$1} + } +| qlParam + { + n := $1.(int) + $$ = parameter{n} + l := yylex.(*lexer) + l.params = mathutil.Max(l.params, n) + if n == 0 { + l.err("parameter number must be non zero") + return 1 + } + } +| QualifiedIdent + { + $$ = &ident{$1.(string)} + } +| '(' Expression ')' + { + $$ = &pexpr{expr: $2.(expression)} + } + +OrderBy: + order by ExpressionList OrderBy1 + { + $$ = &orderByRset{by: $3.([]expression), asc: $4.(bool)} + } + +OrderBy1: + /* EMPTY */ + { + $$ = true // ASC by default + } +| asc + { + $$ = true + } +| desc + { + $$ = false + } + +PrimaryExpression: + Operand +| Conversion +| PrimaryExpression Index + { + var err error + if $$, err = newIndex($1.(expression), $2.(expression)); err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } +| PrimaryExpression Slice + { + var err error + s := $2.([2]*expression) + if $$, err = newSlice($1.(expression), s[0], s[1]); err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } +| PrimaryExpression Call + { + x := yylex.(*lexer) + f, ok := $1.(*ident) + if !ok { + x.err("expected identifier or qualified identifier") + return 1 + } + + var err error + var agg bool + if $$, agg, err = newCall(f.s, $2.([]expression)); err != nil { + x.err("%v", err) + return 1 + } + if n := len(x.agg); n > 0 { + x.agg[n-1] = x.agg[n-1] || agg + } + } + +PrimaryFactor: + PrimaryTerm +| PrimaryFactor '^' PrimaryTerm + { + var err error + if $$, err = newBinaryOperation('^', $1, $3); err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } +| PrimaryFactor '|' PrimaryTerm + { + var err error + if $$, err = newBinaryOperation('|', $1, $3); err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } +| PrimaryFactor '-' PrimaryTerm + { + var err error + if $$, err = newBinaryOperation('-', $1, $3); err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } +| PrimaryFactor '+' PrimaryTerm + { + var err error + $$, err = newBinaryOperation('+', $1, $3) + if err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } + +PrimaryTerm: + UnaryExpr +| PrimaryTerm andnot UnaryExpr + { + var err error + $$, err = newBinaryOperation(andnot, $1, $3) + if err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } +| PrimaryTerm '&' UnaryExpr + { + var err error + $$, err = newBinaryOperation('&', $1, $3) + if err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } +| PrimaryTerm lsh UnaryExpr + { + var err error + $$, err = newBinaryOperation(lsh, $1, $3) + if err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } +| PrimaryTerm rsh UnaryExpr + { + var err error + $$, err = newBinaryOperation(rsh, $1, $3) + if err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } +| PrimaryTerm '%' UnaryExpr + { + var err error + $$, err = newBinaryOperation('%', $1, $3) + if err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } +| PrimaryTerm '/' UnaryExpr + { + var err error + $$, err = newBinaryOperation('/', $1, $3) + if err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } +| PrimaryTerm '*' UnaryExpr + { + var err error + $$, err = newBinaryOperation('*', $1, $3) + if err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } + +QualifiedIdent: + identifier +| identifier '.' identifier + { + $$ = fmt.Sprintf("%s.%s", $1.(string), $3.(string)) + } + +RecordSet: + RecordSet1 RecordSet2 + { + $$ = []interface{}{$1, $2} + } + +RecordSet1: + identifier +| '(' SelectStmt RecordSet11 ')' + { + $$ = $2 + } + +RecordSet11: + /* EMPTY */ +| ';' + +RecordSet2: + /* EMPTY */ + { + $$ = "" + } +| as identifier + { + $$ = $2 + } + +RecordSetList: + RecordSet + { + $$ = []interface{}{$1} + } +| RecordSetList ',' RecordSet + { + $$ = append($1, $3) + } + +RollbackStmt: + rollback + { + $$ = rollbackStmt{} + } + +SelectStmt: + selectKwd SelectStmtDistinct SelectStmtFieldList from RecordSetList + SelectStmtWhere SelectStmtGroup SelectStmtOrder SelectStmtLimit SelectStmtOffset + { + x := yylex.(*lexer) + n := len(x.agg) + $$ = &selectStmt{ + distinct: $2.(bool), + flds: $3.([]*fld), + from: &crossJoinRset{sources: $5}, + hasAggregates: x.agg[n-1], + where: $6.(*whereRset), + group: $7.(*groupByRset), + order: $8.(*orderByRset), + limit: $9.(*limitRset), + offset: $10.(*offsetRset), + } + x.agg = x.agg[:n-1] + } +| selectKwd SelectStmtDistinct SelectStmtFieldList from RecordSetList ',' + SelectStmtWhere SelectStmtGroup SelectStmtOrder SelectStmtLimit SelectStmtOffset + { + x := yylex.(*lexer) + n := len(x.agg) + $$ = &selectStmt{ + distinct: $2.(bool), + flds: $3.([]*fld), + from: &crossJoinRset{sources: $5}, + hasAggregates: x.agg[n-1], + where: $7.(*whereRset), + group: $8.(*groupByRset), + order: $9.(*orderByRset), + limit: $10.(*limitRset), + offset: $11.(*offsetRset), + } + x.agg = x.agg[:n-1] + } + +SelectStmtLimit: + { + $$ = (*limitRset)(nil) + } +| limit Expression + { + $$ = &limitRset{expr: $2.(expression)} + } + +SelectStmtOffset: + { + $$ = (*offsetRset)(nil) + } +| offset Expression + { + $$ = &offsetRset{expr: $2.(expression)} + } + +SelectStmtDistinct: + /* EMPTY */ + { + $$ = false + } +| distinct + { + $$ = true + } + +SelectStmtFieldList: + '*' + { + $$ = []*fld{} + } +| FieldList + { + $$ = $1 + } +| FieldList ',' + { + $$ = $1 + } + +SelectStmtWhere: + /* EMPTY */ + { + $$ = (*whereRset)(nil) + } +| WhereClause + +SelectStmtGroup: + /* EMPTY */ + { + $$ = (*groupByRset)(nil) + } +| GroupByClause + +SelectStmtOrder: + /* EMPTY */ + { + $$ = (*orderByRset)(nil) + } +| OrderBy + +Slice: + '[' ':' ']' + { + $$ = [2]*expression{nil, nil} + } +| '[' ':' Expression ']' + { + hi := $3.(expression) + $$ = [2]*expression{nil, &hi} + } +| '[' Expression ':' ']' + { + lo := $2.(expression) + $$ = [2]*expression{&lo, nil} + } +| '[' Expression ':' Expression ']' + { + lo := $2.(expression) + hi := $4.(expression) + $$ = [2]*expression{&lo, &hi} + } + +Statement: + EmptyStmt +| AlterTableStmt +| BeginTransactionStmt +| CommitStmt +| CreateIndexStmt +| CreateTableStmt +| DeleteFromStmt +| DropIndexStmt +| DropTableStmt +| InsertIntoStmt +| RollbackStmt +| SelectStmt +| TruncateTableStmt +| UpdateStmt + +StatementList: + Statement + { + if $1 != nil { + yylex.(*lexer).list = []stmt{$1.(stmt)} + } + } +| StatementList ';' Statement + { + if $3 != nil { + yylex.(*lexer).list = append(yylex.(*lexer).list, $3.(stmt)) + } + } + +TableName: + identifier + +Term: + Factor +| Term logAnd Factor + { + var err error + if $$, err = newBinaryOperation(andand, $1, $3); err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } + +logAnd: + andand +| and + +TruncateTableStmt: + truncate tableKwd TableName + { + $$ = &truncateTableStmt{tableName: $3.(string)} + } + +Type: + bigIntType +| bigRatType +| blobType +| boolType +| byteType +| complex128Type +| complex64Type +| durationType +| floatType +| float32Type +| float64Type +| intType +| int16Type +| int32Type +| int64Type +| int8Type +| runeType +| stringType +| timeType +| uintType +| uint16Type +| uint32Type +| uint64Type +| uint8Type + +UpdateStmt: + update TableName oSet AssignmentList UpdateStmt1 + { + $$ = &updateStmt{tableName: $2.(string), list: $4.([]assignment), where: $5.(*whereRset).expr} + } + +UpdateStmt1: + /* EMPTY */ + { + $$ = nowhere + } +| WhereClause + +UnaryExpr: + PrimaryExpression +| '^' PrimaryExpression + { + var err error + $$, err = newUnaryOperation('^', $2) + if err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } +| '!' PrimaryExpression + { + var err error + $$, err = newUnaryOperation('!', $2) + if err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } +| '-' PrimaryExpression + { + var err error + $$, err = newUnaryOperation('-', $2) + if err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } +| '+' PrimaryExpression + { + var err error + $$, err = newUnaryOperation('+', $2) + if err != nil { + yylex.(*lexer).err("%v", err) + return 1 + } + } + +WhereClause: + where Expression + { + $$ = &whereRset{expr: $2.(expression)} + } + + +oSet: +| set diff --git a/Godeps/_workspace/src/github.com/cznic/ql/parser_test.go b/Godeps/_workspace/src/github.com/cznic/ql/parser_test.go new file mode 100644 index 0000000..d603a28 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/ql/parser_test.go @@ -0,0 +1,193 @@ +// Copyright 2014 The ql 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 ql + +import ( + "testing" +) + +func TestParser0(t *testing.T) { + table := []struct { + src string + ok bool + }{ + {"", true}, + {";", true}, + {"CREATE", false}, + {"CREATE TABLE", false}, + {"CREATE TABLE foo (", false}, + // 5 + {"CREATE TABLE foo ()", false}, + {"CREATE TABLE foo ();", false}, + {"CREATE TABLE foo (a byte)", true}, + {"CREATE TABLE foo (a uint8);", true}, + {"CREATE TABLE foo (a uint16, b uint32)", true}, + // 10 + {"CREATE TABLE foo (a uint64, b bool);", true}, + {"CREATE TABLE foo (a int8, b int16) CREATE TABLE bar (x int32, y int64)", false}, + {"CREATE TABLE foo (a int, b float32); CREATE TABLE bar (x float64, y float)", true}, + {"INSERT INTO foo VALUES (1234)", true}, + {"INSERT INTO foo VALUES (1234, 5678)", true}, + // 15 + {"INSERT INTO foo VALUES (1 || 2)", false}, + {"INSERT INTO foo VALUES (1 | 2)", true}, + {"INSERT INTO foo VALUES (false || true)", true}, + {"INSERT INTO foo VALUES (id())", true}, + {"INSERT INTO foo VALUES (bar(5678))", false}, + // 20 + {"INSERT INTO foo VALUES ()", false}, + {"CREATE TABLE foo (a.b, b);", false}, + {"CREATE TABLE foo (a, b.c);", false}, + {"SELECT * FROM t", true}, + {"SELECT * FROM t AS u", true}, + // 25 + {"SELECT * FROM t, v", true}, + {"SELECT * FROM t AS u, v", true}, + {"SELECT * FROM t, v AS w", true}, + {"SELECT * FROM t AS u, v AS w", true}, + {"SELECT * FROM foo, bar, foo", true}, + // 30 + {"CREATE TABLE foo (a bytes)", false}, + {"SELECT DISTINCTS * FROM t", false}, + {"SELECT DISTINCT * FROM t", true}, + {"INSERT INTO foo (a) VALUES (42)", true}, + {"INSERT INTO foo (a,) VALUES (42,)", true}, + // 35 + {"INSERT INTO foo (a,b) VALUES (42,314)", true}, + {"INSERT INTO foo (a,b,) VALUES (42,314)", true}, + {"INSERT INTO foo (a,b,) VALUES (42,314,)", true}, + {"CREATE TABLE foo (a uint16, b uint32,)", true}, + {"CREATE TABLE foo (a uint16, b uint32,) -- foo", true}, + // 40 + {"CREATE TABLE foo (a uint16, b uint32,) // foo", true}, + {"CREATE TABLE foo (a uint16, b uint32,) /* foo */", true}, + {"CREATE TABLE foo /* foo */ (a uint16, b uint32,) /* foo */", true}, + {`-- Examples + ALTER TABLE Stock ADD Qty int; + + ALTER TABLE Income DROP COLUMN Taxes; + + CREATE TABLE department + ( + DepartmentID int, + DepartmentName string, // optional comma + ); + + CREATE TABLE employee + ( + LastName string, + DepartmentID int // optional comma + ); + + DROP TABLE Inventory; + + INSERT INTO department (DepartmentID) VALUES (42); + + INSERT INTO department ( + DepartmentName, + DepartmentID, + ) + VALUES ( + "R&D", + 42, + ); + + INSERT INTO department VALUES ( + 42, + "R&D", + ); + + SELECT * FROM Stock; + + SELECT DepartmentID + FROM department + WHERE DepartmentID == 42 + ORDER BY DepartmentName; + + SELECT employee.LastName + FROM department, employee + WHERE department.DepartmentID == employee.DepartmentID + ORDER BY DepartmentID; + + SELECT a.b, c.d + FROM + x AS a, + ( + SELECT * FROM y; // optional semicolon + ) AS c + WHERE a.e > c.e; + + SELECT a.b, c.d + FROM + x AS a, + ( + SELECT * FROM y // no semicolon + ) AS c + WHERE a.e > c.e; + + TRUNCATE TABLE department; + + SELECT DepartmentID + FROM department + WHERE DepartmentID == ?1 + ORDER BY DepartmentName; + + SELECT employee.LastName + FROM department, employee + WHERE department.DepartmentID == $1 && employee.LastName > $2 + ORDER BY DepartmentID; + + `, true}, + {"BEGIN TRANSACTION", true}, + // 45 + {"COMMIT", true}, + {"ROLLBACK", true}, + {` + BEGIN TRANSACTION; + INSERT INTO foo VALUES (42, 3.14); + INSERT INTO foo VALUES (-1, 2.78); + COMMIT;`, true}, + {` + BEGIN TRANSACTION; + INSERT INTO AccountA (Amount) VALUES ($1); + INSERT INTO AccountB (Amount) VALUES (-$1); + COMMIT;`, true}, + {` // A + BEGIN TRANSACTION; + INSERT INTO tmp SELECT * from bar; + SELECT * from tmp; + + // B + ROLLBACK;`, true}, + // 50 + {`-- 6 + ALTER TABLE none DROP COLUMN c1; + `, true}, + } + + for i, test := range table { + //dbg("%d ----\n%q\n----\n", i, test.src) + l := newLexer(test.src) + ok := yyParse(l) == 0 + if g, e := ok, test.ok; g != e { + if !ok { + t.Log(l.errs[0]) + } + t.Error(i, test.src, g, e) + return + } + + switch ok { + case true: + if len(l.errs) != 0 { + t.Fatal(l.errs) + } + case false: + if len(l.errs) == 0 { + t.Fatal(l.errs) + } + } + } +} diff --git a/Godeps/_workspace/src/github.com/cznic/ql/ql.ebnf b/Godeps/_workspace/src/github.com/cznic/ql/ql.ebnf new file mode 100644 index 0000000..3c2876c --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/ql/ql.ebnf @@ -0,0 +1,218 @@ +andand = "&&" . +andnot = "&^" . +ascii_letter = "a" … "z" | "A" … "Z" . +big_u_value = "\\" "U" hex_digit hex_digit hex_digit hex_digit hex_digit hex_digit hex_digit hex_digit . +byte_value = octal_byte_value | hex_byte_value . +decimal_digit = "0" … "9" . +decimal_lit = ( "1" … "9" ) { decimal_digit } . +decimals = decimal_digit { decimal_digit } . +eq = "==" . +escaped_char = "\\" ( + "a" + | "b" + | "f" + | "n" + | "r" + | "t" + | "v" + | "\\" + | "'" + | "\"" + ) . +exponent = ( "e" | "E" ) [ "+" | "-" ] decimals . +float_lit = decimals "." [ decimals ] [ exponent ] + | decimals exponent + | "." decimals [ exponent ] . +ge = ">=" . +hex_byte_value = "\\" "x" hex_digit hex_digit . +hex_digit = "0" … "9" + | "A" … "F" + | "a" … "f" . +hex_lit = "0" ( "x" | "X" ) hex_digit { hex_digit } . +identifier = letter { letter | decimal_digit } . +imaginary_lit = ( decimals | float_lit ) "i" . +int_lit = decimal_lit + | octal_lit + | hex_lit . +interpreted_string_lit = "\"" { unicode_value | byte_value } "\"" . +le = "<=" . +letter = ascii_letter | "_" . +little_u_value = "\\" "u" hex_digit hex_digit hex_digit hex_digit . +lsh = "<<" . +neq = "!=" . +newline = . +octal_byte_value = "\\" octal_digit octal_digit octal_digit . +octal_digit = "0" … "7" . +octal_lit = "0" { octal_digit } . +oror = "||" . +ql_parameter = ( "?" | "$" ) "1" … "9" { "0" … "9" } . +raw_string_lit = "`" { unicode_char | newline } "`" . +rsh = ">>" . +rune_lit = "'" ( unicode_value | byte_value ) "'" . +string_lit = raw_string_lit | interpreted_string_lit . +unicode_char = . +unicode_value = unicode_char + | little_u_value + | big_u_value + | escaped_char . + +AlterTableStmt = "ALTER" "TABLE" TableName ( + "ADD" ColumnDef + | "DROP" "COLUMN" ColumnName + ) . +Assignment = ColumnName "=" Expression . +AssignmentList = Assignment { "," Assignment } [ "," ] . +BeginTransactionStmt = "BEGIN" "TRANSACTION" . +Call = "(" [ ExpressionList ] ")" . +ColumnDef = ColumnName Type . +ColumnName = identifier . +ColumnNameList = ColumnName { "," ColumnName } [ "," ] . +CommitStmt = "COMMIT" . +Conversion = Type "(" Expression ")" . +CreateIndexStmt = "CREATE" [ "UNIQUE" ] "INDEX" [ + "IF" "NOT" "EXISTS" + ] IndexName "ON" TableName "(" ( + ColumnName + | "id" Call + ) ")" . +CreateTableStmt = "CREATE" "TABLE" [ + "IF" "NOT" "EXISTS" + ] TableName "(" ColumnDef { "," ColumnDef } [ "," ] ")" . +DeleteFromStmt = "DELETE" "FROM" TableName [ WhereClause ] . +DropIndexStmt = "DROP" "INDEX" [ "IF" "EXISTS" ] IndexName . +DropTableStmt = "DROP" "TABLE" [ "IF" "EXISTS" ] TableName . +EmptyStmt = . +Expression = Term { + ( oror | "OR" ) Term + } . +ExpressionList = Expression { "," Expression } [ "," ] . +Factor = PrimaryFactor { + ( + ge + | ">" + | le + | "<" + | neq + | eq + | "LIKE" + ) PrimaryFactor + } [ Predicate ] . +Field = Expression [ "AS" identifier ] . +FieldList = Field { "," Field } [ "," ] . +GroupByClause = "GROUP BY" ColumnNameList . +Index = "[" Expression "]" . +IndexName = identifier . +InsertIntoStmt = "INSERT" "INTO" TableName [ + "(" ColumnNameList ")" + ] ( Values | SelectStmt ) . +Limit = "Limit" Expression . +Literal = "FALSE" + | "NULL" + | "TRUE" + | float_lit + | imaginary_lit + | int_lit + | rune_lit + | string_lit + | ql_parameter . +Offset = "OFFSET" Expression . +Operand = Literal + | QualifiedIdent + | "(" Expression ")" . +OrderBy = "ORDER" "BY" ExpressionList [ "ASC" | "DESC" ] . +Predicate = ( + [ "NOT" ] ( + "IN" "(" ExpressionList ")" + | "IN" "(" SelectStmt ")" + | "BETWEEN" PrimaryFactor "AND" PrimaryFactor + ) + | "IS" [ "NOT" ] "NULL" + ) . +PrimaryExpression = Operand + | Conversion + | PrimaryExpression Index + | PrimaryExpression Slice + | PrimaryExpression Call . +PrimaryFactor = PrimaryTerm { + ( + "^" + | "|" + | "-" + | "+" + ) PrimaryTerm + } . +PrimaryTerm = UnaryExpr { + ( + andnot + | "&" + | lsh + | rsh + | "%" + | "/" + | "*" + ) UnaryExpr + } . +QualifiedIdent = identifier [ "." identifier ] . +RecordSet = ( + TableName + | "(" SelectStmt [ ";" ] ")" + ) [ "AS" identifier ] . +RecordSetList = RecordSet { "," RecordSet } [ "," ] . +RollbackStmt = "ROLLBACK" . +SelectStmt = "SELECT" [ "DISTINCT" ] ( "*" | FieldList ) "FROM" RecordSetList [ WhereClause ] [ GroupByClause ] [ OrderBy ] [ Limit ] [ Offset ] . +Slice = "[" [ Expression ] ":" [ Expression ] "]" . +Statement = EmptyStmt + | AlterTableStmt + | BeginTransactionStmt + | CommitStmt + | CreateIndexStmt + | CreateTableStmt + | DeleteFromStmt + | DropIndexStmt + | DropTableStmt + | InsertIntoStmt + | RollbackStmt + | SelectStmt + | TruncateTableStmt + | UpdateStmt . +StatementList = Statement { ";" Statement } . +TableName = identifier . +Term = Factor { + ( andand | "AND" ) Factor + } . +TruncateTableStmt = "TRUNCATE" "TABLE" TableName . +Type = "bigint" + | "bigrat" + | "blob" + | "bool" + | "byte" + | "complex128" + | "complex64" + | "duration" + | "float" + | "float32" + | "float64" + | "int" + | "int16" + | "int32" + | "int64" + | "int8" + | "rune" + | "string" + | "time" + | "uint" + | "uint16" + | "uint32" + | "uint64" + | "uint8" . +UnaryExpr = [ + "^" + | "!" + | "-" + | "+" + ] PrimaryExpression . +UpdateStmt = "UPDATE" TableName [ "SET" ] AssignmentList [ WhereClause ] . +Values = "VALUES" "(" ExpressionList ")" { + "," "(" ExpressionList ")" + } [ "," ] . +WhereClause = "WHERE" Expression . diff --git a/Godeps/_workspace/src/github.com/cznic/ql/ql.go b/Godeps/_workspace/src/github.com/cznic/ql/ql.go new file mode 100644 index 0000000..1e7fe61 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/ql/ql.go @@ -0,0 +1,2162 @@ +// Copyright 2014 The ql Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//LATER profile mem +//LATER profile cpu +//LATER coverage + +//MAYBE CROSSJOIN (explicit form), LEFT JOIN, INNER JOIN, OUTER JOIN equivalents. + +package ql + +import ( + "bytes" + "errors" + "fmt" + "io" + "log" + "math/big" + "strconv" + "strings" + "sync" + "time" + + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/strutil" +) + +// NOTE: all rset implementations must be safe for concurrent use by multiple +// goroutines. If the do method requires any execution domain local data, they +// must be held out of the implementing instance. +var ( + _ rset = (*crossJoinRset)(nil) + _ rset = (*distinctRset)(nil) + _ rset = (*groupByRset)(nil) + _ rset = (*limitRset)(nil) + _ rset = (*offsetRset)(nil) + _ rset = (*orderByRset)(nil) + _ rset = (*selectRset)(nil) + _ rset = (*selectStmt)(nil) + _ rset = (*tableRset)(nil) + _ rset = (*whereRset)(nil) + + isTesting bool // enables test hook: select from an index +) + +const ( + noNames = iota + returnNames + onlyNames +) + +// List represents a group of compiled statements. +type List struct { + l []stmt + params int +} + +// String implements fmt.Stringer +func (l List) String() string { + var b bytes.Buffer + f := strutil.IndentFormatter(&b, "\t") + for _, s := range l.l { + switch s.(type) { + case beginTransactionStmt: + f.Format("%s\n%i", s) + case commitStmt, rollbackStmt: + f.Format("%u%s\n", s) + default: + f.Format("%s\n", s) + } + } + return b.String() +} + +type rset interface { + do(ctx *execCtx, onlyNames bool, f func(id interface{}, data []interface{}) (more bool, err error)) error +} + +type recordset struct { + ctx *execCtx + rset + tx *TCtx +} + +func (r recordset) Do(names bool, f func(data []interface{}) (more bool, err error)) (err error) { + nm := noNames + if names { + nm = returnNames + } + return r.ctx.db.do(r, nm, f) +} + +func (r recordset) Fields() (names []string, err error) { + err = r.ctx.db.do( + r, + onlyNames, + func(data []interface{}) (more bool, err error) { + for _, v := range data { + s, ok := v.(string) + if !ok { + return false, fmt.Errorf("got %T(%v), expected string (RecordSet.Fields)", v, v) + } + names = append(names, s) + } + return false, nil + }, + ) + return +} + +func (r recordset) FirstRow() (row []interface{}, err error) { + rows, err := r.Rows(1, 0) + if err != nil { + return nil, err + } + + if len(rows) != 0 { + return rows[0], nil + } + + return nil, nil +} + +func (r recordset) Rows(limit, offset int) (rows [][]interface{}, err error) { + if err := r.Do(false, func(row []interface{}) (bool, error) { + if offset > 0 { + offset-- + return true, nil + } + + switch { + case limit < 0: + rows = append(rows, row) + return true, nil + case limit == 0: + return false, nil + default: // limit > 0 + rows = append(rows, row) + limit-- + return limit > 0, nil + } + }); err != nil { + return nil, err + } + + return rows, nil +} + +type groupByRset struct { + colNames []string + src rset +} + +func (r *groupByRset) do(ctx *execCtx, onlyNames bool, f func(id interface{}, data []interface{}) (more bool, err error)) (err error) { + t, err := ctx.db.store.CreateTemp(true) + if err != nil { + return + } + + defer func() { + if derr := t.Drop(); derr != nil && err == nil { + err = derr + } + }() + + var flds []*fld + var gcols []*col + var cols []*col + ok := false + k := make([]interface{}, len(r.colNames)) //LATER optimize when len(r.cols) == 0 + if err = r.src.do(ctx, onlyNames, func(rid interface{}, in []interface{}) (more bool, err error) { + if ok { + infer(in, &cols) + for i, c := range gcols { + k[i] = in[c.index] + } + h0, err := t.Get(k) + if err != nil { + return false, err + } + + var h int64 + if len(h0) != 0 { + h, _ = h0[0].(int64) + } + nh, err := t.Create(append([]interface{}{h, nil}, in...)...) + if err != nil { + return false, err + } + + for i, c := range gcols { + k[i] = in[c.index] + } + err = t.Set(k, []interface{}{nh}) + if err != nil { + return false, err + } + + return true, nil + } + + ok = true + flds = in[0].([]*fld) + for _, c := range r.colNames { + i := findFldIndex(flds, c) + if i < 0 { + return false, fmt.Errorf("unknown column %s", c) + } + + gcols = append(gcols, &col{name: c, index: i}) + } + return !onlyNames, nil + }); err != nil { + return + } + + if onlyNames { + _, err := f(nil, []interface{}{flds}) + return err + } + + it, err := t.SeekFirst() + if err != nil { + return noEOF(err) + } + + for i, v := range flds { + cols[i].name = v.name + cols[i].index = i + } + + var data []interface{} + var more bool + for more, err = f(nil, []interface{}{t, cols}); more && err == nil; more, err = f(nil, data) { + _, data, err = it.Next() + if err != nil { + return noEOF(err) + } + } + return err +} + +// TCtx represents transaction context. It enables to execute multiple +// statement lists in the same context. The same context guarantees the state +// of the DB cannot change in between the separated executions. +// +// LastInsertID +// +// LastInsertID is updated by INSERT INTO statements. The value considers +// performed ROLLBACK statements, if any, even though roll backed IDs are not +// reused. QL clients should treat the field as read only. +// +// RowsAffected +// +// RowsAffected is updated by INSERT INTO, DELETE FROM and UPDATE statements. +// The value does not (yet) consider any ROLLBACK statements involved. QL +// clients should treat the field as read only. +type TCtx struct { + LastInsertID int64 + RowsAffected int64 +} + +// NewRWCtx returns a new read/write transaction context. NewRWCtx is safe for +// concurrent use by multiple goroutines, every one of them will get a new, +// unique conext. +func NewRWCtx() *TCtx { return &TCtx{} } + +// Recordset is a result of a select statment. It can call a user function for +// every row (record) in the set using the Do method. +// +// Recordsets can be safely reused. Evaluation of the rows is performed lazily. +// Every invocation of Do will see the current, potentially actualized data. +// +// Do +// +// Do will call f for every row (record) in the Recordset. +// +// If f returns more == false or err != nil then f will not be called for any +// remaining rows in the set and the err value is returned from Do. +// +// If names == true then f is firstly called with a virtual row +// consisting of field (column) names of the RecordSet. +// +// Do is executed in a read only context and performs a RLock of the +// database. +// +// Do is safe for concurrent use by multiple goroutines. +// +// Fields +// +// The only reliable way, in the general case, how to get field names of a +// recordset is to execute the Do method with the names parameter set to true. +// Any SELECT can return different fields on different runs, provided the +// columns of some of the underlying tables involved were altered in between +// and the query sports the SELECT * form. Then the fields are not really +// known until the first query result row materializes. The problem is that +// some queries can be costly even before that first row is computed. If only +// the field names is what is required in some situation then executing such +// costly query could be prohibitively expensive. +// +// The Fields method provides an alternative. It computes the recordset fields +// while ignoring table data, WHERE clauses, predicates and without evaluating +// any expressions nor any functions. +// +// The result of Fields can be obviously imprecise if tables are altered before +// running Do later. In exchange, calling Fields is cheap - compared to +// actually computing a first row of a query having, say cross joins on n +// relations (1^n is always 1, n ∈ N). +// +// FirstRow +// +// FirstRow will return the first row of the RecordSet or an error, if any. If +// the Recordset has no rows the result is (nil, nil). +// +// Rows +// +// Rows will return rows in Recordset or an error, if any. The semantics of +// limit and offset are the same as of the LIMIT and OFFSET clauses of the +// SELECT statement. To get all rows pass limit < 0. If there are no rows to +// return the result is (nil, nil). +type Recordset interface { + Do(names bool, f func(data []interface{}) (more bool, err error)) error + Fields() (names []string, err error) + FirstRow() (row []interface{}, err error) + Rows(limit, offset int) (rows [][]interface{}, err error) +} + +type assignment struct { + colName string + expr expression +} + +func (a *assignment) String() string { + return fmt.Sprintf("%s=%s", a.colName, a.expr) +} + +type distinctRset struct { + src rset +} + +func (r *distinctRset) do(ctx *execCtx, onlyNames bool, f func(id interface{}, data []interface{}) (more bool, err error)) (err error) { + t, err := ctx.db.store.CreateTemp(true) + if err != nil { + return + } + + defer func() { + if derr := t.Drop(); derr != nil && err == nil { + err = derr + } + }() + + var flds []*fld + ok := false + if err = r.src.do(ctx, onlyNames, func(id interface{}, in []interface{}) (more bool, err error) { + if ok { + if err = t.Set(in, nil); err != nil { + return false, err + } + + return true, nil + } + + flds = in[0].([]*fld) + ok = true + return true && !onlyNames, nil + }); err != nil { + return + } + + if onlyNames { + _, err := f(nil, []interface{}{flds}) + return noEOF(err) + } + + it, err := t.SeekFirst() + if err != nil { + return noEOF(err) + } + + var data []interface{} + var more bool + for more, err = f(nil, []interface{}{flds}); more && err == nil; more, err = f(nil, data) { + data, _, err = it.Next() + if err != nil { + return noEOF(err) + } + } + return err +} + +type orderByRset struct { + asc bool + by []expression + src rset +} + +func (r *orderByRset) String() string { + a := make([]string, len(r.by)) + for i, v := range r.by { + a[i] = v.String() + } + s := strings.Join(a, ", ") + if !r.asc { + s += " DESC" + } + return s +} + +func (r *orderByRset) do(ctx *execCtx, onlyNames bool, f func(id interface{}, data []interface{}) (more bool, err error)) (err error) { + t, err := ctx.db.store.CreateTemp(r.asc) + if err != nil { + return + } + + defer func() { + if derr := t.Drop(); derr != nil && err == nil { + err = derr + } + }() + + m := map[interface{}]interface{}{} + var flds []*fld + ok := false + k := make([]interface{}, len(r.by)+1) + id := int64(-1) + if err = r.src.do(ctx, onlyNames, func(rid interface{}, in []interface{}) (more bool, err error) { + id++ + if ok { + for i, fld := range flds { + if nm := fld.name; nm != "" { + m[nm] = in[i] + } + } + m["$id"] = rid + for i, expr := range r.by { + val, err := expr.eval(ctx, m, ctx.arg) + if err != nil { + return false, err + } + + if val != nil { + val, ordered, err := isOrderedType(val) + if err != nil { + return false, err + } + + if !ordered { + return false, fmt.Errorf("cannot order by %v (type %T)", val, val) + + } + } + + k[i] = val + } + k[len(r.by)] = id + if err = t.Set(k, in); err != nil { + return false, err + } + + return true, nil + } + + ok = true + flds = in[0].([]*fld) + return true && !onlyNames, nil + }); err != nil { + return + } + + if onlyNames { + _, err = f(nil, []interface{}{flds}) + return noEOF(err) + } + + it, err := t.SeekFirst() + if err != nil { + if err != io.EOF { + return err + } + + _, err = f(nil, []interface{}{flds}) + return err + } + + var data []interface{} + var more bool + for more, err = f(nil, []interface{}{flds}); more && err == nil; more, err = f(nil, data) { + _, data, err = it.Next() + if err != nil { + return noEOF(err) + } + } + return +} + +var nowhere = &whereRset{} + +type whereRset struct { + expr expression + src rset +} + +func (r *whereRset) doIndexedBool(t *table, en indexIterator, v bool, f func(id interface{}, data []interface{}) (more bool, err error)) (err error) { + m, err := f(nil, []interface{}{t.flds()}) + if !m || err != nil { + return + } + + for { + k, h, err := en.Next() + if err != nil { + return noEOF(err) + } + + switch x := k.(type) { + case nil: + panic("internal error 052") // nil should sort before true + case bool: + if x != v { + return nil + } + } + + if _, err := tableRset("").doOne(t, h, f); err != nil { + return err + } + } +} + +func (r *whereRset) tryBinOp(execCtx *execCtx, t *table, id *ident, v value, op int, f func(id interface{}, data []interface{}) (more bool, err error)) (bool, error) { + c := findCol(t.cols0, id.s) + if c == nil { + return false, fmt.Errorf("undefined column: %s", id.s) + } + + xCol := t.indices[c.index+1] + if xCol == nil { // no index for this column + return false, nil + } + + data := []interface{}{v.val} + cc := *c + cc.index = 0 + if err := typeCheck(data, []*col{&cc}); err != nil { + return true, err + } + + v.val = data[0] + ex := &binaryOperation{op, nil, v} + switch op { + case '<', le: + v.val = false // first value collating after nil + fallthrough + case eq, ge: + m, err := f(nil, []interface{}{t.flds()}) + if !m || err != nil { + return true, err + } + + en, _, err := xCol.x.Seek(v.val) + if err != nil { + return true, noEOF(err) + } + + for { + k, h, err := en.Next() + if k == nil { + return true, nil + } + + if err != nil { + return true, noEOF(err) + } + + ex.l = value{k} + eval, err := ex.eval(execCtx, nil, nil) + if err != nil { + return true, err + } + + if !eval.(bool) { + return true, nil + } + + if _, err := tableRset("").doOne(t, h, f); err != nil { + return true, err + } + } + case '>': + m, err := f(nil, []interface{}{t.flds()}) + if !m || err != nil { + return true, err + } + + en, err := xCol.x.SeekLast() + if err != nil { + return true, noEOF(err) + } + + for { + k, h, err := en.Prev() + if k == nil { + return true, nil + } + + if err != nil { + return true, noEOF(err) + } + + ex.l = value{k} + eval, err := ex.eval(execCtx, nil, nil) + if err != nil { + return true, err + } + + if !eval.(bool) { + return true, nil + } + + if _, err := tableRset("").doOne(t, h, f); err != nil { + return true, err + } + } + default: + panic("internal error 053") + } +} + +func (r *whereRset) tryBinOpID(execCtx *execCtx, t *table, v value, op int, f func(id interface{}, data []interface{}) (more bool, err error)) (bool, error) { + xCol := t.indices[0] + if xCol == nil { // no index for id() + return false, nil + } + + data := []interface{}{v.val} + if err := typeCheck(data, []*col{&col{typ: qInt64}}); err != nil { + return true, err + } + + v.val = data[0] + ex := &binaryOperation{op, nil, v} + switch op { + case '<', le: + v.val = int64(1) + fallthrough + case eq, ge: + m, err := f(nil, []interface{}{t.flds()}) + if !m || err != nil { + return true, err + } + + en, _, err := xCol.x.Seek(v.val) + if err != nil { + return true, noEOF(err) + } + + for { + k, h, err := en.Next() + if k == nil { + return true, nil + } + + if err != nil { + return true, noEOF(err) + } + + ex.l = value{k} + eval, err := ex.eval(execCtx, nil, nil) + if err != nil { + return true, err + } + + if !eval.(bool) { + return true, nil + } + + if _, err := tableRset("").doOne(t, h, f); err != nil { + return true, err + } + } + case '>': + m, err := f(nil, []interface{}{t.flds()}) + if !m || err != nil { + return true, err + } + + en, err := xCol.x.SeekLast() + if err != nil { + return true, noEOF(err) + } + + for { + k, h, err := en.Prev() + if k == nil { + return true, nil + } + + if err != nil { + return true, noEOF(err) + } + + ex.l = value{k} + eval, err := ex.eval(execCtx, nil, nil) + if err != nil { + return true, err + } + + if !eval.(bool) { + return true, nil + } + + if _, err := tableRset("").doOne(t, h, f); err != nil { + return true, err + } + } + default: + panic("internal error 071") + } +} + +func (r *whereRset) tryUseIndex(ctx *execCtx, f func(id interface{}, data []interface{}) (more bool, err error)) (bool, error) { + //TODO(indices) support IS [NOT] NULL + c, ok := r.src.(*crossJoinRset) + if !ok { + return false, nil + } + + tabName, ok := c.isSingleTable() + if !ok || isSystemName[tabName] { + return false, nil + } + + t := ctx.db.root.tables[tabName] + if t == nil { + return true, fmt.Errorf("table %s does not exist", tabName) + } + + if !t.hasIndices() { + return false, nil + } + + //LATER WHERE column1 boolOp column2 ... + //LATER WHERE !column (rewritable as: column == false) + switch ex := r.expr.(type) { + case *unaryOperation: // WHERE !column + if ex.op != '!' { + return false, nil + } + + switch operand := ex.v.(type) { + case *ident: + c := findCol(t.cols0, operand.s) + if c == nil { // no such column + return false, fmt.Errorf("unknown column %s", ex) + } + + if c.typ != qBool { // not a bool column + return false, nil + } + + xCol := t.indices[c.index+1] + if xCol == nil { // column isn't indexed + return false, nil + } + + en, _, err := xCol.x.Seek(false) + if err != nil { + return false, noEOF(err) + } + + return true, r.doIndexedBool(t, en, false, f) + default: + return false, nil + } + case *ident: // WHERE column + c := findCol(t.cols0, ex.s) + if c == nil { // no such column + return false, fmt.Errorf("unknown column %s", ex) + } + + if c.typ != qBool { // not a bool column + return false, nil + } + + xCol := t.indices[c.index+1] + if xCol == nil { // column isn't indexed + return false, nil + } + + en, _, err := xCol.x.Seek(true) + if err != nil { + return false, noEOF(err) + } + + return true, r.doIndexedBool(t, en, true, f) + case *binaryOperation: + //DONE handle id() + var invOp int + switch ex.op { + case '<': + invOp = '>' + case le: + invOp = ge + case eq: + invOp = eq + case '>': + invOp = '<' + case ge: + invOp = le + default: + return false, nil + } + + switch lhs := ex.l.(type) { + case *call: + if !(lhs.f == "id" && len(lhs.arg) == 0) { + return false, nil + } + + switch rhs := ex.r.(type) { + case parameter: + v, err := rhs.eval(ctx, nil, ctx.arg) + if err != nil { + return false, err + } + + return r.tryBinOpID(ctx, t, value{v}, ex.op, f) + case value: + return r.tryBinOpID(ctx, t, rhs, ex.op, f) + default: + return false, nil + } + case *ident: + switch rhs := ex.r.(type) { + case parameter: + v, err := rhs.eval(ctx, nil, ctx.arg) + if err != nil { + return false, err + } + + return r.tryBinOp(ctx, t, lhs, value{v}, ex.op, f) + case value: + return r.tryBinOp(ctx, t, lhs, rhs, ex.op, f) + default: + return false, nil + } + case parameter: + switch rhs := ex.r.(type) { + case *call: + if !(rhs.f == "id" && len(rhs.arg) == 0) { + return false, nil + } + + v, err := lhs.eval(ctx, nil, ctx.arg) + if err != nil { + return false, err + } + + return r.tryBinOpID(ctx, t, value{v}, invOp, f) + case *ident: + v, err := lhs.eval(ctx, nil, ctx.arg) + if err != nil { + return false, err + } + + return r.tryBinOp(ctx, t, rhs, value{v}, invOp, f) + default: + return false, nil + } + case value: + switch rhs := ex.r.(type) { + case *call: + if !(rhs.f == "id" && len(rhs.arg) == 0) { + return false, nil + } + + return r.tryBinOpID(ctx, t, lhs, invOp, f) + case *ident: + return r.tryBinOp(ctx, t, rhs, lhs, invOp, f) + default: + return false, nil + } + default: + return false, nil + } + default: + return false, nil + } +} + +func (r *whereRset) do(ctx *execCtx, onlyNames bool, f func(id interface{}, data []interface{}) (more bool, err error)) (err error) { + //dbg("====") + if !onlyNames { + if ok, err := r.tryUseIndex(ctx, f); ok || err != nil { + //dbg("ok %t, err %v", ok, err) + return err + } + } + + //dbg("not using indices") + m := map[interface{}]interface{}{} + var flds []*fld + ok := false + return r.src.do(ctx, onlyNames, func(rid interface{}, in []interface{}) (more bool, err error) { + if ok { + for i, fld := range flds { + if nm := fld.name; nm != "" { + m[nm] = in[i] + } + } + m["$id"] = rid + val, err := r.expr.eval(ctx, m, ctx.arg) + if err != nil { + return false, err + } + + if val == nil { + return true, nil + } + + x, ok := val.(bool) + if !ok { + return false, fmt.Errorf("invalid WHERE expression %s (value of type %T)", val, val) + } + + if !x { + return true, nil + } + + return f(rid, in) + } + + flds = in[0].([]*fld) + ok = true + m, err := f(nil, in) + return m && !onlyNames, err + }) +} + +type offsetRset struct { + expr expression + src rset +} + +func (r *offsetRset) do(ctx *execCtx, onlyNames bool, f func(id interface{}, data []interface{}) (more bool, err error)) (err error) { + m := map[interface{}]interface{}{} + var flds []*fld + var ok, eval bool + var off uint64 + return r.src.do(ctx, onlyNames, func(rid interface{}, in []interface{}) (more bool, err error) { + if ok { + if !eval { + for i, fld := range flds { + if nm := fld.name; nm != "" { + m[nm] = in[i] + } + } + m["$id"] = rid + val, err := r.expr.eval(ctx, m, ctx.arg) + if err != nil { + return false, err + } + + if val == nil { + return true, nil + } + + if off, err = limOffExpr(val); err != nil { + return false, err + } + + eval = true + } + if off > 0 { + off-- + return true, nil + } + + return f(rid, in) + } + + flds = in[0].([]*fld) + ok = true + m, err := f(nil, in) + return m && !onlyNames, err + }) +} + +type limitRset struct { + expr expression + src rset +} + +func (r *limitRset) do(ctx *execCtx, onlyNames bool, f func(id interface{}, data []interface{}) (more bool, err error)) (err error) { + m := map[interface{}]interface{}{} + var flds []*fld + var ok, eval bool + var lim uint64 + return r.src.do(ctx, onlyNames, func(rid interface{}, in []interface{}) (more bool, err error) { + if ok { + if !eval { + for i, fld := range flds { + if nm := fld.name; nm != "" { + m[nm] = in[i] + } + } + m["$id"] = rid + val, err := r.expr.eval(ctx, m, ctx.arg) + if err != nil { + return false, err + } + + if val == nil { + return true, nil + } + + if lim, err = limOffExpr(val); err != nil { + return false, err + } + + eval = true + } + switch lim { + case 0: + return false, nil + default: + lim-- + return f(rid, in) + } + } + + flds = in[0].([]*fld) + ok = true + m, err := f(nil, in) + return m && !onlyNames, err + }) +} + +type selectRset struct { + flds []*fld + src rset +} + +func (r *selectRset) doGroup(grp *groupByRset, ctx *execCtx, onlyNames bool, f func(id interface{}, data []interface{}) (more bool, err error)) (err error) { + if onlyNames { + if len(r.flds) != 0 { + _, err := f(nil, []interface{}{r.flds}) + return err + } + + return grp.do(ctx, true, f) + } + + var t temp + var cols []*col + out := make([]interface{}, len(r.flds)) + ok := false + rows := 0 + if err = r.src.do(ctx, onlyNames, func(rid interface{}, in []interface{}) (more bool, err error) { + if ok { + h := in[0].(int64) + m := map[interface{}]interface{}{} + for h != 0 { + in, err = t.Read(nil, h, cols...) + if err != nil { + return false, err + } + + rec := in[2:] + for i, c := range cols { + if nm := c.name; nm != "" { + m[nm] = rec[i] + } + } + m["$id"] = rid + for _, fld := range r.flds { + if _, err = fld.expr.eval(ctx, m, ctx.arg); err != nil { + return false, err + } + } + + h = in[0].(int64) + } + m["$agg"] = true + for i, fld := range r.flds { + if out[i], err = fld.expr.eval(ctx, m, ctx.arg); err != nil { + return false, err + } + } + rows++ + return f(nil, out) + } + + ok = true + rows++ + t = in[0].(temp) + cols = in[1].([]*col) + if len(r.flds) == 0 { + r.flds = make([]*fld, len(cols)) + for i, v := range cols { + r.flds[i] = &fld{expr: &ident{v.name}, name: v.name} + } + out = make([]interface{}, len(r.flds)) + } + m, err := f(nil, []interface{}{r.flds}) + return m && !onlyNames, err + }); err != nil || onlyNames { + return + } + + switch rows { + case 0: + more, err := f(nil, []interface{}{r.flds}) + if !more || err != nil { + return err + } + + fallthrough + case 1: + m := map[interface{}]interface{}{"$agg0": true} // aggregate empty record set + for i, fld := range r.flds { + if out[i], err = fld.expr.eval(ctx, m, ctx.arg); err != nil { + return + } + } + _, err = f(nil, out) + } + return +} + +func (r *selectRset) do(ctx *execCtx, onlyNames bool, f func(id interface{}, data []interface{}) (more bool, err error)) (err error) { + if grp, ok := r.src.(*groupByRset); ok { + return r.doGroup(grp, ctx, onlyNames, f) + } + + if len(r.flds) == 0 { + return r.src.do(ctx, onlyNames, f) + } + + if onlyNames { + _, err := f(nil, []interface{}{r.flds}) + return err + } + + var flds []*fld + m := map[interface{}]interface{}{} + ok := false + return r.src.do(ctx, onlyNames, func(rid interface{}, in []interface{}) (more bool, err error) { + if ok { + for i, fld := range flds { + if nm := fld.name; nm != "" { + m[nm] = in[i] + } + } + m["$id"] = rid + out := make([]interface{}, len(r.flds)) + for i, fld := range r.flds { + if out[i], err = fld.expr.eval(ctx, m, ctx.arg); err != nil { + return false, err + } + } + m, err := f(rid, out) + return m, err + + } + + ok = true + flds = in[0].([]*fld) + m, err := f(nil, []interface{}{r.flds}) + return m && !onlyNames, err + }) +} + +type tableRset string + +func (r tableRset) doIndex(x *indexedCol, ctx *execCtx, onlyNames bool, f func(id interface{}, data []interface{}) (more bool, err error)) (err error) { + flds := []*fld{&fld{name: x.name}} + m, err := f(nil, []interface{}{flds}) + if onlyNames { + return err + } + + if !m || err != nil { + return + } + + en, _, err := x.x.Seek(nil) + if err != nil { + return err + } + + var id int64 + rec := []interface{}{nil} + for { + k, _, err := en.Next() + if err != nil { + return noEOF(err) + } + + id++ + rec[0] = k + m, err := f(id, rec) + if !m || err != nil { + return err + } + } +} + +func (tableRset) doOne(t *table, h int64, f func(id interface{}, data []interface{}) (more bool, err error)) ( /* next handle */ int64, error) { + cols := t.cols + ncols := len(cols) + rec, err := t.store.Read(nil, h, cols...) + if err != nil { + return -1, err + } + + h = rec[0].(int64) + if n := ncols + 2 - len(rec); n > 0 { + rec = append(rec, make([]interface{}, n)...) + } + + for i, c := range cols { + if x := c.index; 2+x < len(rec) { + rec[2+i] = rec[2+x] + continue + } + + rec[2+i] = nil //DONE +test (#571) + } + m, err := f(rec[1], rec[2:2+ncols]) // 0:next, 1:id + if !m || err != nil { + return -1, err + } + + return h, nil +} + +func (r tableRset) doSysTable(ctx *execCtx, onlyNames bool, f func(id interface{}, data []interface{}) (more bool, err error)) (err error) { + flds := []*fld{&fld{name: "Name"}, &fld{name: "Schema"}} + m, err := f(nil, []interface{}{flds}) + if onlyNames { + return err + } + + if !m || err != nil { + return + } + + rec := make([]interface{}, 2) + di, err := ctx.db.info() + if err != nil { + return err + } + + var id int64 + for _, ti := range di.Tables { + rec[0] = ti.Name + a := []string{} + for _, ci := range ti.Columns { + a = append(a, fmt.Sprintf("%s %s", ci.Name, ci.Type)) + } + rec[1] = fmt.Sprintf("CREATE TABLE %s (%s);", ti.Name, strings.Join(a, ", ")) + id++ + m, err := f(id, rec) + if !m || err != nil { + return err + } + } + return +} + +func (r tableRset) doSysColumn(ctx *execCtx, onlyNames bool, f func(id interface{}, data []interface{}) (more bool, err error)) (err error) { + flds := []*fld{&fld{name: "TableName"}, &fld{name: "Ordinal"}, &fld{name: "Name"}, &fld{name: "Type"}} + m, err := f(nil, []interface{}{flds}) + if onlyNames { + return err + } + + if !m || err != nil { + return + } + + rec := make([]interface{}, 4) + di, err := ctx.db.info() + if err != nil { + return err + } + + var id int64 + for _, ti := range di.Tables { + rec[0] = ti.Name + var ix int64 + for _, ci := range ti.Columns { + ix++ + rec[1] = ix + rec[2] = ci.Name + rec[3] = ci.Type.String() + id++ + m, err := f(id, rec) + if !m || err != nil { + return err + } + } + } + return +} + +func (r tableRset) doSysIndex(ctx *execCtx, onlyNames bool, f func(id interface{}, data []interface{}) (more bool, err error)) (err error) { + flds := []*fld{&fld{name: "TableName"}, &fld{name: "ColumnName"}, &fld{name: "Name"}, &fld{name: "IsUnique"}} + m, err := f(nil, []interface{}{flds}) + if onlyNames { + return err + } + + if !m || err != nil { + return + } + + rec := make([]interface{}, 4) + di, err := ctx.db.info() + if err != nil { + return err + } + + var id int64 + for _, xi := range di.Indices { + rec[0] = xi.Table + rec[1] = xi.Column + rec[2] = xi.Name + rec[3] = xi.Unique + id++ + m, err := f(id, rec) + if !m || err != nil { + return err + } + } + return +} + +func (r tableRset) do(ctx *execCtx, onlyNames bool, f func(id interface{}, data []interface{}) (more bool, err error)) (err error) { + switch r { + case "__Table": + return r.doSysTable(ctx, onlyNames, f) + case "__Column": + return r.doSysColumn(ctx, onlyNames, f) + case "__Index": + return r.doSysIndex(ctx, onlyNames, f) + } + + t, ok := ctx.db.root.tables[string(r)] + var x *indexedCol + if !ok && isTesting { + if _, x = ctx.db.root.findIndexByName(string(r)); x != nil { + return r.doIndex(x, ctx, onlyNames, f) + } + } + + if !ok { + return fmt.Errorf("table %s does not exist", r) + } + + m, err := f(nil, []interface{}{t.flds()}) + if onlyNames { + return err + } + + if !m || err != nil { + return + } + + for h := t.head; h > 0 && err == nil; h, err = r.doOne(t, h, f) { + } + return +} + +type crossJoinRset struct { + sources []interface{} +} + +func (r *crossJoinRset) tables() []struct { + i int + name, rename string +} { + var ret []struct { + i int + name, rename string + } + //dbg("---- %p", r) + for i, pair0 := range r.sources { + //dbg("%d/%d, %#v", i, len(r.sources), pair0) + pair := pair0.([]interface{}) + altName := pair[1].(string) + switch x := pair[0].(type) { + case string: // table name + if altName == "" { + altName = x + } + ret = append(ret, struct { + i int + name, rename string + }{i, x, altName}) + } + } + return ret +} + +func (r *crossJoinRset) String() string { + a := make([]string, len(r.sources)) + for i, pair0 := range r.sources { + pair := pair0.([]interface{}) + altName := pair[1].(string) + switch x := pair[0].(type) { + case string: // table name + switch { + case altName == "": + a[i] = x + default: + a[i] = fmt.Sprintf("%s AS %s", x, altName) + } + case *selectStmt: + switch { + case altName == "": + a[i] = fmt.Sprintf("(%s)", x) + default: + a[i] = fmt.Sprintf("(%s) AS %s", x, altName) + } + default: + log.Panic("internal error 054") + } + } + return strings.Join(a, ", ") +} + +func (r *crossJoinRset) isSingleTable() (string, bool) { + sources := r.sources + if len(sources) != 1 { + return "", false + } + + pair := sources[0].([]interface{}) + s, ok := pair[0].(string) + return s, ok +} + +func (r *crossJoinRset) do(ctx *execCtx, onlyNames bool, f func(id interface{}, data []interface{}) (more bool, err error)) (err error) { + rsets := make([]rset, len(r.sources)) + altNames := make([]string, len(r.sources)) + //dbg(".... %p", r) + for i, pair0 := range r.sources { + pair := pair0.([]interface{}) + //dbg("%d: %#v", len(pair), pair) + altName := pair[1].(string) + switch x := pair[0].(type) { + case string: // table name + rsets[i] = tableRset(x) + if altName == "" { + altName = x + } + case *selectStmt: + rsets[i] = x + default: + log.Panic("internal error 055") + } + altNames[i] = altName + } + + if len(rsets) == 1 { + return rsets[0].do(ctx, onlyNames, f) + } + + var flds []*fld + fldsSent := false + iq := 0 + stop := false + ids := map[string]interface{}{} + var g func([]interface{}, []rset, int) error + g = func(prefix []interface{}, rsets []rset, x int) (err error) { + rset := rsets[0] + rsets = rsets[1:] + ok := false + return rset.do(ctx, onlyNames, func(id interface{}, in []interface{}) (more bool, err error) { + if onlyNames && fldsSent { + stop = true + return false, nil + } + + if ok { + ids[altNames[x]] = id + if len(rsets) != 0 { + return true, g(append(prefix, in...), rsets, x+1) + } + + m, err := f(ids, append(prefix, in...)) + if !m { + stop = true + } + return m && !stop, err + } + + ok = true + if !fldsSent { + f0 := append([]*fld(nil), in[0].([]*fld)...) + q := altNames[iq] + for i, elem := range f0 { + nf := &fld{} + *nf = *elem + switch { + case q == "": + nf.name = "" + case nf.name != "": + nf.name = fmt.Sprintf("%s.%s", altNames[iq], nf.name) + } + f0[i] = nf + } + iq++ + flds = append(flds, f0...) + } + if len(rsets) == 0 && !fldsSent { + fldsSent = true + more, err = f(nil, []interface{}{flds}) + if !more { + stop = true + } + return more && !stop, err + } + + return !stop, nil + }) + } + return g(nil, rsets, 0) +} + +type fld struct { + expr expression + name string +} + +func findFldIndex(fields []*fld, name string) int { + for i, f := range fields { + if f.name == name { + return i + } + } + + return -1 +} + +func findFld(fields []*fld, name string) (f *fld) { + for _, f = range fields { + if f.name == name { + return + } + } + + return nil +} + +type col struct { + index int + name string + typ int +} + +func findCol(cols []*col, name string) (c *col) { + for _, c = range cols { + if c.name == name { + return + } + } + + return nil +} + +func (f *col) typeCheck(x interface{}) (ok bool) { //NTYPE + switch x.(type) { + case nil: + return true + case bool: + return f.typ == qBool + case complex64: + return f.typ == qComplex64 + case complex128: + return f.typ == qComplex128 + case float32: + return f.typ == qFloat32 + case float64: + return f.typ == qFloat64 + case int8: + return f.typ == qInt8 + case int16: + return f.typ == qInt16 + case int32: + return f.typ == qInt32 + case int64: + return f.typ == qInt64 + case string: + return f.typ == qString + case uint8: + return f.typ == qUint8 + case uint16: + return f.typ == qUint16 + case uint32: + return f.typ == qUint32 + case uint64: + return f.typ == qUint64 + case []byte: + return f.typ == qBlob + case *big.Int: + return f.typ == qBigInt + case *big.Rat: + return f.typ == qBigRat + case time.Time: + return f.typ == qTime + case time.Duration: + return f.typ == qDuration + case chunk: + return true // was checked earlier + } + return +} + +func cols2meta(f []*col) (s string) { + a := []string{} + for _, f := range f { + a = append(a, string(f.typ)+f.name) + } + return strings.Join(a, "|") +} + +// DB represent the database capable of executing QL statements. +type DB struct { + cc *TCtx // Current transaction context + isMem bool + mu sync.Mutex + root *root + rw bool // DB FSM + rwmu sync.RWMutex + store storage + tnl int // Transaction nesting level +} + +func newDB(store storage) (db *DB, err error) { + db0 := &DB{ + store: store, + } + if db0.root, err = newRoot(store); err != nil { + return + } + + return db0, nil +} + +// Name returns the name of the DB. +func (db *DB) Name() string { return db.store.Name() } + +// Run compiles and executes a statement list. It returns, if applicable, a +// RecordSet slice and/or an index and error. +// +// For more details please see DB.Execute +// +// Run is safe for concurrent use by multiple goroutines. +func (db *DB) Run(ctx *TCtx, ql string, arg ...interface{}) (rs []Recordset, index int, err error) { + l, err := Compile(ql) + if err != nil { + return nil, -1, err + } + + return db.Execute(ctx, l, arg...) +} + +// Compile parses the ql statements from src and returns a compiled list for +// DB.Execute or an error if any. +// +// Compile is safe for concurrent use by multiple goroutines. +func Compile(src string) (List, error) { + l := newLexer(src) + if yyParse(l) != 0 { + return List{}, l.errs[0] + } + + return List{l.list, l.params}, nil +} + +// MustCompile is like Compile but panics if the ql statements in src cannot be +// compiled. It simplifies safe initialization of global variables holding +// compiled statement lists for DB.Execute. +// +// MustCompile is safe for concurrent use by multiple goroutines. +func MustCompile(src string) List { + list, err := Compile(src) + if err != nil { + panic("ql: Compile(" + strconv.Quote(src) + "): " + err.Error()) // panic ok here + } + + return list +} + +// Execute executes statements in a list while substituting QL paramaters from +// arg. +// +// The resulting []Recordset corresponds to the SELECT FROM statements in the +// list. +// +// If err != nil then index is the zero based index of the failed QL statement. +// Empty statements do not count. +// +// The FSM STT describing the relations between DB states, statements and the +// ctx parameter. +// +// +-----------+---------------------+------------------+------------------+------------------+ +// |\ Event | | | | | +// | \-------\ | BEGIN | | | Other | +// | State \| TRANSACTION | COMMIT | ROLLBACK | statement | +// +-----------+---------------------+------------------+------------------+------------------+ +// | RD | if PC == nil | return error | return error | DB.RLock | +// | | return error | | | Execute(1) | +// | CC == nil | | | | DB.RUnlock | +// | TNL == 0 | DB.Lock | | | | +// | | CC = PC | | | | +// | | TNL++ | | | | +// | | DB.BeginTransaction | | | | +// | | State = WR | | | | +// +-----------+---------------------+------------------+------------------+------------------+ +// | WR | if PC == nil | if PC != CC | if PC != CC | if PC == nil | +// | | return error | return error | return error | DB.Rlock | +// | CC != nil | | | | Execute(1) | +// | TNL != 0 | if PC != CC | DB.Commit | DB.Rollback | RUnlock | +// | | DB.Lock | TNL-- | TNL-- | else if PC != CC | +// | | CC = PC | if TNL == 0 | if TNL == 0 | return error | +// | | | CC = nil | CC = nil | else | +// | | TNL++ | State = RD | State = RD | Execute(2) | +// | | DB.BeginTransaction | DB.Unlock | DB.Unlock | | +// +-----------+---------------------+------------------+------------------+------------------+ +// CC: Curent transaction context +// PC: Passed transaction context +// TNL: Transaction nesting level +// +// Lock, Unlock, RLock, RUnlock semantics above are the same as in +// sync.RWMutex. +// +// (1): Statement list is executed outside of a transaction. Attempts to update +// the DB will fail, the execution context is read-only. Other statements with +// read only context will execute concurrently. If any statement fails, the +// execution of the statement list is aborted. +// +// Note that the RLock/RUnlock surrounds every single "other" statement when it +// is executed outside of a transaction. If read consistency is required by a +// list of more than one statement then an explicit BEGIN TRANSACTION / COMMIT +// or ROLLBACK wrapper must be provided. Otherwise the state of the DB may +// change in between executing any two out-of-transaction statements. +// +// (2): Statement list is executed inside an isolated transaction. Execution of +// statements can update the DB, the execution context is read-write. If any +// statement fails, the execution of the statement list is aborted and the DB +// is automatically rolled back to the TNL which was active before the start of +// execution of the statement list. +// +// Execute is safe for concurrent use by multiple goroutines, but one must +// consider the blocking issues as discussed above. +// +// ACID +// +// Atomicity: Transactions are atomic. Transactions can be nested. Commit or +// rollbacks work on the current transaction level. Transactions are made +// persistent only on the top level commit. Reads made from within an open +// transaction are dirty reads. +// +// Consistency: Transactions bring the DB from one structurally consistent +// state to other structurally consistent state. +// +// Isolation: Transactions are isolated. Isolation is implemented by +// serialization. +// +// Durability: Transactions are durable. A two phase commit protocol and a +// write ahead log is used. Database is recovered after a crash from the write +// ahead log automatically on open. +func (db *DB) Execute(ctx *TCtx, l List, arg ...interface{}) (rs []Recordset, index int, err error) { + // Sanitize args + for i, v := range arg { + switch x := v.(type) { + case nil, bool, complex64, complex128, float32, float64, string, + int8, int16, int32, int64, int, + uint8, uint16, uint32, uint64, uint, + *big.Int, *big.Rat, []byte, time.Duration, time.Time: + case big.Int: + arg[i] = &x + case big.Rat: + arg[i] = &x + default: + return nil, 0, fmt.Errorf("cannot use arg[%d] (type %T):unsupported type", i, v) + } + } + + tnl0 := -1 + if ctx != nil { + ctx.LastInsertID, ctx.RowsAffected = 0, 0 + } + + var s stmt + for index, s = range l.l { + r, err := db.run1(ctx, &tnl0, s, arg...) + if err != nil { + for tnl0 >= 0 && db.tnl > tnl0 { + if _, e2 := db.run1(ctx, &tnl0, rollbackStmt{}); e2 != nil { + err = e2 + } + } + return rs, index, err + } + + if r != nil { + rs = append(rs, r) + } + } + return +} + +func (db *DB) run1(pc *TCtx, tnl0 *int, s stmt, arg ...interface{}) (rs Recordset, err error) { + //dbg("%v", s) + db.mu.Lock() + switch db.rw { + case false: + switch s.(type) { + case beginTransactionStmt: + defer db.mu.Unlock() + if pc == nil { + return nil, errors.New("BEGIN TRANSACTION: cannot start a transaction in nil TransactionCtx") + } + + if err = db.store.BeginTransaction(); err != nil { + return + } + + db.beginTransaction() + db.rwmu.Lock() + db.cc = pc + *tnl0 = db.tnl // 0 + db.tnl++ + db.rw = true + return + case commitStmt: + defer db.mu.Unlock() + return nil, errCommitNotInTransaction + case rollbackStmt: + defer db.mu.Unlock() + return nil, errRollbackNotInTransaction + default: + if s.isUpdating() { + db.mu.Unlock() + return nil, fmt.Errorf("attempt to update the DB outside of a transaction") + } + + db.rwmu.RLock() // can safely grab before Unlock + db.mu.Unlock() + defer db.rwmu.RUnlock() + return s.exec(&execCtx{db, arg}) // R/O tctx + } + default: // case true: + switch s.(type) { + case beginTransactionStmt: + defer db.mu.Unlock() + + if pc == nil { + return nil, errBeginTransNoCtx + } + + if pc != db.cc { + for db.rw == true { + db.mu.Unlock() // Transaction isolation + db.mu.Lock() + } + + db.rw = true + db.rwmu.Lock() + *tnl0 = db.tnl // 0 + } + + if err = db.store.BeginTransaction(); err != nil { + return + } + + db.beginTransaction() + db.cc = pc + db.tnl++ + return + case commitStmt: + defer db.mu.Unlock() + if pc != db.cc { + return nil, fmt.Errorf("invalid passed transaction context") + } + + db.commit() + err = db.store.Commit() + db.tnl-- + if db.tnl != 0 { + return + } + + db.cc = nil + db.rw = false + db.rwmu.Unlock() + return + case rollbackStmt: + defer db.mu.Unlock() + defer func() { pc.LastInsertID = db.root.lastInsertID }() + if pc != db.cc { + return nil, fmt.Errorf("invalid passed transaction context") + } + + db.rollback() + err = db.store.Rollback() + db.tnl-- + if db.tnl != 0 { + return + } + + db.cc = nil + db.rw = false + db.rwmu.Unlock() + return + default: + if pc == nil { + if s.isUpdating() { + db.mu.Unlock() + return nil, fmt.Errorf("attempt to update the DB outside of a transaction") + } + + db.mu.Unlock() // must Unlock before RLock + db.rwmu.RLock() + defer db.rwmu.RUnlock() + return s.exec(&execCtx{db, arg}) + } + + defer db.mu.Unlock() + defer func() { pc.LastInsertID = db.root.lastInsertID }() + if pc != db.cc { + return nil, fmt.Errorf("invalid passed transaction context") + } + + if !s.isUpdating() { + return s.exec(&execCtx{db, arg}) + } + + if rs, err = s.exec(&execCtx{db, arg}); err != nil { + return + } + + return rs, nil + } + } +} + +// Flush ends the transaction collecting window, if applicable. IOW, if the DB +// is dirty, it schedules a 2PC (WAL + DB file) commit on the next outer most +// DB.Commit or performs it synchronously if there's currently no open +// transaction. +// +// The collecting window is an implementation detail and future versions of +// Flush may become a no operation while keeping the operation semantics. +func (db *DB) Flush() (err error) { + return nil +} + +// Close will close the DB. Successful Close is idempotent. +func (db *DB) Close() error { + db.mu.Lock() + defer db.mu.Unlock() + if db.store == nil { + return nil + } + + if db.tnl != 0 { + return fmt.Errorf("cannot close DB while open transaction exist") + } + + err := db.store.Close() + db.root, db.store = nil, nil + return err +} + +func (db *DB) do(r recordset, names int, f func(data []interface{}) (more bool, err error)) (err error) { + db.mu.Lock() + switch db.rw { + case false: + db.rwmu.RLock() // can safely grab before Unlock + db.mu.Unlock() + defer db.rwmu.RUnlock() + default: // case true: + if r.tx == nil { + db.mu.Unlock() // must Unlock before RLock + db.rwmu.RLock() + defer db.rwmu.RUnlock() + break + } + + defer db.mu.Unlock() + if r.tx != db.cc { + return fmt.Errorf("invalid passed transaction context") + } + } + + ok := false + return r.do(r.ctx, names == onlyNames, func(id interface{}, data []interface{}) (more bool, err error) { + if ok { + if err = expand(data); err != nil { + return + } + + return f(data) + } + + ok = true + done := false + switch names { + case noNames: + return true, nil + case onlyNames: + done = true + fallthrough + default: // returnNames + flds := data[0].([]*fld) + a := make([]interface{}, len(flds)) + for i, v := range flds { + a[i] = v.name + } + more, err := f(a) + return more && !done, err + + } + }) +} + +func (db *DB) beginTransaction() { //TODO Rewrite, must use much smaller undo info! + oldRoot := db.root + newRoot := &root{} + *newRoot = *oldRoot + newRoot.parent = oldRoot + a := make([]*table, 0, len(oldRoot.tables)) + newRoot.tables = make(map[string]*table, len(oldRoot.tables)) + for k, v := range oldRoot.tables { + c := v.clone() + a = append(a, c) + newRoot.tables[k] = c + } + for i := 0; i < len(a)-1; i++ { + l, p := a[i], a[i+1] + l.tnext = p + p.tprev = l + } + if len(a) != 0 { + newRoot.thead = a[0] + } + db.root = newRoot +} + +func (db *DB) rollback() { + db.root = db.root.parent +} + +func (db *DB) commit() { + db.root.parent = db.root.parent.parent +} + +// Type represents a QL type (bigint, int, string, ...) +type Type int + +// Values of ColumnInfo.Type. +const ( + BigInt Type = qBigInt + BigRat = qBigRat + Blob = qBlob + Bool = qBool + Complex128 = qComplex128 + Complex64 = qComplex64 + Duration = qDuration + Float32 = qFloat32 + Float64 = qFloat64 + Int16 = qInt16 + Int32 = qInt32 + Int64 = qInt64 + Int8 = qInt8 + String = qString + Time = qTime + Uint16 = qUint16 + Uint32 = qUint32 + Uint64 = qUint64 + Uint8 = qUint8 +) + +// String implements fmt.Stringer. +func (t Type) String() string { + return typeStr(int(t)) +} + +// ColumnInfo provides meta data describing a table column. +type ColumnInfo struct { + Name string // Column name. + Type Type // Column type (BigInt, BigRat, ...). +} + +// TableInfo provides meta data describing a DB table. +type TableInfo struct { + // Table name. + Name string + + // Table schema. Columns are listed in the order in which they appear + // in the schema. + Columns []ColumnInfo +} + +// IndexInfo provides meta data describing a DB index. It corresponds to the +// statement +// +// CREATE INDEX Name ON Table (Column); +type IndexInfo struct { + Name string // Index name + Table string // Table name. + Column string // Column name. + Unique bool // Wheter the index is unique. +} + +// DbInfo provides meta data describing a DB. +type DbInfo struct { + Name string // DB name. + Tables []TableInfo // Tables in the DB. + Indices []IndexInfo // Indices in the DB. +} + +func (db *DB) info() (r *DbInfo, err error) { + r = &DbInfo{Name: db.Name()} + for nm, t := range db.root.tables { + ti := TableInfo{Name: nm} + for _, c := range t.cols { + ti.Columns = append(ti.Columns, ColumnInfo{Name: c.name, Type: Type(c.typ)}) + } + r.Tables = append(r.Tables, ti) + for i, x := range t.indices { + if x == nil { + continue + } + + var cn string + switch { + case i == 0: + cn = "id()" + default: + cn = t.cols0[i-1].name + } + r.Indices = append(r.Indices, IndexInfo{x.name, nm, cn, x.unique}) + } + } + return +} + +// Info provides meta data describing a DB or an error if any. It locks the DB +// to obtain the result. +func (db *DB) Info() (r *DbInfo, err error) { + db.mu.Lock() + defer db.mu.Unlock() + return db.info() +} diff --git a/Godeps/_workspace/src/github.com/cznic/ql/ql.y b/Godeps/_workspace/src/github.com/cznic/ql/ql.y new file mode 100644 index 0000000..29c5071 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/ql/ql.y @@ -0,0 +1,1573 @@ +%{ + +//TODO Put your favorite license here + +// yacc source generated by ebnf2y[1] +// at 2015-02-16 13:21:59.814850051 +0100 CET +// +// $ ebnf2y -o ql.y -oe ql.ebnf -start StatementList -pkg ql -p _ +// +// CAUTION: If this file is a Go source file (*.go), it was generated +// automatically by '$ go tool yacc' from a *.y file - DO NOT EDIT in that case! +// +// [1]: http://github.com/cznic/ebnf2y + +package ql //TODO real package name + +//TODO required only be the demo _dump function +import ( + "bytes" + "fmt" + "strings" + + "github.com/cznic/strutil" +) + +%} + +%union { + item interface{} //TODO insert real field(s) +} + +%token _ANDAND +%token _ANDNOT +%token _EQ +%token _FLOAT_LIT +%token _GE +%token _IDENTIFIER +%token _IMAGINARY_LIT +%token _INT_LIT +%token _LE +%token _LSH +%token _NEQ +%token _OROR +%token _QL_PARAMETER +%token _RSH +%token _RUNE_LIT +%token _STRING_LIT + +%type /*TODO real type(s), if/where applicable */ + _ANDAND + _ANDNOT + _EQ + _FLOAT_LIT + _GE + _IDENTIFIER + _IMAGINARY_LIT + _INT_LIT + _LE + _LSH + _NEQ + _OROR + _QL_PARAMETER + _RSH + _RUNE_LIT + _STRING_LIT + +%token _ADD +%token _ALTER +%token _AND +%token _AS +%token _ASC +%token _BEGIN +%token _BETWEEN +%token _BIGINT +%token _BIGRAT +%token _BLOB +%token _BOOL +%token _BY +%token _BYTE +%token _COLUMN +%token _COMMIT +%token _COMPLEX128 +%token _COMPLEX64 +%token _CREATE +%token _DELETE +%token _DESC +%token _DISTINCT +%token _DROP +%token _DURATION +%token _EXISTS +%token _FALSE +%token _FLOAT +%token _FLOAT32 +%token _FLOAT64 +%token _FROM +%token _GROUPBY +%token _ID +%token _IF +%token _IN +%token _INDEX +%token _INSERT +%token _INT +%token _INT16 +%token _INT32 +%token _INT64 +%token _INT8 +%token _INTO +%token _IS +%token _LIKE +%token _LIMIT +%token _NOT +%token _NULL +%token _OFFSET +%token _ON +%token _OR +%token _ORDER +%token _ROLLBACK +%token _RUNE +%token _SELECT +%token _SET +%token _STRING +%token _TABLE +%token _TIME +%token _TRANSACTION +%token _TRUE +%token _TRUNCATE +%token _UINT +%token _UINT16 +%token _UINT32 +%token _UINT64 +%token _UINT8 +%token _UNIQUE +%token _UPDATE +%token _VALUES +%token _WHERE + +%type /*TODO real type(s), if/where applicable */ + AlterTableStmt + AlterTableStmt1 + Assignment + AssignmentList + AssignmentList1 + AssignmentList2 + BeginTransactionStmt + Call + Call1 + ColumnDef + ColumnName + ColumnNameList + ColumnNameList1 + ColumnNameList2 + CommitStmt + Conversion + CreateIndexStmt + CreateIndexStmt1 + CreateIndexStmt2 + CreateIndexStmt3 + CreateTableStmt + CreateTableStmt1 + CreateTableStmt2 + CreateTableStmt3 + DeleteFromStmt + DeleteFromStmt1 + DropIndexStmt + DropIndexStmt1 + DropTableStmt + DropTableStmt1 + EmptyStmt + Expression + Expression1 + Expression11 + ExpressionList + ExpressionList1 + ExpressionList2 + Factor + Factor1 + Factor11 + Factor2 + Field + Field1 + FieldList + FieldList1 + FieldList2 + GroupByClause + Index + IndexName + InsertIntoStmt + InsertIntoStmt1 + InsertIntoStmt2 + Limit + Literal + Offset + Operand + OrderBy + OrderBy1 + OrderBy11 + Predicate + Predicate1 + Predicate11 + Predicate12 + Predicate13 + PrimaryExpression + PrimaryFactor + PrimaryFactor1 + PrimaryFactor11 + PrimaryTerm + PrimaryTerm1 + PrimaryTerm11 + QualifiedIdent + QualifiedIdent1 + RecordSet + RecordSet1 + RecordSet11 + RecordSet2 + RecordSetList + RecordSetList1 + RecordSetList2 + RollbackStmt + SelectStmt + SelectStmt1 + SelectStmt2 + SelectStmt3 + SelectStmt4 + SelectStmt5 + SelectStmt6 + SelectStmt7 + Slice + Slice1 + Slice2 + Start + Statement + StatementList + StatementList1 + TableName + Term + Term1 + Term11 + TruncateTableStmt + Type + UnaryExpr + UnaryExpr1 + UnaryExpr11 + UpdateStmt + UpdateStmt1 + UpdateStmt2 + Values + Values1 + Values2 + WhereClause + +/*TODO %left, %right, ... declarations */ + +%start Start + +%% + +AlterTableStmt: + _ALTER _TABLE TableName AlterTableStmt1 + { + $$ = []AlterTableStmt{"ALTER", "TABLE", $3, $4} //TODO 1 + } + +AlterTableStmt1: + _ADD ColumnDef + { + $$ = []AlterTableStmt1{"ADD", $2} //TODO 2 + } +| _DROP _COLUMN ColumnName + { + $$ = []AlterTableStmt1{"DROP", "COLUMN", $3} //TODO 3 + } + +Assignment: + ColumnName '=' Expression + { + $$ = []Assignment{$1, "=", $3} //TODO 4 + } + +AssignmentList: + Assignment AssignmentList1 AssignmentList2 + { + $$ = []AssignmentList{$1, $2, $3} //TODO 5 + } + +AssignmentList1: + /* EMPTY */ + { + $$ = []AssignmentList1(nil) //TODO 6 + } +| AssignmentList1 ',' Assignment + { + $$ = append($1.([]AssignmentList1), ",", $3) //TODO 7 + } + +AssignmentList2: + /* EMPTY */ + { + $$ = nil //TODO 8 + } +| ',' + { + $$ = "," //TODO 9 + } + +BeginTransactionStmt: + _BEGIN _TRANSACTION + { + $$ = []BeginTransactionStmt{"BEGIN", "TRANSACTION"} //TODO 10 + } + +Call: + '(' Call1 ')' + { + $$ = []Call{"(", $2, ")"} //TODO 11 + } + +Call1: + /* EMPTY */ + { + $$ = nil //TODO 12 + } +| ExpressionList + { + $$ = $1 //TODO 13 + } + +ColumnDef: + ColumnName Type + { + $$ = []ColumnDef{$1, $2} //TODO 14 + } + +ColumnName: + _IDENTIFIER + { + $$ = $1 //TODO 15 + } + +ColumnNameList: + ColumnName ColumnNameList1 ColumnNameList2 + { + $$ = []ColumnNameList{$1, $2, $3} //TODO 16 + } + +ColumnNameList1: + /* EMPTY */ + { + $$ = []ColumnNameList1(nil) //TODO 17 + } +| ColumnNameList1 ',' ColumnName + { + $$ = append($1.([]ColumnNameList1), ",", $3) //TODO 18 + } + +ColumnNameList2: + /* EMPTY */ + { + $$ = nil //TODO 19 + } +| ',' + { + $$ = "," //TODO 20 + } + +CommitStmt: + _COMMIT + { + $$ = "COMMIT" //TODO 21 + } + +Conversion: + Type '(' Expression ')' + { + $$ = []Conversion{$1, "(", $3, ")"} //TODO 22 + } + +CreateIndexStmt: + _CREATE CreateIndexStmt1 _INDEX CreateIndexStmt2 IndexName _ON TableName '(' CreateIndexStmt3 ')' + { + $$ = []CreateIndexStmt{"CREATE", $2, "INDEX", $4, $5, "ON", $7, "(", $9, ")"} //TODO 23 + } + +CreateIndexStmt1: + /* EMPTY */ + { + $$ = nil //TODO 24 + } +| _UNIQUE + { + $$ = "UNIQUE" //TODO 25 + } + +CreateIndexStmt2: + /* EMPTY */ + { + $$ = nil //TODO 26 + } +| _IF _NOT _EXISTS + { + $$ = []CreateIndexStmt2{"IF", "NOT", "EXISTS"} //TODO 27 + } + +CreateIndexStmt3: + ColumnName + { + $$ = $1 //TODO 28 + } +| _ID Call + { + $$ = []CreateIndexStmt3{"id", $2} //TODO 29 + } + +CreateTableStmt: + _CREATE _TABLE CreateTableStmt1 TableName '(' ColumnDef CreateTableStmt2 CreateTableStmt3 ')' + { + $$ = []CreateTableStmt{"CREATE", "TABLE", $3, $4, "(", $6, $7, $8, ")"} //TODO 30 + } + +CreateTableStmt1: + /* EMPTY */ + { + $$ = nil //TODO 31 + } +| _IF _NOT _EXISTS + { + $$ = []CreateTableStmt1{"IF", "NOT", "EXISTS"} //TODO 32 + } + +CreateTableStmt2: + /* EMPTY */ + { + $$ = []CreateTableStmt2(nil) //TODO 33 + } +| CreateTableStmt2 ',' ColumnDef + { + $$ = append($1.([]CreateTableStmt2), ",", $3) //TODO 34 + } + +CreateTableStmt3: + /* EMPTY */ + { + $$ = nil //TODO 35 + } +| ',' + { + $$ = "," //TODO 36 + } + +DeleteFromStmt: + _DELETE _FROM TableName DeleteFromStmt1 + { + $$ = []DeleteFromStmt{"DELETE", "FROM", $3, $4} //TODO 37 + } + +DeleteFromStmt1: + /* EMPTY */ + { + $$ = nil //TODO 38 + } +| WhereClause + { + $$ = $1 //TODO 39 + } + +DropIndexStmt: + _DROP _INDEX DropIndexStmt1 IndexName + { + $$ = []DropIndexStmt{"DROP", "INDEX", $3, $4} //TODO 40 + } + +DropIndexStmt1: + /* EMPTY */ + { + $$ = nil //TODO 41 + } +| _IF _EXISTS + { + $$ = []DropIndexStmt1{"IF", "EXISTS"} //TODO 42 + } + +DropTableStmt: + _DROP _TABLE DropTableStmt1 TableName + { + $$ = []DropTableStmt{"DROP", "TABLE", $3, $4} //TODO 43 + } + +DropTableStmt1: + /* EMPTY */ + { + $$ = nil //TODO 44 + } +| _IF _EXISTS + { + $$ = []DropTableStmt1{"IF", "EXISTS"} //TODO 45 + } + +EmptyStmt: + /* EMPTY */ + { + $$ = nil //TODO 46 + } + +Expression: + Term Expression1 + { + $$ = []Expression{$1, $2} //TODO 47 + } + +Expression1: + /* EMPTY */ + { + $$ = []Expression1(nil) //TODO 48 + } +| Expression1 Expression11 Term + { + $$ = append($1.([]Expression1), $2, $3) //TODO 49 + } + +Expression11: + _OROR + { + $$ = $1 //TODO 50 + } +| _OR + { + $$ = "OR" //TODO 51 + } + +ExpressionList: + Expression ExpressionList1 ExpressionList2 + { + $$ = []ExpressionList{$1, $2, $3} //TODO 52 + } + +ExpressionList1: + /* EMPTY */ + { + $$ = []ExpressionList1(nil) //TODO 53 + } +| ExpressionList1 ',' Expression + { + $$ = append($1.([]ExpressionList1), ",", $3) //TODO 54 + } + +ExpressionList2: + /* EMPTY */ + { + $$ = nil //TODO 55 + } +| ',' + { + $$ = "," //TODO 56 + } + +Factor: + PrimaryFactor Factor1 Factor2 + { + $$ = []Factor{$1, $2, $3} //TODO 57 + } + +Factor1: + /* EMPTY */ + { + $$ = []Factor1(nil) //TODO 58 + } +| Factor1 Factor11 PrimaryFactor + { + $$ = append($1.([]Factor1), $2, $3) //TODO 59 + } + +Factor11: + _GE + { + $$ = $1 //TODO 60 + } +| '>' + { + $$ = ">" //TODO 61 + } +| _LE + { + $$ = $1 //TODO 62 + } +| '<' + { + $$ = "<" //TODO 63 + } +| _NEQ + { + $$ = $1 //TODO 64 + } +| _EQ + { + $$ = $1 //TODO 65 + } +| _LIKE + { + $$ = "LIKE" //TODO 66 + } + +Factor2: + /* EMPTY */ + { + $$ = nil //TODO 67 + } +| Predicate + { + $$ = $1 //TODO 68 + } + +Field: + Expression Field1 + { + $$ = []Field{$1, $2} //TODO 69 + } + +Field1: + /* EMPTY */ + { + $$ = nil //TODO 70 + } +| _AS _IDENTIFIER + { + $$ = []Field1{"AS", $2} //TODO 71 + } + +FieldList: + Field FieldList1 FieldList2 + { + $$ = []FieldList{$1, $2, $3} //TODO 72 + } + +FieldList1: + /* EMPTY */ + { + $$ = []FieldList1(nil) //TODO 73 + } +| FieldList1 ',' Field + { + $$ = append($1.([]FieldList1), ",", $3) //TODO 74 + } + +FieldList2: + /* EMPTY */ + { + $$ = nil //TODO 75 + } +| ',' + { + $$ = "," //TODO 76 + } + +GroupByClause: + _GROUPBY ColumnNameList + { + $$ = []GroupByClause{"GROUP BY", $2} //TODO 77 + } + +Index: + '[' Expression ']' + { + $$ = []Index{"[", $2, "]"} //TODO 78 + } + +IndexName: + _IDENTIFIER + { + $$ = $1 //TODO 79 + } + +InsertIntoStmt: + _INSERT _INTO TableName InsertIntoStmt1 InsertIntoStmt2 + { + $$ = []InsertIntoStmt{"INSERT", "INTO", $3, $4, $5} //TODO 80 + } + +InsertIntoStmt1: + /* EMPTY */ + { + $$ = nil //TODO 81 + } +| '(' ColumnNameList ')' + { + $$ = []InsertIntoStmt1{"(", $2, ")"} //TODO 82 + } + +InsertIntoStmt2: + Values + { + $$ = $1 //TODO 83 + } +| SelectStmt + { + $$ = $1 //TODO 84 + } + +Limit: + _LIMIT Expression + { + $$ = []Limit{"Limit", $2} //TODO 85 + } + +Literal: + _FALSE + { + $$ = "FALSE" //TODO 86 + } +| _NULL + { + $$ = "NULL" //TODO 87 + } +| _TRUE + { + $$ = "TRUE" //TODO 88 + } +| _FLOAT_LIT + { + $$ = $1 //TODO 89 + } +| _IMAGINARY_LIT + { + $$ = $1 //TODO 90 + } +| _INT_LIT + { + $$ = $1 //TODO 91 + } +| _RUNE_LIT + { + $$ = $1 //TODO 92 + } +| _STRING_LIT + { + $$ = $1 //TODO 93 + } +| _QL_PARAMETER + { + $$ = $1 //TODO 94 + } + +Offset: + _OFFSET Expression + { + $$ = []Offset{"OFFSET", $2} //TODO 95 + } + +Operand: + Literal + { + $$ = $1 //TODO 96 + } +| QualifiedIdent + { + $$ = $1 //TODO 97 + } +| '(' Expression ')' + { + $$ = []Operand{"(", $2, ")"} //TODO 98 + } + +OrderBy: + _ORDER _BY ExpressionList OrderBy1 + { + $$ = []OrderBy{"ORDER", "BY", $3, $4} //TODO 99 + } + +OrderBy1: + /* EMPTY */ + { + $$ = nil //TODO 100 + } +| OrderBy11 + { + $$ = $1 //TODO 101 + } + +OrderBy11: + _ASC + { + $$ = "ASC" //TODO 102 + } +| _DESC + { + $$ = "DESC" //TODO 103 + } + +Predicate: + Predicate1 + { + $$ = $1 //TODO 104 + } + +Predicate1: + Predicate11 Predicate12 + { + $$ = []Predicate1{$1, $2} //TODO 105 + } +| _IS Predicate13 _NULL + { + $$ = []Predicate1{"IS", $2, "NULL"} //TODO 106 + } + +Predicate11: + /* EMPTY */ + { + $$ = nil //TODO 107 + } +| _NOT + { + $$ = "NOT" //TODO 108 + } + +Predicate12: + _IN '(' ExpressionList ')' + { + $$ = []Predicate12{"IN", "(", $3, ")"} //TODO 109 + } +| _IN '(' SelectStmt ')' + { + $$ = []Predicate12{"IN", "(", $3, ")"} //TODO 110 + } +| _BETWEEN PrimaryFactor _AND PrimaryFactor + { + $$ = []Predicate12{"BETWEEN", $2, "AND", $4} //TODO 111 + } + +Predicate13: + /* EMPTY */ + { + $$ = nil //TODO 112 + } +| _NOT + { + $$ = "NOT" //TODO 113 + } + +PrimaryExpression: + Operand + { + $$ = $1 //TODO 114 + } +| Conversion + { + $$ = $1 //TODO 115 + } +| PrimaryExpression Index + { + $$ = []PrimaryExpression{$1, $2} //TODO 116 + } +| PrimaryExpression Slice + { + $$ = []PrimaryExpression{$1, $2} //TODO 117 + } +| PrimaryExpression Call + { + $$ = []PrimaryExpression{$1, $2} //TODO 118 + } + +PrimaryFactor: + PrimaryTerm PrimaryFactor1 + { + $$ = []PrimaryFactor{$1, $2} //TODO 119 + } + +PrimaryFactor1: + /* EMPTY */ + { + $$ = []PrimaryFactor1(nil) //TODO 120 + } +| PrimaryFactor1 PrimaryFactor11 PrimaryTerm + { + $$ = append($1.([]PrimaryFactor1), $2, $3) //TODO 121 + } + +PrimaryFactor11: + '^' + { + $$ = "^" //TODO 122 + } +| '|' + { + $$ = "|" //TODO 123 + } +| '-' + { + $$ = "-" //TODO 124 + } +| '+' + { + $$ = "+" //TODO 125 + } + +PrimaryTerm: + UnaryExpr PrimaryTerm1 + { + $$ = []PrimaryTerm{$1, $2} //TODO 126 + } + +PrimaryTerm1: + /* EMPTY */ + { + $$ = []PrimaryTerm1(nil) //TODO 127 + } +| PrimaryTerm1 PrimaryTerm11 UnaryExpr + { + $$ = append($1.([]PrimaryTerm1), $2, $3) //TODO 128 + } + +PrimaryTerm11: + _ANDNOT + { + $$ = $1 //TODO 129 + } +| '&' + { + $$ = "&" //TODO 130 + } +| _LSH + { + $$ = $1 //TODO 131 + } +| _RSH + { + $$ = $1 //TODO 132 + } +| '%' + { + $$ = "%" //TODO 133 + } +| '/' + { + $$ = "/" //TODO 134 + } +| '*' + { + $$ = "*" //TODO 135 + } + +QualifiedIdent: + _IDENTIFIER QualifiedIdent1 + { + $$ = []QualifiedIdent{$1, $2} //TODO 136 + } + +QualifiedIdent1: + /* EMPTY */ + { + $$ = nil //TODO 137 + } +| '.' _IDENTIFIER + { + $$ = []QualifiedIdent1{".", $2} //TODO 138 + } + +RecordSet: + RecordSet1 RecordSet2 + { + $$ = []RecordSet{$1, $2} //TODO 139 + } + +RecordSet1: + TableName + { + $$ = $1 //TODO 140 + } +| '(' SelectStmt RecordSet11 ')' + { + $$ = []RecordSet1{"(", $2, $3, ")"} //TODO 141 + } + +RecordSet11: + /* EMPTY */ + { + $$ = nil //TODO 142 + } +| ';' + { + $$ = ";" //TODO 143 + } + +RecordSet2: + /* EMPTY */ + { + $$ = nil //TODO 144 + } +| _AS _IDENTIFIER + { + $$ = []RecordSet2{"AS", $2} //TODO 145 + } + +RecordSetList: + RecordSet RecordSetList1 RecordSetList2 + { + $$ = []RecordSetList{$1, $2, $3} //TODO 146 + } + +RecordSetList1: + /* EMPTY */ + { + $$ = []RecordSetList1(nil) //TODO 147 + } +| RecordSetList1 ',' RecordSet + { + $$ = append($1.([]RecordSetList1), ",", $3) //TODO 148 + } + +RecordSetList2: + /* EMPTY */ + { + $$ = nil //TODO 149 + } +| ',' + { + $$ = "," //TODO 150 + } + +RollbackStmt: + _ROLLBACK + { + $$ = "ROLLBACK" //TODO 151 + } + +SelectStmt: + _SELECT SelectStmt1 SelectStmt2 _FROM RecordSetList SelectStmt3 SelectStmt4 SelectStmt5 SelectStmt6 SelectStmt7 + { + $$ = []SelectStmt{"SELECT", $2, $3, "FROM", $5, $6, $7, $8, $9, $10} //TODO 152 + } + +SelectStmt1: + /* EMPTY */ + { + $$ = nil //TODO 153 + } +| _DISTINCT + { + $$ = "DISTINCT" //TODO 154 + } + +SelectStmt2: + '*' + { + $$ = "*" //TODO 155 + } +| FieldList + { + $$ = $1 //TODO 156 + } + +SelectStmt3: + /* EMPTY */ + { + $$ = nil //TODO 157 + } +| WhereClause + { + $$ = $1 //TODO 158 + } + +SelectStmt4: + /* EMPTY */ + { + $$ = nil //TODO 159 + } +| GroupByClause + { + $$ = $1 //TODO 160 + } + +SelectStmt5: + /* EMPTY */ + { + $$ = nil //TODO 161 + } +| OrderBy + { + $$ = $1 //TODO 162 + } + +SelectStmt6: + /* EMPTY */ + { + $$ = nil //TODO 163 + } +| Limit + { + $$ = $1 //TODO 164 + } + +SelectStmt7: + /* EMPTY */ + { + $$ = nil //TODO 165 + } +| Offset + { + $$ = $1 //TODO 166 + } + +Slice: + '[' Slice1 ':' Slice2 ']' + { + $$ = []Slice{"[", $2, ":", $4, "]"} //TODO 167 + } + +Slice1: + /* EMPTY */ + { + $$ = nil //TODO 168 + } +| Expression + { + $$ = $1 //TODO 169 + } + +Slice2: + /* EMPTY */ + { + $$ = nil //TODO 170 + } +| Expression + { + $$ = $1 //TODO 171 + } + +Start: + StatementList + { + _parserResult = $1 //TODO 172 + } + +Statement: + EmptyStmt + { + $$ = $1 //TODO 173 + } +| AlterTableStmt + { + $$ = $1 //TODO 174 + } +| BeginTransactionStmt + { + $$ = $1 //TODO 175 + } +| CommitStmt + { + $$ = $1 //TODO 176 + } +| CreateIndexStmt + { + $$ = $1 //TODO 177 + } +| CreateTableStmt + { + $$ = $1 //TODO 178 + } +| DeleteFromStmt + { + $$ = $1 //TODO 179 + } +| DropIndexStmt + { + $$ = $1 //TODO 180 + } +| DropTableStmt + { + $$ = $1 //TODO 181 + } +| InsertIntoStmt + { + $$ = $1 //TODO 182 + } +| RollbackStmt + { + $$ = $1 //TODO 183 + } +| SelectStmt + { + $$ = $1 //TODO 184 + } +| TruncateTableStmt + { + $$ = $1 //TODO 185 + } +| UpdateStmt + { + $$ = $1 //TODO 186 + } + +StatementList: + Statement StatementList1 + { + $$ = []StatementList{$1, $2} //TODO 187 + } + +StatementList1: + /* EMPTY */ + { + $$ = []StatementList1(nil) //TODO 188 + } +| StatementList1 ';' Statement + { + $$ = append($1.([]StatementList1), ";", $3) //TODO 189 + } + +TableName: + _IDENTIFIER + { + $$ = $1 //TODO 190 + } + +Term: + Factor Term1 + { + $$ = []Term{$1, $2} //TODO 191 + } + +Term1: + /* EMPTY */ + { + $$ = []Term1(nil) //TODO 192 + } +| Term1 Term11 Factor + { + $$ = append($1.([]Term1), $2, $3) //TODO 193 + } + +Term11: + _ANDAND + { + $$ = $1 //TODO 194 + } +| _AND + { + $$ = "AND" //TODO 195 + } + +TruncateTableStmt: + _TRUNCATE _TABLE TableName + { + $$ = []TruncateTableStmt{"TRUNCATE", "TABLE", $3} //TODO 196 + } + +Type: + _BIGINT + { + $$ = "bigint" //TODO 197 + } +| _BIGRAT + { + $$ = "bigrat" //TODO 198 + } +| _BLOB + { + $$ = "blob" //TODO 199 + } +| _BOOL + { + $$ = "bool" //TODO 200 + } +| _BYTE + { + $$ = "byte" //TODO 201 + } +| _COMPLEX128 + { + $$ = "complex128" //TODO 202 + } +| _COMPLEX64 + { + $$ = "complex64" //TODO 203 + } +| _DURATION + { + $$ = "duration" //TODO 204 + } +| _FLOAT + { + $$ = "float" //TODO 205 + } +| _FLOAT32 + { + $$ = "float32" //TODO 206 + } +| _FLOAT64 + { + $$ = "float64" //TODO 207 + } +| _INT + { + $$ = "int" //TODO 208 + } +| _INT16 + { + $$ = "int16" //TODO 209 + } +| _INT32 + { + $$ = "int32" //TODO 210 + } +| _INT64 + { + $$ = "int64" //TODO 211 + } +| _INT8 + { + $$ = "int8" //TODO 212 + } +| _RUNE + { + $$ = "rune" //TODO 213 + } +| _STRING + { + $$ = "string" //TODO 214 + } +| _TIME + { + $$ = "time" //TODO 215 + } +| _UINT + { + $$ = "uint" //TODO 216 + } +| _UINT16 + { + $$ = "uint16" //TODO 217 + } +| _UINT32 + { + $$ = "uint32" //TODO 218 + } +| _UINT64 + { + $$ = "uint64" //TODO 219 + } +| _UINT8 + { + $$ = "uint8" //TODO 220 + } + +UnaryExpr: + UnaryExpr1 PrimaryExpression + { + $$ = []UnaryExpr{$1, $2} //TODO 221 + } + +UnaryExpr1: + /* EMPTY */ + { + $$ = nil //TODO 222 + } +| UnaryExpr11 + { + $$ = $1 //TODO 223 + } + +UnaryExpr11: + '^' + { + $$ = "^" //TODO 224 + } +| '!' + { + $$ = "!" //TODO 225 + } +| '-' + { + $$ = "-" //TODO 226 + } +| '+' + { + $$ = "+" //TODO 227 + } + +UpdateStmt: + _UPDATE TableName UpdateStmt1 AssignmentList UpdateStmt2 + { + $$ = []UpdateStmt{"UPDATE", $2, $3, $4, $5} //TODO 228 + } + +UpdateStmt1: + /* EMPTY */ + { + $$ = nil //TODO 229 + } +| _SET + { + $$ = "SET" //TODO 230 + } + +UpdateStmt2: + /* EMPTY */ + { + $$ = nil //TODO 231 + } +| WhereClause + { + $$ = $1 //TODO 232 + } + +Values: + _VALUES '(' ExpressionList ')' Values1 Values2 + { + $$ = []Values{"VALUES", "(", $3, ")", $5, $6} //TODO 233 + } + +Values1: + /* EMPTY */ + { + $$ = []Values1(nil) //TODO 234 + } +| Values1 ',' '(' ExpressionList ')' + { + $$ = append($1.([]Values1), ",", "(", $4, ")") //TODO 235 + } + +Values2: + /* EMPTY */ + { + $$ = nil //TODO 236 + } +| ',' + { + $$ = "," //TODO 237 + } + +WhereClause: + _WHERE Expression + { + $$ = []WhereClause{"WHERE", $2} //TODO 238 + } + +%% + +//TODO remove demo stuff below + +var _parserResult interface{} + +type ( + AlterTableStmt interface{} + AlterTableStmt1 interface{} + Assignment interface{} + AssignmentList interface{} + AssignmentList1 interface{} + AssignmentList2 interface{} + BeginTransactionStmt interface{} + Call interface{} + Call1 interface{} + ColumnDef interface{} + ColumnName interface{} + ColumnNameList interface{} + ColumnNameList1 interface{} + ColumnNameList2 interface{} + CommitStmt interface{} + Conversion interface{} + CreateIndexStmt interface{} + CreateIndexStmt1 interface{} + CreateIndexStmt2 interface{} + CreateIndexStmt3 interface{} + CreateTableStmt interface{} + CreateTableStmt1 interface{} + CreateTableStmt2 interface{} + CreateTableStmt3 interface{} + DeleteFromStmt interface{} + DeleteFromStmt1 interface{} + DropIndexStmt interface{} + DropIndexStmt1 interface{} + DropTableStmt interface{} + DropTableStmt1 interface{} + EmptyStmt interface{} + Expression interface{} + Expression1 interface{} + Expression11 interface{} + ExpressionList interface{} + ExpressionList1 interface{} + ExpressionList2 interface{} + Factor interface{} + Factor1 interface{} + Factor11 interface{} + Factor2 interface{} + Field interface{} + Field1 interface{} + FieldList interface{} + FieldList1 interface{} + FieldList2 interface{} + GroupByClause interface{} + Index interface{} + IndexName interface{} + InsertIntoStmt interface{} + InsertIntoStmt1 interface{} + InsertIntoStmt2 interface{} + Limit interface{} + Literal interface{} + Offset interface{} + Operand interface{} + OrderBy interface{} + OrderBy1 interface{} + OrderBy11 interface{} + Predicate interface{} + Predicate1 interface{} + Predicate11 interface{} + Predicate12 interface{} + Predicate13 interface{} + PrimaryExpression interface{} + PrimaryFactor interface{} + PrimaryFactor1 interface{} + PrimaryFactor11 interface{} + PrimaryTerm interface{} + PrimaryTerm1 interface{} + PrimaryTerm11 interface{} + QualifiedIdent interface{} + QualifiedIdent1 interface{} + RecordSet interface{} + RecordSet1 interface{} + RecordSet11 interface{} + RecordSet2 interface{} + RecordSetList interface{} + RecordSetList1 interface{} + RecordSetList2 interface{} + RollbackStmt interface{} + SelectStmt interface{} + SelectStmt1 interface{} + SelectStmt2 interface{} + SelectStmt3 interface{} + SelectStmt4 interface{} + SelectStmt5 interface{} + SelectStmt6 interface{} + SelectStmt7 interface{} + Slice interface{} + Slice1 interface{} + Slice2 interface{} + Start interface{} + Statement interface{} + StatementList interface{} + StatementList1 interface{} + TableName interface{} + Term interface{} + Term1 interface{} + Term11 interface{} + TruncateTableStmt interface{} + Type interface{} + UnaryExpr interface{} + UnaryExpr1 interface{} + UnaryExpr11 interface{} + UpdateStmt interface{} + UpdateStmt1 interface{} + UpdateStmt2 interface{} + Values interface{} + Values1 interface{} + Values2 interface{} + WhereClause interface{} +) + +func _dump() { + s := fmt.Sprintf("%#v", _parserResult) + s = strings.Replace(s, "%", "%%", -1) + s = strings.Replace(s, "{", "{%i\n", -1) + s = strings.Replace(s, "}", "%u\n}", -1) + s = strings.Replace(s, ", ", ",\n", -1) + var buf bytes.Buffer + strutil.IndentFormatter(&buf, ". ").Format(s) + buf.WriteString("\n") + a := strings.Split(buf.String(), "\n") + for _, v := range a { + if strings.HasSuffix(v, "(nil)") || strings.HasSuffix(v, "(nil),") { + continue + } + + fmt.Println(v) + } +} + +// End of demo stuff diff --git a/Godeps/_workspace/src/github.com/cznic/ql/ql/.34a8b4c1ad933745146fdbfef3073706ee571625 b/Godeps/_workspace/src/github.com/cznic/ql/ql/.34a8b4c1ad933745146fdbfef3073706ee571625 new file mode 100644 index 0000000..e69de29 diff --git a/Godeps/_workspace/src/github.com/cznic/ql/ql/.f630cc97640448d8f823924a7df3ca00e4d9e53b b/Godeps/_workspace/src/github.com/cznic/ql/ql/.f630cc97640448d8f823924a7df3ca00e4d9e53b new file mode 100644 index 0000000..e69de29 diff --git a/Godeps/_workspace/src/github.com/cznic/ql/ql/Makefile b/Godeps/_workspace/src/github.com/cznic/ql/ql/Makefile new file mode 100644 index 0000000..e795538 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/ql/ql/Makefile @@ -0,0 +1,24 @@ +# Copyright 2014 The ql Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +.PHONY: all clean nuke + +all: editor + go vet + go install + make todo + +clean: + go clean + rm -f *~ ql + +editor: + go fmt + go install + +todo: + @grep -n ^[[:space:]]*_[[:space:]]*=[[:space:]][[:alpha:]][[:alnum:]]* *.go || true + @grep -n TODO *.go || true + @grep -n BUG *.go || true + @grep -n println *.go || true diff --git a/Godeps/_workspace/src/github.com/cznic/ql/ql/README.md b/Godeps/_workspace/src/github.com/cznic/ql/ql/README.md new file mode 100644 index 0000000..07139fd --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/ql/ql/README.md @@ -0,0 +1,10 @@ +ql +== + +Command ql is a utility to explore a database, prototype a schema or test drive a query, etc. + +Installation + + $ go get github.com/cznic/ql/ql + +Documentation: [godoc.org/github.com/cznic/ql/ql](http://godoc.org/github.com/cznic/ql/ql) diff --git a/Godeps/_workspace/src/github.com/cznic/ql/ql/main.go b/Godeps/_workspace/src/github.com/cznic/ql/ql/main.go new file mode 100644 index 0000000..74c85b5 --- /dev/null +++ b/Godeps/_workspace/src/github.com/cznic/ql/ql/main.go @@ -0,0 +1,200 @@ +// Copyright 2014 The ql Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Command ql is a utility to explore a database, prototype a schema or test +// drive a query, etc. +// +// Installation: +// +// $ go get github.com/cznic/ql/ql +// +// Usage: +// +// ql [-db name] [-schema regexp] [-tables regexp] [-fld] statement_list +// +// Options: +// +// -db name Name of the database to use. Defaults to "ql.db". +// If the DB file does not exists it is created automatically. +// +// -schema re If re != "" show the CREATE statements of matching tables and exit. +// +// -tables re If re != "" show the matching table names and exit. +// +// -fld First row of a query result set will show field names. +// +// statement_list QL statements to execute. +// If no non flag arguments are present, ql reads from stdin. +// The list is wrapped into an automatic transaction. +// +// Example: +// +// $ ql 'create table t (i int, s string)' +// $ ql << EOF +// > insert into t values +// > (1, "a"), +// > (2, "b"), +// > (3, "c"), +// > EOF +// $ ql 'select * from t' +// 3, "c" +// 2, "b" +// 1, "a" +// $ ql -fld 'select * from t where i != 2 order by s' +// "i", "s" +// 1, "a" +// 3, "c" +// $ +package main + +import ( + "bufio" + "flag" + "fmt" + "io/ioutil" + "log" + "os" + "regexp" + "sort" + "strings" + + "github.com/coreos/rocket/Godeps/_workspace/src/github.com/cznic/ql" +) + +func str(data []interface{}) string { + a := make([]string, len(data)) + for i, v := range data { + switch x := v.(type) { + case string: + a[i] = fmt.Sprintf("%q", x) + default: + a[i] = fmt.Sprint(x) + } + } + return strings.Join(a, ", ") +} + +func main() { + if err := do(); err != nil { + log.Fatal(err) + } +} + +func do() (err error) { + oDB := flag.String("db", "ql.db", "The DB file to open. It'll be created if missing.") + oFlds := flag.Bool("fld", false, "Show recordset's field names.") + oSchema := flag.String("schema", "", "If non empty, show the CREATE statements of matching tables and exit.") + oTables := flag.String("tables", "", "If non empty, list matching table names and exit.") + flag.Parse() + + db, err := ql.OpenFile(*oDB, &ql.Options{CanCreate: true}) + if err != nil { + return err + } + + defer func() { + ec := db.Close() + switch { + case ec != nil && err != nil: + log.Println(ec) + case ec != nil: + err = ec + } + }() + + if pat := *oSchema; pat != "" { + re, err := regexp.Compile(pat) + if err != nil { + return err + } + + nfo, err := db.Info() + if err != nil { + return err + } + + r := []string{} + for _, ti := range nfo.Tables { + if !re.MatchString(ti.Name) { + continue + } + + a := []string{} + for _, ci := range ti.Columns { + a = append(a, fmt.Sprintf("%s %s", ci.Name, ci.Type)) + } + r = append(r, fmt.Sprintf("CREATE TABLE %s (%s);", ti.Name, strings.Join(a, ", "))) + } + sort.Strings(r) + if len(r) != 0 { + fmt.Println(strings.Join(r, "\n")) + } + return nil + } + + if pat := *oTables; pat != "" { + re, err := regexp.Compile(pat) + if err != nil { + return err + } + + nfo, err := db.Info() + if err != nil { + return err + } + + r := []string{} + for _, ti := range nfo.Tables { + if !re.MatchString(ti.Name) { + continue + } + + r = append(r, ti.Name) + } + sort.Strings(r) + if len(r) != 0 { + fmt.Println(strings.Join(r, "\n")) + } + return nil + } + + var src string + switch n := flag.NArg(); n { + case 0: + b, err := ioutil.ReadAll(bufio.NewReader(os.Stdin)) + if err != nil { + return err + } + + src = string(b) + default: + a := make([]string, n) + for i := range a { + a[i] = flag.Arg(i) + } + src = strings.Join(a, " ") + } + + src = "BEGIN TRANSACTION; " + src + "; COMMIT;" + l, err := ql.Compile(src) + if err != nil { + log.Println(src) + return err + } + + rs, i, err := db.Execute(ql.NewRWCtx(), l) + if err != nil { + a := strings.Split(strings.TrimSpace(fmt.Sprint(l)), "\n") + return fmt.Errorf("%v: %s", err, a[i]) + } + + if len(rs) == 0 { + return + } + + return rs[len(rs)-1].Do(*oFlds, func(data []interface{}) (bool, error) { + fmt.Println(str(data)) + return true, nil + }) +} diff --git a/Godeps/_workspace/src/github.com/cznic/ql/ql/ql b/Godeps/_workspace/src/github.com/cznic/ql/ql/ql new file mode 100644 index 0000000000000000000000000000000000000000..8d4f948daa9d60d9db1f01cdbcff1d5d081779d0 GIT binary patch literal 10535847 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

XE12$oiYZ& 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%0Ahw~L)k1M|qKN!wP{rBxH(ti_) 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

lGT54hM7L$8*?^Yf2HfcvwjrRaMOfze$ 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

j-*2` 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 z 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 =;^ip7*7no+E~C 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≧+d5|$?+Wol?a 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�uOB}G(-wP$V|8%YszPEv%MB;~jq9;20% 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%0DAqq%IWTc}Who>W;Ce&>V%t6~XeSyl7C6_rj^ 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