@@ -221,18 +221,49 @@ impl HilbertRTree {
221221 hilbert_values[ i] = hilbert_xy_to_index ( hx, hy) ;
222222 }
223223
224- // Initialize leaf indices BEFORE sorting
224+ // Create an indirection array to track sorting permutations
225+ // This allows us to use Rust's optimized sort (introsort) instead of custom quicksort
226+ let mut sort_indices: Vec < usize > = ( 0 ..num_items) . collect ( ) ;
227+
228+ // Sort indices by their corresponding Hilbert values
229+ sort_indices. sort_unstable_by_key ( |& i| hilbert_values[ i] ) ;
230+
231+ // Apply the permutation to boxes
232+ let mut temp_data = vec ! [ 0u8 ; num_items * size_of:: <Box >( ) ] ;
233+
234+ for ( new_pos, & old_pos) in sort_indices. iter ( ) . enumerate ( ) {
235+ let old_box_idx = HEADER_SIZE + old_pos * size_of :: < Box > ( ) ;
236+ let new_box_idx = new_pos * size_of :: < Box > ( ) ;
237+ temp_data[ new_box_idx..new_box_idx + size_of :: < Box > ( ) ]
238+ . copy_from_slice ( & self . data [ old_box_idx..old_box_idx + size_of :: < Box > ( ) ] ) ;
239+ }
240+
241+ // Copy sorted boxes back to data
242+ for i in 0 ..num_items {
243+ let src_idx = i * size_of :: < Box > ( ) ;
244+ let dst_idx = HEADER_SIZE + i * size_of :: < Box > ( ) ;
245+ self . data [ dst_idx..dst_idx + size_of :: < Box > ( ) ]
246+ . copy_from_slice ( & temp_data[ src_idx..src_idx + size_of :: < Box > ( ) ] ) ;
247+ }
248+
249+ // Apply the same permutation to hilbert_values array to keep it in sync with boxes
250+ let mut temp_hilbert = vec ! [ 0_u32 ; num_items] ;
251+ for ( new_pos, & old_pos) in sort_indices. iter ( ) . enumerate ( ) {
252+ temp_hilbert[ new_pos] = hilbert_values[ old_pos] ;
253+ }
254+ // Note: We keep temp_hilbert for consistency but don't need it for later operations
255+ // since the indices array contains the original box IDs
256+
257+ // Initialize leaf indices AFTER sorting - map new position to original box ID
225258 let indices_start = HEADER_SIZE + total_nodes * size_of :: < Box > ( ) ;
226259 for i in 0 ..num_items {
227260 let idx_ptr = & mut self . data [ indices_start + i * size_of :: < u32 > ( ) ] as * mut u8 as * mut u32 ;
228261 unsafe {
229- std:: ptr:: write_unaligned ( idx_ptr, i as u32 ) ;
262+ // sort_indices[i] tells us which original box is now at position i
263+ std:: ptr:: write_unaligned ( idx_ptr, sort_indices[ i] as u32 ) ;
230264 }
231265 }
232266
233- // Sort leaves by Hilbert value
234- self . quicksort ( & mut hilbert_values, 0 , num_items - 1 ) ;
235-
236267 // Build parent levels
237268 let mut pos = 0_usize ;
238269 for level_idx in 0 ..self . level_bounds . len ( ) - 1 {
@@ -1276,98 +1307,6 @@ impl HilbertRTree {
12761307 }
12771308 }
12781309
1279- /// Quicksort by Hilbert value, also reordering boxes and indices
1280- fn quicksort ( & mut self , hilbert_values : & mut [ u32 ] , left : usize , right : usize ) {
1281- if left >= right {
1282- return ;
1283- }
1284-
1285- let pivot = self . median_of_three ( hilbert_values, left, right) ;
1286- let mut pivot_left = left as i32 - 1 ;
1287- let mut pivot_right = right as i32 + 1 ;
1288-
1289- loop {
1290- loop {
1291- pivot_left += 1 ;
1292- if hilbert_values[ pivot_left as usize ] >= pivot {
1293- break ;
1294- }
1295- }
1296- loop {
1297- pivot_right -= 1 ;
1298- if hilbert_values[ pivot_right as usize ] <= pivot {
1299- break ;
1300- }
1301- }
1302-
1303- if pivot_left >= pivot_right {
1304- break ;
1305- }
1306-
1307- self . swap_elements ( hilbert_values, pivot_left as usize , pivot_right as usize ) ;
1308- }
1309-
1310- if pivot_right as usize > left {
1311- self . quicksort ( hilbert_values, left, pivot_right as usize ) ;
1312- }
1313- if ( pivot_right as usize + 1 ) < right {
1314- self . quicksort ( hilbert_values, pivot_right as usize + 1 , right) ;
1315- }
1316- }
1317-
1318- /// Median of three for quicksort pivot selection
1319- #[ inline]
1320- fn median_of_three ( & self , values : & [ u32 ] , left : usize , right : usize ) -> u32 {
1321- let mid = ( left + right) / 2 ;
1322- let a = values[ left] ;
1323- let b = values[ mid] ;
1324- let c = values[ right] ;
1325-
1326- let x = a. max ( b) ;
1327- if c > x {
1328- x
1329- } else if x == a {
1330- b. max ( c)
1331- } else if x == b {
1332- a. max ( c)
1333- } else {
1334- c
1335- }
1336- }
1337-
1338- /// Swap two elements (including boxes and indices)
1339- fn swap_elements ( & mut self , hilbert_values : & mut [ u32 ] , left : usize , right : usize ) {
1340- hilbert_values. swap ( left, right) ;
1341-
1342- // Swap boxes
1343- let left_box_idx = HEADER_SIZE + left * size_of :: < Box > ( ) ;
1344- let right_box_idx = HEADER_SIZE + right * size_of :: < Box > ( ) ;
1345-
1346- let left_box = self . get_box ( left) ;
1347- let right_box = self . get_box ( right) ;
1348-
1349- let left_ptr = & mut self . data [ left_box_idx] as * mut u8 as * mut Box ;
1350- let right_ptr = & mut self . data [ right_box_idx] as * mut u8 as * mut Box ;
1351-
1352- unsafe {
1353- std:: ptr:: write_unaligned ( left_ptr, right_box) ;
1354- std:: ptr:: write_unaligned ( right_ptr, left_box) ;
1355- }
1356-
1357- // Swap indices
1358- let indices_start = HEADER_SIZE + self . total_nodes * size_of :: < Box > ( ) ;
1359-
1360- let left_idx_ptr = & mut self . data [ indices_start + left * size_of :: < u32 > ( ) ] as * mut u8 as * mut u32 ;
1361- let right_idx_ptr = & mut self . data [ indices_start + right * size_of :: < u32 > ( ) ] as * mut u8 as * mut u32 ;
1362-
1363- unsafe {
1364- let left_idx = std:: ptr:: read_unaligned ( left_idx_ptr) ;
1365- let right_idx = std:: ptr:: read_unaligned ( right_idx_ptr) ;
1366- std:: ptr:: write_unaligned ( left_idx_ptr, right_idx) ;
1367- std:: ptr:: write_unaligned ( right_idx_ptr, left_idx) ;
1368- }
1369- }
1370-
13711310 /// Saves the built Hilbert R-tree to a file.
13721311 ///
13731312 /// Serializes the complete tree structure including the header, buffer, metadata, and level bounds
0 commit comments