Skip to content

Commit

Permalink
Function iterator_from/2.
Browse files Browse the repository at this point in the history
  • Loading branch information
walter-weinmann committed Nov 8, 2016
1 parent cab8e62 commit 1a0e0aa
Show file tree
Hide file tree
Showing 3 changed files with 426 additions and 1 deletion.
29 changes: 28 additions & 1 deletion src/b_trees.erl
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@
%% 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, B): Returns an iterator that can be used for traversing the
%% entries of B-Tree B; see next/1. The difference as compared to the iterator
%% returned by iterator/1 is that the first key greater than or equal to Key K
%% is returned.
%%
%% - keys(B): returns an ordered list of all keys in B-tree B.
%%
%% - largest(B): returns tuple {K, V}, where K is the largest key in B-tree B,
Expand Down Expand Up @@ -128,6 +133,7 @@
is_defined/2,
is_empty/1,
iterator/1,
iterator_from/2,
keys/1,
largest/1,
lookup/2,
Expand Down Expand Up @@ -821,6 +827,27 @@ iterator_1({KeyValues, Subtrees}, Iterator) ->

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

-spec iterator_from(key(), b_tree()) -> iterator().

iterator_from(_Key, {_, _, 0, nil}) ->
[];
iterator_from(Key, {_, _, _, Tree}) ->
iterator_from_1(Key, Tree, []).

-spec iterator_from_1(key(), tree(), iterator()) -> iterator().

% The most left key / value.
iterator_from_1(Key, {KeyNo, 0, KeyValues, []} = _Next, Iterator) ->
{_, Pos} = binary_search(Key, KeyValues, KeyNo, 1, KeyNo),
[{lists:sublist(KeyValues, Pos, KeyNo), []} | Iterator];
% The most left subtree.
iterator_from_1(Key, {KeyNo, SubtreeNo, KeyValues, Subtrees} = _Next, Iterator) ->
{_, Pos} = binary_search(Key, KeyValues, KeyNo, 1, KeyNo),
{KeyNo_1, SubtreeNo_1, KeyValues_1, Subtrees_1} = _NextIterator = lists:nth(Pos, Subtrees),
iterator_from_1(Key, {KeyNo_1, SubtreeNo_1, KeyValues_1, Subtrees_1}, [{lists:sublist(KeyValues, Pos, KeyNo), lists:sublist(Subtrees, Pos, SubtreeNo)} | Iterator]).

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

-spec keys(b_tree()) -> keys().

keys({_, _, 0, nil}) ->
Expand Down Expand Up @@ -910,7 +937,7 @@ next([{[], _}, {[], _} = Iterator | TailIterator]) ->
% End of leaf node.
next([{[], _}, {[{Key, Value} | TailKeyValues], [_ | TailSubtrees]} | TailIterator]) ->
{Key, Value, iterator_1({TailKeyValues, TailSubtrees}, TailIterator)};
% Processing a leaf node..
% Processing a leaf node.
next([{[{Key, Value} | KeyValues], []} | Iterator]) ->
{Key, Value, [{KeyValues, []} | Iterator]};
% End of iterator.
Expand Down
204 changes: 204 additions & 0 deletions test/b_trees_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,16 @@ all() ->
insert_error_test,
is_defined_test,
is_empty_test,
iterator_from_next_00_test,
iterator_from_next_01_test,
iterator_from_next_02_test,
iterator_from_next_03_test,
iterator_from_next_04_test,
iterator_from_next_04_16_test,
iterator_from_next_06_test,
iterator_from_next_08_256_test,
iterator_from_next_16_test,
iterator_from_next_17_test,
iterator_next_test,
keys_test,
largest_test,
Expand Down Expand Up @@ -678,6 +688,190 @@ is_empty_test(_Config) ->

ok.

%%--------------------------------------------------------------------
%% TEST CASES: iterator_from & next
%%--------------------------------------------------------------------

iterator_from_next_00_test(_Config) ->
BTree_04_00 = b_trees:empty(4),
_Iterator_04_00_00 = b_trees:iterator_from("k_01", BTree_04_00),
?assertEqual(none, b_trees:next(_Iterator_04_00_00)),

BTree_04_01 = test_generator:generate_b_tree_from_number(4, 1, 2),
Iterator_04_01_00 = b_trees:iterator_from("k_00", BTree_04_01),
{_Key_04_01_01, _Value_04_01_01, _Iterator_04_01_01} = b_trees:next(Iterator_04_01_00),
?assertEqual({"k_01", "v_01"}, {_Key_04_01_01, _Value_04_01_01}),
?assertEqual(none, b_trees:next(_Iterator_04_01_01)),

