1use std::cell::{Cell, UnsafeCell};
18use std::cmp::Ordering;
19use std::hash::{Hash, Hasher};
20use std::iter::FusedIterator;
21use std::marker::PhantomData;
22use std::mem::ManuallyDrop;
23use std::ops::Range;
24use std::sync::Arc;
25use std::sync::atomic::AtomicU64;
26use std::sync::atomic::Ordering::{Acquire, Relaxed};
27
28use crossbeam_utils::CachePadded;
29use derive_where::derive_where;
30use fixedbitset::FixedBitSet;
31use parking_lot::{Condvar, Mutex, MutexGuard};
32use rustc_hash::FxHasher;
33
34use oxidd_core::error::{DuplicateVarName, OutOfMemory};
35use oxidd_core::function::EdgeOfFunc;
36use oxidd_core::util::{AbortOnDrop, AllocResult, Borrowed, DropWith, VarNameMap};
37use oxidd_core::{DiagramRules, InnerNode, LevelNo, ManagerEventSubscriber, Tag, VarNo};
38
39use crate::node::NodeBase;
40use crate::terminal_manager::TerminalManager;
41use crate::util::{Invariant, TryLock, VarLevelMap, rwlock::RwLock};
42
43#[cfg(not(feature = "hugealloc"))]
44mod huge {
45 pub type Box<T> = std::boxed::Box<T>;
46 pub type Vec<T> = std::vec::Vec<T>;
47
48 pub type RawTable<T> = linear_hashtbl::raw::RawTable<T, u32>;
49 pub type RawTableIntoIter<T> = linear_hashtbl::raw::IntoIter<T, u32>;
50}
51#[cfg(feature = "hugealloc")]
52mod huge {
53 use hugealloc::HugeAlloc;
54 pub type Box<T> = allocator_api2::boxed::Box<T, HugeAlloc>;
55 pub type Vec<T> = allocator_api2::vec::Vec<T, HugeAlloc>;
56
57 pub type RawTable<T> = linear_hashtbl::raw::RawTable<T, u32, HugeAlloc>;
58 pub type RawTableIntoIter<T> = linear_hashtbl::raw::IntoIter<T, u32, HugeAlloc>;
59}
60
61pub trait InnerNodeCons<ET: Tag> {
65 type T<'id>: NodeBase + InnerNode<Edge<'id, Self::T<'id>, ET>> + Send + Sync;
66}
67
68pub trait TerminalManagerCons<NC: InnerNodeCons<ET>, ET: Tag, const TERMINALS: usize>:
70 Sized
71{
72 type TerminalNode: Send + Sync;
73 type T<'id>: Send
74 + Sync
75 + TerminalManager<'id, NC::T<'id>, ET, TERMINALS, TerminalNode = Self::TerminalNode>;
76}
77
78pub trait DiagramRulesCons<
80 NC: InnerNodeCons<ET>,
81 ET: Tag,
82 TMC: TerminalManagerCons<NC, ET, TERMINALS>,
83 MDC: ManagerDataCons<NC, ET, TMC, Self, TERMINALS>,
84 const TERMINALS: usize,
85>: Sized
86{
87 type T<'id>: Send
88 + Sync
89 + DiagramRules<
90 Edge<'id, NC::T<'id>, ET>,
91 NC::T<'id>,
92 <TMC::T<'id> as TerminalManager<'id, NC::T<'id>, ET, TERMINALS>>::TerminalNode,
93 >;
94}
95
96pub trait ManagerDataCons<
98 NC: InnerNodeCons<ET>,
99 ET: Tag,
100 TMC: TerminalManagerCons<NC, ET, TERMINALS>,
101 RC: DiagramRulesCons<NC, ET, TMC, Self, TERMINALS>,
102 const TERMINALS: usize,
103>: Sized
104{
105 type T<'id>: Send
106 + Sync
107 + DropWith<Edge<'id, NC::T<'id>, ET>>
108 + ManagerEventSubscriber<
109 Manager<'id, NC::T<'id>, ET, TMC::T<'id>, RC::T<'id>, Self::T<'id>, TERMINALS>,
110 >;
111}
112
113#[derive(Clone, Copy, PartialEq, Eq, Debug)]
117enum GCSignal {
118 RunGc,
119 Quit,
120}
121
122pub struct Store<'id, N, ET, TM, R, MD, const TERMINALS: usize>
123where
124 N: NodeBase + InnerNode<Edge<'id, N, ET>>,
125 ET: Tag,
126 TM: TerminalManager<'id, N, ET, TERMINALS>,
127 MD: DropWith<Edge<'id, N, ET>>,
128{
129 inner_nodes: huge::Box<SlotSlice<'id, N, TERMINALS>>,
130 manager: RwLock<Manager<'id, N, ET, TM, R, MD, TERMINALS>>,
131 terminal_manager: TM,
132 state: CachePadded<Mutex<SharedStoreState>>,
133 gc_signal: (Mutex<GCSignal>, Condvar),
134 workers: crate::workers::Workers,
135}
136
137unsafe impl<'id, N, ET, TM, R, MD, const TERMINALS: usize> Sync
138 for Store<'id, N, ET, TM, R, MD, TERMINALS>
139where
140 N: NodeBase + InnerNode<Edge<'id, N, ET>> + Send + Sync,
141 ET: Tag + Send + Sync,
142 TM: TerminalManager<'id, N, ET, TERMINALS> + Send + Sync,
143 MD: DropWith<Edge<'id, N, ET>> + Send + Sync,
144{
145}
146
147const CHUNK_SIZE: u32 = 64 * 1024;
149
150#[derive(Clone, Copy, PartialEq, Eq, Debug)]
152enum GCState {
153 Disabled,
155 Init,
157 Triggered,
163}
164
165struct SharedStoreState {
166 next_free: Vec<u32>,
175
176 allocated: u32,
182
183 node_count: i64,
193
194 gc_state: GCState,
196 gc_lwm: u32,
198 gc_hwm: u32,
200}
201
202#[repr(align(64))] struct LocalStoreState {
204 next_free: Cell<u32>,
210
211 initialized: Cell<u32>,
220
221 current_store: Cell<usize>,
226
227 node_count_delta: Cell<i32>,
233}
234
235thread_local! {
236 static LOCAL_STORE_STATE: LocalStoreState = const {
237 LocalStoreState {
238 next_free: Cell::new(0),
239 initialized: Cell::new(0),
240 current_store: Cell::new(0),
241 node_count_delta: Cell::new(0),
242 }
243 };
244}
245
246struct LocalStoreStateGuard<'a, 'id, N, ET, TM, R, MD, const TERMINALS: usize>(
247 &'a Store<'id, N, ET, TM, R, MD, TERMINALS>,
248)
249where
250 N: NodeBase + InnerNode<Edge<'id, N, ET>>,
251 ET: Tag,
252 TM: TerminalManager<'id, N, ET, TERMINALS>,
253 MD: DropWith<Edge<'id, N, ET>>;
254
255union Slot<N> {
258 node: ManuallyDrop<N>,
259 next_free: u32,
262 #[allow(unused)]
263 uninit: (),
264}
265
266#[repr(transparent)]
267struct SlotSlice<'id, N, const TERMINALS: usize> {
268 phantom: PhantomData<Invariant<'id>>,
269 slots: [UnsafeCell<Slot<N>>],
270}
271
272#[repr(transparent)]
276#[must_use]
277#[derive_where(PartialEq, Eq, PartialOrd, Ord, Hash)]
278pub struct Edge<'id, N, ET>(
279 u32,
281 #[derive_where(skip)] PhantomData<(Invariant<'id>, N, ET)>,
282);
283
284#[repr(C)]
285pub struct Manager<'id, N, ET, TM, R, MD, const TERMINALS: usize>
286where
287 N: NodeBase + InnerNode<Edge<'id, N, ET>>,
288 ET: Tag,
289 TM: TerminalManager<'id, N, ET, TERMINALS>,
290 MD: DropWith<Edge<'id, N, ET>>,
291{
292 unique_table: Vec<Mutex<LevelViewSet<'id, N, ET, TM, R, MD, TERMINALS>>>,
293 var_level_map: VarLevelMap,
294 var_name_map: VarNameMap,
295 data: ManuallyDrop<MD>,
296 store: *const Store<'id, N, ET, TM, R, MD, TERMINALS>,
301 gc_count: AtomicU64,
302 reorder_count: u64,
303 gc_ongoing: TryLock,
304 reorder_gc_prepared: bool,
305}
306
307type M<'id, NC, ET, TMC, RC, MDC, const TERMINALS: usize> = Manager<
309 'id,
310 <NC as InnerNodeCons<ET>>::T<'id>,
311 ET,
312 <TMC as TerminalManagerCons<NC, ET, TERMINALS>>::T<'id>,
313 <RC as DiagramRulesCons<NC, ET, TMC, MDC, TERMINALS>>::T<'id>,
314 <MDC as ManagerDataCons<NC, ET, TMC, RC, TERMINALS>>::T<'id>,
315 TERMINALS,
316>;
317
318unsafe impl<
319 'id,
320 N: NodeBase + InnerNode<Edge<'id, N, ET>> + Send + Sync,
321 ET: Tag + Send + Sync,
322 TM: TerminalManager<'id, N, ET, TERMINALS> + Send + Sync,
323 R,
324 MD: DropWith<Edge<'id, N, ET>> + Send + Sync,
325 const TERMINALS: usize,
326> Send for Manager<'id, N, ET, TM, R, MD, TERMINALS>
327{
328}
329unsafe impl<
330 'id,
331 N: NodeBase + InnerNode<Edge<'id, N, ET>> + Send + Sync,
332 ET: Tag + Send + Sync,
333 TM: TerminalManager<'id, N, ET, TERMINALS> + Send + Sync,
334 R,
335 MD: DropWith<Edge<'id, N, ET>> + Send + Sync,
336 const TERMINALS: usize,
337> Sync for Manager<'id, N, ET, TM, R, MD, TERMINALS>
338{
339}
340
341impl<N: NodeBase, ET: Tag> Edge<'_, N, ET> {
344 const TAG_BITS: u32 = {
345 let bits = usize::BITS - ET::MAX_VALUE.leading_zeros();
346 assert!(bits <= 16, "Maximum value of edge tag is too large");
347 bits
348 };
349 const TAG_SHIFT: u32 = (u32::BITS - Self::TAG_BITS) % 32;
351
352 const TAG_MASK: u32 = ((1 << Self::TAG_BITS) - 1) << Self::TAG_SHIFT;
354
355 #[inline(always)]
357 unsafe fn node_id_unchecked(&self) -> u32 {
358 debug_assert_eq!(self.0 & Self::TAG_MASK, 0);
359 self.0
360 }
361
362 #[inline(always)]
364 fn node_id(&self) -> usize {
365 (self.0 & !Self::TAG_MASK) as usize
366 }
367
368 #[inline(always)]
370 fn is_tagged(&self) -> bool {
371 self.0 & Self::TAG_MASK != 0
372 }
373
374 #[inline(always)]
376 pub fn raw(&self) -> u32 {
377 self.0
378 }
379
380 #[inline(always)]
387 pub unsafe fn from_terminal_id(id: u32) -> Self {
388 Self(id, PhantomData)
389 }
390}
391
392impl<N: NodeBase, ET: Tag> oxidd_core::Edge for Edge<'_, N, ET> {
393 type Tag = ET;
394
395 #[inline]
396 fn borrowed(&self) -> Borrowed<'_, Self> {
397 Borrowed::new(Self(self.0, PhantomData))
398 }
399
400 #[inline]
401 fn with_tag(&self, tag: Self::Tag) -> Borrowed<'_, Self> {
402 Borrowed::new(Self(
403 (self.0 & !Self::TAG_MASK) | ((tag.as_usize() as u32) << Self::TAG_SHIFT),
404 PhantomData,
405 ))
406 }
407
408 #[inline]
409 fn with_tag_owned(mut self, tag: Self::Tag) -> Self {
410 self.0 = (self.0 & !Self::TAG_MASK) | ((tag.as_usize() as u32) << Self::TAG_SHIFT);
411 self
412 }
413
414 #[inline]
415 fn tag(&self) -> Self::Tag {
416 ET::from_usize(((self.0 & Self::TAG_MASK) >> Self::TAG_SHIFT) as usize)
417 }
418
419 #[inline]
420 fn node_id(&self) -> oxidd_core::NodeID {
421 (self.0 & !Self::TAG_MASK) as oxidd_core::NodeID
422 }
423}
424
425impl<N, ET> Drop for Edge<'_, N, ET> {
426 #[inline(never)]
427 #[cold]
428 fn drop(&mut self) {
429 eprintln!(
430 "`Edge`s must not be dropped. Use `Manager::drop_edge()`. Backtrace:\n{}",
431 std::backtrace::Backtrace::capture()
432 );
433
434 #[cfg(feature = "static_leak_check")]
435 {
436 extern "C" {
437 #[link_name = "\n\n`Edge`s must not be dropped. Use `Manager::drop_edge()`.\n"]
438 fn trigger() -> !;
439 }
440 unsafe { trigger() }
441 }
442 }
443}
444
445impl<'id, N: NodeBase, const TERMINALS: usize> SlotSlice<'id, N, TERMINALS> {
448 fn new_boxed(capacity: u32) -> huge::Box<Self> {
450 #[cfg(not(feature = "hugealloc"))]
451 let mut vec: huge::Vec<UnsafeCell<Slot<N>>> = huge::Vec::with_capacity(capacity as usize);
452 #[cfg(feature = "hugealloc")]
453 let mut vec: huge::Vec<UnsafeCell<Slot<N>>> =
454 huge::Vec::with_capacity_in(capacity as usize, hugealloc::HugeAlloc);
455
456 #[allow(clippy::uninit_vec)]
462 unsafe {
463 vec.set_len(capacity as usize)
464 };
465
466 let boxed = vec.into_boxed_slice();
467 unsafe { std::mem::transmute(boxed) }
470 }
471
472 #[inline]
474 unsafe fn slot_pointer_unchecked<ET: Tag>(&self, edge: &Edge<'id, N, ET>) -> *mut Slot<N> {
475 let id = unsafe { edge.node_id_unchecked() } as usize;
477 debug_assert!(id >= TERMINALS, "`edge` must reference an inner node");
478 debug_assert!(id - TERMINALS < self.slots.len());
479 unsafe { self.slots.get_unchecked(id - TERMINALS).get() }
482 }
483
484 #[inline]
486 fn inner_node<ET: Tag>(&self, edge: &Edge<'id, N, ET>) -> &N {
487 let id = edge.node_id();
488 assert!(id >= TERMINALS, "`edge` must reference an inner node");
489 debug_assert!(id - TERMINALS < self.slots.len());
490 unsafe { &(*self.slots.get_unchecked(id - TERMINALS).get()).node }
495 }
496
497 #[inline(always)]
499 unsafe fn inner_node_unchecked<ET: Tag>(&self, edge: &Edge<'id, N, ET>) -> &N {
500 unsafe { &(*self.slot_pointer_unchecked(edge)).node }
503 }
504
505 #[inline(always)]
507 unsafe fn clone_edge_unchecked<ET: Tag>(&self, edge: &Edge<'id, N, ET>) -> Edge<'id, N, ET> {
508 unsafe { self.inner_node_unchecked(edge) }.retain();
509 Edge(edge.0, PhantomData)
510 }
511}
512
513#[inline(always)]
517fn addr<T>(ptr: *const T) -> usize {
518 ptr.addr()
519}
520
521impl<'id, N, ET, TM, R, MD, const TERMINALS: usize> Store<'id, N, ET, TM, R, MD, TERMINALS>
522where
523 N: NodeBase + InnerNode<Edge<'id, N, ET>>,
524 ET: Tag,
525 TM: TerminalManager<'id, N, ET, TERMINALS>,
526 MD: DropWith<Edge<'id, N, ET>>,
527{
528 const CHECK_TERMINALS: () = {
529 assert!(TERMINALS >= 1, "TERMINALS must be >= 1");
530 assert!(
531 TERMINALS <= u32::MAX as usize,
532 "TERMINALS must fit into an u32"
533 );
534 };
535
536 #[inline]
537 fn prepare_local_state(
538 &self,
539 ) -> Option<LocalStoreStateGuard<'_, 'id, N, ET, TM, R, MD, TERMINALS>> {
540 LOCAL_STORE_STATE.with(|state| {
541 if state.current_store.get() == 0 {
542 state.next_free.set(0);
543 state.initialized.set(0);
544 state.current_store.set(addr(self));
545 debug_assert_eq!(state.node_count_delta.get(), 0);
546 Some(LocalStoreStateGuard(self))
547 } else {
548 None
549 }
550 })
551 }
552
553 #[inline]
557 fn add_node(&self, node: N) -> AllocResult<[Edge<'id, N, ET>; 2]> {
558 debug_assert_eq!(node.load_rc(Relaxed), 2);
559 let res = LOCAL_STORE_STATE.with(|state| {
560 let node_count_delta = if state.current_store.get() == addr(self) {
561 let delta = state.node_count_delta.get() + 1;
562 let id = state.next_free.get();
563 if id != 0 {
564 let (next_free, slot) = unsafe { self.use_free_slot(id) };
566 state.next_free.set(next_free);
567 state.node_count_delta.set(delta);
568 return Ok((id, slot));
569 }
570
571 let index = state.initialized.get();
572 if index % CHUNK_SIZE != 0 {
573 let slots = &self.inner_nodes.slots;
574 debug_assert!((index as usize) < slots.len());
575 let slot = unsafe { &mut *slots.get_unchecked(index as usize).get() };
580 state.initialized.set(index + 1);
581 state.node_count_delta.set(delta);
582 return Ok((index + TERMINALS as u32, slot));
583 }
584
585 state.node_count_delta.set(0);
586 delta
587 } else {
588 1
589 };
590
591 self.get_slot_from_shared(state, node_count_delta)
592 });
593 match res {
594 Ok((id, slot)) => {
595 slot.node = ManuallyDrop::new(node);
596 Ok([Edge(id, PhantomData), Edge(id, PhantomData)])
597 }
598 Err(OutOfMemory) => {
599 node.drop_with(|e| self.drop_edge(e));
600 Err(OutOfMemory)
601 }
602 }
603 }
604
605 #[inline(always)]
610 #[allow(clippy::mut_from_ref)]
611 unsafe fn use_free_slot(&self, id: u32) -> (u32, &mut Slot<N>) {
612 debug_assert!(id as usize >= TERMINALS);
613 let index = id as usize - TERMINALS;
614 debug_assert!(index < self.inner_nodes.slots.len());
615 let slot = unsafe { &mut *self.inner_nodes.slots.get_unchecked(index).get() };
618 let next_free = unsafe { slot.next_free };
620 (next_free, slot)
621 }
622
623 #[cold]
630 #[allow(clippy::mut_from_ref)]
631 fn get_slot_from_shared(
632 &self,
633 local: &LocalStoreState,
634 delta: i32,
635 ) -> AllocResult<(u32, &mut Slot<N>)> {
636 let mut shared = self.state.lock();
637
638 shared.node_count += delta as i64;
639 if shared.gc_state == GCState::Init && shared.node_count >= shared.gc_hwm as i64 {
640 shared.gc_state = GCState::Triggered;
641 self.gc_signal.1.notify_one();
642 }
643
644 if local.current_store.get() == addr(self) {
645 debug_assert_eq!(local.next_free.get(), 0);
646 debug_assert_eq!(local.initialized.get() % CHUNK_SIZE, 0);
647
648 if let Some(id) = shared.next_free.pop() {
649 let (next_free, slot) = unsafe { self.use_free_slot(id) };
651 local.next_free.set(next_free);
652 return Ok((id, slot));
653 }
654
655 let index = shared.allocated;
656 let slots = &self.inner_nodes.slots;
657 if (index as usize + CHUNK_SIZE as usize) < slots.len() {
658 shared.allocated = (index / CHUNK_SIZE + 1) * CHUNK_SIZE;
659 local.initialized.set(index + 1);
660 } else if (index as usize) < slots.len() {
661 shared.allocated += 1;
662 } else {
663 return Err(OutOfMemory);
664 }
665 let slot = unsafe { &mut *slots.get_unchecked(index as usize).get() };
667 Ok((index + TERMINALS as u32, slot))
668 } else {
669 if let Some(id) = shared.next_free.pop() {
670 let (next_free, slot) = unsafe { self.use_free_slot(id) };
672 if next_free != 0 {
673 shared.next_free.push(next_free);
674 }
675 return Ok((id, slot));
676 }
677
678 let index = shared.allocated;
679 let slots = &self.inner_nodes.slots;
680 if (index as usize) >= slots.len() {
681 return Err(OutOfMemory);
682 }
683 shared.allocated += 1;
684 let slot = unsafe { &mut *slots.get_unchecked(index as usize).get() };
686 Ok((index + TERMINALS as u32, slot))
687 }
688 }
689
690 unsafe fn drop_unique_table_edge(&self, edge: Edge<'id, N, ET>) {
701 let slot_ptr = unsafe { self.inner_nodes.slot_pointer_unchecked(&edge) };
703 let id = unsafe { edge.node_id_unchecked() };
704 std::mem::forget(edge);
705
706 if unsafe { (*slot_ptr).node.release() } != 1 {
711 return;
712 }
713
714 std::sync::atomic::fence(Acquire);
718
719 unsafe { self.free_slot(&mut *slot_ptr, id) };
722 }
723
724 #[inline]
728 unsafe fn free_slot(&self, slot: &mut Slot<N>, id: u32) {
729 debug_assert!(id as usize >= TERMINALS);
730 unsafe { ManuallyDrop::take(&mut slot.node) }.drop_with(|edge| self.drop_edge(edge));
732
733 LOCAL_STORE_STATE.with(|state| {
734 if state.current_store.get() == addr(self) {
735 slot.next_free = state.next_free.get();
736 state.next_free.set(id);
737
738 let delta = state.node_count_delta.get() - 1;
739 if delta > -(CHUNK_SIZE as i32) {
740 state.node_count_delta.set(delta);
741 } else {
742 let mut shared = self.state.lock();
743 shared.next_free.push(state.next_free.replace(0));
744 shared.node_count += state.node_count_delta.replace(0) as i64;
745 }
746 } else {
747 #[cold]
748 fn return_slot<N>(shared: &Mutex<SharedStoreState>, slot: &mut Slot<N>, id: u32) {
749 let mut shared = shared.lock();
750 slot.next_free = shared.next_free.pop().unwrap_or(0);
751 shared.next_free.push(id);
752 shared.node_count -= 1;
753 }
754 return_slot(&self.state, slot, id);
755 }
756 });
757 }
758
759 #[inline]
768 fn drop_edge(&self, edge: Edge<'id, N, ET>) {
769 let id = edge.node_id();
770 if id >= TERMINALS {
771 let node = self.inner_nodes.inner_node(&edge);
773 std::mem::forget(edge);
774 let _old_rc = unsafe { node.release() };
776 debug_assert!(_old_rc > 1);
777 } else {
778 std::mem::forget(edge);
779 unsafe { self.terminal_manager.release(id) };
781 }
782 }
783
784 #[inline]
788 fn clone_edge(&self, edge: &Edge<'id, N, ET>) -> Edge<'id, N, ET> {
789 let id = edge.node_id();
790 if id >= TERMINALS {
791 self.inner_nodes.inner_node(edge).retain();
793 } else {
794 unsafe { self.terminal_manager.retain(id) };
796 }
797 Edge(edge.0, PhantomData)
798 }
799}
800
801impl<'id, N, ET, TM, R, MD, const TERMINALS: usize> Drop for Store<'id, N, ET, TM, R, MD, TERMINALS>
802where
803 N: NodeBase + InnerNode<Edge<'id, N, ET>>,
804 ET: Tag,
805 TM: TerminalManager<'id, N, ET, TERMINALS>,
806 MD: DropWith<Edge<'id, N, ET>>,
807{
808 fn drop(&mut self) {
809 let manager = self.manager.get_mut();
810 unsafe { ManuallyDrop::take(&mut manager.data) }.drop_with(std::mem::forget);
813
814 if N::needs_drop() {
815 let unique_table = std::mem::take(&mut manager.unique_table);
816 for level in unique_table {
817 for edge in level.into_inner() {
818 let slot_ptr = unsafe { self.inner_nodes.slot_pointer_unchecked(&edge) };
821 std::mem::forget(edge);
822 let node = unsafe { ManuallyDrop::take(&mut (*slot_ptr).node) };
825
826 node.drop_with(std::mem::forget);
828 }
829 }
830 }
831 }
832}
833
834impl<'id, N, ET, TM, R, MD, const TERMINALS: usize> Drop
837 for LocalStoreStateGuard<'_, 'id, N, ET, TM, R, MD, TERMINALS>
838where
839 N: NodeBase + InnerNode<Edge<'id, N, ET>>,
840 ET: Tag,
841 TM: TerminalManager<'id, N, ET, TERMINALS>,
842 MD: DropWith<Edge<'id, N, ET>>,
843{
844 #[inline]
845 fn drop(&mut self) {
846 #[cold]
847 fn drop_slow<N>(
848 slots: &[UnsafeCell<Slot<N>>],
849 shared_state: &Mutex<SharedStoreState>,
850 terminals: u32,
851 ) {
852 LOCAL_STORE_STATE.with(|local| {
853 local.current_store.set(0);
854 let start = local.initialized.get();
855 let next_free = if start % CHUNK_SIZE != 0 {
856 debug_assert!(start <= u32::MAX - CHUNK_SIZE);
859 let end = (start / CHUNK_SIZE + 1) * CHUNK_SIZE;
860 let last_slot = &slots[(end - 1) as usize];
861 unsafe { &mut *last_slot.get() }.next_free = local.next_free.get();
864 for (slot, next_id) in slots[start as usize..(end - 1) as usize]
865 .iter()
866 .zip(start + terminals + 1..)
867 {
868 unsafe { &mut *slot.get() }.next_free = next_id;
869 }
870 start + terminals
871 } else {
872 local.next_free.get()
873 };
874
875 let mut shared = shared_state.lock();
876 if next_free != 0 {
877 shared.next_free.push(next_free);
878 }
879 shared.node_count += local.node_count_delta.replace(0) as i64;
880 });
881 }
882
883 LOCAL_STORE_STATE.with(|local| {
884 if addr(self.0) == local.current_store.get()
885 && (local.next_free.get() != 0
886 || local.initialized.get() % CHUNK_SIZE != 0
887 || local.node_count_delta.get() != 0)
888 {
889 drop_slow(&self.0.inner_nodes.slots, &self.0.state, TERMINALS as u32);
890 }
891 });
892 }
893}
894
895impl<'id, N, ET, TM, R, MD, const TERMINALS: usize> Manager<'id, N, ET, TM, R, MD, TERMINALS>
898where
899 N: NodeBase + InnerNode<Edge<'id, N, ET>>,
900 ET: Tag,
901 TM: TerminalManager<'id, N, ET, TERMINALS>,
902 R: oxidd_core::DiagramRules<Edge<'id, N, ET>, N, TM::TerminalNode>,
903 MD: DropWith<Edge<'id, N, ET>> + ManagerEventSubscriber<Self>,
904{
905 #[inline]
907 fn store(&self) -> &Store<'id, N, ET, TM, R, MD, TERMINALS> {
908 let offset = const {
913 std::mem::offset_of!(Store<'static, N, ET, TM, R, MD, TERMINALS>, manager)
914 + RwLock::<Self>::DATA_OFFSET
915 };
916 unsafe {
921 std::hint::assert_unchecked(std::ptr::eq(
922 std::ptr::from_ref(self).cast::<u8>().sub(offset).cast(),
923 self.store,
924 ))
925 };
926
927 unsafe { &*self.store }
930 }
931
932 fn init(&mut self) {
934 self.data.init(self);
935 MD::init_mut(self);
936 }
937}
938
939unsafe impl<'id, N, ET, TM, R, MD, const TERMINALS: usize> oxidd_core::Manager
940 for Manager<'id, N, ET, TM, R, MD, TERMINALS>
941where
942 N: NodeBase + InnerNode<Edge<'id, N, ET>>,
943 ET: Tag,
944 TM: TerminalManager<'id, N, ET, TERMINALS>,
945 R: oxidd_core::DiagramRules<Edge<'id, N, ET>, N, TM::TerminalNode>,
946 MD: DropWith<Edge<'id, N, ET>> + ManagerEventSubscriber<Self>,
947{
948 type Edge = Edge<'id, N, ET>;
949 type EdgeTag = ET;
950 type InnerNode = N;
951 type Terminal = TM::TerminalNode;
952 type TerminalRef<'a>
953 = TM::TerminalNodeRef<'a>
954 where
955 Self: 'a;
956 type Rules = R;
957
958 type TerminalIterator<'a>
959 = TM::Iterator<'a>
960 where
961 Self: 'a;
962 type NodeSet = NodeSet;
963 type LevelView<'a>
964 = LevelView<'a, 'id, N, ET, TM, R, MD, TERMINALS>
965 where
966 Self: 'a;
967 type LevelIterator<'a>
968 = LevelIter<'a, 'id, N, ET, TM, R, MD, TERMINALS>
969 where
970 Self: 'a;
971
972 #[inline]
973 fn get_node(&self, edge: &Self::Edge) -> oxidd_core::Node<'_, Self> {
974 let store = self.store();
975 let id = edge.node_id();
976 if id >= TERMINALS {
977 oxidd_core::Node::Inner(store.inner_nodes.inner_node(edge))
978 } else {
979 oxidd_core::Node::Terminal(unsafe { store.terminal_manager.get_terminal(id) })
981 }
982 }
983
984 #[inline]
985 fn clone_edge(&self, edge: &Self::Edge) -> Self::Edge {
986 self.store().clone_edge(edge)
987 }
988
989 #[inline]
990 fn drop_edge(&self, edge: Self::Edge) {
991 self.store().drop_edge(edge)
992 }
993
994 #[track_caller]
995 fn try_remove_node(&self, edge: Edge<'id, N, ET>, level: LevelNo) -> bool {
996 let id = edge.node_id();
997 let store = self.store();
998 if id < TERMINALS {
999 std::mem::forget(edge);
1000 unsafe { store.terminal_manager.release(id) };
1002 debug_assert_eq!(level, LevelNo::MAX, "`level` does not match");
1003 return false;
1004 }
1005
1006 let node = store.inner_nodes.inner_node(&edge);
1008 std::mem::forget(edge);
1009 let old_rc = unsafe { node.release() };
1011
1012 debug_assert_ne!(level, LevelNo::MAX, "`level` does not match");
1013 debug_assert!(
1014 (level as usize) < self.unique_table.len(),
1015 "`level` out of range"
1016 );
1017 debug_assert!(node.check_level(|l| l == level), "`level` does not match");
1018 debug_assert!(old_rc > 1);
1019
1020 if old_rc != 2 || !self.reorder_gc_prepared {
1021 return false;
1022 }
1023
1024 let Some(set) = self.unique_table.get(level as usize) else {
1025 return false;
1026 };
1027 let mut set = set.lock();
1028
1029 let rc = node.load_rc(Acquire);
1032 debug_assert_ne!(rc, 0);
1033 if rc != 1 {
1034 return false;
1035 }
1036
1037 let Some(edge) = (unsafe { set.remove(&store.inner_nodes, node) }) else {
1039 return false;
1040 };
1041
1042 let slot_ptr = unsafe { store.inner_nodes.slot_pointer_unchecked(&edge) };
1044 let id = unsafe { edge.node_id_unchecked() };
1045 std::mem::forget(edge);
1046
1047 unsafe { store.free_slot(&mut *slot_ptr, id) };
1052
1053 true
1054 }
1055
1056 #[inline]
1057 fn num_inner_nodes(&self) -> usize {
1058 self.unique_table
1059 .iter()
1060 .map(|level| level.lock().len())
1061 .sum()
1062 }
1063
1064 #[inline]
1065 fn approx_num_inner_nodes(&self) -> usize {
1066 let count = self.store().state.lock().node_count;
1067 if count < 0 { 0 } else { count as u64 as usize }
1068 }
1069
1070 #[inline(always)]
1071 fn num_levels(&self) -> LevelNo {
1072 self.unique_table.len() as LevelNo
1073 }
1074
1075 #[inline(always)]
1076 fn num_named_vars(&self) -> VarNo {
1077 self.var_name_map.named_count() as VarNo
1078 }
1079
1080 #[track_caller]
1081 fn add_vars(&mut self, additional: VarNo) -> Range<VarNo> {
1082 let len = self.unique_table.len() as VarNo;
1083 let new_len = len.checked_add(additional).expect("too many variables");
1084 let range = len..new_len;
1085
1086 self.data.pre_reorder(self);
1087 MD::pre_reorder_mut(self);
1088
1089 self.unique_table
1090 .resize_with(new_len as usize, || Mutex::new(LevelViewSet::default()));
1091 self.var_level_map.extend(additional);
1092 self.var_name_map.add_unnamed(additional);
1093
1094 debug_assert_eq!(new_len as usize, self.unique_table.len());
1095 debug_assert_eq!(new_len as usize, self.var_level_map.len());
1096 debug_assert_eq!(new_len, self.var_name_map.len());
1097
1098 self.data.post_reorder(self);
1099 MD::post_reorder_mut(self);
1100
1101 range
1102 }
1103
1104 #[track_caller]
1105 fn add_named_vars<S: Into<String>>(
1106 &mut self,
1107 names: impl IntoIterator<Item = S>,
1108 ) -> Result<Range<VarNo>, DuplicateVarName> {
1109 self.data.pre_reorder(self);
1110 MD::pre_reorder_mut(self);
1111
1112 let len = self.var_name_map.len();
1113 let mut guard = scopeguard::guard(self, |this| {
1114 let new_len = this.var_name_map.len();
1119 this.unique_table
1120 .resize_with(new_len as usize, || Mutex::new(LevelViewSet::default()));
1121 this.var_level_map.extend((new_len - len) as VarNo);
1122
1123 debug_assert_eq!(new_len as usize, this.unique_table.len());
1124 debug_assert_eq!(new_len as usize, this.var_level_map.len());
1125 debug_assert_eq!(new_len, this.var_name_map.len());
1126
1127 this.data.post_reorder(this);
1128 MD::post_reorder_mut(this);
1129 });
1130
1131 let mut names = names.into_iter();
1132 let range = guard.var_name_map.add_named(names.by_ref())?;
1133 drop(guard);
1134
1135 if names.next().is_some() {
1136 panic!("too many variables");
1138 }
1139
1140 Ok(range)
1141 }
1142
1143 #[track_caller]
1144 fn add_named_vars_from_map(
1145 &mut self,
1146 map: VarNameMap,
1147 ) -> Result<Range<VarNo>, DuplicateVarName> {
1148 if !self.var_name_map.is_empty() {
1149 return self.add_named_vars(map.into_names_iter());
1150 }
1151
1152 self.data.pre_reorder(self);
1153 MD::pre_reorder_mut(self);
1154
1155 let n = map.len();
1156 self.unique_table
1157 .resize_with(n as usize, || Mutex::new(LevelViewSet::default()));
1158 self.var_level_map.extend(n);
1159 self.var_name_map = map;
1160
1161 debug_assert_eq!(n as usize, self.unique_table.len());
1162 debug_assert_eq!(n as usize, self.var_level_map.len());
1163 debug_assert_eq!(n, self.var_name_map.len());
1164
1165 self.data.post_reorder(self);
1166 MD::post_reorder_mut(self);
1167
1168 Ok(0..n)
1169 }
1170
1171 #[track_caller]
1172 #[inline(always)]
1173 fn var_name(&self, var: VarNo) -> &str {
1174 self.var_name_map.var_name(var)
1175 }
1176
1177 #[track_caller]
1178 #[inline(always)]
1179 fn set_var_name(
1180 &mut self,
1181 var: VarNo,
1182 name: impl Into<String>,
1183 ) -> Result<(), DuplicateVarName> {
1184 self.var_name_map.set_var_name(var, name)
1185 }
1186
1187 #[inline(always)]
1188 fn name_to_var(&self, name: impl AsRef<str>) -> Option<VarNo> {
1189 self.var_name_map.name_to_var(name)
1190 }
1191
1192 #[track_caller]
1193 #[inline(always)]
1194 fn var_to_level(&self, var: VarNo) -> LevelNo {
1195 self.var_level_map.var_to_level(var)
1196 }
1197
1198 #[track_caller]
1199 #[inline(always)]
1200 fn level_to_var(&self, level: LevelNo) -> VarNo {
1201 self.var_level_map.level_to_var(level)
1202 }
1203
1204 #[track_caller]
1205 #[inline(always)]
1206 fn level(&self, no: LevelNo) -> Self::LevelView<'_> {
1207 LevelView {
1208 store: self.store(),
1209 var_level_map: &self.var_level_map,
1210 allow_node_removal: self.reorder_gc_prepared,
1211 level: no,
1212 set: self.unique_table[no as usize].lock(),
1213 }
1214 }
1215
1216 #[inline(always)]
1217 unsafe fn level_unchecked(&self, no: LevelNo) -> Self::LevelView<'_> {
1218 LevelView {
1219 store: self.store(),
1220 var_level_map: &self.var_level_map,
1221 allow_node_removal: self.reorder_gc_prepared,
1222 level: no,
1223 set: unsafe { self.unique_table.get_unchecked(no as usize) }.lock(),
1225 }
1226 }
1227
1228 #[inline]
1229 fn levels(&self) -> Self::LevelIterator<'_> {
1230 LevelIter {
1231 store: self.store(),
1232 var_level_map: &self.var_level_map,
1233 allow_node_removal: self.reorder_gc_prepared,
1234 level_front: 0,
1235 level_back: self.unique_table.len() as LevelNo,
1236 it: self.unique_table.iter(),
1237 }
1238 }
1239
1240 #[inline]
1241 fn get_terminal(&self, terminal: Self::Terminal) -> AllocResult<Self::Edge> {
1242 self.store().terminal_manager.get_edge(terminal)
1243 }
1244
1245 #[inline]
1246 fn num_terminals(&self) -> usize {
1247 self.store().terminal_manager.len()
1248 }
1249
1250 #[inline]
1251 fn terminals(&self) -> Self::TerminalIterator<'_> {
1252 self.store().terminal_manager.iter()
1253 }
1254
1255 fn gc(&self) -> usize {
1256 if !self.gc_ongoing.try_lock() {
1257 return 0;
1259 }
1260 self.gc_count.fetch_add(1, Relaxed);
1261 let guard = AbortOnDrop("Garbage collection panicked.");
1262
1263 #[cfg(feature = "statistics")]
1264 eprintln!(
1265 "[oxidd-manager-index] garbage collection started at {}",
1266 std::time::SystemTime::now()
1267 .duration_since(std::time::UNIX_EPOCH)
1268 .unwrap()
1269 .as_secs()
1270 );
1271
1272 if !self.reorder_gc_prepared {
1273 self.data.pre_gc(self);
1274 }
1275
1276 let store = self.store();
1277 let mut collected = 0;
1278 for level in &self.unique_table {
1279 let mut level = level.lock();
1280 collected += level.len() as u32;
1281 unsafe { level.gc(store) };
1284 collected -= level.len() as u32;
1285 }
1286 collected += store.terminal_manager.gc();
1287
1288 if !self.reorder_gc_prepared {
1289 unsafe { self.data.post_gc(self) };
1291 }
1292 self.gc_ongoing.unlock();
1293 guard.defuse();
1294
1295 #[cfg(feature = "statistics")]
1296 eprintln!(
1297 "[oxidd-manager-index] garbage collection finished at {}: removed {} nodes",
1298 std::time::SystemTime::now()
1299 .duration_since(std::time::UNIX_EPOCH)
1300 .unwrap()
1301 .as_secs(),
1302 collected,
1303 );
1304 collected as usize
1305 }
1306
1307 fn reorder<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T {
1308 if self.reorder_gc_prepared {
1309 return f(self);
1313 }
1314 let guard = AbortOnDrop("Reordering panicked.");
1315
1316 self.data.pre_gc(self);
1317 self.reorder_gc_prepared = true;
1318 self.data.pre_reorder(self);
1319 MD::pre_reorder_mut(self);
1320
1321 let res = f(self);
1322
1323 self.data.post_reorder(self);
1324 MD::post_reorder_mut(self);
1325 self.reorder_gc_prepared = false;
1326 unsafe { self.data.post_gc(self) };
1328
1329 guard.defuse();
1330 *self.gc_count.get_mut() += 1;
1334 self.reorder_count += 1;
1335 res
1336 }
1337
1338 #[inline]
1339 fn gc_count(&self) -> u64 {
1340 self.gc_count.load(Relaxed)
1341 }
1342
1343 #[inline]
1344 fn reorder_count(&self) -> u64 {
1345 self.reorder_count
1346 }
1347}
1348
1349impl<'id, N, ET, TM, R, MD, const TERMINALS: usize> oxidd_core::HasWorkers
1350 for Manager<'id, N, ET, TM, R, MD, TERMINALS>
1351where
1352 N: NodeBase + InnerNode<Edge<'id, N, ET>> + Send + Sync,
1353 ET: Tag + Send + Sync,
1354 TM: TerminalManager<'id, N, ET, TERMINALS> + Send + Sync,
1355 R: oxidd_core::DiagramRules<Edge<'id, N, ET>, N, TM::TerminalNode>,
1356 MD: DropWith<Edge<'id, N, ET>> + ManagerEventSubscriber<Self> + Send + Sync,
1357{
1358 type WorkerPool = crate::workers::Workers;
1359
1360 #[inline]
1361 fn workers(&self) -> &Self::WorkerPool {
1362 &self.store().workers
1363 }
1364}
1365
1366struct LevelViewSet<'id, N, ET, TM, R, MD, const TERMINALS: usize>(
1379 huge::RawTable<Edge<'id, N, ET>>,
1380 PhantomData<(TM, R, MD)>,
1381);
1382
1383#[inline]
1384fn hash_node<N: NodeBase>(node: &N) -> u64 {
1385 let mut hasher = FxHasher::default();
1386 node.hash(&mut hasher);
1387 hasher.finish()
1388}
1389
1390impl<'id, N, ET, TM, R, MD, const TERMINALS: usize> LevelViewSet<'id, N, ET, TM, R, MD, TERMINALS>
1391where
1392 N: NodeBase + InnerNode<Edge<'id, N, ET>>,
1393 ET: Tag,
1394 TM: TerminalManager<'id, N, ET, TERMINALS>,
1395 MD: DropWith<Edge<'id, N, ET>>,
1396{
1397 #[inline]
1399 fn len(&self) -> usize {
1400 self.0.len()
1401 }
1402
1403 #[inline]
1408 unsafe fn eq<'a>(
1409 nodes: &'a SlotSlice<'id, N, TERMINALS>,
1410 node: &'a N,
1411 ) -> impl Fn(&Edge<'id, N, ET>) -> bool + 'a {
1412 move |edge| unsafe { nodes.inner_node_unchecked(edge) == node }
1413 }
1414
1415 #[inline]
1417 fn reserve(&mut self, additional: usize) {
1418 self.0.reserve(additional)
1421 }
1422
1423 #[inline]
1424 fn get(&self, nodes: &SlotSlice<'id, N, TERMINALS>, node: &N) -> Option<&Edge<'id, N, ET>> {
1425 let hash = hash_node(node);
1426 self.0.get(hash, unsafe { Self::eq(nodes, node) })
1429 }
1430
1431 #[inline]
1440 fn insert(&mut self, nodes: &SlotSlice<'id, N, TERMINALS>, edge: Edge<'id, N, ET>) -> bool {
1441 debug_assert!(!edge.is_tagged(), "`edge` must not be tagged");
1442 let node = nodes.inner_node(&edge);
1443 let hash = hash_node(node);
1444 match self
1447 .0
1448 .find_or_find_insert_slot(hash, unsafe { Self::eq(nodes, node) })
1449 {
1450 Ok(_) => {
1451 std::mem::forget(edge);
1455 let _old_rc = unsafe { node.release() };
1457 debug_assert!(_old_rc > 1);
1458
1459 false
1460 }
1461 Err(slot) => {
1462 unsafe { self.0.insert_in_slot_unchecked(hash, slot, edge) };
1466 true
1467 }
1468 }
1469 }
1470
1471 #[inline]
1476 fn get_or_insert(
1477 &mut self,
1478 nodes: &SlotSlice<'id, N, TERMINALS>,
1479 node: N,
1480 insert: impl FnOnce(N) -> AllocResult<[Edge<'id, N, ET>; 2]>,
1481 drop: impl FnOnce(N),
1482 ) -> AllocResult<Edge<'id, N, ET>> {
1483 let hash = hash_node(&node);
1484 match self
1487 .0
1488 .find_or_find_insert_slot(hash, unsafe { Self::eq(nodes, &node) })
1489 {
1490 Ok(slot) => {
1491 drop(node);
1492 Ok(unsafe { nodes.clone_edge_unchecked(self.0.get_at_slot_unchecked(slot)) })
1497 }
1498 Err(slot) => {
1499 let [e1, e2] = insert(node)?;
1500 unsafe { self.0.insert_in_slot_unchecked(hash, slot, e1) };
1504 Ok(e2)
1505 }
1506 }
1507 }
1508
1509 unsafe fn gc(&mut self, store: &Store<'id, N, ET, TM, R, MD, TERMINALS>) {
1516 let inner_nodes = &*store.inner_nodes;
1517 self.0.retain(
1518 |edge| {
1519 unsafe { inner_nodes.inner_node_unchecked(edge) }.load_rc(Acquire) != 1
1522 },
1523 |edge| {
1524 let slot_ptr = unsafe { inner_nodes.slot_pointer_unchecked(&edge) };
1526 let id = unsafe { edge.node_id_unchecked() };
1527 std::mem::forget(edge);
1528
1529 unsafe { store.free_slot(&mut *slot_ptr, id) };
1534 },
1535 );
1536 }
1537
1538 #[inline]
1546 unsafe fn remove(
1547 &mut self,
1548 nodes: &SlotSlice<'id, N, TERMINALS>,
1549 node: &N,
1550 ) -> Option<Edge<'id, N, ET>> {
1551 let hash = hash_node(node);
1552 self.0.remove_entry(hash, unsafe { Self::eq(nodes, node) })
1555 }
1556
1557 #[inline]
1559 fn iter(&self) -> LevelViewIter<'_, 'id, N, ET> {
1560 LevelViewIter(self.0.iter())
1561 }
1562
1563 #[inline]
1565 fn drain(&mut self) -> linear_hashtbl::raw::Drain<'_, Edge<'id, N, ET>, u32> {
1566 self.0.drain()
1567 }
1568}
1569
1570impl<N, ET, TM, R, MD, const TERMINALS: usize> Drop
1571 for LevelViewSet<'_, N, ET, TM, R, MD, TERMINALS>
1572{
1573 #[inline]
1574 fn drop(&mut self) {
1575 self.0.reset_no_drop();
1578 }
1579}
1580
1581impl<N, ET, TM, R, MD, const TERMINALS: usize> Default
1582 for LevelViewSet<'_, N, ET, TM, R, MD, TERMINALS>
1583{
1584 #[inline]
1585 fn default() -> Self {
1586 Self(Default::default(), PhantomData)
1587 }
1588}
1589
1590impl<'id, N, ET, TM, R, MD, const TERMINALS: usize> IntoIterator
1591 for LevelViewSet<'id, N, ET, TM, R, MD, TERMINALS>
1592{
1593 type Item = Edge<'id, N, ET>;
1594
1595 type IntoIter = huge::RawTableIntoIter<Edge<'id, N, ET>>;
1596
1597 fn into_iter(self) -> Self::IntoIter {
1598 let this = ManuallyDrop::new(self);
1599 let set = unsafe { std::ptr::read(&this.0) };
1601 set.into_iter()
1602 }
1603}
1604
1605pub struct LevelViewIter<'a, 'id, N, ET>(linear_hashtbl::raw::Iter<'a, Edge<'id, N, ET>, u32>);
1606
1607impl<'a, 'id, N, ET> Iterator for LevelViewIter<'a, 'id, N, ET> {
1608 type Item = &'a Edge<'id, N, ET>;
1609
1610 #[inline]
1611 fn next(&mut self) -> Option<Self::Item> {
1612 self.0.next()
1613 }
1614
1615 #[inline]
1616 fn size_hint(&self) -> (usize, Option<usize>) {
1617 self.0.size_hint()
1618 }
1619}
1620
1621impl<N, ET> ExactSizeIterator for LevelViewIter<'_, '_, N, ET> {
1622 #[inline(always)]
1623 fn len(&self) -> usize {
1624 self.0.len()
1625 }
1626}
1627impl<'a, 'id, N, ET> FusedIterator for LevelViewIter<'a, 'id, N, ET> where
1628 linear_hashtbl::raw::Iter<'a, Edge<'id, N, ET>, u32>: FusedIterator
1629{
1630}
1631
1632pub struct LevelView<'a, 'id, N, ET, TM, R, MD, const TERMINALS: usize>
1633where
1634 N: NodeBase + InnerNode<Edge<'id, N, ET>>,
1635 ET: Tag,
1636 TM: TerminalManager<'id, N, ET, TERMINALS>,
1637 MD: DropWith<Edge<'id, N, ET>>,
1638{
1639 store: &'a Store<'id, N, ET, TM, R, MD, TERMINALS>,
1640 var_level_map: &'a VarLevelMap,
1641 allow_node_removal: bool,
1644 level: LevelNo,
1645 set: MutexGuard<'a, LevelViewSet<'id, N, ET, TM, R, MD, TERMINALS>>,
1646}
1647
1648unsafe impl<'a, 'id, N, ET, TM, R, MD, const TERMINALS: usize>
1649 oxidd_core::LevelView<Edge<'id, N, ET>, N> for LevelView<'a, 'id, N, ET, TM, R, MD, TERMINALS>
1650where
1651 N: NodeBase + InnerNode<Edge<'id, N, ET>>,
1652 ET: Tag,
1653 TM: TerminalManager<'id, N, ET, TERMINALS>,
1654 MD: DropWith<Edge<'id, N, ET>>,
1655{
1656 type Iterator<'b>
1657 = LevelViewIter<'b, 'id, N, ET>
1658 where
1659 Self: 'b,
1660 Edge<'id, N, ET>: 'b;
1661
1662 type Taken = TakenLevelView<'a, 'id, N, ET, TM, R, MD, TERMINALS>;
1663
1664 #[inline(always)]
1665 fn len(&self) -> usize {
1666 self.set.len()
1667 }
1668
1669 #[inline(always)]
1670 fn level_no(&self) -> LevelNo {
1671 self.level
1672 }
1673
1674 #[inline]
1675 fn reserve(&mut self, additional: usize) {
1676 self.set.reserve(additional);
1677 }
1678
1679 #[inline]
1680 fn get(&self, node: &N) -> Option<&Edge<'id, N, ET>> {
1681 self.set.get(&self.store.inner_nodes, node)
1682 }
1683
1684 #[inline]
1685 fn insert(&mut self, edge: Edge<'id, N, ET>) -> bool {
1686 debug_assert!(!edge.is_tagged(), "`edge` should not be tagged");
1687 let nodes = &self.store.inner_nodes;
1690 nodes.inner_node(&edge).assert_level_matches(self.level);
1691 self.set.insert(nodes, edge)
1692 }
1693
1694 #[inline]
1695 unsafe fn insert_unchecked(&mut self, edge: Edge<'id, N, ET>) -> bool {
1696 debug_assert!(!edge.is_tagged(), "`edge` should not be tagged");
1697 self.set.insert(&self.store.inner_nodes, edge)
1700 }
1701
1702 #[inline(always)]
1703 fn get_or_insert(&mut self, node: N) -> AllocResult<Edge<'id, N, ET>> {
1704 node.assert_level_matches(self.level);
1705 self.set.get_or_insert(
1708 &self.store.inner_nodes,
1709 node,
1710 |node| self.store.add_node(node),
1711 |node| node.drop_with(|edge| self.store.drop_edge(edge)),
1712 )
1713 }
1714
1715 #[inline(always)]
1716 unsafe fn get_or_insert_unchecked(&mut self, node: N) -> AllocResult<Edge<'id, N, ET>> {
1717 self.set.get_or_insert(
1720 &self.store.inner_nodes,
1721 node,
1722 |node| self.store.add_node(node),
1723 |node| node.drop_with(|edge| self.store.drop_edge(edge)),
1724 )
1725 }
1726
1727 #[inline]
1728 fn gc(&mut self) {
1729 if self.allow_node_removal {
1730 unsafe { self.set.gc(self.store) };
1732 }
1733 }
1734
1735 #[inline]
1736 fn remove(&mut self, node: &N) -> bool {
1737 if !self.allow_node_removal {
1738 return false;
1739 }
1740 match unsafe { self.set.remove(&self.store.inner_nodes, node) } {
1742 Some(edge) => {
1743 unsafe { self.store.drop_unique_table_edge(edge) };
1745 true
1746 }
1747 None => false,
1748 }
1749 }
1750
1751 #[inline]
1752 unsafe fn swap(&mut self, other: &mut Self) {
1753 self.var_level_map.swap_levels(self.level, other.level);
1754 std::mem::swap(&mut *self.set, &mut *other.set);
1755 }
1756
1757 #[inline]
1758 fn iter(&self) -> Self::Iterator<'_> {
1759 self.set.iter()
1760 }
1761
1762 #[inline(always)]
1763 fn take(&mut self) -> Option<Self::Taken> {
1764 if self.allow_node_removal {
1765 Some(TakenLevelView {
1766 store: self.store,
1767 var_level_map: self.var_level_map,
1768 level: self.level,
1769 set: std::mem::take(&mut self.set),
1770 })
1771 } else {
1772 None
1773 }
1774 }
1775}
1776
1777pub struct TakenLevelView<'a, 'id, N, ET, TM, R, MD, const TERMINALS: usize>
1786where
1787 N: NodeBase + InnerNode<Edge<'id, N, ET>>,
1788 ET: Tag,
1789 TM: TerminalManager<'id, N, ET, TERMINALS>,
1790 MD: DropWith<Edge<'id, N, ET>>,
1791{
1792 store: &'a Store<'id, N, ET, TM, R, MD, TERMINALS>,
1793 var_level_map: &'a VarLevelMap,
1794 level: LevelNo,
1795 set: LevelViewSet<'id, N, ET, TM, R, MD, TERMINALS>,
1796}
1797
1798unsafe impl<'id, N, ET, TM, R, MD, const TERMINALS: usize>
1799 oxidd_core::LevelView<Edge<'id, N, ET>, N>
1800 for TakenLevelView<'_, 'id, N, ET, TM, R, MD, TERMINALS>
1801where
1802 N: NodeBase + InnerNode<Edge<'id, N, ET>>,
1803 ET: Tag,
1804 TM: TerminalManager<'id, N, ET, TERMINALS>,
1805 MD: DropWith<Edge<'id, N, ET>>,
1806{
1807 type Iterator<'b>
1808 = LevelViewIter<'b, 'id, N, ET>
1809 where
1810 Self: 'b,
1811 Edge<'id, N, ET>: 'b;
1812
1813 type Taken = Self;
1814
1815 #[inline(always)]
1816 fn len(&self) -> usize {
1817 self.set.len()
1818 }
1819
1820 #[inline(always)]
1821 fn level_no(&self) -> LevelNo {
1822 self.level
1823 }
1824
1825 #[inline]
1826 fn reserve(&mut self, additional: usize) {
1827 self.set.reserve(additional);
1828 }
1829
1830 #[inline]
1831 fn get(&self, node: &N) -> Option<&Edge<'id, N, ET>> {
1832 self.set.get(&self.store.inner_nodes, node)
1833 }
1834
1835 #[inline]
1836 fn insert(&mut self, edge: Edge<'id, N, ET>) -> bool {
1837 debug_assert!(!edge.is_tagged(), "`edge` should not be tagged");
1838 let nodes = &self.store.inner_nodes;
1841 nodes.inner_node(&edge).assert_level_matches(self.level);
1842 self.set.insert(nodes, edge)
1843 }
1844
1845 #[inline]
1846 unsafe fn insert_unchecked(&mut self, edge: Edge<'id, N, ET>) -> bool {
1847 debug_assert!(!edge.is_tagged(), "`edge` should not be tagged");
1848 self.set.insert(&self.store.inner_nodes, edge)
1851 }
1852
1853 #[inline(always)]
1854 fn get_or_insert(&mut self, node: N) -> AllocResult<Edge<'id, N, ET>> {
1855 node.assert_level_matches(self.level);
1856 self.set.get_or_insert(
1859 &self.store.inner_nodes,
1860 node,
1861 |node| self.store.add_node(node),
1862 |node| node.drop_with(|edge| self.store.drop_edge(edge)),
1863 )
1864 }
1865
1866 #[inline(always)]
1867 unsafe fn get_or_insert_unchecked(&mut self, node: N) -> AllocResult<Edge<'id, N, ET>> {
1868 self.set.get_or_insert(
1871 &self.store.inner_nodes,
1872 node,
1873 |node| self.store.add_node(node),
1874 |node| node.drop_with(|edge| self.store.drop_edge(edge)),
1875 )
1876 }
1877
1878 #[inline]
1879 fn gc(&mut self) {
1880 unsafe { self.set.gc(self.store) };
1882 }
1883
1884 #[inline]
1885 fn remove(&mut self, node: &N) -> bool {
1886 match unsafe { self.set.remove(&self.store.inner_nodes, node) } {
1888 Some(edge) => {
1889 unsafe { self.store.drop_unique_table_edge(edge) };
1891 true
1892 }
1893 None => false,
1894 }
1895 }
1896
1897 #[inline(always)]
1898 unsafe fn swap(&mut self, other: &mut Self) {
1899 self.var_level_map.swap_levels(self.level, other.level);
1900 std::mem::swap(&mut self.set, &mut other.set);
1901 }
1902
1903 #[inline]
1904 fn iter(&self) -> Self::Iterator<'_> {
1905 self.set.iter()
1906 }
1907
1908 #[inline(always)]
1909 fn take(&mut self) -> Option<Self::Taken> {
1910 Some(Self {
1911 store: self.store,
1912 var_level_map: self.var_level_map,
1913 level: self.level,
1914 set: std::mem::take(&mut self.set),
1915 })
1916 }
1917}
1918
1919impl<'id, N, ET, TM, R, MD, const TERMINALS: usize> Drop
1920 for TakenLevelView<'_, 'id, N, ET, TM, R, MD, TERMINALS>
1921where
1922 N: NodeBase + InnerNode<Edge<'id, N, ET>>,
1923 ET: Tag,
1924 TM: TerminalManager<'id, N, ET, TERMINALS>,
1925 MD: DropWith<Edge<'id, N, ET>>,
1926{
1927 fn drop(&mut self) {
1928 for edge in self.set.drain() {
1929 unsafe { self.store.drop_unique_table_edge(edge) }
1932 }
1933 }
1934}
1935
1936pub struct LevelIter<'a, 'id, N, ET, TM, R, MD, const TERMINALS: usize>
1939where
1940 N: NodeBase + InnerNode<Edge<'id, N, ET>>,
1941 ET: Tag,
1942 TM: TerminalManager<'id, N, ET, TERMINALS>,
1943 MD: DropWith<Edge<'id, N, ET>>,
1944{
1945 store: &'a Store<'id, N, ET, TM, R, MD, TERMINALS>,
1946 var_level_map: &'a VarLevelMap,
1947 allow_node_removal: bool,
1950 level_front: LevelNo,
1951 level_back: LevelNo,
1952 it: std::slice::Iter<'a, Mutex<LevelViewSet<'id, N, ET, TM, R, MD, TERMINALS>>>,
1953}
1954
1955impl<'a, 'id, N, ET, TM, R, MD, const TERMINALS: usize> Iterator
1956 for LevelIter<'a, 'id, N, ET, TM, R, MD, TERMINALS>
1957where
1958 N: NodeBase + InnerNode<Edge<'id, N, ET>>,
1959 ET: Tag,
1960 TM: TerminalManager<'id, N, ET, TERMINALS>,
1961 MD: DropWith<Edge<'id, N, ET>>,
1962{
1963 type Item = LevelView<'a, 'id, N, ET, TM, R, MD, TERMINALS>;
1964
1965 #[inline]
1966 fn next(&mut self) -> Option<Self::Item> {
1967 let mutex = self.it.next()?;
1968 let level = self.level_front;
1969 self.level_front += 1;
1970 Some(LevelView {
1971 store: self.store,
1972 var_level_map: self.var_level_map,
1973 allow_node_removal: self.allow_node_removal,
1974 level,
1975 set: mutex.lock(),
1976 })
1977 }
1978
1979 #[inline]
1980 fn size_hint(&self) -> (usize, Option<usize>) {
1981 self.it.size_hint()
1982 }
1983}
1984
1985impl<'id, N, ET, TM, R, MD, const TERMINALS: usize> ExactSizeIterator
1986 for LevelIter<'_, 'id, N, ET, TM, R, MD, TERMINALS>
1987where
1988 N: NodeBase + InnerNode<Edge<'id, N, ET>>,
1989 ET: Tag,
1990 TM: TerminalManager<'id, N, ET, TERMINALS>,
1991 MD: DropWith<Edge<'id, N, ET>>,
1992{
1993 #[inline(always)]
1994 fn len(&self) -> usize {
1995 self.it.len()
1996 }
1997}
1998impl<'a, 'id, N, ET, TM, R, MD, const TERMINALS: usize> FusedIterator
1999 for LevelIter<'a, 'id, N, ET, TM, R, MD, TERMINALS>
2000where
2001 N: NodeBase + InnerNode<Edge<'id, N, ET>>,
2002 ET: Tag,
2003 TM: TerminalManager<'id, N, ET, TERMINALS>,
2004 MD: DropWith<Edge<'id, N, ET>>,
2005 std::slice::Iter<'a, Mutex<LevelViewSet<'id, N, ET, TM, R, MD, TERMINALS>>>: FusedIterator,
2006{
2007}
2008
2009impl<'id, N, ET, TM, R, MD, const TERMINALS: usize> DoubleEndedIterator
2010 for LevelIter<'_, 'id, N, ET, TM, R, MD, TERMINALS>
2011where
2012 N: NodeBase + InnerNode<Edge<'id, N, ET>>,
2013 ET: Tag,
2014 TM: TerminalManager<'id, N, ET, TERMINALS>,
2015 MD: DropWith<Edge<'id, N, ET>>,
2016{
2017 fn next_back(&mut self) -> Option<Self::Item> {
2018 let mutex = self.it.next_back()?;
2019 self.level_back -= 1;
2020 Some(LevelView {
2021 store: self.store,
2022 var_level_map: self.var_level_map,
2023 allow_node_removal: self.allow_node_removal,
2024 level: self.level_back,
2025 set: mutex.lock(),
2026 })
2027 }
2028}
2029
2030#[repr(transparent)]
2033#[derive_where(Clone)]
2034pub struct ManagerRef<
2035 NC: InnerNodeCons<ET>,
2036 ET: Tag,
2037 TMC: TerminalManagerCons<NC, ET, TERMINALS>,
2038 RC: DiagramRulesCons<NC, ET, TMC, MDC, TERMINALS>,
2039 MDC: ManagerDataCons<NC, ET, TMC, RC, TERMINALS>,
2040 const TERMINALS: usize,
2041>(
2042 Arc<
2043 Store<
2044 'static,
2045 NC::T<'static>,
2046 ET,
2047 TMC::T<'static>,
2048 RC::T<'static>,
2049 MDC::T<'static>,
2050 TERMINALS,
2051 >,
2052 >,
2053);
2054
2055impl<
2056 NC: InnerNodeCons<ET>,
2057 ET: Tag,
2058 TMC: TerminalManagerCons<NC, ET, TERMINALS>,
2059 RC: DiagramRulesCons<NC, ET, TMC, MDC, TERMINALS>,
2060 MDC: ManagerDataCons<NC, ET, TMC, RC, TERMINALS>,
2061 const TERMINALS: usize,
2062> Drop for ManagerRef<NC, ET, TMC, RC, MDC, TERMINALS>
2063{
2064 fn drop(&mut self) {
2065 if Arc::strong_count(&self.0) == 2 {
2066 let gc_signal = &self.0.gc_signal;
2069 *gc_signal.0.lock() = GCSignal::Quit;
2070 gc_signal.1.notify_one();
2071 }
2072 }
2073}
2074
2075impl<
2076 NC: InnerNodeCons<ET>,
2077 ET: Tag,
2078 TMC: TerminalManagerCons<NC, ET, TERMINALS>,
2079 RC: DiagramRulesCons<NC, ET, TMC, MDC, TERMINALS>,
2080 MDC: ManagerDataCons<NC, ET, TMC, RC, TERMINALS>,
2081 const TERMINALS: usize,
2082> ManagerRef<NC, ET, TMC, RC, MDC, TERMINALS>
2083{
2084 #[inline(always)]
2091 pub fn into_raw(self) -> *const std::ffi::c_void {
2092 let this = ManuallyDrop::new(self);
2093 Arc::into_raw(unsafe { std::ptr::read(&this.0) }).cast()
2095 }
2096
2097 #[inline(always)]
2106 pub unsafe fn from_raw(raw: *const std::ffi::c_void) -> Self {
2107 Self(unsafe { Arc::from_raw(raw.cast()) })
2109 }
2110}
2111
2112impl<
2113 NC: InnerNodeCons<ET>,
2114 ET: Tag,
2115 TMC: TerminalManagerCons<NC, ET, TERMINALS>,
2116 RC: DiagramRulesCons<NC, ET, TMC, MDC, TERMINALS>,
2117 MDC: ManagerDataCons<NC, ET, TMC, RC, TERMINALS>,
2118 const TERMINALS: usize,
2119> PartialEq for ManagerRef<NC, ET, TMC, RC, MDC, TERMINALS>
2120{
2121 #[inline]
2122 fn eq(&self, other: &Self) -> bool {
2123 Arc::ptr_eq(&self.0, &other.0)
2124 }
2125}
2126impl<
2127 NC: InnerNodeCons<ET>,
2128 ET: Tag,
2129 TMC: TerminalManagerCons<NC, ET, TERMINALS>,
2130 RC: DiagramRulesCons<NC, ET, TMC, MDC, TERMINALS>,
2131 MDC: ManagerDataCons<NC, ET, TMC, RC, TERMINALS>,
2132 const TERMINALS: usize,
2133> Eq for ManagerRef<NC, ET, TMC, RC, MDC, TERMINALS>
2134{
2135}
2136impl<
2137 NC: InnerNodeCons<ET>,
2138 ET: Tag,
2139 TMC: TerminalManagerCons<NC, ET, TERMINALS>,
2140 RC: DiagramRulesCons<NC, ET, TMC, MDC, TERMINALS>,
2141 MDC: ManagerDataCons<NC, ET, TMC, RC, TERMINALS>,
2142 const TERMINALS: usize,
2143> PartialOrd for ManagerRef<NC, ET, TMC, RC, MDC, TERMINALS>
2144{
2145 #[inline]
2146 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
2147 Some(self.cmp(other))
2148 }
2149}
2150impl<
2151 NC: InnerNodeCons<ET>,
2152 ET: Tag,
2153 TMC: TerminalManagerCons<NC, ET, TERMINALS>,
2154 RC: DiagramRulesCons<NC, ET, TMC, MDC, TERMINALS>,
2155 MDC: ManagerDataCons<NC, ET, TMC, RC, TERMINALS>,
2156 const TERMINALS: usize,
2157> Ord for ManagerRef<NC, ET, TMC, RC, MDC, TERMINALS>
2158{
2159 #[inline]
2160 fn cmp(&self, other: &Self) -> Ordering {
2161 std::ptr::from_ref(&*self.0).cmp(&std::ptr::from_ref(&*other.0))
2162 }
2163}
2164impl<
2165 NC: InnerNodeCons<ET>,
2166 ET: Tag,
2167 TMC: TerminalManagerCons<NC, ET, TERMINALS>,
2168 RC: DiagramRulesCons<NC, ET, TMC, MDC, TERMINALS>,
2169 MDC: ManagerDataCons<NC, ET, TMC, RC, TERMINALS>,
2170 const TERMINALS: usize,
2171> Hash for ManagerRef<NC, ET, TMC, RC, MDC, TERMINALS>
2172{
2173 #[inline]
2174 fn hash<H: Hasher>(&self, state: &mut H) {
2175 std::ptr::from_ref(&*self.0).hash(state);
2176 }
2177}
2178
2179impl<
2180 'a,
2181 'id,
2182 NC: InnerNodeCons<ET>,
2183 ET: Tag,
2184 TMC: TerminalManagerCons<NC, ET, TERMINALS>,
2185 RC: DiagramRulesCons<NC, ET, TMC, MDC, TERMINALS>,
2186 MDC: ManagerDataCons<NC, ET, TMC, RC, TERMINALS>,
2187 const TERMINALS: usize,
2188> From<&'a M<'id, NC, ET, TMC, RC, MDC, TERMINALS>>
2189 for ManagerRef<NC, ET, TMC, RC, MDC, TERMINALS>
2190{
2191 fn from(manager: &'a M<'id, NC, ET, TMC, RC, MDC, TERMINALS>) -> Self {
2192 let ptr: *const M<'static, NC, ET, TMC, RC, MDC, TERMINALS> =
2193 std::ptr::from_ref(manager).cast();
2194 ManagerRef(unsafe {
2199 let manager = &*ptr;
2200 Arc::increment_strong_count(manager.store);
2201 Arc::from_raw(manager.store)
2202 })
2203 }
2204}
2205
2206impl<
2207 NC: InnerNodeCons<ET>,
2208 ET: Tag,
2209 TMC: TerminalManagerCons<NC, ET, TERMINALS>,
2210 RC: DiagramRulesCons<NC, ET, TMC, MDC, TERMINALS>,
2211 MDC: ManagerDataCons<NC, ET, TMC, RC, TERMINALS>,
2212 const TERMINALS: usize,
2213> oxidd_core::ManagerRef for ManagerRef<NC, ET, TMC, RC, MDC, TERMINALS>
2214{
2215 type Manager<'id> = M<'id, NC, ET, TMC, RC, MDC, TERMINALS>;
2216
2217 fn with_manager_shared<F, T>(&self, f: F) -> T
2218 where
2219 F: for<'id> FnOnce(&Self::Manager<'id>) -> T,
2220 {
2221 let local_guard = self.0.prepare_local_state();
2222 let res = f(&self.0.manager.shared());
2223 drop(local_guard);
2224 res
2225 }
2226
2227 fn with_manager_exclusive<F, T>(&self, f: F) -> T
2228 where
2229 F: for<'id> FnOnce(&mut Self::Manager<'id>) -> T,
2230 {
2231 let local_guard = self.0.prepare_local_state();
2232 let res = f(&mut self.0.manager.exclusive());
2233 drop(local_guard);
2234 res
2235 }
2236}
2237
2238pub fn new_manager<
2240 NC: InnerNodeCons<ET> + 'static,
2241 ET: Tag + Send + Sync + 'static,
2242 TMC: TerminalManagerCons<NC, ET, TERMINALS> + 'static,
2243 RC: DiagramRulesCons<NC, ET, TMC, MDC, TERMINALS> + 'static,
2244 MDC: ManagerDataCons<NC, ET, TMC, RC, TERMINALS> + 'static,
2245 const TERMINALS: usize,
2246>(
2247 inner_node_capacity: u32,
2248 terminal_node_capacity: u32,
2249 threads: u32,
2250 data: MDC::T<'static>,
2251) -> ManagerRef<NC, ET, TMC, RC, MDC, TERMINALS> {
2252 let () = Store::<
2254 'static,
2255 NC::T<'static>,
2256 ET,
2257 TMC::T<'static>,
2258 RC::T<'static>,
2259 MDC::T<'static>,
2260 TERMINALS,
2261 >::CHECK_TERMINALS;
2262
2263 let max_inner_capacity = if usize::BITS > u32::BITS {
2264 ((1usize << (u32::BITS - Edge::<NC::T<'static>, ET>::TAG_BITS)) - TERMINALS) as u32
2265 } else {
2266 u32::MAX / 24
2271 };
2272 let inner_node_capacity = std::cmp::min(inner_node_capacity, max_inner_capacity);
2273
2274 let gc_lwm = inner_node_capacity / 100 * 90;
2275 let gc_hwm = inner_node_capacity / 100 * 95;
2276
2277 let arc = Arc::new(Store {
2278 inner_nodes: SlotSlice::new_boxed(inner_node_capacity),
2279 state: CachePadded::new(Mutex::new(SharedStoreState {
2280 next_free: Vec::new(),
2281 allocated: 0,
2282 node_count: 0,
2283 gc_state: if gc_lwm < gc_hwm {
2284 GCState::Init
2285 } else {
2286 GCState::Disabled
2287 },
2288 gc_lwm,
2289 gc_hwm,
2290 })),
2291 manager: RwLock::new(Manager {
2292 unique_table: Vec::new(),
2293 var_level_map: VarLevelMap::new(),
2294 var_name_map: VarNameMap::new(),
2295 data: ManuallyDrop::new(data),
2296 store: std::ptr::null(),
2297 gc_count: AtomicU64::new(0),
2298 reorder_count: 0,
2299 gc_ongoing: TryLock::new(),
2300 reorder_gc_prepared: false,
2301 }),
2302 terminal_manager: TMC::T::<'static>::with_capacity(terminal_node_capacity),
2303 gc_signal: (Mutex::new(GCSignal::RunGc), Condvar::new()),
2304 workers: crate::workers::Workers::new(threads),
2305 });
2306
2307 let mut manager = arc.manager.exclusive();
2308 manager.store = Arc::as_ptr(&arc);
2309 drop(manager);
2310
2311 let store_addr = addr(&*arc);
2312 arc.workers.pool.spawn_broadcast(move |_| {
2313 LOCAL_STORE_STATE.with(|state| state.current_store.set(store_addr))
2315 });
2316
2317 let gc_mref: ManagerRef<NC, ET, TMC, RC, MDC, TERMINALS> = ManagerRef(arc.clone());
2319 std::thread::Builder::new()
2320 .name("oxidd mi gc".to_string())
2321 .spawn(move || {
2322 LOCAL_STORE_STATE.with(|state| state.current_store.set(store_addr));
2324
2325 let store = &*gc_mref.0;
2326 loop {
2327 let mut lock = store.gc_signal.0.lock();
2328 store.gc_signal.1.wait(&mut lock);
2329 if *lock == GCSignal::Quit {
2330 break;
2331 }
2332 drop(lock);
2333
2334 oxidd_core::ManagerRef::with_manager_shared(&gc_mref, |manager| {
2336 oxidd_core::Manager::gc(manager);
2337 });
2338
2339 let mut shared = store.state.lock();
2340 LOCAL_STORE_STATE.with(|local| {
2341 if local.next_free.get() != 0 {
2342 shared.node_count += local.node_count_delta.replace(0) as i64;
2343 shared.next_free.push(local.next_free.replace(0));
2344 }
2345 });
2346
2347 if shared.node_count < shared.gc_lwm as i64 && shared.gc_state != GCState::Disabled
2348 {
2349 shared.gc_state = GCState::Init;
2350 }
2351 }
2352 })
2353 .unwrap();
2354
2355 let local_guard = arc.prepare_local_state();
2357 arc.manager.exclusive().init();
2358 drop(local_guard);
2359
2360 ManagerRef(arc)
2361}
2362
2363impl<
2364 NC: InnerNodeCons<ET>,
2365 ET: Tag + Send + Sync,
2366 TMC: TerminalManagerCons<NC, ET, TERMINALS>,
2367 RC: DiagramRulesCons<NC, ET, TMC, MDC, TERMINALS>,
2368 MDC: ManagerDataCons<NC, ET, TMC, RC, TERMINALS>,
2369 const TERMINALS: usize,
2370> oxidd_core::HasWorkers for ManagerRef<NC, ET, TMC, RC, MDC, TERMINALS>
2371{
2372 type WorkerPool = crate::workers::Workers;
2373
2374 #[inline]
2375 fn workers(&self) -> &Self::WorkerPool {
2376 &self.0.workers
2377 }
2378}
2379
2380#[repr(C)]
2383#[derive_where(PartialEq, Eq, PartialOrd, Ord, Hash)]
2384pub struct Function<
2385 NC: InnerNodeCons<ET>,
2386 ET: Tag,
2387 TMC: TerminalManagerCons<NC, ET, TERMINALS>,
2388 RC: DiagramRulesCons<NC, ET, TMC, MDC, TERMINALS>,
2389 MDC: ManagerDataCons<NC, ET, TMC, RC, TERMINALS>,
2390 const TERMINALS: usize,
2391> {
2392 store: ManagerRef<NC, ET, TMC, RC, MDC, TERMINALS>,
2393 edge: ManuallyDrop<Edge<'static, NC::T<'static>, ET>>,
2394}
2395
2396impl<
2397 NC: InnerNodeCons<ET>,
2398 ET: Tag,
2399 TMC: TerminalManagerCons<NC, ET, TERMINALS>,
2400 RC: DiagramRulesCons<NC, ET, TMC, MDC, TERMINALS>,
2401 MDC: ManagerDataCons<NC, ET, TMC, RC, TERMINALS>,
2402 const TERMINALS: usize,
2403> Function<NC, ET, TMC, RC, MDC, TERMINALS>
2404{
2405 #[inline(always)]
2412 pub fn into_raw(self) -> (*const std::ffi::c_void, u32) {
2413 let this = ManuallyDrop::new(self);
2414 (
2416 unsafe { std::ptr::read(&this.store) }.into_raw(),
2417 this.edge.0,
2418 )
2419 }
2420
2421 #[inline(always)]
2430 pub unsafe fn from_raw(ptr: *const std::ffi::c_void, edge_val: u32) -> Self {
2431 Self {
2433 store: unsafe { ManagerRef::from_raw(ptr) },
2434 edge: ManuallyDrop::new(Edge(edge_val, PhantomData)),
2435 }
2436 }
2437}
2438
2439impl<
2440 NC: InnerNodeCons<ET>,
2441 ET: Tag,
2442 TMC: TerminalManagerCons<NC, ET, TERMINALS>,
2443 RC: DiagramRulesCons<NC, ET, TMC, MDC, TERMINALS>,
2444 MDC: ManagerDataCons<NC, ET, TMC, RC, TERMINALS>,
2445 const TERMINALS: usize,
2446> Drop for Function<NC, ET, TMC, RC, MDC, TERMINALS>
2447{
2448 #[inline]
2449 fn drop(&mut self) {
2450 let edge = unsafe { ManuallyDrop::take(&mut self.edge) };
2452 self.store.0.drop_edge(edge);
2453 }
2454}
2455
2456impl<
2457 NC: InnerNodeCons<ET>,
2458 ET: Tag,
2459 TMC: TerminalManagerCons<NC, ET, TERMINALS>,
2460 RC: DiagramRulesCons<NC, ET, TMC, MDC, TERMINALS>,
2461 MDC: ManagerDataCons<NC, ET, TMC, RC, TERMINALS>,
2462 const TERMINALS: usize,
2463> Clone for Function<NC, ET, TMC, RC, MDC, TERMINALS>
2464{
2465 #[inline]
2466 fn clone(&self) -> Self {
2467 Self {
2468 store: self.store.clone(),
2469 edge: ManuallyDrop::new(self.store.0.clone_edge(&self.edge)),
2470 }
2471 }
2472}
2473
2474unsafe impl<
2475 NC: InnerNodeCons<ET>,
2476 ET: Tag,
2477 TMC: TerminalManagerCons<NC, ET, TERMINALS>,
2478 RC: DiagramRulesCons<NC, ET, TMC, MDC, TERMINALS>,
2479 MDC: ManagerDataCons<NC, ET, TMC, RC, TERMINALS>,
2480 const TERMINALS: usize,
2481> oxidd_core::function::Function for Function<NC, ET, TMC, RC, MDC, TERMINALS>
2482{
2483 const REPR_ID: &str = "<none>";
2484
2485 type Manager<'id> = M<'id, NC, ET, TMC, RC, MDC, TERMINALS>;
2486
2487 type ManagerRef = ManagerRef<NC, ET, TMC, RC, MDC, TERMINALS>;
2488
2489 #[inline]
2490 fn from_edge<'id>(manager: &Self::Manager<'id>, edge: EdgeOfFunc<'id, Self>) -> Self {
2491 let ptr: *const Self::Manager<'static> = std::ptr::from_ref(manager).cast();
2492 let store = ManagerRef(unsafe {
2497 let manager = &*ptr;
2498 Arc::increment_strong_count(manager.store);
2499 Arc::from_raw(manager.store)
2500 });
2501 let id = edge.0;
2503 std::mem::forget(edge);
2504 Self {
2505 store,
2506 edge: ManuallyDrop::new(Edge(id, PhantomData)),
2507 }
2508 }
2509
2510 #[inline]
2511 fn as_edge<'id>(&self, manager: &Self::Manager<'id>) -> &EdgeOfFunc<'id, Self> {
2512 assert!(
2513 std::ptr::eq(self.store.0.manager.data_ptr().cast(), manager),
2514 "This function does not belong to `manager`"
2515 );
2516
2517 let ptr: *const EdgeOfFunc<'id, Self> = std::ptr::from_ref(&*self.edge).cast();
2518 unsafe { &*ptr }
2521 }
2522
2523 #[inline]
2524 fn into_edge<'id>(self, manager: &Self::Manager<'id>) -> EdgeOfFunc<'id, Self> {
2525 assert!(
2526 std::ptr::eq(self.store.0.manager.data_ptr().cast(), manager),
2527 "This function does not belong to `manager`"
2528 );
2529 let mut this = ManuallyDrop::new(self);
2532 let edge = Edge(this.edge.0, PhantomData);
2533 unsafe { std::ptr::drop_in_place(&mut this.store) };
2535 edge
2536 }
2537
2538 #[inline]
2539 fn manager_ref(&self) -> Self::ManagerRef {
2540 self.store.clone()
2541 }
2542
2543 fn with_manager_shared<F, T>(&self, f: F) -> T
2544 where
2545 F: for<'id> FnOnce(&Self::Manager<'id>, &EdgeOfFunc<'id, Self>) -> T,
2546 {
2547 let local_guard = self.store.0.prepare_local_state();
2548 let res = f(&self.store.0.manager.shared(), &self.edge);
2549 drop(local_guard);
2550 res
2551 }
2552
2553 fn with_manager_exclusive<F, T>(&self, f: F) -> T
2554 where
2555 F: for<'id> FnOnce(&mut Self::Manager<'id>, &EdgeOfFunc<'id, Self>) -> T,
2556 {
2557 let local_guard = self.store.0.prepare_local_state();
2558 let res = f(&mut self.store.0.manager.exclusive(), &self.edge);
2559 drop(local_guard);
2560 res
2561 }
2562}
2563
2564#[derive(Default, Clone, PartialEq, Eq)]
2571pub struct NodeSet {
2572 len: usize,
2573 data: FixedBitSet,
2574}
2575
2576impl<'id, N: NodeBase, ET: Tag> oxidd_core::util::NodeSet<Edge<'id, N, ET>> for NodeSet {
2577 #[inline(always)]
2578 fn len(&self) -> usize {
2579 self.len
2580 }
2581
2582 #[inline]
2583 fn insert(&mut self, edge: &Edge<'id, N, ET>) -> bool {
2584 let index = edge.node_id();
2585 if index < self.data.len() && self.data.contains(index) {
2586 return false;
2587 }
2588 self.data.grow_and_insert(index);
2589 self.len += 1;
2590 true
2591 }
2592
2593 #[inline]
2594 fn contains(&self, edge: &Edge<'id, N, ET>) -> bool {
2595 let index = edge.node_id();
2596 if index < self.data.len() {
2597 self.data.contains(index)
2598 } else {
2599 false
2600 }
2601 }
2602
2603 #[inline]
2604 fn remove(&mut self, edge: &Edge<'id, N, ET>) -> bool {
2605 let index = edge.node_id();
2606 if index < self.data.len() && self.data.contains(index) {
2607 self.len -= 1;
2608 self.data.remove(index);
2609 true
2610 } else {
2611 false
2612 }
2613 }
2614}
2615
2616impl<
2619 'id,
2620 N: NodeBase + InnerNode<Edge<'id, N, ET>>,
2621 ET: Tag,
2622 TM: TerminalManager<'id, N, ET, TERMINALS>,
2623 R: DiagramRules<Edge<'id, N, ET>, N, TM::TerminalNode>,
2624 MD: oxidd_core::HasApplyCache<Self, O> + ManagerEventSubscriber<Self> + DropWith<Edge<'id, N, ET>>,
2625 O: Copy,
2626 const TERMINALS: usize,
2627> oxidd_core::HasApplyCache<Self, O> for Manager<'id, N, ET, TM, R, MD, TERMINALS>
2628{
2629 type ApplyCache = MD::ApplyCache;
2630
2631 #[inline]
2632 fn apply_cache(&self) -> &Self::ApplyCache {
2633 self.data.apply_cache()
2634 }
2635
2636 #[inline]
2637 fn apply_cache_mut(&mut self) -> &mut Self::ApplyCache {
2638 self.data.apply_cache_mut()
2639 }
2640}
2641
2642impl<'id, T, N, ET, TM, R, MD, const TERMINALS: usize> AsRef<T>
2643 for Manager<'id, N, ET, TM, R, MD, TERMINALS>
2644where
2645 N: NodeBase + InnerNode<Edge<'id, N, ET>>,
2646 ET: Tag,
2647 TM: TerminalManager<'id, N, ET, TERMINALS>,
2648 MD: DropWith<Edge<'id, N, ET>> + AsRef<T>,
2649{
2650 #[inline(always)]
2651 fn as_ref(&self) -> &T {
2652 self.data.as_ref()
2653 }
2654}
2655
2656impl<'id, T, N, ET, TM, R, MD, const TERMINALS: usize> AsMut<T>
2657 for Manager<'id, N, ET, TM, R, MD, TERMINALS>
2658where
2659 N: NodeBase + InnerNode<Edge<'id, N, ET>>,
2660 ET: Tag,
2661 TM: TerminalManager<'id, N, ET, TERMINALS>,
2662 MD: DropWith<Edge<'id, N, ET>> + AsMut<T>,
2663{
2664 #[inline(always)]
2665 fn as_mut(&mut self) -> &mut T {
2666 self.data.as_mut()
2667 }
2668}