use core::hint::select_unpredictable;
use core::mem::{ManuallyDrop, MaybeUninit, size_of};
use core::ptr;
use core::sync::atomic::{AtomicUsize, Ordering};
use std::panic::resume_unwind;
use std::sync::{Condvar, Mutex, PoisonError};
use std::thread;
pub fn odd_even<T: Ord>(arr: &mut [T]) {
if arr.len() < 2 {
return;
}
let mut rounds = Rounds::new(arr.len());
rounds.run(arr, usize::MAX);
}
pub fn odd_even_parallel<T: Ord + Send>(arr: &mut [T]) {
let n = arr.len();
if n < 2 {
return;
}
let mut rounds = Rounds::new(n);
let min_len = parallel_min_len(size_of::<T>());
if n >= min_len {
rounds.run(arr, (warmup_pairs(size_of::<T>()) / n).max(WARMUP_ROUNDS));
let mut threads = None;
while let Some((lo, m)) = rounds.next {
let e0 = lo - 1;
let e1 = (lo + 2 * m + 1).min(n);
let active = e1 - e0;
let threads = *threads
.get_or_insert_with(|| thread::available_parallelism().map_or(1, |p| p.get()));
if threads < 2 || active < min_len / 2 {
break;
}
let margin = active / 2;
let w0 = e0.saturating_sub(margin);
let w1 = (e1 + margin).min(n);
if !session(arr, w0, w1, &mut rounds, threads) {
break;
}
}
}
rounds.run(arr, usize::MAX);
}
const fn parallel_min_len(size: usize) -> usize {
if cfg!(miri) {
64
} else if size <= BRANCHLESS_MAX_SIZE {
4096
} else {
2048
}
}
const fn warmup_pairs(size: usize) -> usize {
if cfg!(miri) {
256
} else if size <= BRANCHLESS_MAX_SIZE {
1 << 20
} else {
1 << 16
}
}
const fn min_block(size: usize) -> usize {
if cfg!(miri) {
16
} else if size <= BRANCHLESS_MAX_SIZE {
1024
} else {
512
}
}
const WARMUP_ROUNDS: usize = 64;
const FIRST_K: usize = 8;
const BLOCKS_PER_THREAD: usize = 2;
#[derive(Clone, Copy, Debug)]
struct Swaps {
first: usize,
last: usize,
}
impl Swaps {
const NONE: Swaps = Swaps {
first: usize::MAX,
last: 0,
};
#[inline(always)]
fn is_none(self) -> bool {
self.first == usize::MAX
}
#[inline(always)]
fn merge(self, other: Swaps) -> Swaps {
Swaps {
first: self.first.min(other.first),
last: self.last.max(other.last),
}
}
#[inline(always)]
fn push(&mut self, k: usize) {
self.first = self.first.min(k);
self.last = k;
}
}
struct Rounds {
n: usize,
next: Option<(usize, usize)>,
left: usize,
}
impl Rounds {
fn new(n: usize) -> Self {
Rounds {
n,
next: Some((1, (n - 1) / 2)),
left: n.div_ceil(2),
}
}
fn after(&mut self, swaps: Swaps) {
self.next = if swaps.is_none() || self.left == 0 {
None
} else {
let lo = if swaps.first == 0 { 1 } else { swaps.first - 1 };
let hi = if swaps.last + 2 < self.n {
Some(swaps.last + 1)
} else {
swaps.last.checked_sub(1)
};
match hi {
Some(hi) if hi >= lo => Some((lo, (hi - lo) / 2 + 1)),
_ => None,
}
};
}
fn run<T: Ord>(&mut self, arr: &mut [T], max: usize) {
let base = arr.as_mut_ptr();
let mut budget = max;
while let Some((lo, m)) = self.next {
if budget == 0 {
return;
}
budget -= 1;
self.left -= 1;
let nb = if lo + 2 * m < self.n { m + 1 } else { m };
let swaps = unsafe { round(base, lo, m, lo - 1, nb) };
self.after(swaps);
}
}
}
const BRANCHLESS_MAX_SIZE: usize = 8;
const CHUNK: usize = 32;
const LAG: usize = 2;
#[inline(always)]
unsafe fn cx_branchless<T: Ord>(a: *mut T, b: *mut T) -> bool {
unsafe {
let swap = *b < *a;
let x = ManuallyDrop::new(ptr::read(a));
let y = ManuallyDrop::new(ptr::read(b));
let lo = select_unpredictable(swap, &y, &x);
let hi = select_unpredictable(swap, &x, &y);
ptr::copy_nonoverlapping::<T>(&**lo, a, 1);
ptr::copy_nonoverlapping::<T>(&**hi, b, 1);
swap
}
}
#[inline(always)]
unsafe fn cx_branchy<T: Ord>(a: *mut T, b: *mut T) -> bool {
unsafe {
if *b < *a {
let x = ManuallyDrop::new(ptr::read(a));
let y = ManuallyDrop::new(ptr::read(b));
ptr::write(a, ManuallyDrop::into_inner(y));
ptr::write(b, ManuallyDrop::into_inner(x));
true
} else {
false
}
}
}
#[inline(always)]
unsafe fn cx<T: Ord>(base: *mut T, k: usize) -> bool {
unsafe {
if size_of::<T>() <= BRANCHLESS_MAX_SIZE {
cx_branchless(base.add(k), base.add(k + 1))
} else {
cx_branchy(base.add(k), base.add(k + 1))
}
}
}
#[inline(always)]
unsafe fn steps_branchless<T: Ord>(p: *mut T, c: usize) -> u64 {
let mut mask = 0;
for i in 0..c {
unsafe {
let q = p.add(2 * i);
cx_branchless(q.add(1), q.add(2));
let s = cx_branchless(q, q.add(1));
mask |= (s as u64) << i;
}
}
mask
}
const SPLIT_MAX_SIZE: usize = 4;
struct Carry<T> {
val: MaybeUninit<T>,
dst: *mut T,
}
impl<T> Drop for Carry<T> {
#[inline(always)]
fn drop(&mut self) {
unsafe { ptr::copy_nonoverlapping(self.val.as_ptr(), self.dst, 1) }
}
}
struct Chunk<'a, T> {
even: [MaybeUninit<T>; CHUNK],
odd: [MaybeUninit<T>; CHUNK],
last: MaybeUninit<T>,
p: *mut T,
carry: &'a mut Carry<T>,
}
impl<T> Drop for Chunk<'_, T> {
#[inline(always)]
fn drop(&mut self) {
unsafe {
for i in 0..CHUNK {
ptr::copy_nonoverlapping(self.even[i].as_ptr(), self.p.add(2 * i), 1);
ptr::copy_nonoverlapping(self.odd[i].as_ptr(), self.p.add(2 * i + 1), 1);
}
ptr::copy_nonoverlapping(self.last.as_ptr(), self.carry.val.as_mut_ptr(), 1);
self.carry.dst = self.p.add(2 * CHUNK);
}
}
}
#[inline(always)]
unsafe fn cx_held<T: Ord>(a: *mut MaybeUninit<T>, b: *mut MaybeUninit<T>) -> bool {
unsafe {
let swap = (*b).assume_init_ref() < (*a).assume_init_ref();
let (x, y) = (ptr::read(a), ptr::read(b));
let (lo, hi) = select_unpredictable(swap, (ptr::read(&y), ptr::read(&x)), (x, y));
ptr::write(a, lo);
ptr::write(b, hi);
swap
}
}
#[inline(always)]
unsafe fn chunk_steps<T: Ord>(p: *mut T, carry: &mut Carry<T>) -> u64 {
unsafe {
let mut chunk = Chunk::<T> {
even: [const { MaybeUninit::uninit() }; CHUNK],
odd: [const { MaybeUninit::uninit() }; CHUNK],
last: ptr::read(p.add(2 * CHUNK).cast()),
p,
carry,
};
ptr::copy_nonoverlapping(chunk.carry.val.as_ptr(), chunk.even[0].as_mut_ptr(), 1);
for i in 1..CHUNK {
chunk.even[i] = ptr::read(p.add(2 * i).cast());
}
for i in 0..CHUNK {
chunk.odd[i] = ptr::read(p.add(2 * i + 1).cast());
}
let even = chunk.even.as_mut_ptr();
let odd = chunk.odd.as_mut_ptr();
for i in 0..CHUNK - 1 {
cx_held(odd.add(i), even.add(i + 1));
}
cx_held(odd.add(CHUNK - 1), &raw mut chunk.last);
let mut swapped = [0u8; CHUNK];
for (i, s) in swapped.iter_mut().enumerate() {
*s = cx_held(even.add(i), odd.add(i)) as u8;
}
drop(chunk);
let mut mask = 0;
for (k, bytes) in swapped.as_chunks::<8>().0.iter().enumerate() {
let x = u64::from_le_bytes(*bytes);
mask |= (x.wrapping_mul(0x0102_0408_1020_4080) >> 56) << (8 * k);
}
mask
}
}
#[inline(always)]
unsafe fn round<T: Ord>(base: *mut T, a0: usize, na: usize, b0: usize, nb: usize) -> Swaps {
let head = if nb == 0 {
na
} else if na == 0 || b0 + 1 == a0 {
0
} else {
1
};
let mut swaps = Swaps::NONE;
unsafe {
for i in 0..head {
cx(base, a0 + 2 * i);
}
let steps = (na - head).min(nb);
if size_of::<T>() <= BRANCHLESS_MAX_SIZE {
let mut done = 0;
if size_of::<T>() <= SPLIT_MAX_SIZE && steps >= CHUNK {
let mut carry = Carry {
val: MaybeUninit::new(ptr::read(base.add(b0))),
dst: base.add(b0),
};
while steps - done >= CHUNK {
let p = b0 + 2 * done;
let mask = chunk_steps(base.add(p), &mut carry);
if mask != 0 {
swaps.first = swaps.first.min(p + 2 * mask.trailing_zeros() as usize);
swaps.last = p + 2 * (63 - mask.leading_zeros() as usize);
}
done += CHUNK;
}
}
while done < steps {
let p = b0 + 2 * done;
let c = if steps - done >= CHUNK {
CHUNK
} else {
steps - done
};
let mask = if c == CHUNK {
steps_branchless(base.add(p), CHUNK)
} else {
steps_branchless(base.add(p), c)
};
if mask != 0 {
swaps.first = swaps.first.min(p + 2 * mask.trailing_zeros() as usize);
swaps.last = p + 2 * (63 - mask.leading_zeros() as usize);
}
done += c;
}
} else {
for i in 0..steps {
cx(base, a0 + 2 * (head + i));
if i >= LAG {
let k = b0 + 2 * (i - LAG);
if cx(base, k) {
swaps.push(k);
}
}
}
}
for i in head + steps..na {
cx(base, a0 + 2 * i);
}
let from = if size_of::<T>() <= BRANCHLESS_MAX_SIZE {
steps
} else {
steps.saturating_sub(LAG)
};
for i in from..nb {
let k = b0 + 2 * i;
if cx(base, k) {
swaps.push(k);
}
}
}
swaps
}
fn pairs(lo: isize, hi: isize, w0: usize, odd: bool) -> (usize, usize) {
if hi < lo.max(0) {
return (0, 0);
}
let mut first = lo.max(0) as usize;
if ((first + w0) & 1 == 1) != odd {
first += 1;
}
let hi = hi as usize;
if first > hi {
(0, 0)
} else {
(first, (hi - first) / 2 + 1)
}
}
struct Shared<T>(*mut T);
impl<T> Clone for Shared<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for Shared<T> {}
impl<T> Shared<T> {
fn get(self) -> *mut T {
self.0
}
}
unsafe impl<T: Send> Send for Shared<T> {}
unsafe impl<T: Send> Sync for Shared<T> {}
#[derive(Clone, Copy)]
struct Block {
x0: usize,
x1: usize,
shrink_left: bool,
shrink_right: bool,
mid: Option<usize>,
}
struct Plan {
w: usize,
b: Vec<usize>,
c: Vec<usize>,
}
impl Plan {
fn new(w: usize, nb: usize) -> Plan {
let b: Vec<usize> = (0..=nb).map(|i| w * i / nb).collect();
let c: Vec<usize> = (0..nb).map(|i| (b[i] + b[i + 1]) / 2).collect();
Plan { w, b, c }
}
fn max_k(&self) -> usize {
let nb = self.c.len();
(0..nb)
.map(|i| (self.c[i] - self.b[i]).min(self.b[i + 1] - self.c[i]))
.min()
.unwrap_or(0)
}
fn blocks(&self, second: bool) -> usize {
if second {
self.c.len() + 1
} else {
self.c.len()
}
}
fn block(&self, second: bool, i: usize) -> Block {
let nb = self.c.len();
if !second {
Block {
x0: self.b[i],
x1: self.b[i + 1],
shrink_left: i > 0,
shrink_right: i + 1 < nb,
mid: Some(self.c[i]),
}
} else if i == 0 {
Block {
x0: 0,
x1: self.c[0],
shrink_left: false,
shrink_right: true,
mid: None,
}
} else if i == nb {
Block {
x0: self.c[nb - 1],
x1: self.w,
shrink_left: true,
shrink_right: false,
mid: None,
}
} else {
Block {
x0: self.c[i - 1],
x1: self.c[i],
shrink_left: true,
shrink_right: true,
mid: Some(self.b[i]),
}
}
}
}
unsafe fn trapezoid<T: Ord>(base: *mut T, w0: usize, block: Block, k: usize) -> Swaps {
let range = |j: usize| {
let lo = block.x0 + if block.shrink_left { j } else { 0 };
let hi = block.x1 as isize - 2 - if block.shrink_right { j as isize } else { 0 };
(lo as isize, hi)
};
let mut swaps = Swaps::NONE;
for j in (0..k).step_by(2) {
let (lo, hi) = range(j);
let (a0, na) = pairs(lo, hi, w0, true);
let (lo, hi) = range(j + 1);
let (b0, nb) = pairs(lo, hi, w0, false);
swaps = unsafe { round(base, a0, na, b0, nb) };
}
swaps
}
unsafe fn triangle<T: Ord>(base: *mut T, w0: usize, mid: usize, k: usize) -> Swaps {
let mid = mid as isize;
let mut swaps = Swaps::NONE;
for j in (0..k as isize).step_by(2) {
let (a0, na) = pairs(mid - 1 - j, mid + j - 1, w0, true);
let (b0, nb) = pairs(mid - 2 - j, mid + j, w0, false);
swaps = unsafe { round(base, a0, na, b0, nb) };
}
swaps
}
#[derive(Clone, Copy)]
enum Decision {
Run {
s: usize,
k: usize,
kp: usize,
},
Stop,
}
#[derive(Clone, Copy)]
enum Outcome {
Aborted,
Sorted,
Swapped(Swaps),
}
struct Leader {
started: bool,
finishing: bool,
s: usize,
k: usize,
k_max: usize,
rounds_left: usize,
trap: Swaps,
init: (usize, usize),
w: usize,
open_left: bool,
open_right: bool,
outcome: Outcome,
}
impl Leader {
fn decide(&mut self, tri: Swaps, trap: Swaps) -> Decision {
if !self.started {
self.started = true;
self.rounds_left -= self.k / 2;
return Decision::Run {
s: 0,
k: self.k,
kp: 0,
};
}
if self.finishing {
self.outcome = Outcome::Swapped(self.trap.merge(tri));
return Decision::Stop;
}
let s = self.s;
let (lo, hi) = if s == 0 {
self.init
} else {
let known = self.trap.merge(tri);
if known.is_none() {
self.outcome = Outcome::Sorted;
return Decision::Stop;
}
(known.first.saturating_sub(1), known.last + 1)
};
self.trap = trap;
let next_k = self.k_max.min(2 * self.k).min(2 * self.rounds_left);
let reach = self.k + next_k;
let fits =
(!self.open_left || lo >= reach) && (!self.open_right || hi + reach + 2 <= self.w);
let shrunk = s > 0 && (hi - lo + 2) * 2 < self.init.1 - self.init.0 + 2;
if next_k == 0 || !fits || shrunk {
self.finishing = true;
return Decision::Run {
s: s + 1,
k: 0,
kp: self.k,
};
}
self.rounds_left -= next_k / 2;
let kp = self.k;
self.s = s + 1;
self.k = next_k;
Decision::Run {
s: s + 1,
k: next_k,
kp,
}
}
}
struct BarrierState {
arrived: usize,
generation: usize,
poisoned: bool,
tri: Swaps,
trap: Swaps,
decision: Decision,
leader: Leader,
}
struct Barrier {
state: Mutex<BarrierState>,
cv: Condvar,
parties: usize,
next_block: AtomicUsize,
}
impl Barrier {
fn wait(&self, tri: Swaps, trap: Swaps) -> Option<Decision> {
let mut st = self.state.lock().unwrap_or_else(PoisonError::into_inner);
if st.poisoned {
return None;
}
st.tri = st.tri.merge(tri);
st.trap = st.trap.merge(trap);
st.arrived += 1;
if st.arrived == self.parties {
let (tri, trap) = (st.tri, st.trap);
st.tri = Swaps::NONE;
st.trap = Swaps::NONE;
st.arrived = 0;
st.decision = st.leader.decide(tri, trap);
st.generation += 1;
self.next_block.store(0, Ordering::Relaxed);
self.cv.notify_all();
Some(st.decision)
} else {
let generation = st.generation;
while st.generation == generation && !st.poisoned {
st = self.cv.wait(st).unwrap_or_else(PoisonError::into_inner);
}
if st.poisoned { None } else { Some(st.decision) }
}
}
fn poison(&self) {
let mut st = self.state.lock().unwrap_or_else(PoisonError::into_inner);
st.poisoned = true;
self.cv.notify_all();
}
}
struct PoisonOnUnwind<'a>(&'a Barrier);
impl Drop for PoisonOnUnwind<'_> {
fn drop(&mut self) {
if thread::panicking() {
self.0.poison();
}
}
}
fn worker<T: Ord>(base: Shared<T>, w0: usize, plan: &Plan, barrier: &Barrier) {
let _guard = PoisonOnUnwind(barrier);
let base = base.get();
let (mut tri, mut trap) = (Swaps::NONE, Swaps::NONE);
while let Some(Decision::Run { s, k, kp }) = barrier.wait(tri, trap) {
tri = Swaps::NONE;
trap = Swaps::NONE;
let second = s % 2 == 1;
loop {
let i = barrier.next_block.fetch_add(1, Ordering::Relaxed);
if i >= plan.blocks(second) {
break;
}
let block = plan.block(second, i);
unsafe {
if let (Some(mid), true) = (block.mid, kp > 0) {
tri = tri.merge(triangle(base, w0, mid, kp));
}
if k > 0 {
trap = trap.merge(trapezoid(base, w0, block, k));
}
}
}
}
}
fn session<T: Ord + Send>(
arr: &mut [T],
w0: usize,
w1: usize,
rounds: &mut Rounds,
threads: usize,
) -> bool {
let n = arr.len();
let Some((lo, m)) = rounds.next else {
return false;
};
let w = w1 - w0;
let nb = (threads * BLOCKS_PER_THREAD).min(w / min_block(size_of::<T>()));
if nb < 2 {
return false;
}
let plan = Plan::new(w, nb);
let init = (lo - 1 - w0, lo + 2 * m - 1 - w0);
let mut k_max = plan.max_k();
if w0 > 0 {
k_max = k_max.min(init.0 / 2);
}
if w1 < n {
k_max = k_max.min((w - init.1 - 2) / 2);
}
let k = k_max.min(FIRST_K).min(2 * rounds.left) & !1;
if k == 0 {
return false;
}
let p = threads.min(nb);
let barrier = Barrier {
state: Mutex::new(BarrierState {
arrived: 0,
generation: 0,
poisoned: false,
tri: Swaps::NONE,
trap: Swaps::NONE,
decision: Decision::Stop,
leader: Leader {
started: false,
finishing: false,
s: 0,
k,
k_max: k_max & !1,
rounds_left: rounds.left,
trap: Swaps::NONE,
init,
w,
open_left: w0 > 0,
open_right: w1 < n,
outcome: Outcome::Aborted,
},
}),
cv: Condvar::new(),
parties: p,
next_block: AtomicUsize::new(0),
};
let base = Shared(arr[w0..w1].as_mut_ptr());
let (barrier, plan) = (&barrier, &plan);
thread::scope(|scope| {
let mut handles = Vec::with_capacity(p - 1);
for _ in 1..p {
let spawned =
thread::Builder::new().spawn_scoped(scope, move || worker(base, w0, plan, barrier));
match spawned {
Ok(handle) => handles.push(handle),
Err(_) => {
barrier.poison();
break;
}
}
}
worker(base, w0, plan, barrier);
let mut panic = None;
for handle in handles {
if let Err(payload) = handle.join() {
panic.get_or_insert(payload);
}
}
if let Some(payload) = panic {
resume_unwind(payload);
}
});
let st = barrier.state.lock().unwrap_or_else(PoisonError::into_inner);
rounds.left = st.leader.rounds_left;
match st.leader.outcome {
Outcome::Aborted => false,
Outcome::Sorted => {
rounds.next = None;
true
}
Outcome::Swapped(s) => {
let shifted = if s.is_none() {
s
} else {
Swaps {
first: s.first + w0,
last: s.last + w0,
}
};
rounds.after(shifted);
true
}
}
}