BTree_04_16 = test_generator:generate_b_tree_from_number(4, 16, 2),
Iterator_04_16_01 = b_trees:iterator_from("k_00", BTree_04_16),
{_Key_04_16_01, _Value_04_16_01, Iterator_04_16_02} = b_trees:next(Iterator_04_16_01),
?assertEqual({"k_01", "v_01"}, {_Key_04_16_01, _Value_04_16_01}),
{_Key_04_16_02, _Value_04_16_02, _Iterator_04_16_03} = b_trees:next(Iterator_04_16_02),
?assertEqual({"k_02", "v_02"}, {_Key_04_16_02, _Value_04_16_02}),

ok.

%%--------------------------------------------------------------------
%% TEST CASES: iterator_from & next
%%--------------------------------------------------------------------

iterator_from_next_01_test(_Config) ->
BTree_04_16 = test_generator:generate_b_tree_from_number(4, 16, 2),
Iterator_04_16_01 = b_trees:iterator_from("k_01", BTree_04_16),
{_Key_04_16_01, _Value_04_16_01, Iterator_04_16_02} = b_trees:next(Iterator_04_16_01),
?assertEqual({"k_01", "v_01"}, {_Key_04_16_01, _Value_04_16_01}),
{_Key_04_16_02, _Value_04_16_02, _Iterator_04_16_03} = b_trees:next(Iterator_04_16_02),
?assertEqual({"k_02", "v_02"}, {_Key_04_16_02, _Value_04_16_02}),

ok.

%%--------------------------------------------------------------------
%% TEST CASES: iterator_from & next
%%--------------------------------------------------------------------

iterator_from_next_02_test(_Config) ->
BTree_04_16 = test_generator:generate_b_tree_from_number(4, 16, 2),
Iterator_04_16_02 = b_trees:iterator_from("k_02", BTree_04_16),
{_Key_04_16_02, _Value_04_16_02, Iterator_04_16_03} = b_trees:next(Iterator_04_16_02),
?assertEqual({"k_02", "v_02"}, {_Key_04_16_02, _Value_04_16_02}),
{_Key_04_16_03, _Value_04_16_03, _Iterator_04_16_04} = b_trees:next(Iterator_04_16_03),
?assertEqual({"k_03", "v_03"}, {_Key_04_16_03, _Value_04_16_03}),

ok.

%%--------------------------------------------------------------------
%% TEST CASES: iterator_from & next
%%--------------------------------------------------------------------

iterator_from_next_03_test(_Config) ->
BTree_04_16 = test_generator:generate_b_tree_from_number(4, 16, 2),
Iterator_04_16_03 = b_trees:iterator_from("k_03", BTree_04_16),
{_Key_04_16_03, _Value_04_16_03, Iterator_04_16_04} = b_trees:next(Iterator_04_16_03),
?assertEqual({"k_03", "v_03"}, {_Key_04_16_03, _Value_04_16_03}),
{_Key_04_16_04, _Value_04_16_04, _Iterator_04_16_05} = b_trees:next(Iterator_04_16_04),
?assertEqual({"k_04", "v_04"}, {_Key_04_16_04, _Value_04_16_04}),

ok.

%%--------------------------------------------------------------------
%% TEST CASES: iterator_from & next
%%--------------------------------------------------------------------

iterator_from_next_04_test(_Config) ->
BTree_04_16 = test_generator:generate_b_tree_from_number(4, 16, 2),
Iterator_04_16_04 = b_trees:iterator_from("k_04", BTree_04_16),
{_Key_04_16_04, _Value_04_16_04, Iterator_04_16_05} = b_trees:next(Iterator_04_16_04),
?assertEqual({"k_04", "v_04"}, {_Key_04_16_04, _Value_04_16_04}),
{_Key_04_16_05, _Value_04_16_05, _Iterator_04_16_06} = b_trees:next(Iterator_04_16_05),
?assertEqual({"k_05", "v_05"}, {_Key_04_16_05, _Value_04_16_05}),

ok.

%%--------------------------------------------------------------------
%% TEST CASES: iterator_from & next
%%--------------------------------------------------------------------

iterator_from_next_04_16_test(_Config) ->
Number = 16,

BTree = test_generator:generate_b_tree_from_number(4, Number, 2),
KeyValues = test_generator:generate_key_values_from(Number, 2),

