use crate::sorter::constants::{
MAX_MEDIAN_TILE_SIZE, MAX_NUM_LARGE_TILES, MAX_NUM_TILES, MIN_MEDIAN_TILE_SIZE, MIN_NUM_TILES,
MIN_TILE_SIZE,
};
use crate::tile_index::TileIndex;
use log::{debug, info};
pub fn should_use_in_place(tile_index: &TileIndex, n: usize) -> bool {
let stats = tile_index.stats();
if stats.num_tiles == 0 {
return false;
}
if stats.num_tiles > MAX_NUM_LARGE_TILES && stats.median_size >= MAX_MEDIAN_TILE_SIZE {
debug!(
"n={}, tiles={}, avg={}, median={}, min={}, decision=INPLACE (many large tiles)",
n, stats.num_tiles, stats.avg_size, stats.median_size, stats.min_size
);
return true;
}
if stats.num_tiles > MAX_NUM_TILES && stats.median_size < MIN_MEDIAN_TILE_SIZE {
debug!(
"n={}, tiles={}, avg={}, median={}, min={}, decision=CLONE (many tiny tiles)",
n, stats.num_tiles, stats.avg_size, stats.median_size, stats.min_size
);
return false;
}
if stats.median_size < MIN_MEDIAN_TILE_SIZE {
debug!(
"n={}, tiles={}, avg={}, median={}, min={}, decision=CLONE (small median)",
n, stats.num_tiles, stats.avg_size, stats.median_size, stats.min_size
);
return false;
}
if stats.min_size < MIN_TILE_SIZE && stats.num_tiles > MIN_NUM_TILES {
debug!(
"n={}, tiles={}, avg={}, median={}, min={}, decision=CLONE (tiny min, many tiles)",
n, stats.num_tiles, stats.avg_size, stats.median_size, stats.min_size
);
return false;
}
debug!(
"n={}, tiles={}, avg={}, median={}, min={}, decision=CLONE (default)",
n, stats.num_tiles, stats.avg_size, stats.median_size, stats.min_size
);
false
}
pub(crate) fn restructure_in_place_permute<T>(data: &mut [T], tile_index: &TileIndex)
where
T: Clone,
{
if tile_index.len() <= 1 {
return;
}
let n = data.len();
let mut permutation: Vec<usize> = vec![0; n];
let mut dest_pos = 0;
for tile in tile_index.iter() {
let src_start = tile.start_idx();
let len = tile.len();
debug!("Tile: src={} dest={} len={}", src_start, dest_pos, len);
for i in 0..len {
permutation[src_start + i] = dest_pos + i;
}
dest_pos += len;
}
debug!("Permutation: {:?}", permutation);
debug!("Starting cycle-following on {} elements", n);
let mut visited = vec![false; n];
for start in 0..n {
if visited[start] || permutation[start] == start {
visited[start] = true;
continue;
}
let mut temp = data[start].clone();
visited[start] = true;
let mut current = start;
loop {
let next = permutation[current];
let next_val = data[next].clone();
visited[next] = true;
data[next] = temp;
if next == start {
break;
}
temp = next_val;
current = next;
}
}
}
pub fn restructure_in_place_copy<T>(data: &mut [T], tile_index: &TileIndex)
where
T: Clone,
{
info!("Restructuring with {} tiles", tile_index.len());
let original = data.to_vec();
let mut write_pos = 0;
for (i, tile) in tile_index.iter().enumerate() {
let start = tile.start_idx();
let end = start + tile.len();
debug!(
"Tile {}: start={}, count={}, copying to position {}",
i,
start,
tile.len(),
write_pos
);
data[write_pos..write_pos + tile.len()].clone_from_slice(&original[start..end]);
write_pos += tile.len();
}
}
#[cfg(test)]
mod tests {
use crate::tilesort;
#[test]
fn test_integration() {
let mut data = vec![3, 4, 5, 1, 2, 6, 7, 8];
tilesort(&mut data);
assert_eq!(data, vec![1, 2, 3, 4, 5, 6, 7, 8]);
}
}