Path: blob/main/crates/polars-utils/src/idx_map/total_idx_map.rs
6940 views
use hashbrown::hash_table::{1Entry as TEntry, HashTable, OccupiedEntry as TOccupiedEntry, VacantEntry as TVacantEntry,2};34use crate::IdxSize;5use crate::aliases::PlRandomState;6use crate::total_ord::{BuildHasherTotalExt, TotalEq, TotalHash};78/// An IndexMap where the keys are hashed and compared with TotalOrd/TotalEq.9pub struct TotalIndexMap<K, V> {10table: HashTable<IdxSize>,11tuples: Vec<(K, V)>,12random_state: PlRandomState,13}1415impl<K, V> Default for TotalIndexMap<K, V> {16fn default() -> Self {17Self {18table: HashTable::new(),19tuples: Vec::new(),20random_state: PlRandomState::default(),21}22}23}2425impl<K: TotalHash + TotalEq, V> TotalIndexMap<K, V> {26pub fn reserve(&mut self, additional: usize) {27self.table.reserve(additional, |i| unsafe {28let tuple = self.tuples.get_unchecked(*i as usize);29self.random_state.tot_hash_one(&tuple.0)30});31self.tuples.reserve(additional);32}3334pub fn len(&self) -> IdxSize {35self.tuples.len() as IdxSize36}3738pub fn is_empty(&self) -> bool {39self.tuples.is_empty()40}4142pub fn get(&self, key: &K) -> Option<&V> {43let hash = self.random_state.tot_hash_one(key);44let idx = self.table.find(hash, |i| unsafe {45let t = self.tuples.get_unchecked(*i as usize);46hash == self.random_state.tot_hash_one(&t.0) && key.tot_eq(&t.0)47})?;48unsafe { Some(&self.tuples.get_unchecked(*idx as usize).1) }49}5051pub fn entry(&mut self, key: K) -> Entry<'_, K, V> {52let hash = self.random_state.tot_hash_one(&key);53let entry = self.table.entry(54hash,55|i| unsafe {56let t = self.tuples.get_unchecked(*i as usize);57hash == self.random_state.tot_hash_one(&t.0) && key.tot_eq(&t.0)58},59|i| unsafe {60let t = self.tuples.get_unchecked(*i as usize);61self.random_state.tot_hash_one(&t.0)62},63);6465match entry {66TEntry::Occupied(o) => Entry::Occupied(OccupiedEntry {67entry: o,68tuples: &mut self.tuples,69}),70TEntry::Vacant(v) => Entry::Vacant(VacantEntry {71key,72entry: v,73tuples: &mut self.tuples,74}),75}76}7778/// Insert a key which will never be mapped to. Returns the index of the entry.79///80/// This is useful for entries which are handled externally.81pub fn push_unmapped_entry(&mut self, key: K, value: V) -> IdxSize {82let ret = self.tuples.len() as IdxSize;83self.tuples.push((key, value));84ret85}8687/// Gets the key and value at the given index by insertion order.88#[inline(always)]89pub fn get_index(&self, idx: IdxSize) -> Option<(&K, &V)> {90let t = self.tuples.get(idx as usize)?;91Some((&t.0, &t.1))92}9394/// Gets the key and value at the given index by insertion order.95///96/// # Safety97/// The index must be less than len().98#[inline(always)]99pub unsafe fn get_index_unchecked(&self, idx: IdxSize) -> (&K, &V) {100let t = unsafe { self.tuples.get_unchecked(idx as usize) };101(&t.0, &t.1)102}103104/// Iterates over the keys in insertion order.105pub fn iter_keys(&self) -> impl Iterator<Item = &K> {106self.tuples.iter().map(|t| &t.0)107}108109/// Iterates over the values in insertion order.110pub fn iter_values(&self) -> impl Iterator<Item = &V> {111self.tuples.iter().map(|t| &t.1)112}113}114115pub enum Entry<'a, K, V> {116Occupied(OccupiedEntry<'a, K, V>),117Vacant(VacantEntry<'a, K, V>),118}119120pub struct OccupiedEntry<'a, K, V> {121entry: TOccupiedEntry<'a, IdxSize>,122tuples: &'a mut Vec<(K, V)>,123}124125impl<'a, K, V> OccupiedEntry<'a, K, V> {126pub fn index(&self) -> IdxSize {127*self.entry.get()128}129130pub fn into_mut(self) -> &'a mut V {131let idx = self.index();132unsafe { &mut self.tuples.get_unchecked_mut(idx as usize).1 }133}134}135136pub struct VacantEntry<'a, K, V> {137key: K,138entry: TVacantEntry<'a, IdxSize>,139tuples: &'a mut Vec<(K, V)>,140}141142impl<'a, K, V> VacantEntry<'a, K, V> {143pub fn index(&self) -> IdxSize {144self.tuples.len() as IdxSize145}146147pub fn insert(self, value: V) -> &'a mut V {148unsafe {149let tuple_idx: IdxSize = self.tuples.len().try_into().unwrap();150self.tuples.push((self.key, value));151self.entry.insert(tuple_idx);152&mut self.tuples.last_mut().unwrap_unchecked().1153}154}155}156157158