Created
September 3, 2023 22:51
-
-
Save YuriGor/df275e6112bf436ead3c11a99fde8ef6 to your computer and use it in GitHub Desktop.
variable_row_array (in short: use array of slices instead)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// https://users.rust-lang.org/t/memory-friendly-2d-array-with-variable-length-rows/99330 | |
pub struct VariableRowArray<T, const SIZE: usize, const ROWS: usize> { | |
data: [T; SIZE], // The main data array where rows are stored. | |
index: [usize; ROWS], // An index array to track the start of each row in the data array. | |
num_rows: usize, // The current number of rows in the array. | |
} | |
impl<T: Default + std::marker::Copy, const SIZE: usize, const ROWS: usize> | |
VariableRowArray<T, SIZE, ROWS> | |
{ | |
pub fn new() -> Self { | |
let def = T::default(); | |
VariableRowArray { | |
data: [def; SIZE], | |
index: [0; ROWS], | |
num_rows: 0, | |
} | |
} | |
pub const fn new_with_data(rows: &[&[T]]) -> Self { | |
let mut r = 0; | |
let mut def = None; | |
while r < ROWS && r < rows.len() { | |
if rows[r].len() > 0 { | |
def = Some(rows[r][0]); | |
break; | |
} | |
r += 1; | |
} | |
if let Some(def) = def { | |
let mut data = [def; SIZE]; | |
let mut index = [0; ROWS]; | |
let mut num_rows: usize = 0; | |
while num_rows < ROWS && num_rows < rows.len() { | |
let row = rows[num_rows]; | |
let start = if num_rows > 0 { | |
index[num_rows - 1] | |
} else { | |
0 // first row always has 0 start index so we don't track it | |
}; | |
let mut c = 0; | |
while c < row.len() { | |
data[start + c] = row[c]; | |
c += 1; | |
} | |
index[num_rows] = start + row.len(); | |
num_rows += 1; | |
} | |
VariableRowArray { | |
data, | |
index, | |
num_rows, | |
} | |
} else { | |
panic!("At least one not empty row is required"); | |
} | |
} | |
pub fn add_row(&mut self, row: &[T]) { | |
let start = self.num_rows.checked_sub(1).map_or(0, |i| self.index[i]); | |
let end = start + row.len(); | |
self.data[start..end].copy_from_slice(row); | |
self.index[self.num_rows] = end; | |
self.num_rows += 1; | |
} | |
pub fn get_row(&self, row_index: usize) -> Option<&[T]> { | |
if row_index >= self.num_rows { | |
return None; | |
} | |
let start = row_index.checked_sub(1).map_or(0, |i| self.index[i]); | |
let end = self.index[row_index]; | |
Some(&self.data[start..end]) | |
} | |
pub fn get(&self, row_index: usize, col_index: usize) -> Option<T> { | |
if row_index >= self.num_rows { | |
return None; | |
} | |
let start = row_index.checked_sub(1).map_or(0, |i| self.index[i]); | |
let end = self.index[row_index]; | |
if col_index >= end - start { | |
return None; | |
} | |
Some(self.data[start + col_index]) | |
} | |
pub fn num_rows(&self) -> usize { | |
self.num_rows | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment