Skip to content

Commit 339ec63

Browse files
committed
Add: IndexedSplit for Rust
1 parent 115f74f commit 339ec63

File tree

1 file changed

+40
-0
lines changed

1 file changed

+40
-0
lines changed

rust/lib.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2002,6 +2002,46 @@ where
20022002
});
20032003
}
20042004

2005+
/// Splits a range of tasks into fair-sized chunks for parallel distribution.
2006+
///
2007+
/// The first `(tasks % threads)` chunks have size `ceil(tasks / threads)`.
2008+
/// The remaining chunks have size `floor(tasks / threads)`.
2009+
///
2010+
/// This ensures optimal load balancing across threads with minimal size variance.
2011+
/// See: https://lemire.me/blog/2025/05/22/dividing-an-array-into-fair-sized-chunks/
2012+
#[derive(Debug, Clone)]
2013+
pub struct IndexedSplit {
2014+
quotient: usize,
2015+
remainder: usize,
2016+
}
2017+
2018+
impl IndexedSplit {
2019+
/// Creates a new indexed split for distributing tasks across threads.
2020+
///
2021+
/// # Arguments
2022+
///
2023+
/// * `tasks_count` - Total number of tasks to distribute
2024+
/// * `threads_count` - Number of threads to distribute across (must be > 0)
2025+
///
2026+
/// # Panics
2027+
///
2028+
/// Panics if `threads_count` is zero.
2029+
pub fn new(tasks_count: usize, threads_count: usize) -> Self {
2030+
assert!(threads_count > 0, "Threads count must be greater than zero");
2031+
Self {
2032+
quotient: tasks_count / threads_count,
2033+
remainder: tasks_count % threads_count,
2034+
}
2035+
}
2036+
2037+
/// Returns the range for a specific thread index.
2038+
pub fn get(&self, thread_index: usize) -> core::ops::Range<usize> {
2039+
let begin = self.quotient * thread_index + thread_index.min(self.remainder);
2040+
let count = self.quotient + if thread_index < self.remainder { 1 } else { 0 };
2041+
begin..(begin + count)
2042+
}
2043+
}
2044+
20052045
#[cfg(test)]
20062046
#[cfg(feature = "std")]
20072047
mod tests {

0 commit comments

Comments
 (0)