/apps/arweave/src/ar_intervals.erl

https://github.com/ArweaveTeam/arweave · Erlang · 194 lines · 165 code · 26 blank · 3 comment · 1 complexity · 9fe3f54b210de25faa552b45a6ae71e3 MD5 · raw file

  1. -module(ar_intervals).
  2. -export([
  3. new/0,
  4. add/3,
  5. cut/2,
  6. is_inside/2,
  7. sum/1,
  8. outerjoin/2,
  9. get_interval_by_nth_inner_number/2,
  10. to_etf/2,
  11. to_json/2,
  12. safe_from_etf/1
  13. ]).
  14. new() ->
  15. gb_sets:new().
  16. add(Intervals, End, Start) ->
  17. compact(gb_sets:add_element({End, Start}, Intervals)).
  18. cut(Intervals, Cut) ->
  19. case gb_sets:size(Intervals) of
  20. 0 ->
  21. Intervals;
  22. _ ->
  23. case gb_sets:take_largest(Intervals) of
  24. {{_, Start}, UpdatedIntervals} when Start >= Cut ->
  25. cut(UpdatedIntervals, Cut);
  26. {{End, Start}, UpdatedIntervals} when End > Cut ->
  27. gb_sets:add_element({Cut, Start}, UpdatedIntervals);
  28. _ ->
  29. Intervals
  30. end
  31. end.
  32. is_inside(Intervals, Number) ->
  33. is_inside2(gb_sets:iterator(Intervals), Number).
  34. sum(Intervals) ->
  35. gb_sets:fold(fun({End, Start}, Acc) -> Acc + End - Start end, 0, Intervals).
  36. outerjoin(I1, I2) ->
  37. intersection(inverse(I1), I2).
  38. get_interval_by_nth_inner_number(Intervals, N) ->
  39. get_interval_by_nth_inner_number(gb_sets:iterator(Intervals), N, 0, infinity).
  40. to_etf(Intervals, Limit) ->
  41. serialize(Intervals, Limit, etf).
  42. to_json(Intervals, Limit) ->
  43. serialize(Intervals, Limit, json).
  44. safe_from_etf(Binary) ->
  45. case catch from_etf(Binary) of
  46. {ok, Intervals} ->
  47. {ok, Intervals};
  48. _ ->
  49. {error, invalid}
  50. end.
  51. %%%===================================================================
  52. %%% Private functions.
  53. %%%===================================================================
  54. compact(Intervals) ->
  55. Iterator = gb_sets:iterator(Intervals),
  56. case gb_sets:next(Iterator) of
  57. none ->
  58. Intervals;
  59. {Item, UpdatedIterator} ->
  60. compact(UpdatedIterator, Item, [])
  61. end.
  62. compact(Iterator, {End, Start}, List) ->
  63. case gb_sets:next(Iterator) of
  64. none ->
  65. gb_sets:from_list([{End, Start} | List]);
  66. {{End2, End}, UpdatedIterator} ->
  67. compact(UpdatedIterator, {End2, Start}, List);
  68. {Item, UpdatedIterator} ->
  69. compact(UpdatedIterator, Item, [{End, Start} | List])
  70. end.
  71. is_inside2(Iterator, Number) ->
  72. case gb_sets:next(Iterator) of
  73. none ->
  74. false;
  75. {{_, Start}, _} when Number =< Start ->
  76. false;
  77. {{End, _}, _} when Number =< End ->
  78. true;
  79. {_, UpdatedIterator} ->
  80. is_inside2(UpdatedIterator, Number)
  81. end.
  82. inverse(Intervals) ->
  83. inverse(gb_sets:iterator(Intervals), 0, gb_sets:new()).
  84. inverse(Iterator, L, G) ->
  85. case gb_sets:next(Iterator) of
  86. none ->
  87. gb_sets:add_element({infinity, L}, G);
  88. {{End1, Start1}, I1} ->
  89. G2 = case Start1 > L of true -> gb_sets:add_element({Start1, L}, G); _ -> G end,
  90. L2 = End1,
  91. case gb_sets:next(I1) of
  92. none ->
  93. gb_sets:add_element({infinity, L2}, G2);
  94. {{End2, Start2}, I2} ->
  95. inverse(I2, End2, gb_sets:add_element({Start2, End1}, G2))
  96. end
  97. end.
  98. intersection(I1, I2) ->
  99. intersection(gb_sets:iterator(I1), gb_sets:iterator(I2), gb_sets:new()).
  100. intersection(I1, I2, G) ->
  101. case {gb_sets:next(I1), gb_sets:next(I2)} of
  102. {none, _} ->
  103. G;
  104. {_, none} ->
  105. G;
  106. {{{End1, _Start1}, UpdatedI1}, {{_End2, Start2}, _UpdatedI2}} when Start2 >= End1 ->
  107. intersection(UpdatedI1, I2, G);
  108. {{{_End1, Start1}, _UpdatedI1}, {{End2, _Start2}, UpdatedI2}} when Start1 >= End2 ->
  109. intersection(I1, UpdatedI2, G);
  110. {{{End1, Start1}, UpdatedI1}, {{End2, Start2}, _UpdatedI2}} when End2 >= End1 ->
  111. intersection(UpdatedI1, I2, gb_sets:add_element({End1, max(Start1, Start2)}, G));
  112. {{{End1, Start1}, _UpdatedI1}, {{End2, Start2}, UpdatedI2}} when End1 > End2 ->
  113. intersection(I1, UpdatedI2, gb_sets:add_element({End2, max(Start1, Start2)}, G))
  114. end.
  115. get_interval_by_nth_inner_number(Iterator, N, L, R) ->
  116. case gb_sets:next(Iterator) of
  117. none ->
  118. {L, N, R};
  119. {{End, Start}, UpdatedIterator} when N >= End - Start ->
  120. get_interval_by_nth_inner_number(UpdatedIterator, N - End + Start, End, R);
  121. {{End, Start}, _UpdatedIterator} ->
  122. {Start, Start + N, End}
  123. end.
  124. serialize(Intervals, Limit, Format) ->
  125. case gb_sets:is_empty(Intervals) of
  126. true ->
  127. term_to_binary([]);
  128. false ->
  129. Iterator = gb_sets:iterator(Intervals),
  130. serialize(Iterator, min(Limit / gb_sets:size(Intervals), 1), [], 0, Limit, Format)
  131. end.
  132. serialize(_Iterator, _Probability, L, Count, Limit, Format) when Count == Limit ->
  133. serialize_list(L, Format);
  134. serialize(Iterator, Probability, L, Count, Limit, Format) ->
  135. case gb_sets:next(Iterator) of
  136. none ->
  137. serialize_list(L, Format);
  138. {{End, Start}, UpdatedIterator} ->
  139. PickItem = case Probability < 1 of
  140. true ->
  141. rand:uniform() < Probability;
  142. false ->
  143. true
  144. end,
  145. case PickItem of
  146. false ->
  147. serialize(UpdatedIterator, Probability, L, Count, Limit, Format);
  148. true ->
  149. UpdatedL = [serialize_item(End, Start, Format) | L],
  150. serialize(UpdatedIterator, Probability, UpdatedL, Count + 1, Limit, Format)
  151. end
  152. end.
  153. serialize_list(L, etf) ->
  154. term_to_binary(L);
  155. serialize_list(L, json) ->
  156. jiffy:encode(L).
  157. serialize_item(End, Start, etf) ->
  158. {<< End:256 >>, << Start:256 >>};
  159. serialize_item(End, Start, json) ->
  160. #{ integer_to_binary(End) => integer_to_binary(Start) }.
  161. from_etf(Binary) ->
  162. L = binary_to_term(Binary, [safe]),
  163. from_etf(L, infinity, gb_sets:new()).
  164. from_etf([], _, Intervals) ->
  165. {ok, Intervals};
  166. from_etf([{<< End:256 >>, << Start:256 >>} | List], R, Intervals)
  167. when End > Start andalso R > End andalso Start >= 0 ->
  168. from_etf(List, Start, gb_sets:add_element({End, Start}, Intervals)).