summaryrefslogtreecommitdiff
path: root/src/ts.erl
blob: c69519c8d2a957a33f4b6e66698013777df7487d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
%%% 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, add/3, delete/2, retrieve/2, count/2]).

%% #tree_store{} has one member, layers, holding an array of arrays
%% with binaries, keyed on layer.
-record(tree_store, {layers :: array:array(array:array(binary()))}).
-type tree_store() :: #tree_store{}.

%%%%%%%%%%%%%%%%%%%%
%% Public.
new() ->
    #tree_store{layers = array:new()}.

-spec add(tree_store(), non_neg_integer(), binary()) -> tree_store().
add(S = #tree_store{layers = Layers}, Layer, Entry) ->
    {NewLayers, Array} = layer_rw(Layers, Layer),
    NewArray = array:set(array:size(Array), Entry, Array),
    S#tree_store{layers = array:set(Layer, NewArray, NewLayers)}.

-spec delete(tree_store(), non_neg_integer()) -> tree_store().
delete(S = #tree_store{layers = Layers}, Layer) ->
    Array = layer_ro(Layers, Layer),
    NewArray = array:resize(array:size(Array) - 1, Array),
    S#tree_store{layers = array:set(Layer, NewArray, Layers)}.

-spec retrieve(tree_store(), tuple()) -> binary() | undefined.
retrieve(#tree_store{layers = Layers}, {Layer, Index}) ->
    Array = layer_ro(Layers, Layer),
    Len = array:size(Array),
    case Index < Len of
        true -> array:get(Index, Array);
        false -> undefined
    end.

-spec count(tree_store(), non_neg_integer()) -> non_neg_integer().
count(#tree_store{layers = Layers}, Layer) ->
    array:size(layer_ro(Layers, Layer)).

%%%%%%%%%%%%%%%%%%%%
%% Private.
-spec layer_ro(array:array(array:array(binary())), non_neg_integer()) ->
                      array:array(binary).
layer_ro(Layers, Layer) ->
    case array:get(Layer, Layers) of
        undefined -> array:new();
        Array -> Array
    end.

-spec layer_rw(array:array(array:array(binary())), non_neg_integer()) ->
                      {array:array(), array:array(binary)}.
layer_rw(Layers, Layer) ->
    case array:get(Layer, Layers) of
        undefined -> {array:set(Layer, array:new(), Layers), array:new()};
        Array -> {Layers, Array}
    end.

%%%%%%%%%%%%%%%%%%%%
%% Testing ts.
add_retrieve_test_() ->
    S = new(),
    S0 = add(S, 0, <<00>>),
    S1 = add(S0, 0, <<01>>),
    S2 = add(S1, 1, <<10>>),
    [?_assertEqual(2, count(S2, 0)),
     ?_assertEqual(1, count(S2, 1)),
     ?_assertEqual(<<10>>, retrieve(S2, {1,0})),
     ?_assertEqual(<<00>>, retrieve(S2, {0,0})),
     ?_assertEqual(<<01>>, retrieve(S2, {0,1})),
     ?_assertEqual(<<00>>, retrieve(S2, {0,0})),
     ?_assertEqual(undefined, retrieve(S2, {3,0})),
     ?_assertEqual(undefined, retrieve(S1, {1,0}))].

delete_test_() ->
    S = new(),
    S0 = add(S, 0, <<00>>),
    S1 = add(S0, 0, <<01>>),
    S2 = add(S1, 1, <<10>>),
    S3 = delete(S2, 0),
    S4 = add(S3, 0, <<99>>),
    [?_assertEqual(2, count(S2, 0)),
     ?_assertEqual(1, count(S3, 0)),
     ?_assertEqual(2, count(S4, 0)),
     ?_assertEqual(retrieve(S2, {0,1}), <<01>>),
     ?_assertEqual(retrieve(S3, {0,1}), undefined),
     ?_assertEqual(retrieve(S3, {0,0}), <<00>>),
     ?_assertEqual(retrieve(S4, {0,1}), <<99>>)].