/rust/registry/src/index.crates.io-1949cf8c6b5b557f/moka-0.12.15/src/common/deque.rs
Line | Count | Source |
1 | | // License and Copyright Notice: |
2 | | // |
3 | | // Some of the code and doc comments in this module were copied from |
4 | | // `std::collections::LinkedList` in the Rust standard library. |
5 | | // https://github.com/rust-lang/rust/blob/master/src/liballoc/collections/linked_list.rs |
6 | | // |
7 | | // The original code/comments from LinkedList are dual-licensed under |
8 | | // the Apache License, Version 2.0 <https://github.com/rust-lang/rust/blob/master/LICENSE-APACHE> |
9 | | // or the MIT license <https://github.com/rust-lang/rust/blob/master/LICENSE-MIT> |
10 | | // |
11 | | // Copyrights of the original code/comments are retained by their contributors. |
12 | | // For full authorship information, see the version control history of |
13 | | // https://github.com/rust-lang/rust/ or https://thanks.rust-lang.org |
14 | | |
15 | | use std::{marker::PhantomData, ptr::NonNull}; |
16 | | |
17 | | use super::CacheRegion; |
18 | | |
19 | | #[cfg(feature = "unstable-debug-counters")] |
20 | | use crate::common::concurrent::debug_counters; |
21 | | |
22 | | // `crate::{sync,unsync}::DeqNodes` uses a `tagptr::TagNonNull<DeqNode<T>, 2>` |
23 | | // pointer. To reserve the space for the 2-bit tag, use 4 bytes as the *minimum* |
24 | | // alignment. |
25 | | // https://doc.rust-lang.org/reference/type-layout.html#the-alignment-modifiers |
26 | | #[repr(align(4))] |
27 | | #[derive(PartialEq, Eq)] |
28 | | pub(crate) struct DeqNode<T> { |
29 | | next: Option<NonNull<DeqNode<T>>>, |
30 | | prev: Option<NonNull<DeqNode<T>>>, |
31 | | pub(crate) element: T, |
32 | | } |
33 | | |
34 | | impl<T> std::fmt::Debug for DeqNode<T> { |
35 | 0 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
36 | 0 | f.debug_struct("DeqNode") |
37 | 0 | .field("next", &self.next) |
38 | 0 | .field("prev", &self.prev) |
39 | 0 | .finish() |
40 | 0 | } Unexecuted instantiation: <moka::common::deque::DeqNode<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>> as core::fmt::Debug>::fmt Unexecuted instantiation: <moka::common::deque::DeqNode<_> as core::fmt::Debug>::fmt |
41 | | } |
42 | | |
43 | | impl<T> DeqNode<T> { |
44 | 0 | pub(crate) fn new(element: T) -> Self { |
45 | | #[cfg(feature = "unstable-debug-counters")] |
46 | | debug_counters::InternalGlobalDebugCounters::deq_node_created(); |
47 | | |
48 | 0 | Self { |
49 | 0 | next: None, |
50 | 0 | prev: None, |
51 | 0 | element, |
52 | 0 | } |
53 | 0 | } Unexecuted instantiation: <moka::common::deque::DeqNode<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::new Unexecuted instantiation: <moka::common::deque::DeqNode<moka::common::timer_wheel::TimerNode<hickory_proto::op::query::Query>>>::new Unexecuted instantiation: <moka::common::deque::DeqNode<_>>::new |
54 | | |
55 | 0 | pub(crate) fn next_node_ptr(this: NonNull<Self>) -> Option<NonNull<DeqNode<T>>> { |
56 | 0 | unsafe { this.as_ref() }.next |
57 | 0 | } Unexecuted instantiation: <moka::common::deque::DeqNode<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::next_node_ptr Unexecuted instantiation: <moka::common::deque::DeqNode<_>>::next_node_ptr |
58 | | } |
59 | | |
60 | | #[cfg(feature = "unstable-debug-counters")] |
61 | | impl<T> Drop for DeqNode<T> { |
62 | | fn drop(&mut self) { |
63 | | debug_counters::InternalGlobalDebugCounters::deq_node_dropped(); |
64 | | } |
65 | | } |
66 | | |
67 | | /// Cursor is used to remember the current iterating position. |
68 | | enum DeqCursor<T> { |
69 | | Node(NonNull<DeqNode<T>>), |
70 | | Done, |
71 | | } |
72 | | |
73 | | pub(crate) struct Deque<T> { |
74 | | region: CacheRegion, |
75 | | len: usize, |
76 | | head: Option<NonNull<DeqNode<T>>>, |
77 | | tail: Option<NonNull<DeqNode<T>>>, |
78 | | cursor: Option<DeqCursor<T>>, |
79 | | marker: PhantomData<Box<DeqNode<T>>>, |
80 | | } |
81 | | |
82 | | impl<T> Drop for Deque<T> { |
83 | 0 | fn drop(&mut self) { |
84 | | struct DropGuard<'a, T>(&'a mut Deque<T>); |
85 | | |
86 | | impl<T> Drop for DropGuard<'_, T> { |
87 | 0 | fn drop(&mut self) { |
88 | | // Continue the same loop we do below. This only runs when a destructor has |
89 | | // panicked. If another one panics this will abort. |
90 | 0 | while self.0.pop_front().is_some() {} |
91 | 0 | } Unexecuted instantiation: <<moka::common::deque::Deque<_> as core::ops::drop::Drop>::drop::DropGuard<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>> as core::ops::drop::Drop>::drop Unexecuted instantiation: <<moka::common::deque::Deque<_> as core::ops::drop::Drop>::drop::DropGuard<moka::common::timer_wheel::TimerNode<hickory_proto::op::query::Query>> as core::ops::drop::Drop>::drop Unexecuted instantiation: <<moka::common::deque::Deque<_> as core::ops::drop::Drop>::drop::DropGuard<_> as core::ops::drop::Drop>::drop |
92 | | } |
93 | | |
94 | 0 | while let Some(node) = self.pop_front() { |
95 | 0 | let guard = DropGuard(self); |
96 | 0 | drop(node); |
97 | 0 | std::mem::forget(guard); |
98 | 0 | } |
99 | 0 | } Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>> as core::ops::drop::Drop>::drop Unexecuted instantiation: <moka::common::deque::Deque<moka::common::timer_wheel::TimerNode<hickory_proto::op::query::Query>> as core::ops::drop::Drop>::drop Unexecuted instantiation: <moka::common::deque::Deque<_> as core::ops::drop::Drop>::drop |
100 | | } |
101 | | |
102 | | // Inner crate public function/methods |
103 | | impl<T> Deque<T> { |
104 | 0 | pub(crate) fn new(region: CacheRegion) -> Self { |
105 | 0 | Self { |
106 | 0 | region, |
107 | 0 | len: 0, |
108 | 0 | head: None, |
109 | 0 | tail: None, |
110 | 0 | cursor: None, |
111 | 0 | marker: PhantomData, |
112 | 0 | } |
113 | 0 | } Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::new Unexecuted instantiation: <moka::common::deque::Deque<moka::common::timer_wheel::TimerNode<hickory_proto::op::query::Query>>>::new Unexecuted instantiation: <moka::common::deque::Deque<_>>::new |
114 | | |
115 | 0 | pub(crate) fn region(&self) -> CacheRegion { |
116 | 0 | self.region |
117 | 0 | } Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::region Unexecuted instantiation: <moka::common::deque::Deque<_>>::region |
118 | | |
119 | 0 | pub(crate) fn len(&self) -> usize { |
120 | 0 | self.len |
121 | 0 | } Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::len Unexecuted instantiation: <moka::common::deque::Deque<_>>::len |
122 | | |
123 | 0 | pub(crate) fn contains(&self, node: &DeqNode<T>) -> bool { |
124 | 0 | node.prev.is_some() || self.is_head(node) |
125 | 0 | } Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::contains Unexecuted instantiation: <moka::common::deque::Deque<_>>::contains |
126 | | |
127 | 0 | pub(crate) fn peek_front(&self) -> Option<&DeqNode<T>> { |
128 | 0 | self.head.as_ref().map(|node| unsafe { node.as_ref() })Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::peek_front::{closure#0}Unexecuted instantiation: <moka::common::deque::Deque<moka::common::timer_wheel::TimerNode<hickory_proto::op::query::Query>>>::peek_front::{closure#0}Unexecuted instantiation: <moka::common::deque::Deque<_>>::peek_front::{closure#0} |
129 | 0 | } Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::peek_front Unexecuted instantiation: <moka::common::deque::Deque<moka::common::timer_wheel::TimerNode<hickory_proto::op::query::Query>>>::peek_front Unexecuted instantiation: <moka::common::deque::Deque<_>>::peek_front |
130 | | |
131 | 0 | pub(crate) fn peek_front_ptr(&self) -> Option<NonNull<DeqNode<T>>> { |
132 | 0 | self.head.as_ref().copied() |
133 | 0 | } Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::peek_front_ptr Unexecuted instantiation: <moka::common::deque::Deque<_>>::peek_front_ptr |
134 | | |
135 | | /// Removes and returns the node at the front of the list. |
136 | 0 | pub(crate) fn pop_front(&mut self) -> Option<Box<DeqNode<T>>> { |
137 | | // This method takes care not to create mutable references to whole nodes, |
138 | | // to maintain validity of aliasing pointers into `element`. |
139 | 0 | self.head.map(|node| unsafe { |
140 | 0 | if self.is_at_cursor(node.as_ref()) { |
141 | 0 | self.advance_cursor(); |
142 | 0 | } |
143 | | |
144 | 0 | let mut node = Box::from_raw(node.as_ptr()); |
145 | 0 | self.head = node.next; |
146 | | |
147 | 0 | match self.head { |
148 | 0 | None => self.tail = None, |
149 | | // Not creating new mutable (unique!) references overlapping `element`. |
150 | 0 | Some(head) => (*head.as_ptr()).prev = None, |
151 | | } |
152 | | |
153 | 0 | self.len -= 1; |
154 | | |
155 | 0 | node.prev = None; |
156 | 0 | node.next = None; |
157 | 0 | node |
158 | 0 | }) Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::pop_front::{closure#0}Unexecuted instantiation: <moka::common::deque::Deque<moka::common::timer_wheel::TimerNode<hickory_proto::op::query::Query>>>::pop_front::{closure#0}Unexecuted instantiation: <moka::common::deque::Deque<_>>::pop_front::{closure#0} |
159 | 0 | } Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::pop_front Unexecuted instantiation: <moka::common::deque::Deque<moka::common::timer_wheel::TimerNode<hickory_proto::op::query::Query>>>::pop_front Unexecuted instantiation: <moka::common::deque::Deque<_>>::pop_front |
160 | | |
161 | 0 | pub(crate) fn peek_back(&self) -> Option<&DeqNode<T>> { |
162 | 0 | self.tail.as_ref().map(|node| unsafe { node.as_ref() })Unexecuted instantiation: <moka::common::deque::Deque<moka::common::timer_wheel::TimerNode<hickory_proto::op::query::Query>>>::peek_back::{closure#0}Unexecuted instantiation: <moka::common::deque::Deque<_>>::peek_back::{closure#0} |
163 | 0 | } Unexecuted instantiation: <moka::common::deque::Deque<moka::common::timer_wheel::TimerNode<hickory_proto::op::query::Query>>>::peek_back Unexecuted instantiation: <moka::common::deque::Deque<_>>::peek_back |
164 | | |
165 | | /// Adds the given node to the back of the list. |
166 | 0 | pub(crate) fn push_back(&mut self, mut node: Box<DeqNode<T>>) -> NonNull<DeqNode<T>> { |
167 | | // This method takes care not to create mutable references to whole nodes, |
168 | | // to maintain validity of aliasing pointers into `element`. |
169 | | unsafe { |
170 | 0 | node.next = None; |
171 | 0 | node.prev = self.tail; |
172 | 0 | let node = NonNull::new(Box::into_raw(node)).expect("Got a null ptr"); |
173 | | |
174 | 0 | match self.tail { |
175 | 0 | None => self.head = Some(node), |
176 | | // Not creating new mutable (unique!) references overlapping `element`. |
177 | 0 | Some(tail) => (*tail.as_ptr()).next = Some(node), |
178 | | } |
179 | | |
180 | 0 | self.tail = Some(node); |
181 | 0 | self.len += 1; |
182 | 0 | node |
183 | | } |
184 | 0 | } Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::push_back Unexecuted instantiation: <moka::common::deque::Deque<moka::common::timer_wheel::TimerNode<hickory_proto::op::query::Query>>>::push_back Unexecuted instantiation: <moka::common::deque::Deque<_>>::push_back |
185 | | |
186 | 0 | pub(crate) unsafe fn move_to_back(&mut self, mut node: NonNull<DeqNode<T>>) { |
187 | 0 | if self.is_tail(node.as_ref()) { |
188 | | // Already at the tail. Nothing to do. |
189 | 0 | return; |
190 | 0 | } |
191 | | |
192 | 0 | if self.is_at_cursor(node.as_ref()) { |
193 | 0 | self.advance_cursor(); |
194 | 0 | } |
195 | | |
196 | | // Extract the prev and next pointers before we start modifying the node |
197 | 0 | let (prev, next) = { |
198 | 0 | let node_ref = node.as_ref(); |
199 | 0 | (node_ref.prev, node_ref.next) |
200 | 0 | }; |
201 | | |
202 | | // Not creating new mutable (unique!) references overlapping `element`. |
203 | 0 | match prev { |
204 | 0 | Some(prev_node) if next.is_some() => (*prev_node.as_ptr()).next = next, |
205 | 0 | Some(..) => (), |
206 | | // This node is the head node. |
207 | 0 | None => self.head = next, |
208 | | }; |
209 | | |
210 | | // This node is not the tail node. |
211 | 0 | if let Some(next_node) = next { |
212 | 0 | (*next_node.as_ptr()).prev = prev; |
213 | | |
214 | | // Update the node's pointers directly without creating conflicting references |
215 | 0 | let node_mut = node.as_mut(); |
216 | 0 | node_mut.prev = self.tail; |
217 | 0 | node_mut.next = None; |
218 | | |
219 | 0 | match self.tail { |
220 | | // Not creating new mutable (unique!) references overlapping `element`. |
221 | 0 | Some(tail) => (*tail.as_ptr()).next = Some(node), |
222 | 0 | None => unreachable!(), |
223 | | } |
224 | 0 | self.tail = Some(node); |
225 | 0 | } |
226 | 0 | } Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::move_to_back Unexecuted instantiation: <moka::common::deque::Deque<moka::common::timer_wheel::TimerNode<hickory_proto::op::query::Query>>>::move_to_back Unexecuted instantiation: <moka::common::deque::Deque<_>>::move_to_back |
227 | | |
228 | 0 | pub(crate) fn move_front_to_back(&mut self) { |
229 | 0 | if let Some(node) = self.head { |
230 | 0 | unsafe { self.move_to_back(node) }; |
231 | 0 | } |
232 | 0 | } Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::move_front_to_back Unexecuted instantiation: <moka::common::deque::Deque<moka::common::timer_wheel::TimerNode<hickory_proto::op::query::Query>>>::move_front_to_back Unexecuted instantiation: <moka::common::deque::Deque<_>>::move_front_to_back |
233 | | |
234 | | /// Unlinks the specified node from the current list. |
235 | | /// |
236 | | /// This method takes care not to create mutable references to `element`, to |
237 | | /// maintain validity of aliasing pointers. |
238 | | /// |
239 | | /// IMPORTANT: This method does not drop the node. If the node is no longer |
240 | | /// needed, use `unlink_and_drop` instead, or drop it at the caller side. |
241 | | /// Otherwise, the node will leak. |
242 | 0 | pub(crate) unsafe fn unlink(&mut self, mut node: NonNull<DeqNode<T>>) { |
243 | 0 | if self.is_at_cursor(node.as_ref()) { |
244 | 0 | self.advance_cursor(); |
245 | 0 | } |
246 | | |
247 | 0 | let node = node.as_mut(); // this one is ours now, we can create an &mut. |
248 | | |
249 | | // Not creating new mutable (unique!) references overlapping `element`. |
250 | 0 | match node.prev { |
251 | 0 | Some(prev) => (*prev.as_ptr()).next = node.next, |
252 | | // this node is the head node |
253 | 0 | None => self.head = node.next, |
254 | | }; |
255 | | |
256 | 0 | match node.next { |
257 | 0 | Some(next) => (*next.as_ptr()).prev = node.prev, |
258 | | // this node is the tail node |
259 | 0 | None => self.tail = node.prev, |
260 | | }; |
261 | | |
262 | 0 | node.prev = None; |
263 | 0 | node.next = None; |
264 | | |
265 | 0 | self.len -= 1; |
266 | 0 | } Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::unlink Unexecuted instantiation: <moka::common::deque::Deque<moka::common::timer_wheel::TimerNode<hickory_proto::op::query::Query>>>::unlink Unexecuted instantiation: <moka::common::deque::Deque<_>>::unlink |
267 | | |
268 | | /// Unlinks the specified node from the current list, and then drop the node. |
269 | | /// |
270 | | /// This method takes care not to create mutable references to `element`, to |
271 | | /// maintain validity of aliasing pointers. |
272 | | /// |
273 | | /// Panics: |
274 | 0 | pub(crate) unsafe fn unlink_and_drop(&mut self, node: NonNull<DeqNode<T>>) { |
275 | 0 | self.unlink(node); |
276 | 0 | std::mem::drop(Box::from_raw(node.as_ptr())); |
277 | 0 | } Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::unlink_and_drop Unexecuted instantiation: <moka::common::deque::Deque<_>>::unlink_and_drop |
278 | | |
279 | 0 | pub(crate) fn reset_cursor(&mut self) { |
280 | 0 | self.cursor = None; |
281 | 0 | } Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::reset_cursor Unexecuted instantiation: <moka::common::deque::Deque<_>>::reset_cursor |
282 | | } |
283 | | |
284 | | impl<'a, T> Iterator for &'a mut Deque<T> { |
285 | | type Item = &'a T; |
286 | | |
287 | 0 | fn next(&mut self) -> Option<Self::Item> { |
288 | 0 | if self.cursor.is_none() { |
289 | 0 | if let Some(head) = self.head { |
290 | 0 | self.cursor = Some(DeqCursor::Node(head)); |
291 | 0 | } |
292 | 0 | } |
293 | 0 | let elem = if let Some(DeqCursor::Node(node)) = self.cursor { |
294 | 0 | unsafe { Some(&(*node.as_ptr()).element) } |
295 | | } else { |
296 | 0 | None |
297 | | }; |
298 | 0 | self.advance_cursor(); |
299 | 0 | elem |
300 | 0 | } Unexecuted instantiation: <&mut moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>> as core::iter::traits::iterator::Iterator>::next Unexecuted instantiation: <&mut moka::common::deque::Deque<_> as core::iter::traits::iterator::Iterator>::next |
301 | | } |
302 | | |
303 | | // Private function/methods |
304 | | impl<T> Deque<T> { |
305 | 0 | fn is_head(&self, node: &DeqNode<T>) -> bool { |
306 | 0 | if let Some(head) = self.head { |
307 | 0 | std::ptr::eq(unsafe { head.as_ref() }, node) |
308 | | } else { |
309 | 0 | false |
310 | | } |
311 | 0 | } Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::is_head Unexecuted instantiation: <moka::common::deque::Deque<_>>::is_head |
312 | | |
313 | 0 | fn is_tail(&self, node: &DeqNode<T>) -> bool { |
314 | 0 | if let Some(tail) = self.tail { |
315 | 0 | std::ptr::eq(unsafe { tail.as_ref() }, node) |
316 | | } else { |
317 | 0 | false |
318 | | } |
319 | 0 | } Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::is_tail Unexecuted instantiation: <moka::common::deque::Deque<moka::common::timer_wheel::TimerNode<hickory_proto::op::query::Query>>>::is_tail Unexecuted instantiation: <moka::common::deque::Deque<_>>::is_tail |
320 | | |
321 | 0 | fn is_at_cursor(&self, node: &DeqNode<T>) -> bool { |
322 | 0 | if let Some(DeqCursor::Node(cur_node)) = self.cursor { |
323 | 0 | std::ptr::eq(unsafe { cur_node.as_ref() }, node) |
324 | | } else { |
325 | 0 | false |
326 | | } |
327 | 0 | } Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::is_at_cursor Unexecuted instantiation: <moka::common::deque::Deque<moka::common::timer_wheel::TimerNode<hickory_proto::op::query::Query>>>::is_at_cursor Unexecuted instantiation: <moka::common::deque::Deque<_>>::is_at_cursor |
328 | | |
329 | 0 | fn advance_cursor(&mut self) { |
330 | 0 | match self.cursor.take() { |
331 | 0 | None => (), |
332 | 0 | Some(DeqCursor::Node(node)) => unsafe { |
333 | 0 | if let Some(next) = (*node.as_ptr()).next { |
334 | 0 | self.cursor = Some(DeqCursor::Node(next)); |
335 | 0 | } else { |
336 | 0 | self.cursor = Some(DeqCursor::Done); |
337 | 0 | } |
338 | | }, |
339 | 0 | Some(DeqCursor::Done) => { |
340 | 0 | self.cursor = None; |
341 | 0 | } |
342 | | } |
343 | 0 | } Unexecuted instantiation: <moka::common::deque::Deque<moka::common::concurrent::KeyHashDate<hickory_proto::op::query::Query>>>::advance_cursor Unexecuted instantiation: <moka::common::deque::Deque<moka::common::timer_wheel::TimerNode<hickory_proto::op::query::Query>>>::advance_cursor Unexecuted instantiation: <moka::common::deque::Deque<_>>::advance_cursor |
344 | | } |
345 | | |
346 | | #[cfg(test)] |
347 | | mod tests { |
348 | | use super::{CacheRegion::MainProbation, DeqNode, Deque}; |
349 | | |
350 | | #[test] |
351 | | #[allow(clippy::cognitive_complexity)] |
352 | | fn basics() { |
353 | | let mut deque: Deque<String> = Deque::new(MainProbation); |
354 | | assert_eq!(deque.len(), 0); |
355 | | assert!(deque.peek_front().is_none()); |
356 | | assert!(deque.peek_back().is_none()); |
357 | | |
358 | | // push_back(node1) |
359 | | let node1 = DeqNode::new("a".to_string()); |
360 | | assert!(!deque.contains(&node1)); |
361 | | let node1 = Box::new(node1); |
362 | | let node1_ptr = deque.push_back(node1); |
363 | | assert_eq!(deque.len(), 1); |
364 | | |
365 | | // peek_front() -> node1 |
366 | | let head_a = deque.peek_front().unwrap(); |
367 | | assert!(deque.contains(head_a)); |
368 | | assert!(deque.is_head(head_a)); |
369 | | assert!(deque.is_tail(head_a)); |
370 | | assert_eq!(head_a.element, "a".to_string()); |
371 | | |
372 | | // move_to_back(node1) |
373 | | unsafe { deque.move_to_back(node1_ptr) }; |
374 | | assert_eq!(deque.len(), 1); |
375 | | |
376 | | // peek_front() -> node1 |
377 | | let head_b = deque.peek_front().unwrap(); |
378 | | assert!(deque.contains(head_b)); |
379 | | assert!(deque.is_head(head_b)); |
380 | | assert!(deque.is_tail(head_b)); |
381 | | assert!(std::ptr::eq(head_b, node1_ptr.as_ptr())); |
382 | | assert!(head_b.prev.is_none()); |
383 | | assert!(head_b.next.is_none()); |
384 | | |
385 | | // peek_back() -> node1 |
386 | | let tail_a = deque.peek_back().unwrap(); |
387 | | assert!(deque.contains(tail_a)); |
388 | | assert!(deque.is_head(tail_a)); |
389 | | assert!(deque.is_tail(tail_a)); |
390 | | assert!(std::ptr::eq(tail_a, node1_ptr.as_ptr())); |
391 | | assert!(tail_a.prev.is_none()); |
392 | | assert!(tail_a.next.is_none()); |
393 | | |
394 | | // push_back(node2) |
395 | | let node2 = DeqNode::new("b".to_string()); |
396 | | assert!(!deque.contains(&node2)); |
397 | | let node2_ptr = deque.push_back(Box::new(node2)); |
398 | | assert_eq!(deque.len(), 2); |
399 | | |
400 | | // peek_front() -> node1 |
401 | | let head_c = deque.peek_front().unwrap(); |
402 | | assert!(deque.contains(head_c)); |
403 | | assert!(deque.is_head(head_c)); |
404 | | assert!(!deque.is_tail(head_c)); |
405 | | assert!(std::ptr::eq(head_c, node1_ptr.as_ptr())); |
406 | | assert!(head_c.prev.is_none()); |
407 | | assert!(std::ptr::eq( |
408 | | head_c.next.unwrap().as_ptr(), |
409 | | node2_ptr.as_ptr() |
410 | | )); |
411 | | |
412 | | // move_to_back(node2) |
413 | | unsafe { deque.move_to_back(node2_ptr) }; |
414 | | assert_eq!(deque.len(), 2); |
415 | | |
416 | | // peek_front() -> node1 |
417 | | let head_d = deque.peek_front().unwrap(); |
418 | | assert!(deque.contains(head_d)); |
419 | | assert!(deque.is_head(head_d)); |
420 | | assert!(!deque.is_tail(head_d)); |
421 | | assert!(std::ptr::eq(head_d, node1_ptr.as_ptr())); |
422 | | assert!(head_d.prev.is_none()); |
423 | | assert!(std::ptr::eq( |
424 | | head_d.next.unwrap().as_ptr(), |
425 | | node2_ptr.as_ptr() |
426 | | )); |
427 | | |
428 | | // peek_back() -> node2 |
429 | | let tail_b = deque.peek_back().unwrap(); |
430 | | assert!(deque.contains(tail_b)); |
431 | | assert!(!deque.is_head(tail_b)); |
432 | | assert!(deque.is_tail(tail_b)); |
433 | | assert!(std::ptr::eq(tail_b, node2_ptr.as_ptr())); |
434 | | assert!(std::ptr::eq( |
435 | | tail_b.prev.unwrap().as_ptr(), |
436 | | node1_ptr.as_ptr() |
437 | | )); |
438 | | assert_eq!(tail_b.element, "b".to_string()); |
439 | | assert!(tail_b.next.is_none()); |
440 | | |
441 | | // move_to_back(node1) |
442 | | unsafe { deque.move_to_back(node1_ptr) }; |
443 | | assert_eq!(deque.len(), 2); |
444 | | |
445 | | // peek_front() -> node2 |
446 | | let head_e = deque.peek_front().unwrap(); |
447 | | assert!(deque.contains(head_e)); |
448 | | assert!(deque.is_head(head_e)); |
449 | | assert!(!deque.is_tail(head_e)); |
450 | | assert!(std::ptr::eq(head_e, node2_ptr.as_ptr())); |
451 | | assert!(head_e.prev.is_none()); |
452 | | assert!(std::ptr::eq( |
453 | | head_e.next.unwrap().as_ptr(), |
454 | | node1_ptr.as_ptr() |
455 | | )); |
456 | | |
457 | | // peek_back() -> node1 |
458 | | let tail_c = deque.peek_back().unwrap(); |
459 | | assert!(deque.contains(tail_c)); |
460 | | assert!(!deque.is_head(tail_c)); |
461 | | assert!(deque.is_tail(tail_c)); |
462 | | assert!(std::ptr::eq(tail_c, node1_ptr.as_ptr())); |
463 | | assert!(std::ptr::eq( |
464 | | tail_c.prev.unwrap().as_ptr(), |
465 | | node2_ptr.as_ptr() |
466 | | )); |
467 | | assert!(tail_c.next.is_none()); |
468 | | |
469 | | // push_back(node3) |
470 | | let node3 = DeqNode::new("c".to_string()); |
471 | | assert!(!deque.contains(&node3)); |
472 | | let node3_ptr = deque.push_back(Box::new(node3)); |
473 | | assert_eq!(deque.len(), 3); |
474 | | |
475 | | // peek_front() -> node2 |
476 | | let head_f = deque.peek_front().unwrap(); |
477 | | assert!(deque.contains(head_f)); |
478 | | assert!(deque.is_head(head_f)); |
479 | | assert!(!deque.is_tail(head_f)); |
480 | | assert!(std::ptr::eq(head_f, node2_ptr.as_ptr())); |
481 | | assert!(head_f.prev.is_none()); |
482 | | assert!(std::ptr::eq( |
483 | | head_f.next.unwrap().as_ptr(), |
484 | | node1_ptr.as_ptr() |
485 | | )); |
486 | | |
487 | | // peek_back() -> node3 |
488 | | let tail_d = deque.peek_back().unwrap(); |
489 | | assert!(std::ptr::eq(tail_d, node3_ptr.as_ptr())); |
490 | | assert_eq!(tail_d.element, "c".to_string()); |
491 | | assert!(deque.contains(tail_d)); |
492 | | assert!(!deque.is_head(tail_d)); |
493 | | assert!(deque.is_tail(tail_d)); |
494 | | assert!(std::ptr::eq(tail_d, node3_ptr.as_ptr())); |
495 | | assert!(std::ptr::eq( |
496 | | tail_d.prev.unwrap().as_ptr(), |
497 | | node1_ptr.as_ptr() |
498 | | )); |
499 | | assert!(tail_d.next.is_none()); |
500 | | |
501 | | // move_to_back(node1) |
502 | | unsafe { deque.move_to_back(node1_ptr) }; |
503 | | assert_eq!(deque.len(), 3); |
504 | | |
505 | | // peek_front() -> node2 |
506 | | let head_g = deque.peek_front().unwrap(); |
507 | | assert!(deque.contains(head_g)); |
508 | | assert!(deque.is_head(head_g)); |
509 | | assert!(!deque.is_tail(head_g)); |
510 | | assert!(std::ptr::eq(head_g, node2_ptr.as_ptr())); |
511 | | assert!(head_g.prev.is_none()); |
512 | | assert!(std::ptr::eq( |
513 | | head_g.next.unwrap().as_ptr(), |
514 | | node3_ptr.as_ptr() |
515 | | )); |
516 | | |
517 | | // peek_back() -> node1 |
518 | | let tail_e = deque.peek_back().unwrap(); |
519 | | assert!(deque.contains(tail_e)); |
520 | | assert!(!deque.is_head(tail_e)); |
521 | | assert!(deque.is_tail(tail_e)); |
522 | | assert!(std::ptr::eq(tail_e, node1_ptr.as_ptr())); |
523 | | assert!(std::ptr::eq( |
524 | | tail_e.prev.unwrap().as_ptr(), |
525 | | node3_ptr.as_ptr() |
526 | | )); |
527 | | assert!(tail_e.next.is_none()); |
528 | | |
529 | | // unlink(node3) |
530 | | unsafe { deque.unlink(node3_ptr) }; |
531 | | assert_eq!(deque.len(), 2); |
532 | | let node3_ref = unsafe { node3_ptr.as_ref() }; |
533 | | assert!(!deque.contains(node3_ref)); |
534 | | assert!(node3_ref.next.is_none()); |
535 | | assert!(node3_ref.next.is_none()); |
536 | | std::mem::drop(unsafe { Box::from_raw(node3_ptr.as_ptr()) }); |
537 | | |
538 | | // peek_front() -> node2 |
539 | | let head_h = deque.peek_front().unwrap(); |
540 | | assert!(deque.contains(head_h)); |
541 | | assert!(deque.is_head(head_h)); |
542 | | assert!(!deque.is_tail(head_h)); |
543 | | assert!(std::ptr::eq(head_h, node2_ptr.as_ptr())); |
544 | | assert!(head_h.prev.is_none()); |
545 | | assert!(std::ptr::eq( |
546 | | head_h.next.unwrap().as_ptr(), |
547 | | node1_ptr.as_ptr() |
548 | | )); |
549 | | |
550 | | // peek_back() -> node1 |
551 | | let tail_f = deque.peek_back().unwrap(); |
552 | | assert!(deque.contains(tail_f)); |
553 | | assert!(!deque.is_head(tail_f)); |
554 | | assert!(deque.is_tail(tail_f)); |
555 | | assert!(std::ptr::eq(tail_f, node1_ptr.as_ptr())); |
556 | | assert!(std::ptr::eq( |
557 | | tail_f.prev.unwrap().as_ptr(), |
558 | | node2_ptr.as_ptr() |
559 | | )); |
560 | | assert!(tail_f.next.is_none()); |
561 | | |
562 | | // unlink(node2) |
563 | | unsafe { deque.unlink(node2_ptr) }; |
564 | | assert_eq!(deque.len(), 1); |
565 | | let node2_ref = unsafe { node2_ptr.as_ref() }; |
566 | | assert!(!deque.contains(node2_ref)); |
567 | | assert!(node2_ref.next.is_none()); |
568 | | assert!(node2_ref.next.is_none()); |
569 | | std::mem::drop(unsafe { Box::from_raw(node2_ptr.as_ptr()) }); |
570 | | |
571 | | // peek_front() -> node1 |
572 | | let head_g = deque.peek_front().unwrap(); |
573 | | assert!(deque.contains(head_g)); |
574 | | assert!(deque.is_head(head_g)); |
575 | | assert!(deque.is_tail(head_g)); |
576 | | assert!(std::ptr::eq(head_g, node1_ptr.as_ptr())); |
577 | | assert!(head_g.prev.is_none()); |
578 | | assert!(head_g.next.is_none()); |
579 | | |
580 | | // peek_back() -> node1 |
581 | | let tail_g = deque.peek_back().unwrap(); |
582 | | assert!(deque.contains(tail_g)); |
583 | | assert!(deque.is_head(tail_g)); |
584 | | assert!(deque.is_tail(tail_g)); |
585 | | assert!(std::ptr::eq(tail_g, node1_ptr.as_ptr())); |
586 | | assert!(tail_g.next.is_none()); |
587 | | assert!(tail_g.next.is_none()); |
588 | | |
589 | | // unlink(node1) |
590 | | unsafe { deque.unlink(node1_ptr) }; |
591 | | assert_eq!(deque.len(), 0); |
592 | | let node1_ref = unsafe { node1_ptr.as_ref() }; |
593 | | assert!(!deque.contains(node1_ref)); |
594 | | assert!(node1_ref.next.is_none()); |
595 | | assert!(node1_ref.next.is_none()); |
596 | | std::mem::drop(unsafe { Box::from_raw(node1_ptr.as_ptr()) }); |
597 | | |
598 | | // peek_front() -> node1 |
599 | | let head_h = deque.peek_front(); |
600 | | assert!(head_h.is_none()); |
601 | | |
602 | | // peek_back() -> node1 |
603 | | let tail_e = deque.peek_back(); |
604 | | assert!(tail_e.is_none()); |
605 | | } |
606 | | |
607 | | #[test] |
608 | | fn iter() { |
609 | | let mut deque: Deque<String> = Deque::new(MainProbation); |
610 | | assert!((&mut deque).next().is_none()); |
611 | | |
612 | | let node1 = DeqNode::new("a".into()); |
613 | | deque.push_back(Box::new(node1)); |
614 | | let node2 = DeqNode::new("b".into()); |
615 | | let node2_ptr = deque.push_back(Box::new(node2)); |
616 | | let node3 = DeqNode::new("c".into()); |
617 | | let node3_ptr = deque.push_back(Box::new(node3)); |
618 | | |
619 | | // ------------------------------------------------------- |
620 | | // First iteration. |
621 | | assert_eq!((&mut deque).next(), Some(&"a".into())); |
622 | | assert_eq!((&mut deque).next(), Some(&"b".into())); |
623 | | assert_eq!((&mut deque).next(), Some(&"c".into())); |
624 | | assert!((&mut deque).next().is_none()); |
625 | | |
626 | | // ------------------------------------------------------- |
627 | | // Ensure the iterator restarts. |
628 | | assert_eq!((&mut deque).next(), Some(&"a".into())); |
629 | | assert_eq!((&mut deque).next(), Some(&"b".into())); |
630 | | assert_eq!((&mut deque).next(), Some(&"c".into())); |
631 | | assert!((&mut deque).next().is_none()); |
632 | | |
633 | | // ------------------------------------------------------- |
634 | | // Ensure reset_cursor works. |
635 | | assert_eq!((&mut deque).next(), Some(&"a".into())); |
636 | | assert_eq!((&mut deque).next(), Some(&"b".into())); |
637 | | deque.reset_cursor(); |
638 | | assert_eq!((&mut deque).next(), Some(&"a".into())); |
639 | | assert_eq!((&mut deque).next(), Some(&"b".into())); |
640 | | assert_eq!((&mut deque).next(), Some(&"c".into())); |
641 | | assert!((&mut deque).next().is_none()); |
642 | | |
643 | | // ------------------------------------------------------- |
644 | | // Try to move_to_back during iteration. |
645 | | assert_eq!((&mut deque).next(), Some(&"a".into())); |
646 | | // Next will be "b", but we move it to the back. |
647 | | unsafe { deque.move_to_back(node2_ptr) }; |
648 | | // Now, next should be "c", and then "b". |
649 | | assert_eq!((&mut deque).next(), Some(&"c".into())); |
650 | | assert_eq!((&mut deque).next(), Some(&"b".into())); |
651 | | assert!((&mut deque).next().is_none()); |
652 | | |
653 | | // ------------------------------------------------------- |
654 | | // Try to unlink during iteration. |
655 | | assert_eq!((&mut deque).next(), Some(&"a".into())); |
656 | | // Next will be "c", but we unlink it. |
657 | | unsafe { deque.unlink_and_drop(node3_ptr) }; |
658 | | // Now, next should be "b". |
659 | | assert_eq!((&mut deque).next(), Some(&"b".into())); |
660 | | assert!((&mut deque).next().is_none()); |
661 | | |
662 | | // ------------------------------------------------------- |
663 | | // Try pop_front during iteration. |
664 | | let node3 = DeqNode::new("c".into()); |
665 | | deque.push_back(Box::new(node3)); |
666 | | |
667 | | assert_eq!((&mut deque).next(), Some(&"a".into())); |
668 | | // Next will be "b", but we call pop_front twice to remove "a" and "b". |
669 | | deque.pop_front(); // "a" |
670 | | deque.pop_front(); // "b" |
671 | | // Now, next should be "c". |
672 | | assert_eq!((&mut deque).next(), Some(&"c".into())); |
673 | | assert!((&mut deque).next().is_none()); |
674 | | |
675 | | // ------------------------------------------------------- |
676 | | // Check iterating on an empty deque. |
677 | | deque.pop_front(); // "c" |
678 | | assert!((&mut deque).next().is_none()); |
679 | | assert!((&mut deque).next().is_none()); |
680 | | } |
681 | | |
682 | | #[test] |
683 | | fn next_node() { |
684 | | let mut deque: Deque<String> = Deque::new(MainProbation); |
685 | | |
686 | | let node1 = DeqNode::new("a".into()); |
687 | | deque.push_back(Box::new(node1)); |
688 | | let node2 = DeqNode::new("b".into()); |
689 | | let node2_ptr = deque.push_back(Box::new(node2)); |
690 | | let node3 = DeqNode::new("c".into()); |
691 | | let node3_ptr = deque.push_back(Box::new(node3)); |
692 | | |
693 | | // ------------------------------------------------------- |
694 | | // First iteration. |
695 | | // peek_front() -> node1 |
696 | | let node1a = deque.peek_front_ptr().unwrap(); |
697 | | assert_eq!(unsafe { node1a.as_ref() }.element, "a".to_string()); |
698 | | let node2a = DeqNode::next_node_ptr(node1a).unwrap(); |
699 | | assert_eq!(unsafe { node2a.as_ref() }.element, "b".to_string()); |
700 | | let node3a = DeqNode::next_node_ptr(node2a).unwrap(); |
701 | | assert_eq!(unsafe { node3a.as_ref() }.element, "c".to_string()); |
702 | | assert!(DeqNode::next_node_ptr(node3a).is_none()); |
703 | | |
704 | | // ------------------------------------------------------- |
705 | | // Iterate after a move_to_back. |
706 | | // Move "b" to the back. So now "a" -> "c" -> "b". |
707 | | unsafe { deque.move_to_back(node2_ptr) }; |
708 | | let node1a = deque.peek_front_ptr().unwrap(); |
709 | | assert_eq!(unsafe { node1a.as_ref() }.element, "a".to_string()); |
710 | | let node3a = DeqNode::next_node_ptr(node1a).unwrap(); |
711 | | assert_eq!(unsafe { node3a.as_ref() }.element, "c".to_string()); |
712 | | let node2a = DeqNode::next_node_ptr(node3a).unwrap(); |
713 | | assert_eq!(unsafe { node2a.as_ref() }.element, "b".to_string()); |
714 | | assert!(DeqNode::next_node_ptr(node2a).is_none()); |
715 | | |
716 | | // ------------------------------------------------------- |
717 | | // Iterate after an unlink. |
718 | | // Unlink the second node "c". Now "a" -> "c". |
719 | | unsafe { deque.unlink_and_drop(node3_ptr) }; |
720 | | let node1a = deque.peek_front_ptr().unwrap(); |
721 | | assert_eq!(unsafe { node1a.as_ref() }.element, "a".to_string()); |
722 | | let node2a = DeqNode::next_node_ptr(node1a).unwrap(); |
723 | | assert_eq!(unsafe { node2a.as_ref() }.element, "b".to_string()); |
724 | | assert!(DeqNode::next_node_ptr(node2a).is_none()); |
725 | | } |
726 | | |
727 | | #[test] |
728 | | fn peek_and_move_to_back() { |
729 | | let mut deque: Deque<String> = Deque::new(MainProbation); |
730 | | |
731 | | let node1 = DeqNode::new("a".into()); |
732 | | deque.push_back(Box::new(node1)); |
733 | | let node2 = DeqNode::new("b".into()); |
734 | | let _ = deque.push_back(Box::new(node2)); |
735 | | let node3 = DeqNode::new("c".into()); |
736 | | let _ = deque.push_back(Box::new(node3)); |
737 | | // "a" -> "b" -> "c" |
738 | | |
739 | | let node1a = deque.peek_front_ptr().unwrap(); |
740 | | assert_eq!(unsafe { node1a.as_ref() }.element, "a".to_string()); |
741 | | unsafe { deque.move_to_back(node1a) }; |
742 | | // "b" -> "c" -> "a" |
743 | | |
744 | | let node2a = deque.peek_front_ptr().unwrap(); |
745 | | assert_eq!(unsafe { node2a.as_ref() }.element, "b".to_string()); |
746 | | |
747 | | let node3a = DeqNode::next_node_ptr(node2a).unwrap(); |
748 | | assert_eq!(unsafe { node3a.as_ref() }.element, "c".to_string()); |
749 | | unsafe { deque.move_to_back(node3a) }; |
750 | | // "b" -> "a" -> "c" |
751 | | |
752 | | deque.move_front_to_back(); |
753 | | // "a" -> "c" -> "b" |
754 | | |
755 | | let node1b = deque.peek_front().unwrap(); |
756 | | assert_eq!(node1b.element, "a".to_string()); |
757 | | } |
758 | | |
759 | | #[test] |
760 | | fn drop() { |
761 | | use std::{cell::RefCell, rc::Rc}; |
762 | | |
763 | | struct X(u32, Rc<RefCell<Vec<u32>>>); |
764 | | |
765 | | impl Drop for X { |
766 | | fn drop(&mut self) { |
767 | | self.1.borrow_mut().push(self.0) |
768 | | } |
769 | | } |
770 | | |
771 | | let mut deque: Deque<X> = Deque::new(MainProbation); |
772 | | let dropped = Rc::new(RefCell::new(Vec::default())); |
773 | | |
774 | | let node1 = DeqNode::new(X(1, Rc::clone(&dropped))); |
775 | | let node2 = DeqNode::new(X(2, Rc::clone(&dropped))); |
776 | | let node3 = DeqNode::new(X(3, Rc::clone(&dropped))); |
777 | | let node4 = DeqNode::new(X(4, Rc::clone(&dropped))); |
778 | | deque.push_back(Box::new(node1)); |
779 | | deque.push_back(Box::new(node2)); |
780 | | deque.push_back(Box::new(node3)); |
781 | | deque.push_back(Box::new(node4)); |
782 | | assert_eq!(deque.len(), 4); |
783 | | |
784 | | std::mem::drop(deque); |
785 | | |
786 | | assert_eq!(*dropped.borrow(), &[1, 2, 3, 4]); |
787 | | } |
788 | | } |