use std::iter::FusedIterator;
use crate::{
column::{borrowed::HashTableColumnBorrowed, owned::HashTableColumnOwned},
row::borrowed::HashTableRowBorrowed,
*,
};
impl<K, V> IntoIterator for HashTable<K, V>
where
K: Clone,
K: Hash + Eq,
{
type Item = HashMap<K, V>;
type IntoIter = HashTableIntoIter<K, V>;
fn into_iter(self) -> Self::IntoIter {
HashTableIntoIter { inner: self }
}
}
#[derive(Debug)]
pub struct HashTableIntoIter<K, V> {
inner: HashTable<K, V>,
}
impl<K, V> Iterator for HashTableIntoIter<K, V>
where
K: Clone,
K: Hash + Eq,
{
type Item = HashMap<K, V>;
fn next(&mut self) -> Option<Self::Item> {
if self.inner.rows_len() == 0 {
None
} else {
self.inner
.remove_row_hashmap(0)
.map(|row| row.into_iter().map(|(k, v)| (k.clone(), v)).collect())
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.inner.rows_len();
(len, Some(len))
}
}
impl<K, V> HashTable<K, V> {
#[inline]
pub fn iter(&self) -> HashTableBorrowedIter<'_, K, V> {
HashTableBorrowedIter {
row: 0,
table: self,
}
}
pub fn into_iter_columns(self) -> HashTableOwnedIntoIterColumn<K, V> {
HashTableOwnedIntoIterColumn {
row_len: self.columns_len(),
indices_iter: self.indices_table.into_iter(),
values: self.values_vector.into_iter().map(Option::Some).collect(),
}
}
#[inline]
pub fn iter_columns(&self) -> HashTableBorrowedIterColumn<'_, K, V> {
HashTableBorrowedIterColumn {
row_len: self.columns_len(),
indices_iter: self.indices_table.iter(),
values: &self.values_vector,
}
}
}
impl<'t, K, V> IntoIterator for &'t HashTable<K, V> {
type Item = HashTableRowBorrowed<'t, K, V>;
type IntoIter = HashTableBorrowedIter<'t, K, V>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
#[derive(Debug)]
pub struct HashTableBorrowedIter<'t, K, V> {
row: usize,
table: &'t HashTable<K, V>,
}
impl<'t, K, V> Iterator for HashTableBorrowedIter<'t, K, V> {
type Item = HashTableRowBorrowed<'t, K, V>;
fn next(&mut self) -> Option<Self::Item> {
let val = self.table.get_row(self.row)?;
self.row += 1;
Some(val)
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.table.rows_len();
let remainder = len - self.row;
(remainder, Some(remainder))
}
}
impl<'t, K, V> Clone for HashTableBorrowedIter<'t, K, V> {
fn clone(&self) -> Self {
*self
}
}
impl<'t, K, V> Copy for HashTableBorrowedIter<'t, K, V> {}
impl<'t, K, V> FusedIterator for HashTableBorrowedIter<'t, K, V> {}
impl<'t, K, V> ExactSizeIterator for HashTableBorrowedIter<'t, K, V> {
#[inline]
fn len(&self) -> usize {
self.table.rows_len() - self.row
}
}
#[derive(Debug)]
pub struct HashTableOwnedIntoIterColumn<K, V> {
indices_iter: <HashMap<K, usize> as IntoIterator>::IntoIter,
values: Vec<Option<V>>,
row_len: usize,
}
impl<K, V> Iterator for HashTableOwnedIntoIterColumn<K, V> {
type Item = HashTableColumnOwned<K, V>;
fn next(&mut self) -> Option<Self::Item> {
let (key, idx) = self.indices_iter.next()?;
let values = self
.values
.chunks_exact_mut(self.row_len)
.map(|chunk| {
chunk[idx]
.take()
.expect("Each column is accessed only once")
})
.collect();
Some(HashTableColumnOwned { key, values })
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.indices_iter.size_hint()
}
}
impl<K, V> FusedIterator for HashTableOwnedIntoIterColumn<K, V> {}
impl<K, V> ExactSizeIterator for HashTableOwnedIntoIterColumn<K, V> {
fn len(&self) -> usize {
self.indices_iter.len()
}
}
#[derive(Debug)]
pub struct HashTableBorrowedIterColumn<'t, K, V> {
indices_iter: <&'t HashMap<K, usize> as IntoIterator>::IntoIter,
values: &'t [V],
row_len: usize,
}
impl<'t, K, V> Clone for HashTableBorrowedIterColumn<'t, K, V> {
fn clone(&self) -> Self {
Self {
indices_iter: self.indices_iter.clone(),
values: self.values,
row_len: self.row_len,
}
}
}
impl<'t, K, V> Iterator for HashTableBorrowedIterColumn<'t, K, V> {
type Item = HashTableColumnBorrowed<'t, 't, K, V>;
fn next(&mut self) -> Option<Self::Item> {
let (key, idx) = self.indices_iter.next()?;
let values = self
.values
.chunks_exact(self.row_len)
.map(|chunk| &chunk[*idx])
.collect();
Some(HashTableColumnBorrowed {
column: key,
values,
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.indices_iter.size_hint()
}
}
impl<'t, K, V> FusedIterator for HashTableBorrowedIterColumn<'t, K, V> {}
impl<'t, K, V> ExactSizeIterator for HashTableBorrowedIterColumn<'t, K, V> {
fn len(&self) -> usize {
self.indices_iter.len()
}
}