this repo has no description
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add split_at to RangeTree and RangeForest

+68 -1
+32
lib/range_forest.ex
··· 78 78 end 79 79 end 80 80 81 + @spec split_at(RangeTree.t, non_neg_integer, binary) :: {:updated, RangeTree.t} | :noop 82 + def split_at(tree, version, key) do 83 + next = key <> "\x00" 84 + case :gb_trees.smaller(next, tree) do 85 + {sk, {ek, ^version}} -> 86 + tree = :gb_trees.update(sk, {key, version}, tree) 87 + case ek do 88 + ^next -> {:updated, tree} 89 + ek -> {:updated, :gb_trees.insert(next, {ek, version}, tree)} 90 + end 91 + 92 + _ -> 93 + :noop 94 + end 95 + end 96 + 81 97 @spec intersect_key(RangeTree.t, non_neg_integer, binary) :: {binary, binary, non_neg_integer} | nil 82 98 def intersect_key(tree, min_version, key) do 83 99 case :gb_trees.smaller(key <> "\x00", tree) do ··· 142 158 end 143 159 end 144 160 161 + @spec split_at(RangeForest.t, non_neg_integer, binary) :: {:updated, RangeForest.t} | :noop 162 + def split_at(forest, version, key) do 163 + case :gb_trees.lookup(version, forest) do 164 + {:value, tree} -> 165 + case RangeTree.split_at(tree, version, key) do 166 + {:updated, tree} -> 167 + {:updated, :gb_trees.update(version, tree, forest)} 168 + :noop -> 169 + :noop 170 + end 171 + :none -> 172 + :noop 173 + end 174 + end 175 + 145 176 @spec tree_at(RangeForest.t, non_neg_integer) :: RangeTree.t 146 177 def tree_at(forest, version) do 147 178 case :gb_trees.smaller(version + 1, forest) do ··· 177 208 @spec dump(RangeForest.t) :: list 178 209 def dump(forest) do 179 210 :gb_trees.to_list(forest) 211 + |> Enum.map(fn {v, t} -> {v, RangeTree.dump(t)} end) 180 212 end 181 213 end
+36 -1
test/range_forest_test.exs
··· 50 50 assert RangeTree.dump(rt) == [ 51 51 {"foo_a", "foo_z", 4}, 52 52 ] 53 + 54 + assert :noop = RangeTree.split_at(rt, 3, "foo_c") 55 + assert :noop = RangeTree.split_at(rt, 5, "foo_c") 56 + 57 + assert {:updated, rt} = RangeTree.split_at(rt, 4, "foo_c") 58 + assert RangeTree.dump(rt) == [ 59 + {"foo_a", "foo_c", 4}, 60 + {"foo_c\x00", "foo_z", 4}, 61 + ] 62 + 63 + rt = RangeTree.insert_range(rt, 6, "foo_b", "foo_d\x00") 64 + 65 + assert RangeTree.dump(rt) == [ 66 + {"foo_a", "foo_b", 4}, 67 + {"foo_b", "foo_d\x00", 6}, 68 + {"foo_d\x00", "foo_z", 4}, 69 + ] 70 + 71 + assert {:updated, rt} = RangeTree.split_at(rt, 6, "foo_d") 72 + 73 + assert RangeTree.dump(rt) == [ 74 + {"foo_a", "foo_b", 4}, 75 + {"foo_b", "foo_d", 6}, 76 + {"foo_d\x00", "foo_z", 4}, 77 + ] 53 78 end 54 79 55 80 test "intersects keys", %{rt: rt} do ··· 123 148 {"foo_g", "foo_z", 1}, 124 149 ] 125 150 151 + assert {:updated, rf} = RangeForest.split_at(rf, 3, "foo_c") 152 + assert RangeForest.tree_at(rf, 3) |> RangeTree.dump() == [ 153 + {"foo_a", "foo_b", 1}, 154 + {"foo_b", "foo_c", 3}, 155 + {"foo_c\x00", "foo_f", 3}, 156 + {"foo_f", "foo_g", 1}, 157 + {"foo_g", "foo_z", 1}, 158 + ] 159 + 126 160 assert {ranges1, rf1} = RangeForest.flush(rf, 1, 0) 127 161 128 162 assert ranges1 == [ ··· 136 170 assert {ranges2, rf2} = RangeForest.flush(rf, 3, 2) 137 171 138 172 assert ranges2 == [ 139 - {"foo_b", "foo_f", 3}, 173 + {"foo_b", "foo_c", 3}, 174 + {"foo_c\x00", "foo_f", 3}, 140 175 ] 141 176 142 177 assert [] = RangeForest.dump(rf2)