feefrac.cpp
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 std::partial_ordering CompareChunks(std::span<const FeeFrac> chunks0, std::span<const FeeFrac> chunks1) 11 { 12 /** Array to allow indexed access to input diagrams. */ 13 const std::array<std::span<const FeeFrac>, 2> chunk = {chunks0, chunks1}; 14 /** How many elements we have processed in each input. */ 15 size_t next_index[2] = {0, 0}; 16 /** Accumulated fee/sizes in diagrams, up to next_index[i] - 1. */ 17 FeeFrac accum[2]; 18 /** Whether the corresponding input is strictly better than the other at least in one place. */ 19 bool better_somewhere[2] = {false, false}; 20 /** Get the first unprocessed point in diagram number dia. */ 21 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 const auto prev_point = [&](int dia) { return accum[dia]; }; 24 /** Move to the next point in diagram number dia. */ 25 const auto advance = [&](int dia) { accum[dia] += chunk[dia][next_index[dia]++]; }; 26 27 do { 28 bool done_0 = next_index[0] == chunk[0].size(); 29 bool done_1 = next_index[1] == chunk[1].size(); 30 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 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 const FeeFrac& point_p = next_point(unproc_side); 41 const FeeFrac& point_a = prev_point(!unproc_side); 42 43 const auto slope_ap = point_p - point_a; 44 Assume(slope_ap.size > 0); 45 std::weak_ordering cmp = std::weak_ordering::equivalent; 46 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 Assume(!(done_0 && done_1)); 49 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 const FeeFrac& point_b = next_point(!unproc_side); 53 const auto slope_ab = point_b - point_a; 54 Assume(slope_ab.size >= slope_ap.size); 55 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 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 if (std::is_gt(cmp)) better_somewhere[unproc_side] = true; 64 if (std::is_lt(cmp)) better_somewhere[!unproc_side] = true; 65 advance(unproc_side); 66 67 // If both diagrams are better somewhere, they are incomparable. 68 if (better_somewhere[0] && better_somewhere[1]) return std::partial_ordering::unordered; 69 } while(true); 70 71 // Otherwise compare the better_somewhere values. 72 return better_somewhere[0] <=> better_somewhere[1]; 73 }