?assertEqual(lists:sublist(KeyValues, 1, Number), iterate_next_b_tree(b_trees:iterator_from("k_00", BTree), Number - 0, [])),
?assertEqual(lists:sublist(KeyValues, 2, Number), iterate_next_b_tree(b_trees:iterator_from("k_02", BTree), Number - 1, [])),
?assertEqual(lists:sublist(KeyValues, 3, Number), iterate_next_b_tree(b_trees:iterator_from("k_03", BTree), Number - 2, [])),
?assertEqual(lists:sublist(KeyValues, 4, Number), iterate_next_b_tree(b_trees:iterator_from("k_04", BTree), Number - 3, [])),
?assertEqual(lists:sublist(KeyValues, 5, Number), iterate_next_b_tree(b_trees:iterator_from("k_05", BTree), Number - 4, [])),
?assertEqual(lists:sublist(KeyValues, 6, Number), iterate_next_b_tree(b_trees:iterator_from("k_06", BTree), Number - 5, [])),
?assertEqual(lists:sublist(KeyValues, 7, Number), iterate_next_b_tree(b_trees:iterator_from("k_07", BTree), Number - 6, [])),
?assertEqual(lists:sublist(KeyValues, 8, Number), iterate_next_b_tree(b_trees:iterator_from("k_08", BTree), Number - 7, [])),
?assertEqual(lists:sublist(KeyValues, 9, Number), iterate_next_b_tree(b_trees:iterator_from("k_09", BTree), Number - 8, [])),
?assertEqual(lists:sublist(KeyValues, 10, Number), iterate_next_b_tree(b_trees:iterator_from("k_10", BTree), Number - 9, [])),
?assertEqual(lists:sublist(KeyValues, 11, Number), iterate_next_b_tree(b_trees:iterator_from("k_11", BTree), Number - 10, [])),
?assertEqual(lists:sublist(KeyValues, 12, Number), iterate_next_b_tree(b_trees:iterator_from("k_12", BTree), Number - 11, [])),
?assertEqual(lists:sublist(KeyValues, 13, Number), iterate_next_b_tree(b_trees:iterator_from("k_13", BTree), Number - 12, [])),
?assertEqual(lists:sublist(KeyValues, 14, Number), iterate_next_b_tree(b_trees:iterator_from("k_14", BTree), Number - 13, [])),
?assertEqual(lists:sublist(KeyValues, 15, Number), iterate_next_b_tree(b_trees:iterator_from("k_15", BTree), Number - 14, [])),
?assertEqual(lists:sublist(KeyValues, 16, Number), iterate_next_b_tree(b_trees:iterator_from("k_16", BTree), Number - 15, [])),

ok.

%%--------------------------------------------------------------------
%% TEST CASES: iterator_from & next
%%--------------------------------------------------------------------

iterator_from_next_06_test(_Config) ->
BTree_04_16 = test_generator:generate_b_tree_from_number(4, 16, 2),
Iterator_04_16_06 = b_trees:iterator_from("k_06", BTree_04_16),
{_Key_04_16_06, _Value_04_16_06, Iterator_04_16_07} = b_trees:next(Iterator_04_16_06),
?assertEqual({"k_06", "v_06"}, {_Key_04_16_06, _Value_04_16_06}),
{_Key_04_16_07, _Value_04_16_07, _Iterator_04_16_08} = b_trees:next(Iterator_04_16_07),
?assertEqual({"k_07", "v_07"}, {_Key_04_16_07, _Value_04_16_07}),

ok.

%%--------------------------------------------------------------------
%% TEST CASES: iterator_from & next
%%--------------------------------------------------------------------

iterator_from_next_08_256_test(_Config) ->
Number = 256,

BTree = test_generator:generate_b_tree_from_number(4, Number, 3),
KeyValues = test_generator:generate_key_values_from(Number, 3),

