dets_utils.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 1,580 行 · 第 1/4 页
ERL
1,580 行
none;find_next_free(_Ftab, _Addr, _Pos, _MaxBud, Next, PosN, _Base) -> {Next, PosN}.collect_all_interval(Ftab, Addr, MaxAddr, Base) -> MaxBud = size(Ftab), collect_all_interval(Ftab, Addr, MaxAddr, 1, MaxBud, Base, []).collect_all_interval(Ftab, L0, U, Pos, MaxBud, Base, Acc0) when Pos =< MaxBud -> PosTab = element(Pos, Ftab), L = adjust_addr(L0, Pos, Base), Acc = collect_interval(PosTab, Pos, L, U, Acc0), collect_all_interval(Ftab, L0, U, Pos+1, MaxBud, Base, Acc);collect_all_interval(_Ftab, _L, _U, _Pos, _MaxBud, _Base, Acc) -> lists:sort(Acc).%% It could be that Addr is inside a free area. This function adjusts%% the address so that is placed on a boundary in the Pos tree. Inlined.adjust_addr(Addr, Pos, Base) -> Pow = ?POW(Pos - 1), Rem = (Addr - Base) rem Pow, if Rem =:= 0 -> Addr; Addr < Pow -> Addr; true -> Addr - Rem end.%%%-----------------------------------------------------------------%%% These functions implements a B+ tree.%%% The code is originally written by lelle@erlang.ericsson.se,%%%------------------------------------------------------------------define(max_size, 16).-define(min_size, 8).%%-----------------------------------------------------------------%% Finds out the type of the node: 'l' or 'n'.%%------------------------------------------------------------------define(NODE_TYPE(Tree), element(1, Tree)).%% Finds out if a node/leaf is full or not.-define(FULL(Tree), (bplus_get_size(Tree) >= ?max_size)).%% Finds out if a node/leaf is filled up over its limit.-define(OVER_FULL(Tree), (bplus_get_size(Tree) > ?max_size)).%% Finds out if a node/leaf has less items than allowed.-define(UNDER_FILLED(Tree), (bplus_get_size(Tree) < ?min_size)).%% Finds out if a node/leaf has as few items as minimum allowed.-define(LOW_FILLED(Tree), (bplus_get_size(Tree) =< ?min_size)).%%Returns a key in a leaf at position Pos.-define(GET_LEAF_KEY(Leaf, Pos), element(Pos+1, Leaf)).%% Special for dets.collect_tree(v, _TI, Acc) -> Acc;collect_tree(T, TI, Acc) -> Pow = ?POW(TI-1), collect_tree2(T, Pow, Acc).collect_tree2(Tree, Pow, Acc) -> S = bplus_get_size(Tree), case ?NODE_TYPE(Tree) of l -> collect_leaf(Tree, S, Pow, Acc); n -> collect_node(Tree, S, Pow, Acc) end. collect_leaf(_Leaf, 0, _Pow, Acc) -> Acc;collect_leaf(Leaf, I, Pow, Acc) -> Key = ?GET_LEAF_KEY(Leaf, I), V = {Key, Key+Pow}, collect_leaf(Leaf, I-1, Pow, [V | Acc]).collect_node(_Node, 0, _Pow, Acc) -> Acc;collect_node(Node, I, Pow, Acc) -> Acc1 = collect_tree2(bplus_get_tree(Node, I), Pow, Acc), collect_node(Node, I-1, Pow, Acc1).%% Special for dets.tree_to_bin(v, _F, _Max, Ws, WsSz) -> {Ws, WsSz};tree_to_bin(T, F, Max, Ws, WsSz) -> {N, L1, Ws1, WsSz1} = tree_to_bin2(T, F, Max, 0, [], Ws, WsSz), {N1, L2, Ws2, WsSz2} = F(N, lists:reverse(L1), Ws1, WsSz1), {0, [], NWs, NWsSz} = F(N1, L2, Ws2, WsSz2), {NWs, NWsSz}.tree_to_bin2(Tree, F, Max, N, Acc, Ws, WsSz) when N >= Max -> {NN, NAcc, NWs, NWsSz} = F(N, lists:reverse(Acc), Ws, WsSz), tree_to_bin2(Tree, F, Max, NN, lists:reverse(NAcc), NWs, NWsSz);tree_to_bin2(Tree, F, Max, N, Acc, Ws, WsSz) -> S = bplus_get_size(Tree), case ?NODE_TYPE(Tree) of l -> {N+S, leaf_to_bin(bplus_leaf_to_list(Tree), Acc), Ws, WsSz}; n -> node_to_bin(Tree, F, Max, N, Acc, 1, S, Ws, WsSz) end. node_to_bin(_Node, _F, _Max, N, Acc, I, S, Ws, WsSz) when I > S -> {N, Acc, Ws, WsSz};node_to_bin(Node, F, Max, N, Acc, I, S, Ws, WsSz) -> {N1,Acc1,Ws1,WsSz1} = tree_to_bin2(bplus_get_tree(Node, I), F, Max, N, Acc, Ws, WsSz), node_to_bin(Node, F, Max, N1, Acc1, I+1, S, Ws1, WsSz1).leaf_to_bin([N | L], Acc) -> leaf_to_bin(L, [<<N:32>> | Acc]);leaf_to_bin([], Acc) -> Acc.%% Special for dets. list_to_tree(L) -> leafs_to_nodes(L, length(L), fun bplus_mk_leaf/1, []).leafs_to_nodes([], 0, _F, [T]) -> T;leafs_to_nodes([], 0, _F, L) -> leafs_to_nodes(lists:reverse(L), length(L), fun mk_node/1, []);leafs_to_nodes(Ls, Sz, F, L) -> I = if Sz =< 16 -> Sz; Sz =< 32 -> Sz div 2; true -> 12 end, {L1, R} = split_list(Ls, I, []), N = F(L1), Sz1 = Sz - I, leafs_to_nodes(R, Sz1, F, [N | L]).mk_node([E | Es]) -> NL = [E | lists:foldr(fun(X, A) -> [get_first_key(X), X | A] end, [], Es)], bplus_mk_node(NL). split_list(L, 0, SL) -> {SL, L};split_list([E | Es], I, SL) -> split_list(Es, I-1, [E | SL]).get_first_key(T) -> case ?NODE_TYPE(T) of l -> ?GET_LEAF_KEY(T, 1); n -> get_first_key(bplus_get_tree(T, 1)) end.%% Special for dets.collect_interval(v, _TI, _L, _U, Acc) -> Acc;collect_interval(T, TI, L, U, Acc) -> Pow = ?POW(TI-1), collect_interval2(T, Pow, L, U, Acc).collect_interval2(Tree, Pow, L, U, Acc) -> S = bplus_get_size(Tree), case ?NODE_TYPE(Tree) of l -> collect_leaf_interval(Tree, S, Pow, L, U, Acc); n -> {Max, _} = bplus_select_sub_tree(Tree, U), {Min, _} = bplus_select_sub_tree_2(Tree, L, Max), collect_node_interval(Tree, Min, Max, Pow, L, U, Acc) end. collect_leaf_interval(_Leaf, 0, _Pow, _L, _U, Acc) -> Acc;collect_leaf_interval(Leaf, I, Pow, L, U, Acc) -> Key = ?GET_LEAF_KEY(Leaf, I), if Key < L -> Acc; Key > U -> collect_leaf_interval(Leaf, I-1, Pow, L, U, Acc); true -> collect_leaf_interval(Leaf, I-1, Pow, L, U, [{Key,Key+Pow} | Acc]) end.collect_node_interval(_Node, I, UP, _Pow, _L, _U, Acc) when I > UP -> Acc;collect_node_interval(Node, I, UP, Pow, L, U, Acc) -> Acc1 = collect_interval2(bplus_get_tree(Node, I), Pow, L, U, Acc), collect_node_interval(Node, I+1, UP, Pow, L, U, Acc1).%%-----------------------------------------------------------------%% Func: empty_tree/0%% Purpose: Creates a new empty tree.%% Returns: tree()%%-----------------------------------------------------------------bplus_empty_tree() -> v.%%-----------------------------------------------------------------%% Func: lookup/2%% Purpose: Looks for Key in the Tree.%% Returns: {ok, {Key, Val}} | 'undefined'.%%-----------------------------------------------------------------bplus_lookup(v, _Key) -> undefined;bplus_lookup(Tree, Key) -> case ?NODE_TYPE(Tree) of l -> bplus_lookup_leaf(Key, Tree); n -> {_, SubTree} = bplus_select_sub_tree(Tree, Key), bplus_lookup(SubTree, Key) end.%%-----------------------------------------------------------------%% Searches through a leaf until the Key is ok or%% when it is determined that it does not exist.%%-----------------------------------------------------------------bplus_lookup_leaf(Key, Leaf) -> bplus_lookup_leaf_2(Key, Leaf, bplus_get_size(Leaf)).bplus_lookup_leaf_2(_, _, 0) -> undefined;bplus_lookup_leaf_2(Key, Leaf, N) -> case ?GET_LEAF_KEY(Leaf, N) of Key -> {ok, Key}; _ -> bplus_lookup_leaf_2(Key, Leaf, N-1) end.%%-----------------------------------------------------------------%% Func: lookup_first/1%% Purpose: Finds the smallest key in the entire Tree.%% Returns: {ok, {Key, Val}} | 'undefined'.%%-----------------------------------------------------------------bplus_lookup_first(v) -> undefined;bplus_lookup_first(Tree) -> case ?NODE_TYPE(Tree) of l -> % Then it is the leftmost key here. {ok, ?GET_LEAF_KEY(Tree, 1)}; n -> % Look in the leftmost subtree. bplus_lookup_first(bplus_get_tree(Tree, 1)) end.%%-----------------------------------------------------------------%% Func: lookup_next/2%% Purpose: Finds the next key nearest after Key.%% Returns: {ok, {Key, Val}} | 'undefined'. NIX!!!%%-----------------------------------------------------------------bplus_lookup_next(v, _) -> undefined;bplus_lookup_next(Tree, Key) -> case ?NODE_TYPE(Tree) of l -> lookup_next_leaf(Key, Tree); n -> {Pos, SubTree} = bplus_select_sub_tree(Tree, Key), case bplus_lookup_next(SubTree, Key) of undefined -> S = bplus_get_size(Tree), if % There is a right brother. S > Pos -> bplus_lookup_first(bplus_get_tree(Tree, Pos+1)); % No there is no right brother. true -> undefined end; % We ok a next item. Result -> Result end end.%%-----------------------------------------------------------------%% Returns {ok, NextKey} if there is a key in the leaf which is greater.%% If there is no such key we return 'undefined' instead.%% Key does not have to be a key in the structure, just a search value.%%-----------------------------------------------------------------lookup_next_leaf(Key, Leaf) -> lookup_next_leaf_2(Key, Leaf, bplus_get_size(Leaf), 1).lookup_next_leaf_2(Key, Leaf, Size, Size) -> % This is the rightmost key. K = ?GET_LEAF_KEY(Leaf, Size), if K > Key -> {ok, ?GET_LEAF_KEY(Leaf, Size)}; true -> undefined end;lookup_next_leaf_2(Key, Leaf, Size, N) -> K = ?GET_LEAF_KEY(Leaf, N), if K < Key -> % K is still smaller, try next in the leaf. lookup_next_leaf_2(Key, Leaf, Size, N+1); Key == K -> % Since this is exact Key it must be the next. {ok, ?GET_LEAF_KEY(Leaf, N+1)}; true -> % Key was not an exact specification. % It must be K that is next greater. {ok, ?GET_LEAF_KEY(Leaf, N)} end.%%-----------------------------------------------------------------%% Func: insert/3%% Purpose: Inserts a new {Key, Value} into the tree.%% Returns: tree()%%-----------------------------------------------------------------bplus_insert(v, Key) -> bplus_mk_leaf([Key]);bplus_insert(Tree, Key) -> NewTree = bplus_insert_in(Tree, Key), case ?OVER_FULL(NewTree) of false -> NewTree; % If the node is over-full the tree will grow. true -> {LTree, DKey, RTree} = case ?NODE_TYPE(NewTree) of l -> bplus_split_leaf(NewTree); n -> bplus_split_node(NewTree) end, bplus_mk_node([LTree, DKey, RTree]) end.%%-----------------------------------------------------------------%% Func: delete/2%% Purpose: Deletes a key from the tree (if present).%% Returns: tree()%%-----------------------------------------------------------------bplus_delete(v, _Key) -> v;bplus_delete(Tree, Key) -> NewTree = bplus_delete_in(Tree, Key), S = bplus_get_size(NewTree), case ?NODE_TYPE(NewTree) of l -> if S =:= 0 -> v; true -> NewTree end; n -> if S =:= 1 -> bplus_get_tree(NewTree, 1); true -> NewTree end end.%%% -----------------------%%% Help function to insert.%%% -----------------------bplus_insert_in(Tree, Key) -> case ?NODE_TYPE(Tree) of l -> bplus_insert_in_leaf(Tree, Key); n -> {Pos, SubTree} = bplus_select_sub_tree(Tree, Key), % Pos = "the position of the subtree". NewSubTree = bplus_insert_in(SubTree, Key), case ?OVER_FULL(NewSubTree) of false -> bplus_put_subtree(Tree, [NewSubTree, Pos]); true -> case bplus_reorganize_tree_ins(Tree, NewSubTree, Pos) of {left, {LeftT, DKey, MiddleT}} -> bplus_put_subtree(bplus_put_lkey(Tree, DKey, Pos), [LeftT, Pos-1, MiddleT, Pos]); {right, {MiddleT, DKey, RightT}} -> bplus_put_subtree(bplus_put_rkey(Tree, DKey, Pos), [MiddleT, Pos, RightT, Pos+1]); {split, {LeftT, DKey, RightT}} -> bplus_extend_tree(Tree, {LeftT, DKey, RightT}, Pos) end end end.%%-----------------------------------------------------------------%% Inserts a key in correct position in a leaf.%%-----------------------------------------------------------------bplus_insert_in_leaf(Leaf, Key) -> bplus_insert_in_leaf_2(Leaf, Key, bplus_get_size(Leaf), []).bplus_insert_in_leaf_2(Leaf, Key, 0, Accum) -> bplus_insert_in_leaf_3(Leaf, 0, [Key|Accum]);bplus_insert_in_leaf_2(Leaf, Key, N, Accum) -> K = ?GET_LEAF_KEY(Leaf, N), if Key < K -> % Not here! bplus_insert_in_leaf_2(Leaf, Key, N-1, [K|Accum]); K < Key -> % Insert here. bplus_insert_in_leaf_3(Leaf, N-1, [K, Key|Accum]);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?