Generated on 2009-08-09 21:22:55 with etap 0.3.4.
| Name | Total lines | Lines of code | Total coverage | Code coverage | ||||
| couch_key_tree | ?? | ?? | ?? |
|
....1 % Licensed under the Apache License, Version 2.0 (the "License"); you may not ....2 % use this file except in compliance with the License. You may obtain a copy of ....3 % the License at ....4 % ....5 % http://www.apache.org/licenses/LICENSE-2.0 ....6 % ....7 % Unless required by applicable law or agreed to in writing, software ....8 % distributed under the License is distributed on an "AS IS" BASIS, WITHOUT ....9 % WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the ...10 % License for the specific language governing permissions and limitations under ...11 % the License. ...12 ...13 -module(couch_key_tree). ...14 ...15 -export([merge/2, find_missing/2, get_key_leafs/2, get_full_key_paths/2, get/2]). ...16 -export([map/2, get_all_leafs/1, count_leafs/1, remove_leafs/2, ...17 get_all_leafs_full/1,stem/2,map_leafs/2]). ...18 ...19 % a key tree looks like this: ...20 % Tree -> [] or [{Key, Value, ChildTree} | SiblingTree] ...21 % ChildTree -> Tree ...22 % SiblingTree -> [] or [{SiblingKey, Value, Tree} | Tree] ...23 % And each Key < SiblingKey ...24 ...25 ...26 % partial trees arranged by how much they are cut off. ...27 ...28 merge(A, B) -> ...29 {Merged, HasConflicts} = ...30 lists:foldl( ...31 fun(InsertTree, {AccTrees, AccConflicts}) -> ...32 {ok, Merged, Conflicts} = merge_one(AccTrees, InsertTree, [], false), ...33 {Merged, Conflicts or AccConflicts} ...34 end, ...35 {A, false}, B), ...36 if HasConflicts or ...37 ((length(Merged) /= length(A)) and (length(Merged) /= length(B))) -> ...38 Conflicts = conflicts; ...39 true -> ...40 Conflicts = no_conflicts ...41 end, ...42 {lists:sort(Merged), Conflicts}. ...43 ...44 merge_one([], Insert, OutAcc, ConflictsAcc) -> ...45 {ok, [Insert | OutAcc], ConflictsAcc}; ...46 merge_one([{Start, Tree}|Rest], {StartInsert, TreeInsert}, OutAcc, ConflictsAcc) -> ...47 if Start =< StartInsert -> ...48 StartA = Start, ...49 StartB = StartInsert, ...50 TreeA = Tree, ...51 TreeB = TreeInsert; ...52 true -> ...53 StartB = Start, ...54 StartA = StartInsert, ...55 TreeB = Tree, ...56 TreeA = TreeInsert ...57 end, ...58 case merge_at([TreeA], StartB - StartA, TreeB) of ...59 {ok, [CombinedTrees], Conflicts} -> ...60 merge_one(Rest, {StartA, CombinedTrees}, OutAcc, Conflicts or ConflictsAcc); ...61 no -> ...62 merge_one(Rest, {StartB, TreeB}, [{StartA, TreeA} | OutAcc], ConflictsAcc) ...63 end. ...64 ...65 merge_at([], _Place, _Insert) -> ...66 no; ...67 merge_at([{Key, Value, SubTree}|Sibs], 0, {InsertKey, InsertValue, InsertSubTree}) -> ...68 if Key == InsertKey -> ...69 {Merge, Conflicts} = merge_simple(SubTree, InsertSubTree), ...70 {ok, [{Key, Value, Merge} | Sibs], Conflicts}; ...71 true -> ...72 case merge_at(Sibs, 0, {InsertKey, InsertValue, InsertSubTree}) of ...73 {ok, Merged, Conflicts} -> ...74 {ok, [{Key, Value, SubTree} | Merged], Conflicts}; ...75 no -> ...76 no ...77 end ...78 end; ...79 merge_at([{Key, Value, SubTree}|Sibs], Place, Insert) -> ...80 case merge_at(SubTree, Place - 1,Insert) of ...81 {ok, Merged, Conflicts} -> ...82 {ok, [{Key, Value, Merged} | Sibs], Conflicts}; ...83 no -> ...84 case merge_at(Sibs, Place, Insert) of ...85 {ok, Merged, Conflicts} -> ...86 {ok, [{Key, Value, SubTree} | Merged], Conflicts}; ...87 no -> ...88 no ...89 end ...90 end. ...91 ...92 % key tree functions ...93 merge_simple([], B) -> ...94 {B, false}; ...95 merge_simple(A, []) -> ...96 {A, false}; ...97 merge_simple([ATree | ANextTree], [BTree | BNextTree]) -> ...98 {AKey, AValue, ASubTree} = ATree, ...99 {BKey, _BValue, BSubTree} = BTree, ..100 if ..101 AKey == BKey -> ..102 %same key ..103 {MergedSubTree, Conflict1} = merge_simple(ASubTree, BSubTree), ..104 {MergedNextTree, Conflict2} = merge_simple(ANextTree, BNextTree), ..105 {[{AKey, AValue, MergedSubTree} | MergedNextTree], Conflict1 or Conflict2}; ..106 AKey < BKey -> ..107 {MTree, _} = merge_simple(ANextTree, [BTree | BNextTree]), ..108 {[ATree | MTree], true}; ..109 true -> ..110 {MTree, _} = merge_simple([ATree | ANextTree], BNextTree), ..111 {[BTree | MTree], true} ..112 end. ..113 ..114 find_missing(_Tree, []) -> ..115 []; ..116 find_missing([], SeachKeys) -> ..117 SeachKeys; ..118 find_missing([{Start, {Key, Value, SubTree}} | RestTree], SeachKeys) -> ..119 PossibleKeys = [{KeyPos, KeyValue} || {KeyPos, KeyValue} <- SeachKeys, KeyPos >= Start], ..120 ImpossibleKeys = [{KeyPos, KeyValue} || {KeyPos, KeyValue} <- SeachKeys, KeyPos < Start], ..121 Missing = find_missing_simple(Start, [{Key, Value, SubTree}], PossibleKeys), ..122 find_missing(RestTree, ImpossibleKeys ++ Missing). ..123 ..124 find_missing_simple(_Pos, _Tree, []) -> ..125 []; ..126 find_missing_simple(_Pos, [], SeachKeys) -> ..127 SeachKeys; ..128 find_missing_simple(Pos, [{Key, _, SubTree} | RestTree], SeachKeys) -> ..129 PossibleKeys = [{KeyPos, KeyValue} || {KeyPos, KeyValue} <- SeachKeys, KeyPos >= Pos], ..130 ImpossibleKeys = [{KeyPos, KeyValue} || {KeyPos, KeyValue} <- SeachKeys, KeyPos < Pos], ..131 ..132 SrcKeys2 = PossibleKeys -- [{Pos, Key}], ..133 SrcKeys3 = find_missing_simple(Pos + 1, SubTree, SrcKeys2), ..134 ImpossibleKeys ++ find_missing_simple(Pos, RestTree, SrcKeys3). ..135 ..136 ..137 filter_leafs([], _Keys, FilteredAcc, RemovedKeysAcc) -> ..138 {FilteredAcc, RemovedKeysAcc}; ..139 filter_leafs([{Pos, [{LeafKey, _}|_]} = Path |Rest], Keys, FilteredAcc, RemovedKeysAcc) -> ..140 FilteredKeys = lists:delete({Pos, LeafKey}, Keys), ..141 if FilteredKeys == Keys -> ..142 % this leaf is not a key we are looking to remove ..143 filter_leafs(Rest, Keys, [Path | FilteredAcc], RemovedKeysAcc); ..144 true -> ..145 % this did match a key, remove both the node and the input key ..146 filter_leafs(Rest, FilteredKeys, FilteredAcc, [{Pos, LeafKey} | RemovedKeysAcc]) ..147 end. ..148 ..149 % Removes any branches from the tree whose leaf node(s) are in the Keys ..150 remove_leafs(Trees, Keys) -> ..151 % flatten each branch in a tree into a tree path ..152 Paths = get_all_leafs_full(Trees), ..153 ..154 % filter out any that are in the keys list. ..155 {FilteredPaths, RemovedKeys} = filter_leafs(Paths, Keys, [], []), ..156 ..157 % convert paths back to trees ..158 NewTree = lists:foldl( ..159 fun({PathPos, Path},TreeAcc) -> ..160 [SingleTree] = lists:foldl( ..161 fun({K,V},NewTreeAcc) -> [{K,V,NewTreeAcc}] end, [], Path), ..162 {NewTrees, _} = merge(TreeAcc, [{PathPos + 1 - length(Path), SingleTree}]), ..163 NewTrees ..164 end, [], FilteredPaths), ..165 {NewTree, RemovedKeys}. ..166 ..167 ..168 % get the leafs in the tree matching the keys. The matching key nodes can be ..169 % leafs or an inner nodes. If an inner node, then the leafs for that node ..170 % are returned. ..171 get_key_leafs(Tree, Keys) -> ..172 get_key_leafs(Tree, Keys, []). ..173 ..174 get_key_leafs(_, [], Acc) -> ..175 {Acc, []}; ..176 get_key_leafs([], Keys, Acc) -> ..177 {Acc, Keys}; ..178 get_key_leafs([{Pos, Tree}|Rest], Keys, Acc) -> ..179 {Gotten, RemainingKeys} = get_key_leafs_simple(Pos, [Tree], Keys, []), ..180 get_key_leafs(Rest, RemainingKeys, Gotten ++ Acc). ..181 ..182 get_key_leafs_simple(_Pos, _Tree, [], _KeyPathAcc) -> ..183 {[], []}; ..184 get_key_leafs_simple(_Pos, [], KeysToGet, _KeyPathAcc) -> ..185 {[], KeysToGet}; ..186 get_key_leafs_simple(Pos, [{Key, _Value, SubTree}=Tree | RestTree], KeysToGet, KeyPathAcc) -> ..187 case lists:delete({Pos, Key}, KeysToGet) of ..188 KeysToGet -> % same list, key not found ..189 {LeafsFound, KeysToGet2} = get_key_leafs_simple(Pos + 1, SubTree, KeysToGet, [Key | KeyPathAcc]), ..190 {RestLeafsFound, KeysRemaining} = get_key_leafs_simple(Pos, RestTree, KeysToGet2, KeyPathAcc), ..191 {LeafsFound ++ RestLeafsFound, KeysRemaining}; ..192 KeysToGet2 -> ..193 LeafsFound = get_all_leafs_simple(Pos, [Tree], KeyPathAcc), ..194 LeafKeysFound = [LeafKeyFound || {LeafKeyFound, _} <- LeafsFound], ..195 KeysToGet2 = KeysToGet2 -- LeafKeysFound, ..196 {RestLeafsFound, KeysRemaining} = get_key_leafs_simple(Pos, RestTree, KeysToGet2, KeyPathAcc), ..197 {LeafsFound ++ RestLeafsFound, KeysRemaining} ..198 end. ..199 ..200 get(Tree, KeysToGet) -> ..201 {KeyPaths, KeysNotFound} = get_full_key_paths(Tree, KeysToGet), ..202 FixedResults = [ {Value, {Pos, [Key0 || {Key0, _} <- Path]}} || {Pos, [{_Key, Value}|_]=Path} <- KeyPaths], ..203 {FixedResults, KeysNotFound}. ..204 ..205 get_full_key_paths(Tree, Keys) -> ..206 get_full_key_paths(Tree, Keys, []). ..207 ..208 get_full_key_paths(_, [], Acc) -> ..209 {Acc, []}; ..210 get_full_key_paths([], Keys, Acc) -> ..211 {Acc, Keys}; ..212 get_full_key_paths([{Pos, Tree}|Rest], Keys, Acc) -> ..213 {Gotten, RemainingKeys} = get_full_key_paths(Pos, [Tree], Keys, []), ..214 get_full_key_paths(Rest, RemainingKeys, Gotten ++ Acc). ..215 ..216 ..217 get_full_key_paths(_Pos, _Tree, [], _KeyPathAcc) -> ..218 {[], []}; ..219 get_full_key_paths(_Pos, [], KeysToGet, _KeyPathAcc) -> ..220 {[], KeysToGet}; ..221 get_full_key_paths(Pos, [{KeyId, Value, SubTree} | RestTree], KeysToGet, KeyPathAcc) -> ..222 KeysToGet2 = KeysToGet -- [{Pos, KeyId}], ..223 CurrentNodeResult = ..224 case length(KeysToGet2) == length(KeysToGet) of ..225 true -> % not in the key list. ..226 []; ..227 false -> % this node is the key list. return it ..228 [{Pos, [{KeyId, Value} | KeyPathAcc]}] ..229 end, ..230 {KeysGotten, KeysRemaining} = get_full_key_paths(Pos + 1, SubTree, KeysToGet2, [{KeyId, Value} | KeyPathAcc]), ..231 {KeysGotten2, KeysRemaining2} = get_full_key_paths(Pos, RestTree, KeysRemaining, KeyPathAcc), ..232 {CurrentNodeResult ++ KeysGotten ++ KeysGotten2, KeysRemaining2}. ..233 ..234 get_all_leafs_full(Tree) -> ..235 get_all_leafs_full(Tree, []). ..236 ..237 get_all_leafs_full([], Acc) -> ..238 Acc; ..239 get_all_leafs_full([{Pos, Tree} | Rest], Acc) -> ..240 get_all_leafs_full(Rest, get_all_leafs_full_simple(Pos, [Tree], []) ++ Acc). ..241 ..242 get_all_leafs_full_simple(_Pos, [], _KeyPathAcc) -> ..243 []; ..244 get_all_leafs_full_simple(Pos, [{KeyId, Value, []} | RestTree], KeyPathAcc) -> ..245 [{Pos, [{KeyId, Value} | KeyPathAcc]} | get_all_leafs_full_simple(Pos, RestTree, KeyPathAcc)]; ..246 get_all_leafs_full_simple(Pos, [{KeyId, Value, SubTree} | RestTree], KeyPathAcc) -> ..247 get_all_leafs_full_simple(Pos + 1, SubTree, [{KeyId, Value} | KeyPathAcc]) ++ get_all_leafs_full_simple(Pos, RestTree, KeyPathAcc). ..248 ..249 get_all_leafs(Trees) -> ..250 get_all_leafs(Trees, []). ..251 ..252 get_all_leafs([], Acc) -> ..253 Acc; ..254 get_all_leafs([{Pos, Tree}|Rest], Acc) -> ..255 get_all_leafs(Rest, get_all_leafs_simple(Pos, [Tree], []) ++ Acc). ..256 ..257 get_all_leafs_simple(_Pos, [], _KeyPathAcc) -> ..258 []; ..259 get_all_leafs_simple(Pos, [{KeyId, Value, []} | RestTree], KeyPathAcc) -> ..260 [{Value, {Pos, [KeyId | KeyPathAcc]}} | get_all_leafs_simple(Pos, RestTree, KeyPathAcc)]; ..261 get_all_leafs_simple(Pos, [{KeyId, _Value, SubTree} | RestTree], KeyPathAcc) -> ..262 get_all_leafs_simple(Pos + 1, SubTree, [KeyId | KeyPathAcc]) ++ get_all_leafs_simple(Pos, RestTree, KeyPathAcc). ..263 ..264 ..265 count_leafs([]) -> ..266 0; ..267 count_leafs([{_Pos,Tree}|Rest]) -> ..268 count_leafs_simple([Tree]) + count_leafs(Rest). ..269 ..270 count_leafs_simple([]) -> ..271 0; ..272 count_leafs_simple([{_Key, _Value, []} | RestTree]) -> ..273 1 + count_leafs_simple(RestTree); ..274 count_leafs_simple([{_Key, _Value, SubTree} | RestTree]) -> ..275 count_leafs_simple(SubTree) + count_leafs_simple(RestTree). ..276 ..277 ..278 map(_Fun, []) -> ..279 []; ..280 map(Fun, [{Pos, Tree}|Rest]) -> ..281 case erlang:fun_info(Fun, arity) of ..282 {arity, 2} -> ..283 [NewTree] = map_simple(fun(A,B,_C) -> Fun(A,B) end, Pos, [Tree]), ..284 [{Pos, NewTree} | map(Fun, Rest)]; ..285 {arity, 3} -> ..286 [NewTree] = map_simple(Fun, Pos, [Tree]), ..287 [{Pos, NewTree} | map(Fun, Rest)] ..288 end. ..289 ..290 map_simple(_Fun, _Pos, []) -> ..291 []; ..292 map_simple(Fun, Pos, [{Key, Value, SubTree} | RestTree]) -> ..293 Value2 = Fun({Pos, Key}, Value, ..294 if SubTree == [] -> leaf; true -> branch end), ..295 [{Key, Value2, map_simple(Fun, Pos + 1, SubTree)} | map_simple(Fun, Pos, RestTree)]. ..296 ..297 ..298 map_leafs(_Fun, []) -> ..299 []; ..300 map_leafs(Fun, [{Pos, Tree}|Rest]) -> ..301 [NewTree] = map_leafs_simple(Fun, Pos, [Tree]), ..302 [{Pos, NewTree} | map_leafs(Fun, Rest)]. ..303 ..304 map_leafs_simple(_Fun, _Pos, []) -> ..305 []; ..306 map_leafs_simple(Fun, Pos, [{Key, Value, []} | RestTree]) -> ..307 Value2 = Fun({Pos, Key}, Value), ..308 [{Key, Value2, []} | map_leafs_simple(Fun, Pos, RestTree)]; ..309 map_leafs_simple(Fun, Pos, [{Key, Value, SubTree} | RestTree]) -> ..310 [{Key, Value, map_leafs_simple(Fun, Pos + 1, SubTree)} | map_leafs_simple(Fun, Pos, RestTree)]. ..311 ..312 ..313 stem(Trees, Limit) -> ..314 % flatten each branch in a tree into a tree path ..315 Paths = get_all_leafs_full(Trees), ..316 ..317 Paths2 = [{Pos, lists:sublist(Path, Limit)} || {Pos, Path} <- Paths], ..318 ..319 % convert paths back to trees ..320 lists:foldl( ..321 fun({PathPos, Path},TreeAcc) -> ..322 [SingleTree] = lists:foldl( ..323 fun({K,V},NewTreeAcc) -> [{K,V,NewTreeAcc}] end, [], Path), ..324 {NewTrees, _} = merge(TreeAcc, [{PathPos + 1 - length(Path), SingleTree}]), ..325 NewTrees ..326 end, [], Paths2). ..327 ..328 % Tests moved to test/etap/06?-*.t ..329
Generated using etap 0.3.4.