?assertEqual(lists:sublist(KeyValues, 1, Number), iterate_next_b_tree(b_trees:iterator_from("k_000", BTree), Number - 0, [])),
?assertEqual(lists:sublist(KeyValues, 2, Number), iterate_next_b_tree(b_trees:iterator_from("k_002", BTree), Number - 1, [])),
?assertEqual(lists:sublist(KeyValues, 3, Number), iterate_next_b_tree(b_trees:iterator_from("k_003", BTree), Number - 2, [])),
?assertEqual(lists:sublist(KeyValues, 4, Number), iterate_next_b_tree(b_trees:iterator_from("k_004", BTree), Number - 3, [])),
?assertEqual(lists:sublist(KeyValues, 5, Number), iterate_next_b_tree(b_trees:iterator_from("k_005", BTree), Number - 4, [])),
?assertEqual(lists:sublist(KeyValues, 7, Number), iterate_next_b_tree(b_trees:iterator_from("k_007", BTree), Number - 6, [])),
?assertEqual(lists:sublist(KeyValues, 8, Number), iterate_next_b_tree(b_trees:iterator_from("k_008", BTree), Number - 7, [])),
?assertEqual(lists:sublist(KeyValues, 11, Number), iterate_next_b_tree(b_trees:iterator_from("k_011", BTree), Number - 10, [])),
?assertEqual(lists:sublist(KeyValues, 13, Number), iterate_next_b_tree(b_trees:iterator_from("k_013", BTree), Number - 12, [])),
?assertEqual(lists:sublist(KeyValues, 16, Number), iterate_next_b_tree(b_trees:iterator_from("k_016", BTree), Number - 15, [])),
?assertEqual(lists:sublist(KeyValues, 17, Number), iterate_next_b_tree(b_trees:iterator_from("k_017", BTree), Number - 16, [])),
?assertEqual(lists:sublist(KeyValues, 19, Number), iterate_next_b_tree(b_trees:iterator_from("k_019", BTree), Number - 18, [])),
?assertEqual(lists:sublist(KeyValues, 23, Number), iterate_next_b_tree(b_trees:iterator_from("k_023", BTree), Number - 22, [])),
?assertEqual(lists:sublist(KeyValues, 29, Number), iterate_next_b_tree(b_trees:iterator_from("k_029", BTree), Number - 28, [])),
?assertEqual(lists:sublist(KeyValues, 31, Number), iterate_next_b_tree(b_trees:iterator_from("k_031", BTree), Number - 30, [])),
?assertEqual(lists:sublist(KeyValues, 32, Number), iterate_next_b_tree(b_trees:iterator_from("k_032", BTree), Number - 31, [])),
?assertEqual(lists:sublist(KeyValues, 37, Number), iterate_next_b_tree(b_trees:iterator_from("k_037", BTree), Number - 36, [])),
?assertEqual(lists:sublist(KeyValues, 41, Number), iterate_next_b_tree(b_trees:iterator_from("k_041", BTree), Number - 40, [])),
?assertEqual(lists:sublist(KeyValues, 43, Number), iterate_next_b_tree(b_trees:iterator_from("k_043", BTree), Number - 42, [])),
?assertEqual(lists:sublist(KeyValues, 47, Number), iterate_next_b_tree(b_trees:iterator_from("k_047", BTree), Number - 46, [])),
?assertEqual(lists:sublist(KeyValues, 49, Number), iterate_next_b_tree(b_trees:iterator_from("k_049", BTree), Number - 48, [])),
?assertEqual(lists:sublist(KeyValues, 64, Number), iterate_next_b_tree(b_trees:iterator_from("k_064", BTree), Number - 63, [])),
?assertEqual(lists:sublist(KeyValues, 128, Number), iterate_next_b_tree(b_trees:iterator_from("k_128", BTree), Number - 127, [])),
?assertEqual(lists:sublist(KeyValues, 256, Number), iterate_next_b_tree(b_trees:iterator_from("k_256", BTree), Number - 255, [])),

ok.

%%--------------------------------------------------------------------
%% TEST CASES: iterator_from & next
%%--------------------------------------------------------------------

iterator_from_next_16_test(_Config) ->
BTree_04_16 = test_generator:generate_b_tree_from_number(4, 16, 2),
Iterator_04_16_16 = b_trees:iterator_from("k_16", BTree_04_16),
{_Key_04_16_16, _Value_04_16_16, Iterator_04_16_17} = b_trees:next(Iterator_04_16_16),
?assertEqual({"k_16", "v_16"}, {_Key_04_16_16, _Value_04_16_16}),
none = b_trees:next(Iterator_04_16_17),

ok.

%%--------------------------------------------------------------------
%% TEST CASES: iterator_from & next
%%--------------------------------------------------------------------

iterator_from_next_17_test(_Config) ->
BTree_04_16 = test_generator:generate_b_tree_from_number(4, 16, 2),
Iterator_04_16_17 = b_trees:iterator_from("k_17", BTree_04_16),
none = b_trees:next(Iterator_04_16_17),

ok.

%%--------------------------------------------------------------------
%% TEST CASES: iterator & next
%%--------------------------------------------------------------------
Expand Down Expand Up @@ -1107,3 +1301,13 @@ values_test(_Config) ->
?assertEqual(16, length(b_trees:values(?B_TREE_06_16))),

ok.

%%--------------------------------------------------------------------
%% Helper functions.
%%--------------------------------------------------------------------

iterate_next_b_tree(_, 0, KeyValues) ->
KeyValues;
iterate_next_b_tree(Iterator, Count, KeyValues) ->
{Key, Value, IteratorNew} = b_trees:next(Iterator),
iterate_next_b_tree(IteratorNew, Count - 1, KeyValues ++ [{Key, Value}]).
Loading

0 comments on commit 1a0e0aa

Please sign in to comment.