Skip to content

Instantly share code, notes, and snippets.

@am-kantox
Created March 22, 2020 08:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save am-kantox/edcbd04280291d569ee48b109d52894e to your computer and use it in GitHub Desktop.
Save am-kantox/edcbd04280291d569ee48b109d52894e to your computer and use it in GitHub Desktop.
WC on counters
defmodule Wc do
@prehandle 42
@sink @prehandle + 1
@chunk 1_000_000
@type acc_counters :: 0 | 1
@spec counters(binary) :: acc()
def counters(file) do
cs = :counters.new(3, [:write_concurrency])
file
|> File.stream!([], @chunk)
|> Flow.from_enumerable()
|> Flow.partition()
|> Flow.reduce(fn -> 1 end, &parse_counters(&1, &2, cs))
|> Flow.run()
%{bc: :counters.get(cs, 1), lc: :counters.get(cs, 3), wc: :counters.get(cs, 2)}
end
defmacrop ns!(0, ns), do: ns
defmacrop ns!(_, _), do: 1
defmacrop acc_counters!(cs, bc, ns, lc) do
quote do
:counters.add(unquote(cs), 1, unquote(bc))
:counters.add(unquote(cs), 2, unquote(ns))
:counters.add(unquote(cs), 3, unquote(lc))
ns!(unquote(bc), unquote(ns))
end
end
@spec parse_counters(<<_::_*8>>, acc_counters(), :counters.counters_ref()) :: acc_counters()
Enum.each(0..@prehandle, fn i ->
def parse_counters(
<<_::binary-size(unquote(i)), ?\n, rest::binary>>, ns, cs
),
do: parse_counters(rest, acc_counters!(cs, 1 + unquote(i), ns, 1), cs)
def parse_counters(
<<_::binary-size(unquote(i)), ?\s, rest::binary>>, ns, cs
),
do: parse_counters(rest, acc_counters!(cs, 1 + unquote(i), ns, 0), cs)
end)
def parse_counters(<<_::binary-size(@sink), rest::binary>>, _acc, cs),
do: parse_counters(rest, acc_counters!(cs, @sink, 1, 0), cs)
Enum.each(@prehandle..0, fn i ->
def parse_counters(<<_::binary-size(unquote(i))>>, _acc, cs),
do: acc_counters!(cs, 1 + unquote(i), 1, 0)
end)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment