-module(gliff@internal@similarity).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/gliff/internal/similarity.gleam").
-export([ratio/1, line_similarity/2]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(false).
-file("src/gliff/internal/similarity.gleam", 29).
?DOC(false).
-spec lines_of(gliff@types:edit()) -> list(binary()).
lines_of(Edit) ->
case Edit of
{equal, Lines} ->
Lines;
{insert, Lines@1} ->
Lines@1;
{delete, Lines@2} ->
Lines@2
end.
-file("src/gliff/internal/similarity.gleam", 15).
?DOC(false).
-spec count(list(gliff@types:edit()), integer(), integer()) -> {integer(),
integer()}.
count(Edits, Matching, Total) ->
case Edits of
[] ->
{Matching, Total};
[Edit | Rest] ->
N = erlang:length(lines_of(Edit)),
case Edit of
{equal, _} ->
count(Rest, Matching + N, (Total + N) + N);
{delete, _} ->
count(Rest, Matching, Total + N);
{insert, _} ->
count(Rest, Matching, Total + N)
end
end.
-file("src/gliff/internal/similarity.gleam", 7).
?DOC(false).
-spec ratio(list(gliff@types:edit())) -> float().
ratio(Edits) ->
{Matching, Total} = count(Edits, 0, 0),
case Total of
0 ->
1.0;
_ ->
case erlang:float(Total) of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> erlang:float(2 * Matching) / Gleam@denominator
end
end.
-file("src/gliff/internal/similarity.gleam", 51).
?DOC(false).
-spec count_matching_raw(list(gliff@types:raw_edit()), integer()) -> integer().
count_matching_raw(Edits, Acc) ->
case Edits of
[] ->
Acc;
[{raw_equal, _} | Rest] ->
count_matching_raw(Rest, Acc + 1);
[_ | Rest@1] ->
count_matching_raw(Rest@1, Acc)
end.
-file("src/gliff/internal/similarity.gleam", 37).
?DOC(false).
-spec line_similarity(binary(), binary()) -> float().
line_similarity(A, B) ->
A_chars = gleam@string:to_graphemes(A),
B_chars = gleam@string:to_graphemes(B),
Total = erlang:length(A_chars) + erlang:length(B_chars),
case Total of
0 ->
1.0;
_ ->
Raw_edits = gliff@internal@myers:diff(A_chars, B_chars),
Matching = count_matching_raw(Raw_edits, 0),
case erlang:float(Total) of
+0.0 -> +0.0;
-0.0 -> -0.0;
Gleam@denominator -> erlang:float(2 * Matching) / Gleam@denominator
end
end.