Skip to main content

tree_table/types/
index.rs

1use alloc::{
2    rc::Rc,
3    string::{String, ToString},
4    vec::Vec,
5};
6use hashbrown::HashMap;
7
8use crate::types::CyclingCounter;
9use crate::utils::utils_fns::{n_to_base62, pull_n, push_n, push_n_add};
10use crate::{CellProps, IndexCell, MaxMap, TableCell, str_err};
11
12#[derive(Debug, Clone)]
13pub struct Index {
14    pub iid_to_row: HashMap<Rc<str>, usize>,
15    pub cells: Vec<IndexCell>,
16    pub iid_ctr: CyclingCounter,
17    pub empty_par: Rc<str>,
18}
19
20impl Index {
21    pub(crate) fn new() -> Self {
22        Index {
23            iid_to_row: HashMap::new(),
24            cells: Vec::new(),
25            iid_ctr: CyclingCounter::new(),
26            empty_par: Rc::from("".to_string()),
27        }
28    }
29
30    /// Clears all mappings and cells from the index and resets the iid counter.
31    pub(crate) fn reset(&mut self) {
32        self.iid_to_row.clear();
33        self.cells.clear();
34        self.iid_ctr = CyclingCounter::new();
35    }
36
37    /// Clone index cell properties at row.
38    pub(crate) fn clone_props(&self, row: &usize) -> Option<CellProps> {
39        self.cells.get(*row).and_then(|cell| cell.props.clone())
40    }
41
42    /// Clone table cell properties at row and col.
43    pub(crate) fn clone_table_props(&self, row: &usize, col: &usize) -> Option<CellProps> {
44        self.cells.get(*row).and_then(|icell| {
45            icell
46                .vals
47                .get(col)
48                .and_then(|table_cell| table_cell.props.clone())
49        })
50    }
51
52    /// Use a Vec of tuples of usize, Indexcell.
53    /// Pushes the existing indices of the Index forward.
54    pub(crate) fn add_rows_just_push_hm(&mut self, sorted_seq: &[usize]) {
55        // Adjust existing HashMap indices
56        for (_, row) in self.iid_to_row.iter_mut() {
57            *row = push_n(*row, &sorted_seq);
58        }
59    }
60
61    /// Use a Vec of usize.
62    /// Pulls the existing indices of the Index backwards.
63    pub(crate) fn del_rows_just_pull_hm(&mut self, sorted_seq: &[usize]) {
64        // Adjust existing HashMap indices
65        for (_, row) in self.iid_to_row.iter_mut() {
66            *row = pull_n(*row, sorted_seq);
67        }
68    }
69
70    /// Add a single row, assumes iid_to_row has been adjusted before insertion.
71    #[inline(always)]
72    pub(crate) fn add_row(&mut self, pos: usize, iid: Rc<str>, cell: IndexCell) {
73        self.iid_to_row.insert(iid, pos);
74        self.cells.insert(pos, cell);
75    }
76
77    /// Add a single row, assumes iid_to_row has been adjusted before insertion.
78    #[inline(always)]
79    pub(crate) fn push_row(&mut self, pos: usize, iid: Rc<str>, cell: IndexCell) {
80        self.iid_to_row.insert(iid, pos);
81        self.cells.push(cell);
82    }
83
84    /// Insert multiple items, add rows
85    pub(crate) fn add_rows(&mut self, to_add: Vec<(usize, IndexCell)>) {
86        // Adjust existing HashMap indices
87        for (_, row) in self.iid_to_row.iter_mut() {
88            *row = push_n_add(*row, &to_add);
89        }
90        // Add items
91        for (pos, cell) in to_add.into_iter() {
92            self.iid_to_row.insert(cell.iid.clone(), pos);
93            self.cells.insert(pos, cell);
94        }
95    }
96
97    /// Remove and return multiple items, delete rows
98    pub(crate) fn del_rows(
99        &mut self,
100        sorted_seq: &[usize],
101    ) -> Result<Vec<(usize, IndexCell)>, String> {
102        let largest_pos = *sorted_seq
103            .last()
104            .ok_or_else(|| str_err!("To delete is empty."))?;
105        if largest_pos >= self.cells.len() {
106            return Err(str_err!(
107                "Deletion pos: {} out of bounds of index len: {}",
108                largest_pos,
109                self.cells.len()
110            ));
111        }
112        let mut removed = Vec::with_capacity(sorted_seq.len());
113        for (i, &pos) in sorted_seq.iter().enumerate() {
114            let cell = self.cells.remove(pos - i);
115            self.iid_to_row.remove(&cell.iid);
116            removed.push((pos, cell));
117        }
118        // Adjust indices post removal
119        for (_, pos) in self.iid_to_row.iter_mut() {
120            *pos = pull_n(*pos, sorted_seq);
121        }
122        Ok(removed)
123    }
124
125    pub(crate) fn move_rows(&mut self, full_new_to_old: &[usize]) -> Result<(), String> {
126        let n = self.cells.len();
127        if n == 0 {
128            return Ok(());
129        }
130        if full_new_to_old.len() != n {
131            return Err(str_err!(
132                "move_rows: length mismatch (got {}, expected {})",
133                full_new_to_old.len(),
134                n
135            ));
136        }
137
138        #[cfg(any(debug_assertions, feature = "safety"))]
139        {
140            use alloc::vec;
141
142            let mut seen = vec![false; n];
143            for &old_idx in full_new_to_old {
144                if old_idx >= n || seen[old_idx] {
145                    return Err(str_err!("Mapping error: invalid old index {}", old_idx));
146                }
147                seen[old_idx] = true;
148            }
149        }
150
151        let mut old_cells = core::mem::take(&mut self.cells)
152            .into_iter()
153            .map(Some)
154            .collect::<Vec<_>>();
155
156        self.cells = Vec::with_capacity(n);
157
158        for (new_idx, &old_idx) in full_new_to_old.iter().enumerate() {
159            let cell = old_cells
160                .get_mut(old_idx)
161                .and_then(Option::take)
162                .ok_or_else(|| str_err!("Mapping error: invalid or duplicate index {}", old_idx))?;
163
164            if let Some(row) = self.iid_to_row.get_mut(&cell.iid) {
165                *row = new_idx; // new row index
166            }
167            self.cells.push(cell);
168        }
169
170        Ok(())
171    }
172
173    // Insert multiple columns.
174    pub(crate) fn add_cols(
175        &mut self,
176        to_add: Option<Vec<(usize, Vec<(usize, TableCell)>)>>,
177        sorted_seq: &[usize],
178    ) {
179        // Adjust existing HashMap indices
180        for icell in self.cells.iter_mut() {
181            let index_row_vals = &mut icell.vals;
182            index_row_vals.hm = index_row_vals
183                .hm
184                .drain()
185                .map(|(k, v)| (push_n(k, sorted_seq), v))
186                .collect();
187            index_row_vals.maxk = index_row_vals.maxk.map(|max| push_n(max, sorted_seq));
188        }
189
190        // Add the new columns if provided
191        if let Some(to_add) = to_add {
192            for (colk, rows) in to_add {
193                for (rowk, val) in rows {
194                    if let Some(row) = self.cells.get_mut(rowk) {
195                        let index_row_vals: &mut MaxMap<TableCell> = &mut row.vals;
196                        index_row_vals.insert(colk, val);
197                    }
198                }
199            }
200        }
201    }
202
203    pub(crate) fn del_cols(
204        &mut self,
205        sorted_seq: &[usize],
206    ) -> Vec<(usize, Vec<(usize, TableCell)>)> {
207        let mut removed: Vec<(usize, Vec<(usize, TableCell)>)> = Vec::new();
208
209        // Process each row
210        for (rowk, icell) in self.cells.iter_mut().enumerate() {
211            let mut row_removed: Vec<(usize, TableCell)> = Vec::new();
212            let mut redo_maxk = false;
213            let row = &mut icell.vals;
214
215            // Remove specified columns and collect them
216            for &colk in sorted_seq {
217                if let Some(val) = row.hm.remove(&colk) {
218                    row_removed.push((colk, val));
219                    if row.maxk == Some(colk) {
220                        redo_maxk = true;
221                    }
222                }
223            }
224
225            // If we removed anything from this row, store it
226            if !row_removed.is_empty() {
227                removed.push((rowk, row_removed));
228            }
229
230            row.hm = row
231                .hm
232                .drain()
233                .map(|(k, v)| (pull_n(k, sorted_seq), v))
234                .collect();
235
236            if redo_maxk {
237                let mut new_maxk = None;
238                for k in (0..row.maxk.unwrap_or(0)).rev() {
239                    if row.hm.contains_key(&k) {
240                        new_maxk = Some(k);
241                        break;
242                    }
243                }
244                row.maxk = new_maxk;
245            } else {
246                row.maxk = row.maxk.map(|k| pull_n(k, sorted_seq));
247            }
248        }
249
250        removed
251    }
252
253    pub(crate) fn move_cols(&mut self, full_old_to_new: &[usize]) {
254        for icell in self.cells.iter_mut() {
255            let max_map = &mut icell.vals;
256            if max_map.is_empty() {
257                continue;
258            }
259            let mut new_hm: HashMap<usize, TableCell> = HashMap::new();
260            let mut max: usize = 0;
261            for (old_pos, new_pos) in full_old_to_new.iter().enumerate() {
262                if let Some(cell) = max_map.hm.remove(&old_pos) {
263                    new_hm.insert(*new_pos, cell);
264                    if *new_pos > max {
265                        max = *new_pos;
266                    }
267                }
268            }
269            max_map.hm = new_hm;
270            max_map.maxk = Some(max);
271        }
272    }
273
274    #[inline]
275    pub(crate) fn new_iid(&mut self) -> Result<String, String> {
276        let mut iid = n_to_base62(
277            self.iid_ctr
278                .next()
279                .ok_or_else(|| str_err!("Cycling counter should never end"))?,
280        );
281        if self.iid_to_row.contains_key(iid.as_str()) {
282            let mut cycles: usize = 0;
283            while self.iid_to_row.contains_key(iid.as_str()) {
284                if cycles == usize::MAX {
285                    return Err(str_err!("Row limit reached."));
286                }
287                iid = n_to_base62(
288                    self.iid_ctr
289                        .next()
290                        .ok_or_else(|| str_err!("Cycling counter should never end"))?,
291                );
292                cycles = cycles.saturating_add(1);
293            }
294        }
295        Ok(iid)
296    }
297}