Created
February 22, 2020 19:59
-
-
Save am-kantox/afd52c2ee4c95ea25eff464e8692ac15 to your computer and use it in GitHub Desktop.
wc in elixir
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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