[
  {
    "path": ".gitignore",
    "content": "/doc/\n/lib/\n/bin/\n/.shards/\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2017-2019 icyleaf\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "Makefile",
    "content": "CRYSTAL_BIN ?= $(shell which crystal)\nPREFIX ?= /usr/local\n\nrun: build\n\t./bin/fast-crystal\n\nclean:\n\trm -rf bin\n\tmkdir bin\n\nbuild: clean\n\t$(CRYSTAL_BIN) build --release --no-debug -o bin/fast-crystal src/fast-crystal.cr $(CRFLAGS)\n"
  },
  {
    "path": "README.md",
    "content": "# 💎 Fast Crystal\n\nIt's Crystal version based on [ruby version](https://github.com/JuanitoFatas/fast-ruby).\n\nEach idiom has a corresponding code example that resides in [code](code).\n\nAll results listed in README.md are running with Crystal 0.25.0 (2018-06-15) LLVM 5.0.1 on OS X 10.13.5.\n\nMachine information: MacBook Pro (Retina, 15-inch, Mid 2015), 2.2 GHz Intel Core i7, 16 GB 1600 MHz DDR3.\n\nYour results may vary, but you get the idea. : )\n\n> Doubt the results? please discuss in [Crystal Issue#4383](https://github.com/crystal-lang/crystal/issues/4383).\n\n**Let's write faster code, together! :trollface:**\n\n## Measurement Tool\n\nUse Crystal's built-in [benchmark](https://crystal-lang.org/api/0.22.0/Benchmark.html).\n\n## Run the Benchmarks\n\n```bash\n$ make\n```\n\n### Template\n\n```crystal\nrequire \"benchmark\"\n\ndef fast\nend\n\ndef slow\nend\n\nBenchmark.ips do |x|\n  x.report(\"fast code description\") { fast }\n  x.report(\"slow code description\") { slow }\nend\n```\n\n## Idioms\n\n### Index\n\n- [Array](#array)\n- [Enumerable](#enumerable)\n- [General](#general)\n- [Hash](#hash)\n- [NamedTuple](#namedtuple)\n- [Proc & Block](#proc--block)\n- [String](#string)\n\n> Test in Crystal 0.35.1 (2020-06-19)  LLVM: 10.0.0 Default target: x86_64-apple-macosx\n\n### Array\n\n#### `first` vs `index[0]` [code](code/array/first-vs-index[0].cr)\n\n```\n$ crystal build --release --no-debug -o bin/code/array/first-vs-index[0] code/array/first-vs-index[0].cr\n$ ./bin/code/array/first-vs-index[0]\n\nArray#first 265.31M (  3.77ns) (±11.17%)  0.0B/op   1.01× slower\n  Array#[0] 267.85M (  3.73ns) (± 6.86%)  0.0B/op        fastest\n```\n\n#### `insert` vs `unshift` [code](code/array/insert-vs-unshift.cr)\n\n```\n$ crystal build --release --no-debug -o bin/code/array/insert-vs-unshift code/array/insert-vs-unshift.cr\n$ ./bin/code/array/insert-vs-unshift\n\n Array#insert   1.30  (768.66ms) (± 1.33%)  1.5MB/op        fastest\nArray#unshift   1.29  (775.05ms) (± 1.81%)  1.5MB/op   1.01× slower\n```\n\n#### `last` vs `index[-1]` [code](code/array/last-vs-index[-1].cr)\n\n```\n$ crystal build --release --no-debug -o bin/code/array/last-vs-index[-1] code/array/last-vs-index[-1].cr\n$ ./bin/code/array/last-vs-index[-1]\n\nArray#[-1] 273.97M (  3.65ns) (± 4.16%)  0.0B/op        fastest\nArray#last 273.61M (  3.65ns) (± 4.75%)  0.0B/op   1.00× slower\n```\n\n#### `range` vs `times.map` [code](code/array/range-vs-times.map.cr)\n\n```\n$ crystal build --release --no-debug -o bin/code/array/range-vs-times.map code/array/range-vs-times.map.cr\n$ ./bin/code/array/range-vs-times.map\n\nRange#to_a   1.11M (897.91ns) (±17.84%)  1.67kB/op        fastest\nTimes#to_a   1.02M (980.17ns) (±17.56%)  1.69kB/op   1.09× slower\n```\n\n### Enumerable\n\n#### `each push` vs `map` [code](code/enumerable/each-push-vs-map.cr)\n\n```\n$ crystal build --release --no-debug -o bin/code/enumerable/each-push-vs-map code/enumerable/each-push-vs-map.cr\n$ ./bin/code/enumerable/each-push-vs-map\n\n             Array#map 507.91k (  1.97µs) (±11.92%)  3.96kB/op        fastest\n     Array#each + push 145.04k (  6.89µs) (±18.89%)  12.7kB/op   3.50× slower\nArray#each_with_object 155.85k (  6.42µs) (±17.07%)  12.7kB/op   3.26× slower\n```\n\n#### `each` vs `loop` [code](code/enumerable/each-vs-loop.cr)\n\n```\n$ crystal build --release --no-debug -o bin/code/enumerable/each-vs-loop code/enumerable/each-vs-loop.cr\n$ ./bin/code/enumerable/each-vs-loop\n\nWhile Loop   1.64M (609.64ns) (± 7.66%)  0.0B/op  159.20× slower\n     #each 261.15M (  3.83ns) (±10.82%)  0.0B/op         fastest\n```\n\n#### `each_with_index` vs `while loop` [code](code/enumerable/each_with_index-vs-while-loop.cr)\n\n```\n$ crystal build --release --no-debug -o bin/code/enumerable/each_with_index-vs-while-loop code/enumerable/each_with_index-vs-while-loop.cr\n$ ./bin/code/enumerable/each_with_index-vs-while-loop\n\n     While Loop   1.51M (661.13ns) (± 9.29%)  0.0B/op   6.94× slower\neach_with_index  10.50M ( 95.23ns) (±17.95%)  0.0B/op        fastest\n```\n\n#### `map flatten` vs `flat_map` [code](code/enumerable/map-flatten-vs-flat_map.cr)\n\n```\n$ crystal build --release --no-debug -o bin/code/enumerable/map-flatten-vs-flat_map code/enumerable/map-flatten-vs-flat_map.cr\n$ ./bin/code/enumerable/map-flatten-vs-flat_map\n\n   Array#flat_map (Tuple) 902.86k (  1.11µs) (± 6.63%)  3.65kB/op        fastest\nArray#map.flatten (Tuple) 664.00k (  1.51µs) (± 6.00%)  4.69kB/op   1.36× slower\n   Array#flat_map (Array) 238.37k (  4.20µs) (± 5.73%)  7.18kB/op   3.79× slower\nArray#map.flatten (Array) 193.64k (  5.16µs) (± 3.78%)  9.39kB/op   4.66× slower\n```\n\n#### `reverse.each` vs `reverse_each` [code](code/enumerable/reverse.each-vs-reverse_each.cr)\n\n```\n$ crystal build --release --no-debug -o bin/code/enumerable/reverse.each-vs-reverse_each code/enumerable/reverse.each-vs-reverse_each.cr\n$ ./bin/code/enumerable/reverse.each-vs-reverse_each\n\nArray#reverse.each   4.03M (248.39ns) (± 5.02%)  480B/op   4.94× slower\nArray#reverse_each  19.88M ( 50.30ns) (± 2.49%)  0.0B/op        fastest\n```\n\n#### `sort` vs `sort_by` [code](code/enumerable/sort-vs-sort_by.cr)\n\n```\n$ crystal build --release --no-debug -o bin/code/enumerable/sort-vs-sort_by code/enumerable/sort-vs-sort_by.cr\n$ ./bin/code/enumerable/sort-vs-sort_by\n\n   Enumerable#sort 145.32k (  6.88µs) (± 2.89%)  3.07kB/op   1.17× slower\nEnumerable#sort_by 170.71k (  5.86µs) (± 4.47%)  1.04kB/op        fastest\n```\n\n### General\n\n#### Assignment [code](code/general/assignment.cr)\n\n```\n$ crystal build --release --no-debug -o bin/code/general/assignment code/general/assignment.cr\n$ ./bin/code/general/assignment\n\nSequential Assignment 611.21M (  1.64ns) (± 4.98%)  0.0B/op   1.00× slower\n  Parallel Assignment 613.61M (  1.63ns) (± 5.04%)  0.0B/op        fastest\n```\n\n#### `hash` vs `struct` vs `namedtuple` [code](code/general/hash-vs-struct-vs-namedtuple.cr)\n\n```\n$ crystal build --release --no-debug -o bin/code/general/hash-vs-struct-vs-namedtuple code/general/hash-vs-struct-vs-namedtuple.cr\n$ ./bin/code/general/hash-vs-struct-vs-namedtuple\n\nNamedTuple 515.36M (  1.94ns) (± 4.05%)  0.0B/op        fastest\n    Struct 503.85M (  1.98ns) (± 6.54%)  0.0B/op   1.02× slower\n      Hash   9.60M (104.18ns) (± 2.76%)  208B/op  53.69× slower\n```\n\n#### `loop` vs `while_true` [code](code/general/loop-vs-while_true.cr)\n\n```\n$ crystal build --release --no-debug -o bin/code/general/loop-vs-while_true code/general/loop-vs-while_true.cr\n$ ./bin/code/general/loop-vs-while_true\n\n While Loop 512.11M (  1.95ns) (± 5.15%)  0.0B/op        fastest\nKernel Loop 482.98M (  2.07ns) (±16.94%)  0.0B/op   1.06× slower\n```\n\n#### `positional_argument` vs `named_argument` [code](code/general/positional_argument-vs-named_argument.cr)\n\n```\n$ crystal build --release --no-debug -o bin/code/general/positional_argument-vs-named_argument code/general/positional_argument-vs-named_argument.cr\n$ ./bin/code/general/positional_argument-vs-named_argument\n\n     Named arguments 564.18M (  1.77ns) (±16.11%)  0.0B/op   1.03× slower\nPositional arguments 578.90M (  1.73ns) (±10.46%)  0.0B/op        fastest\n```\n\n#### `property` vs `getter_and_setter` [code](code/general/property-vs-getter_and_setter.cr)\n\n```\n$ crystal build --release --no-debug -o bin/code/general/property-vs-getter_and_setter code/general/property-vs-getter_and_setter.cr\n$ ./bin/code/general/property-vs-getter_and_setter\n\n         property  50.89M ( 19.65ns) (± 5.34%)  32.0B/op        fastest\ngetter_and_setter  49.68M ( 20.13ns) (± 7.27%)  32.0B/op   1.02× slower\n```\n\n### Hash\n\n#### `[]?` vs `has_key?` [code](code/hash/[]?-vs-has_key?.cr)\n\n```\n$ crystal build --release --no-debug -o bin/code/hash/[]?-vs-has_key? code/hash/[]?-vs-has_key?.cr\n$ ./bin/code/hash/[]?-vs-has_key?\n\n     Hash#[]?  41.12M ( 24.32ns) (±12.09%)  0.0B/op   1.01× slower\nHash#has_key?  41.48M ( 24.11ns) (± 8.25%)  0.0B/op        fastest\n```\n\n#### `bracket` vs `fetch` [code](code/hash/bracket-vs-fetch.cr)\n\n```\n$ crystal build --release --no-debug -o bin/code/hash/bracket-vs-fetch code/hash/bracket-vs-fetch.cr\n$ ./bin/code/hash/bracket-vs-fetch\n\n   Hash#[]  95.60M ( 10.46ns) (± 6.16%)  0.0B/op   1.02× slower\nHash#fetch  97.08M ( 10.30ns) (± 9.36%)  0.0B/op        fastest\n```\n\n#### `clone` vs `dup` [code](code/hash/clone-vs-dup.cr)\n\n```\n$ crystal build --release --no-debug -o bin/code/hash/clone-vs-dup code/hash/clone-vs-dup.cr\n$ ./bin/code/hash/clone-vs-dup\n\n  Hash#dup   5.39M (185.50ns) (±17.96%)    480B/op        fastest\nHash#clone 293.35k (  3.41µs) (±10.17%)  5.94kB/op  18.38× slower\n```\n\n#### `keys each` vs `each_key` [code](code/hash/keys-each-vs-each_key.cr)\n\n```\n$ crystal build --release --no-debug -o bin/code/hash/keys-each-vs-each_key code/hash/keys-each-vs-each_key.cr\n$ ./bin/code/hash/keys-each-vs-each_key\n\nHash#keys.each   4.25M (235.11ns) (± 8.09%)  240B/op   1.11× slower\n Hash#each_key   4.71M (212.43ns) (±22.16%)  160B/op        fastest\n```\n\n#### `merge bang` vs `[]=` [code](code/hash/merge-bang-vs-[]=.cr)\n\n```\n$ crystal build --release --no-debug -o bin/code/hash/merge-bang-vs-[]= code/hash/merge-bang-vs-[]=.cr\n$ ./bin/code/hash/merge-bang-vs-[]=\n\nHash#merge!  67.40k ( 14.84µs) (±23.77%)  16.6kB/op   4.19× slower\n   Hash#[]= 282.73k (  3.54µs) (±21.37%)  4.14kB/op        fastest\n```\n\n### Namedtuple\n\n#### `bracket` vs `fetch` [code](code/namedtuple/bracket-vs-fetch.cr)\n\n```\n$ crystal build --release --no-debug -o bin/code/namedtuple/bracket-vs-fetch code/namedtuple/bracket-vs-fetch.cr\n$ ./bin/code/namedtuple/bracket-vs-fetch\n\n   NamedTuple#[] 294.37M (  3.40ns) (±19.52%)  0.0B/op   1.00× slower\nNamedTuple#fetch 295.49M (  3.38ns) (±19.80%)  0.0B/op        fastest\n```\n\n#### `fetch` vs `fetch_with_block` [code](code/namedtuple/fetch-vs-fetch_with_block.cr)\n\n```\n$ crystal build --release --no-debug -o bin/code/namedtuple/fetch-vs-fetch_with_block code/namedtuple/fetch-vs-fetch_with_block.cr\n$ ./bin/code/namedtuple/fetch-vs-fetch_with_block\n\nNamedTuple#fetch + const 168.24M (  5.94ns) (± 6.53%)  0.0B/op   1.81× slower\nNamedTuple#fetch + block 304.53M (  3.28ns) (± 4.50%)  0.0B/op        fastest\n  NamedTuple#fetch + arg 296.07M (  3.38ns) (± 6.99%)  0.0B/op   1.03× slower\n```\n\n### Proc & Block\n\n#### `block` vs `to_proc` [code](code/proc-and-block/block-vs-to_proc.cr)\n\n```\n$ crystal build --release --no-debug -o bin/code/proc-and-block/block-vs-to_proc code/proc-and-block/block-vs-to_proc.cr\n$ ./bin/code/proc-and-block/block-vs-to_proc\n\n         Block 331.06k (  3.02µs) (±13.18%)  2.6kB/op   1.10× slower\nSymbol#to_proc 362.78k (  2.76µs) (± 5.27%)  2.6kB/op        fastest\n```\n\n#### `proc call` vs `yield` [code](code/proc-and-block/proc-call-vs-yield.cr)\n\n```\n$ crystal build --release --no-debug -o bin/code/proc-and-block/proc-call-vs-yield code/proc-and-block/proc-call-vs-yield.cr\n$ ./bin/code/proc-and-block/proc-call-vs-yield\n\n    block.call 513.72M (  1.95ns) (± 4.51%)  0.0B/op        fastest\n block + yield 501.67M (  1.99ns) (± 7.25%)  0.0B/op   1.02× slower\nblock argument 512.94M (  1.95ns) (± 5.41%)  0.0B/op   1.00× slower\n         yield 482.96M (  2.07ns) (±15.43%)  0.0B/op   1.06× slower\n```\n\n### String\n\n#### Concatenation [code](code/string/concatenation.cr)\n\n```\n$ crystal build --release --no-debug -o bin/code/string/concatenation code/string/concatenation.cr\n$ ./bin/code/string/concatenation\n\n String#+  44.62M ( 22.41ns) (± 8.00%)  32.0B/op        fastest\nString#{}  23.68M ( 42.22ns) (±16.74%)  32.0B/op   1.88× slower\n String#%   4.28M (233.43ns) (±20.03%)   176B/op  10.41× slower\n```\n\n#### `ends string-matching-match` vs `end_with` [code](code/string/ends-string-matching-match-vs-end_with.cr)\n\n```\n$ crystal build --release --no-debug -o bin/code/string/ends-string-matching-match-vs-end_with code/string/ends-string-matching-match-vs-end_with.cr\n$ ./bin/code/string/ends-string-matching-match-vs-end_with\n\nString#end_with? 238.71M (  4.19ns) (±11.61%)   0.0B/op        fastest\n       String#=~   7.93M (126.04ns) (± 4.61%)  16.0B/op  30.09× slower\n```\n\n#### Equal-substring-of-char [code](code/string/equal-substring-of-char.cr)\n\n```\n$ crystal build --release --no-debug -o bin/code/string/equal-substring-of-char code/string/equal-substring-of-char.cr\n$ ./bin/code/string/equal-substring-of-char\n\n         \"===\"[0] == '=' 298.29M (  3.35ns) (± 7.06%)   0.0B/op        fastest\n    \"===\"[0].to_s == \"=\"  23.29M ( 42.94ns) (± 6.52%)  48.0B/op  12.81× slower\n\"===\"[0] == \"=\".chars[0]  27.62M ( 36.21ns) (± 4.66%)  48.0B/op  10.80× slower\n```\n\n#### `equal` vs `match` [code](code/string/equal-vs-match.cr)\n\n```\n$ crystal build --release --no-debug -o bin/code/string/equal-vs-match code/string/equal-vs-match.cr\n$ ./bin/code/string/equal-vs-match\n\nString#match  15.00M ( 66.65ns) (± 8.74%)  16.0B/op   1.02× slower\n  Regexp#===  15.32M ( 65.27ns) (± 9.61%)  16.0B/op        fastest\n   String#=~  14.67M ( 68.17ns) (± 8.60%)  16.0B/op   1.04× slower\n```\n\n#### `gsub` vs `sub` [code](code/string/gsub-vs-sub.cr)\n\n```\n$ crystal build --release --no-debug -o bin/code/string/gsub-vs-sub code/string/gsub-vs-sub.cr\n$ ./bin/code/string/gsub-vs-sub\n\n String#sub   3.67M (272.77ns) (± 5.43%)  1.22kB/op        fastest\nString#gsub   1.37M (728.87ns) (± 4.13%)  1.22kB/op   2.67× slower\n```\n\n#### `includes` vs `to_s.includes` [code](code/string/includes-vs-to_s.includes.cr)\n\n```\n$ crystal build --release --no-debug -o bin/code/string/includes-vs-to_s.includes code/string/includes-vs-to_s.includes.cr\n$ ./bin/code/string/includes-vs-to_s.includes\n\n  String#includes? 368.22M (  2.72ns) (± 8.30%)  0.0B/op   1.02× slower\nNil#to_s#includes? 376.21M (  2.66ns) (± 6.76%)  0.0B/op        fastest\n```\n\n#### `nil` vs `to_s.empty` [code](code/string/nil-vs-to_s.empty.cr)\n\n```\n$ crystal build --release --no-debug -o bin/code/string/nil-vs-to_s.empty code/string/nil-vs-to_s.empty.cr\n$ ./bin/code/string/nil-vs-to_s.empty\n\n    String#nil? 468.25M (  2.14ns) (±14.49%)  0.0B/op        fastest\nNil#to_s#empty? 450.24M (  2.22ns) (±14.74%)  0.0B/op   1.04× slower\n```\n\n#### `sub` vs `chomp` [code](code/string/sub-vs-chomp.cr)\n\n```\n$ crystal build --release --no-debug -o bin/code/string/sub-vs-chomp code/string/sub-vs-chomp.cr\n$ ./bin/code/string/sub-vs-chomp\n\nString#chomp\"string\"  43.85M ( 22.81ns) (±12.35%)  32.0B/op        fastest\n  String#sub/regexp/   3.57M (280.13ns) (± 5.92%)   176B/op  12.28× slower\n```\n\n## You may also like\n\n- [halite](https://github.com/icyleaf/halite) - HTTP Requests Client with a chainable REST API, built-in sessions and middlewares.\n- [totem](https://github.com/icyleaf/totem) - Load and parse a configuration file or string in JSON, YAML, dotenv formats.\n- [markd](https://github.com/icyleaf/markd) - Yet another markdown parser built for speed, Compliant to CommonMark specification.\n- [poncho](https://github.com/icyleaf/poncho) - A .env parser/loader improved for performance.\n- [popcorn](https://github.com/icyleaf/popcorn) - Easy and Safe casting from one type to another.\n"
  },
  {
    "path": "code/array/first-vs-index[0].cr",
    "content": "require \"benchmark\"\n\nARRAY = (1..100).to_a\n\ndef fast\n  ARRAY.first\nend\n\ndef slow\n  ARRAY[0]\nend\n\nBenchmark.ips do |x|\n  x.report(\"Array#first\") { fast }\n  x.report(\"Array#[0]\") { slow }\nend\n"
  },
  {
    "path": "code/array/insert-vs-unshift.cr",
    "content": "require \"benchmark\"\n\nBenchmark.ips do |x|\n  x.report(\"Array#insert\") do\n    array = [] of Int32\n    100_000.times { |i| array.insert(0, i) }\n  end\n\n  x.report(\"Array#unshift\") do\n    array = [] of Int32\n    100_000.times { |i| array.unshift(i) }\n  end\nend\n"
  },
  {
    "path": "code/array/last-vs-index[-1].cr",
    "content": "require \"benchmark\"\n\nARRAY = (1..100).to_a\n\ndef fast\n  ARRAY[-1]\nend\n\ndef slow\n  ARRAY.last\nend\n\nBenchmark.ips do |x|\n  x.report(\"Array#[-1]\") { fast }\n  x.report(\"Array#last\") { slow }\nend\n"
  },
  {
    "path": "code/array/range-vs-times.map.cr",
    "content": "require \"benchmark\"\n\nBenchmark.ips do |x|\n  x.report(\"Range#to_a\") do\n    (1..100).to_a\n  end\n\n  x.report(\"Times#to_a\") do\n    100.times.map { |i| i + 1 }.to_a\n  end\nend\n"
  },
  {
    "path": "code/enumerable/each-push-vs-map.cr",
    "content": "require \"benchmark\"\n\nARRAY = (1..1000).to_a\n\ndef fastest\n  ARRAY.map { |i| i }\nend\n\ndef fast\n  array = [] of Int32\n  ARRAY.each { |i| array.push i }\n  array\nend\n\ndef slow\n  ARRAY.each_with_object([] of Int32) { |i, obj| obj << i }\nend\n\nBenchmark.ips do |x|\n  x.report(\"Array#map\") { fastest }\n  x.report(\"Array#each + push\") { fast }\n  x.report(\"Array#each_with_object\") { slow }\nend\n"
  },
  {
    "path": "code/enumerable/each-vs-loop.cr",
    "content": "require \"benchmark\"\n\nARRAY = (1..100).to_a\n\ndef fast\n  i = 0\n  while i < ARRAY.size\n    ARRAY[i]\n    i += 1\n  end\nend\n\ndef slow\n  ARRAY.each do |number|\n    number\n  end\nend\n\nBenchmark.ips do |x|\n  x.report(\"While Loop\") { fast }\n  x.report(\"#each\") { slow }\nend\n"
  },
  {
    "path": "code/enumerable/each_with_index-vs-while-loop.cr",
    "content": "require \"benchmark\"\n\nARRAY = (1..100).to_a\n\ndef fast\n  index = 0\n  while index < ARRAY.size\n    ARRAY[index] + index\n    index += 1\n  end\n  ARRAY\nend\n\ndef slow\n  ARRAY.each_with_index do |number, index|\n    number + index\n  end\nend\n\nBenchmark.ips do |x|\n  x.report(\"While Loop\") { fast }\n  x.report(\"each_with_index\") { slow }\nend\n"
  },
  {
    "path": "code/enumerable/map-flatten-vs-flat_map.cr",
    "content": "require \"benchmark\"\n\nARRAY = (1..100).to_a\n\ndef fastest\n  ARRAY.flat_map { |e| {e, e} }\nend\n\ndef fast\n  ARRAY.map { |e| {e, e} }.flatten\nend\n\ndef slow\n  ARRAY.flat_map { |e| [e, e] }\nend\n\ndef slowest\n  ARRAY.map { |e| [e, e] }.flatten\nend\n\nBenchmark.ips do |x|\n  x.report(\"Array#flat_map (Tuple)\") { fastest }\n  x.report(\"Array#map.flatten (Tuple)\") { fast }\n  x.report(\"Array#flat_map (Array)\") { slow }\n  x.report(\"Array#map.flatten (Array)\") { slowest }\nend\n"
  },
  {
    "path": "code/enumerable/reverse.each-vs-reverse_each.cr",
    "content": "require \"benchmark\"\n\nARRAY = (1..100).to_a\n\ndef slow\n  ARRAY.reverse.each { |x| x }\nend\n\ndef fast\n  ARRAY.reverse_each { |x| x }\nend\n\nBenchmark.ips do |x|\n  x.report(\"Array#reverse.each\") { slow }\n  x.report(\"Array#reverse_each\") { fast }\nend\n"
  },
  {
    "path": "code/enumerable/sort-vs-sort_by.cr",
    "content": "require \"benchmark\"\n\nstruct User\n  property name\n\n  def initialize(@name : String)\n  end\nend\n\nARRAY = Array.new(100) do\n  User.new(sprintf \"%010d\", rand(1_000_000_000))\nend\n\ndef fast\n  ARRAY.sort_by(&.name)\nend\n\ndef slow\n  ARRAY.sort { |a, b| a.name <=> b.name }\nend\n\nBenchmark.ips do |x|\n  x.report(\"Enumerable#sort\") { fast }\n  x.report(\"Enumerable#sort_by\") { slow }\nend\n"
  },
  {
    "path": "code/general/assignment.cr",
    "content": "require \"benchmark\"\n\ndef fast\n  _a, _b, _c, _d, _e, _f, _g, _h = 1, 2, 3, 4, 5, 6, 7, 8\n  nil\nend\n\ndef slow\n  _a = 1\n  _b = 2\n  _c = 3\n  _d = 4\n  _e = 5\n  _f = 6\n  _g = 7\n  _h = 8\n  nil\nend\n\nBenchmark.ips do |x|\n  x.report(\"Sequential Assignment\") { slow }\n  x.report(\"Parallel Assignment\") { fast }\nend\n"
  },
  {
    "path": "code/general/hash-vs-struct-vs-namedtuple.cr",
    "content": "require \"benchmark\"\n\nstruct SampleStruct\n  property name, year\n\n  def initialize(@name : String, @year : Int32)\n  end\nend\n\ndef slow\n  {\"name\" => \"Crystal\", \"year\" => 2011}\nend\n\ndef fast\n  SampleStruct.new(\"Crystal\", 2011)\nend\n\ndef fastest\n  {name: \"Crystal\", year: 2011}\nend\n\nBenchmark.ips do |x|\n  x.report(\"NamedTuple\") { fastest }\n  x.report(\"Struct\") { fast }\n  x.report(\"Hash\") { slow }\nend\n"
  },
  {
    "path": "code/general/loop-vs-while_true.cr",
    "content": "require \"benchmark\"\n\nNUMBER = 100_000_000\n\ndef fast\n  index = 0\n  while true\n    break if index > NUMBER\n    index += 1\n  end\nend\n\ndef slow\n  index = 0\n  loop do\n    break if index > NUMBER\n    index += 1\n  end\nend\n\nBenchmark.ips do |x|\n  x.report(\"While Loop\") { fast }\n  x.report(\"Kernel Loop\") { slow }\nend\n"
  },
  {
    "path": "code/general/positional_argument-vs-named_argument.cr",
    "content": "require \"benchmark\"\n\nmodule M\n  def self.func(a, b, c)\n  end\nend\n\ndef fast\n  M.func(a: 1, b: 2, c: 3)\nend\n\ndef slow\n  M.func(1, 2, 3)\nend\n\nBenchmark.ips do |x|\n  x.report(\"Named arguments\") { fast }\n  x.report(\"Positional arguments\") { slow }\nend\n"
  },
  {
    "path": "code/general/property-vs-getter_and_setter.cr",
    "content": "require \"benchmark\"\n\nclass User\n  property :first_name\n\n  def initialize\n    @first_name = \"\"\n    @last_name = \"\"\n  end\n\n  def last_name\n    @last_name\n  end\n\n  def last_name=(value)\n    @last_name = value\n  end\nend\n\ndef slow\n  user = User.new\n  user.last_name = \"Wang\"\n  user.last_name\nend\n\ndef fast\n  user = User.new\n  user.first_name = \"Wang\"\n  user.first_name\nend\n\nBenchmark.ips do |x|\n  x.report(\"property\") { fast }\n  x.report(\"getter_and_setter\") { slow }\nend\n"
  },
  {
    "path": "code/hash/[]?-vs-has_key?.cr",
    "content": "require \"benchmark\"\n\nHASH = {\"a\" => \"z\"}\n\nBenchmark.ips do |x|\n  x.report(\"Hash#[]?\") do\n    HASH[\"a\"]?\n    HASH[\"b\"]?\n  end\n\n  x.report(\"Hash#has_key?\") do\n    HASH.has_key? \"a\"\n    HASH.has_key? \"b\"\n  end\nend\n"
  },
  {
    "path": "code/hash/bracket-vs-fetch.cr",
    "content": "require \"benchmark\"\n\nHASH       = {\"fast\" => \"ruby\"}\nNAMEDTUPLE = {fast: \"ruby\"}\n\nBenchmark.ips do |x|\n  x.report(\"Hash#[]\") do\n    HASH[\"fast\"]\n  end\n\n  x.report(\"Hash#fetch\") do\n    HASH.fetch(\"fast\") { }\n  end\nend\n"
  },
  {
    "path": "code/hash/clone-vs-dup.cr",
    "content": "require \"benchmark\"\n\nHASH = (\"a\"..\"z\").map { |v| {v => v.bytes} }\n\ndef fast\n  HASH.dup\nend\n\ndef slow\n  HASH.clone\nend\n\nBenchmark.ips do |x|\n  x.report(\"Hash#dup\") { fast }\n  x.report(\"Hash#clone\") { slow }\nend\n"
  },
  {
    "path": "code/hash/keys-each-vs-each_key.cr",
    "content": "require \"benchmark\"\n\nHASH = {\n  \"provider\" => \"facebook\",\n  \"uid\"      => \"1234567\",\n  \"info\"     => {\n    \"nickname\"   => \"jbloggs\",\n    \"email\"      => \"joe@bloggs.com\",\n    \"name\"       => \"Joe Bloggs\",\n    \"first_name\" => \"Joe\",\n    \"last_name\"  => \"Bloggs\",\n    \"image\"      => \"http://graph.facebook.com/1234567/picture?type=square\",\n    \"urls\"       => {\"Facebook\" => \"http://www.facebook.com/jbloggs\"},\n    \"location\"   => \"Palo Alto, California\",\n    \"verified\"   => true,\n  },\n  \"credentials\" => {\n    \"token\"      => \"ABCDEF...\",\n    \"expires_at\" => 1321747205,\n    \"expires\"    => true,\n  },\n  \"extra\" => {\n    \"raw_info\" => {\n      \"id\"           => \"1234567\",\n      \"name\"         => \"Joe Bloggs\",\n      \"first_name\"   => \"Joe\",\n      \"last_name\"    => \"Bloggs\",\n      \"link\"         => \"http://www.facebook.com/jbloggs\",\n      \"username\"     => \"jbloggs\",\n      \"location\"     => {\"id\" => \"123456789\", \"name\" => \"Palo Alto, California\"},\n      \"gender\"       => \"male\",\n      \"email\"        => \"joe@bloggs.com\",\n      \"timezone\"     => -8,\n      \"locale\"       => \"en_US\",\n      \"verified\"     => true,\n      \"updated_time\" => \"2011-11-11T06:21:03+0000\",\n    },\n  },\n}\n\ndef slow\n  HASH.keys.each(&.downcase)\nend\n\ndef fast\n  HASH.each_key(&.downcase)\nend\n\nBenchmark.ips do |x|\n  x.report(\"Hash#keys.each\") { slow }\n  x.report(\"Hash#each_key\") { fast }\nend\n"
  },
  {
    "path": "code/hash/merge-bang-vs-[]=.cr",
    "content": "require \"benchmark\"\n\nENUM = (1..100)\n\ndef slow\n  ENUM.each_with_object({} of Int32 => Int32) do |e, h|\n    h.merge!({e => e})\n  end\nend\n\ndef fast\n  ENUM.each_with_object({} of Int32 => Int32) do |e, h|\n    h[e] = e\n  end\nend\n\nBenchmark.ips do |x|\n  x.report(\"Hash#merge!\") { slow }\n  x.report(\"Hash#[]=\") { fast }\nend\n"
  },
  {
    "path": "code/namedtuple/bracket-vs-fetch.cr",
    "content": "require \"benchmark\"\n\nNAMEDTUPLE = {fast: \"ruby\"}\n\ndef fast\n  NAMEDTUPLE[:fast]\nend\n\ndef slow\n  NAMEDTUPLE.fetch(:fast, \"\")\nend\n\nBenchmark.ips do |x|\n  x.report(\"NamedTuple#[]\") { fast }\n  x.report(\"NamedTuple#fetch\") { slow }\nend\n"
  },
  {
    "path": "code/namedtuple/fetch-vs-fetch_with_block.cr",
    "content": "require \"benchmark\"\n\nHASH    = {writing: :fast_ruby}\nDEFAULT = \"fast ruby\"\n\nBenchmark.ips do |x|\n  x.report(\"NamedTuple#fetch + const\") { HASH.fetch(:writing, DEFAULT) }\n  x.report(\"NamedTuple#fetch + block\") { HASH.fetch(:writing) { \"fast ruby\" } }\n  x.report(\"NamedTuple#fetch + arg\") { HASH.fetch(:writing, \"fast ruby\") }\nend\n"
  },
  {
    "path": "code/proc-and-block/block-vs-to_proc.cr",
    "content": "require \"benchmark\"\n\nRANGE = (1..100)\n\ndef slow\n  RANGE.map { |i| i.to_s }\nend\n\ndef fast\n  RANGE.map(&.to_s)\nend\n\nBenchmark.ips do |x|\n  x.report(\"Block\") { slow }\n  x.report(\"Symbol#to_proc\") { fast }\nend\n"
  },
  {
    "path": "code/proc-and-block/proc-call-vs-yield.cr",
    "content": "require \"benchmark\"\n\ndef slow(&block)\n  block.call\nend\n\ndef slow2(&block)\n  yield\nend\n\ndef slow3(&block)\nend\n\ndef fast\n  yield\nend\n\nBenchmark.ips do |x|\n  x.report(\"block.call\") { slow { 1 + 1 } }\n  x.report(\"block + yield\") { slow2 { 1 + 1 } }\n  x.report(\"block argument\") { slow3 { 1 + 1 } }\n  x.report(\"yield\") { fast { 1 + 1 } }\nend\n"
  },
  {
    "path": "code/string/concatenation.cr",
    "content": "require \"benchmark\"\n\nWORLD = \"world\"\n\ndef fastest\n  \"hello \" + WORLD\nend\n\ndef fast\n  \"hello #{WORLD}\"\nend\n\ndef slow\n  \"hello %s\" % WORLD\nend\n\nBenchmark.ips do |x|\n  x.report(\"String#+\") { fastest }\n  x.report(\"String\\#{}\") { fast }\n  x.report(\"String#%\") { slow }\nend\n"
  },
  {
    "path": "code/string/ends-string-matching-match-vs-end_with.cr",
    "content": "require \"benchmark\"\n\nSLUG = \"root_url\"\n\ndef fast\n  SLUG.ends_with?(\"_url\")\nend\n\ndef slow\n  SLUG =~ /_url$/\nend\n\nBenchmark.ips do |x|\n  x.report(\"String#end_with?\") { fast }\n  x.report(\"String#=~\") { slow }\nend\n"
  },
  {
    "path": "code/string/equal-substring-of-char.cr",
    "content": "require \"benchmark\"\n\ndef fastest\n  \"====\"[0] == '='\nend\n\ndef fast\n  \"====\"[0].to_s == \"=\"\nend\n\ndef slow\n  \"====\"[0] == \"=\".chars[0]\nend\n\nBenchmark.ips do |x|\n  x.report(\"\\\"===\\\"[0] == '='\") { fastest }\n  x.report(\"\\\"===\\\"[0].to_s == \\\"=\\\"\") { fast }\n  x.report(\"\\\"===\\\"[0] == \\\"=\\\".chars[0]\") { slow }\nend\n"
  },
  {
    "path": "code/string/equal-vs-match.cr",
    "content": "require \"benchmark\"\n\ndef fastest\n  \"foo\".match(/boo/)\nend\n\ndef fast\n  /boo/ === \"foo\"\nend\n\ndef slow\n  \"foo\" =~ /boo/\nend\n\nBenchmark.ips do |x|\n  x.report(\"String#match\") { fastest }\n  x.report(\"Regexp#===\") { fast }\n  x.report(\"String#=~\") { slow }\nend\n"
  },
  {
    "path": "code/string/gsub-vs-sub.cr",
    "content": "require \"benchmark\"\n\nURL = \"http://www.thelongestlistofthelongeststuffatthelongestdomainnameatlonglast.com/wearejustdoingthistobestupidnowsincethiscangoonforeverandeverandeverbutitstilllookskindaneatinthebrowsereventhoughitsabigwasteoftimeandenergyandhasnorealpointbutwehadtodoitanyways.html\"\n\ndef slow\n  URL.gsub(\"http://\", \"https://\")\nend\n\ndef fast\n  URL.sub(\"http://\", \"https://\")\nend\n\nBenchmark.ips do |x|\n  x.report(\"String#sub\") { fast }\n  x.report(\"String#gsub\") { slow }\nend\n"
  },
  {
    "path": "code/string/includes-vs-to_s.includes.cr",
    "content": "require \"benchmark\"\n\ndef slow\n  \"foobar\".includes?(\"crystal\")\nend\n\ndef fast\n  nil.to_s.includes?(\"crystal\")\nend\n\nBenchmark.ips do |x|\n  x.report(\"String#includes?\") { fast }\n  x.report(\"Nil#to_s#includes?\") { slow }\nend\n"
  },
  {
    "path": "code/string/nil-vs-to_s.empty.cr",
    "content": "require \"benchmark\"\n\ndef slow\n  nil.to_s.empty?\nend\n\ndef fast\n  \"\".nil?\nend\n\nBenchmark.ips do |x|\n  x.report(\"String#nil?\") { fast }\n  x.report(\"Nil#to_s#empty?\") { slow }\nend\n"
  },
  {
    "path": "code/string/sub-vs-chomp.cr",
    "content": "require \"benchmark\"\n\nSLUG = \"YourSubclassType\"\n\ndef fast\n  SLUG.chomp(\"Type\")\nend\n\ndef slow\n  SLUG.sub(/Type\\z/, \"\")\nend\n\nBenchmark.ips do |x|\n  x.report(\"String#chomp\\\"string\\\"\") { fast }\n  x.report(\"String#sub/regexp/\") { slow }\nend\n"
  },
  {
    "path": "shard.yml",
    "content": "name: fast-crystal\nversion: 0.2.2\n\nauthors:\n  - icyleaf <icyleaf.cn@gmail.com>\n\ntargets:\n  fast-crystal:\n    main: src/fast-crystal.cr\n\ncrystal: 0.35.1\n\nlicense: MIT\n"
  },
  {
    "path": "src/fast-crystal.cr",
    "content": "require \"file_utils\"\n\nBIN_PATH        = \"bin/code\"\nSOURCE_PATH     = File.expand_path(\"code\")\nCRYSTAL_BIN     = `which crystal`.strip\nCRYSTAL_VERSION = `#{CRYSTAL_BIN} -v`.strip\n\nif Dir.exists?(BIN_PATH)\n  FileUtils.rm_rf(BIN_PATH)\nend\n\nputs\nputs \"> Test in #{CRYSTAL_VERSION.split(\"\\n\").join(\" \")}\"\nputs\n\nsection = \"\"\n\nfiles = if (file = ARGV[0]?) && File.exists? file\n          {file}\n        else\n          Dir.glob(\"code/**/*.cr\").sort\n        end\nfiles.each do |file|\n  test_file = File.basename(file)\n  test_section = file.sub(test_file, \"\").sub(\"code/\", \"\")[0..-2]\n\n  bin_section = File.join(BIN_PATH, test_section)\n  bin_file = File.join(bin_section, File.basename(test_file, File.extname(test_file)))\n\n  FileUtils.mkdir_p(bin_section)\n\n  if section.empty? || section != test_section\n    section = test_section\n    puts \"### \" + (section == \"proc-and-block\" ? \"Proc & Block\" : section.capitalize)\n    puts\n  end\n\n  compile_command = [CRYSTAL_BIN, \"build\", \"--release\", \"--no-debug\", \"-o\", bin_file, file]\n  print_title(file)\n  puts\n  puts \"```\"\n  puts \"$ \" + compile_command.join(\" \")\n  `#{compile_command.join(\" \")}`\n\n  puts \"$ ./\" + bin_file\n  puts\n  puts `./#{bin_file}`\n  puts \"```\"\n  puts\nend\n\ndef print_title(file)\n  filename = File.basename(file)\n  file_path = file.sub(SOURCE_PATH, \"\")\n\n  title = filename.sub(File.extname(filename), \"\")\n  title = if title.includes?(\"-vs-\")\n            title_sections = [] of String\n            title.split(\"-vs-\").each do |str|\n              title_sections << \"`\" + (str.includes?(\"[-1]\") ? str : str.sub(\"-\", \" \")) + \"`\"\n            end\n\n            title_sections.join(\" vs \")\n          else\n            title.capitalize\n          end\n\n  puts \"#### \" + title + \" [code](\" + file_path + \")\"\nend\n"
  }
]