defmodule Hobbes.TestVersionMap do @moduledoc """ This module contains a simple (and very inefficient) implementation of the VersionMap API to be used for fuzz/simulation testing and model checking. """ alias Hobbes.TestVersionMap import Hobbes.Utils @type t :: %__MODULE__{ ranges: list, } @enforce_keys [ :ranges, ] defstruct @enforce_keys @spec new :: t def new do %TestVersionMap{ ranges: [], } end @spec add_writes(t, non_neg_integer, list) :: t def add_writes(%TestVersionMap{} = vm, version, writes) when is_list(writes) do Enum.reduce(writes, vm.ranges, fn key_or_range, acc -> range = case key_or_range do {_sk, _ek} = tup -> tup key -> {key, next_key(key)} end [{range, version} | acc] end) |> then(fn ranges -> %{vm | ranges: ranges} end) end @spec written_after?(t, non_neg_integer, {binary, binary} | binary) :: boolean def written_after?(%TestVersionMap{} = vm, version, {_start_key, _end_key} = range) do Enum.any?(vm.ranges, fn {r, ver} -> ver > version and intersects?(range, r) end) end def written_after?(%TestVersionMap{} = vm, version, key) when is_binary(key) do written_after?(vm, version, {key, next_key(key)}) end defp intersects?({sk1, ek1}, {sk2, ek2}) do ek1 > sk2 and ek2 > sk1 end @spec clear_old(t, non_neg_integer) :: t def clear_old(%TestVersionMap{} = vm, up_to_version) do Enum.reject(vm.ranges, fn {_range, ver} -> ver <= up_to_version end) |> then(fn ranges -> %{vm | ranges: ranges} end) end end