oxidd_manager_index/node/
fixed_arity.rs1use std::cell::UnsafeCell;
2use std::hash::Hash;
3use std::hash::Hasher;
4use std::mem::MaybeUninit;
5use std::sync::atomic::AtomicU32;
6use std::sync::atomic::Ordering::{self, Relaxed, Release};
7
8use oxidd_core::AtomicLevelNo;
9use oxidd_core::Edge;
10use oxidd_core::HasLevel;
11use oxidd_core::InnerNode;
12use oxidd_core::LevelNo;
13use oxidd_core::Tag;
14use oxidd_core::util::Borrowed;
15use oxidd_core::util::BorrowedEdgeIter;
16use oxidd_core::util::DropWith;
17
18use crate::manager;
19use crate::manager::InnerNodeCons;
20
21use super::NodeBase;
22
23pub struct NodeWithLevel<'id, ET, const ARITY: usize> {
24 rc: AtomicU32,
25 level: AtomicLevelNo,
26 children: UnsafeCell<[manager::Edge<'id, Self, ET>; ARITY]>,
27}
28
29impl<'id, ET: Tag, const ARITY: usize> NodeWithLevel<'id, ET, ARITY> {
30 const UNINIT_EDGE: MaybeUninit<manager::Edge<'id, Self, ET>> = MaybeUninit::uninit();
31}
32
33impl<ET: Tag, const ARITY: usize> PartialEq for NodeWithLevel<'_, ET, ARITY> {
34 #[inline(always)]
35 fn eq(&self, other: &Self) -> bool {
36 unsafe { *self.children.get() == *other.children.get() }
38 }
39}
40impl<ET: Tag, const ARITY: usize> Eq for NodeWithLevel<'_, ET, ARITY> {}
41
42impl<ET: Tag, const ARITY: usize> Hash for NodeWithLevel<'_, ET, ARITY> {
43 #[inline(always)]
44 fn hash<H: Hasher>(&self, state: &mut H) {
45 unsafe { &*self.children.get() }.hash(state);
47 }
48}
49
50unsafe impl<ET: Tag, const ARITY: usize> NodeBase for NodeWithLevel<'_, ET, ARITY> {
58 #[inline(always)]
59 fn retain(&self) {
60 if self.rc.fetch_add(1, Relaxed) > (u32::MAX >> 1) {
61 std::process::abort();
62 }
63 }
64
65 #[inline(always)]
66 unsafe fn release(&self) -> usize {
67 self.rc.fetch_sub(1, Release) as usize
68 }
69
70 #[inline(always)]
71 fn load_rc(&self, order: Ordering) -> usize {
72 self.rc.load(order) as usize
73 }
74
75 #[inline(always)]
76 fn needs_drop() -> bool {
77 false
78 }
79}
80
81impl<'id, ET: Tag, const ARITY: usize> DropWith<manager::Edge<'id, Self, ET>>
82 for NodeWithLevel<'id, ET, ARITY>
83{
84 #[inline]
85 fn drop_with(self, drop_edge: impl Fn(manager::Edge<'id, Self, ET>)) {
86 for c in self.children.into_inner() {
87 drop_edge(c);
88 }
89 }
90}
91
92impl<'id, ET: Tag, const ARITY: usize> InnerNode<manager::Edge<'id, Self, ET>>
93 for NodeWithLevel<'id, ET, ARITY>
94{
95 const ARITY: usize = ARITY;
96
97 type ChildrenIter<'a>
98 = BorrowedEdgeIter<
99 'a,
100 manager::Edge<'id, Self, ET>,
101 std::slice::Iter<'a, manager::Edge<'id, Self, ET>>,
102 >
103 where
104 Self: 'a;
105
106 #[inline(always)]
107 fn new(
108 level: LevelNo,
109 children: impl IntoIterator<Item = manager::Edge<'id, Self, ET>>,
110 ) -> Self {
111 let mut it = children.into_iter();
112 let mut children = [Self::UNINIT_EDGE; ARITY];
113
114 for slot in &mut children {
115 slot.write(it.next().unwrap());
116 }
117 debug_assert!(it.next().is_none());
118
119 let children = unsafe {
127 std::ptr::read((&raw const children).cast::<[manager::Edge<'id, Self, ET>; ARITY]>())
128 };
129
130 Self {
131 rc: AtomicU32::new(2),
132 level: AtomicLevelNo::new(level),
133 children: UnsafeCell::new(children),
134 }
135 }
136
137 #[inline(always)]
138 fn check_level(&self, check: impl FnOnce(LevelNo) -> bool) -> bool {
139 check(self.level.load(Relaxed))
140 }
141 #[inline(always)]
142 #[track_caller]
143 fn assert_level_matches(&self, level: LevelNo) {
144 assert_eq!(
145 self.level.load(Relaxed),
146 level,
147 "the level number does not match"
148 );
149 }
150
151 #[inline(always)]
152 fn children(&self) -> Self::ChildrenIter<'_> {
153 BorrowedEdgeIter::from(unsafe { &*self.children.get() }.iter())
155 }
156
157 #[inline(always)]
158 fn child(&self, n: usize) -> Borrowed<'_, manager::Edge<'id, Self, ET>> {
159 let children = unsafe { &*self.children.get() };
161 children[n].borrowed()
162 }
163
164 #[inline(always)]
165 unsafe fn set_child(
166 &self,
167 n: usize,
168 child: manager::Edge<'id, Self, ET>,
169 ) -> manager::Edge<'id, Self, ET> {
170 let children = unsafe { &mut *self.children.get() };
173 std::mem::replace(&mut children[n], child)
174 }
175
176 #[inline(always)]
177 fn ref_count(&self) -> usize {
178 (self.rc.load(Relaxed) - 1) as usize
180 }
181}
182
183unsafe impl<ET, const ARITY: usize> HasLevel for NodeWithLevel<'_, ET, ARITY> {
184 #[inline(always)]
185 fn level(&self) -> LevelNo {
186 self.level.load(Relaxed)
187 }
188
189 #[inline(always)]
190 unsafe fn set_level(&self, level: LevelNo) {
191 self.level.store(level, Relaxed);
192 }
193}
194
195unsafe impl<ET: Send + Sync, const ARITY: usize> Send for NodeWithLevel<'_, ET, ARITY> {}
196unsafe impl<ET: Send + Sync, const ARITY: usize> Sync for NodeWithLevel<'_, ET, ARITY> {}
197
198pub struct NodeWithLevelCons<const ARITY: usize>;
199impl<ET: Tag + Send + Sync, const ARITY: usize> InnerNodeCons<ET> for NodeWithLevelCons<ARITY> {
200 type T<'id> = NodeWithLevel<'id, ET, ARITY>;
201}