use super::{Entry, Key};
use core::hash::{BuildHasher, Hash};
use hashbrown::hash_table::Entry as TableEntry;
use hashbrown::{DefaultHashBuilder, HashTable};
pub trait Equivalent<K: ?Sized> {
fn equivalent(&self, key: &K) -> bool;
}
impl<Q: ?Sized + Eq, K: ?Sized> Equivalent<K> for Q
where
K: std::borrow::Borrow<Q>,
{
fn equivalent(&self, key: &K) -> bool {
self == key.borrow()
}
}
fn equivalent_key<'a, Q>(entries: &'a [Entry], k: &'a Q) -> impl 'a + Fn(&Indexes) -> bool
where
Q: ?Sized + Equivalent<Key>,
{
move |indexes| k.equivalent(&entries[indexes.rep].key)
}
fn make_hasher() -> impl Fn(&Indexes) -> u64 {
|indexes| indexes.hash
}
#[derive(Clone, Debug)]
pub struct Indexes {
rep: usize,
other: Vec<usize>,
hash: u64,
}
impl PartialEq for Indexes {
fn eq(&self, other: &Self) -> bool {
self.rep == other.rep && self.other == other.other
}
}
impl Eq for Indexes {}
impl Indexes {
const fn new(rep: usize, hash: u64) -> Self {
Self {
rep,
other: Vec::new(),
hash,
}
}
pub fn len(&self) -> usize {
1 + self.other.len()
}
pub const fn first(&self) -> usize {
self.rep
}
pub fn is_redundant(&self) -> bool {
!self.other.is_empty()
}
pub fn redundant(&self) -> Option<usize> {
self.other.first().copied()
}
pub fn redundants(&self) -> &[usize] {
&self.other
}
fn insert(&mut self, mut index: usize) {
if index != self.rep {
if index < self.rep {
core::mem::swap(&mut index, &mut self.rep);
}
if let Err(i) = self.other.binary_search(&index) {
self.other.insert(i, index)
}
}
}
fn remove(&mut self, index: usize) -> bool {
if self.rep == index {
if self.other.is_empty() {
false
} else {
self.rep = self.other.remove(0);
true
}
} else {
if let Ok(i) = self.other.binary_search(&index) {
self.other.remove(i);
}
true
}
}
pub fn shift_down(&mut self, index: usize) {
if self.rep > index {
self.rep -= 1
}
for i in &mut self.other {
if *i > index {
*i -= 1
}
}
}
pub fn shift_up(&mut self, index: usize) {
if self.rep >= index {
self.rep += 1
}
for i in &mut self.other {
if *i >= index {
*i += 1
}
}
}
pub fn iter(&self) -> super::Indexes<'_> {
super::Indexes::Some {
first: Some(self.rep),
other: self.other.iter(),
}
}
}
impl<'a> IntoIterator for &'a Indexes {
type Item = usize;
type IntoIter = super::Indexes<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
#[derive(Clone)]
pub struct IndexMap<S = DefaultHashBuilder> {
hash_builder: S,
table: HashTable<Indexes>,
}
impl<S: Default> Default for IndexMap<S> {
fn default() -> Self {
Self {
hash_builder: S::default(),
table: HashTable::new(),
}
}
}
impl<S> IndexMap<S> {
pub fn new() -> Self
where
S: Default,
{
Self::default()
}
pub fn with_capacity(capacity: usize) -> Self
where
S: Default,
{
Self {
hash_builder: S::default(),
table: HashTable::with_capacity(capacity),
}
}
pub fn contains_duplicate_keys(&self) -> bool {
self.table.iter().any(Indexes::is_redundant)
}
}
impl<S: BuildHasher> IndexMap<S> {
pub fn get<Q>(&self, entries: &[Entry], key: &Q) -> Option<&Indexes>
where
Q: ?Sized + Hash + Equivalent<Key>,
{
let hash = self.hash_builder.hash_one(key);
self.table.find(hash, equivalent_key(entries, key))
}
pub fn insert(&mut self, entries: &[Entry], index: usize) -> bool {
let key = &entries[index].key;
let hash = self.hash_builder.hash_one(key);
match self
.table
.entry(hash, equivalent_key(entries, key), make_hasher())
{
TableEntry::Occupied(mut occupied) => {
occupied.get_mut().insert(index);
false
}
TableEntry::Vacant(vacant) => {
vacant.insert(Indexes::new(index, hash));
true
}
}
}
pub fn lookup_or_insert<Q>(
&mut self,
entries: &[Entry],
new_index: usize,
key: &Q,
) -> Option<usize>
where
Q: ?Sized + Hash + Equivalent<Key>,
{
let hash = self.hash_builder.hash_one(key);
match self
.table
.entry(hash, equivalent_key(entries, key), make_hasher())
{
TableEntry::Occupied(occupied) => Some(occupied.get().first()),
TableEntry::Vacant(vacant) => {
vacant.insert(Indexes::new(new_index, hash));
None
}
}
}
pub fn remove(&mut self, entries: &[Entry], index: usize) {
let key = &entries[index].key;
let hash = self.hash_builder.hash_one(key);
if let Ok(mut occupied) = self.table.find_entry(hash, equivalent_key(entries, key)) {
if !occupied.get_mut().remove(index) {
occupied.remove();
}
}
}
pub fn shift_down(&mut self, index: usize) {
for indexes in self.table.iter_mut() {
indexes.shift_down(index);
}
}
pub fn shift_up(&mut self, index: usize) {
for indexes in self.table.iter_mut() {
indexes.shift_up(index);
}
}
pub fn rebuild_sorted(&mut self, entries: &[Entry]) {
self.table.clear();
self.table.reserve(entries.len(), make_hasher());
let mut run_start = 0;
while run_start < entries.len() {
let key = &entries[run_start].key;
let mut run_end = run_start + 1;
while run_end < entries.len() && entries[run_end].key == *key {
run_end += 1;
}
let hash = self.hash_builder.hash_one(key);
let mut indexes = Indexes::new(run_start, hash);
indexes.other.reserve_exact(run_end - run_start - 1);
indexes.other.extend(run_start + 1..run_end);
self.table.insert_unique(hash, indexes, make_hasher());
run_start = run_end;
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Value;
#[test]
fn insert() {
let entries = [
Entry::new("a".into(), Value::Null),
Entry::new("b".into(), Value::Null),
Entry::new("a".into(), Value::Null),
];
let mut indexes: IndexMap = IndexMap::default();
indexes.insert(&entries, 2);
indexes.insert(&entries, 1);
indexes.insert(&entries, 0);
let mut a = indexes.get(&entries, "a").unwrap().iter();
let mut b = indexes.get(&entries, "b").unwrap().iter();
assert_eq!(a.next(), Some(0));
assert_eq!(a.next(), Some(2));
assert_eq!(a.next(), None);
assert_eq!(b.next(), Some(1));
assert_eq!(b.next(), None);
assert_eq!(indexes.get(&entries, "c"), None)
}
#[test]
fn remove1() {
let entries = [
Entry::new("a".into(), Value::Null),
Entry::new("b".into(), Value::Null),
Entry::new("a".into(), Value::Null),
];
let mut indexes: IndexMap = IndexMap::default();
indexes.insert(&entries, 2);
indexes.insert(&entries, 1);
indexes.insert(&entries, 0);
indexes.remove(&entries, 1);
indexes.remove(&entries, 0);
let mut a = indexes.get(&entries, "a").unwrap().iter();
assert_eq!(a.next(), Some(2));
assert_eq!(a.next(), None);
assert_eq!(indexes.get(&entries, "b"), None)
}
#[test]
fn remove2() {
let entries = [
Entry::new("a".into(), Value::Null),
Entry::new("b".into(), Value::Null),
Entry::new("a".into(), Value::Null),
];
let mut indexes: IndexMap = IndexMap::default();
indexes.insert(&entries, 2);
indexes.insert(&entries, 1);
indexes.insert(&entries, 0);
indexes.remove(&entries, 0);
indexes.remove(&entries, 1);
indexes.remove(&entries, 2);
assert_eq!(indexes.get(&entries, "a"), None);
assert_eq!(indexes.get(&entries, "b"), None)
}
}