From db679b031712e9da8ac72f56b2d5d000b4b88c3d Mon Sep 17 00:00:00 2001 From: Alexander Slesarev Date: Thu, 3 Dec 2020 10:47:43 -0700 Subject: [PATCH] Bf-tests improvements and maintanance update (#287) * Re-run bf mandel tests (addressing #258). * Maintenance update (#261) * Re-run bf mandel tests (addressing #258). * Preparation for Perl 7. * Lua module conflicts have been resolved. * Update README.md Fixed UPDATE date. * Maintenance update (#265) * Added workaround for Intel JCC bug (#263). * Maintenance update. * Added JCC bugfix flag to clang. (#266) * Vala numbers have been updated. (#268) * Update test_dawjsonlink.cpp (#271) Updated code to reflect API changes in v2 of DAW JSON Link * Maintenance update with the renamed tests (#269). (#270) * Switch the simdjson code to On Demand (#272) * Updating simdjson to 0.6 API (on demand). * Making things safer by specifying the commit + removing unnecessary std:: qualifiers. * Minor changes following review * Maintenance update and simdjson test changes (#273) * Maintenance update * Maintenance update and simdjson test changes. * The JSON key ordering tests have been added. (#275) * Boost.JSON test has been added and the old test has been renamed. (#277) * Updated to use better numbers for floating point ops, changed Boost.JSON test to use doubles. (#279) * Improved precisions of the tests (#281) * Median cals have been added. * Try another formatting. * Changed memory calculations. * Printing has been moved out from JSON benchmarks. * Up-to-dated results. * TOC updated. * Typo * Added printer to Scheme langs. * Racket code has been fixed to use idiomatic struct instead of macros. * C++ and Kotlin tests have been updated. * D tests have been fixed to use proper initializations. * Go and Elixir tests have improved. * Nim microoptimization have been removed. * Julia test has been updated. * All haskell tests have been updated. * Lua tests have been improved. * OCaml tests have been improved. * SML tests have been improved. * Fsharp test has been improved. * Tcl tests have been improved. * Perl tests have been updated to use v5.32. * Other tests have been fixed. * Haskell networking has been fixed. * Fixed JS code. Co-authored-by: Darrell Wright Co-authored-by: Daniel Lemire --- README.md | 484 +++++++++++++++--------------- analyze.rb | 1 + base64/Makefile | 8 +- base64/base64.csproj | 2 +- base64/base64.rs/Cargo.lock | 8 +- base64/base64.rs/Cargo.toml | 2 +- base64/test-xs.pl | 5 +- base64/test.js | 7 +- base64/test.pl | 5 +- base64/test.v | 8 +- brainfuck/Makefile | 28 +- brainfuck/bf-marray.hs | 111 +++++-- brainfuck/bf.c | 401 +++++++++++++------------ brainfuck/bf.cpp | 75 ++++- brainfuck/bf.cr | 58 +++- brainfuck/bf.cs | 77 +++-- brainfuck/bf.d | 88 +++++- brainfuck/bf.ex | 73 ++++- brainfuck/bf.go | 64 +++- brainfuck/bf.hs | 109 +++++-- brainfuck/bf.java | 65 +++- brainfuck/bf.jl | 91 +++--- brainfuck/bf.js | 198 +++++++----- brainfuck/bf.lua | 136 ++++++--- brainfuck/bf.ml | 83 +++-- brainfuck/bf.nim | 86 ++++-- brainfuck/bf.pl | 77 ++++- brainfuck/bf.rb | 57 +++- brainfuck/bf.rkt | 69 +++-- brainfuck/bf.rs | 95 ++++-- brainfuck/bf.scala | 56 +++- brainfuck/bf.sml | 103 +++++-- brainfuck/bf.ss | 73 +++-- brainfuck/bf.tcl | 70 ++++- brainfuck/bf.v | 71 ++++- brainfuck/bf.vala | 90 ++++-- brainfuck/bf2.kt | 63 +++- brainfuck/bf3.py | 56 +++- brainfuck/bf_oo.tcl | 71 ++++- brainfuck/brainfuck.csproj | 2 +- brainfuck/fsharp/bf.fs | 164 ++++++---- brainfuck/fsharp/brainfuck.fsproj | 2 +- common/commands.mk | 13 +- docker/Dockerfile | 40 +-- havlak/Makefile | 8 +- havlak/havlak.csproj | 2 +- havlak/havlak.nim | 2 +- json/Makefile | 20 +- json/json-core/json-core.csproj | 2 +- json/json-hs/Makefile | 1 + json/json-hs/json-hs.cabal | 2 +- json/json-hs/src/Main.hs | 48 +-- json/json-java/Maven.list | 2 +- json/json-scala/Maven.list | 2 +- json/json.csproj | 2 +- json/json.rs/Cargo.lock | 72 +++-- json/json.rs/Cargo.toml | 6 +- json/test-xs.pl | 5 +- json/test.d | 4 +- json/test.js | 26 +- json/test.pl | 5 +- json/test.v | 8 +- matmul/Makefile | 8 +- matmul/matmul.csproj | 2 +- matmul/matmul.js | 58 ++-- matmul/matmul.pl | 5 +- matmul/matmul.v | 8 +- 67 files changed, 2533 insertions(+), 1210 deletions(-) diff --git a/README.md b/README.md index 47d8de92..85932305 100644 --- a/README.md +++ b/README.md @@ -47,104 +47,108 @@ The measured values are: All values are presented as: `median`±`median absolute deviation`. -UPDATE: 2020-10-30 +UPDATE: 2020-12-01 # Test Cases ## Brainfuck Testing brainfuck implementations using two code samples (bench.b and mandel.b). +Supports two mode: + + - Verbose (default). Prints the output immediately. + - Quiet (if QUIET environment variable is set). Accumulates the output using Fletcher-16 checksum, and prints it out after the benchmark. [Brainfuck](brainfuck) ### bench.b -| Language | Time, s | Memory, MiB | Energy, J | -| :----------------------- | -----------------------: | ------------------------------------------------: | -------------------------: | -| C++/g++ | 0.876±0.010 | 1.50±00.00 + 0.00±00.00 | 17.08±00.19 | -| Nim/gcc | 1.826±0.010 | 1.80±00.08 + 0.00±00.00 | 33.07±00.41 | -| Vala/gcc | 1.830±0.009 | 3.98±00.04 + 0.00±00.00 | 33.87±00.54 | -| C/gcc | 1.854±0.036 | 0.55±00.01 + 0.00±00.00 | 35.34±01.45 | -| Kotlin | 1.867±0.026 | 37.01±00.14 + 2.88±00.26 | 35.09±00.90 | -| OCaml | 1.868±0.045 | 2.57±00.02 + 2.48±00.03 | 38.04±01.74 | -| D/ldc2 | 1.934±0.019 | 2.98±00.05 + 0.00±00.00 | 36.46±00.54 | -| Nim/clang | 1.939±0.048 | 2.29±00.05 + 0.00±00.00 | 38.99±01.12 | -| Vala/clang | 1.975±0.027 | 3.94±00.06 + 0.00±00.00 | 41.58±00.67 | -| D/gdc | 2.027±0.037 | 6.28±00.04 + 0.00±00.00 | 39.34±01.18 | -| Rust | 2.102±0.050 | 2.03±00.09 + 0.00±00.00 | 41.01±01.32 | -| Go/gccgo | 2.206±0.074 | 20.78±00.21 + 0.00±00.00 | 45.18±02.77 | -| C/clang | 2.245±0.024 | 0.50±00.01 + 0.00±00.00 | 42.46±02.19 | -| Java | 2.337±0.022 | 35.96±00.18 + 1.89±00.30 | 42.72±00.65 | -| C#/.NET Core | 2.451±0.037 | 33.26±00.12 + 1.30±00.05 | 46.20±01.47 | -| Go | 2.475±0.035 | 3.38±00.08 + 0.00±00.00 | 48.20±01.90 | -| MLton | 2.493±0.024 | 0.55±00.03 + 0.00±00.00 | 52.45±02.54 | -| V/gcc | 2.530±0.063 | 0.50±00.00 + 0.00±00.00 | 51.52±02.51 | -| Crystal | 2.670±0.014 | 3.35±00.05 + 0.00±00.00 | 51.04±01.64 | -| F#/.NET Core | 2.794±0.062 | 35.15±00.13 + 90.27±00.91 | 55.36±01.72 | -| V/clang | 2.867±0.077 | 0.87±00.01 + 0.00±00.00 | 56.10±03.03 | -| Chez Scheme | 2.936±0.054 | 22.88±00.06 + 6.24±00.05 | 58.09±03.11 | -| Julia | 3.242±0.133 | 155.09±00.47 + 21.86±00.38 | 64.32±04.93 | -| Scala | 3.496±0.078 | 80.21±00.68 + 57.68±05.60 | 71.55±02.78 | -| D/dmd | 3.771±0.039 | 3.49±00.05 + 0.00±00.00 | 66.90±02.18 | -| Haskell (MArray) | 4.380±0.073 | 4.11±00.08 + 1.25±00.00 | 101.37±03.59 | -| C#/Mono | 4.459±0.179 | 20.03±00.05 + 0.37±00.00 | 90.94±07.00 | -| Node.js | 5.063±0.030 | 29.49±00.02 + 1.97±00.19 | 88.66±01.54 | -| Lua/luajit | 7.571±0.151 | 2.82±00.08 + 0.00±00.00 | 128.54±04.21 | -| Racket | 8.077±0.170 | 106.98±00.08 + 0.00±00.00 | 141.31±03.73 | -| Python/pypy | 13.003±0.274 | 63.79±00.21 + 45.38±00.00 | 315.76±02.70 | -| Haskell | 16.686±0.512 | 4.11±00.04 + 1.34±00.00 | 310.02±13.55 | -| Ruby/truffleruby (--jvm) | 18.445±0.329 | 596.26±11.32 + 324.76±14.58 | 522.27±23.71 | -| Ruby/truffleruby | 51.534±2.159 | 260.91±00.06 + 277.20±10.48 | 978.82±137.20 | -| Lua | 56.908±1.507 | 2.64±00.02 + 0.00±00.00 | 1203.05±52.83 | -| Ruby (--jit) | 61.920±1.734 | 14.12±00.04 + 0.15±00.00 | 1110.14±49.84 | -| Ruby | 82.990±1.020 | 14.08±00.01 + 0.00±00.00 | 1771.74±67.67 | -| Ruby/jruby | 111.106±3.402 | 199.68±05.79 + 242.16±03.23 | 2182.73±161.51 | -| Elixir | 113.521±0.406 | 53.51±00.27 + 0.47±00.15 | 2493.22±31.14 | -| Python | 220.743±3.369 | 9.32±00.04 + 0.00±00.00 | 4797.72±88.75 | -| Tcl (FP) | 274.283±3.413 | 4.27±00.04 + 0.00±00.00 | 5234.49±210.69 | -| Perl | 339.112±7.722 | 6.43±00.02 + 0.00±00.00 | 7050.02±301.70 | -| Tcl (OOP) | 529.515±6.545 | 4.28±00.05 + 0.00±00.00 | 11591.55±176.57 | +| Language | Time, s | Memory, MiB | Energy, J | +| :----------------------- | ------------------------: | ------------------------------------------------: | -------------------------: | +| C++/g++ | 0.892±0.044 | 1.49±00.03 + 0.00±00.00 | 15.92±00.43 | +| Kotlin | 1.705±0.018 | 38.11±00.12 + 2.12±00.07 | 38.89±00.47 | +| D/ldc2 | 1.832±0.023 | 3.06±00.03 + 0.00±00.00 | 33.17±01.19 | +| Nim/gcc | 1.860±0.036 | 1.92±00.04 + 0.00±00.00 | 35.16±02.06 | +| C/gcc | 1.887±0.034 | 0.50±00.00 + 0.00±00.00 | 36.04±00.71 | +| Rust | 1.921±0.036 | 2.02±00.06 + 0.00±00.00 | 45.72±01.08 | +| Nim/clang | 1.921±0.036 | 2.37±00.05 + 0.00±00.00 | 44.39±01.02 | +| D/gdc | 1.950±0.034 | 6.34±00.07 + 0.00±00.00 | 37.39±01.93 | +| C/clang | 2.223±0.066 | 0.50±00.00 + 0.00±00.00 | 42.64±01.37 | +| OCaml | 2.230±0.026 | 2.60±00.02 + 2.50±00.03 | 42.50±01.23 | +| Go | 2.241±0.034 | 3.53±00.08 + 0.00±00.00 | 50.55±01.43 | +| Vala/clang | 2.316±0.026 | 3.73±00.04 + 0.00±00.00 | 54.54±00.49 | +| Crystal | 2.317±0.021 | 3.37±00.01 + 0.00±00.00 | 55.93±01.28 | +| Vala/gcc | 2.335±0.062 | 3.77±00.04 + 0.00±00.00 | 47.62±01.82 | +| C#/.NET Core | 2.341±0.089 | 34.18±00.04 + 0.01±00.00 | 48.13±04.76 | +| V/gcc | 2.433±0.071 | 0.50±00.00 + 0.00±00.00 | 51.49±01.99 | +| Java | 2.458±0.113 | 37.49±00.09 + 0.96±00.11 | 48.82±02.17 | +| Go/gccgo | 2.593±0.203 | 20.93±00.22 + 0.00±00.00 | 52.43±10.28 | +| V/clang | 2.742±0.106 | 0.87±00.00 + 0.00±00.00 | 57.97±03.80 | +| MLton | 2.841±0.030 | 1.44±00.05 + 0.25±00.00 | 69.59±01.25 | +| Chez Scheme | 2.898±0.136 | 24.87±00.05 + 4.23±00.09 | 61.62±05.33 | +| Julia | 2.989±0.124 | 169.09±00.12 + 0.00±00.00 | 52.77±03.78 | +| D/dmd | 3.398±0.051 | 3.58±00.04 + 0.00±00.00 | 75.85±04.16 | +| Scala | 3.451±0.036 | 80.33±00.31 + 63.22±04.38 | 70.71±01.84 | +| Node.js | 3.876±0.091 | 29.72±00.07 + 2.08±00.00 | 86.57±02.19 | +| C#/Mono | 4.047±0.035 | 20.14±00.06 + 0.00±00.00 | 93.13±00.66 | +| Haskell (MArray) | 4.626±0.065 | 3.52±00.05 + 1.23±00.00 | 104.52±07.29 | +| F#/.NET Core | 5.759±0.060 | 36.41±00.05 + 90.04±00.54 | 122.34±02.41 | +| Lua/luajit | 6.266±0.056 | 2.84±00.05 + 0.00±00.00 | 134.09±03.45 | +| Racket | 10.241±0.263 | 101.02±00.05 + 0.00±00.00 | 188.03±09.99 | +| Ruby/truffleruby (--jvm) | 11.014±0.785 | 554.32±05.28 + 467.70±85.03 | 346.21±23.03 | +| Python/pypy | 14.634±0.483 | 63.77±00.19 + 45.38±00.00 | 348.98±16.82 | +| Haskell | 16.436±0.405 | 4.28±00.05 + 1.00±00.00 | 320.67±10.52 | +| Ruby/truffleruby | 21.492±1.470 | 253.22±00.14 + 638.77±14.18 | 517.59±37.53 | +| Lua | 57.236±1.627 | 2.67±00.01 + 0.00±00.00 | 1122.15±58.58 | +| Ruby (--jit) | 61.421±1.978 | 14.12±00.05 + 0.15±00.00 | 1122.68±34.10 | +| Ruby | 82.449±3.315 | 14.15±00.05 + 0.00±00.00 | 1706.93±130.86 | +| Ruby/jruby | 109.907±2.647 | 202.52±03.44 + 236.59±02.42 | 2259.77±110.02 | +| Elixir | 119.090±1.217 | 56.61±01.01 + 0.00±00.00 | 2268.87±68.60 | +| Python | 235.009±4.679 | 9.45±00.03 + 0.00±00.00 | 4650.00±179.37 | +| Tcl (FP) | 279.844±8.099 | 4.28±00.03 + 0.00±00.00 | 5693.86±351.71 | +| Perl | 361.937±3.237 | 6.51±00.04 + 0.00±00.00 | 7386.06±407.83 | +| Tcl (OOP) | 540.958±12.988 | 4.26±00.09 + 0.00±00.00 | 11178.46±579.19 | ### mandel.b [Mandel in Brainfuck](brainfuck/mandel.b) -| Language | Time, s | Memory, MiB | Energy, J | -| :----------------------- | ------------------------: | ------------------------------------------------: | ------------------------: | -| C++/g++ | 11.750±0.200 | 1.50±00.03 + 2.20±00.03 | 238.08±19.76 | -| C/gcc | 13.152±0.230 | 0.55±00.01 + 1.09±00.03 | 226.01±09.52 | -| Vala/gcc | 13.553±0.141 | 0.00±00.00 + 0.00±00.00 | 232.63±09.26 | -| D/gdc | 14.056±0.695 | 6.60±00.06 + 0.52±00.00 | 256.56±26.63 | -| D/ldc2 | 15.040±0.137 | 3.09±00.02 + 0.77±00.00 | 319.73±08.24 | -| Vala/clang | 15.198±0.222 | 0.00±00.00 + 0.00±00.00 | 328.05±10.27 | -| Crystal | 15.442±0.156 | 3.36±00.01 + 0.41±00.02 | 322.26±06.55 | -| V/gcc | 16.213±0.211 | 0.53±00.03 + 1.92±00.03 | 303.77±17.59 | -| C/clang | 18.020±0.552 | 0.55±00.01 + 1.06±00.04 | 329.77±13.16 | -| Nim/clang | 18.082±0.336 | 2.32±00.04 + 0.51±00.00 | 382.29±19.97 | -| C#/.NET Core | 18.168±0.287 | 33.42±00.03 + 2.48±00.05 | 377.64±08.61 | -| Rust | 18.961±0.684 | 2.02±00.07 + 0.28±00.03 | 356.32±27.58 | -| V/clang | 19.085±0.786 | 0.86±00.06 + 1.98±00.12 | 338.08±24.00 | -| Nim/gcc | 20.081±0.098 | 1.86±00.04 + 0.51±00.00 | 447.29±05.66 | -| Java | 21.567±1.482 | 35.91±00.21 + 7.39±00.35 | 422.11±40.28 | -| Kotlin | 22.433±0.767 | 36.90±00.03 + 8.33±00.17 | 461.84±23.20 | -| Scala | 23.711±0.735 | 72.71±00.27 + 32.66±05.22 | 493.04±40.26 | -| MLton | 24.570±0.317 | 1.24±00.04 + 1.78±00.00 | 420.67±12.22 | -| Go/gccgo | 27.242±0.228 | 21.23±00.51 + 1.28±00.00 | 455.59±17.41 | -| OCaml | 29.912±1.068 | 3.29±00.02 + 7.26±01.97 | 565.03±42.35 | -| Go | 32.794±0.618 | 2.78±00.09 + 1.25±00.00 | 686.73±17.76 | -| D/dmd | 44.664±1.621 | 3.63±00.04 + 0.77±00.00 | 838.73±38.99 | -| C#/Mono | 46.634±0.426 | 20.14±00.05 + 1.14±00.00 | 990.63±12.21 | -| Chez Scheme | 48.198±1.162 | 23.48±00.03 + 5.73±00.04 | 936.23±64.37 | -| Node.js | 58.719±1.972 | 29.56±00.15 + 6.96±00.13 | 1164.88±81.55 | -| Julia | 59.297±0.975 | 154.91±00.49 + 21.99±00.40 | 1277.50±17.66 | -| Haskell (MArray) | 62.629±0.442 | 4.09±00.05 + 2.45±00.00 | 1401.28±13.64 | -| Lua/luajit | 64.387±0.450 | 2.88±00.06 + 0.85±00.00 | 1364.42±54.12 | -| Python/pypy | 70.615±0.932 | 63.83±00.25 + 46.61±00.10 | 1326.94±73.41 | -| Ruby/truffleruby (--jvm) | 113.544±1.747 | 589.01±03.74 + 341.00±21.87 | 2375.13±83.06 | -| F#/.NET Core | 124.378±0.274 | 35.29±00.07 + 93.01±00.09 | 2416.39±10.62 | -| Racket | 136.034±4.331 | 106.99±00.03 + 0.00±00.00 | 2542.90±190.09 | -| Ruby/truffleruby | 194.627±15.454 | 261.21±00.27 + 251.62±11.10 | 3804.72±383.77 | -| Haskell | 214.731±1.549 | 4.01±00.08 + 2.54±00.00 | 4658.95±141.03 | +| Language | Time, s | Memory, MiB | Energy, J | +| :----------------------- | -----------------------: | ------------------------------------------------: | ------------------------: | +| D/ldc2 | 13.023±0.141 | 3.02±00.04 + 0.77±00.00 | 282.47±15.54 | +| C/gcc | 13.024±0.044 | 0.49±00.00 + 1.11±00.02 | 232.35±06.92 | +| C++/g++ | 13.508±0.519 | 3.14±00.14 + 0.49±00.02 | 243.38±14.88 | +| D/gdc | 13.622±0.486 | 6.68±00.06 + 0.52±00.00 | 284.97±15.61 | +| V/gcc | 13.929±0.345 | 0.55±00.05 + 1.88±00.06 | 263.36±22.17 | +| Kotlin | 16.201±0.639 | 37.89±00.20 + 2.53±00.14 | 333.78±12.48 | +| C/clang | 17.205±0.296 | 0.54±00.00 + 1.09±00.02 | 409.86±07.81 | +| C#/.NET Core | 17.817±0.206 | 34.36±00.02 + 1.06±00.06 | 386.31±09.90 | +| Nim/gcc | 18.909±0.573 | 1.81±00.04 + 0.57±00.05 | 364.59±13.74 | +| Rust | 19.121±0.365 | 2.06±00.09 + 0.28±00.03 | 450.43±14.62 | +| V/clang | 19.954±0.144 | 0.85±00.00 + 1.97±00.09 | 354.30±05.02 | +| Nim/clang | 21.089±0.839 | 2.31±00.07 + 0.51±00.00 | 427.52±33.64 | +| Vala/clang | 21.997±0.558 | 3.54±00.04 + 2.02±00.02 | 417.73±08.93 | +| Java | 22.059±2.009 | 37.61±00.10 + 1.41±00.15 | 438.82±32.38 | +| Vala/gcc | 22.339±0.495 | 3.55±00.02 + 2.05±00.02 | 395.91±13.76 | +| Scala | 22.953±0.280 | 80.06±00.43 + 38.70±03.31 | 533.87±10.60 | +| Go/gccgo | 23.761±0.456 | 33.35±00.22 + 1.28±00.05 | 519.74±23.32 | +| Crystal | 23.958±0.297 | 3.32±00.04 + 0.45±00.02 | 442.85±08.69 | +| Go | 34.576±0.772 | 3.50±00.03 + 1.24±00.01 | 636.21±19.42 | +| OCaml | 36.101±0.674 | 3.81±00.03 + 7.19±01.04 | 809.54±37.56 | +| Chez Scheme | 38.361±0.223 | 25.47±00.03 + 3.65±00.02 | 928.03±21.01 | +| D/dmd | 40.256±0.116 | 3.48±00.03 + 0.77±00.00 | 890.37±04.94 | +| C#/Mono | 43.907±0.601 | 20.06±00.06 + 0.88±00.00 | 974.19±30.51 | +| Node.js | 45.577±1.511 | 29.36±00.12 + 6.12±00.01 | 911.95±74.08 | +| MLton | 52.145±0.592 | 1.40±00.03 + 4.11±00.00 | 997.68±30.34 | +| Julia | 57.873±1.982 | 168.56±00.17 + 0.00±00.00 | 1150.80±96.19 | +| Python/pypy | 65.443±0.415 | 64.01±00.25 + 45.97±00.09 | 1537.62±41.76 | +| Haskell (MArray) | 65.728±1.731 | 3.56±00.09 + 2.74±00.00 | 1333.81±82.75 | +| Ruby/truffleruby (--jvm) | 127.906±1.069 | 553.57±06.48 + 384.87±17.42 | 2850.44±62.68 | +| F#/.NET Core | 133.896±0.448 | 36.46±00.05 + 91.62±00.12 | 2663.72±08.90 | +| Racket | 167.016±3.127 | 100.96±00.07 + 0.00±00.00 | 3106.19±93.72 | +| Ruby/truffleruby | 169.044±5.202 | 252.82±00.38 + 661.55±17.47 | 3637.07±123.52 | +| Haskell | 224.213±5.516 | 3.65±00.06 + 26.29±00.00 | 4739.08±376.63 | +| Lua/luajit | 246.285±3.792 | 2.79±00.03 + 0.86±00.00 | 4889.38±291.91 | ## Base64 @@ -154,38 +158,38 @@ Testing base64 encoding/decoding of the large blob into the newly allocated buff | Language | Time, s | Memory, MiB | Energy, J | | :------------------------ | ----------------------: | ------------------------------------------------: | ----------------------: | -| C/gcc (aklomp) | 0.157±0.002 | 1.92±00.03 + 0.00±00.00 | 3.41±00.14 | -| V/clang | 0.831±0.032 | 1.97±00.01 + 0.43±00.10 | 14.57±01.00 | -| C/gcc | 1.237±0.067 | 1.88±00.03 + 0.00±00.00 | 22.43±02.28 | -| Rust | 1.256±0.022 | 2.55±00.05 + 0.01±00.00 | 27.66±01.25 | -| V/gcc | 1.474±0.026 | 1.72±00.04 + 0.23±00.07 | 31.07±01.58 | -| Nim/clang | 1.578±0.036 | 2.72±00.05 + 4.41±00.03 | 35.12±02.09 | -| D/ldc2 | 1.897±0.039 | 3.42±00.04 + 3.61±00.00 | 32.52±01.16 | -| Crystal | 1.982±0.014 | 3.83±00.04 + 1.80±00.02 | 46.74±00.43 | -| Nim/gcc | 1.983±0.024 | 2.27±00.04 + 4.44±00.00 | 43.66±01.35 | -| Java | 2.271±0.078 | 38.62±00.04 + 327.05±22.71 | 48.84±03.76 | -| D/gdc | 2.306±0.098 | 7.11±00.06 + 3.47±00.05 | 45.83±05.01 | -| Kotlin | 2.427±0.038 | 39.58±00.05 + 345.29±04.26 | 56.48±01.80 | -| Go | 2.505±0.013 | 4.61±00.03 + 4.50±00.17 | 47.49±00.47 | -| Ruby (--jit) | 2.549±0.096 | 14.51±00.02 + 43.25±00.57 | 47.31±03.07 | -| Scala | 2.554±0.031 | 80.89±00.67 + 71.32±05.09 | 51.15±03.92 | -| Ruby | 2.569±0.075 | 14.53±00.02 + 43.50±00.16 | 44.80±00.80 | -| Perl (MIME::Base64) | 2.646±0.104 | 14.45±00.08 + 0.02±00.00 | 48.60±04.70 | -| C++/g++ (libcrypto) | 2.719±0.084 | 5.34±00.16 + 0.07±00.00 | 62.23±03.17 | -| PHP | 2.942±0.101 | 15.80±00.08 + 0.00±00.00 | 49.58±01.39 | -| Node.js | 3.123±0.105 | 31.01±00.06 + 1029.64±00.08 | 68.11±01.22 | -| Go/gccgo | 3.506±0.010 | 22.03±00.17 + 7.14±00.14 | 72.97±01.36 | -| D/dmd | 3.815±0.128 | 3.69±00.06 + 3.67±00.06 | 65.92±04.33 | -| Tcl | 4.008±0.080 | 5.23±00.03 + 0.00±00.00 | 87.92±02.24 | -| Python | 5.166±0.061 | 9.37±00.02 + 0.18±00.00 | 117.11±03.97 | -| Python/pypy | 5.475±0.300 | 63.99±00.11 + 45.65±00.07 | 106.11±11.82 | -| C#/.NET Core | 5.513±0.093 | 33.86±00.11 + 40.39±00.61 | 104.92±01.62 | -| Julia | 5.623±0.132 | 199.35±00.31 + 43.17±00.15 | 131.97±01.86 | -| Ruby/truffleruby (--jvm) | 6.183±0.233 | 595.53±10.25 + 132.10±12.97 | 125.76±15.33 | -| C#/Mono | 7.263±0.080 | 20.73±00.07 + 18.50±00.02 | 173.29±05.14 | -| Ruby/jruby | 10.530±0.747 | 206.29±07.04 + 169.80±07.50 | 215.73±13.87 | -| Perl (MIME::Base64::Perl) | 16.329±0.482 | 15.77±00.12 + 0.25±00.04 | 358.67±13.10 | -| Ruby/truffleruby | 24.242±0.227 | 263.40±00.14 + 354.47±00.19 | 411.96±05.26 | +| C/gcc (aklomp) | 0.156±0.002 | 1.90±00.02 + 0.00±00.00 | 3.43±00.14 | +| C/gcc | 1.190±0.010 | 1.87±00.04 + 0.00±00.00 | 24.92±00.52 | +| Rust | 1.246±0.045 | 2.49±00.08 + 0.01±00.01 | 28.21±00.74 | +| V/clang | 1.522±0.026 | 1.98±00.04 + 0.47±00.01 | 32.63±00.77 | +| V/gcc | 1.624±0.026 | 1.73±00.03 + 0.23±00.11 | 35.31±01.20 | +| D/ldc2 | 1.745±0.011 | 3.40±00.02 + 3.66±00.00 | 30.74±00.31 | +| Nim/clang | 1.877±0.024 | 2.68±00.06 + 4.41±00.03 | 33.76±01.21 | +| Nim/gcc | 2.048±0.075 | 2.23±00.05 + 4.44±00.00 | 40.58±03.26 | +| Crystal | 2.100±0.006 | 3.76±00.03 + 1.79±00.02 | 43.08±00.46 | +| D/gdc | 2.137±0.015 | 7.05±00.09 + 3.46±00.03 | 37.92±01.38 | +| Java | 2.248±0.032 | 38.45±00.09 + 360.35±13.12 | 49.02±02.22 | +| Ruby | 2.336±0.029 | 14.41±00.05 + 42.64±00.90 | 53.21±02.22 | +| Ruby (--jit) | 2.364±0.048 | 14.47±00.04 + 43.78±00.06 | 53.65±03.10 | +| Kotlin | 2.411±0.058 | 39.43±00.08 + 339.98±11.43 | 51.45±02.95 | +| Go | 2.497±0.007 | 4.52±00.13 + 4.89±00.10 | 47.17±00.43 | +| Scala | 2.518±0.028 | 81.21±00.46 + 64.54±07.62 | 55.40±03.45 | +| C++/g++ (libcrypto) | 2.623±0.028 | 5.34±00.04 + 0.07±00.00 | 47.14±00.51 | +| PHP | 2.945±0.031 | 15.72±00.15 + 0.00±00.00 | 51.14±01.07 | +| Perl (MIME::Base64) | 3.024±0.046 | 14.16±00.03 + 0.02±00.00 | 52.92±01.33 | +| Node.js | 3.065±0.030 | 29.89±00.05 + 1029.92±00.07 | 67.19±00.76 | +| Go/gccgo | 3.660±0.012 | 22.07±00.12 + 7.22±00.22 | 72.73±00.40 | +| D/dmd | 3.663±0.066 | 3.67±00.06 + 3.67±00.00 | 74.06±00.79 | +| Tcl | 4.295±0.072 | 5.06±00.05 + 0.00±00.00 | 73.76±01.81 | +| Python/pypy | 4.723±0.117 | 64.13±00.15 + 45.72±00.05 | 101.07±05.88 | +| C#/.NET Core | 5.213±0.062 | 34.44±00.09 + 41.21±01.20 | 97.46±00.94 | +| Python | 5.448±0.112 | 9.21±00.05 + 0.18±00.00 | 102.56±05.80 | +| Julia | 5.857±0.093 | 200.32±00.21 + 42.88±00.21 | 111.74±01.76 | +| Ruby/truffleruby (--jvm) | 5.859±0.142 | 551.20±02.74 + 399.55±28.65 | 124.74±07.81 | +| C#/Mono | 7.565±0.204 | 20.60±00.05 + 18.49±00.06 | 144.66±05.48 | +| Ruby/jruby | 9.862±0.279 | 192.07±03.01 + 173.11±05.41 | 213.68±16.56 | +| Perl (MIME::Base64::Perl) | 16.414±0.631 | 15.46±00.05 + 0.20±00.08 | 353.95±27.54 | +| Ruby/truffleruby | 20.647±0.721 | 253.00±00.31 + 404.70±00.60 | 413.32±37.94 | ## Json @@ -193,58 +197,58 @@ Testing parsing and simple calculating of values from a big JSON file. [Json](json) -| Language | Time, s | Memory, MiB | Energy, J | -| :------------------------------ | ----------------------: | -------------------------------------------------: | -----------------------: | -| C++/g++ (DAW JSON Link) | 0.087±0.003 | 109.28±00.04 + 0.00±00.00 | 1.73±00.10 | -| C++/g++ (simdjson On-Demand) | 0.091±0.002 | 109.62±00.24 + 59.90±00.09 | 1.72±00.11 | -| D/gdc (fast) | 0.111±0.000 | 219.99±00.10 + 11.09±00.00 | 2.15±00.08 | -| Rust (Serde Custom) | 0.152±0.003 | 108.40±00.06 + 0.00±00.00 | 2.54±00.07 | -| Rust (Serde Typed) | 0.158±0.002 | 108.50±00.09 + 11.77±00.19 | 2.60±00.10 | -| C++/g++ (gason) | 0.163±0.003 | 109.26±00.01 + 97.17±00.00 | 3.19±00.15 | -| C++/g++ (simdjson DOM) | 0.169±0.002 | 109.85±00.05 + 176.60±00.00 | 3.22±00.06 | -| C++/g++ (RapidJSON) | 0.227±0.007 | 109.26±00.01 + 128.85±00.03 | 5.00±00.44 | -| C++/g++ (Boost.JSON) | 0.502±0.010 | 109.76±00.01 + 435.70±00.00 | 11.39±00.55 | -| Java | 0.522±0.018 | 252.52±00.10 + 74.25±00.75 | 14.47±00.36 | -| C++/g++ (RapidJSON SAX) | 0.567±0.014 | 109.46±00.04 + 0.00±00.00 | 11.43±00.56 | -| Scala | 0.588±0.016 | 327.12±00.93 + 74.86±00.92 | 15.12±00.83 | -| Node.js | 0.665±0.021 | 243.12±00.07 + 184.81±00.18 | 15.24±01.17 | -| Go (jsoniter) | 0.703±0.022 | 224.85±00.09 + 13.71±00.10 | 14.27±00.99 | -| Julia (JSON3) | 0.710±0.019 | 408.21±00.90 + 141.92±00.89 | 12.78±00.14 | -| Python/pypy | 0.827±0.020 | 277.20±00.18 + 127.96±00.00 | 18.50±01.17 | -| Rust (Serde Untyped) | 0.875±0.012 | 108.46±00.07 + 839.98±00.00 | 19.34±00.64 | -| Crystal (Schema) | 0.889±0.045 | 110.32±00.05 + 46.85±00.09 | 16.80±00.73 | -| Crystal (Pull) | 0.901±0.043 | 110.34±00.04 + 18.23±00.01 | 15.21±01.31 | -| Perl (Cpanel::JSON::XS) | 1.025±0.020 | 121.62±00.08 + 402.76±00.03 | 19.48±00.72 | -| Go | 1.107±0.031 | 113.88±00.13 + 95.54±00.16 | 24.14±01.13 | -| Crystal | 1.159±0.017 | 110.31±00.07 + 393.35±00.02 | 24.91±00.86 | -| V/clang | 1.232±0.018 | 107.89±00.02 + 484.45±00.06 | 27.71±00.73 | -| PHP | 1.243±0.020 | 121.59±00.04 + 682.01±00.00 | 25.89±00.38 | -| V/gcc | 1.330±0.017 | 107.43±00.05 + 484.56±00.00 | 23.84±00.92 | -| Go/gccgo | 1.443±0.024 | 132.33±00.23 + 96.04±00.04 | 31.07±00.79 | -| Nim/clang (Packedjson) | 1.477±0.024 | 109.02±00.06 + 290.81±00.00 | 32.36±00.67 | -| C++/g++ (json-c) | 1.541±0.052 | 109.48±00.03 + 1216.08±00.00 | 34.25±01.00 | -| Nim/gcc (Packedjson) | 1.566±0.015 | 108.54±00.04 + 290.81±00.00 | 27.16±00.44 | -| Clojure | 1.611±0.019 | 483.89±04.47 + 529.38±25.20 | 41.64±01.98 | -| Haskell | 1.740±0.036 | 4.79±00.06 + 5.76±00.08 | 39.03±00.59 | -| Python | 1.785±0.042 | 115.90±00.03 + 377.23±00.01 | 37.85±02.11 | -| CPython (UltraJSON) | 1.813±0.026 | 117.51±00.06 + 544.41±01.03 | 39.64±01.78 | -| Nim/gcc | 1.858±0.058 | 108.55±00.01 + 915.81±00.00 | 36.52±02.83 | -| Nim/clang | 1.969±0.021 | 109.01±00.03 + 915.75±00.00 | 35.52±00.93 | -| C#/.NET Core | 2.047±0.042 | 472.62±00.04 + 288.50±00.03 | 43.35±02.30 | -| Ruby | 2.197±0.020 | 120.73±00.03 + 277.82±00.05 | 50.09±00.62 | -| D/gdc | 2.211±0.017 | 113.23±00.10 + 600.30±00.00 | 46.68±01.28 | -| Ruby (YAJL) | 2.223±0.014 | 120.66±00.03 + 287.03±00.01 | 49.99±01.09 | -| C#/Mono | 2.233±0.041 | 462.10±00.08 + 0.17±00.00 | 39.21±01.32 | -| Ruby (--jit) | 2.245±0.059 | 120.77±00.05 + 277.87±00.16 | 50.96±00.94 | -| D/ldc2 | 2.560±0.023 | 109.60±00.04 + 680.21±00.00 | 51.78±00.54 | -| Rust (jq) | 3.753±0.117 | 110.43±00.04 + 775.50±00.77 | 77.53±04.71 | -| Ruby/jruby | 3.834±0.087 | 477.64±08.08 + 1485.96±39.70 | 112.73±03.38 | -| C++/g++ (Boost.PropertyTree) | 4.629±0.110 | 109.59±00.02 + 1440.03±00.03 | 89.83±06.60 | -| D/dmd | 5.052±0.027 | 110.11±00.05 + 680.11±00.01 | 98.13±01.90 | -| C#/.NET Core (System.Text.Json) | 7.049±0.162 | 463.86±00.06 + 183.08±00.02 | 151.72±08.05 | -| Perl (JSON::Tiny) | 11.629±0.119 | 122.21±00.07 + 525.14±00.04 | 256.57±04.73 | -| Ruby/truffleruby (--jvm) | 23.532±0.665 | 842.35±06.97 + 1280.99±74.13 | 597.41±27.51 | -| Ruby/truffleruby | 66.911±1.141 | 532.60±00.30 + 2336.97±87.82 | 1503.14±30.64 | +| Language | Time, s | Memory, MiB | Energy, J | +| :------------------------------ | -----------------------: | -------------------------------------------------: | -------------------------: | +| C++/g++ (DAW JSON Link) | 0.082±0.002 | 109.27±00.02 + 0.00±00.00 | 1.95±00.06 | +| C++/g++ (simdjson On-Demand) | 0.088±0.001 | 109.90±00.05 + 59.81±00.12 | 1.69±00.08 | +| D/gdc (fast) | 0.100±0.001 | 219.98±00.03 + 11.12±00.03 | 2.58±00.06 | +| Rust (Serde Custom) | 0.141±0.001 | 108.43±00.09 + 0.00±00.00 | 2.35±00.04 | +| Rust (Serde Typed) | 0.150±0.001 | 108.48±00.07 + 11.51±00.03 | 2.52±00.04 | +| C++/g++ (gason) | 0.158±0.004 | 109.25±00.01 + 97.17±00.03 | 3.19±00.21 | +| C++/g++ (simdjson DOM) | 0.160±0.003 | 109.81±00.03 + 176.60±00.00 | 3.21±00.08 | +| C++/g++ (RapidJSON) | 0.229±0.006 | 109.27±00.02 + 128.82±00.00 | 4.51±00.35 | +| C++/g++ (Boost.JSON) | 0.481±0.009 | 109.80±00.03 + 435.70±00.00 | 11.83±00.26 | +| Java | 0.528±0.018 | 252.65±00.15 + 75.46±01.57 | 14.53±00.36 | +| C++/g++ (RapidJSON SAX) | 0.534±0.021 | 109.46±00.02 + 0.00±00.00 | 11.52±00.82 | +| Scala | 0.609±0.009 | 327.43±00.58 + 73.55±00.87 | 16.90±00.72 | +| Julia (JSON3) | 0.615±0.031 | 355.85±00.44 + 243.86±02.20 | 13.47±01.25 | +| Node.js | 0.663±0.010 | 242.73±00.08 + 185.38±00.82 | 14.04±00.37 | +| Go (jsoniter) | 0.702±0.019 | 224.79±00.11 + 13.89±00.15 | 14.43±01.07 | +| Python/pypy | 0.780±0.013 | 277.41±00.16 + 127.96±00.00 | 18.71±00.61 | +| Rust (Serde Untyped) | 0.846±0.013 | 108.48±00.08 + 839.98±00.00 | 19.09±00.42 | +| Crystal (Pull) | 0.856±0.033 | 110.30±00.05 + 18.20±00.04 | 16.65±01.40 | +| Crystal (Schema) | 0.883±0.039 | 110.36±00.03 + 47.05±00.08 | 15.84±01.53 | +| C#/.NET Core (System.Text.Json) | 0.982±0.018 | 465.50±00.22 + 135.59±00.10 | 22.84±00.75 | +| Perl (Cpanel::JSON::XS) | 1.000±0.013 | 121.32±00.06 + 402.72±00.00 | 18.21±00.37 | +| Go | 1.129±0.049 | 113.94±00.19 + 95.95±00.02 | 22.35±01.99 | +| Crystal | 1.147±0.029 | 110.37±00.03 + 393.35±00.03 | 24.00±01.31 | +| PHP | 1.204±0.012 | 121.69±00.09 + 682.01±00.00 | 25.92±00.20 | +| V/gcc | 1.211±0.024 | 107.42±00.01 + 484.49±00.03 | 27.41±00.83 | +| V/clang | 1.299±0.021 | 107.91±00.03 + 484.48±00.03 | 29.13±01.05 | +| Go/gccgo | 1.401±0.025 | 132.57±00.07 + 95.88±00.20 | 31.66±01.06 | +| Nim/gcc (Packedjson) | 1.458±0.035 | 108.80±00.04 + 290.55±00.00 | 31.04±03.08 | +| Nim/clang (Packedjson) | 1.459±0.028 | 109.22±00.08 + 290.55±00.00 | 34.02±00.59 | +| C++/g++ (json-c) | 1.561±0.044 | 109.42±00.01 + 1216.08±00.00 | 30.31±01.55 | +| Clojure | 1.561±0.053 | 491.24±08.10 + 516.55±22.59 | 42.27±01.67 | +| Haskell | 1.701±0.024 | 4.41±00.03 + 5.42±00.03 | 39.66±00.56 | +| C#/.NET Core | 1.736±0.054 | 474.19±00.09 + 288.64±00.06 | 30.96±01.72 | +| Nim/gcc | 1.756±0.020 | 108.60±00.11 + 915.75±00.06 | 39.94±01.11 | +| Python | 1.757±0.056 | 115.88±00.05 + 377.23±00.01 | 38.02±02.48 | +| CPython (UltraJSON) | 1.771±0.020 | 117.52±00.04 + 545.45±00.90 | 35.77±00.50 | +| Nim/clang | 1.880±0.064 | 109.09±00.10 + 915.65±00.10 | 37.34±03.24 | +| C#/Mono | 2.072±0.048 | 462.61±00.08 + 0.18±00.00 | 45.96±02.08 | +| Ruby (YAJL) | 2.183±0.061 | 120.60±00.03 + 286.98±00.01 | 50.23±02.52 | +| D/gdc | 2.234±0.115 | 113.23±00.03 + 600.32±00.00 | 44.22±05.07 | +| Ruby | 2.260±0.067 | 120.71±00.04 + 277.85±00.04 | 42.18±01.80 | +| Ruby (--jit) | 2.316±0.029 | 120.76±00.02 + 277.83±00.05 | 44.52±01.57 | +| D/ldc2 | 2.503±0.033 | 109.55±00.05 + 680.07±00.04 | 50.98±01.91 | +| Rust (jq) | 3.578±0.063 | 110.41±00.05 + 774.34±00.26 | 79.25±01.55 | +| Ruby/jruby | 3.815±0.041 | 473.21±08.23 + 1448.93±24.01 | 116.78±04.54 | +| C++/g++ (Boost.PropertyTree) | 4.353±0.127 | 109.59±00.02 + 1440.00±00.00 | 94.67±07.97 | +| D/dmd | 4.867±0.131 | 110.06±00.04 + 680.07±00.03 | 101.12±04.66 | +| Perl (JSON::Tiny) | 11.508±0.117 | 121.91±00.06 + 525.12±00.04 | 268.69±04.33 | +| Ruby/truffleruby (--jvm) | 101.930±0.923 | 730.89±03.57 + 1288.83±43.61 | 2876.01±27.44 | +| Ruby/truffleruby | 582.209±8.945 | 731.12±00.18 + 2184.33±38.93 | 11738.06±202.59 | ## Matmul @@ -254,42 +258,42 @@ Testing allocating and multiplying matrices. | Language | Time, s | Memory, MiB | Energy, J | | :----------------------- | ------------------------: | ------------------------------------------------: | -------------------------: | -| D/ldc2 (lubeck) | 0.137±0.001 | 6.72±00.09 + 51.74±00.08 | 7.52±00.04 | -| Nim/clang (Arraymancer) | 0.142±0.002 | 5.48±00.04 + 51.56±00.00 | 7.78±00.07 | -| Nim/gcc (Arraymancer) | 0.150±0.000 | 5.57±00.02 + 51.56±00.00 | 8.35±00.04 | -| Python (NumPy) | 0.179±0.003 | 27.09±00.07 + 51.76±00.00 | 9.69±00.05 | -| Java (ND4J) | 0.187±0.016 | 136.80±03.36 + 87.35±00.00 | 8.93±01.00 | -| Julia (threads: 8) | 0.194±0.002 | 239.15±00.44 + 46.04±00.22 | 10.09±00.13 | -| Julia (threads: 1) | 0.523±0.008 | 239.18±00.25 + 45.49±00.01 | 12.43±00.50 | -| D/ldc2 | 1.944±0.005 | 3.46±00.09 + 70.11±00.00 | 42.60±00.52 | -| D/gdc | 2.057±0.012 | 6.67±00.04 + 70.71±00.00 | 47.61±00.92 | -| D/dmd | 2.100±0.026 | 3.84±00.04 + 70.43±00.00 | 47.27±00.61 | -| Java | 3.275±0.011 | 37.94±00.07 + 77.19±00.13 | 75.91±01.83 | -| C/gcc | 3.288±0.006 | 2.03±00.02 + 68.06±00.00 | 75.73±01.24 | -| Rust | 3.355±0.008 | 2.61±00.11 + 68.32±00.00 | 68.01±00.52 | -| Nim/gcc | 3.425±0.011 | 2.55±00.09 + 77.34±07.09 | 69.39±01.38 | -| Scala | 3.450±0.015 | 79.25±05.38 + 71.40±05.68 | 80.02±02.01 | -| Nim/clang | 3.459±0.025 | 3.09±00.03 + 75.80±05.67 | 71.13±00.84 | -| Julia (no BLAS) | 3.478±0.049 | 175.71±00.08 + 70.04±00.04 | 72.18±00.85 | -| Go/gccgo | 3.535±0.031 | 21.32±00.15 + 72.88±00.12 | 73.13±01.32 | -| Go | 3.549±0.019 | 3.72±00.02 + 73.50±00.23 | 75.80±01.20 | -| V/gcc | 3.561±0.015 | 1.96±00.04 + 68.84±00.00 | 78.66±04.04 | -| Swift | 3.577±0.015 | 149.02±00.06 + 59.88±00.10 | 88.52±00.94 | -| V/clang | 3.589±0.023 | 2.41±00.04 + 68.84±00.00 | 78.70±03.86 | -| Crystal | 3.735±0.120 | 4.15±00.06 + 59.66±00.05 | 86.20±03.69 | -| Node.js | 3.844±0.137 | 33.97±00.05 + 70.96±00.09 | 78.02±08.53 | -| Kotlin | 3.975±0.176 | 37.60±00.11 + 78.11±00.12 | 73.55±05.83 | -| Python/pypy | 6.357±0.166 | 64.19±00.07 + 69.19±00.02 | 115.30±06.42 | -| C#/.NET Core | 6.801±0.194 | 33.19±00.04 + 69.24±00.01 | 152.98±08.29 | -| C#/Mono | 10.657±0.226 | 20.15±00.04 + 69.04±00.03 | 227.93±10.56 | -| Ruby/truffleruby | 51.967±1.464 | 423.34±00.44 + 320.91±01.45 | 1094.70±90.05 | -| Ruby/truffleruby (--jvm) | 71.432±0.730 | 736.79±19.45 + 310.91±14.36 | 1751.33±46.57 | -| Ruby | 218.581±6.384 | 15.12±00.02 + 68.87±00.03 | 4453.92±329.16 | -| Ruby (--jit) | 219.854±5.378 | 15.18±00.02 + 69.08±00.06 | 4231.52±319.08 | -| Python | 247.284±5.100 | 9.97±00.01 + 68.58±00.00 | 4808.31±369.14 | -| Tcl | 350.227±14.139 | 7.22±00.03 + 400.44±00.03 | 7283.56±481.47 | -| Perl | 384.838±3.283 | 8.88±00.05 + 599.59±00.03 | 9488.54±129.93 | -| Ruby/jruby | 491.907±6.937 | 268.25±03.80 + 669.53±05.06 | 10651.33±411.72 | +| D/ldc2 (lubeck) | 0.069±0.001 | 6.70±00.04 + 56.29±00.19 | 3.83±00.09 | +| Nim/clang (Arraymancer) | 0.070±0.001 | 5.54±00.04 + 57.67±00.02 | 4.02±00.04 | +| Nim/gcc (Arraymancer) | 0.079±0.001 | 5.53±00.04 + 57.67±00.02 | 4.70±00.09 | +| Python (NumPy) | 0.105±0.002 | 27.06±00.06 + 57.64±00.04 | 5.91±00.21 | +| Julia (threads: 8) | 0.190±0.003 | 222.04±00.19 + 52.41±00.12 | 11.08±00.30 | +| Java (ND4J) | 0.206±0.026 | 137.15±03.95 + 87.35±00.00 | 9.96±01.00 | +| Julia (threads: 1) | 0.531±0.019 | 221.56±00.17 + 53.05±00.22 | 12.27±00.94 | +| D/ldc2 | 1.965±0.010 | 3.55±00.04 + 70.11±00.00 | 43.78±00.60 | +| D/gdc | 2.072±0.027 | 6.68±00.05 + 70.70±00.01 | 48.59±01.94 | +| D/dmd | 2.103±0.009 | 3.75±00.11 + 70.43±00.13 | 48.29±00.94 | +| Java | 3.289±0.020 | 37.92±00.04 + 77.27±00.26 | 74.62±01.52 | +| C/gcc | 3.320±0.010 | 2.03±00.02 + 68.06±00.00 | 76.08±01.58 | +| Rust | 3.363±0.008 | 2.62±00.06 + 68.32±00.00 | 69.32±01.58 | +| Nim/gcc | 3.434±0.017 | 2.63±00.03 + 74.77±04.64 | 70.32±01.18 | +| Scala | 3.451±0.039 | 84.70±00.88 + 80.50±03.14 | 80.20±01.58 | +| Nim/clang | 3.454±0.009 | 3.08±00.06 + 72.19±02.19 | 71.54±01.32 | +| Julia (no BLAS) | 3.503±0.024 | 177.98±00.14 + 69.74±00.07 | 74.83±00.82 | +| Go | 3.572±0.037 | 3.79±00.08 + 73.24±00.23 | 76.44±01.29 | +| Go/gccgo | 3.604±0.055 | 27.67±06.19 + 72.72±00.21 | 75.21±00.74 | +| Crystal | 3.623±0.010 | 4.13±00.04 + 59.70±00.01 | 90.24±00.72 | +| V/clang | 3.642±0.054 | 2.44±00.01 + 68.84±00.00 | 90.91±01.22 | +| Swift | 3.657±0.059 | 148.95±00.13 + 59.76±00.07 | 87.78±02.97 | +| Node.js | 3.891±0.137 | 33.06±00.01 + 71.18±00.03 | 82.84±05.76 | +| Kotlin | 3.990±0.016 | 37.62±00.11 + 77.96±00.23 | 69.54±02.71 | +| V/gcc | 4.671±0.152 | 1.97±00.05 + 68.84±00.00 | 97.06±09.17 | +| Python/pypy | 6.261±0.256 | 64.29±00.20 + 69.20±00.03 | 122.94±12.29 | +| C#/.NET Core | 6.892±0.269 | 33.88±00.14 + 69.12±00.01 | 150.17±12.02 | +| C#/Mono | 10.532±0.078 | 20.20±00.05 + 69.02±00.01 | 237.07±02.79 | +| Ruby/truffleruby | 38.623±0.297 | 527.69±00.21 + 482.24±03.58 | 706.62±15.54 | +| Ruby/truffleruby (--jvm) | 70.781±1.848 | 597.32±03.94 + 330.89±08.63 | 1912.53±68.70 | +| Ruby (--jit) | 213.343±7.607 | 15.17±00.04 + 69.09±00.00 | 4581.51±99.85 | +| Ruby | 214.756±3.892 | 15.14±00.04 + 68.89±00.00 | 4585.32±103.55 | +| Python | 240.588±5.667 | 9.84±00.04 + 68.58±00.00 | 5021.18±181.03 | +| Tcl | 348.604±8.750 | 7.25±00.03 + 400.41±00.03 | 7605.35±576.78 | +| Perl | 402.099±5.437 | 8.96±00.08 + 599.69±00.05 | 8531.93±821.67 | +| Ruby/jruby | 488.395±11.851 | 279.21±05.66 + 658.86±07.14 | 10808.74±390.65 | ## Havlak @@ -299,20 +303,20 @@ Testing Havlak's loop finder implementations. | Language | Time, s | Memory, MiB | Energy, J | | :----------- | -----------------------: | ------------------------------------------------: | ------------------------: | -| Crystal | 6.919±0.034 | 3.31±00.03 + 225.37±00.68 | 170.28±02.29 | -| C++/g++ | 13.672±0.160 | 1.49±00.00 + 176.77±00.03 | 294.67±03.91 | -| Nim/gcc | 13.863±0.319 | 1.85±00.04 + 498.51±03.35 | 318.93±19.72 | -| Nim/clang | 13.891±0.151 | 2.29±00.01 + 504.69±00.16 | 342.27±07.22 | -| C#/.NET Core | 14.928±0.117 | 32.35±00.05 + 1357.19±39.35 | 371.50±01.94 | -| Scala | 17.869±0.326 | 75.99±03.94 + 312.90±01.65 | 559.85±12.85 | -| Go | 18.582±0.064 | 3.58±00.03 + 364.18±00.38 | 427.98±04.67 | -| D/ldc2 | 18.731±0.256 | 2.95±00.03 + 475.72±04.96 | 498.51±07.46 | -| D/gdc | 22.151±0.494 | 6.25±00.07 + 345.21±00.01 | 480.81±24.95 | -| D/dmd | 23.633±0.093 | 3.20±00.07 + 438.16±00.34 | 569.98±08.72 | -| C#/Mono | 25.318±0.340 | 19.79±00.03 + 314.47±01.46 | 621.60±42.61 | -| Go/gccgo | 26.014±0.120 | 21.01±00.32 + 361.91±04.37 | 663.53±10.03 | -| Python/pypy | 28.480±0.449 | 65.90±00.25 + 569.64±06.46 | 685.08±14.01 | -| Python | 103.731±2.547 | 9.02±00.03 + 398.56±00.00 | 2379.21±104.07 | +| Crystal | 6.967±0.047 | 3.35±00.02 + 225.61±00.81 | 168.07±01.75 | +| Nim/clang | 13.876±0.242 | 2.32±00.05 + 504.98±00.32 | 339.76±09.64 | +| Nim/gcc | 13.951±0.290 | 1.84±00.06 + 514.59±02.96 | 319.73±19.33 | +| C#/.NET Core | 14.376±0.124 | 33.19±00.05 + 1325.18±49.91 | 354.88±02.69 | +| C++/g++ | 14.675±0.092 | 1.49±00.01 + 176.74±00.02 | 319.49±03.11 | +| Scala | 18.237±0.566 | 79.12±00.19 + 307.60±05.21 | 558.81±14.47 | +| Go | 18.649±0.070 | 3.58±00.01 + 365.72±03.81 | 427.89±02.08 | +| D/ldc2 | 18.784±0.311 | 2.98±00.04 + 475.59±00.64 | 496.34±11.13 | +| D/gdc | 21.677±0.106 | 6.27±00.03 + 345.24±00.01 | 500.98±06.03 | +| D/dmd | 23.556±0.149 | 3.24±00.03 + 438.52±00.27 | 573.23±05.91 | +| C#/Mono | 25.040±0.277 | 19.86±00.07 + 316.46±01.31 | 636.95±27.02 | +| Go/gccgo | 26.036±0.202 | 20.96±00.13 + 358.92±06.52 | 662.70±08.52 | +| Python/pypy | 28.213±0.522 | 65.76±00.21 + 560.36±51.36 | 677.92±15.99 | +| Python | 101.997±2.348 | 9.03±00.04 + 398.56±00.00 | 2319.85±150.21 | # Tests Execution @@ -324,45 +328,45 @@ Base Docker image: Debian GNU/Linux bullseye/sid | Language | Version | | ---------------- | ------------------------------- | -| .NET Core | 3.1.109 | -| C#/.NET Core | 3.4.1-beta4-20127-10 (d8180a5e) | +| .NET Core | 5.0.100 | +| C#/.NET Core | 3.8.0-5.20519.18 (4c195c3a) | | C#/Mono | 6.12.0.90 | -| C/clang | 10.0.1 | +| C/clang | 11.0.0 | | C/gcc | 10.2.0 | | Chez Scheme | 9.5.4 | | Clojure | "1.10.1" | | Crystal | 0.35.1 | -| D/dmd | v2.094.0 | +| D/dmd | v2.094.2 | | D/gdc | 10.2.0 | -| D/ldc2 | 1.23.0 | +| D/ldc2 | 1.24.0 | | Elixir | 1.10.3 | -| F#/.NET Core | 10.7.0.0 for F# 4.7 | -| Go | go1.15.2 | +| F#/.NET Core | 11.0.0.0 for F# 5.0 | +| Go | go1.15.5 | | Go/gccgo | 10.2.0 | | Haskell | 8.10.2 | -| Java | 15 | -| Julia | v"1.5.2" | -| Kotlin | 1.4.10 | +| Java | 15.0.1 | +| Julia | v"1.5.3" | +| Kotlin | 1.4.20 | | Lua | Lua 5.4 | | Lua/luajit | LuaJIT 2.1.0-beta3 | | MLton | 20201002 | -| Nim | 1.2.6 | -| Node.js | v14.13.1 | +| Nim | 1.4.0 | +| Node.js | v15.3.0 | | OCaml | 4.11.1 | -| PHP | 7.4.10 | -| Perl | v5.30.3 | +| PHP | 7.4.11 | +| Perl | v5.32.0 | | Python | 3.8.6 | -| Python/pypy | 7.3.2-alpha0 for Python 3.7.4 | -| Racket | "7.8" | +| Python/pypy | 7.3.3-beta0 for Python 3.7.9 | +| Racket | "7.9" | | Ruby | 2.7.2p137 | | Ruby/jruby | 9.2.13.0 | -| Ruby/truffleruby | 20.2.0 | -| Rust | 1.47.0 | -| Scala | 2.13.3 | -| Swift | swift-5.3-RELEASE | +| Ruby/truffleruby | 20.3.0 | +| Rust | 1.48.0 | +| Scala | 2.13.4 | +| Swift | swift-5.3.1-RELEASE | | Tcl | 8.6 | -| V | 0.1.29 | -| Vala | 0.48.11 | +| V | 0.1.30 | +| Vala | 0.48.12 | ## Using Docker @@ -457,8 +461,10 @@ For Lua: For Haskell: - - [network-simple](http://hackage.haskell.org/package/network-simple) for + - [network](http://hackage.haskell.org/package/network) for TCP connectivity between the tests and the test runner. + - [raw-strings-qq](http://hackage.haskell.org/package/raw-strings-qq) for +raw string literals used in tests. For Perl: diff --git a/analyze.rb b/analyze.rb index a6e035f5..bb08650a 100755 --- a/analyze.rb +++ b/analyze.rb @@ -12,6 +12,7 @@ ATTEMPTS.times do |n| puts "--- Iteration #{n + 1}" + ENV['QUIET'] = '1' exit unless system(*ARGV) end end diff --git a/base64/Makefile b/base64/Makefile index 238c0327..1c8c5535 100644 --- a/base64/Makefile +++ b/base64/Makefile @@ -22,7 +22,7 @@ artifacts := $(executables) \ target/Base64Java.class \ target/Test-kt.jar \ target/test.exe \ - target/Release/netcoreapp3.1/base64.dll + target/Release/net5.0/base64.dll all_runners := $(patsubst %,run[%], $(artifacts)) \ run[test.pl] \ @@ -104,8 +104,8 @@ base64.rs/target/release/base64: $(base64-rs-toml) target/test.exe: test.cs | target $(MCS_BUILD) -.PHONY: target/Release/netcoreapp3.1/base64.dll -target/Release/netcoreapp3.1/base64.dll: base64.csproj | target +.PHONY: target/Release/net5.0/base64.dll +target/Release/net5.0/base64.dll: base64.csproj | target $(DOTNET_BUILD) target/base64_v_gcc: test.v | $(v_fmt) @@ -141,7 +141,7 @@ run[target/Test-kt.jar]:: run[%]: % run[target/test.exe]:: run[%]: % $(MONO_RUN) -run[target/Release/netcoreapp3.1/base64.dll]:: run[%]: % +run[target/Release/net5.0/base64.dll]:: run[%]: % $(DOTNET_RUN) .PHONY: base64_perl diff --git a/base64/base64.csproj b/base64/base64.csproj index 5f35b2e5..8f612967 100644 --- a/base64/base64.csproj +++ b/base64/base64.csproj @@ -1,6 +1,6 @@ - netcoreapp3.1 + net5.0 Exe diff --git a/base64/base64.rs/Cargo.lock b/base64/base64.rs/Cargo.lock index 66f4d227..6cb7bfa6 100644 --- a/base64/base64.rs/Cargo.lock +++ b/base64/base64.rs/Cargo.lock @@ -2,15 +2,13 @@ # It is not intended for manual editing. [[package]] name = "base64" -version = "0.12.3" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" [[package]] name = "base64_rs" version = "0.0.1" dependencies = [ - "base64 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", + "base64", ] - -[metadata] -"checksum base64 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" diff --git a/base64/base64.rs/Cargo.toml b/base64/base64.rs/Cargo.toml index e31f2f45..693cb95e 100644 --- a/base64/base64.rs/Cargo.toml +++ b/base64/base64.rs/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.1" edition = "2018" [dependencies] -base64 = "0.12.3" +base64 = "0.13.0" [profile.release] lto = true diff --git a/base64/test-xs.pl b/base64/test-xs.pl index f5e9e0ae..eb29c707 100644 --- a/base64/test-xs.pl +++ b/base64/test-xs.pl @@ -1,7 +1,8 @@ -use v5.12; +use v5.32; use warnings; +no feature qw(indirect); use feature qw(signatures); -no warnings qw(experimental::signatures); +no warnings qw(experimental); use MIME::Base64 qw(encode_base64 decode_base64); use Time::HiRes 'time'; diff --git a/base64/test.js b/base64/test.js index cc3137b1..f5c269e7 100644 --- a/base64/test.js +++ b/base64/test.js @@ -1,4 +1,7 @@ +'use strict'; + const assert = require("assert"); +const net = require('net'); const util = require('util'); const STR_SIZE = 131072; @@ -9,7 +12,7 @@ async function main() { const str2 = b.toString('base64'); const str3 = Buffer.from(str2, 'base64'); - await notify(`Node.js\t${require('process').pid}`); + await notify(`Node.js\t${process.pid}`); var s_encoded = 0; const start = new Date(); @@ -40,7 +43,7 @@ async function main() { function notify(msg) { return new Promise(resolve => { - const client = require('net').connect(9001, 'localhost', () => { + const client = net.connect(9001, 'localhost', () => { client.end(msg, 'utf8', () => { client.destroy(); resolve(); diff --git a/base64/test.pl b/base64/test.pl index 16623572..91494a5d 100644 --- a/base64/test.pl +++ b/base64/test.pl @@ -1,7 +1,8 @@ -use v5.12; +use v5.32; use warnings; +no feature qw(indirect); use feature qw(signatures); -no warnings qw(experimental::signatures); +no warnings qw(experimental); use MIME::Base64::Perl qw(encode_base64 decode_base64); use Time::HiRes 'time'; diff --git a/base64/test.v b/base64/test.v index e025ab26..74b18270 100644 --- a/base64/test.v +++ b/base64/test.v @@ -3,11 +3,13 @@ import net import time fn notify(msg string) { - sock := net.dial('127.0.0.1', 9001) or { + sock := net.dial_tcp('127.0.0.1:9001') or { return } - sock.write(msg) or { } - sock.close() or { } + defer { + sock.close() + } + sock.write_str(msg) or { } } fn main() { diff --git a/brainfuck/Makefile b/brainfuck/Makefile index d43a9fce..3aa483a7 100644 --- a/brainfuck/Makefile +++ b/brainfuck/Makefile @@ -26,11 +26,11 @@ executables := \ target/bin_c_clang artifacts := $(executables) \ - fsharp/target/Release/netcoreapp3.1/brainfuck.dll \ + fsharp/target/Release/net5.0/brainfuck.dll \ target/bf_scala.jar \ target/bf2-kt.jar \ target/bf.exe \ - target/Release/netcoreapp3.1/brainfuck.dll \ + target/Release/net5.0/brainfuck.dll \ target/bf.class fast_runners := $(patsubst %,run[%], $(artifacts)) \ @@ -74,12 +74,12 @@ target/bf_scala.jar: bf.scala | target target/bf.exe: bf.cs | target $(MCS_BUILD) -.PHONY: target/Release/netcoreapp3.1/brainfuck.dll -target/Release/netcoreapp3.1/brainfuck.dll: brainfuck.csproj | target +.PHONY: target/Release/net5.0/brainfuck.dll +target/Release/net5.0/brainfuck.dll: brainfuck.csproj | target $(DOTNET_BUILD) -.PHONY: fsharp/target/Release/netcoreapp3.1/brainfuck.dll -fsharp/target/Release/netcoreapp3.1/brainfuck.dll: fsharp/brainfuck.fsproj | target +.PHONY: fsharp/target/Release/net5.0/brainfuck.dll +fsharp/target/Release/net5.0/brainfuck.dll: fsharp/brainfuck.fsproj | target $(DOTNET_BUILD) target/bf2-kt.jar: bf2.kt | target @@ -106,10 +106,10 @@ target/bin_nim_clang: bf.nim | target target/bin_nim_gcc: bf.nim | target $(NIM_GCC_BUILD) -target/bin_hs: bf.hs | target +target/bin_hs: bf.hs | $(hlint) $(GHC_BUILD) -target/bin_hs_marray: bf-marray.hs | target +target/bin_hs_marray: bf-marray.hs | $(hlint) $(GHC_BUILD) target/bin_ocaml: bf.ml | target @@ -164,10 +164,10 @@ run[target/bf_scala.jar]:: run[%]: % run[target/bf.exe]:: run[%]: % $(MONO_RUN) $(BF_SRC) -run[target/Release/netcoreapp3.1/brainfuck.dll]:: run[%]: % +run[target/Release/net5.0/brainfuck.dll]:: run[%]: % $(DOTNET_RUN) $(BF_SRC) -run[fsharp/target/Release/netcoreapp3.1/brainfuck.dll]:: run[%]: % +run[fsharp/target/Release/net5.0/brainfuck.dll]:: run[%]: % $(DOTNET_RUN) $(BF_SRC) run[target/bf2-kt.jar]:: run[%]: % @@ -208,13 +208,13 @@ run[jruby][bf.rb]:: run[jruby][%]: % | $(rubocop) .PHONY: lua-deps lua-deps: - $(LUAROCKS_LUA) install luasocket - $(LUAROCKS_LUA) install luaposix + $(LUAROCKS_LUA) install luasocket > /dev/null + $(LUAROCKS_LUA) install luaposix > /dev/null .PHONY: luajit-deps luajit-deps: - $(LUAROCKS_LUAJIT) install luasocket - $(LUAROCKS_LUAJIT) install luaposix + $(LUAROCKS_LUAJIT) install luasocket > /dev/null + $(LUAROCKS_LUAJIT) install luaposix > /dev/null run[bf.lua]:: run[%]: % | lua-deps $(LUA_RUN) $(BF_SRC) diff --git a/brainfuck/bf-marray.hs b/brainfuck/bf-marray.hs index 8f06854e..eed48276 100644 --- a/brainfuck/bf-marray.hs +++ b/brainfuck/bf-marray.hs @@ -1,19 +1,50 @@ +{-# LANGUAGE QuasiQuotes #-} +{-# LANGUAGE ScopedTypeVariables #-} + module Main where import qualified Data.Array.Base as ArrayBase import qualified Data.Array.IO as IOUArray import qualified Data.Array.MArray as MArray import qualified Data.ByteString.Char8 as C -import Network.Simple.TCP -import Data.Char (chr) -import System.Environment (getArgs) +import Control.Exception +import Control.Monad +import Data.Bits +import Data.Char +import Data.Maybe +import Network.Socket +import Network.Socket.ByteString +import System.Environment +import System.Exit import System.IO (hFlush, stdout) import System.Posix (getProcessID) +import Text.RawString.QQ data Op = Inc !Int | Move !Int | Print | Loop ![Op] deriving Show data Tape = Tape { tapeData :: IOUArray.IOUArray Int Int , tapePos :: !Int } +data Printer = Printer { sum1 :: Int + , sum2 :: Int + , quiet :: Bool + } + +write :: Printer -> Int -> IO Printer +write p n = if quiet p + then do let s1 = mod (sum1 p + n) 255 + let s2 = mod (s1 + sum2 p) 255 + return Printer { + sum1=s1, + sum2=s2, + quiet=True + } + else do + putStr [chr n] + hFlush stdout + return p + +getChecksum :: Printer -> Int +getChecksum p = (sum2 p `shiftL` 8) .|. sum1 p current :: Tape -> IO Int current tape = ArrayBase.unsafeRead (tapeData tape) (tapePos tape) @@ -30,11 +61,12 @@ move m tape = do then return curData else do el <- MArray.getElems curData - MArray.newListArray (0, newPos) (el ++ [0 | i <- [len..newPos]]) + MArray.newListArray (0, newPos) + (el ++ replicate (newPos - len + 1) 0) return $ Tape newData newPos where curData = tapeData tape - newPos = (tapePos tape) + m + newPos = tapePos tape + m parse :: ([Char], [Op]) -> ([Char], [Op]) parse ([], acc) = ([], reverse acc) @@ -50,41 +82,72 @@ parse (c:cs, acc) = ']' -> (cs, reverse acc) _ -> parse (cs, acc) -run :: [Op] -> Tape -> IO Tape -run [] tape = return tape -run (op:ops) tape = do +run :: [Op] -> Tape -> Printer -> IO (Tape, Printer) +run [] tape p = return (tape, p) +run (op:ops) tape p = do case op of Inc d -> do inc d tape - run ops tape + run ops tape p Move m -> do newTape <- move m tape - run ops newTape + run ops newTape p Print -> do x <- current tape - putStr $ [chr x] - hFlush stdout - run ops tape + newP <- write p x + run ops tape newP Loop loop -> - let go tape = do - x <- current tape - if x == 0 then run ops tape - else run loop tape >>= go - in go tape + let go (newTape, newP) = do + x <- current newTape + if x == 0 then run ops newTape newP + else run loop newTape newP >>= go + in go (tape, p) -notify msg = do - connect "localhost" "9001" $ \(socket, _) -> do - send socket $ C.pack msg +notify :: String -> IO () +notify msg = withSocketsDo $ do + addr <- resolve + catch (_notify addr) (\(_ :: IOException) -> return ()) + where + writeMsg s = sendAll s $ C.pack msg + resolve = do + let hints = defaultHints { addrSocketType = Stream } + head <$> getAddrInfo (Just hints) (Just "localhost") (Just "9001") + _notify addr = bracket (openSocket addr) close $ \sock -> do + connect sock $ addrAddress addr + writeMsg sock +verify :: IO () +verify = do + let source = [r|++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>\ + ---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.|] + let (_, ops) = parse (source, []) + empty <- MArray.newListArray (0, 0) [0] + (_, pLeft) <- run ops + (Tape empty 0) + Printer {sum1=0, sum2=0, quiet=True} + let left = getChecksum pLeft + + pRight <- foldM (\p c -> write p $ ord c) + (Printer {sum1=0, sum2=0, quiet=True}) + "Hello World!\n" + let right = getChecksum pRight + when (left /= right) + $ die $ show left ++ " != " ++ show right + +main :: IO () main = do + verify [filename] <- getArgs source <- readFile filename + quiet_env <- lookupEnv "QUIET" + let p = Printer {sum1=0, sum2=0, quiet=isJust quiet_env} pid <- getProcessID notify $ "Haskell (MArray)\t" ++ show pid - let (_, ops) = parse (source, []) empty <- MArray.newListArray (0, 0) [0] - run ops $ Tape empty 0 - + (_, newP) <- run ops (Tape empty 0) p notify "stop" + + when (quiet newP) + $ do putStrLn $ "Output checksum: " ++ show (getChecksum newP) diff --git a/brainfuck/bf.c b/brainfuck/bf.c index 1678b463..03a79793 100644 --- a/brainfuck/bf.c +++ b/brainfuck/bf.c @@ -1,8 +1,9 @@ +#include +#include #include #include #include #include -#include #ifdef __clang__ # define COMPILER "clang" @@ -13,279 +14,295 @@ struct op_list; enum op_type { - OP_INC, - OP_MOVE, - OP_LOOP, - OP_PRINT + OP_INC, + OP_MOVE, + OP_LOOP, + OP_PRINT }; union op_value { - int offset; - struct op_list *list; + int offset; + struct op_list *list; }; struct op { - enum op_type type; - union op_value value; + enum op_type type; + union op_value value; }; struct op_list { - struct op *ops; - int cap, len; + struct op *ops; + int cap, len; }; struct op op_new(enum op_type type, union op_value value) { - struct op op; + struct op op; - op.type = type; - if (type == OP_LOOP) - op.value.list = value.list; - else - op.value.offset = value.offset; + op.type = type; + if (type == OP_LOOP) + op.value.list = value.list; + else + op.value.offset = value.offset; - return op; + return op; } void op_list_free(struct op_list *list); void op_free(struct op op) { - if (op.type == OP_LOOP) { - op_list_free(op.value.list); - free(op.value.list); - } -} - -void op_list_init(struct op_list *list) -{ - list->len = 0; - list->cap = 0; - list->ops = NULL; + if (op.type == OP_LOOP) { + op_list_free(op.value.list); + free(op.value.list); + } } void op_list_free(struct op_list *list) { - int i; + int i; - for (i = 0; i < list->len; i += 1) - op_free(list->ops[i]); + for (i = 0; i < list->len; i += 1) + op_free(list->ops[i]); - free(list->ops); + free(list->ops); } void op_list_grow(struct op_list *list) { - if (list->ops == NULL) { - list->cap = 4; - } else { - /* double the capacity */ - list->cap <<= 1; - } - list->ops = realloc(list->ops, sizeof(struct op) * list->cap); + if (list->ops == NULL) { + list->cap = 4; + } else { + /* double the capacity */ + list->cap <<= 1; + } + list->ops = realloc(list->ops, sizeof(struct op) * list->cap); } int op_list_length(const struct op_list *list) { - return list->len; + return list->len; } struct op op_list_get(const struct op_list *list, int i) { - return list->ops[i]; + return list->ops[i]; } void op_list_push(struct op_list *list, struct op op) { - if (list->len == list->cap) - op_list_grow(list); + if (list->len == list->cap) + op_list_grow(list); - list->ops[list->len++] = op; + list->ops[list->len++] = op; } struct string_iterator { - const char *string; - int pos; + const char *string; + int pos; }; -void string_iterator_init(struct string_iterator *it, const char *s) +char string_iterator_next(struct string_iterator *it) { - it->string = s; - it->pos = 0; + return it->string[it->pos++]; } -char string_iterator_next(struct string_iterator *it) -{ - return it->string[it->pos++]; +struct printer { + int sum1; + int sum2; + bool quiet; +}; + +void print(struct printer *p, int n) { + if (p->quiet) { + p->sum1 = (p->sum1 + n) % 255; + p->sum2 = (p->sum2 + p->sum1) % 255; + } else { + putc(n, stdout); + fflush(stdout); + } +} + +int get_checksum(const struct printer *p) { + return (p->sum2 << 8) | p->sum1; } void parse(struct string_iterator *it, struct op_list *ops) { - char c; - struct op_list *loop_ops; - union op_value value; - enum op_type type; - - while ((c = string_iterator_next(it))) { - switch (c) { - case '+': - type = OP_INC; - value.offset = 1; - break; - case '-': - type = OP_INC; - value.offset = -1; - break; - case '>': - type = OP_MOVE; - value.offset = 1; - break; - case '<': - type = OP_MOVE; - value.offset = -1; - break; - case '.': - type = OP_PRINT; - value.offset = 0; - break; - case '[': - loop_ops = malloc(sizeof(struct op_list)); - op_list_init(loop_ops); - parse(it, loop_ops); - - type = OP_LOOP; - value.list = loop_ops; - break; - case ']': - return; - default: - continue; - } - - op_list_push(ops, op_new(type, value)); - } + char c; + struct op_list *loop_ops; + union op_value value; + enum op_type type; + + while ((c = string_iterator_next(it))) { + switch (c) { + case '+': + type = OP_INC; + value.offset = 1; + break; + case '-': + type = OP_INC; + value.offset = -1; + break; + case '>': + type = OP_MOVE; + value.offset = 1; + break; + case '<': + type = OP_MOVE; + value.offset = -1; + break; + case '.': + type = OP_PRINT; + value.offset = 0; + break; + case '[': + loop_ops = calloc(1, sizeof(struct op_list)); + parse(it, loop_ops); + + type = OP_LOOP; + value.list = loop_ops; + break; + case ']': + return; + default: + continue; + } + + op_list_push(ops, op_new(type, value)); + } } struct tape { - int *tape; - int cap, pos; + int *tape; + int cap, pos; }; -void tape_init(struct tape *tape) -{ - tape->pos = 0; - tape->cap = 1; - tape->tape = malloc(sizeof(int)); - *tape->tape = 0; -} - -void tape_free(struct tape tape) -{ - free(tape.tape); -} - char tape_get(const struct tape tape) { - return tape.tape[tape.pos]; + return tape.tape[tape.pos]; } void tape_grow(struct tape *tape) { - int i, new_cap; + int i, new_cap; - new_cap = tape->cap << 1; - tape->tape = realloc(tape->tape, sizeof(int) * new_cap); + new_cap = tape->cap << 1; + tape->tape = realloc(tape->tape, sizeof(int) * new_cap); - for (i = tape->cap; i < new_cap; i += 1) - tape->tape[i] = 0; + for (i = tape->cap; i < new_cap; i += 1) + tape->tape[i] = 0; - tape->cap = new_cap; + tape->cap = new_cap; } void tape_move(struct tape *tape, int amount) { - tape->pos += amount; + tape->pos += amount; - if (tape->pos >= tape->cap) - tape_grow(tape); + if (tape->pos >= tape->cap) + tape_grow(tape); } void tape_inc(struct tape tape, int amount) { - tape.tape[tape.pos] += amount; + tape.tape[tape.pos] += amount; } -void eval(const struct op_list *ops, struct tape *tape) -{ - int i, len; - struct op op; - - for (i = 0, len = op_list_length(ops); i < len; i += 1) { - switch ((op = op_list_get(ops, i)).type) { - case OP_INC: - tape_inc(*tape, op.value.offset); - break; - case OP_MOVE: - tape_move(tape, op.value.offset); - break; - case OP_LOOP: - while (tape_get(*tape) > 0) - eval(op.value.list, tape); - break; - case OP_PRINT: - putc(tape_get(*tape), stdout); - fflush(stdout); - break; - } - } +void eval(const struct op_list *ops, struct tape *tape, struct printer *p) { + int i, len; + struct op op; + + for (i = 0, len = op_list_length(ops); i < len; i += 1) { + switch ((op = op_list_get(ops, i)).type) { + case OP_INC: + tape_inc(*tape, op.value.offset); + break; + case OP_MOVE: + tape_move(tape, op.value.offset); + break; + case OP_LOOP: + while (tape_get(*tape) > 0) + eval(op.value.list, tape, p); + break; + case OP_PRINT: + print(p, tape_get(*tape)); + break; + } + } +} + +void run(const char* code, struct printer *p) { + struct tape tape = {.tape=calloc(1, sizeof(int)), .cap=1, .pos=0}; + struct op_list ops = {.ops=NULL, .cap=0, .len=0}; + struct string_iterator it = {.string=code, .pos=0}; + parse(&it, &ops); + eval(&ops, &tape, p); + free(tape.tape); + op_list_free(&ops); +} + +void verify() { + char text[] = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>" + "---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++."; + struct printer p_left = {.sum1=0, .sum2=0, .quiet=true}; + run(text, &p_left); + int left = get_checksum(&p_left); + + struct printer p_right = {.sum1=0, .sum2=0, .quiet=true}; + char result[] = "Hello World!\n"; + size_t i = 0; + while (result[i] != '\0') { + print(&p_right, result[i++]); + } + int right = get_checksum(&p_right); + if (left != right) { + fprintf(stderr, "%d != %d", left, right); + exit(EXIT_FAILURE); + } } int main(int argc, char *argv[]) { - FILE *f; - int fsize, notify_len; - const char *filename; - char *code; - char notify_msg[32]; - struct op_list ops; - struct tape tape; - struct string_iterator it; - - if (argc < 2) { - fprintf(stderr, "Expected filename\n"); - return EXIT_FAILURE; - } - - filename = argv[1]; - - f = fopen(filename, "r"); - if (f == NULL) { - perror("bfc: fopen"); - return EXIT_FAILURE; - } - - fseek(f, 0, SEEK_END); - fsize = ftell(f); - fseek(f, 0, SEEK_SET); - - code = malloc(sizeof(char) * fsize + 1); - fread(code, 1, fsize, f); - fclose(f); - code[fsize] = 0; - - notify_len = snprintf(notify_msg, sizeof(notify_msg), - "C/" COMPILER "\t%d", getpid()); - notify(notify_msg, notify_len); - - tape_init(&tape); - op_list_init(&ops); - string_iterator_init(&it, code); - parse(&it, &ops); - - eval(&ops, &tape); - - free(code); - tape_free(tape); - op_list_free(&ops); - - notify("stop", 4); + FILE *f; + int fsize, notify_len; + const char *filename; + char *code; + char notify_msg[32]; + + verify(); + struct printer p = {.sum1=0, .sum2=0, .quiet=getenv("QUIET") != NULL}; + + if (argc < 2) { + fprintf(stderr, "Expected filename\n"); + return EXIT_FAILURE; + } + + filename = argv[1]; + + f = fopen(filename, "r"); + if (f == NULL) { + perror("bfc: fopen"); + return EXIT_FAILURE; + } + + fseek(f, 0, SEEK_END); + fsize = ftell(f); + fseek(f, 0, SEEK_SET); + + code = malloc(sizeof(char) * fsize + 1); + fread(code, 1, fsize, f); + fclose(f); + code[fsize] = 0; + + notify_len = snprintf(notify_msg, sizeof(notify_msg), + "C/" COMPILER "\t%d", getpid()); + notify(notify_msg, notify_len); + run(code, &p); + notify("stop", 4); + + free(code); + + if (p.quiet) { + printf("Output checksum: %d\n", get_checksum(&p)); + } } diff --git a/brainfuck/bf.cpp b/brainfuck/bf.cpp index 831042bb..74908e51 100644 --- a/brainfuck/bf.cpp +++ b/brainfuck/bf.cpp @@ -1,10 +1,11 @@ -#include -#include -#include #include +#include #include +#include #include +#include #include +#include using namespace std; @@ -26,8 +27,7 @@ class Tape { tape_type tape; public: - Tape() { - pos = 0; + Tape(): pos(0) { tape.push_back(0); } @@ -36,12 +36,35 @@ class Tape { void move(int x) { pos += x; while (pos >= tape.size()) tape.resize(2 * tape.size()); } }; +class Printer { + int sum1; + int sum2; +public: + bool quiet; + + Printer(bool quiet): sum1(0), sum2(0), quiet(quiet) {} + + void print(int n) { + if (quiet) { + sum1 = (sum1 + n) % 255; + sum2 = (sum2 + sum1) % 255; + } else { + cout << static_cast(n); + } + } + + int get_checksum() const { + return (sum2 << 8) | sum1; + } +}; + class Program { Ops ops; + Printer& p; public: - Program(string code) { + Program(string code, Printer& p): p(p) { string::iterator iterator = code.begin(); ops = parse(&iterator, code.end()); } @@ -58,7 +81,7 @@ class Program { while (*iterator != end) { char c = **iterator; *iterator += 1; - switch (c) { + switch (c) { case '+': res.push_back(Op(INC, 1)); break; case '-': res.push_back(Op(INC, -1)); break; case '>': res.push_back(Op(MOVE, 1)); break; @@ -75,10 +98,10 @@ class Program { for (Ops::iterator it = program.begin(); it != program.end(); it++) { Op &op = *it; switch (op.op) { - case INC: tape.inc(op.val); break; - case MOVE: tape.move(op.val); break; - case LOOP: while (tape.get() > 0) _run(op.loop, tape); break; - case PRINT: printf("%c", tape.get()); fflush(stdout); break; + case INC: tape.inc(op.val); break; + case MOVE: tape.move(op.val); break; + case LOOP: while (tape.get() > 0) _run(op.loop, tape); break; + case PRINT: p.print(tape.get()); break; } } } @@ -95,18 +118,42 @@ string read_file(string filename){ return text; } +void verify() { + const string text("++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>" + "---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++."); + Printer p_left(true); + Program(text, p_left).run(); + const auto left = p_left.get_checksum(); + + Printer p_right(true); + for (const auto& c : string("Hello World!\n")) { + p_right.print(c); + } + const auto right = p_right.get_checksum(); + if (left != right) { + cerr << left << " != " << right << endl; + exit(EXIT_FAILURE); + } +} + int main(int argc, char** argv) { + verify(); if (argc < 2) { exit(EXIT_FAILURE); } - string text = read_file(string(argv[1])); + const auto text = read_file(string(argv[1])); + Printer p(getenv("QUIET") != nullptr); + cout << unitbuf; // enable automatic flushing stringstream ostr; ostr << "C++/g++\t" << getpid(); notify(ostr.str()); - Program p(text); - p.run(); + Program(text, p).run(); notify("stop"); + + if (p.quiet) { + cout << "Output checksum: " << p.get_checksum() << endl; + } } diff --git a/brainfuck/bf.cr b/brainfuck/bf.cr index fee45feb..b02f61ab 100644 --- a/brainfuck/bf.cr +++ b/brainfuck/bf.cr @@ -29,11 +29,35 @@ class Tape end end +class Printer + getter quiet + + def initialize(quiet : Bool) + @sum1 = 0 + @sum2 = 0 + @quiet = quiet + end + + def print(n : Int32) + if @quiet + @sum1 = (@sum1 + n) % 255 + @sum2 = (@sum2 + @sum1) % 255 + else + print(n.chr) + end + end + + def checksum + (@sum2 << 8) | @sum1 + end +end + class Program @ops : Array(Op::T) - def initialize(code : String) + def initialize(code : String, p : Printer) @ops = parse(code.each_char) + @p = p end def run @@ -52,7 +76,7 @@ class Program _run(op, tape) end when Op::Print - print(tape.get.chr) + @p.print(tape.get) else # pass end @@ -88,13 +112,33 @@ def notify(msg) end end -class EntryPoint - text = File.read(ARGV[0]) +def verify + text = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.> + ---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++." + p_left = Printer.new(true) + Program.new(text, p_left).run + left = p_left.checksum - pid = Process.pid - notify("Crystal\t#{pid}") + p_right = Printer.new(true) + "Hello World!\n".each_char { |c| p_right.print(c.ord) } - Program.new(text).run + right = p_right.checksum + if left != right + STDERR.puts "#{left} != #{right}" + exit(1) + end +end +class EntryPoint + verify + text = File.read(ARGV[0]) + p = Printer.new(ENV.has_key?("QUIET")) + + notify("Crystal\t#{Process.pid}") + Program.new(text, p).run notify("stop") + + if p.quiet + puts "Output checksum: #{p.checksum}" + end end diff --git a/brainfuck/bf.cs b/brainfuck/bf.cs index 7d7da677..79b3c552 100644 --- a/brainfuck/bf.cs +++ b/brainfuck/bf.cs @@ -20,31 +20,48 @@ struct Op { public class Tape { - int pos; - int[] tape; - - public Tape() - { - pos = 0; - tape = new int[1]; - } + int pos = 0; + int[] tape = new int[1]; public int Get() { return tape[pos]; } public void Inc(int x) { tape[pos] += x; } public void Move(int x) { pos += x; while (pos >= tape.Length) Array.Resize(ref tape, tape.Length*2); } } + class Printer { + int sum1 = 0; + int sum2 = 0; + + public bool Quiet { get; set; } + + public void Print(int n) { + if (Quiet) { + sum1 = (sum1 + n) % 255; + sum2 = (sum2 + sum1) % 255; + } else { + Console.Write((char)n); + } + } + + public int Checksum { + get { + return (sum2 << 8) | sum1; + } + } + } + class Program { string code; - int pos; + int pos = 0; Op[] ops; + Printer p; - Program(string text) + Program(string text, Printer p) { code = text; - pos = 0; ops = parse(); + this.p = p; } private Op[] parse() { @@ -75,7 +92,7 @@ class Program case OpT.INC: tape.Inc(op.v); break; case OpT.MOVE: tape.Move(op.v); break; case OpT.LOOP: while (tape.Get() > 0) _run(op.loop, tape); break; - case OpT.PRINT: Console.Write((char)tape.Get()); break; + case OpT.PRINT: p.Print(tape.Get()); break; } } } @@ -91,20 +108,46 @@ class Program } } + private static void Verify() { + var text = @"++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.> + ---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++."; + var p_left = new Printer{Quiet = true}; + new Program(text, p_left).run(); + var left = p_left.Checksum; + + var p_right = new Printer{Quiet = true}; + foreach (var c in "Hello World!\n") { + p_right.Print(c); + } + var right = p_right.Checksum; + if (left != right) { + Console.Error.WriteLine($"{left} != {right}"); + System.Environment.Exit(1); + } + } + static void Main(string[] args) { - string text = File.ReadAllText(args[0]); + Verify(); + var text = File.ReadAllText(args[0]); + var p = new Printer { + Quiet = Environment.GetEnvironmentVariable("QUIET") != null + }; var runtime = Type.GetType("Mono.Runtime") != null ? "Mono" : ".NET Core"; Notify($"C#/{runtime}\t{Process.GetCurrentProcess().Id}"); - var stopWatch = new Stopwatch(); + var stopWatch = Stopwatch.StartNew(); - var p = new Program(text); - p.run(); + new Program(text, p).run(); stopWatch.Stop(); - Console.Error.WriteLine("time: " + stopWatch.ElapsedMilliseconds / 1e3 + "s"); + var elapsed = stopWatch.ElapsedMilliseconds / 1e3; Notify("stop"); + Console.Error.WriteLine($"time: {elapsed}s"); + + if (p.Quiet) { + Console.WriteLine($"Output checksum: {p.Checksum}"); + } } } } diff --git a/brainfuck/bf.d b/brainfuck/bf.d index 4b7427d4..5c88237f 100644 --- a/brainfuck/bf.d +++ b/brainfuck/bf.d @@ -1,12 +1,14 @@ import std.conv : to; import std.exception : assumeUnique; import std.file : readText; -import std.stdio : write, stdout; +import std.stdio; import std.traits : EnumMembers; import std.socket; import std.compiler; import std.format; import core.thread; +import std.process; +import core.stdc.stdlib; // for compatability with older versions of the standard library static if (__VERSION__ < 2068) @@ -29,15 +31,41 @@ void notify(string msg) } } +void verify() +{ + immutable text = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.> +---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++."; + auto p_left = new Printer(true); + Program(text).run(p_left); + immutable left = p_left.get_checksum(); + + auto p_right = new Printer(true); + foreach (i, c; "Hello World!\n") + { + p_right.print(c); + } + immutable right = p_right.get_checksum(); + if (left != right) + { + stderr.writefln("%s != %s", left, right); + exit(1); + } +} + void main(string[] args) { - string text = readText(args[1]); + verify(); + auto text = readText(args[1]); + auto p = new Printer(environment.get("QUIET") != null); notify("%s\t%d".format(name, getpid())); - - Program(text).run(); - + Program(text).run(p); notify("stop"); + + if (p.quiet) + { + writeln("Output checksum: %d".format(p.get_checksum())); + } } struct Op @@ -59,7 +87,15 @@ enum OpT : dchar struct Tape { uint pos; - int[] tape = [0]; + int[] tape; + Printer* p; + + this(Printer* p) + { + this.pos = 0; + this.tape = new int[1]; + this.p = p; + } int get() { @@ -90,8 +126,40 @@ struct Tape void print() { - write(cast(char) get()); - stdout.flush(); + p.print(get()); + } +} + +struct Printer +{ + int sum1; + int sum2; + bool quiet; + + this(bool quiet) + { + this.sum1 = 0; + this.sum2 = 0; + this.quiet = quiet; + } + + void print(int n) + { + if (quiet) + { + sum1 = (sum1 + n) % 255; + sum2 = (sum2 + sum1) % 255; + } + else + { + write(cast(char) n); + stdout.flush(); + } + } + + int get_checksum() const + { + return (sum2 << 8) | sum1; } } @@ -104,9 +172,9 @@ struct Program this.ops = parse(code).assumeUnique; } - void run() + void run(Printer* p) { - auto t = Tape(); + auto t = Tape(p); run(ops, t); } diff --git a/brainfuck/bf.ex b/brainfuck/bf.ex index f303127f..f36688f9 100644 --- a/brainfuck/bf.ex +++ b/brainfuck/bf.ex @@ -25,6 +25,28 @@ defmodule BF.Tape do end end +defmodule Printer do + @enforce_keys [:quiet] + defstruct [:quiet, sum1: 0, sum2: 0] + + def print(n, p) do + if p.quiet do + new_sum1 = rem(p.sum1 + n, 255) + new_sum2 = rem(p.sum2 + new_sum1, 255) + %Printer{p | sum1: new_sum1, sum2: new_sum2} + else + :ok = IO.binwrite([n]) + :file.sync(:stdout) + p + end + end + + def get_checksum(p) do + use Bitwise + (p.sum2 <<< 8) ||| p.sum1 + end +end + defmodule BF do alias BF.Tape, as: Tape @@ -52,23 +74,23 @@ defmodule BF do end end - def run([], tape) do - tape + def run([], tape, p) do + {tape, p} end - def run(program = [op | ops], tape) do + def run(program = [op | ops], tape, p) do case op do - {:inc, x} -> run(ops, Tape.inc(tape, x)) - {:move, x} -> run(ops, Tape.move(tape, x)) + {:inc, x} -> run(ops, Tape.inc(tape, x), p) + {:move, x} -> run(ops, Tape.move(tape, x), p) {:print, nil} -> - :ok = IO.binwrite([Tape.current(tape)]) - :file.sync(:stdout) - run(ops, tape) + p = Printer.print(Tape.current(tape), p) + run(ops, tape, p) {:loop, loop_code} -> if Tape.current(tape) == 0 do - run(ops, tape) + run(ops, tape, p) else - run(program, run(loop_code, tape)) + {tape, p} = run(loop_code, tape, p) + run(program, tape, p) end end end @@ -82,16 +104,39 @@ defmodule Benchmark do end end + def verify do + text = """ + ++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.> + ---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++. + """ + left = Printer.get_checksum( + elem(BF.parse(text) + |> BF.run(%BF.Tape{}, %Printer{quiet: true}), 1)) + + right = Printer.get_checksum( + Enum.reduce( + String.to_charlist("Hello World!\n"), + %Printer{quiet: true}, + &Printer.print/2)) + if left != right do + IO.puts(:stderr, "#{left} != #{right}") + exit(:shutdown) + end + end + def run do + verify() [filename] = System.argv() text = File.read!(filename) notify("Elixir\t#{System.pid()}") - - BF.parse(text) - |> BF.run(%BF.Tape{}) - + p = elem(BF.parse(text) + |> BF.run(%BF.Tape{}, %Printer{quiet: System.get_env("QUIET")}), 1) notify("stop") + + if p.quiet do + IO.puts("Output checksum: #{Printer.get_checksum(p)}") + end end end diff --git a/brainfuck/bf.go b/brainfuck/bf.go index f2e399dd..8e5db7d8 100644 --- a/brainfuck/bf.go +++ b/brainfuck/bf.go @@ -6,6 +6,7 @@ import ( "net" "os" "runtime" + "log" ) const ( @@ -75,6 +76,29 @@ func (t *Tape) Get() int { return t.tape[t.pos] } +type Printer struct { + sum1 int + sum2 int + quiet bool +} + +func NewPrinter(quiet bool) *Printer { + return &Printer{sum1: 0, sum2: 0, quiet: quiet} +} + +func (p *Printer) Print(n int) { + if p.quiet { + p.sum1 = (p.sum1 + n) % 255 + p.sum2 = (p.sum2 + p.sum1) % 255 + } else { + fmt.Printf("%c", n) + } +} + +func (p *Printer) GetChecksum() int { + return (p.sum2 << 8) | p.sum1 +} + type Program struct { Ops []Op } @@ -83,8 +107,8 @@ func NewProgram(code string) *Program { return &Program{Ops: parse(NewStringIterator(code))} } -func (p *Program) Run() { - _run(p.Ops, NewTape()) +func (p *Program) Run(printer *Printer) { + _run(p.Ops, NewTape(), printer) } func parse(si *StringIterator) []Op { @@ -117,7 +141,7 @@ func parse(si *StringIterator) []Op { return res } -func _run(program []Op, tape *Tape) { +func _run(program []Op, tape *Tape, p *Printer) { for i := 0; i < len(program); i++ { switch program[i].O { case INC: @@ -126,10 +150,10 @@ func _run(program []Op, tape *Tape) { tape.Move(program[i].V) case LOOP: for tape.Get() > 0 { - _run(program[i].Loop, tape) + _run(program[i].Loop, tape, p) } case PRINT: - fmt.Printf("%c", tape.Get()) + p.Print(tape.Get()) } } } @@ -142,15 +166,37 @@ func notify(msg string) { } } +func verify() { + text := `++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.> +---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.` + p_left := NewPrinter(true) + NewProgram(text).Run(p_left) + left := p_left.GetChecksum() + + p_right := NewPrinter(true) + for _, c := range "Hello World!\n" { + p_right.Print(int(c)) + } + right := p_right.GetChecksum() + if left != right { + log.Fatalf("%+v != %+v\n", left, right) + } +} + func main() { - Code, err := ioutil.ReadFile(os.Args[1]) + verify() + code, err := ioutil.ReadFile(os.Args[1]) if err != nil { panic(fmt.Sprintf("%v", err)) } + text := string(code) + p := NewPrinter(os.Getenv("QUIET") != "") notify(fmt.Sprintf("%s\t%d", runtime.Compiler, os.Getpid())) - - NewProgram(string(Code)).Run() - + NewProgram(text).Run(p) notify("stop") + + if p.quiet { + fmt.Printf("Output checksum: %d\n", p.GetChecksum()) + } } diff --git a/brainfuck/bf.hs b/brainfuck/bf.hs index 073367fa..4fd3105c 100644 --- a/brainfuck/bf.hs +++ b/brainfuck/bf.hs @@ -1,18 +1,45 @@ +{-# LANGUAGE QuasiQuotes #-} +{-# LANGUAGE ScopedTypeVariables #-} + module Main where import qualified Data.Array.Base as ArrayBase import qualified Data.Array.Unboxed as UArray import qualified Data.ByteString.Char8 as C -import Data.Char (chr) -import System.Environment (getArgs) -import System.IO (hFlush, stdout) -import Network.Simple.TCP +import Control.Exception +import Control.Monad +import Data.Bits +import Data.Char +import Data.Maybe +import Network.Socket +import Network.Socket.ByteString +import System.Environment +import System.Exit +import System.IO import System.Posix (getProcessID) +import Text.RawString.QQ -data Op = Inc Int | Move Int | Print | Loop [Op] deriving Show +data Op = Inc Int | Move Int | Print | Loop [Op] data Tape = Tape { tapeData :: UArray.UArray Int Int , tapePos :: Int - } deriving Show + } +data Printer = Printer { sum1 :: Int + , sum2 :: Int + , quiet :: Bool + } + +write :: Printer -> Int -> IO Printer +write p n = if quiet p + then do + let newP = p {sum1 = mod (sum1 p + n) 255} + return newP {sum2 = mod (sum1 newP + sum2 newP) 255} + else do + putStr [chr n] + hFlush stdout + return p + +getChecksum :: Printer -> Int +getChecksum p = (sum2 p `shiftL` 8) .|. sum1 p current :: Tape -> Int current tape = ArrayBase.unsafeAt (tapeData tape) (tapePos tape) @@ -22,7 +49,7 @@ inc delta tape = tape { tapeData = newData } where newData = ArrayBase.unsafeReplace (tapeData tape) - [(tapePos tape, (current tape) + delta)] + [(tapePos tape, current tape + delta)] move :: Int -> Tape -> Tape move m tape = @@ -30,7 +57,7 @@ move m tape = where curData = tapeData tape len = ArrayBase.numElements curData - newPos = (tapePos tape) + m + newPos = tapePos tape + m asc = ArrayBase.assocs curData newData = if newPos < len then curData @@ -49,37 +76,67 @@ parse (c:cs, acc) = '[' -> parse (newCs, Loop loop:acc) where (newCs, loop) = parse (cs, []) ']' -> (cs, reverse acc) - otherwise -> parse (cs, acc) + _ -> parse (cs, acc) -run :: [Op] -> Tape -> IO Tape -run [] tape = return tape -run (op:ops) tape = do +run :: [Op] -> Tape -> Printer -> IO (Tape, Printer) +run [] tape p = return (tape, p) +run (op:ops) tape p = do case op of - Inc d -> run ops $ inc d tape - Move m -> run ops $ move m tape + Inc d -> run ops (inc d tape) p + Move m -> run ops (move m tape) p Print -> do - putStr $ [chr $ current tape] - hFlush stdout - run ops tape + newP <- write p $ current tape + run ops tape newP Loop loop -> do if current tape == 0 - then run ops tape + then run ops tape p else do - newTape <- run loop tape - run (op:ops) newTape + (newTape, newP) <- run loop tape p + run (op:ops) newTape newP + +notify :: String -> IO () +notify msg = withSocketsDo $ do + addr <- resolve + catch (_notify addr) (\(_ :: IOException) -> return ()) + where + writeMsg s = sendAll s $ C.pack msg + resolve = do + let hints = defaultHints { addrSocketType = Stream } + head <$> getAddrInfo (Just hints) (Just "localhost") (Just "9001") + _notify addr = bracket (openSocket addr) close $ \sock -> do + connect sock $ addrAddress addr + writeMsg sock -notify msg = do - connect "localhost" "9001" $ \(socket, _) -> do - send socket $ C.pack msg +verify :: IO () +verify = do + let source = [r|++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>\ + ---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.|] + let (_, ops) = parse (source, []) + (_, pLeft) <- run ops + (Tape (ArrayBase.unsafeArray (0, 0) [(0, 0)]) 0) + Printer {sum1=0, sum2=0, quiet=True} + let left = getChecksum pLeft + + pRight <- foldM (\p c -> write p $ ord c) + (Printer {sum1=0, sum2=0, quiet=True}) + "Hello World!\n" + let right = getChecksum pRight + when (left /= right) + $ die $ show left ++ " != " ++ show right +main :: IO () main = do + verify [filename] <- getArgs source <- readFile filename + quiet_env <- lookupEnv "QUIET" + let p = Printer {sum1=0, sum2=0, quiet=isJust quiet_env} pid <- getProcessID notify $ "Haskell\t" ++ show pid - let (_, ops) = parse (source, []) - run ops (Tape (ArrayBase.unsafeArray (0, 0) [(0, 0)]) 0) - + (_, newP) <- run ops (Tape (ArrayBase.unsafeArray (0, 0) [(0, 0)]) 0) p notify "stop" + + when (quiet newP) + $ do putStrLn $ "Output checksum: " ++ show (getChecksum newP) diff --git a/brainfuck/bf.java b/brainfuck/bf.java index 4cbf52fb..c16756fa 100644 --- a/brainfuck/bf.java +++ b/brainfuck/bf.java @@ -63,12 +63,37 @@ public void move(final int x) { } } + static final class Printer { + private int sum1 = 0; + private int sum2 = 0; + final boolean quiet; + + Printer(boolean quiet) { + this.quiet = quiet; + } + + void print(int n) { + if (quiet) { + sum1 = (sum1 + n) % 255; + sum2 = (sum2 + sum1) % 255; + } else { + System.out.print((char)n); + } + } + + int getChecksum() { + return (sum2 << 8) | sum1; + } + } + public static final class Program { private final Op[] ops; + private final Printer p; - public Program(final String code) { + public Program(final String code, final Printer p) { CharacterIterator it = new CharacterIterator(code); ops = parse(it); + this.p = p; } private Op[] parse(final CharacterIterator it) { @@ -110,7 +135,7 @@ private void _run(final Op[] program, final Tape tape) { case INC: tape.inc(op.v); break; case MOVE: tape.move(op.v); break; case LOOP: while (tape.get() > 0) _run(op.loop, tape); break; - case PRINT: System.out.print( (char) tape.get() ); break; + case PRINT: p.print(tape.get()); break; } } } @@ -124,16 +149,38 @@ private static void notify(final String msg) { } } - public static void main( final String[] args ) throws IOException { - final String code = new String(Files.readAllBytes( Paths.get( args[0] ) )); + private static void verify() { + final var text = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>" + + "---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++."; + final var pLeft = new Printer(true); + new Program(text, pLeft).run(); + final var left = pLeft.getChecksum(); - notify("Java\t" + ProcessHandle.current().pid()); - var start_time = System.currentTimeMillis(); + final var pRight = new Printer(true); + for (final var c : "Hello World!\n".toCharArray()) { + pRight.print(c); + } + final var right = pRight.getChecksum(); + if (left != right) { + System.err.printf("%d != %d\n", left, right); + System.exit(1); + } + } - final Program program = new Program(code); - program.run(); - System.err.println("time: " + (System.currentTimeMillis()-start_time)/1e3+"s"); + public static void main( final String[] args ) throws IOException { + verify(); + final var code = new String(Files.readAllBytes( Paths.get( args[0] ) )); + final var p = new Printer(System.getenv("QUIET") != null); + notify("Java\t" + ProcessHandle.current().pid()); + final var startTime = System.currentTimeMillis(); + new Program(code, p).run(); + final var elapsed = (System.currentTimeMillis()-startTime) / 1e3; notify("stop"); + + System.err.println("time: " + elapsed +"s"); + if (p.quiet) { + System.out.println("Output checksum: " + p.getChecksum()); + } } } diff --git a/brainfuck/bf.jl b/brainfuck/bf.jl index b47fdec9..ee680404 100644 --- a/brainfuck/bf.jl +++ b/brainfuck/bf.jl @@ -4,21 +4,24 @@ using Sockets mutable struct Tape count::Int pos::Int - tape::Vector{UInt8} + tape::Vector{Int} end Tape() = Tape(0, 1, [0]) +mutable struct Printer + sum1::Int + sum2::Int + quiet::Bool +end + +Printer(quiet) = Printer(0, 0, quiet) + +getChecksum(p::Printer) = (p.sum2 << 8) | p.sum1 + Base.getindex(t::Tape) = t.tape[t.pos] Base.setindex!(t::Tape, v) = t.tape[t.pos] = v -function Base.show(io::IO, t::Tape) - print(io, "[$(t.count)] ") - for i = 1:length(t.tape) - print(io, t.tape[i], i == t.pos ? "* " : " ") - end -end - Base.:(==)(a::Tape, b::Tape) = a.tape == b.tape function left!(t::Tape) @@ -37,17 +40,16 @@ end inc!(t::Tape) = t[] += 0x01 dec!(t::Tape) = t[] -= 0x01 -function read!(t::Tape, io::IO) - t[] = read(io, UInt8) -end - -function write!(t::Tape, io::IO) - write(io, t[]) +function write!(n::Int, p::Printer) + if p.quiet + p.sum1 = (p.sum1 + n) % 255 + p.sum2 = (p.sum2 + p.sum1) % 255 + else + write(stdout, n) + end end -# Gets ~370 MHz - -function interpret(t::Tape, bf; input::IO = stdin, output::IO = stdout) +function interpret(t::Tape, bf, p::Printer) loops = Int[] scan = 0 ip = 1 @@ -59,26 +61,23 @@ function interpret(t::Tape, bf; input::IO = stdin, output::IO = stdout) elseif op == ']' scan > 0 ? (scan -= 1) : t[] == 0 ? pop!(loops) : (ip = loops[end]) elseif scan == 0 - op == '+' ? inc!(t) : - op == '-' ? dec!(t) : - op == '<' ? left!(t) : - op == '>' ? right!(t) : - op == ',' ? read!(t, input) : - op == '.' ? write!(t, output) : op == '#' ? println(t) : nothing + if op == '+' + inc!(t) + elseif op == '-' + dec!(t) + elseif op == '<' + left!(t) + elseif op == '>' + right!(t) + elseif op == '.' + write!(t[], p) + end end ip += 1 end return t end -interpret(t::Tape, bf::String; kws...) = interpret(t, collect(bf); kws...) - -interpret(bf; kws...) = interpret(Tape(), bf; kws...) - -function main(text) - interpret(text) -end - function notify(msg) try socket = connect("localhost", 9001) @@ -89,15 +88,37 @@ function notify(msg) end end +function verify() + text = """++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.> + ---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.""" + pLeft = Printer(true) + interpret(Tape(), collect(text), pLeft) + left = getChecksum(pLeft) + + pRight = Printer(true) + for c in "Hello World!\n" + write!(convert(Int, c), pRight) + end + right = getChecksum(pRight) + + if left != right + println(stderr, "$(left) != $(right)") + exit(1) + end +end + if abspath(PROGRAM_FILE) == @__FILE__ + verify() text = open(ARGS[1]) do file read(file, String) end + p = Printer(haskey(ENV, "QUIET")) notify("Julia\t$(getpid())") - - x = @timed main(text) - println("Elapsed: $(x[2]), Allocated: $(x[3]), GC Time: $(x[4])") - + interpret(Tape(), collect(text), p) notify("stop") + + if p.quiet + println("Output checksum: $(getChecksum(p))") + end end diff --git a/brainfuck/bf.js b/brainfuck/bf.js index a31925c3..eeaec0b7 100644 --- a/brainfuck/bf.js +++ b/brainfuck/bf.js @@ -1,28 +1,67 @@ -function StringIterator(str){ - this.str = str; - this.current = 0; - this.last = str.length - 1; - - this.done = function(){ - if (this.current > this.last) - return true; - else - return false; - }; - - this.next = function(){ - if (this.current > this.last) - throw StopIteration; - else - return this.str[this.current++]; - }; +'use strict'; + +const assert = require("assert"); +const fs = require("fs"); +const net = require('net'); + +class StringIterator { + constructor(str) { + this.str = str; + this.current = 0; + this.last = str.length - 1; + } + + done() { + return this.current > this.last; + } + + next() { + if (this.current > this.last) + throw StopIteration; + else + return this.str[this.current++]; + } } -var Tape = function() { - var pos = 0, tape = [0]; - this.inc = function(x) { tape[pos] += x; } - this.move = function(x) { pos += x; while (pos >= tape.length) tape.push(0); } - this.get = function() { return tape[pos]; } +class Tape { + constructor() { + this.pos = 0; + this.tape = [0]; + } + + inc(x) { + this.tape[this.pos] += x; + } + + move(x) { + this.pos += x; + while (this.pos >= this.tape.length) this.tape.push(0); + } + + get() { + return this.tape[this.pos]; + } +} + +class Printer { + constructor(quiet) { + this.sum1 = 0; + this.sum2 = 0; + this.quiet = quiet; + } + + print(n) { + if (this.quiet) { + this.sum1 = (this.sum1 + n) % 255; + this.sum2 = (this.sum2 + this.sum1) % 255; + } else { + process.stdout.write(String.fromCharCode(n)); + } + } + + get checksum() { + return (this.sum2 << 8) | this.sum1; + } } const INC = 1; @@ -30,57 +69,55 @@ const MOVE = 2; const LOOP = 3; const PRINT = 4; -function Op(op, v) { - this.op = op; - this.v = v; +class Op { + constructor(op, v) { + this.op = op; + this.v = v; + } } -var Brainfuck = function(text) { - var me = this; - - var parse = function(iterator) { - var res = []; - while (!iterator.done()) { - switch(iterator.next()) { - case '+': res.push(new Op(INC, 1)); break; - case '-': res.push(new Op(INC, -1)); break; - case '>': res.push(new Op(MOVE, 1)); break; - case '<': res.push(new Op(MOVE, -1)); break; - case '.': res.push(new Op(PRINT, 0)); break; - case '[': res.push(new Op(LOOP, parse(iterator))); break; - case ']': return res; - } - } - return res; - } - - me.ops = parse(new StringIterator(text)); - - var _run = function(ops, tape) { - for (var i = 0; i < ops.length; i++) { - var op = ops[i]; - switch(op.op) { - case INC: tape.inc(op.v); break; - case MOVE: tape.move(op.v); break; - case LOOP: while (tape.get() > 0) _run(op.v, tape); break; - case PRINT: process.stdout.write(String.fromCharCode(tape.get())); break; - } - } - }; - - me.run = function() { - _run(me.ops, new Tape()); - }; -} +class Brainfuck { + constructor(text, p) { + this.ops = this.parse(new StringIterator(text)); + this.p = p; + } + + parse(iterator) { + var res = []; + while (!iterator.done()) { + switch(iterator.next()) { + case '+': res.push(new Op(INC, 1)); break; + case '-': res.push(new Op(INC, -1)); break; + case '>': res.push(new Op(MOVE, 1)); break; + case '<': res.push(new Op(MOVE, -1)); break; + case '.': res.push(new Op(PRINT, 0)); break; + case '[': res.push(new Op(LOOP, this.parse(iterator))); break; + case ']': return res; + } + } + return res; + } -function main(text) { - var brainfuck = new Brainfuck(text); - brainfuck.run(); + _run(ops, tape) { + for (var i = 0; i < ops.length; i++) { + const op = ops[i]; + switch(op.op) { + case INC: tape.inc(op.v); break; + case MOVE: tape.move(op.v); break; + case LOOP: while (tape.get() > 0) this._run(op.v, tape); break; + case PRINT: this.p.print(tape.get()); break; + } + } + } + + run() { + this._run(this.ops, new Tape()); + } } function notify(msg) { return new Promise(resolve => { - const client = require('net').connect(9001, 'localhost', () => { + const client = net.connect(9001, 'localhost', () => { client.end(msg, 'utf8', () => { client.destroy(); resolve(); @@ -89,10 +126,31 @@ function notify(msg) { }); } +function verify() { + const text = `++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.> + ---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.`; + const p_left= new Printer(true); + new Brainfuck(text, p_left).run(); + const left = p_left.checksum; + + const p_right = new Printer(true); + for (const c of "Hello World!\n") { + p_right.print(c.charCodeAt(0)); + } + const right = p_right.checksum; + assert.deepStrictEqual(left, right); +} + (async function() { - var text = require('fs').readFileSync(process.argv[2].toString()).toString(); + verify(); + const text = fs.readFileSync(process.argv[2].toString()).toString(); + const p = new Printer(process.env.QUIET); - await notify(`Node.js\t${require('process').pid}`); - main(text); + await notify(`Node.js\t${process.pid}`); + new Brainfuck(text, p).run(); await notify('stop'); + + if (p.quiet) { + console.log(`Output checksum: ${p.checksum}`) + } })(); diff --git a/brainfuck/bf.lua b/brainfuck/bf.lua index ab5f026a..d13ab143 100644 --- a/brainfuck/bf.lua +++ b/brainfuck/bf.lua @@ -4,74 +4,99 @@ local PRINT = 3 local LOOP = 4 local function Tape() - local pos = 1; - local data = {0}; + local pos = 1 + local data = {0} local get = function() - return data[pos]; + return data[pos] end local inc = function(x) - data[pos] = data[pos] + x; + data[pos] = data[pos] + x end local move = function(x) - local length = #data; - pos = pos + x; + local length = #data + pos = pos + x for i = length + 1, pos do - data[i] = 0; + data[i] = 0 end end return { - get = get; - inc = inc; - move = move; - }; + get = get, + inc = inc, + move = move, + } end -local function Brainfuck(text) +local function Printer(quiet) + local sum1 = 0 + local sum2 = 0 + + local function print(n) + if quiet then + sum1 = (sum1 + n) % 255 + sum2 = (sum2 + sum1) % 255 + else + io.write(string.char(n)) + io.flush() + end + end + + local function get_checksum() + local bit32 = require "bit32" + return bit32.bor(bit32.lshift(sum2, 8), sum1) + end + + return { + print = print, + get_checksum = get_checksum, + quiet = quiet + } +end + +local function Brainfuck(text, p) local function parse(source, i) - local res = {}; + local res = {} while i <= source:len() do - local c = source:sub(i, i); + local c = source:sub(i, i) if c == "+" then - table.insert(res, {INC, 1}); + table.insert(res, {INC, 1}) elseif c == "-" then - table.insert(res, {INC, -1}); + table.insert(res, {INC, -1}) elseif c == ">" then - table.insert(res, {MOVE, 1}); + table.insert(res, {MOVE, 1}) elseif c == "<" then - table.insert(res, {MOVE, -1}); + table.insert(res, {MOVE, -1}) elseif c == "." then - table.insert(res, {PRINT}); + table.insert(res, {PRINT}) elseif c == "[" then - local loop_code; - loop_code, i = parse(source, i+1); - table.insert(res, {LOOP, loop_code}); + local loop_code + loop_code, i = parse(source, i+1) + table.insert(res, {LOOP, loop_code}) elseif c == "]" then break; end - i = i + 1; + i = i + 1 end - return res, i; + return res, i end local function _run(program, tape) for i = 1, #program do - local op = program[i]; - local operator = op[1]; + local op = program[i] + local operator = op[1] if operator == INC then - tape.inc(op[2]); + tape.inc(op[2]) elseif operator == MOVE then - tape.move(op[2]); + tape.move(op[2]) elseif operator == LOOP then while tape.get() > 0 do - _run(op[2], tape); + _run(op[2], tape) end elseif operator == PRINT then - io.write(string.char(tape.get())); - io.flush(); + p.print(tape.get()) end end end @@ -81,8 +106,8 @@ local function Brainfuck(text) end return { - run = run; - }; + run = run + } end local function notify(msg) @@ -95,17 +120,42 @@ local function notify(msg) end)() end -(function(arg) - local f = io.open(arg[1]) - local text = f:read("*a") - f:close() +local function verify() + text = [[ + ++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.> + ---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++. + ]] + local p_left = Printer(true) + Brainfuck(text, p_left).run() + local left = p_left.get_checksum() + + local p_right = Printer(true) + local str = "Hello World!\n" + for i = 1, #str do + p_right.print(string.byte(str, i)) + end + local right = p_right.get_checksum() + + if left ~= right then + print(string.format("%d != %d", left, right)) + os.exit(1) + end +end - local compiler = type(jit) == 'table' and "Lua/luajit" or "Lua" - local getpid = require 'posix.unistd'.getpid - notify(string.format("%s\t%d", compiler, getpid())) +(function(arg) + verify() + local f = io.open(arg[1]) + local text = f:read("*a") + f:close() + local p = Printer(os.getenv("QUIET")) - local brainfuck = Brainfuck(text) - brainfuck.run() + local compiler = type(jit) == 'table' and "Lua/luajit" or "Lua" + local getpid = require 'posix.unistd'.getpid + notify(string.format("%s\t%d", compiler, getpid())) + Brainfuck(text, p).run() + notify("stop") - notify("stop") + if p.quiet then + print(string.format("Output checksum: %d", p.get_checksum())) + end end)(arg) diff --git a/brainfuck/bf.ml b/brainfuck/bf.ml index 383f0a2b..fa9589cc 100644 --- a/brainfuck/bf.ml +++ b/brainfuck/bf.ml @@ -1,8 +1,26 @@ type op = Inc of int | Move of int | Print | Loop of op list type tape = - { data : int array; - pos : int; - } + { data : int array; + pos : int; + } +type printer = + { sum1 : int; + sum2: int; + quiet: bool; + } + +let print p n = + if p.quiet then + let new_sum1 = (p.sum1 + n) mod 255 in + let new_sum2 = (new_sum1 + p.sum2) mod 255 in + { sum1 = new_sum1; sum2 = new_sum2; quiet = true } + else ( + print_char (Char.chr n); + flush stdout; + p + ) + +let get_checksum p = (p.sum2 lsl 8) lor p.sum1 let current t = t.data.(t.pos) @@ -35,22 +53,21 @@ let rec parse (s, acc) = | ']' -> (rest, List.rev acc) | _ -> parse (rest, acc) -let rec run program t = +let rec run program t p = match program with - | [] -> t + | [] -> (t, p) | Inc d :: ops -> - inc d t; - run ops t - | Move m :: ops -> run ops (move m t) + inc d t; + run ops t p + | Move m :: ops -> run ops (move m t) p | Print :: ops -> - print_char (Char.chr (current t)); - flush stdout; - run ops t + let new_p = print p (current t) in + run ops t new_p | Loop loop_code :: ops -> - let rec loop t = - if current t = 0 then run ops t - else loop (run loop_code t) - in loop t + let rec loop (t, p) = + if current t = 0 then run ops t p + else loop (run loop_code t p) + in loop (t, p) let read_file filename = let s = ref "" in @@ -72,16 +89,38 @@ let notify msg = ~finally:(fun() -> close_out oc) with Unix.Unix_error _ -> () +let verify = + let source = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>\ + ---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++." in + let (_, ops) = parse(source, []) in + let p = { sum1 = 0; sum2 = 0; quiet = true } in + let (_, p_left) = run ops { data = [| 0 |]; pos = 0 } p in + let left = get_checksum p_left in + + let s = "Hello World!\n" in + let seq = List.init + (String.length s) + (fun i -> (Char.code (String.get s i))) in + let p_right = List.fold_left print p seq in + let right = get_checksum p_right in + if left != right then ( + Printf.eprintf "%d != %d\n" left right; + exit 1 + ) + let main = + verify; match Sys.argv with | [| _; filename |] -> - let source = read_file filename in - - let pid = Unix.getpid() in - notify(Printf.sprintf "OCaml\t%d" pid); + let source = read_file filename in + let quiet = Sys.getenv_opt "QUIET" in + let p = { sum1 = 0; sum2 = 0; quiet = Option.is_some quiet} in - let (_, ops) = parse(source, []) in - ignore(run ops { data = [| 0 |]; pos = 0 }); + notify(Printf.sprintf "OCaml\t%d" (Unix.getpid())); + let (_, ops) = parse(source, []) in + let (_, new_p) = run ops { data = [| 0 |]; pos = 0 } p in + notify "stop"; - notify "stop" + if new_p.quiet then + Printf.printf "Output checksum: %d\n" (get_checksum new_p) | _ -> exit 1 diff --git a/brainfuck/bf.nim b/brainfuck/bf.nim index de4f6e98..46a8fc52 100644 --- a/brainfuck/bf.nim +++ b/brainfuck/bf.nim @@ -1,6 +1,7 @@ import net -import strformat +import os import posix +import strformat type OpType = enum Inc, Move, Loop, Print @@ -16,25 +17,47 @@ type pos: int tape: seq[int] + Printer = object + sum1: int + sum2: int + quiet: bool + Program = distinct Ops -func initTape(): Tape = - result.pos = 0 - result.tape = newSeq[int](1) +proc newTape(): Tape = + Tape(pos: 0, tape: newSeq[int](1)) + +proc get(t: Tape): int = + t.tape[t.pos] -proc get(t: Tape): int {.inline.} = t.tape[t.pos] -proc inc(t: var Tape, x: int) {.inline.} = t.tape[t.pos] += x -proc move(t: var Tape, x: int) {.inline.} = +proc inc(t: var Tape, x: int) = + t.tape[t.pos] += x + +proc move(t: var Tape, x: int) = t.pos += x while t.pos >= t.tape.len: t.tape.setLen 2 * t.tape.len func newStringIterator(s: string): StringIterator = result = iterator(): char = - for i in s: - yield i + for i in s: + yield i + +proc newPrinter(quiet: bool): Printer = + Printer(sum1: 0, sum2: 0, quiet: quiet) + +proc print(p: var Printer, n: int) = + if p.quiet: + p.sum1 = (p.sum1 + n) mod 255 + p.sum2 = (p.sum2 + p.sum1) mod 255 + else: + stdout.write n.chr() + stdout.flushFile() -func parse(iter: StringIterator): Ops = +proc checksum(p: Printer): int = + (p.sum2 shl 8) or p.sum1 + +proc parse(iter: StringIterator): Ops = for i in iter(): case i of '+': result.add Op(op: Inc, val: 1) @@ -46,24 +69,23 @@ func parse(iter: StringIterator): Ops = of ']': break else: discard -func parse(code: string): Program = - let iter = newStringIterator code +proc parse(code: string): Program = + let iter = newStringIterator(code) result = Program parse iter -proc run(ops: Ops, t: var Tape) = +proc run(ops: Ops, t: var Tape, p: var Printer) = for op in ops: case op.op of Inc: t.inc op.val of Move: t.move op.val of Loop: - while t.get() > 0: run(op.loop, t) + while t.get() > 0: run(op.loop, t, p) of Print: - stdout.write t.get().chr() - stdout.flushFile() + p.print(t.get()) -proc run(ops: Program) = - var tape = initTape() - run Ops ops, tape +proc run(ops: Program, p: var Printer) = + var tape = newTape() + run Ops ops, tape, p proc notify(msg: string) = try: @@ -74,16 +96,32 @@ proc notify(msg: string) = except: discard -when isMainModule: - import os +proc verify() = + let text = """++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.> + ---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.""" + var p_left = newPrinter(true) + text.parse().run(p_left) + let left = p_left.checksum + + var p_right = newPrinter(true) + for c in "Hello World!\n": + p_right.print(ord(c)) + let right = p_right.checksum + if left != right: + stderr.writeLine(&"{left} != {right}") + quit(1) +when isMainModule: + verify() let text = paramStr(1).readFile() + var p = newPrinter(existsEnv("QUIET")) var compiler = "Nim/clang" when defined(gcc): compiler = "Nim/gcc" notify(&"{compiler}\t{getpid()}") - - text.parse().run() - + text.parse().run(p) notify("stop") + + if p.quiet: + echo &"Output checksum: {p.checksum}" diff --git a/brainfuck/bf.pl b/brainfuck/bf.pl index a90dad16..782dc217 100644 --- a/brainfuck/bf.pl +++ b/brainfuck/bf.pl @@ -1,7 +1,6 @@ -#! /usr/bin/env perl - -use v5.12; +use v5.32; use warnings; +no feature qw(indirect); use feature qw(signatures); no warnings qw(experimental); @@ -47,6 +46,32 @@ ($self, $x) } +package Printer; + +sub new ($class, $quiet) { + my $self = { + sum1 => 0, + sum2 => 0, + quiet => $quiet + }; + bless $self, $class; + return $self; +} + +sub print ($self, $n) { + if ($self->{quiet}) { + $self->{sum1} = ($self->{sum1} + $n) % 255; + $self->{sum2} = ($self->{sum2} + $self->{sum1}) % 255; + } else { + printf "%c", $n; + } +} + +sub checksum ($self) { + return ($self->{sum2} << 8) | $self->{sum1}; +} + + package Main; my $INC = 1; @@ -74,15 +99,15 @@ ($source, $i = 0) return ($repr, $i); } -sub run ($parsed, $tape) { +sub run ($parsed, $tape, $p) { foreach my $op (@$parsed) { CORE::given ($op->{op}) { when ($INC) { $tape->inc($op->{val}); } when ($MOVE) { $tape->move($op->{val}); } - when ($PRINT) { printf "%c", $tape->get(); } + when ($PRINT) { $p->print($tape->get()); } when ($LOOP) { while ($tape->get() > 0) { - run($op->{val}, $tape); + run($op->{val}, $tape, $p); } } } @@ -97,19 +122,43 @@ ($msg) close($socket); } +sub verify { + my $text = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.> + ---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++."; + my $p_left = Printer->new(1); + my @source = split(//, $text); + my ($parsed, $n) = parse(\@source); + run($parsed, Tape->new(), $p_left); + my $left = $p_left->checksum; + + my $p_right = Printer->new(1); + foreach my $c (split //, "Hello World!\n") { + $p_right->print(ord($c)); + } + my $right = $p_right->checksum; + + if ($left != $right) { + print STDERR "${left} != ${right}\n"; + exit(1); + } +} + if ($0 eq __FILE__) { + verify; open (FH, "<", shift) or die $!; undef $/; $| = 1; - my $text = [split //, ]; + read FH, my $text, -s FH; close(FH); + my $p = Printer->new($ENV{'QUIET'}); - my $pid = $$; - notify("Perl\t${pid}"); - - my ($parsed, $n) = parse($text); - my $tape = Tape->new(); - run($parsed, $tape); - + notify("Perl\t". $$); + my @source = split(//, $text); + my ($parsed, $n) = parse(\@source); + run($parsed, Tape->new(), $p); notify("stop"); + + if ($p->{quiet}) { + printf("Output checksum: %d\n", $p->checksum); + } } diff --git a/brainfuck/bf.rb b/brainfuck/bf.rb index a52a7762..600f6b23 100644 --- a/brainfuck/bf.rb +++ b/brainfuck/bf.rb @@ -31,9 +31,33 @@ def move(x) end end +class Printer + attr_reader :quiet + + def initialize(quiet) + @sum1 = 0 + @sum2 = 0 + @quiet = quiet + end + + def print(n) + if @quiet + @sum1 = (@sum1 + n) % 255 + @sum2 = (@sum2 + @sum1) % 255 + else + $stdout.print(n.chr) + end + end + + def checksum + (@sum2 << 8) | @sum1 + end +end + class Program - def initialize(code) + def initialize(code, p) @ops = parse code.chars.each + @p = p end def run @@ -48,7 +72,7 @@ def _run(program, tape) when :inc then tape.inc(op.val) when :move then tape.move(op.val) when :loop then _run(op.val, tape) while tape.get.positive? - when :print then print(tape.get.chr) + when :print then @p.print(tape.get) end end end @@ -77,7 +101,26 @@ def notify(msg) # standalone usage end +def verify + text = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.> + ---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++." + p_left = Printer.new(true) + Program.new(text, p_left).run + left = p_left.checksum + + p_right = Printer.new(true) + "Hello World!\n".each_char { |c| p_right.print(c.ord) } + + right = p_right.checksum + return unless left != right + + warn "#{left} != #{right}" + exit(1) +end + if __FILE__ == $PROGRAM_NAME + verify + engine = RUBY_ENGINE if engine == 'truffleruby' desc = RUBY_DESCRIPTION @@ -91,11 +134,11 @@ def notify(msg) end text = IO.read(ARGV[0]) + p = Printer.new(ENV.key?('QUIET')) - pid = Process.pid - notify("#{engine}\t#{pid}") - - Program.new(text).run - + notify("#{engine}\t#{Process.pid}") + Program.new(text, p).run notify('stop') + + puts "Output checksum: #{p.checksum}" if p.quiet end diff --git a/brainfuck/bf.rkt b/brainfuck/bf.rkt index 89a9aecf..9709093b 100644 --- a/brainfuck/bf.rkt +++ b/brainfuck/bf.rkt @@ -5,9 +5,28 @@ [unsafe-vector-set! vector-set!] [unsafe-fx+ +])) -(define-syntax-rule (define-match-expander* k r) (define-match-expander k r r)) -(define-match-expander* op (syntax-rules () [(_ op val) (cons op val)])) -(define-match-expander* tape (syntax-rules () [(_ data pos) (mcons data pos)])) +(struct op (op val)) +(struct tape ([data #:mutable] [pos #:mutable])) + +;;; Printer. + +(struct printer ([sum1 #:mutable] [sum2 #:mutable] quiet)) + +(define (print p n) + (if (printer-quiet p) + (begin + (set-printer-sum1! p (remainder + (+ (printer-sum1 p) n) + 255)) + (set-printer-sum2! p (remainder + (+ (printer-sum2 p) (printer-sum1 p)) + 255))) + (begin + (display (integer->char n)) + (flush-output)))) + +(define (get-checksum p) + (bitwise-ior (arithmetic-shift (printer-sum2 p) 8) (printer-sum1 p))) ;;; Vector and tape ops. @@ -22,17 +41,15 @@ new-vec]))])) (define (tape-get t) - (match-let ([(tape data pos) t]) - (vector-ref data pos))) + (vector-ref (tape-data t) (tape-pos t))) (define (tape-move! t n) - (match-let ([(tape data pos) t]) - (let ([new-pos (+ n pos)]) - (set-mcar! t (vector-grow-if-needed data new-pos)) - (set-mcdr! t new-pos)))) + (let ([new-pos (+ n (tape-pos t))]) + (set-tape-data! t (vector-grow-if-needed (tape-data t) new-pos)) + (set-tape-pos! t new-pos))) (define (tape-inc! t n) - (match-let ([(tape data pos) t]) + (let ((data (tape-data t)) (pos (tape-pos t))) (vector-set! data pos (+ n (vector-ref data pos))))) ;;; Parser. @@ -57,13 +74,12 @@ ;;; Interpreter. -(define (run parsed t) +(define (run parsed t p) (define step-op! (match-lambda [(op 'inc x) (tape-inc! t x)] [(op 'move x) (tape-move! t x)] - ['print (display (integer->char (tape-get t))) - (flush-output)] + ['print (print p (tape-get t))] [(op 'loop body) (let loop () (when (> (tape-get t) 0) (step-ops! body) @@ -84,12 +100,29 @@ (parameterize ([current-locale "C"]) (file->string path))) +(define (verify) + (define text "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>\ +---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.") + (define p-left (printer 0 0 #t)) + (define p-right (printer 0 0 #t)) + + (run (parse text) (tape (vector 0) 0) p-left) + (for-each + (lambda (c) (print p-right (char->integer c))) + (string->list "Hello World!\n")) + + (let ((left (get-checksum p-left)) + (right (get-checksum p-right))) + (when (not (eq? left right)) + (error 'verify "~s != ~s" left right)))) + (module+ main - (define text null) - (set! text (read-c (command-line #:args (filename) filename))) + (verify) + (define text (read-c (command-line #:args (filename) filename))) + (define p (printer 0 0 (getenv "QUIET"))) (notify (format "Racket\t~s" (getpid))) + (run (parse text) (tape (vector 0) 0) p) + (notify "stop") - (run (parse text) (tape (vector 0) 0)) - - (notify "stop")) + (when (printer-quiet p) (printf "Output checksum: ~s\n" (get-checksum p)))) diff --git a/brainfuck/bf.rs b/brainfuck/bf.rs index 77aeddf6..27e08acd 100644 --- a/brainfuck/bf.rs +++ b/brainfuck/bf.rs @@ -1,4 +1,6 @@ use std::io; +use std::fs; +use std::env; enum Op { Inc(i32), @@ -9,32 +11,54 @@ enum Op { use Op::*; struct Tape { - pos: usize, - tape: Vec + pos: usize, + tape: Vec } impl Tape { - fn new() -> Tape { Tape { pos: 0, tape: vec![0] } } - fn get(&self) -> i32 { self.tape[self.pos] } - fn getc(&self) -> char { self.get() as u8 as char } - fn inc(&mut self, x: i32) { self.tape[self.pos] += x; } - fn mov(&mut self, x: isize) { - self.pos = (self.pos as isize + x) as usize; - while self.pos >= self.tape.len() { self.tape.push(0); } - } + fn new() -> Tape { Tape { pos: 0, tape: vec![0] } } + fn get(&self) -> i32 { self.tape[self.pos] } + fn inc(&mut self, x: i32) { self.tape[self.pos] += x; } + fn mov(&mut self, x: isize) { + self.pos = (self.pos as isize + x) as usize; + while self.pos >= self.tape.len() { self.tape.push(0); } + } +} + +struct Printer { + sum1: i32, + sum2: i32, + quiet: bool +} + +impl Printer { + fn new(quiet: bool) -> Printer { Printer { sum1: 0, sum2: 0, quiet: quiet} } + + fn print(&mut self, n: i32) { + if self.quiet { + self.sum1 = (self.sum1 + n) % 255; + self.sum2 = (self.sum2 + self.sum1) % 255; + } else { + print!("{}", n as u8 as char); + io::Write::flush(&mut io::stdout()).unwrap(); + } + } + + fn get_checksum(&self) -> i32 { + (self.sum2 << 8) | self.sum1 + } } -fn _run(program: &[Op], tape: &mut Tape) { +fn _run(program: &[Op], tape: &mut Tape, p: &mut Printer) { for op in program { match *op { Inc(x) => tape.inc(x), Move(x) => tape.mov(x), Loop(ref program) => while tape.get() > 0 { - _run(program, tape); + _run(program, tape, p); }, Print => { - print!("{}", tape.getc()); - io::Write::flush(&mut io::stdout()).unwrap(); + p.print(tape.get()); } } } @@ -58,15 +82,15 @@ fn parse>(it: &mut I) -> Box<[Op]> { } struct Program { - ops: Box<[Op]> + ops: Box<[Op]> } impl Program { - fn new(code: String) -> Program { Program { ops: parse(&mut code.chars()) } } - fn run(&self) { - let mut tape = Tape::new(); - _run(&self.ops, &mut tape); - } + fn new(code: String) -> Program { Program { ops: parse(&mut code.chars()) } } + fn run(&self, p: &mut Printer) { + let mut tape = Tape::new(); + _run(&self.ops, &mut tape, p); + } } fn notify(msg: &str) { @@ -77,17 +101,36 @@ fn notify(msg: &str) { } } +fn verify() { + let s = String::from("++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.> + ---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++."); + let mut p_left = Printer::new(true); + Program::new(s).run(&mut p_left); + let left = p_left.get_checksum(); + + let mut p_right = Printer::new(true); + for c in "Hello World!\n".chars() { + p_right.print(c as i32); + } + let right = p_right.get_checksum(); + if left != right { + eprintln!("{:?} != {:?}", left, right); + std::process::exit(-1); + } +} + fn main() { - use std::fs; - use std::env; + verify(); let arg1 = env::args().nth(1).unwrap(); let s = fs::read_to_string(arg1).unwrap(); + let mut p = Printer::new(std::env::var("QUIET").is_ok()); notify(&format!("Rust\t{}", std::process::id())); - - let program = Program::new(s); - program.run(); - + Program::new(s).run(&mut p); notify("stop"); + + if p.quiet { + println!("Output checksum: {}", p.get_checksum()); + } } diff --git a/brainfuck/bf.scala b/brainfuck/bf.scala index 13913d00..8a4971fe 100644 --- a/brainfuck/bf.scala +++ b/brainfuck/bf.scala @@ -20,7 +20,23 @@ class Tape() { } } -class Program(text: String) { +class Printer(val quiet: Boolean) { + private var sum1: Int = 0 + private var sum2: Int = 0 + + def write(n: Int) = { + if (quiet) { + sum1 = (sum1 + n) % 255 + sum2 = (sum2 + sum1) % 255 + } else { + print(n.toChar) + } + } + + def checksum = (sum2 << 8) | sum1 +} + +class Program(text: String, p: Printer) { val ops: Array[Op] = parse(text.iterator) def parse(iterator: Iterator[Char]) : Array[Op] = { @@ -48,34 +64,50 @@ class Program(text: String) { case Inc(x) => tape.inc(x) case Move(x) => tape.move(x) case Loop(loop) => while (tape.get > 0) _run(loop, tape) - case Print => print(tape.get.toChar) + case Print => p.write(tape.get) } } } object BrainFuck { - def time(f: => Any) = { - val s = System.nanoTime - val ret = f - System.err.println("time: "+(System.nanoTime-s)/1e9+"s") - ret - } - def notify(msg: String): Unit = { scala.util.Using((new java.net.Socket("localhost", 9001)).getOutputStream()) { _.write(msg.getBytes()) } } + def verify = { + val text = """++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.> + ---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.""" + val pLeft = new Printer(true) + new Program(text, pLeft).run + val left = pLeft.checksum + + val pRight = new Printer(true) + for (c <- "Hello World!\n") { + pRight.write(c) + } + val right = pRight.checksum + if (left != right) { + System.err.println(s"${left} != ${right}") + System.exit(1) + } + } + def main(args: Array[String]): Unit = { val text = scala.util.Using(scala.io.Source.fromFile(args(0))) { _.mkString }.get + val p = new Printer(sys.env.get("QUIET").isDefined) notify(s"Scala\t${ProcessHandle.current().pid()}") + val s = System.nanoTime + new Program(text, p).run + val elapsed = (System.nanoTime - s) / 1e9 + notify("stop") - time { - new Program(text).run + System.err.println(s"time: $elapsed s") + if (p.quiet) { + System.out.println(s"Output checksum: ${p.checksum}"); } - notify("stop") } } diff --git a/brainfuck/bf.sml b/brainfuck/bf.sml index e122d3fd..298da81f 100644 --- a/brainfuck/bf.sml +++ b/brainfuck/bf.sml @@ -1,5 +1,28 @@ -type tape = { data : int array, pos : int } datatype opr = INC of int | MOVE of int | PRINT | LOOP of opr list +type tape = { data : int array, pos : int } +type printer = { sum1 : int, sum2: int, quiet: bool } + +fun print (n, (p : printer)) = + if #quiet p then + let + val newSum1 = (#sum1 p + n) mod 255 + val newSum2 = (newSum1 + #sum2 p) mod 255 + in + { sum1 = newSum1, sum2 = newSum2, quiet = true } + end + else + ( + TextIO.print (String.str (Char.chr n)); + TextIO.flushOut TextIO.stdOut; + p + ) + +fun getChecksum (p : printer) = + let + val left = IntInf.<< (IntInf.fromInt (#sum2 p), Word.fromInt 8) + in + IntInf.orb (left, IntInf.fromInt (#sum1 p)) + end fun current (t : tape) = Array.sub (#data t, #pos t) @@ -9,19 +32,19 @@ fun inc delta (t : tape) = fun move m (t : tape) = let - val new_pos = (#pos t) + m + val newPos = (#pos t) + m val len = Array.length (#data t) - val new_data = - if new_pos < len then #data t + val newData = + if newPos < len then #data t else let - val arr = Array.array (new_pos + 1, 0) + val arr = Array.array (newPos + 1, 0) val _ = Array.copy { src = #data t, dst = arr, di = 0 } in arr end in - { data = new_data, pos = new_pos } + { data = newData, pos = newPos } end fun parse (s, acc) = @@ -39,32 +62,27 @@ fun parse (s, acc) = | #"." => parse (rest, PRINT :: acc) | #"[" => let - val (new_s, loop_code) = parse (rest, []) + val (newS, loopCode) = parse (rest, []) in - parse (new_s, LOOP loop_code :: acc) + parse (newS, LOOP loopCode :: acc) end | #"]" => (rest, List.rev acc) | _ => parse (rest, acc) end -fun run program (t : tape) = +fun run program (t : tape) (p : printer)= case program of - [] => t - | INC d :: ops => (inc d t; run ops t) - | MOVE m :: ops => run ops (move m t) - | PRINT :: ops => - ( - TextIO.print (String.str (Char.chr (current t))); - TextIO.flushOut TextIO.stdOut; - run ops t - ) - | LOOP loop_code :: ops => - if current t = 0 then run ops t + [] => (t, p) + | INC d :: ops => (inc d t; run ops t p) + | MOVE m :: ops => run ops (move m t) p + | PRINT :: ops => run ops t (print ((current t), p)) + | LOOP loopCode :: ops => + if current t = 0 then run ops t p else let - val new_tape = run loop_code t + val (newTape, newP) = run loopCode t p in - run program new_tape + run program newTape newP end fun read_file filename = @@ -88,11 +106,29 @@ fun notify msg = end handle OS.SysErr _ => () -fun main source = +fun main source (p : printer) = let val (_, ops) = parse(source, []) in - run ops { data = Array.fromList [0], pos = 0 } + run ops { data = Array.fromList [0], pos = 0 } p + end + +fun verify () = + let + val source = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>" ^ + "---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++." + val p = { sum1 = 0, sum2 = 0, quiet = true } + val (_, pLeft) = main source p + val left = IntInf.toString (getChecksum pLeft) + + val seq = List.map Char.ord (explode("Hello World!\n")) + val pRight = List.foldl print p seq + val right = IntInf.toString (getChecksum pRight) + in + if left <> right then ( + TextIO.output (TextIO.stdErr, left ^ " != " ^ right ^ "\n"); + OS.Process.exit OS.Process.failure + ) else () end val () = @@ -104,9 +140,22 @@ val () = | _ => OS.Process.exit(OS.Process.failure) val pid = LargeWord.toInt (Posix.Process.pidToWord - (Posix.ProcEnv.getpid ())); + (Posix.ProcEnv.getpid ())) + val quiet = OS.Process.getEnv "QUIET" + val p = { sum1 = 0, sum2 = 0, quiet = isSome quiet } in + verify(); notify("MLton\t" ^ Int.toString pid); - main(source); - notify("stop") + let + val (_, newP) = main source p + in + notify("stop"); + if #quiet newP then + let + val checksum = IntInf.toString (getChecksum newP) + in + TextIO.print ("Output checksum: " ^ checksum ^ "\n") + end + else () + end end diff --git a/brainfuck/bf.ss b/brainfuck/bf.ss index 442215a4..3ad4918b 100644 --- a/brainfuck/bf.ss +++ b/brainfuck/bf.ss @@ -3,6 +3,26 @@ (define-record-type op (fields op val)) (define-record-type tape (fields data pos)) +;;; Printer. + +(define-record-type printer (fields (mutable sum1) (mutable sum2) quiet)) + +(define (print p n) + (if (printer-quiet p) + (begin + (printer-sum1-set! p (remainder + (+ (printer-sum1 p) n) + 255)) + (printer-sum2-set! p (remainder + (+ (printer-sum2 p) (printer-sum1 p)) + 255))) + (begin + (display (integer->char n)) + (flush-output-port)))) + +(define (get-checksum p) + (bitwise-ior (ash (printer-sum2 p) 8) (printer-sum1 p))) + ;;; Vector and tape ops. (define (vector-copy! dest dest-start src) @@ -59,24 +79,23 @@ ;;; Interpreter. -(define (run parsed t) +(define (run parsed t p) (if (null? parsed) t (let* ((op (op-op (car parsed))) (val (op-val (car parsed))) (rst (cdr parsed))) (case op - ((inc) (run rst (tape-inc! t val))) - ((move) (run rst (tape-move t val))) + ((inc) (run rst (tape-inc! t val) p)) + ((move) (run rst (tape-move t val) p)) ((print) - (display (integer->char (tape-get t))) - (flush-output-port) - (run rst t)) + (print p (tape-get t)) + (run rst t p)) ((loop) (if (> (tape-get t) 0) - (run parsed (run val t)) - (run rst t))) - (else (run rst t)))))) + (run parsed (run val t p) p) + (run rst t p))) + (else (run rst t p)))))) ;;; I/O. (load-shared-object "../common/libnotify/target/libnotify.so") @@ -100,15 +119,33 @@ (call-with-input-file path (lambda (port) (get-string-all port)))) -((lambda () - (define text '()) - (set! text (file->string (get-file-arg-or-exit))) +(define (verify) + (define text "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>\ +---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.") + (define p-left (make-printer 0 0 #t)) + (define p-right (make-printer 0 0 #t)) + + (run (parse text) (make-tape (make-vector 1) 0) p-left) + (for-each + (lambda (c) (print p-right (char->integer c))) + (string->list "Hello World!\n")) - (notify (format "Chez Scheme\t~s" (get-process-id))) + (let ((left (get-checksum p-left)) + (right (get-checksum p-right))) + (if (not (eq? left right)) + (errorf 'verify "~s != ~s" left right)))) - (run - (parse text) - (make-tape (make-vector 1) 0)) +(define (main) + (define text (file->string (get-file-arg-or-exit))) + (define p (make-printer 0 0 (getenv "QUIET"))) - (notify "stop")) - ) + (notify (format "Chez Scheme\t~s" (get-process-id))) + (run (parse text) (make-tape (make-vector 1) 0) p) + (notify "stop") + + (if (printer-quiet p) (printf "Output checksum: ~s\n" (get-checksum p)))) + +((lambda () + (verify) + (main) +)) diff --git a/brainfuck/bf.tcl b/brainfuck/bf.tcl index ebb964c1..e1b73750 100644 --- a/brainfuck/bf.tcl +++ b/brainfuck/bf.tcl @@ -1,6 +1,30 @@ package require Tcl 8.6 namespace eval bf { + ::oo::class create Printer { + variable sum1 sum2 quiet + + constructor q { + set sum1 0 + set sum2 0 + set quiet $q + } + + method print n { + if {$quiet} { + set sum1 [expr ($sum1 + $n) % 255] + set sum2 [expr ($sum2 + $sum1) % 255] + } else { + puts -nonewline [format %c $n] + flush stdout + } + } + + method checksum {} { + return [expr ($sum2 << 8) | $sum1] + } + } + proc parse source { set res {} while 1 { @@ -24,7 +48,7 @@ namespace eval bf { return [list $res $source] } - proc run {program tape pos} { + proc run {program tape pos p} { foreach x $program { lassign $x op val switch -exact -- $op { @@ -38,12 +62,11 @@ namespace eval bf { } } PRINT { - puts -nonewline [format %c [lindex $tape $pos]] - flush stdout + $p print [lindex $tape $pos] } LOOP { while {[lindex $tape $pos] > 0} { - lassign [run $val $tape $pos] tape pos + lassign [run $val $tape $pos $p] tape pos } } } @@ -52,9 +75,9 @@ namespace eval bf { } } -proc main text { - lassign [::bf::parse $text] program - ::bf::run $program 0 0 +proc main {text p} { + lassign [::bf::parse [split $text {}]] program + ::bf::run $program 0 0 $p } proc notify msg { @@ -65,12 +88,41 @@ proc notify msg { } } + +proc verify {} { + set text {++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.> + ---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.} + set p_left [::bf::Printer new 1] + main $text $p_left + set left [$p_left checksum] + $p_left destroy + + set p_right [::bf::Printer new 1] + foreach c [split "Hello World!\n" ""] { + $p_right print [scan $c %c] + } + set right [$p_right checksum] + $p_right destroy + if {$left != $right} { + puts stderr [format "%d != %d" $left $right] + exit 1 + } +} + apply {{filename} { + verify set f [open $filename] - set text [split [read $f] {}] + set text [read $f] close $f + set quiet [info exists ::env(QUIET)] + set p [::bf::Printer new $quiet] notify [format "%s\t%d" "Tcl (FP)" [pid]] - main $text + main $text $p notify "stop" + + if {$quiet} { + puts [format "Output checksum: %d" [$p checksum]] + } + $p destroy }} {*}$argv diff --git a/brainfuck/bf.v b/brainfuck/bf.v index 19939e63..9143fe01 100644 --- a/brainfuck/bf.v +++ b/brainfuck/bf.v @@ -57,6 +57,35 @@ fn (mut t Tape) move(x int) { } } +struct Printer { + quiet bool +mut: + sum1 int + sum2 int +} + +fn new_printer(quiet bool) Printer { + return Printer{ + sum1: 0 + sum2: 0 + quiet: quiet + } +} + +fn (mut p Printer) print(n int) { + if p.quiet { + p.sum1 = (p.sum1 + n) % 255 + p.sum2 = (p.sum2 + p.sum1) % 255 + } else { + print(byte(n).str()) + os.flush() + } +} + +fn (p Printer) get_checksum() int { + return (p.sum2 << 8) | p.sum1 +} + struct Program { ops []Op } @@ -105,12 +134,12 @@ fn parse(mut si StringIterator) []Op { return res } -fn (p Program) run() { +fn (p Program) run(mut printer Printer) { mut t := new_tape() - run_ops(p.ops, mut t) + run_ops(p.ops, mut t, mut printer) } -fn run_ops(ops []Op, mut tape Tape) { +fn run_ops(ops []Op, mut tape Tape, mut p Printer) { for op in ops { match op.o { inc { @@ -120,12 +149,11 @@ fn run_ops(ops []Op, mut tape Tape) { tape.move(op.v) } print { - print(byte(tape.get()).str()) - os.flush() + p.print(tape.get()) } loop { for tape.get() > 0 { - run_ops(op.loop, mut tape) + run_ops(op.loop, mut tape, mut p) } } else {} @@ -157,14 +185,33 @@ fn (mut si StringIterator) next() byte { } fn notify(msg string) { - sock := net.dial('127.0.0.1', 9001) or { + sock := net.dial_tcp('127.0.0.1:9001') or { return } - sock.write(msg) or { } - sock.close() or { } + defer { + sock.close() + } + sock.write_str(msg) or { } +} + +fn verify() { + text := '++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.> +---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.' + mut p_left := new_printer(true) + new_program(text).run(mut p_left) + left := p_left.get_checksum() + mut p_right := new_printer(true) + for c in 'Hello World!\n' { + p_right.print(c) + } + right := p_right.get_checksum() + if left != right { + panic('$left != $right') + } } fn main() { + verify() args := os.args mut filename := '' if args.len == 2 { @@ -177,11 +224,15 @@ fn main() { eprintln('Failed to open file $filename') return } + mut p := new_printer(os.getenv('QUIET') != '') mut lang := 'V/gcc' $if clang { lang = 'V/clang' } notify('$lang\t$C.getpid()') - new_program(code).run() + new_program(code).run(mut p) notify('stop') + if p.quiet { + println('Output checksum: $p.get_checksum()') + } } diff --git a/brainfuck/bf.vala b/brainfuck/bf.vala index d24929dc..f8e51f23 100644 --- a/brainfuck/bf.vala +++ b/brainfuck/bf.vala @@ -35,29 +35,51 @@ namespace Test { public Op.vnull(OpT _op, Op[] _l) { op = _op; loop = _l; v = 0; } } - public class Tape { - public int pos; - public int[] tape; - - public Tape() { - pos = 0; - tape = new int[1]; - } + class Tape { + private int pos = 0; + private int[] tape = new int[1]; public int Get() { return tape[pos]; } public void Inc(int x) { tape[pos] += x; } public void Move(int x) { pos += x; while (pos >= tape.length) tape.resize(tape.length*2);} } + class Printer { + private int sum1 = 0; + private int sum2 = 0; + public bool quiet; + + public Printer(bool quiet) { + this.quiet = quiet; + } + + public void print(int n) { + if (quiet) { + sum1 = (sum1 + n) % 255; + sum2 = (sum2 + sum1) % 255; + } else { + stdout.printf("%c", (char)n); + stdout.flush(); + } + } + + public int checksum { + get { + return (sum2 << 8) | sum1; + } + } + } + class Program { - public string code; - public int pos; - public Op[] ops; + private string code; + private int pos = 0; + private Op[] ops; + private Printer p; - Program(string text) { + Program(string text, Printer p) { code = text; - pos = 0; ops = parse(); + this.p = p; } private Op[] parse() { @@ -85,15 +107,34 @@ namespace Test { private void _run(Op[] program, Tape tape) { for (int i=0;i 0) _run(program[i].loop, tape); break; - case OpT.PRINT: stdout.printf("%c", (char)tape.Get()); stdout.flush(); break; + case OpT.INC: tape.Inc(program[i].v); break; + case OpT.MOVE: tape.Move(program[i].v); break; + case OpT.LOOP: while (tape.Get() > 0) _run(program[i].loop, tape); break; + case OpT.PRINT: p.print(tape.Get());break; } } } + static void verify() { + var text = """++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.> + ---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++."""; + var p_left = new Printer(true); + new Program(text, p_left).run(); + var left = p_left.checksum; + + var p_right = new Printer(true); + foreach (int c in "Hello World!\n".data) { + p_right.print(c); + } + var right = p_left.checksum; + if (left != right) { + stderr.printf("%d != %d\n", left, right); + Process.exit(1); + } + } + static void main(string[] args) { + verify(); string text; try { FileUtils.get_contents(args[1], out text); @@ -101,18 +142,21 @@ namespace Test { stdout.printf("Error: %s\n", e.message); } if (text.length == 0) { - Process.exit(-1); + Process.exit(1); } + var p = new Printer(Environment.get_variable("QUIET") != null); start(); - message("run"); - Timer timer = new Timer (); - var p = new Program(text); - p.run(); + var timer = new Timer(); + new Program(text, p).run(); timer.stop(); + notify("stop"); + message("time: " + timer.elapsed().to_string() + " s"); - notify("stop"); + if (p.quiet) { + stdout.printf("Output checksum: %d\n", p.checksum); + } } } } \ No newline at end of file diff --git a/brainfuck/bf2.kt b/brainfuck/bf2.kt index 11037918..2f52d1a9 100644 --- a/brainfuck/bf2.kt +++ b/brainfuck/bf2.kt @@ -21,7 +21,7 @@ class Tape { fun inc(x: Int) { tape[pos] += x } - + fun move(x: Int) { pos += x while (pos >= tape.size) { @@ -29,8 +29,24 @@ class Tape { } } } - -class Program(code: String) { + +class Printer(val quiet: Boolean) { + private var sum1: Int = 0 + private var sum2: Int = 0 + + fun print(n: Int) { + if (quiet) { + sum1 = (sum1 + n) % 255 + sum2 = (sum2 + sum1) % 255 + } else { + print(n.toChar()) + } + } + + fun getChecksum() = (sum2 shl 8) or sum1 +} + +class Program(code: String, val p: Printer) { private val ops: Array init { @@ -57,7 +73,7 @@ class Program(code: String) { fun run() { _run(ops, Tape()) } - + private fun _run(program: Array, tape: Tape) { for (op in program) { when (op) { @@ -66,7 +82,7 @@ class Program(code: String) { is Op.Loop -> while (tape.get() > 0) { _run(op.loop, tape) } - is Op.Print -> print(tape.get().toChar()) + is Op.Print -> p.print(tape.get()) } } } @@ -82,17 +98,38 @@ fun notify(msg: String) { } } +fun verify() { + val code = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>" + + "---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++."; + val pLeft = Printer(true) + Program(code, pLeft).run() + val left = pLeft.getChecksum() + + val pRight = Printer(true) + for (c in "Hello World!\n") { + pRight.print(c.toInt()) + } + val right = pRight.getChecksum() + if (left != right) { + System.err.println("${left} != ${right}") + System.exit(1) + } +} + @Throws(IOException::class) fun main(args: Array) { + verify() val code = String(Files.readAllBytes(Paths.get(args[0]))) + val p = Printer(!System.getenv("QUIET").isNullOrEmpty()) - val pid = ProcessHandle.current().pid() - notify("Kotlin\t${pid}") - val start_time = System.currentTimeMillis() - - val program = Program(code) - program.run() - System.err.println("time: ${(System.currentTimeMillis() - start_time) / 1e3}s") - + notify("Kotlin\t${ProcessHandle.current().pid()}") + val startTime = System.currentTimeMillis() + Program(code, p).run() + val timeDiff = (System.currentTimeMillis() - startTime) / 1e3 notify("stop") + + if (p.quiet) { + println("Output checksum: ${p.getChecksum()}") + } + System.err.println("time: ${timeDiff}s") } diff --git a/brainfuck/bf3.py b/brainfuck/bf3.py index 7796f9df..6c00cd27 100644 --- a/brainfuck/bf3.py +++ b/brainfuck/bf3.py @@ -2,6 +2,7 @@ import socket import sys import os +import itertools from pathlib import Path INC = 1 @@ -30,7 +31,26 @@ def inc(self, x): def move(self, x): self.pos += x while self.pos >= len(self.tape): - self.tape.append(0) + self.tape.extend(itertools.repeat(0, len(self.tape))) + + +class Printer(object): + def __init__(self, quiet): + self.sum1 = 0 + self.sum2 = 0 + self.quiet = quiet + + def print(self, n): + if self.quiet: + self.sum1 = (self.sum1 + n) % 255 + self.sum2 = (self.sum2 + self.sum1) % 255 + else: + sys.stdout.write(chr(n)) + sys.stdout.flush() + + @property + def checksum(self): + return (self.sum2 << 8) | self.sum1 def parse(iterator): @@ -59,7 +79,7 @@ def parse(iterator): return res -def _run(program, tape): +def _run(program, tape, p): for op in program: if op.op == INC: tape.inc(op.val) @@ -67,18 +87,17 @@ def _run(program, tape): tape.move(op.val) elif op.op == LOOP: while tape.get() > 0: - _run(op.val, tape) + _run(op.val, tape, p) elif op.op == PRINT: - sys.stdout.write(chr(tape.get())) - sys.stdout.flush() + p.print(tape.get()) class Program(object): def __init__(self, code): self.ops = parse(iter(code)) - def run(self): - _run(self.ops, Tape()) + def run(self, p): + _run(self.ops, Tape(), p) def notify(msg): @@ -87,9 +106,30 @@ def notify(msg): s.sendall(bytes(msg, "utf8")) +def verify(): + text = """++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.> + ---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.""" + p_left = Printer(True) + Program(text).run(p_left) + left = p_left.checksum + + p_right = Printer(True) + for c in "Hello World!\n": + p_right.print(ord(c)) + right = p_right.checksum + if left != right: + print("%s != %s" % (left, right), file=sys.stderr) + quit(1) + + if __name__ == "__main__": + verify() text = Path(sys.argv[1]).read_text() + p = Printer(os.getenv("QUIET")) notify("%s\t%d" % (platform.python_implementation(), os.getpid())) - Program(text).run() + Program(text).run(p) notify("stop") + + if p.quiet: + print("Output checksum:", p.checksum) diff --git a/brainfuck/bf_oo.tcl b/brainfuck/bf_oo.tcl index 920b309a..e4d34ac2 100644 --- a/brainfuck/bf_oo.tcl +++ b/brainfuck/bf_oo.tcl @@ -25,6 +25,30 @@ namespace eval bf {} { } } + ::oo::class create Printer { + variable sum1 sum2 quiet + + constructor q { + set sum1 0 + set sum2 0 + set quiet $q + } + + method print n { + if {$quiet} { + set sum1 [expr ($sum1 + $n) % 255] + set sum2 [expr ($sum2 + $sum1) % 255] + } else { + puts -nonewline [format %c $n] + flush stdout + } + } + + method checksum {} { + return [expr ($sum2 << 8) | $sum1] + } + } + proc parse source { set res {} while 1 { @@ -48,7 +72,7 @@ namespace eval bf {} { return [list $res $source] } - proc run {program tape} { + proc run {program tape p} { foreach x $program { lassign $x op val switch -exact -- $op { @@ -59,23 +83,22 @@ namespace eval bf {} { $tape move $val } PRINT { - puts -nonewline [format %c [$tape current]] - flush stdout + $p print [$tape current] } LOOP { while {[$tape current] > 0} { - run $val $tape + run $val $tape $p } } } } } -} +} -proc main text { - lassign [::bf::parse $text] program +proc main {text p} { + lassign [::bf::parse [split $text {}]] program set tape [::bf::Tape new] - ::bf::run $program $tape + ::bf::run $program $tape $p $tape destroy } @@ -87,12 +110,40 @@ proc notify msg { } } +proc verify {} { + set text {++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.> + ---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.} + set p_left [::bf::Printer new 1] + main $text $p_left + set left [$p_left checksum] + $p_left destroy + + set p_right [::bf::Printer new 1] + foreach c [split "Hello World!\n" ""] { + $p_right print [scan $c %c] + } + set right [$p_right checksum] + $p_right destroy + if {$left != $right} { + puts stderr [format "%d != %d" $left $right] + exit 1 + } +} + apply {{filename} { + verify set f [open $filename] - set text [split [read $f] {}] + set text [read $f] close $f + set quiet [info exists ::env(QUIET)] + set p [::bf::Printer new $quiet] notify [format "%s\t%d" "Tcl (OOP)" [pid]] - main $text + main $text $p notify "stop" + + if {$quiet} { + puts [format "Output checksum: %d" [$p checksum]] + } + $p destroy }} {*}$argv diff --git a/brainfuck/brainfuck.csproj b/brainfuck/brainfuck.csproj index a52b53e2..8eea1937 100644 --- a/brainfuck/brainfuck.csproj +++ b/brainfuck/brainfuck.csproj @@ -1,6 +1,6 @@ - netcoreapp3.1 + net5.0 Exe false diff --git a/brainfuck/fsharp/bf.fs b/brainfuck/fsharp/bf.fs index 0a1f33d8..4ac77232 100644 --- a/brainfuck/fsharp/bf.fs +++ b/brainfuck/fsharp/bf.fs @@ -2,84 +2,122 @@ open System open System.Diagnostics open System.IO -type op = Inc of int | Move of int | Print | Loop of op list -type tape = +type Op = Inc of int | Move of int | Print | Loop of Op list +type Tape = { data : int array; pos : int; - } + } +type Printer = + { sum1 : int; + sum2: int; + quiet: bool; + } + +let print p n = + if p.quiet then + let newSum1 = (p.sum1 + n) % 255 + let newSum2 = (newSum1 + p.sum2) % 255 + { sum1 = newSum1; sum2 = newSum2; quiet = true } + else + printf "%c" (char n) + Console.Out.Flush() + p + +let getChecksum p = (p.sum2 <<< 8) ||| p.sum1 let current t = - t.data.[t.pos] + t.data.[t.pos] let inc delta t = - t.data.[t.pos] <- t.data.[t.pos] + delta + t.data.[t.pos] <- t.data.[t.pos] + delta let move m t = - let new_pos = t.pos + m - let len = Array.length t.data - let new_data = - if new_pos < len then t.data - else Array.append t.data (Array.create (new_pos - len + 1) 0) - { data = new_data; pos = new_pos } + let newPos = t.pos + m + let len = Array.length t.data + let newData = + if newPos < len then t.data + else Array.append t.data (Array.create (newPos - len + 1) 0) + { data = newData; pos = newPos } let rec parse (s, acc) = - if s = "" then ("", List.rev acc) - else - let c = s.[0] - let rest = s.[1..((String.length s) - 1)] - match c with - | '+' -> parse (rest, Inc 1 :: acc) - | '-' -> parse (rest, Inc -1 :: acc) - | '>' -> parse (rest, Move 1 :: acc) - | '<' -> parse (rest, Move -1 :: acc) - | '.' -> parse (rest, Print :: acc) - | '[' -> - let (new_s, loop_code) = parse (rest, []) - parse (new_s, Loop loop_code :: acc) - | ']' -> (rest, List.rev acc) - | _ -> parse (rest, acc) - -let rec run program t = - match program with - | [] -> t - | Inc d :: ops -> - inc d t - run ops t - | Move m :: ops -> run ops (move m t) - | Print :: ops -> - t |> current |> char |> printf "%c" - Console.Out.Flush() - run ops t - | Loop loop_code :: ops -> - let rec loop t = - if current t = 0 then run ops t - else run loop_code t |> loop - in loop t + if s = "" then ("", List.rev acc) + else + let c = s.[0] + let rest = s.[1..((String.length s) - 1)] + match c with + | '+' -> parse (rest, Inc 1 :: acc) + | '-' -> parse (rest, Inc -1 :: acc) + | '>' -> parse (rest, Move 1 :: acc) + | '<' -> parse (rest, Move -1 :: acc) + | '.' -> parse (rest, Print :: acc) + | '[' -> + let (newS, loopCode) = parse (rest, []) + parse (newS, Loop loopCode :: acc) + | ']' -> (rest, List.rev acc) + | _ -> parse (rest, acc) + +let rec run program t p = + match program with + | [] -> (t, p) + | Inc d :: ops -> + inc d t + run ops t p + | Move m :: ops -> run ops (move m t) p + | Print :: ops -> + let newP = t |> current |> print p + run ops t newP + | Loop loopCode :: ops -> + let rec loop (t, p) = + if current t = 0 then run ops t p + else run loopCode t p |> loop + in loop (t, p) let notify (msg: string) = - try - use s = new System.Net.Sockets.TcpClient("localhost", 9001) - let data = System.Text.Encoding.UTF8.GetBytes(msg) - ignore(s.Client.Send(data)) - with _ -> () + try + use s = new System.Net.Sockets.TcpClient("localhost", 9001) + let data = System.Text.Encoding.UTF8.GetBytes(msg) + ignore(s.Client.Send(data)) + with _ -> () + +let verify = + let source = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>\ + ---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++." + let (_, ops) = parse(source, []) + let p = { sum1 = 0; sum2 = 0; quiet = true } + let (_, pLeft) = run ops { data = [| 0 |]; pos = 0 } p + let left = getChecksum pLeft + + let seq = [for c in "Hello World!\n" -> (int c)] + let pRight = List.fold print p seq + let right = getChecksum pRight + if left <> right then + Printf.eprintf "%d != %d\n" left right; + exit 1 [] let main argv = - match argv with - | [| filename |] -> - let source = - File.ReadAllLines filename - |> String.concat "\n" + verify + match argv with + | [| filename |] -> + let source = + File.ReadAllLines filename + |> String.concat "\n" + let quiet = Environment.GetEnvironmentVariable("QUIET") <> null + let p = { sum1 = 0; sum2 = 0; quiet = quiet} - let runtime = if isNull(Type.GetType("Mono.Runtime")) then ".NET Core" else "Mono" - notify(String.Format("F#/{0}\t{1}", runtime, Process.GetCurrentProcess().Id)) - let stopWatch = new Stopwatch() + let runtime = if isNull(Type.GetType("Mono.Runtime")) then ".NET Core" else "Mono" + notify(String.Format("F#/{0}\t{1}", runtime, Process.GetCurrentProcess().Id)) + let stopWatch = Stopwatch.StartNew() - let (_, ops) = parse(source, []) - let _ = run ops { data = [| 0 |]; pos = 0 } - stopWatch.Stop() - Console.Error.WriteLine("time: {0}s", stopWatch.Elapsed.TotalSeconds) + let (_, ops) = parse(source, []) + let (_, pNew) = run ops { data = [| 0 |]; pos = 0 } p + stopWatch.Stop() + let elapsed = stopWatch.Elapsed.TotalSeconds + + notify("stop") - notify("stop") - 0 - | _ -> 1 + Console.Error.WriteLine("time: {0}s", elapsed) + if pNew.quiet then + printf "Output checksum: %d\n" (getChecksum pNew) + 0 + | _ -> 1 diff --git a/brainfuck/fsharp/brainfuck.fsproj b/brainfuck/fsharp/brainfuck.fsproj index 8bb219e0..a16cc8ea 100644 --- a/brainfuck/fsharp/brainfuck.fsproj +++ b/brainfuck/fsharp/brainfuck.fsproj @@ -1,6 +1,6 @@ - netcoreapp3.1 + net5.0 Exe false diff --git a/common/commands.mk b/common/commands.mk index 03d54e50..5763f5a3 100644 --- a/common/commands.mk +++ b/common/commands.mk @@ -7,18 +7,18 @@ V_FLAGS := -prod CLANG_BUILD = clang $(CLANG_FLAGS) -o $@ $^ $(LIBNOTIFY_FLAGS) CRYSTAL_BUILD = crystal build --release --no-debug -o $@ $^ -DMD_BUILD = dmd -of$@ -O -release -inline $^ +DMD_BUILD = dmd -of$@ -O -release -inline -boundscheck=off $^ DOTNET_BUILD = dotnet build --nologo -v q $< -c Release DUB_BUILD = dub -q build --build=release --compiler=ldc2 --single $^ GCC_BUILD = gcc $(GCC_FLAGS) -std=c17 -o $@ $^ $(LIBNOTIFY_FLAGS) GCC_CPP_BUILD = g++ $(GCC_FLAGS) -std=c++2a -o $@ $^ $(LIBNOTIFY_FLAGS) GCC_GO_BUILD = gccgo -O3 -o $@ $^ -GDC_BUILD = gdc -o $@ -O3 -frelease -finline $^ -GHC_BUILD = ghc -v0 -O2 -fforce-recomp $^ -o $@ -outputdir $(@D) +GDC_BUILD = gdc -o $@ -O3 -frelease -finline -fbounds-check=off $^ +GHC_BUILD = ghc -v0 -O2 -fforce-recomp -Wall $^ -o $@ -outputdir $(@D) GO_BUILD = go build -o $@ $^ JAVAC_BUILD = javac -d $(@D) $^ KOTLINC_BUILD = kotlinc -include-runtime -jvm-target 14 -d $@ $^ -LDC2_BUILD = ldc2 -of$@ -O5 -release $^ +LDC2_BUILD = ldc2 -of$@ -O5 -release -boundscheck=off $^ MCS_BUILD = mcs -debug- -optimize+ -out:$@ $^ MLTON_BUILD = mlton -output $@ $^ NIM_CLANG_BUILD = nim c -o:$@ --cc:clang $(NIM_FLAGS) $^ @@ -112,6 +112,11 @@ $(dfmt): *.d | target dub -q run -y dfmt -- -i $^ @touch $@ +hlint := target/.hlint +$(hlint): *.hs | target + ~/.cabal/bin/hlint $^ + @touch $@ + .PHONY: libnotify libnotify: $(MAKE) -C ../common/libnotify diff --git a/docker/Dockerfile b/docker/Dockerfile index 01216cf7..960068cc 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -14,13 +14,13 @@ RUN apt-get update \ mono-devel nuget \ chezscheme gcc-10 gccgo-10 gdc-10 valac cpanminus \ luajit lua5.4 liblua5.4-dev libluajit-5.1-dev \ - tcl tcllib php elixir clang-10 opam + tcl tcllib php elixir clang-11 opam RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 10 \ && update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 10 \ && update-alternatives --install /usr/bin/gdc gdc /usr/bin/gdc-10 10 \ && update-alternatives --install /usr/bin/gccgo gccgo /usr/bin/gccgo-10 10 \ - && update-alternatives --install /usr/bin/clang clang /usr/bin/clang-10 10 \ + && update-alternatives --install /usr/bin/clang clang /usr/bin/clang-11 10 \ && rm -rf /var/lib/apt/lists/* /tmp/* # Requires for https://crates.io/crates/jq-sys in Debian @@ -49,14 +49,14 @@ RUN export VERSION=ruby-2.7.2 \ ENV PATH="/opt/ruby/bin:${PATH}" # https://pypy.org/download.html -ARG PYPY=pypy3.7-v7.3.2-linux64 +ARG PYPY=pypy3.7-v7.3.3-linux64 RUN wget --progress=dot:giga -O - \ https://downloads.python.org/pypy/$PYPY.tar.bz2 \ | tar -xj ENV PATH="/opt/$PYPY/bin:${PATH}" # https://www.scala-lang.org/download/ -ARG SCALA=2.13.3 +ARG SCALA=2.13.4 RUN wget --progress=dot:giga -O - \ https://downloads.lightbend.com/scala/$SCALA/scala-$SCALA.tgz \ | tar -xz @@ -92,7 +92,7 @@ ENV PATH="/opt/$NIM/bin/:${PATH}" # https://dlang.org/download.html RUN wget --progress=dot:giga -O - \ - http://downloads.dlang.org/releases/2.x/2.094.1/dmd.2.094.1.linux.tar.xz \ + http://downloads.dlang.org/releases/2.x/2.094.2/dmd.2.094.2.linux.tar.xz \ | tar -xJ ENV PATH="/opt/dmd2/linux/bin64/:${PATH}" @@ -104,21 +104,21 @@ RUN wget --progress=dot:giga -O - \ && ln -s /opt/jruby-$JRUBY/bin/jruby /usr/bin/jruby # https://julialang.org/downloads/ -ARG JULIA=julia-1.5.2 +ARG JULIA=julia-1.5.3 RUN wget --progress=dot:giga -O - \ https://julialang-s3.julialang.org/bin/linux/x64/1.5/$JULIA-linux-x86_64.tar.gz \ | tar -xz ENV PATH="/opt/$JULIA/bin/:${PATH}" # https://swift.org/download/ -ARG SWIFT=swift-5.3-RELEASE-ubuntu20.04 +ARG SWIFT=swift-5.3.1-RELEASE-ubuntu20.04 RUN wget --progress=dot:giga -O - \ - https://swift.org/builds/swift-5.3-release/ubuntu2004/swift-5.3-RELEASE/$SWIFT.tar.gz \ + https://swift.org/builds/swift-5.3.1-release/ubuntu2004/swift-5.3.1-RELEASE/$SWIFT.tar.gz \ | tar -xz \ && ln -s /opt/$SWIFT/usr/bin/swift /usr/bin/swift # https://clojure.org/community/downloads -ARG CLOJURE=1.10.1.727 +ARG CLOJURE=1.10.1.739 RUN wget --progress=dot:giga -O - \ https://download.clojure.org/install/linux-install-$CLOJURE.sh \ | bash -s @@ -139,12 +139,8 @@ ENV PATH="/opt/.ghcup/bin/:${PATH}" ARG GHC_VER=8.10.2 RUN ghcup install ghc $GHC_VER && ghcup set ghc $GHC_VER -# Shared packages for all Haskell code -RUN cabal update && cabal install network-simple --lib -ENV GHC_PACKAGE_PATH="~/.cabal/store/ghc-${GHC_VER}/package.db:" - # https://github.com/graalvm/graalvm-ce-builds/releases -ARG GRAALVM=20.2.0 +ARG GRAALVM=20.3.0 RUN wget --progress=dot:giga -O - \ https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-$GRAALVM/graalvm-ce-java11-linux-amd64-$GRAALVM.tar.gz \ | tar -xz \ @@ -167,13 +163,13 @@ RUN wget --progress=dot:giga -O - \ # https://github.com/dotnet/core/tree/master/release-notes RUN mkdir dotnet && wget --progress=dot:giga -O - \ - https://download.visualstudio.microsoft.com/download/pr/fdd9ecec-56b4-40f4-b762-d7efe24fc3cd/ffef51844c92afa6714528e10609a30f/dotnet-sdk-3.1.403-linux-x64.tar.gz \ + https://download.visualstudio.microsoft.com/download/pr/820db713-c9a5-466e-b72a-16f2f5ed00e2/628aa2a75f6aa270e77f4a83b3742fb8/dotnet-sdk-5.0.100-linux-x64.tar.gz \ | tar -xz -C dotnet ENV PATH="/opt/dotnet:${PATH}" ENV DOTNET_CLI_TELEMETRY_OPTOUT=1 # https://nodejs.org/en/download/current/ -ARG NODE=v15.0.1 +ARG NODE=v15.3.0 RUN wget --progress=dot:giga -O - \ https://nodejs.org/dist/$NODE/node-$NODE-linux-x64.tar.xz \ | tar -xJ @@ -181,7 +177,7 @@ ENV PATH="/opt/node-$NODE-linux-x64/bin/:${PATH}" # https://golang.org/dl/ RUN wget --progress=dot:giga -O - \ - https://golang.org/dl/go1.15.3.linux-amd64.tar.gz \ + https://golang.org/dl/go1.15.5.linux-amd64.tar.gz \ | tar -xz ENV PATH="/opt/go/bin/:${PATH}" @@ -191,11 +187,11 @@ RUN wget -O - https://sh.rustup.rs | sh -s -- -y # https://ocaml.org/releases/ ARG OCAML=4.11.1 -RUN opam init --disable-sandboxing -n --root=/opt/opam --compiler=$OCAML +RUN opam init --disable-sandboxing -n --root=/opt/opam --compiler=ocaml-base-compiler.$OCAML ENV PATH="/opt/opam/$OCAML/bin/:${PATH}" # https://kotlinlang.org/docs/tutorials/command-line.html -ARG KOTLIN=1.4.10 +ARG KOTLIN=1.4.20 RUN wget --progress=dot:giga \ https://github.com/JetBrains/kotlin/releases/download/v$KOTLIN/kotlin-compiler-$KOTLIN.zip \ && unzip kotlin-compiler-$KOTLIN.zip \ @@ -210,6 +206,12 @@ RUN git clone https://github.com/vlang/v.git /opt/v \ && make -j ENV PATH="/opt/v/:${PATH}" +# Shared packages for all Haskell code +RUN cabal update \ + && cabal install network raw-strings-qq --lib \ + && cabal install hlint +ENV GHC_PACKAGE_PATH="~/.cabal/store/ghc-${GHC_VER}/package.db:" + ARG SCRIPTS_VER=unknown COPY *.rb ./ diff --git a/havlak/Makefile b/havlak/Makefile index e0c44970..2e6a6359 100644 --- a/havlak/Makefile +++ b/havlak/Makefile @@ -15,7 +15,7 @@ executables := \ artifacts := $(executables) \ target/havlak_scala.jar \ target/havlak.exe \ - target/Release/netcoreapp3.1/havlak.dll + target/Release/net5.0/havlak.dll all_runners := $(patsubst %,run[%], $(artifacts)) \ run[pypy][havlak.py] \ @@ -59,8 +59,8 @@ target/havlak_nim_clang: havlak.nim | target target/havlak.exe: havlak.cs | target $(MCS_BUILD) -.PHONY: target/Release/netcoreapp3.1/havlak.dll -target/Release/netcoreapp3.1/havlak.dll: havlak.csproj | target +.PHONY: target/Release/net5.0/havlak.dll +target/Release/net5.0/havlak.dll: havlak.csproj | target $(DOTNET_BUILD) # Run @@ -85,7 +85,7 @@ run[target/havlak_scala.jar]:: run[%]: % run[target/havlak.exe]:: run[%]: % $(MONO_RUN) -run[target/Release/netcoreapp3.1/havlak.dll]:: run[%]: % +run[target/Release/net5.0/havlak.dll]:: run[%]: % $(DOTNET_RUN) run[pypy][havlak.py]:: run[pypy][%]: % diff --git a/havlak/havlak.csproj b/havlak/havlak.csproj index 5f35b2e5..8f612967 100644 --- a/havlak/havlak.csproj +++ b/havlak/havlak.csproj @@ -1,6 +1,6 @@ - netcoreapp3.1 + net5.0 Exe diff --git a/havlak/havlak.nim b/havlak/havlak.nim index d8ccd70b..fec6f11a 100644 --- a/havlak/havlak.nim +++ b/havlak/havlak.nim @@ -38,7 +38,7 @@ proc createNode(self: var Cfg, name: int): ref BasicBlock = node = self.basicBlockMap.getOrDefault(name) if node == nil: node = NewBasicBlock(name) - self.basicBlockMap.add name, node + self.basicBlockMap[name] = node if self.startNode == nil: self.startNode = node diff --git a/json/Makefile b/json/Makefile index 05c51130..53a739a5 100644 --- a/json/Makefile +++ b/json/Makefile @@ -41,8 +41,8 @@ executables := \ artifacts := $(executables) \ target/test.exe \ - target/Release/netcoreapp3.1/json.dll \ - json-core/target/Release/netcoreapp3.1/json-core.dll \ + target/Release/net5.0/json.dll \ + json-core/target/Release/net5.0/json-core.dll \ json-scala/target/application.jar all_runners := $(patsubst %,run[%], $(artifacts)) \ @@ -173,12 +173,12 @@ $(newtonsoft_json): | target target/test.exe: test.cs | $(newtonsoft_json) $(MCS_BUILD) -r:$(newtonsoft_json) -.PHONY: target/Release/netcoreapp3.1/json.dll -target/Release/netcoreapp3.1/json.dll: json.csproj | target +.PHONY: target/Release/net5.0/json.dll +target/Release/net5.0/json.dll: json.csproj | target $(DOTNET_BUILD) -.PHONY: json-core/target/Release/netcoreapp3.1/json-core.dll -json-core/target/Release/netcoreapp3.1/json-core.dll: json-core/json-core.csproj +.PHONY: json-core/target/Release/net5.0/json-core.dll +json-core/target/Release/net5.0/json-core.dll: json-core/json-core.csproj $(DOTNET_BUILD) .PHONY: target/json_hs @@ -196,9 +196,7 @@ json-scala/target/application.jar: simdjson-dir := target/simdjson $(simdjson-dir): | target - $(GIT_CLONE) "https://github.com/simdjson/simdjson.git" $@ \ - && cd $@/singleheader \ - && ./amalgamate.sh + $(GIT_CLONE) "https://github.com/simdjson/simdjson.git" $@ target/json_simdjson_cpp: test_simdjson.cpp | $(simdjson-dir) $(boost) libnotify $(GCC_CPP_BUILD) $(simdjson-dir)/singleheader/simdjson.cpp \ @@ -253,10 +251,10 @@ run[test.jl]:: run[%]: % | $(julia_fmt) run[target/test.exe]:: run[%]: % MONO_PATH=$(newtonsoft_json_dir) $(MONO_RUN) -run[target/Release/netcoreapp3.1/json.dll]:: run[%]: % +run[target/Release/net5.0/json.dll]:: run[%]: % $(DOTNET_RUN) -run[json-core/target/Release/netcoreapp3.1/json-core.dll]:: run[%]: % +run[json-core/target/Release/net5.0/json-core.dll]:: run[%]: % $(DOTNET_RUN) .PHONY: yajl-ruby diff --git a/json/json-core/json-core.csproj b/json/json-core/json-core.csproj index 5151945a..e1a6bd08 100644 --- a/json/json-core/json-core.csproj +++ b/json/json-core/json-core.csproj @@ -1,6 +1,6 @@ - netcoreapp3.1 + net5.0 Exe false diff --git a/json/json-hs/Makefile b/json/json-hs/Makefile index f0b92692..21c5ce73 100644 --- a/json/json-hs/Makefile +++ b/json/json-hs/Makefile @@ -1,6 +1,7 @@ undefine GHC_PACKAGE_PATH build: + ~/.cabal/bin/hlint . cabal update -v0 --builddir=target cabal build -v0 --builddir=target cabal install -v0 --overwrite-policy=always --installdir=../target/ --builddir=target diff --git a/json/json-hs/json-hs.cabal b/json/json-hs/json-hs.cabal index dcfc621b..0bb878c2 100644 --- a/json/json-hs/json-hs.cabal +++ b/json/json-hs/json-hs.cabal @@ -23,7 +23,7 @@ executable json_hs , json-stream , unordered-containers , vector - , network-simple + , network , unix ghc-options: -O2 -Wall diff --git a/json/json-hs/src/Main.hs b/json/json-hs/src/Main.hs index c8dfe659..f73c680b 100644 --- a/json/json-hs/src/Main.hs +++ b/json/json-hs/src/Main.hs @@ -1,16 +1,21 @@ -{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE RecordWildCards #-} +{-# LANGUAGE TupleSections #-} +{-# LANGUAGE ScopedTypeVariables #-} import qualified Data.Aeson as J import qualified Data.ByteString.Lazy as BL import qualified Data.ByteString.Char8 as C -import Data.JsonStream.Parser -import Data.List (foldl') -import GHC.Generics -import Network.Simple.TCP -import System.Posix (getProcessID) +import Control.Exception +import Control.Monad +import Data.JsonStream.Parser +import Data.List (foldl') +import GHC.Generics +import Network.Socket +import Network.Socket.ByteString import System.Exit +import System.Posix (getProcessID) data Coordinate = Coordinate { x :: !Double , y :: !Double @@ -20,9 +25,17 @@ instance J.FromJSON Coordinate data Res = Res !Double !Double !Double !Int notify :: String -> IO () -notify msg = do - connect "localhost" "9001" $ \(socket, _) -> do - send socket $ C.pack msg +notify msg = withSocketsDo $ do + addr <- resolve + catch (_notify addr) (\(_ :: IOException) -> return ()) + where + writeMsg s = sendAll s $ C.pack msg + resolve = do + let hints = defaultHints { addrSocketType = Stream } + head <$> getAddrInfo (Just hints) (Just "localhost") (Just "9001") + _notify addr = bracket (openSocket addr) close $ \sock -> do + connect sock $ addrAddress addr + writeMsg sock calc :: BL.ByteString -> Coordinate calc f = do @@ -33,29 +46,28 @@ calc f = do where parser_coordinates = "coordinates" .: arrayOf coord coord = Coordinate <$> ("x" .: real) <*> ("y" .: real) <*> ("z" .: real) - op (Res xsum ysum zsum count) (Coordinate{..}) = + op (Res xsum ysum zsum count) Coordinate{..} = Res (xsum + x) (ysum + y) (zsum + z) (count + 1) verify :: (Coordinate, BL.ByteString) -> IO () verify (right, v) = do - let left = calc $ v - if left /= right - then die $ show(left) ++ " != " ++ show(right) - else return () + let left = calc v + when (left /= right) + $ die $ show left ++ " != " ++ show right main :: IO () main = do let right = Coordinate 2.0 0.5 0.25 - let verification_pairs = map (\x -> (right, x)) + let verification_pairs = map (right,) ["{\"coordinates\":[{\"x\":2.0,\"y\":0.5,\"z\":0.25}]}", "{\"coordinates\":[{\"y\":0.5,\"x\":2.0,\"z\":0.25}]}"] - _ <- sequence (map verify verification_pairs) + mapM_ verify verification_pairs f <- BL.readFile "/tmp/1.json" pid <- getProcessID notify $ "Haskell\t" ++ show pid - results <- return $! calc $ f + results <- return $! calc f notify "stop" print results diff --git a/json/json-java/Maven.list b/json/json-java/Maven.list index c903e9a4..76cc1648 100644 --- a/json/json-java/Maven.list +++ b/json/json-java/Maven.list @@ -2,4 +2,4 @@ # # lines starting with # are ignored # -com.dslplatform:dsl-json-java8:1.9.6 +com.dslplatform:dsl-json-java8:1.9.7 diff --git a/json/json-scala/Maven.list b/json/json-scala/Maven.list index 0dc0b7e7..1b1137e9 100644 --- a/json/json-scala/Maven.list +++ b/json/json-scala/Maven.list @@ -2,4 +2,4 @@ # # lines starting with # are ignored # -com.dslplatform:dsl-json-scala_2.13:1.9.6 +com.dslplatform:dsl-json-scala_2.13:1.9.7 diff --git a/json/json.csproj b/json/json.csproj index 9232933d..5bda879e 100644 --- a/json/json.csproj +++ b/json/json.csproj @@ -1,6 +1,6 @@ - netcoreapp3.1 + net5.0 Exe false diff --git a/json/json.rs/Cargo.lock b/json/json.rs/Cargo.lock index 7cbc6892..a6dc95a4 100644 --- a/json/json.rs/Cargo.lock +++ b/json/json.rs/Cargo.lock @@ -4,109 +4,107 @@ name = "itoa" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" [[package]] name = "jq-rs" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9cfaeae42ef96b227ab787558cc7bbd5f1dfe96b4df7c63f92853017751b0e4" dependencies = [ - "jq-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "jq-sys", ] [[package]] name = "jq-sys" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81b65b7e54bd2fffc8cb20cbcf19f40d3158dab5cf5b5adb1f65f9b35eba4c48" dependencies = [ - "pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config", ] [[package]] name = "json-rs" version = "0.0.1" dependencies = [ - "jq-rs 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.116 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.116 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.57 (registry+https://github.com/rust-lang/crates.io-index)", + "jq-rs", + "serde", + "serde_derive", + "serde_json", ] [[package]] name = "pkg-config" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" [[package]] name = "proc-macro2" -version = "1.0.19" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" dependencies = [ - "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid", ] [[package]] name = "quote" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" dependencies = [ - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", ] [[package]] name = "ryu" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "serde" -version = "1.0.116" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a" [[package]] name = "serde_derive" -version = "1.0.116" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbd1ae72adb44aab48f325a02444a5fc079349a8d804c1fc922aed3f7454c74e" dependencies = [ - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "serde_json" -version = "1.0.57" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcac07dbffa1c65e7f816ab9eba78eb142c6d44410f4eeba1e26e4f5dfa56b95" dependencies = [ - "itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.116 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa", + "ryu", + "serde", ] [[package]] name = "syn" -version = "1.0.39" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b4f34193997d92804d359ed09953e25d5138df6bcc055a71bf68ee89fdf9223" dependencies = [ - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "unicode-xid", ] [[package]] name = "unicode-xid" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" -"checksum jq-rs 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c9cfaeae42ef96b227ab787558cc7bbd5f1dfe96b4df7c63f92853017751b0e4" -"checksum jq-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "81b65b7e54bd2fffc8cb20cbcf19f40d3158dab5cf5b5adb1f65f9b35eba4c48" -"checksum pkg-config 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)" = "d36492546b6af1463394d46f0c834346f31548646f6ba10849802c9c9a27ac33" -"checksum proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12" -"checksum quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" -"checksum ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" -"checksum serde 1.0.116 (registry+https://github.com/rust-lang/crates.io-index)" = "96fe57af81d28386a513cbc6858332abc6117cfdb5999647c6444b8f43a370a5" -"checksum serde_derive 1.0.116 (registry+https://github.com/rust-lang/crates.io-index)" = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8" -"checksum serde_json 1.0.57 (registry+https://github.com/rust-lang/crates.io-index)" = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c" -"checksum syn 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "891d8d6567fe7c7f8835a3a98af4208f3846fba258c1bc3c31d6e506239f11f9" -"checksum unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" diff --git a/json/json.rs/Cargo.toml b/json/json.rs/Cargo.toml index 7d1114a0..3c533b64 100644 --- a/json/json.rs/Cargo.toml +++ b/json/json.rs/Cargo.toml @@ -4,9 +4,9 @@ version = "0.0.1" edition = "2018" [dependencies] -serde = "1.0.116" -serde_derive = "1.0.116" -serde_json = "1.0.57" +serde = "1.0.117" +serde_derive = "1.0.117" +serde_json = "1.0.59" jq-rs = "0.4.1" [profile.release] diff --git a/json/test-xs.pl b/json/test-xs.pl index e9679712..a663b531 100644 --- a/json/test-xs.pl +++ b/json/test-xs.pl @@ -1,7 +1,8 @@ -use v5.12; +use v5.32; use warnings; +no feature qw(indirect); use feature qw(signatures); -no warnings qw(experimental::signatures); +no warnings qw(experimental); use File::Slurper 'read_binary'; use Cpanel::JSON::XS 'decode_json'; diff --git a/json/test.d b/json/test.d index eef7bf45..cf273eb6 100644 --- a/json/test.d +++ b/json/test.d @@ -61,13 +61,13 @@ Coordinate calc(string text) void main() { - auto right = Coordinate(2.0, 0.5, 0.25); + immutable right = Coordinate(2.0, 0.5, 0.25); foreach (v; [ `{"coordinates":[{"x":2.0,"y":0.5,"z":0.25}]}`, `{"coordinates":[{"y":0.5,"x":2.0,"z":0.25}]}` ]) { - auto left = calc(v); + immutable left = calc(v); if (left != right) { stderr.writefln("%s != %s", left, right); diff --git a/json/test.js b/json/test.js index f797caaf..edd27f95 100644 --- a/json/test.js +++ b/json/test.js @@ -1,16 +1,20 @@ +'use strict'; + const assert = require("assert"); +const fs = require("fs"); +const net = require('net'); function calc(text) { - var jobj = JSON.parse(text); + const jobj = JSON.parse(text); - var coordinates = jobj['coordinates']; - var len = coordinates.length; - var x = 0; - var y = 0; - var z = 0; + const coordinates = jobj['coordinates']; + const len = coordinates.length; + let x = 0; + let y = 0; + let z = 0; - for (var i = 0; i < coordinates.length; i++) { - coord = coordinates[i]; + for (let i = 0; i < coordinates.length; i++) { + const coord = coordinates[i]; x += coord['x']; y += coord['y']; z += coord['z']; @@ -25,7 +29,7 @@ function calc(text) { function notify(msg) { return new Promise(resolve => { - const client = require('net').connect(9001, 'localhost', () => { + const client = net.connect(9001, 'localhost', () => { client.end(msg, 'utf8', () => { client.destroy(); resolve(); @@ -43,9 +47,9 @@ function notify(msg) { assert.deepStrictEqual(left, right); }); - const text = require('fs').readFileSync("/tmp/1.json", "utf8"); + const text = fs.readFileSync("/tmp/1.json", "utf8"); - await notify(`Node.js\t${require('process').pid}`); + await notify(`Node.js\t${process.pid}`); const results = calc(text); await notify('stop'); diff --git a/json/test.pl b/json/test.pl index 8295a5fd..8b636d12 100644 --- a/json/test.pl +++ b/json/test.pl @@ -1,7 +1,8 @@ -use v5.12; +use v5.32; use warnings; +no feature qw(indirect); use feature qw(signatures); -no warnings qw(experimental::signatures); +no warnings qw(experimental); use File::Slurper 'read_binary'; use JSON::Tiny 'decode_json'; diff --git a/json/test.v b/json/test.v index 3a5c5d09..912b7e70 100644 --- a/json/test.v +++ b/json/test.v @@ -17,11 +17,13 @@ struct Coordinates { } fn notify(msg string) { - sock := net.dial('127.0.0.1', 9001) or { + sock := net.dial_tcp('127.0.0.1:9001') or { return } - sock.write(msg) or { } - sock.close() or { } + defer { + sock.close() + } + sock.write_str(msg) or { } } fn calc(s string) Coordinate { diff --git a/matmul/Makefile b/matmul/Makefile index 190e26c2..0333b154 100644 --- a/matmul/Makefile +++ b/matmul/Makefile @@ -27,7 +27,7 @@ artifacts := $(executables) \ target/matmul.class \ target/matmul-kt.jar \ target/matmul.exe \ - target/Release/netcoreapp3.1/matmul.dll + target/Release/net5.0/matmul.dll all_runners := $(patsubst %,run[%], $(artifacts)) \ run[matmul.js] \ @@ -119,8 +119,8 @@ target/matmul-kt.jar: matmul.kt | target target/matmul.exe: matmul.cs | target $(MCS_BUILD) -.PHONY: target/Release/netcoreapp3.1/matmul.dll -target/Release/netcoreapp3.1/matmul.dll: matmul.csproj | target +.PHONY: target/Release/net5.0/matmul.dll +target/Release/net5.0/matmul.dll: matmul.csproj | target $(DOTNET_BUILD) # Run @@ -150,7 +150,7 @@ run[target/matmul-kt.jar]:: run[%]: % run[target/matmul.exe]:: run[%]: % $(MONO_RUN) $(MSIZE) -run[target/Release/netcoreapp3.1/matmul.dll]:: run[%]: % +run[target/Release/net5.0/matmul.dll]:: run[%]: % $(DOTNET_RUN) $(MSIZE) run[matmul.js]:: run[%]: % diff --git a/matmul/matmul.csproj b/matmul/matmul.csproj index 5f35b2e5..8f612967 100644 --- a/matmul/matmul.csproj +++ b/matmul/matmul.csproj @@ -1,6 +1,6 @@ - netcoreapp3.1 + net5.0 Exe diff --git a/matmul/matmul.js b/matmul/matmul.js index 43349c78..c2dda41c 100644 --- a/matmul/matmul.js +++ b/matmul/matmul.js @@ -1,35 +1,37 @@ -var matrix = {} +'use strict'; -matrix.new = function (n) { - const a = new Array(n); - for (let i = 0; i < n; i++) a[i] = new Float64Array(n); - return a; -} +const net = require('net'); -matrix.T = function (a, n) { - const y = matrix.new(n); - for (let i = 0; i < n; i++) { - for (let j = 0; j < n; j++) { - y[i][j] = a[j][i]; +const matrix = { + new: function (n) { + const a = new Array(n); + for (let i = 0; i < n; i++) a[i] = new Float64Array(n); + return a; + }, + T: function (a, n) { + const y = matrix.new(n); + for (let i = 0; i < n; i++) { + for (let j = 0; j < n; j++) { + y[i][j] = a[j][i]; + } } - } - return y; -} - -matrix.mul = function (a, b, n) { - const y = matrix.new(n); - const c = matrix.T(b, n); - for (let i = 0; i < n; i++) { - for (let j = 0; j < n; j++) { - let sum = 0; - for (let k = 0; k < n; k++) sum = sum + a[i][k] * c[j][k]; - y[i][j] = sum; + return y; + }, + mul: function (a, b, n) { + const y = matrix.new(n); + const c = matrix.T(b, n); + for (let i = 0; i < n; i++) { + for (let j = 0; j < n; j++) { + let sum = 0; + for (let k = 0; k < n; k++) sum = sum + a[i][k] * c[j][k]; + y[i][j] = sum; + } } + return y; } - return y; -} +}; -matgen = function (n, seed) { +function matgen(n, seed) { const y = matrix.new(n); const tmp = seed / n / n; for (let i = 0; i < n; i++) { @@ -50,7 +52,7 @@ function calc(n) { function notify(msg) { return new Promise(resolve => { - const client = require('net').connect(9001, 'localhost', () => { + const client = net.connect(9001, 'localhost', () => { client.end(msg, 'utf8', () => { client.destroy(); resolve(); @@ -69,7 +71,7 @@ function notify(msg) { process.exit(1); } - await notify(`Node.js\t${require('process').pid}`); + await notify(`Node.js\t${process.pid}`); const results = calc(n); await notify('stop'); diff --git a/matmul/matmul.pl b/matmul/matmul.pl index eb450ca6..308652de 100644 --- a/matmul/matmul.pl +++ b/matmul/matmul.pl @@ -1,8 +1,9 @@ # rurban; distributed under the MIT license -use v5.12; +use v5.32; use warnings; +no feature qw(indirect); use feature qw(signatures); -no warnings qw(experimental::signatures); +no warnings qw(experimental); use Socket; diff --git a/matmul/matmul.v b/matmul/matmul.v index 14c951ff..55eca91d 100644 --- a/matmul/matmul.v +++ b/matmul/matmul.v @@ -50,11 +50,13 @@ fn matmul(a [][]f64, b [][]f64) [][]f64 { } fn notify(msg string) { - sock := net.dial('127.0.0.1', 9001) or { + sock := net.dial_tcp('127.0.0.1:9001') or { return } - sock.write(msg) or { } - sock.close() or { } + defer { + sock.close() + } + sock.write_str(msg) or { } } fn calc(n int) f64 {