Files
n8n-openai-adapter/lib/elixir/lib/range.ex
T
2014-07-04 22:07:08 -07:00

126 lines
2.5 KiB
Elixir

defmodule Range do
@moduledoc """
Defines a Range.
A Range is represented internally as a struct. However,
the most common form of creating and matching on ranges
is via the `../2` macro, auto-imported from Kernel:
iex> range = 1..3
1..3
iex> first .. last = range
iex> first
1
iex> last
3
"""
defstruct first: nil, last: nil
@type t :: %Range{}
@type t(first, last) :: %Range{first: first, last: last}
@doc """
Creates a new range.
"""
def new(first, last) do
%Range{first: first, last: last}
end
@doc """
Returns true if the given argument is a range.
## Examples
iex> Range.range?(1..3)
true
iex> Range.range?(0)
false
"""
def range?(%Range{}), do: true
def range?(_), do: false
end
defprotocol Range.Iterator do
@moduledoc """
A protocol used for iterating range elements.
"""
@doc """
Returns the function that calculates the next item.
"""
def next(first, range)
@doc """
Count how many items are in the range.
"""
def count(first, range)
end
defimpl Enumerable, for: Range do
def reduce(first .. last = range, acc, fun) do
reduce(first, last, acc, fun, Range.Iterator.next(first, range), last >= first)
end
defp reduce(_x, _y, {:halt, acc}, _fun, _next, _up) do
{:halted, acc}
end
defp reduce(x, y, {:suspend, acc}, fun, next, up) do
{:suspended, acc, &reduce(x, y, &1, fun, next, up)}
end
defp reduce(x, y, {:cont, acc}, fun, next, true) when x <= y do
reduce(next.(x), y, fun.(x, acc), fun, next, true)
end
defp reduce(x, y, {:cont, acc}, fun, next, false) when x >= y do
reduce(next.(x), y, fun.(x, acc), fun, next, false)
end
defp reduce(_, _, {:cont, acc}, _fun, _next, _up) do
{:done, acc}
end
def member?(first .. last, value) do
if first <= last do
{:ok, first <= value and value <= last}
else
{:ok, last <= value and value <= first}
end
end
def count(first .. _ = range) do
{:ok, Range.Iterator.count(first, range)}
end
end
defimpl Range.Iterator, for: Integer do
def next(first, _ .. last) when is_integer(last) do
if last >= first do
&(&1 + 1)
else
&(&1 - 1)
end
end
def count(first, _ .. last) when is_integer(last) do
if last >= first do
last - first + 1
else
first - last + 1
end
end
end
defimpl Inspect, for: Range do
import Inspect.Algebra
def inspect(first .. last, opts) do
concat [to_doc(first, opts), "..", to_doc(last, opts)]
end
end