%%% Copyright (c) 2014, NORDUnet A/S. %%% See LICENSE for licensing information. %%% %% tree storage, TODO: docdoc -module(ts). -include_lib("eunit/include/eunit.hrl"). -export_type([tree_store/0]). -export([new/0, store/3, append/3, truncate/2, retrieve/2, retrieve_hash/2, delete/2]). %% FIXME: swap IR -> RI for consistency with ht %% FIXME: Keep the arrays in an array instead of in a map? Or maybe an %% array of binaries? Hashes do have fixed lenght. -record(tree_store, {arrays :: map()}). % Map of arrays, indexed by layer. -type tree_store() :: #tree_store{}. new() -> #tree_store{arrays = #{}}. -spec store(tree_store(), tuple(), binary()) -> tree_store(). store(S = #tree_store{arrays = Arrays}, {I, R}, Hash) -> {A, NewArrays} = get_array(R, Arrays), Index = case I of append -> array:size(A); N -> N end, S#tree_store{arrays = maps:put(R, array:set(Index, Hash, A), NewArrays)}. -spec retrieve(tree_store(), tuple()) -> {tuple(), binary()}. retrieve(#tree_store{arrays = Arrays}, {I, R}) -> {{I, R}, case maps:get(R, Arrays, undefined) of undefined -> undefined; A -> array:get(I, A) end}. -spec retrieve_hash(tree_store(), tuple()) -> binary(). retrieve_hash(S, IR) -> element(2, retrieve(S, IR)). -spec delete(tree_store(), tuple()) -> tree_store(). delete(S, {I, R}) -> {A, NewArrays} = get_array(R, S#tree_store.arrays), Index = case I of last -> array:size(A) - 1; N -> N end, S#tree_store{arrays = maps:put(R, array:reset(Index, A), NewArrays)}. append(S, R, Hash) -> store(S, {append, R}, Hash). truncate(S, R) -> delete(S, {last, R}). %% Private get_array(Layer, Arrays) -> case maps:is_key(Layer, Arrays) of true -> {maps:get(Layer, Arrays), Arrays} ; false -> NewArray = array:new(), {NewArray, maps:put(Layer, NewArray, Arrays)} end. %%%%%%%%%%%%%%%%%%%% %% Testing ts. -define(TEST_VECTOR, {{{0,0}, <<00>>}, {{0,1}, <<01>>}, {{1,0}, <<10>>}}). store_test_() -> T = ?TEST_VECTOR, S = new(), S0 = store(S, {0,0}, <<00>>), S1 = store(S0, {0,1}, <<01>>), S2 = store(S1, {1,0}, <<10>>), [?_assertEqual(retrieve(S2, {1,0}), element(3, T)), ?_assertEqual(retrieve(S2, {0,1}), element(2, T)), ?_assertEqual(retrieve(S2, {0,0}), element(1, T)), ?_assertEqual(retrieve_hash(S2, {3,0}), undefined), ?_assertEqual(retrieve_hash(S1, {1,0}), undefined) ].