Skip to content

Instantly share code, notes, and snippets.

@am-kantox
Created February 22, 2020 19:59
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/afd52c2ee4c95ea25eff464e8692ac15 to your computer and use it in GitHub Desktop.
Save am-kantox/afd52c2ee4c95ea25eff464e8692ac15 to your computer and use it in GitHub Desktop.
wc in elixir
defmodule Wc do
@acc %{bc: 0, wc: 1, lc: 0, ns?: 1}
@prehandle 42
@sink @prehandle + 1
@chunk 1_000_000
@type acc :: %{
bc: non_neg_integer(),
wc: non_neg_integer(),
lc: non_neg_integer(),
ns?: 0 | 1
}
@spec lazy(binary) :: acc()
def lazy(file),
do: file |> File.stream!() |> Enum.reduce(@acc, &parse/2)
@spec greedy(binary) :: acc()
def greedy(file),
do: file |> File.read!() |> parse(@acc)
@spec flowy(binary) :: acc()
def flowy(file) do
kw =
file
|> File.stream!([], @chunk)
|> Flow.from_enumerable()
|> Flow.partition()
|> Flow.reduce(fn -> @acc end, &parse/2)
|> Enum.to_list()
m =
[:bc, :lc, :wc, :ns?]
|> Enum.into(%{}, &{&1, Keyword.get_values(kw, &1) |> Enum.sum()})
m
|> Map.update!(:wc, &(&1 + 1 - m.ns?))
|> Map.put(:ns?, 1)
end
defmacrop ns!(0, ns), do: ns
defmacrop ns!(_, _), do: 1
defmacro acc!(i, bc, wc, lc, ns) do
quote do
%{
bc: unquote(bc) + unquote(i) + 1,
wc: unquote(wc) + unquote(ns),
lc: unquote(lc),
ns?: ns!(unquote(i), unquote(ns))
}
end
end
@spec parse(<<_::_*8>>, acc()) :: acc()
Enum.each(0..@prehandle, fn i ->
def parse(
<<_::binary-size(unquote(i)), ?\n, rest::binary>>,
%{bc: bc, wc: wc, lc: lc, ns?: ns}
),
do: parse(rest, acc!(unquote(i), bc, wc, lc + 1, ns))
def parse(
<<_::binary-size(unquote(i)), ?\s, rest::binary>>,
%{bc: bc, wc: wc, lc: lc, ns?: ns}
),
do: parse(rest, acc!(unquote(i), bc, wc, lc, ns))
end)
def parse(<<_::binary-size(@sink), rest::binary>>, acc),
do: parse(rest, %{acc | bc: acc.bc + @sink, ns?: 1})
Enum.each(@prehandle..0, fn i ->
def parse(<<_::binary-size(unquote(i))>>, acc),
do: %{acc | bc: acc.bc + unquote(i), ns?: 1}
end)
defmodule Main do
defdelegate lazy(file), to: Wc
defdelegate greedy(file), to: Wc
defdelegate flowy(file), to: Wc
@spec main([binary()]) :: any
def main([]), do: IO.inspect("Usage: wc file _or_ wc method file")
def main([file]), do: main(["flowy", file])
def main([m, file]) do
%{bc: bc, wc: wc, lc: lc} = apply(Wc, String.to_existing_atom(m), [file])
["", lc, wc, bc, file]
|> Enum.join(<<?\t>>)
|> IO.puts()
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment