Branch data Line data Source code
1 : : // Copyright (c) The Bitcoin Core developers
2 : : // Distributed under the MIT software license, see the accompanying
3 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 : :
5 : : #include <util/feefrac.h>
6 : : #include <algorithm>
7 : : #include <array>
8 : : #include <vector>
9 : :
10 : 25 : std::partial_ordering CompareChunks(Span<const FeeFrac> chunks0, Span<const FeeFrac> chunks1)
11 : : {
12 : : /** Array to allow indexed access to input diagrams. */
13 : 25 : const std::array<Span<const FeeFrac>, 2> chunk = {chunks0, chunks1};
14 : : /** How many elements we have processed in each input. */
15 : 25 : size_t next_index[2] = {0, 0};
16 : : /** Accumulated fee/sizes in diagrams, up to next_index[i] - 1. */
17 : 25 : FeeFrac accum[2];
18 : : /** Whether the corresponding input is strictly better than the other at least in one place. */
19 : 25 : bool better_somewhere[2] = {false, false};
20 : : /** Get the first unprocessed point in diagram number dia. */
21 : 242 : const auto next_point = [&](int dia) { return chunk[dia][next_index[dia]] + accum[dia]; };
22 : : /** Get the last processed point in diagram number dia. */
23 : 98 : const auto prev_point = [&](int dia) { return accum[dia]; };
24 : : /** Move to the next point in diagram number dia. */
25 : 25 : const auto advance = [&](int dia) { accum[dia] += chunk[dia][next_index[dia]++]; };
26 : :
27 : 92 : do {
28 [ + + ]: 92 : bool done_0 = next_index[0] == chunk[0].size();
29 : 92 : bool done_1 = next_index[1] == chunk[1].size();
30 [ + + ]: 92 : if (done_0 && done_1) break;
31 : :
32 : : // Determine which diagram has the first unprocessed point. If a single side is finished, use the
33 : : // other one. Only up to one can be done due to check above.
34 [ + + ]: 73 : const int unproc_side = (done_0 || done_1) ? done_0 : next_point(0).size > next_point(1).size;
35 : :
36 : : // Let `P` be the next point on diagram unproc_side, and `A` and `B` the previous and next points
37 : : // on the other diagram. We want to know if P lies above or below the line AB. To determine this, we
38 : : // compute the slopes of line AB and of line AP, and compare them. These slopes are fee per size,
39 : : // and can thus be expressed as FeeFracs.
40 : 73 : const FeeFrac& point_p = next_point(unproc_side);
41 : 73 : const FeeFrac& point_a = prev_point(!unproc_side);
42 : :
43 : 73 : const auto slope_ap = point_p - point_a;
44 : 73 : Assume(slope_ap.size > 0);
45 : 73 : std::weak_ordering cmp = std::weak_ordering::equivalent;
46 [ + + ]: 73 : if (done_0 || done_1) {
47 : : // If a single side has no points left, act as if AB has slope tail_feerate(of 0).
48 : 25 : Assume(!(done_0 && done_1));
49 : 25 : cmp = FeeRateCompare(slope_ap, FeeFrac(0, 1));
50 : : } else {
51 : : // If both sides have points left, compute B, and the slope of AB explicitly.
52 : 48 : const FeeFrac& point_b = next_point(!unproc_side);
53 : 48 : const auto slope_ab = point_b - point_a;
54 : 48 : Assume(slope_ab.size >= slope_ap.size);
55 : 48 : cmp = FeeRateCompare(slope_ap, slope_ab);
56 : :
57 : : // If B and P have the same size, B can be marked as processed (in addition to P, see
58 : : // below), as we've already performed a comparison at this size.
59 [ + + ]: 48 : if (point_b.size == point_p.size) advance(!unproc_side);
60 : : }
61 : : // If P lies above AB, unproc_side is better in P. If P lies below AB, then !unproc_side is
62 : : // better in P.
63 [ + + ]: 73 : if (std::is_gt(cmp)) better_somewhere[unproc_side] = true;
64 [ + + ]: 73 : if (std::is_lt(cmp)) better_somewhere[!unproc_side] = true;
65 : 73 : advance(unproc_side);
66 : :
67 : : // If both diagrams are better somewhere, they are incomparable.
68 [ + + + + ]: 73 : if (better_somewhere[0] && better_somewhere[1]) return std::partial_ordering::unordered;
69 : : } while(true);
70 : :
71 : : // Otherwise compare the better_somewhere values.
72 [ + + + + ]: 19 : return better_somewhere[0] <=> better_somewhere[1];
73 : : }
|