Packages

GroupManager is extracted from the ScaleSmall project as a standalone piece. This can be used independently to manage a set of nodes and coordinate a common goal expressed as integer ranges.

Current section

Files

Jump to
group_manager lib group_manager data timed_set.ex
Raw

lib/group_manager/data/timed_set.ex

defmodule GroupManager.Data.TimedSet do
require Record
require GroupManager.Data.Item
require GroupManager.Data.LocalClock
require GroupManager.Data.TimedItem
require Chatter.NetID
alias GroupManager.Data.TimedItem
alias Chatter.NetID
alias GroupManager.Data.Item
alias GroupManager.Data.LocalClock
Record.defrecord :timed_set,
items: []
@type t :: record( :timed_set,
items: list(TimedItem.t) )
@spec new() :: t
def new()
do
timed_set()
end
defmacro is_valid(data) do
case Macro.Env.in_guard?(__CALLER__) do
true ->
quote do
is_tuple(unquote(data)) and tuple_size(unquote(data)) == 2 and
:erlang.element(1, unquote(data)) == :timed_set and
# items
is_list(:erlang.element(2, unquote(data)))
end
false ->
quote bind_quoted: binding() do
is_tuple(data) and tuple_size(data) == 2 and
:erlang.element(1, data) == :timed_set and
# items
is_list(:erlang.element(2, data))
end
end
end
defmacro is_empty(data) do
case Macro.Env.in_guard?(__CALLER__) do
true ->
quote do
# items
:erlang.element(2, unquote(data)) == []
end
false ->
quote do
# items
:erlang.element(2, unquote(data)) == []
end
end
end
@spec valid?(t) :: boolean
def valid?(data)
when is_valid(data)
do
true
end
def valid?(_), do: false
@spec empty?(t) :: boolean
def empty?(data)
when is_valid(data) and
is_empty(data)
do
true
end
def empty?(data)
when is_valid(data)
do
false
end
@spec items(t) :: list(TimedItem.t)
def items(set)
when is_valid(set)
do
timed_set(set, :items)
end
@spec add(t, TimedItem.t) :: t
def add(set, item)
when is_valid(set) and
TimedItem.is_valid(item)
do
timed_set(items: TimedItem.merge(timed_set(set, :items), item))
end
@spec merge(t, t) :: t
def merge(lhs, rhs)
when is_valid(lhs) and
is_valid(rhs)
do
timed_set(items: TimedItem.merge(timed_set(lhs, :items),
timed_set(rhs, :items)))
end
@spec count(t, NetID.t) :: integer
def count(set, id)
when is_valid(set) and
NetID.is_valid(id)
do
List.foldl(timed_set(set, :items), 0, fn(x, acc) ->
item_id = TimedItem.item(x) |> Item.member
if( item_id == id )
do
acc + 1
else
acc
end
end)
end
@spec count(t, LocalClock.t) :: integer
def count(set, id)
when is_valid(set) and
LocalClock.is_valid(id)
do
List.foldl(timed_set(set, :items), 0, fn(x, acc) ->
if( TimedItem.updated_at(x) == id )
do
acc + 1
else
acc
end
end)
end
@spec extract_netids(t) :: list(NetID.t)
def extract_netids(set)
when is_valid(set)
do
Enum.map(timed_set(set, :items), fn(x) -> TimedItem.updated_at(x) |> LocalClock.member end)
|> Enum.uniq
end
@spec encode_with(t, map) :: binary
def encode_with(set, id_map)
when is_valid(set) and
is_map(id_map)
do
timed_set(set, :items) |> TimedItem.encode_list_with(id_map)
end
@spec decode_with(binary, map) :: {t, binary}
def decode_with(bin, id_map)
when is_binary(bin) and
byte_size(bin) > 0 and
is_map(id_map)
do
{elems, remaining} = TimedItem.decode_list_with(bin, id_map)
{timed_set(items: elems), remaining}
end
end