%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%% =====================================================================
%% General Balanced Trees - highly efficient dictionaries.
%%
%% Copyright (C) 1999-2001 Sven-Olof Nyström, Richard Carlsson
%%
%% An efficient implementation of Prof. Arne Andersson's General
%% Balanced Trees. These have no storage overhead compared to plain
%% unbalanced binary trees, and their performance is in general better
%% than AVL trees.
%% ---------------------------------------------------------------------
%% Operations:
%%
%% - empty(): returns empty tree.
%%
%% - is_empty(T): returns 'true' if T is an empty tree, and 'false'
%% otherwise.
%%
%% - size(T): returns the number of nodes in the tree as an integer.
%% Returns 0 (zero) if the tree is empty.
%%
%% - lookup(X, T): looks up key X in tree T; returns {value, V}, or
%% `none' if the key is not present.
%%
%% - get(X, T): retreives the value stored with key X in tree T. Assumes
%% that the key is present in the tree.
%%
%% - insert(X, V, T): inserts key X with value V into tree T; returns
%% the new tree. Assumes that the key is *not* present in the tree.
%%
%% - update(X, V, T): updates key X to value V in tree T; returns the
%% new tree. Assumes that the key is present in the tree.
%%
%% - enter(X, V, T): inserts key X with value V into tree T if the key
%% is not present in the tree, otherwise updates key X to value V in
%% T. Returns the new tree.
%%
%% - delete(X, T): removes key X from tree T; returns new tree. Assumes
%% that the key is present in the tree.
%%
%% - delete_any(X, T): removes key X from tree T if the key is present
%% in the tree, otherwise does nothing; returns new tree.
%%
%% - take(X, T): removes element with key X from tree T; returns new tree
%% without removed element. Assumes that the key is present in the tree.
%%
%% - take_any(X, T): removes element with key X from tree T and returns
%% a new tree if the key is present; otherwise does nothing and returns
%% 'error'.
%%
%% - balance(T): rebalances tree T. Note that this is rarely necessary,
%% but may be motivated when a large number of entries have been
%% deleted from the tree without further insertions. Rebalancing could
%% then be forced in order to minimise lookup times, since deletion
%% only does not rebalance the tree.
%%
%% - is_defined(X, T): returns `true' if key X is present in tree T, and
%% `false' otherwise.
%%
%% - keys(T): returns an ordered list of all keys in tree T.
%%
%% - values(T): returns the list of values for all keys in tree T,
%% sorted by their corresponding keys. Duplicates are not removed.
%%
%% - to_list(T): returns an ordered list of {Key, Value} pairs for all
%% keys in tree T.
%%
%% - from_orddict(L): turns an ordered list L of {Key, Value} pairs into
%% a tree. The list must not contain duplicate keys.
%%
%% - smallest(T): returns {X, V}, where X is the smallest key in tree T,
%% and V is the value associated with X in T. Assumes that the tree T
%% is nonempty.
%%
%% - largest(T): returns {X, V}, where X is the largest key in tree T,
%% and V is the value associated with X in T. Assumes that the tree T
%% is nonempty.
%%
%% - take_smallest(T): returns {X, V, T1}, where X is the smallest key
%% in tree T, V is the value associated with X in T, and T1 is the
%% tree T with key X deleted. Assumes that the tree T is nonempty.
%%
%% - take_largest(T): returns {X, V, T1}, where X is the largest key
%% in tree T, V is the value associated with X in T, and T1 is the
%% tree T with key X deleted. Assumes that the tree T is nonempty.
%%
%% - iterator(T): returns an iterator that can be used for traversing
%% the entries of tree T; see `next'. The implementation of this is
%% very efficient; traversing the whole tree using `next' is only
%% slightly slower than getting the list of all elements using
%% `to_list' and traversing that. The main advantage of the iterator
%% approach is that it does not require the complete list of all
%% elements to be built in memory at one time.
%%
%% - iterator_from(K, T): returns an iterator that can be used for
%% traversing the entries of tree T with key greater than or
%% equal to K; see `next'.
%%
%% - next(S): returns {X, V, S1} where X is the smallest key referred to
%% by the iterator S, and S1 is the new iterator to be used for
%% traversing the remaining entries, or the atom `none' if no entries
%% remain.
%%
%% - map(F, T): maps the function F(K, V) -> V' to all key-value pairs
%% of the tree T and returns a new tree T' with the same set of keys
%% as T and the new set of values V'.
-module(gb_trees).
-export([empty/0, is_empty/1, size/1, lookup/2, get/2, insert/3,
update/3, enter/3, delete/2, delete_any/2, balance/1,
is_defined/2, keys/1, values/1, to_list/1, from_orddict/1,
smallest/1, largest/1, take/2, take_any/2,
take_smallest/1, take_largest/1,
iterator/1, iterator_from/2, next/1, map/2]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Data structure:
%% - {Size, Tree}, where `Tree' is composed of nodes of the form:
%% - {Key, Value, Smaller, Bigger}, and the "empty tree" node:
%% - nil.
%%
%% I make no attempt to balance trees after deletions. Since deletions
%% don't increase the height of a tree, I figure this is OK.
%%
%% Original balance condition h(T) <= ceil(c * log(|T|)) has been
%% changed to the similar (but not quite equivalent) condition 2 ^ h(T)
%% <= |T| ^ c. I figure this should also be OK.
%%
%% Performance is comparable to the AVL trees in the Erlang book (and
%% faster in general due to less overhead); the difference is that
%% deletion works for my trees, but not for the book's trees. Behaviour
%% is logaritmic (as it should be).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Some macros.
-define(p, 2). % It seems that p = 2 is optimal for sorted keys
-define(pow(A, _), A * A). % correct with exponent as defined above.
-define(div2(X), X bsr 1).
-define(mul2(X), X bsl 1).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Some types.
-export_type([tree/0, tree/2, iter/0, iter/2]).
-type gb_tree_node(K, V) :: 'nil'
| {K, V, gb_tree_node(K, V), gb_tree_node(K, V)}.
-opaque tree(Key, Value) :: {non_neg_integer(), gb_tree_node(Key, Value)}.
-type tree() :: tree(_, _).
-opaque iter(Key, Value) :: [gb_tree_node(Key, Value)].
-type iter() :: iter(_, _).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-spec empty() -> tree().
empty() ->
{0, nil}.
-spec is_empty(Tree) -> boolean() when
Tree :: tree().
is_empty({0, nil}) ->
true;
is_empty(_) ->
false.
-spec size(Tree) -> non_neg_integer() when
Tree :: tree().
size({Size, _}) when is_integer(Size), Size >= 0 ->
Size.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-spec lookup(Key, Tree) -> 'none' | {'value', Value} when
Tree :: tree(Key, Value).
lookup(Key, {_, T}) ->
lookup_1(Key, T).
%% The term order is an arithmetic total order, so we should not
%% test exact equality for the keys. (If we do, then it becomes
%% possible that neither `>', `<', nor `=:=' matches.) Testing '<'
%% and '>' first is statistically better than testing for
%% equality, and also allows us to skip the test completely in the
%% remaining case.
lookup_1(Key, {Key1, _, Smaller, _}) when Key < Key1 ->
lookup_1(Key, Smaller);
lookup_1(Key, {Key1, _, _, Bigger}) when Key > Key1 ->
lookup_1(Key, Bigger);
lookup_1(_, {_, Value, _, _}) ->
{value, Value};
lookup_1(_, nil) ->
none.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% This is a specialized version of `lookup'.
-spec is_defined(Key, Tree) -> boolean() when
Tree :: tree(Key, Value :: term()).
is_defined(Key, {_, T}) ->
is_defined_1(Key, T).
is_defined_1(Key, {Key1, _, Smaller, _}) when Key < Key1 ->
is_defined_1(Key, Smaller);
is_defined_1(Key, {Key1, _, _, Bigger}) when Key > Key1 ->
is_defined_1(Key, Bigger);
is_defined_1(_, {_, _, _, _}) ->
true;
is_defined_1(_, nil) ->
false.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% This is a specialized version of `lookup'.
-spec get(Key, Tree) -> Value when
Tree :: tree(Key, Value).
get(Key, {_, T}) ->
get_1(Key, T).
get_1(Key, {Key1, _, Smaller, _}) when Key < Key1 ->
get_1(Key, Smaller);
get_1(Key, {Key1, _, _, Bigger}) when Key > Key1 ->
get_1(Key, Bigger);
get_1(_, {_, Value, _, _}) ->
Value.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-spec update(Key, Value, Tree1) -> Tree2 when
Tree1 :: tree(Key, Value),
Tree2 :: tree(Key, Value).
update(Key, Val, {S, T}) ->
T1 = update_1(Key, Val, T),
{S, T1}.
%% See `lookup' for notes on the term comparison order.
update_1(Key, Value, {Key1, V, Smaller, Bigger}) when Key < Key1 ->
{Key1, V, update_1(Key, Value, Smaller), Bigger};
update_1(Key, Value, {Key1, V, Smaller, Bigger}) when Key > Key1 ->
{Key1, V, Smaller, update_1(Key, Value, Bigger)};
update_1(Key, Value, {_, _, Smaller, Bigger}) ->
{Key, Value, Smaller, Bigger}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-spec insert(Key, Value, Tree1) -> Tree2 when
Tree1 :: tree(Key, Value),
Tree2 :: tree(Key, Value).
insert(Key, Val, {S, T}) when is_integer(S) ->
S1 = S+1,
{S1, insert_1(Key, Val, T, ?pow(S1, ?p))}.
insert_1(Key, Value, {Key1, V, Smaller, Bigger}, S) when Key < Key1 ->
case insert_1(Key, Value, Smaller, ?div2(S)) of
{T1, H1, S1} ->
T = {Key1, V, T1, Bigger},
{H2, S2} = count(Bigger),
H = ?mul2(erlang:max(H1, H2)),
SS = S1 + S2 + 1,
P = ?pow(SS, ?p),
if
H > P ->
balance(T, SS);
true ->
{T, H, SS}
end;
T1 ->
{Key1, V, T1, Bigger}
end;
insert_1(Key, Value, {Key1, V, Smaller, Bigger}, S) when Key > Key1 ->
case insert_1(Key, Value, Bigger, ?div2(S)) of
{T1, H1, S1} ->
T = {Key1, V, Smaller, T1},
{H2, S2} = count(Smaller),
H = ?mul2(erlang:max(H1, H2)),
SS = S1 + S2 + 1,
P = ?pow(SS, ?p),
if
H > P ->
balance(T, SS);
true ->
{T, H, SS}
end;
T1 ->
{Key1, V, Smaller, T1}
end;
insert_1(Key, Value, nil, S) when S =:= 0 ->
{{Key, Value, nil, nil}, 1, 1};
insert_1(Key, Value, nil, _S) ->
{Key, Value, nil, nil};
insert_1(Key, _, _, _) ->
erlang:error({key_exists, Key}).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-spec enter(Key, Value, Tree1) -> Tree2 when
Tree1 :: tree(Key, Value),
Tree2 :: tree(Key, Value).
enter(Key, Val, T) ->
case is_defined(Key, T) of
true ->
update(Key, Val, T);
false ->
insert(Key, Val, T)
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
count({_, _, nil, nil}) ->
{1, 1};
count({_, _, Sm, Bi}) ->
{H1, S1} = count(Sm),
{H2, S2} = count(Bi),
{?mul2(erlang:max(H1, H2)), S1 + S2 + 1};
count(nil) ->
{1, 0}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-spec balance(Tree1) -> Tree2 when
Tree1 :: tree(Key, Value),
Tree2 :: tree(Key, Value).
balance({S, T}) ->
{S, balance(T, S)}.
balance(T, S) ->
balance_list(to_list_1(T), S).
balance_list(L, S) ->
{T, []} = balance_list_1(L, S),
T.
balance_list_1(L, S) when S > 1 ->
Sm = S - 1,
S2 = Sm div 2,
S1 = Sm - S2,
{T1, [{K, V} | L1]} = balance_list_1(L, S1),
{T2, L2} = balance_list_1(L1, S2),
T = {K, V, T1, T2},
{T, L2};
balance_list_1([{Key, Val} | L], 1) ->
{{Key, Val, nil, nil}, L};
balance_list_1(L, 0) ->
{nil, L}.
-spec from_orddict(List) -> Tree when
List :: [{Key, Value}],
Tree :: tree(Key, Value).
from_orddict(L) ->
S = length(L),
{S, balance_list(L, S)}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-spec delete_any(Key, Tree1) -> Tree2 when
Tree1 :: tree(Key, Value),
Tree2 :: tree(Key, Value).
delete_any(Key, T) ->
case is_defined(Key, T) of
true ->
delete(Key, T);
false ->
T
end.
%%% delete. Assumes that key is present.
-spec delete(Key, Tree1) -> Tree2 when
Tree1 :: tree(Key, Value),
Tree2 :: tree(Key, Value).
delete(Key, {S, T}) when is_integer(S), S >= 0 ->
{S - 1, delete_1(Key, T)}.
%% See `lookup' for notes on the term comparison order.
delete_1(Key, {Key1, Value, Smaller, Larger}) when Key < Key1 ->
Smaller1 = delete_1(Key, Smaller),
{Key1, Value, Smaller1, Larger};
delete_1(Key, {Key1, Value, Smaller, Bigger}) when Key > Key1 ->
Bigger1 = delete_1(Key, Bigger),
{Key1, Value, Smaller, Bigger1};
delete_1(_, {_, _, Smaller, Larger}) ->
merge(Smaller, Larger).
merge(Smaller, nil) ->
Smaller;
merge(nil, Larger) ->
Larger;
merge(Smaller, Larger) ->
{Key, Value, Larger1} = take_smallest1(Larger),
{Key, Value, Smaller, Larger1}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-spec take_any(Key, Tree1) -> {Value, Tree2} | 'error' when
Tree1 :: tree(Key, _),
Tree2 :: tree(Key, _),
Key :: term(),
Value :: term().
take_any(Key, Tree) ->
case is_defined(Key, Tree) of
true -> take(Key, Tree);
false -> error
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-spec take(Key, Tree1) -> {Value, Tree2} when
Tree1 :: tree(Key, _),
Tree2 :: tree(Key, _),
Key :: term(),
Value :: term().
take(Key, {S, T}) when is_integer(S), S >= 0 ->
{Value, Res} = take_1(Key, T),
{Value, {S - 1, Res}}.
take_1(Key, {Key1, Value, Smaller, Larger}) when Key < Key1 ->
{Value2, Smaller1} = take_1(Key, Smaller),
{Value2, {Key1, Value, Smaller1, Larger}};
take_1(Key, {Key1, Value, Smaller, Bigger}) when Key > Key1 ->
{Value2, Bigger1} = take_1(Key, Bigger),
{Value2, {Key1, Value, Smaller, Bigger1}};
take_1(_, {_Key, Value, Smaller, Larger}) ->
{Value, merge(Smaller, Larger)}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-spec take_smallest(Tree1) -> {Key, Value, Tree2} when
Tree1 :: tree(Key, Value),
Tree2 :: tree(Key, Value).
take_smallest({Size, Tree}) when is_integer(Size), Size >= 0 ->
{Key, Value, Larger} = take_smallest1(Tree),
{Key, Value, {Size - 1, Larger}}.
take_smallest1({Key, Value, nil, Larger}) ->
{Key, Value, Larger};
take_smallest1({Key, Value, Smaller, Larger}) ->
{Key1, Value1, Smaller1} = take_smallest1(Smaller),
{Key1, Value1, {Key, Value, Smaller1, Larger}}.
-spec smallest(Tree) -> {Key, Value} when
Tree :: tree(Key, Value).
smallest({_, Tree}) ->
smallest_1(Tree).
smallest_1({Key, Value, nil, _Larger}) ->
{Key, Value};
smallest_1({_Key, _Value, Smaller, _Larger}) ->
smallest_1(Smaller).
-spec take_largest(Tree1) -> {Key, Value, Tree2} when
Tree1 :: tree(Key, Value),
Tree2 :: tree(Key, Value).
take_largest({Size, Tree}) when is_integer(Size), Size >= 0 ->
{Key, Value, Smaller} = take_largest1(Tree),
{Key, Value, {Size - 1, Smaller}}.
take_largest1({Key, Value, Smaller, nil}) ->
{Key, Value, Smaller};
take_largest1({Key, Value, Smaller, Larger}) ->
{Key1, Value1, Larger1} = take_largest1(Larger),
{Key1, Value1, {Key, Value, Smaller, Larger1}}.
-spec largest(Tree) -> {Key, Value} when
Tree :: tree(Key, Value).
largest({_, Tree}) ->
largest_1(Tree).
largest_1({Key, Value, _Smaller, nil}) ->
{Key, Value};
largest_1({_Key, _Value, _Smaller, Larger}) ->
largest_1(Larger).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-spec to_list(Tree) -> [{Key, Value}] when
Tree :: tree(Key, Value).
to_list({_, T}) ->
to_list(T, []).
to_list_1(T) -> to_list(T, []).
to_list({Key, Value, Small, Big}, L) ->
to_list(Small, [{Key, Value} | to_list(Big, L)]);
to_list(nil, L) -> L.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-spec keys(Tree) -> [Key] when
Tree :: tree(Key, Value :: term()).
keys({_, T}) ->
keys(T, []).
keys({Key, _Value, Small, Big}, L) ->
keys(Small, [Key | keys(Big, L)]);
keys(nil, L) -> L.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-spec values(Tree) -> [Value] when
Tree :: tree(Key :: term(), Value).
values({_, T}) ->
values(T, []).
values({_Key, Value, Small, Big}, L) ->
values(Small, [Value | values(Big, L)]);
values(nil, L) -> L.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-spec iterator(Tree) -> Iter when
Tree :: tree(Key, Value),
Iter :: iter(Key, Value).
iterator({_, T}) ->
iterator_1(T).
iterator_1(T) ->
iterator(T, []).
%% The iterator structure is really just a list corresponding to
%% the call stack of an in-order traversal. This is quite fast.
iterator({_, _, nil, _} = T, As) ->
[T | As];
iterator({_, _, L, _} = T, As) ->
iterator(L, [T | As]);
iterator(nil, As) ->
As.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-spec iterator_from(Key, Tree) -> Iter when
Tree :: tree(Key, Value),
Iter :: iter(Key, Value).
iterator_from(S, {_, T}) ->
iterator_1_from(S, T).
iterator_1_from(S, T) ->
iterator_from(S, T, []).
iterator_from(S, {K, _, _, T}, As) when K < S ->
iterator_from(S, T, As);
iterator_from(_, {_, _, nil, _} = T, As) ->
[T | As];
iterator_from(S, {_, _, L, _} = T, As) ->
iterator_from(S, L, [T | As]);
iterator_from(_, nil, As) ->
As.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-spec next(Iter1) -> 'none' | {Key, Value, Iter2} when
Iter1 :: iter(Key, Value),
Iter2 :: iter(Key, Value).
next([{X, V, _, T} | As]) ->
{X, V, iterator(T, As)};
next([]) ->
none.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-spec map(Function, Tree1) -> Tree2 when
Function :: fun((K :: Key, V1 :: Value1) -> V2 :: Value2),
Tree1 :: tree(Key, Value1),
Tree2 :: tree(Key, Value2).
map(F, {Size, Tree}) when is_function(F, 2) ->
{Size, map_1(F, Tree)}.
map_1(_, nil) -> nil;
map_1(F, {K, V, Smaller, Larger}) ->
{K, F(K, V), map_1(F, Smaller), map_1(F, Larger)}.