mirror of
https://github.com/processone/ejabberd.git
synced 2024-12-26 17:38:45 +01:00
584fa98564
- bounce messages when closing c2s session; - implemented treap:to_list/1 and treap:from_list/1
195 lines
5.0 KiB
Erlang
195 lines
5.0 KiB
Erlang
%%%----------------------------------------------------------------------
|
|
%%% File : treap.erl
|
|
%%% Author : Alexey Shchepin <alexey@process-one.net>
|
|
%%% Purpose : Treaps implementation
|
|
%%% Created : 22 Apr 2008 by Alexey Shchepin <alexey@process-one.net>
|
|
%%%
|
|
%%%
|
|
%%% ejabberd, Copyright (C) 2002-2010 ProcessOne
|
|
%%%
|
|
%%% This program is free software; you can redistribute it and/or
|
|
%%% modify it under the terms of the GNU General Public License as
|
|
%%% published by the Free Software Foundation; either version 2 of the
|
|
%%% License, or (at your option) any later version.
|
|
%%%
|
|
%%% This program is distributed in the hope that it will be useful,
|
|
%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
%%% General Public License for more details.
|
|
%%%
|
|
%%% You should have received a copy of the GNU General Public License
|
|
%%% along with this program; if not, write to the Free Software
|
|
%%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
|
%%% 02111-1307 USA
|
|
%%%
|
|
%%%----------------------------------------------------------------------
|
|
|
|
-module(treap).
|
|
|
|
-export([empty/0,
|
|
insert/4,
|
|
delete/2,
|
|
delete_root/1,
|
|
get_root/1,
|
|
lookup/2,
|
|
is_empty/1,
|
|
fold/3,
|
|
from_list/1,
|
|
to_list/1]).
|
|
|
|
empty() ->
|
|
nil.
|
|
|
|
insert(Key, Priority, Value, Tree) ->
|
|
HashKey = {erlang:phash2(Key), Key},
|
|
insert1(Tree, HashKey, Priority, Value).
|
|
|
|
insert1(nil, HashKey, Priority, Value) ->
|
|
{HashKey, Priority, Value, nil, nil};
|
|
insert1({HashKey1, Priority1, Value1, Left, Right} = Tree,
|
|
HashKey, Priority, Value) ->
|
|
if
|
|
HashKey < HashKey1 ->
|
|
heapify({HashKey1, Priority1, Value1,
|
|
insert1(Left, HashKey, Priority, Value),
|
|
Right});
|
|
HashKey > HashKey1 ->
|
|
heapify({HashKey1, Priority1, Value1,
|
|
Left,
|
|
insert1(Right, HashKey, Priority, Value)});
|
|
Priority == Priority1 ->
|
|
{HashKey, Priority, Value, Left, Right};
|
|
true ->
|
|
insert1(delete_root(Tree), HashKey, Priority, Value)
|
|
end.
|
|
|
|
heapify(nil) ->
|
|
nil;
|
|
heapify({_HashKey, _Priority, _Value, nil, nil} = Tree) ->
|
|
Tree;
|
|
heapify({HashKey, Priority, Value,
|
|
nil = Left,
|
|
{HashKeyR, PriorityR, ValueR, LeftR, RightR}} = Tree) ->
|
|
if
|
|
PriorityR > Priority ->
|
|
{HashKeyR, PriorityR, ValueR,
|
|
{HashKey, Priority, Value, Left, LeftR},
|
|
RightR};
|
|
true ->
|
|
Tree
|
|
end;
|
|
heapify({HashKey, Priority, Value,
|
|
{HashKeyL, PriorityL, ValueL, LeftL, RightL},
|
|
nil = Right} = Tree) ->
|
|
if
|
|
PriorityL > Priority ->
|
|
{HashKeyL, PriorityL, ValueL,
|
|
LeftL,
|
|
{HashKey, Priority, Value, RightL, Right}};
|
|
true ->
|
|
Tree
|
|
end;
|
|
heapify({HashKey, Priority, Value,
|
|
{HashKeyL, PriorityL, ValueL, LeftL, RightL} = Left,
|
|
{HashKeyR, PriorityR, ValueR, LeftR, RightR} = Right} = Tree) ->
|
|
if
|
|
PriorityR > Priority ->
|
|
{HashKeyR, PriorityR, ValueR,
|
|
{HashKey, Priority, Value, Left, LeftR},
|
|
RightR};
|
|
PriorityL > Priority ->
|
|
{HashKeyL, PriorityL, ValueL,
|
|
LeftL,
|
|
{HashKey, Priority, Value, RightL, Right}};
|
|
true ->
|
|
Tree
|
|
end.
|
|
|
|
|
|
delete(Key, Tree) ->
|
|
HashKey = {erlang:phash2(Key), Key},
|
|
delete1(HashKey, Tree).
|
|
|
|
delete1(_HashKey, nil) ->
|
|
nil;
|
|
delete1(HashKey, {HashKey1, Priority1, Value1, Left, Right} = Tree) ->
|
|
if
|
|
HashKey < HashKey1 ->
|
|
{HashKey1, Priority1, Value1, delete1(HashKey, Left), Right};
|
|
HashKey > HashKey1 ->
|
|
{HashKey1, Priority1, Value1, Left, delete1(HashKey, Right)};
|
|
true ->
|
|
delete_root(Tree)
|
|
end.
|
|
|
|
delete_root({HashKey, Priority, Value, Left, Right}) ->
|
|
case {Left, Right} of
|
|
{nil, nil} ->
|
|
nil;
|
|
{_, nil} ->
|
|
Left;
|
|
{nil, _} ->
|
|
Right;
|
|
{{HashKeyL, PriorityL, ValueL, LeftL, RightL},
|
|
{HashKeyR, PriorityR, ValueR, LeftR, RightR}} ->
|
|
if
|
|
PriorityL > PriorityR ->
|
|
{HashKeyL, PriorityL, ValueL,
|
|
LeftL,
|
|
delete_root({HashKey, Priority, Value, RightL, Right})};
|
|
true ->
|
|
{HashKeyR, PriorityR, ValueR,
|
|
delete_root({HashKey, Priority, Value, Left, LeftR}),
|
|
RightR}
|
|
end
|
|
end.
|
|
|
|
is_empty(nil) ->
|
|
true;
|
|
is_empty({_HashKey, _Priority, _Value, _Left, _Right}) ->
|
|
false.
|
|
|
|
get_root({{_Hash, Key}, Priority, Value, _Left, _Right}) ->
|
|
{Key, Priority, Value}.
|
|
|
|
|
|
lookup(Key, Tree) ->
|
|
HashKey = {erlang:phash2(Key), Key},
|
|
lookup1(Tree, HashKey).
|
|
|
|
lookup1(nil, _HashKey) ->
|
|
error;
|
|
lookup1({HashKey1, Priority1, Value1, Left, Right}, HashKey) ->
|
|
if
|
|
HashKey < HashKey1 ->
|
|
lookup1(Left, HashKey);
|
|
HashKey > HashKey1 ->
|
|
lookup1(Right, HashKey);
|
|
true ->
|
|
{ok, Priority1, Value1}
|
|
end.
|
|
|
|
fold(_F, Acc, nil) ->
|
|
Acc;
|
|
fold(F, Acc, {{_Hash, Key}, Priority, Value, Left, Right}) ->
|
|
Acc1 = F({Key, Priority, Value}, Acc),
|
|
Acc2 = fold(F, Acc1, Left),
|
|
fold(F, Acc2, Right).
|
|
|
|
to_list(Tree) ->
|
|
to_list(Tree, []).
|
|
|
|
to_list(nil, Acc) ->
|
|
Acc;
|
|
to_list(Tree, Acc) ->
|
|
Root = get_root(Tree),
|
|
to_list(delete_root(Tree), [Root|Acc]).
|
|
|
|
from_list(List) ->
|
|
from_list(List, nil).
|
|
|
|
from_list([{Key, Priority, Value}|Tail], Tree) ->
|
|
from_list(Tail, insert(Key, Priority, Value, Tree));
|
|
from_list([], Tree) ->
|
|
Tree.
|