Skip to content

Commit

Permalink
fix: better whitespace checking for split_prefix
Browse files Browse the repository at this point in the history
  • Loading branch information
ProducerMatt committed Sep 8, 2024
1 parent a387992 commit 1e769aa
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 44 deletions.
72 changes: 29 additions & 43 deletions lib/stampede.ex
Original file line number Diff line number Diff line change
Expand Up @@ -138,57 +138,43 @@ defmodule Stampede do
end

@doc """
If passed a text prefix, will match the start of the string. If passed a
regex, it will match whatever was given and return the first match group.
"""
@spec! strip_prefix(String.t() | Regex.t(), String.t()) :: false | String.t()
def strip_prefix(prefix, text)
## here comes the "smart" """optimized""" solution
when is_binary(prefix) and
binary_part(text, 0, floor(bit_size(prefix) / 8)) == prefix do
binary_part(text, floor(bit_size(prefix) / 8), floor((bit_size(text) - bit_size(prefix)) / 8))
end
Takes a prefix and a string. Returns the matched part, and the rest of the string. The prefix can be a single string, or a list of strings.
def strip_prefix(prefix, text)
when is_binary(prefix) and
binary_part(text, 0, floor(bit_size(prefix) / 8)) != prefix,
do: false
Here is a single prefix.
def strip_prefix(rex, text) when is_struct(rex, Regex) do
case Regex.run(rex, text) do
nil -> false
[_p, body] -> body
end
end
iex> alias Stampede, as: S
iex> S.split_prefix("!ping", "!")
{"!", "ping"}
iex> S.split_prefix("ping", "!")
{false, "ping"}
iex> S.split_prefix("!", "!")
{false, "!"}
def split_prefix(text, prefix) when is_struct(prefix, Regex) and is_binary(text) do
case Regex.split(prefix, text, include_captures: true, capture: :first, trim: true) do
[p, b] ->
{p, b}
Here is a binary list, which is more performant than the Regex module.
[^text] ->
{false, text}

[] ->
{false, text}
end
end
iex> bl = ["S, ", "S ", "s, ", "s "]
iex> S.split_prefix("S, ping", bl)
{"S, ", "ping"}
"""
def split_prefix(text, prefix) when is_binary(prefix) and is_binary(text) do
case text do
# don't match prefix without message
<<^prefix::binary-size(floor(bit_size(prefix) / 8)), ""::binary>> ->
{false, text}

# don't match prefix without message
<<^prefix::binary-size(floor(bit_size(prefix) / 8)), " "::binary>> ->
{false, text}

<<^prefix::binary-size(floor(bit_size(prefix) / 8)), _::binary>> ->
{
binary_part(text, 0, byte_size(prefix)),
binary_part(text, byte_size(prefix), byte_size(text) - byte_size(prefix))
}
prefix_part = binary_part(text, 0, byte_size(prefix))
msg_part = binary_part(text, byte_size(prefix), byte_size(text) - byte_size(prefix))

# final whitespace check
# TODO: benchmark with/without
case String.trim(msg_part) do
"" ->
{false, text}

_ ->
{
prefix_part,
msg_part
}
end

_ ->
{false, text}
Expand Down
6 changes: 6 additions & 0 deletions test/stampede_stateless_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ defmodule StampedeStatelessTest do
assert_value SiteConfig.check_prefixes_for_conflicts(bl) == :no_conflict
end

test "split_prefix whitespace sanity" do
assert S.split_prefix("! ", "!") == {false, "! "}
assert S.split_prefix("! ", "!") == {false, "! "}
assert S.split_prefix("S, ", "S, ") == {false, "S, "}
end

test "cfg prefix conflict sorting" do
rev = ["a", "b", "c", "aa", "ab", "ba", "bc", "aaa", "aba", "bbc", "cac", "aaaa", "ddddd"]

Expand Down
1 change: 0 additions & 1 deletion test/stampede_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ defmodule StampedeTest do
alias Stampede, as: S
alias Services.Dummy, as: D
import AssertValue
doctest Stampede

@confused_response S.confused_response() |> TxtBlock.to_binary(Services.Dummy)

Expand Down

0 comments on commit 1e769aa

Please sign in to comment.