1use crate::games::go::util::OptionU16;
4use std::collections::HashSet;
5
6#[derive(Debug, Clone)]
11pub struct LinkHead {
12 pub first: OptionU16,
13 pub last: OptionU16,
15 len: u16,
16}
17
18#[derive(Debug, Clone)]
20pub struct LinkNode {
21 pub prev: OptionU16,
22 pub next: OptionU16,
23}
24
25pub trait Linked {
29 fn link(&self) -> &LinkNode;
30 fn link_mut(&mut self) -> &mut LinkNode;
31}
32
33impl LinkHead {
34 pub fn empty() -> Self {
35 Self::full(0)
36 }
37
38 pub fn single(index: u16) -> Self {
40 LinkHead {
41 first: OptionU16::Some(index),
42 last: OptionU16::Some(index),
43 len: 1,
44 }
45 }
46
47 pub fn full(len: u16) -> Self {
49 if len == 0 {
50 LinkHead {
51 first: OptionU16::None,
52 last: OptionU16::None,
53 len: 0,
54 }
55 } else {
56 LinkHead {
57 first: OptionU16::Some(0),
58 last: OptionU16::Some(len - 1),
59 len,
60 }
61 }
62 }
63
64 pub fn pop_front(&mut self, storage: &mut [impl Linked]) -> OptionU16 {
65 let first_id = match self.first.to_option() {
66 None => return OptionU16::None,
67 Some(first_id) => first_id,
68 };
69
70 let first = &mut storage[first_id as usize].link_mut();
71 let next_id = first.next;
72
73 debug_assert_eq!(first.prev, OptionU16::None);
75 first.next = OptionU16::None;
76
77 self.first = next_id;
79 self.len -= 1;
80 match next_id.to_option() {
81 None => self.last = next_id,
82 Some(next) => storage[next as usize].link_mut().prev = OptionU16::None,
83 }
84
85 OptionU16::Some(first_id)
86 }
87
88 pub fn insert_front(&mut self, index: u16, storage: &mut [impl Linked]) {
89 let mut other = LinkHead::single(index);
90 self.splice_front_take(&mut other, storage);
91 debug_assert!(other.is_empty());
92 }
93
94 pub fn splice_front_take(&mut self, other: &mut LinkHead, storage: &mut [impl Linked]) {
95 if let Some(other_last) = other.last.to_option() {
97 storage[other_last as usize].link_mut().next = self.first;
98 }
99 if let Some(self_first) = self.first.to_option() {
100 storage[self_first as usize].link_mut().prev = other.last;
101 }
102
103 let new_head = LinkHead {
105 first: other.first.or(self.first),
106 last: self.last.or(other.last),
107 len: self.len + other.len,
108 };
109
110 *self = new_head;
112 *other = LinkHead::empty();
113 }
114
115 pub fn remove(&mut self, index: u16, storage: &mut [impl Linked]) {
116 let node = storage[index as usize].link_mut();
117 let prev = node.prev.take();
118 let next = node.next.take();
119
120 match prev.to_option() {
121 None => self.first = next,
122 Some(prev) => storage[prev as usize].link_mut().next = next,
123 }
124 match next.to_option() {
125 None => self.last = prev,
126 Some(next) => storage[next as usize].link_mut().prev = prev,
127 }
128
129 self.len -= 1;
130 }
131
132 pub fn len(&self) -> u16 {
133 self.len
134 }
135
136 pub fn is_empty(&self) -> bool {
137 self.len() == 0
138 }
139
140 pub fn iter<'s, L: Linked>(&self, storage: &'s [L]) -> LinkIterator<'s, L> {
141 LinkIterator::new(self, storage)
142 }
143
144 pub fn for_each_mut<L: Linked>(&self, storage: &mut [L], mut f: impl FnMut(&mut [L], u16)) {
146 let mut next = self.first;
147 let mut prev = OptionU16::None;
148 while let Some(curr) = next.to_option() {
149 let link = storage[curr as usize].link();
150 debug_assert_eq!(prev, link.prev);
151 prev = OptionU16::Some(curr);
152
153 next = link.next;
154 f(storage, curr);
155 }
156 }
157
158 pub fn assert_valid_and_collect(&self, storage: &[impl Linked]) -> HashSet<u16> {
161 let mut seen = HashSet::new();
162
163 match self.first.to_option() {
164 None => assert_eq!(OptionU16::None, self.last, "Wrong last: start |-> end"),
165 Some(first) => assert_eq!(
166 OptionU16::None,
167 storage[first as usize].link().prev,
168 "Wrong prev: start |-> {}",
169 first
170 ),
171 }
172
173 let mut next = self.first;
174 while let Some(curr) = next.to_option() {
175 let inserted = seen.insert(curr);
176 assert!(inserted, "Empty linked list contains loop including {}", curr);
177
178 next = storage[curr as usize].link().next;
179 match next.to_option() {
180 None => assert_eq!(OptionU16::Some(curr), self.last, "Wrong last: {} |-> end", curr),
181 Some(next) => assert_eq!(
182 OptionU16::Some(curr),
183 storage[next as usize].link().prev,
184 "Wrong prev: {} |-> {}",
185 curr,
186 next
187 ),
188 }
189 }
190
191 assert_eq!(seen.len(), self.len as usize);
192 seen
193 }
194
195 pub fn map_index(&self, mut f: impl FnMut(u16) -> u16) -> Self {
196 LinkHead {
197 first: self.first.map(&mut f),
198 last: self.last.map(&mut f),
199 len: self.len,
200 }
201 }
202}
203
204impl LinkNode {
205 pub fn single() -> Self {
206 LinkNode {
207 prev: OptionU16::None,
208 next: OptionU16::None,
209 }
210 }
211
212 pub fn full(len: u16, index: u16) -> Self {
213 LinkNode {
214 prev: if index > 0 {
215 OptionU16::Some(index - 1)
216 } else {
217 OptionU16::None
218 },
219 next: if index + 1 < len {
220 OptionU16::Some(index + 1)
221 } else {
222 OptionU16::None
223 },
224 }
225 }
226
227 pub fn is_unconnected_or_single(&self) -> bool {
228 self.prev.is_none() && self.next.is_none()
229 }
230
231 pub fn map_index(&self, mut f: impl FnMut(u16) -> u16) -> Self {
232 LinkNode {
233 prev: self.prev.map(&mut f),
234 next: self.next.map(&mut f),
235 }
236 }
237}
238
239#[derive(Debug)]
240pub struct LinkIterator<'s, L: Linked> {
241 storage: &'s [L],
242 next: OptionU16,
243 items_left: u16,
244}
245
246impl<'s, L: Linked> LinkIterator<'s, L> {
247 pub fn new(head: &LinkHead, storage: &'s [L]) -> Self {
248 Self {
249 storage,
250 next: head.first,
251 items_left: head.len,
252 }
253 }
254}
255
256impl<'s, L: Linked> Iterator for LinkIterator<'s, L> {
257 type Item = u16;
258
259 fn next(&mut self) -> Option<Self::Item> {
260 match self.next.to_option() {
261 None => {
262 debug_assert_eq!(self.items_left, 0);
263 None
264 }
265 Some(index) => {
266 self.next = self.storage[index as usize].link().next;
267 self.items_left -= 1;
268 Some(index)
269 }
270 }
271 }
272
273 fn size_hint(&self) -> (usize, Option<usize>) {
274 (self.len(), Some(self.len()))
275 }
276
277 }
313
314impl<'s, L: Linked> ExactSizeIterator for LinkIterator<'s, L> {
315 fn len(&self) -> usize {
316 self.items_left as usize
317 }
318}