Skip to content

Commit 0f5b486

Browse files
committed
opt 7 for f64
1 parent d253da8 commit 0f5b486

File tree

1 file changed

+36
-97
lines changed

1 file changed

+36
-97
lines changed

src/hilbert_rtree.rs

Lines changed: 36 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)