extsort_iter/merge/
treebuilder.rs1use std::{cmp::Ordering, ops::Range};
2
3use super::{TreeNode, Winner};
4
5pub(super) struct LoserTreeBuilder<'a, C> {
11 winner_comparer: C,
12 loser_tree: &'a mut Vec<u32>,
13}
14
15fn split_range(range: Range<u32>, split_point: usize) -> (Range<u32>, Range<u32>) {
19 let midpoint = range.start + split_point as u32;
20 let mut left = range.clone();
21 let mut right = range;
22 left.end = midpoint;
23 right.start = midpoint;
24 (left, right)
25}
26
27impl<'a, C> LoserTreeBuilder<'a, C>
28where
29 C: FnMut(Winner, Winner) -> Ordering,
30{
31 pub fn new(winner_comparer: C, loser_tree: &'a mut Vec<u32>) -> Self {
32 Self {
33 winner_comparer,
34 loser_tree,
35 }
36 }
37
38 pub(super) fn build(mut self, number_of_tapes: usize) -> Winner {
39 let num_internal_nodes = number_of_tapes - 1;
40 if self.loser_tree.len() < num_internal_nodes {
41 *self.loser_tree = vec![0; num_internal_nodes];
42 }
43 self.build_tree_complete(0..number_of_tapes as u32, TreeNode::root())
44 }
45
46 fn build_tree_perfect(&mut self, range_todo: Range<u32>, root: TreeNode) -> Winner {
47 if range_todo.len() == 1 {
48 Winner {
49 idx: range_todo.start,
50 }
51 } else {
52 let subtree_size = range_todo.len() / 2;
53 let (left, right) = split_range(range_todo, subtree_size);
54 let winner_left = self.build_tree_perfect(left, root.left());
55 let winner_right = self.build_tree_perfect(right, root.right());
56 self.commit_winner(winner_left, winner_right, root)
57 }
58 }
59
60 fn build_tree_complete(&mut self, range_todo: Range<u32>, root: TreeNode) -> Winner {
61 let total_nodes = range_todo.len();
62 if total_nodes.is_power_of_two() {
63 self.build_tree_perfect(range_todo, root)
64 } else {
65 let nodes_if_lowest_level_was_full = total_nodes.next_power_of_two();
66 let nodes_in_lower_level = (total_nodes - nodes_if_lowest_level_was_full / 2) * 2;
67
68 let perfect_tree_left = nodes_in_lower_level >= nodes_if_lowest_level_was_full / 2;
69
70 if perfect_tree_left {
71 let nodes_in_left_tree = nodes_if_lowest_level_was_full / 2;
72 let (left, right) = split_range(range_todo, nodes_in_left_tree);
73 let w_left = self.build_tree_perfect(left, root.left());
74 let w_right = self.build_tree_complete(right, root.right());
75 self.commit_winner(w_left, w_right, root)
76 } else {
77 let nodes_in_right_tree = nodes_if_lowest_level_was_full / 2 / 2;
80 let nodes_in_left_tree = total_nodes - nodes_in_right_tree;
81 let (left, right) = split_range(range_todo, nodes_in_left_tree);
82 let w_left = self.build_tree_complete(left, root.left());
83 let w_right = self.build_tree_perfect(right, root.right());
84 self.commit_winner(w_left, w_right, root)
85 }
86 }
87 }
88
89 fn commit_winner(
90 &mut self,
91 candidate_a: Winner,
92 candidate_b: Winner,
93 root: TreeNode,
94 ) -> Winner {
95 let (winner, loser) = if (self.winner_comparer)(candidate_a, candidate_b).is_le() {
96 (candidate_a, candidate_b)
98 } else {
99 (candidate_b, candidate_a)
101 };
102 self.loser_tree[root.idx] = loser.idx;
103 winner
104 }
105}
106
107#[cfg(test)]
108mod test {
109 use crate::orderer::{OrdOrderer, Orderer};
110
111 use super::LoserTreeBuilder;
112
113 fn assert_winner(tape: &[i64]) {
114 let orderer = OrdOrderer {};
115 let min_value = *tape.iter().min().unwrap();
116 let ref_tape = tape.iter().collect::<Vec<_>>();
117 let mut tree = Vec::new();
118 let winner = LoserTreeBuilder::new(
119 |a, b| orderer.compare(ref_tape[a.idx as usize], ref_tape[b.idx as usize]),
120 &mut tree,
121 )
122 .build(ref_tape.len());
123 assert_eq!(min_value, tape[winner.idx as usize]);
124 if tape.len() > 1 {
125 assert!(min_value <= tape[tree[0] as usize])
126 }
127 }
128
129 #[test]
130 fn test_power_two() {
131 assert!(1usize.is_power_of_two())
132 }
133
134 fn run_tree_construction_test(max_size: usize) {
135 for r in 1..max_size {
136 println!("constructing zero tree with {r} tapes");
137 assert_winner(&vec![0; r]);
138 println!("constructing ordered tree with {r} tapes");
139 let mut tape = (0..r as i64).collect::<Vec<_>>();
140 assert_winner(&tape);
141 println!("constructing reversed tree wtih {r} tapes");
142 let mut reversed_tape = tape.clone();
143 reversed_tape.reverse();
144 assert_winner(&reversed_tape);
145 println!("constructing tree with min in the middle");
146 reversed_tape.append(&mut tape);
147 assert_winner(&reversed_tape);
148 }
149 }
150
151 #[test]
152 fn test_construct_tree_small() {
153 run_tree_construction_test(10);
154 }
155
156 #[test]
159 #[cfg(not(miri))]
160 fn test_construct_tree() {
161 run_tree_construction_test(100);
162 }
163}