use std::cell::Cell;
use std::collections::HashMap;
#[allow(dead_code)]
pub struct RcObserver {
events: Vec<RcEvent>,
max_events: usize,
}
#[allow(dead_code)]
impl RcObserver {
pub fn new(max_events: usize) -> Self {
Self {
events: Vec::new(),
max_events,
}
}
pub fn record(&mut self, id: u64, kind: RcEventKind, count_after: u64) {
if self.events.len() >= self.max_events {
self.events.remove(0);
}
self.events.push(RcEvent {
id,
kind,
count_after,
});
}
pub fn events(&self) -> &[RcEvent] {
&self.events
}
pub fn count_kind(&self, kind: &RcEventKind) -> usize {
self.events.iter().filter(|e| &e.kind == kind).count()
}
pub fn drop_count(&self) -> usize {
self.count_kind(&RcEventKind::Drop)
}
pub fn alloc_count(&self) -> usize {
self.count_kind(&RcEventKind::Alloc)
}
pub fn clear(&mut self) {
self.events.clear();
}
}
#[derive(Clone, Debug)]
pub struct RcElisionAnalysis {
pub variable_hints: HashMap<String, RcElisionHint>,
pub elided_ops: u32,
pub remaining_ops: u32,
pub fully_linear: bool,
}
impl RcElisionAnalysis {
pub fn new() -> Self {
RcElisionAnalysis {
variable_hints: HashMap::new(),
elided_ops: 0,
remaining_ops: 0,
fully_linear: true,
}
}
pub fn add_hint(&mut self, var: String, hint: RcElisionHint) {
if hint == RcElisionHint::None {
self.fully_linear = false;
}
self.variable_hints.insert(var, hint);
}
pub fn get_hint(&self, var: &str) -> RcElisionHint {
self.variable_hints
.get(var)
.cloned()
.unwrap_or(RcElisionHint::None)
}
pub fn elision_ratio(&self) -> f64 {
let total = self.elided_ops + self.remaining_ops;
if total == 0 {
return 1.0;
}
self.elided_ops as f64 / total as f64
}
pub fn merge(&mut self, other: &RcElisionAnalysis) {
for (var, hint) in &other.variable_hints {
let existing = self.get_hint(var);
let combined = existing.combine(hint);
self.add_hint(var.clone(), combined);
}
self.elided_ops += other.elided_ops;
self.remaining_ops += other.remaining_ops;
self.fully_linear = self.fully_linear && other.fully_linear;
}
}
#[allow(dead_code)]
pub struct RefcountedMap<K: Eq + std::hash::Hash + Clone, V: Clone> {
map: HashMap<K, (V, u32)>,
}
#[allow(dead_code)]
impl<K: Eq + std::hash::Hash + Clone, V: Clone> RefcountedMap<K, V> {
pub fn new() -> Self {
Self {
map: HashMap::new(),
}
}
pub fn insert(&mut self, key: K, value: V) {
self.map.insert(key, (value, 1));
}
pub fn inc_ref(&mut self, key: &K) {
if let Some((_, rc)) = self.map.get_mut(key) {
*rc = rc.saturating_add(1);
}
}
pub fn dec_ref(&mut self, key: &K) -> bool {
if let Some((_, rc)) = self.map.get_mut(key) {
if *rc > 0 {
*rc -= 1;
if *rc == 0 {
self.map.remove(key);
return true;
}
}
}
false
}
pub fn get(&self, key: &K) -> Option<&V> {
self.map.get(key).map(|(v, _)| v)
}
pub fn refcount(&self, key: &K) -> u32 {
self.map.get(key).map(|(_, rc)| *rc).unwrap_or(0)
}
pub fn len(&self) -> usize {
self.map.len()
}
pub fn is_empty(&self) -> bool {
self.map.is_empty()
}
}
#[allow(dead_code)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum RcEventKind {
Inc,
Dec,
Drop,
Alloc,
}
#[allow(dead_code)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct StickyRc {
pub(super) count: u32,
pub(super) max: u32,
}
#[allow(dead_code)]
impl StickyRc {
pub fn new(initial: u32, max: u32) -> Self {
Self {
count: initial.min(max),
max,
}
}
pub fn inc(&mut self) {
if self.count < self.max {
self.count += 1;
}
}
pub fn dec(&mut self) -> bool {
if self.count > 0 {
self.count -= 1;
}
self.count == 0
}
pub fn is_immortal(&self) -> bool {
self.count >= self.max
}
pub fn count(&self) -> u32 {
self.count
}
pub fn is_zero(&self) -> bool {
self.count == 0
}
}
pub(super) struct RcInner<T> {
pub(super) value: T,
weak_count: Cell<u32>,
}
impl<T> RcInner<T> {
fn new(value: T) -> Self {
RcInner {
value,
weak_count: Cell::new(0),
}
}
}
pub struct RtArc<T> {
pub(super) inner: std::sync::Arc<ArcInner<T>>,
}
impl<T> RtArc<T> {
pub fn new(value: T) -> Self {
RtArc {
inner: std::sync::Arc::new(ArcInner::new(value)),
}
}
pub fn strong_count(&self) -> u32 {
std::sync::Arc::strong_count(&self.inner) as u32
}
pub fn weak_count(&self) -> u32 {
self.inner
.weak_count
.load(std::sync::atomic::Ordering::Acquire)
}
pub fn is_unique(&self) -> bool {
self.strong_count() == 1
}
#[allow(clippy::should_implement_trait)]
pub fn as_ref(&self) -> &T {
&self.inner.value
}
pub fn get_mut(&mut self) -> Option<&mut T> {
if self.weak_count() == 0 {
std::sync::Arc::get_mut(&mut self.inner).map(|r| &mut r.value)
} else {
None
}
}
pub fn try_unwrap(self) -> Result<T, Self> {
if self.weak_count() == 0 {
match std::sync::Arc::try_unwrap(self.inner) {
Ok(inner) => Ok(inner.value),
Err(inner) => Err(RtArc { inner }),
}
} else {
Err(self)
}
}
pub fn clone_arc(&self) -> Self {
RtArc {
inner: std::sync::Arc::clone(&self.inner),
}
}
}
pub(super) struct ArcInner<T> {
pub(super) value: T,
weak_count: std::sync::atomic::AtomicU32,
}
impl<T> ArcInner<T> {
fn new(value: T) -> Self {
ArcInner {
value,
weak_count: std::sync::atomic::AtomicU32::new(0),
}
}
}
#[allow(dead_code)]
pub struct RcBitmask {
pub(super) mask: u64,
}
#[allow(dead_code)]
impl RcBitmask {
pub fn new() -> Self {
Self { mask: 0 }
}
pub fn set_alive(&mut self, i: u32) {
debug_assert!(i < 64);
self.mask |= 1u64 << i;
}
pub fn set_dead(&mut self, i: u32) {
debug_assert!(i < 64);
self.mask &= !(1u64 << i);
}
pub fn is_alive(&self, i: u32) -> bool {
(self.mask >> i) & 1 == 1
}
pub fn alive_count(&self) -> u32 {
self.mask.count_ones()
}
pub fn dead_count(&self) -> u32 {
self.mask.count_zeros()
}
pub fn first_dead(&self) -> Option<u32> {
let inv = !self.mask;
if inv == 0 {
None
} else {
Some(inv.trailing_zeros())
}
}
pub fn first_alive(&self) -> Option<u32> {
if self.mask == 0 {
None
} else {
Some(self.mask.trailing_zeros())
}
}
pub fn raw(&self) -> u64 {
self.mask
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum BorrowState {
Unborrowed,
ImmutableBorrow(u32),
MutableBorrow,
}
#[allow(dead_code)]
#[derive(Clone, Debug)]
pub struct RcGraphNode {
pub id: u32,
pub data: u64,
pub out_edges: Vec<u32>,
}
#[allow(dead_code)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct RcPoolIdx(pub usize);
pub struct CowBox<T> {
pub(super) inner: Rc<T>,
pub(super) copied: Cell<bool>,
}
impl<T: Clone> CowBox<T> {
pub fn new(value: T) -> Self {
CowBox {
inner: Rc::new(value),
copied: Cell::new(false),
}
}
#[allow(clippy::should_implement_trait)]
pub fn as_ref(&self) -> &T {
self.inner.as_ref()
}
#[allow(clippy::should_implement_trait)]
pub fn as_mut(&mut self) -> &mut T {
if !self.inner.is_unique() {
let new_value = self.inner.as_ref().clone();
self.inner = Rc::new(new_value);
self.copied.set(true);
}
self.inner
.get_mut()
.unwrap_or_else(|| unreachable!("COW clone guarantees unique ownership before get_mut"))
}
pub fn was_copied(&self) -> bool {
self.copied.get()
}
pub fn is_unique(&self) -> bool {
self.inner.is_unique()
}
pub fn into_owned(self) -> T {
match self.inner.try_unwrap() {
Ok(v) => v,
Err(rc) => rc.as_ref().clone(),
}
}
}
#[allow(dead_code)]
#[derive(Clone, Debug)]
pub struct OwnershipEvent {
pub object_id: u64,
pub from_owner: String,
pub to_owner: String,
pub timestamp: u64,
}
#[allow(dead_code)]
pub struct OwnershipLog {
events: Vec<OwnershipEvent>,
max_events: usize,
}
#[allow(dead_code)]
impl OwnershipLog {
pub fn new(max_events: usize) -> Self {
Self {
events: Vec::new(),
max_events,
}
}
pub fn record_transfer(&mut self, object_id: u64, from: &str, to: &str, ts: u64) {
if self.events.len() >= self.max_events {
self.events.remove(0);
}
self.events.push(OwnershipEvent {
object_id,
from_owner: from.to_string(),
to_owner: to.to_string(),
timestamp: ts,
});
}
pub fn events_for(&self, object_id: u64) -> Vec<&OwnershipEvent> {
self.events
.iter()
.filter(|e| e.object_id == object_id)
.collect()
}
pub fn len(&self) -> usize {
self.events.len()
}
pub fn is_empty(&self) -> bool {
self.events.is_empty()
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum RcPolicy {
Standard,
Deferred,
AggressiveElision,
Disabled,
}
impl RcPolicy {
pub fn is_deferred(&self) -> bool {
matches!(self, RcPolicy::Deferred)
}
pub fn allows_elision(&self) -> bool {
matches!(self, RcPolicy::AggressiveElision | RcPolicy::Deferred)
}
pub fn is_enabled(&self) -> bool {
!matches!(self, RcPolicy::Disabled)
}
}
#[allow(dead_code)]
#[derive(Clone, Debug, Default)]
pub struct GcNode {
pub refs: Vec<u32>,
pub is_root: bool,
pub marked: bool,
}
#[allow(dead_code)]
#[derive(Clone, Debug)]
pub struct RcEvent {
pub id: u64,
pub kind: RcEventKind,
pub count_after: u64,
}
pub struct ArcWeak<T> {
pub(super) alive: std::sync::atomic::AtomicBool,
value: Option<T>,
}
impl<T: Clone + Send + Sync> ArcWeak<T> {
pub fn from_arc(arc: &RtArc<T>) -> Self {
arc.inner
.weak_count
.fetch_add(1, std::sync::atomic::Ordering::Release);
ArcWeak {
alive: std::sync::atomic::AtomicBool::new(true),
value: Some(arc.inner.value.clone()),
}
}
pub fn upgrade(&self) -> Option<RtArc<T>> {
if self.alive.load(std::sync::atomic::Ordering::Acquire) {
self.value.as_ref().map(|v| RtArc::new(v.clone()))
} else {
None
}
}
pub fn is_alive(&self) -> bool {
self.alive.load(std::sync::atomic::Ordering::Acquire)
}
pub fn invalidate(&self) {
self.alive
.store(false, std::sync::atomic::Ordering::Release);
}
}
pub struct BorrowFlag {
state: Cell<BorrowState>,
}
impl BorrowFlag {
pub fn new() -> Self {
BorrowFlag {
state: Cell::new(BorrowState::Unborrowed),
}
}
pub fn try_borrow(&self) -> bool {
match self.state.get() {
BorrowState::Unborrowed => {
self.state.set(BorrowState::ImmutableBorrow(1));
true
}
BorrowState::ImmutableBorrow(n) => {
self.state.set(BorrowState::ImmutableBorrow(n + 1));
true
}
BorrowState::MutableBorrow => false,
}
}
pub fn release_borrow(&self) {
match self.state.get() {
BorrowState::ImmutableBorrow(1) => {
self.state.set(BorrowState::Unborrowed);
}
BorrowState::ImmutableBorrow(n) if n > 1 => {
self.state.set(BorrowState::ImmutableBorrow(n - 1));
}
_ => {}
}
}
pub fn try_borrow_mut(&self) -> bool {
match self.state.get() {
BorrowState::Unborrowed => {
self.state.set(BorrowState::MutableBorrow);
true
}
_ => false,
}
}
pub fn release_borrow_mut(&self) {
if self.state.get() == BorrowState::MutableBorrow {
self.state.set(BorrowState::Unborrowed);
}
}
pub fn state(&self) -> BorrowState {
self.state.get()
}
pub fn is_borrowed(&self) -> bool {
self.state.get() != BorrowState::Unborrowed
}
pub fn is_mutably_borrowed(&self) -> bool {
self.state.get() == BorrowState::MutableBorrow
}
}
#[allow(dead_code)]
pub struct RcPool<T: Clone> {
slots: Vec<Option<T>>,
refcounts: Vec<u32>,
free: Vec<usize>,
alloc_count: u64,
}
#[allow(dead_code)]
impl<T: Clone> RcPool<T> {
pub fn new() -> Self {
Self {
slots: Vec::new(),
refcounts: Vec::new(),
free: Vec::new(),
alloc_count: 0,
}
}
pub fn insert(&mut self, value: T) -> RcPoolIdx {
self.alloc_count += 1;
if let Some(idx) = self.free.pop() {
self.slots[idx] = Some(value);
self.refcounts[idx] = 1;
RcPoolIdx(idx)
} else {
let idx = self.slots.len();
self.slots.push(Some(value));
self.refcounts.push(1);
RcPoolIdx(idx)
}
}
pub fn inc_ref(&mut self, idx: RcPoolIdx) {
if let Some(rc) = self.refcounts.get_mut(idx.0) {
*rc = rc.saturating_add(1);
}
}
pub fn dec_ref(&mut self, idx: RcPoolIdx) -> bool {
if let Some(rc) = self.refcounts.get_mut(idx.0) {
if *rc == 0 {
return false;
}
*rc -= 1;
if *rc == 0 {
self.slots[idx.0] = None;
self.free.push(idx.0);
return true;
}
}
false
}
pub fn refcount(&self, idx: RcPoolIdx) -> u32 {
self.refcounts.get(idx.0).copied().unwrap_or(0)
}
pub fn get(&self, idx: RcPoolIdx) -> Option<&T> {
self.slots.get(idx.0)?.as_ref()
}
pub fn get_mut(&mut self, idx: RcPoolIdx) -> Option<&mut T> {
if self.refcount(idx) != 1 {
return None;
}
self.slots.get_mut(idx.0)?.as_mut()
}
pub fn cow(&mut self, idx: RcPoolIdx) -> Option<RcPoolIdx> {
let rc = self.refcount(idx);
if rc <= 1 {
return Some(idx);
}
let value = self.get(idx)?.clone();
self.dec_ref(idx);
Some(self.insert(value))
}
pub fn live_count(&self) -> usize {
self.slots.iter().filter(|s| s.is_some()).count()
}
pub fn alloc_count(&self) -> u64 {
self.alloc_count
}
pub fn capacity(&self) -> usize {
self.slots.len()
}
}
pub struct Rc<T> {
pub(super) inner: std::rc::Rc<RcInner<T>>,
}
impl<T> Rc<T> {
pub fn new(value: T) -> Self {
Rc {
inner: std::rc::Rc::new(RcInner::new(value)),
}
}
pub fn strong_count(&self) -> u32 {
std::rc::Rc::strong_count(&self.inner) as u32
}
pub fn weak_count(&self) -> u32 {
self.inner.weak_count.get()
}
pub fn is_unique(&self) -> bool {
self.strong_count() == 1
}
pub fn get_mut(&mut self) -> Option<&mut T> {
if self.weak_count() == 0 {
std::rc::Rc::get_mut(&mut self.inner).map(|r| &mut r.value)
} else {
None
}
}
#[allow(clippy::should_implement_trait)]
pub fn as_ref(&self) -> &T {
&self.inner.value
}
pub fn try_unwrap(self) -> Result<T, Self> {
if self.weak_count() == 0 {
match std::rc::Rc::try_unwrap(self.inner) {
Ok(inner) => Ok(inner.value),
Err(inner) => Err(Rc { inner }),
}
} else {
Err(self)
}
}
pub fn clone_rc(&self) -> Self {
Rc {
inner: std::rc::Rc::clone(&self.inner),
}
}
fn inc_weak(&self) {
let c = self.inner.weak_count.get();
self.inner.weak_count.set(c.saturating_add(1));
}
fn dec_weak(&self) {
let c = self.inner.weak_count.get();
if c > 0 {
self.inner.weak_count.set(c - 1);
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum RcElisionHint {
None,
LinearUse,
Ephemeral,
Borrowed,
UniqueOwner,
SharedImmutable,
TailPosition,
UncapturedArg,
StructField,
DeadPath,
}
impl RcElisionHint {
pub fn can_elide_inc(&self) -> bool {
matches!(
self,
RcElisionHint::LinearUse
| RcElisionHint::Ephemeral
| RcElisionHint::TailPosition
| RcElisionHint::DeadPath
)
}
pub fn can_elide_dec(&self) -> bool {
matches!(
self,
RcElisionHint::LinearUse | RcElisionHint::Ephemeral | RcElisionHint::DeadPath
)
}
pub fn can_mutate_inplace(&self) -> bool {
matches!(self, RcElisionHint::UniqueOwner | RcElisionHint::LinearUse)
}
pub fn combine(&self, other: &RcElisionHint) -> RcElisionHint {
if self == other {
return self.clone();
}
if *self == RcElisionHint::DeadPath {
return other.clone();
}
if *other == RcElisionHint::DeadPath {
return self.clone();
}
RcElisionHint::None
}
}
#[allow(dead_code)]
pub struct GcTracer {
nodes: Vec<GcNode>,
}
#[allow(dead_code)]
impl GcTracer {
pub fn new() -> Self {
Self { nodes: Vec::new() }
}
pub fn add_node(&mut self, is_root: bool) -> u32 {
let id = self.nodes.len() as u32;
self.nodes.push(GcNode {
refs: Vec::new(),
is_root,
marked: false,
});
id
}
pub fn add_ref(&mut self, from: u32, to: u32) {
if let Some(node) = self.nodes.get_mut(from as usize) {
if !node.refs.contains(&to) {
node.refs.push(to);
}
}
}
pub fn mark(&mut self) {
let roots: Vec<u32> = self
.nodes
.iter()
.enumerate()
.filter(|(_, n)| n.is_root)
.map(|(i, _)| i as u32)
.collect();
let mut worklist = roots;
while let Some(id) = worklist.pop() {
if let Some(node) = self.nodes.get_mut(id as usize) {
if node.marked {
continue;
}
node.marked = true;
let refs = node.refs.clone();
for next in refs {
worklist.push(next);
}
}
}
}
pub fn sweep(&self) -> Vec<u32> {
self.nodes
.iter()
.enumerate()
.filter(|(_, n)| !n.marked)
.map(|(i, _)| i as u32)
.collect()
}
pub fn collect(&mut self) -> Vec<u32> {
for node in self.nodes.iter_mut() {
node.marked = false;
}
self.mark();
self.sweep()
}
pub fn node_count(&self) -> usize {
self.nodes.len()
}
pub fn live_count(&self) -> usize {
self.nodes.iter().filter(|n| n.marked).count()
}
}
#[allow(dead_code)]
pub struct AtomicRefCounter {
count: std::sync::atomic::AtomicU64,
}
#[allow(dead_code)]
impl AtomicRefCounter {
pub fn new(initial: u64) -> Self {
Self {
count: std::sync::atomic::AtomicU64::new(initial),
}
}
pub fn inc(&self) -> u64 {
self.count.fetch_add(1, std::sync::atomic::Ordering::SeqCst) + 1
}
pub fn dec(&self) -> u64 {
match self.count.fetch_update(
std::sync::atomic::Ordering::SeqCst,
std::sync::atomic::Ordering::SeqCst,
|v| if v > 0 { Some(v - 1) } else { None },
) {
Ok(prev) => prev - 1,
Err(_) => 0,
}
}
pub fn load(&self) -> u64 {
self.count.load(std::sync::atomic::Ordering::SeqCst)
}
pub fn reset(&self, val: u64) {
self.count.store(val, std::sync::atomic::Ordering::SeqCst);
}
pub fn is_zero(&self) -> bool {
self.load() == 0
}
}
#[allow(dead_code)]
pub struct WeakTable<T: Clone> {
entries: HashMap<u64, std::sync::Weak<T>>,
next_key: u64,
miss_count: u64,
}
#[allow(dead_code)]
impl<T: Clone> WeakTable<T> {
pub fn new() -> Self {
Self {
entries: HashMap::new(),
next_key: 0,
miss_count: 0,
}
}
pub fn register(&mut self, value: std::sync::Arc<T>) -> u64 {
let key = self.next_key;
self.next_key += 1;
self.entries.insert(key, std::sync::Arc::downgrade(&value));
key
}
pub fn get(&mut self, key: u64) -> Option<std::sync::Arc<T>> {
if let Some(weak) = self.entries.get(&key) {
if let Some(strong) = weak.upgrade() {
return Some(strong);
} else {
self.entries.remove(&key);
self.miss_count += 1;
}
}
None
}
pub fn prune(&mut self) -> usize {
let before = self.entries.len();
self.entries.retain(|_, weak| weak.upgrade().is_some());
before - self.entries.len()
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn miss_count(&self) -> u64 {
self.miss_count
}
}
#[allow(dead_code)]
pub struct RcGraph {
nodes: HashMap<u32, (RcGraphNode, u32)>,
next_id: u32,
edge_count: usize,
}
#[allow(dead_code)]
impl RcGraph {
pub fn new() -> Self {
Self {
nodes: HashMap::new(),
next_id: 0,
edge_count: 0,
}
}
pub fn add_node(&mut self, data: u64) -> u32 {
let id = self.next_id;
self.next_id += 1;
self.nodes.insert(
id,
(
RcGraphNode {
id,
data,
out_edges: Vec::new(),
},
1,
),
);
id
}
pub fn add_edge(&mut self, src: u32, dst: u32) {
if let Some((node, _)) = self.nodes.get_mut(&src) {
if !node.out_edges.contains(&dst) {
node.out_edges.push(dst);
self.edge_count += 1;
}
}
if let Some((_, rc)) = self.nodes.get_mut(&dst) {
*rc = rc.saturating_add(1);
}
}
pub fn remove_edge(&mut self, src: u32, dst: u32) -> bool {
let removed = if let Some((node, _)) = self.nodes.get_mut(&src) {
let before = node.out_edges.len();
node.out_edges.retain(|&e| e != dst);
node.out_edges.len() < before
} else {
false
};
if removed {
self.edge_count = self.edge_count.saturating_sub(1);
if let Some((_, rc)) = self.nodes.get_mut(&dst) {
*rc = rc.saturating_sub(1);
}
}
removed
}
pub fn node_data(&self, id: u32) -> Option<u64> {
self.nodes.get(&id).map(|(n, _)| n.data)
}
pub fn refcount(&self, id: u32) -> u32 {
self.nodes.get(&id).map(|(_, rc)| *rc).unwrap_or(0)
}
pub fn out_edges(&self, id: u32) -> Vec<u32> {
self.nodes
.get(&id)
.map(|(n, _)| n.out_edges.clone())
.unwrap_or_default()
}
pub fn remove_node(&mut self, id: u32) {
if let Some((node, _)) = self.nodes.remove(&id) {
for dst in node.out_edges {
if let Some((_, rc)) = self.nodes.get_mut(&dst) {
*rc = rc.saturating_sub(1);
}
self.edge_count = self.edge_count.saturating_sub(1);
}
}
}
pub fn node_count(&self) -> usize {
self.nodes.len()
}
pub fn edge_count(&self) -> usize {
self.edge_count
}
pub fn zero_refcount_nodes(&self) -> Vec<u32> {
self.nodes
.iter()
.filter(|(_, (_, rc))| *rc == 0)
.map(|(id, _)| *id)
.collect()
}
}
#[derive(Clone, Debug, Default)]
pub struct RcStats {
pub increments: u64,
pub decrements: u64,
pub deallocations: u64,
pub elided_increments: u64,
pub elided_decrements: u64,
pub inplace_mutations: u64,
pub copy_on_write: u64,
pub peak_rc: u32,
}
impl RcStats {
pub fn new() -> Self {
Self::default()
}
pub fn record_inc(&mut self) {
self.increments += 1;
}
pub fn record_dec(&mut self) {
self.decrements += 1;
}
pub fn record_dealloc(&mut self) {
self.deallocations += 1;
}
pub fn record_elided_inc(&mut self) {
self.elided_increments += 1;
}
pub fn record_elided_dec(&mut self) {
self.elided_decrements += 1;
}
pub fn record_inplace_mutation(&mut self) {
self.inplace_mutations += 1;
}
pub fn record_cow(&mut self) {
self.copy_on_write += 1;
}
pub fn update_peak(&mut self, rc: u32) {
if rc > self.peak_rc {
self.peak_rc = rc;
}
}
pub fn total_ops(&self) -> u64 {
self.increments + self.decrements
}
pub fn total_elided(&self) -> u64 {
self.elided_increments + self.elided_decrements
}
pub fn elision_ratio(&self) -> f64 {
let total = self.total_ops() + self.total_elided();
if total == 0 {
return 1.0;
}
self.total_elided() as f64 / total as f64
}
pub fn merge(&mut self, other: &RcStats) {
self.increments += other.increments;
self.decrements += other.decrements;
self.deallocations += other.deallocations;
self.elided_increments += other.elided_increments;
self.elided_decrements += other.elided_decrements;
self.inplace_mutations += other.inplace_mutations;
self.copy_on_write += other.copy_on_write;
if other.peak_rc > self.peak_rc {
self.peak_rc = other.peak_rc;
}
}
pub fn reset(&mut self) {
*self = Self::default();
}
}
#[allow(dead_code)]
pub struct RetainRelease<T> {
pub(super) value: T,
retain_count: u64,
release_count: u64,
}
#[allow(dead_code)]
impl<T> RetainRelease<T> {
pub fn new(value: T) -> Self {
Self {
value,
retain_count: 1,
release_count: 0,
}
}
pub fn retain(&mut self) {
self.retain_count += 1;
}
pub fn release(&mut self) -> bool {
self.release_count += 1;
self.retain_count <= self.release_count
}
pub fn live_count(&self) -> u64 {
self.retain_count.saturating_sub(self.release_count)
}
pub fn get(&self) -> &T {
&self.value
}
pub fn get_mut(&mut self) -> &mut T {
&mut self.value
}
pub fn retain_count(&self) -> u64 {
self.retain_count
}
pub fn release_count(&self) -> u64 {
self.release_count
}
}
pub struct RcManager {
analysis: RcElisionAnalysis,
stats: RcStats,
enabled: bool,
max_rc_threshold: u32,
pending_decrements: Vec<String>,
}
impl RcManager {
pub fn new() -> Self {
RcManager {
analysis: RcElisionAnalysis::new(),
stats: RcStats::new(),
enabled: true,
max_rc_threshold: 1_000_000,
pending_decrements: Vec::new(),
}
}
pub fn with_analysis(analysis: RcElisionAnalysis) -> Self {
RcManager {
analysis,
stats: RcStats::new(),
enabled: true,
max_rc_threshold: 1_000_000,
pending_decrements: Vec::new(),
}
}
pub fn inc(&mut self, var: &str) {
if !self.enabled {
return;
}
let hint = self.analysis.get_hint(var);
if hint.can_elide_inc() {
self.stats.record_elided_inc();
} else {
self.stats.record_inc();
}
}
pub fn dec(&mut self, var: &str) {
if !self.enabled {
return;
}
let hint = self.analysis.get_hint(var);
if hint.can_elide_dec() {
self.stats.record_elided_dec();
} else {
self.stats.record_dec();
}
}
pub fn schedule_dec(&mut self, var: String) {
self.pending_decrements.push(var);
}
pub fn flush_pending(&mut self) {
let pending = std::mem::take(&mut self.pending_decrements);
for var in &pending {
self.dec(var);
}
}
pub fn can_mutate_inplace(&self, var: &str) -> bool {
self.analysis.get_hint(var).can_mutate_inplace()
}
pub fn record_inplace_mutation(&mut self) {
self.stats.record_inplace_mutation();
}
pub fn record_cow(&mut self) {
self.stats.record_cow();
}
pub fn stats(&self) -> &RcStats {
&self.stats
}
pub fn analysis(&self) -> &RcElisionAnalysis {
&self.analysis
}
pub fn set_enabled(&mut self, enabled: bool) {
self.enabled = enabled;
}
pub fn set_max_rc_threshold(&mut self, threshold: u32) {
self.max_rc_threshold = threshold;
}
pub fn max_rc_threshold(&self) -> u32 {
self.max_rc_threshold
}
pub fn reset_stats(&mut self) {
self.stats.reset();
}
}
pub struct Weak<T> {
_marker: std::marker::PhantomData<T>,
pub(super) alive: Cell<bool>,
value: Option<T>,
}
impl<T: Clone> Weak<T> {
pub fn from_rc(rc: &Rc<T>) -> Self {
rc.inc_weak();
Weak {
_marker: std::marker::PhantomData,
alive: Cell::new(true),
value: Some(rc.inner.value.clone()),
}
}
pub fn upgrade(&self) -> Option<Rc<T>> {
if self.alive.get() {
self.value.as_ref().map(|v| Rc::new(v.clone()))
} else {
None
}
}
pub fn is_alive(&self) -> bool {
self.alive.get()
}
pub fn invalidate(&self) {
self.alive.set(false);
}
}