use std::collections::HashMap;
pub struct UniqueIdLookup<T> {
buf: Vec<Option<T>>,
offset: usize,
}
pub struct UniqueIdLookupIterator<'a, T> {
lookup: &'a UniqueIdLookup<T>,
index: usize,
}
pub struct UniqueIdLookupIteratorOccupied<'a, T> {
lookup: &'a UniqueIdLookup<T>,
index: usize,
}
pub struct UniqueIdLookupIteratorValues<'a, T> {
lookup: &'a UniqueIdLookup<T>,
index: usize,
}
pub struct UniqueIdLookupIteratorVacantIDs<'a, T> {
lookup: &'a UniqueIdLookup<T>,
index: usize,
}
impl<T> UniqueIdLookup<T> {
const RESULT_NONE: Option<T> = None;
pub const fn new() -> Self {
UniqueIdLookup {
buf: Vec::new(),
offset: 0,
}
}
#[deprecated(since = "0.2.4", note = "Will be removed in v0.3. Use `with_capacity_and_offset()` instead.")]
pub fn with_capacity(capacity: usize) -> Self {
UniqueIdLookup::with_capacity_and_offset(capacity, 0)
}
pub fn with_capacity_and_offset(capacity: usize, offset: usize) -> Self {
UniqueIdLookup {
buf: Vec::with_capacity(capacity),
offset,
}
}
pub fn with_min_max_id<I: Into<usize> + Copy>(min_id: I, max_id: I) -> Self {
let capacity = 1 + max_id.into() - min_id.into();
UniqueIdLookup::with_capacity_and_offset(capacity, min_id.into())
}
#[deprecated(since = "0.2.10", note = "Will be removed in v0.3. Use `from()` instead.")]
pub fn from_hash_map<I: Into<usize> + Ord + Copy>(map: HashMap<I, T>) -> Self {
Self::from(map)
}
pub fn insert(&mut self, id: usize, value: T) -> &mut T {
if !self.buf.is_empty() {
if id < self.offset {
let nbr_prepend_elements = self.offset - id;
for _i in 0..(nbr_prepend_elements - 1) {
self.buf.insert(0, None);
}
self.buf.insert(0, Some(value));
self.offset = id;
return self.buf[0].as_mut().unwrap();
} else {
let index = id - self.offset;
if index < self.buf.len() {
self.buf[index] = Some(value);
} else {
self.buf.resize_with(index + 1, || None);
self.buf[index] = Some(value);
}
return self.buf[index].as_mut().unwrap();
}
} else {
if self.capacity() == 0 || id < self.offset {
self.offset = id;
self.buf.push(Some(value));
return self.buf[0].as_mut().unwrap();
} else {
let index = id - self.offset;
self.buf.resize_with(index + 1, || None);
self.buf[index] = Some(value);
return self.buf[index].as_mut().unwrap();
}
}
}
pub fn insert_if_absent(&mut self, id: usize, value: T) -> &mut T {
if self.contains_id(id) {
return self.get_mut(id).unwrap();
}
return self.insert(id, value);
}
#[inline]
pub fn contains_id(&self, id: usize) -> bool {
if id < self.offset {
return false;
}
let index = id - self.offset;
if index >= self.buf.len() {
return false;
}
let value = &self.buf[index];
value.is_some()
}
#[inline]
pub fn get(&self, id: usize) -> &Option<T> {
let index = id - self.offset;
&self.buf[index]
}
#[inline]
pub fn get_or_none(&self, id: usize) -> &Option<T> {
if id < self.offset {
return &UniqueIdLookup::RESULT_NONE;
}
let index = id - self.offset;
if index >= self.buf.len() {
return &UniqueIdLookup::RESULT_NONE;
}
&self.buf[index]
}
#[inline]
pub fn get_mut(&mut self, id: usize) -> Option<&mut T> {
let index = id - self.offset;
self.buf.get_mut(index)?.as_mut()
}
#[inline]
pub fn remove(&mut self, id: usize) -> Option<T> {
let index = id - self.offset;
let mut removed_value: Option<T> = None;
std::mem::swap(&mut self.buf[index], &mut removed_value);
removed_value
}
#[deprecated(since = "0.2.4", note = "Will be removed in v0.3. Use `iter_occupied()` instead.")]
pub fn iter(&self) -> UniqueIdLookupIterator<T> {
UniqueIdLookupIterator {
lookup: self,
index: 0,
}
}
pub fn iter_occupied(&self) -> UniqueIdLookupIteratorOccupied<T> {
UniqueIdLookupIteratorOccupied {
lookup: self,
index: 0,
}
}
pub fn values(&self) -> UniqueIdLookupIteratorValues<T> {
UniqueIdLookupIteratorValues {
lookup: self,
index: 0,
}
}
pub fn iter_vacant_ids(&self) -> UniqueIdLookupIteratorVacantIDs<T> {
UniqueIdLookupIteratorVacantIDs {
lookup: self,
index: 0,
}
}
#[inline]
pub const fn get_offset(&self) -> usize {
self.offset
}
#[inline]
pub fn capacity(&self) -> usize {
self.buf.capacity()
}
#[inline]
pub fn range_len(&self) -> usize {
self.buf.len()
}
#[deprecated(since = "0.2.4", note = "Will be removed in v0.3. Use `len_occupied()` instead (just a name change).")]
pub fn len(&self) -> usize {
self.len_occupied()
}
pub fn len_occupied(&self) -> usize {
self.buf.iter().filter(|payload| payload.is_some()).count()
}
pub fn occupation_density(&self) -> f64 {
if self.buf.is_empty() {
return f64::NAN;
}
self.len_occupied() as f64 / self.buf.len() as f64
}
pub fn is_occupied_empty(&self) -> bool {
for e in self.buf.iter() {
if e.is_some() {
return false;
}
}
true
}
#[deprecated(since = "0.2.4", note = "Will be removed in v0.3. Use `is_occupied_empty()` instead (just a name change).")]
pub fn is_empty(&self) -> bool {
self.is_occupied_empty()
}
pub fn into_occupied_vec(self) -> Vec<T> {
let nbr_occupied = self.len_occupied();
let mut result = Vec::with_capacity(nbr_occupied);
for item in self.buf.into_iter().flatten() {
result.push(item);
}
result
}
pub fn shrink_to_fit_and_trim_vacant(&mut self) {
if let Some(index_r) = self.buf.iter().rposition(Option::is_some) {
self.buf.truncate(index_r + 1);
let mut new_offset = self.offset;
while !self.buf.is_empty() && self.buf[0].is_none() {
self.buf.remove(0);
new_offset += 1;
}
self.offset = new_offset;
} else {
self.buf.clear();
self.offset = 0;
}
self.buf.shrink_to_fit()
}
}
impl<T, I> From<HashMap<I, T>> for UniqueIdLookup<T>
where
I: Into<usize> + Ord + Copy,
{
fn from(hash_map: HashMap<I, T>) -> Self {
if hash_map.is_empty() {
return Self::new();
}
let (min_id, max_id) = hash_map.keys()
.map(|&k| k.into())
.fold((usize::MAX, 0), |(min, max), id| {
(min.min(id), max.max(id))
});
let mut lookup = Self::with_min_max_id(min_id, max_id);
for (id, value) in hash_map {
lookup.insert(id.into(), value);
}
lookup
}
}
impl<T> Default for UniqueIdLookup<T> {
fn default() -> Self {
Self::new()
}
}
impl<'a, T> Iterator for UniqueIdLookupIterator<'a, T> {
type Item = (usize, &'a Option<T>);
fn next(&mut self) -> Option<Self::Item> {
while self.index < self.lookup.buf.len() {
let payload = &self.lookup.buf[self.index];
if payload.is_none() {
self.index += 1;
continue;
}
let id = self.index + self.lookup.offset;
let result = Some((id, payload));
self.index += 1;
return result;
}
None
}
}
impl<'a, T> Iterator for UniqueIdLookupIteratorValues<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
while self.index < self.lookup.buf.len() {
let payload = &self.lookup.buf[self.index];
if payload.is_none() {
self.index += 1;
continue;
}
let result = Some(payload.as_ref().unwrap());
self.index += 1;
return result;
}
None
}
}
impl<'a, T> Iterator for UniqueIdLookupIteratorOccupied<'a, T> {
type Item = (usize, &'a T);
fn next(&mut self) -> Option<Self::Item> {
while self.index < self.lookup.buf.len() {
let payload = &self.lookup.buf[self.index];
if payload.is_none() {
self.index += 1;
continue;
}
let id = self.index + self.lookup.offset;
let result = Some((id, payload.as_ref().unwrap()));
self.index += 1;
return result;
}
None
}
}
impl<'a, T> Iterator for UniqueIdLookupIteratorVacantIDs<'a, T> {
type Item = usize;
fn next(&mut self) -> Option<Self::Item> {
while self.index < self.lookup.buf.len() {
let payload = &self.lookup.buf[self.index];
if payload.is_some() {
self.index += 1;
continue;
}
let id = self.index + self.lookup.offset;
let result = Some(id);
self.index += 1;
return result;
}
None
}
}
impl<I, T, const N: usize> From<[(I, T); N]> for UniqueIdLookup<T>
where
I: Into<usize> + Ord + Copy,
{
fn from(arr: [(I, T); N]) -> Self {
if arr.is_empty() {
return UniqueIdLookup::new();
}
let mut min_id = usize::MAX;
let mut max_id = 0usize;
for &(id, _) in &arr {
let id_usize = id.into();
min_id = min_id.min(id_usize);
max_id = max_id.max(id_usize);
}
let mut lookup = UniqueIdLookup::with_min_max_id(min_id, max_id);
for (id, v) in arr.into_iter() {
lookup.insert(id.into(), v);
}
lookup
}
}