171 lines
4.4 KiB
Rust
171 lines
4.4 KiB
Rust
pub(crate) mod weak_vec {
|
|
#![allow(dead_code)]
|
|
//! Module containing the [`WeakVec`] API.
|
|
|
|
use std::{sync::Weak, vec::Vec};
|
|
|
|
/// An optimized container for `Weak` references of `T` that minimizes reallocations by
|
|
/// dropping older elements that no longer have strong references to them.
|
|
#[derive(Debug)]
|
|
pub(crate) struct WeakVec<T> {
|
|
inner: Vec<Weak<T>>,
|
|
}
|
|
|
|
impl<T> Default for WeakVec<T> {
|
|
fn default() -> Self {
|
|
Self {
|
|
inner: Default::default(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<T> WeakVec<T> {
|
|
pub(crate) fn new() -> Self {
|
|
Self { inner: Vec::new() }
|
|
}
|
|
|
|
/// Pushes a new element to this collection.
|
|
///
|
|
/// If the inner Vec needs to be reallocated, we will first drop older elements that
|
|
/// no longer have strong references to them.
|
|
pub(crate) fn push(&mut self, value: Weak<T>) {
|
|
if self.inner.len() == self.inner.capacity() {
|
|
// Iterating backwards has the advantage that we don't do more work than we have to.
|
|
for i in (0..self.inner.len()).rev() {
|
|
if self.inner[i].strong_count() == 0 {
|
|
self.inner.swap_remove(i);
|
|
}
|
|
}
|
|
|
|
// Make sure our capacity is twice the number of live elements.
|
|
// Leaving some spare capacity ensures that we won't re-scan immediately.
|
|
self.inner.reserve_exact(self.inner.len());
|
|
}
|
|
|
|
self.inner.push(value);
|
|
}
|
|
}
|
|
|
|
pub(crate) struct WeakVecIter<T> {
|
|
inner: std::vec::IntoIter<Weak<T>>,
|
|
}
|
|
|
|
impl<T> Iterator for WeakVecIter<T> {
|
|
type Item = Weak<T>;
|
|
fn next(&mut self) -> Option<Self::Item> {
|
|
self.inner.next()
|
|
}
|
|
}
|
|
|
|
impl<T> IntoIterator for WeakVec<T> {
|
|
type Item = Weak<T>;
|
|
type IntoIter = WeakVecIter<T>;
|
|
fn into_iter(self) -> Self::IntoIter {
|
|
WeakVecIter {
|
|
inner: self.inner.into_iter(),
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pub(crate) use weak_vec::WeakVec;
|
|
|
|
pub fn eq_f32(lhs: f32, rhs: f32) -> bool {
|
|
use core::num::FpCategory::*;
|
|
match (lhs.classify(), rhs.classify()) {
|
|
(Zero, Zero) | (Nan, Nan) => true,
|
|
(Infinite, Infinite) => lhs.signum() == rhs.signum(),
|
|
_ => lhs == rhs,
|
|
}
|
|
}
|
|
|
|
pub fn ord_f32(lhs: f32, rhs: f32) -> core::cmp::Ordering {
|
|
use core::cmp::Ordering;
|
|
use core::num::FpCategory::*;
|
|
match (lhs.classify(), rhs.classify()) {
|
|
(Zero, Zero) | (Nan, Nan) => Ordering::Equal,
|
|
(Infinite, Infinite) => {
|
|
core::cmp::PartialOrd::partial_cmp(&lhs.signum(), &rhs.signum()).unwrap()
|
|
}
|
|
_ => core::cmp::PartialOrd::partial_cmp(&lhs, &rhs).unwrap(),
|
|
}
|
|
}
|
|
|
|
pub fn hash_f32<H: std::hash::Hasher>(state: &mut H, f: f32) {
|
|
use std::hash::Hash;
|
|
let classify = f.classify();
|
|
match classify {
|
|
std::num::FpCategory::Nan => (classify as u8).hash(state),
|
|
std::num::FpCategory::Infinite | std::num::FpCategory::Zero => {
|
|
(classify as u8, f.signum() as i8).hash(state)
|
|
}
|
|
std::num::FpCategory::Subnormal | std::num::FpCategory::Normal => f.to_bits().hash(state),
|
|
}
|
|
}
|
|
|
|
#[repr(transparent)]
|
|
#[derive(Debug, Clone, Copy)]
|
|
pub struct F32(f32);
|
|
|
|
impl F32 {
|
|
#[inline]
|
|
pub fn from_bits(bits: u32) -> Self {
|
|
Self(f32::from_bits(bits))
|
|
}
|
|
#[inline]
|
|
pub fn into_bits(self) -> u32 {
|
|
self.0.to_bits()
|
|
}
|
|
}
|
|
|
|
impl From<f32> for F32 {
|
|
fn from(value: f32) -> Self {
|
|
Self(value)
|
|
}
|
|
}
|
|
impl From<F32> for f32 {
|
|
fn from(value: F32) -> Self {
|
|
value.0
|
|
}
|
|
}
|
|
|
|
impl std::ops::Deref for F32 {
|
|
type Target = f32;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
&self.0
|
|
}
|
|
}
|
|
|
|
impl std::ops::DerefMut for F32 {
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
&mut self.0
|
|
}
|
|
}
|
|
|
|
impl PartialEq for F32 {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
eq_f32(self.0, other.0)
|
|
}
|
|
}
|
|
|
|
impl Eq for F32 {}
|
|
|
|
impl PartialOrd for F32 {
|
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
|
Some(ord_f32(self.0, other.0))
|
|
}
|
|
}
|
|
|
|
impl Ord for F32 {
|
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
|
ord_f32(self.0, other.0)
|
|
}
|
|
}
|
|
|
|
impl core::hash::Hash for F32 {
|
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
|
hash_f32(state, self.0)
|
|
}
|
|
}
|